8.3 KiB
spec, created, status
| spec | created | status |
|---|---|---|
| docs/specs/ui/requirements/task-layout-profiles.md | 2026-07-19 | complete |
Implementation Plan: Task Layout Profiles
Overview
Extend the existing saved_layouts user setting instead of introducing new persistence. First harden profile-list validation and add pure reusable-layout operations, then build the responsive settings editor and connect the workbench default path, and finally prove persistence and task isolation in Playwright. The runtime remains compatible with the existing layout menu and environment-scoped layout restoration.
Backend
Saved layout validation
apps/backend/internal/user/service/service.go: extendapplySavedLayoutsto reject empty IDs, duplicate IDs, and more than oneis_defaultprofile while retaining the existing count and name checks.apps/backend/internal/user/service/service_test.go: add table-driven validation coverage, including acceptance of zero or one saved default across custom profiles and reserved overrides.
No schema, repository, DTO, or endpoint changes are required; users.settings.saved_layouts and the existing GET/PATCH contract remain authoritative.
Frontend
Profile domain
- Add
apps/web/lib/layout/layout-profiles.tsand focused tests for built-in template descriptors, reusable-layout validation, effective-default resolution, immutable create/rename/duplicate/delete/default operations, and legacy-layout compatibility status. - Reuse
LayoutState,PANEL_REGISTRY,getPresetLayout, session-panel normalization, and the existingSavedLayoutHTTP type. Editor-created layouts use canonical reusable panel IDs and never introduce task-specific IDs. - Extract shared profile mutations from
apps/web/components/task/layout-preset-selector.tsxso the task menu and settings page cannot diverge on default/delete behavior.
Settings page and editor
- Add
apps/web/app/settings/general/layouts/page.tsxwith the existing user-settings hydration pattern. - Add
apps/web/components/settings/layouts/layout-settings.tsxfor profile selection, create/duplicate/rename/delete/default/reset commands, dirty-state handling through the shared Settings floating save coordinator, error feedback, and narrow-viewport composition. - Add focused editor components under
apps/web/components/settings/layouts/that render lightweight panel placeholders, use the existing Dockview layout engine for pointer/touch split and tab manipulation, and expose contextual keyboard/touch commands beside the selected split. Every command has hover/focus help. Agent is permanent; reusable panels are single-instance. - Represent direct built-in edits as reserved hidden overrides so each built-in remains one visible row with
Built-inand optionalCustomizedstatus. Reset removes the reserved override and restores the code-defined layout. - Treat reserved built-in overrides like custom profiles for
is_defaultuniqueness: an override may own the single saved default, while editing built-in Default preserves an existing custom default. When no saved profile owns the default, editing built-in Default marks its override as the default so that customization becomes effective. - The preview is isolated from
useDockviewStoreand runtime panel components so Browser, VS Code, and Terminal have no runtime side effects in Settings. - Add
Layoutstoapps/web/components/settings/general-nav.tsand the settings tree; register/settings/general/layoutsinapps/web/src/settings-routes.tsxand cover route resolution.
Workbench integration
- Add a compatibility resolver used by
apps/web/components/task/dockview-desktop-layout.tsxso only a valid reusable saved default, including a reserved built-in override, reachessetUserDefaultLayout; invalid legacy defaults fall back to the built-in Default. - Preserve
apps/web/lib/state/dockview-store.tsprecedence: environment layout first, effective user default for fresh/reset paths second, built-in fallback last. - Verify
apps/web/hooks/domains/session/use-ensure-default-terminal-ordinary.tsremains panel-driven, so omittingterminal-defaultpreventscreateUserShell. - Keep
apps/web/components/task/layout-preset-selector.tsxbehavior compatible while reusing profile operations and making deletion of the selected custom default explicitly fall back to the built-in Default.
Tests
- Saved profile list validation:
apps/backend/internal/user/service/service_test.go; table-driven tests cover blank/duplicate IDs, multiple defaults, limits, names, and valid zero/one-default lists. - Profile operations and effective default:
apps/web/lib/layout/layout-profiles.test.ts; pure unit tests cover create, duplicate, rename, delete-default fallback, set-default uniqueness, valid layout requirements, and legacy compatibility. - Default layout resolution: focused tests for the resolver used by
dockview-desktop-layout.tsx; valid reusable layouts are normalized and invalid/unreadable defaults returnnull. - Terminal side-effect guard:
apps/web/hooks/domains/session/use-ensure-default-terminal-ordinary.test.ts; noterminal-defaultpanel means nocreateUserShell, while the existing panel path still migrates once. - Settings SPA route:
apps/web/src/settings-routes.test.tsand general navigation tests cover the Layouts route without direct component fetches.
E2E Tests
- Desktop profile workflow:
apps/web/e2e/tests/settings/layout-profiles.spec.ts; edit built-in Default directly, remove Terminal with contextual controls, verify action help, save through the shared floating control, and reset the built-in override. - Fresh task and reset behavior: the same desktop spec creates and opens a fresh task, verifies no Terminal tab/default shell, proves an existing customized task is unchanged after a default update, then verifies Reset Layout applies the latest default.
- Mobile settings parity:
apps/web/e2e/tests/settings/mobile-layout-profiles.spec.ts; navigate through the settings drawer, select and reorder a built-in tab with the contextual touch controls, save its hidden override, and verify there is no horizontal page scroll. - Existing layout regressions: run
apps/web/e2e/tests/task/task-default-layout.spec.tsandapps/web/e2e/tests/layout/saved-layout-session-isolation.spec.tswith the new specs.
Public Documentation
- Update
docs/public/sessions-and-review.mdwith the Layouts settings path, effective-default behavior, and the distinction between reusable defaults and task-specific restored layouts.
Implementation Waves
Wave 1 (parallel in the shared worktree):
Wave 2 (parallel):
Wave 3:
The user authorized subagents after the approval checkpoint. Tasks 01 and 02 ran in parallel with separate file ownership; Tasks 03 and 04 do the same in Wave 2. The parent agent owns shared plan synchronization and integration review. Read-only editor and E2E research informed the implementation tasks.
Risks
- Existing saved layouts may contain task-specific or old serialized Dockview payloads. Detection must not mutate or discard them silently.
- Dockview pointer behavior alone is insufficient on mobile and for keyboard users. Explicit move/split commands are part of acceptance, not a fallback enhancement.
- Settings previews must never mount real task panels or start terminal/editor/browser resources.
- Environment-scoped restoration must remain higher precedence than the new default, or changing Settings would unexpectedly rewrite active work.
- User-setting updates replace the full profile list, so each mutation must use the latest authoritative store value and adopt the response to avoid lost updates.
Verification
make fmt
make typecheck
make test
make lint
make build-web
cd apps/web && pnpm e2e:run tests/settings/layout-profiles.spec.ts tests/task/task-default-layout.spec.ts tests/layout/saved-layout-session-isolation.spec.ts
cd apps/web && pnpm e2e:run --project mobile-chrome -- tests/settings/mobile-layout-profiles.spec.ts --workers=1