Repository navigation
feat(settings): workspace settings as a drill-down with per-page save - #232
Conversation
Near-full-window overlay; the root lists General/Schedule/Team and one row per agent with a summary, and a page fills the pane behind a breadcrumb. Each page saves on its own through a sticky bar shown only when dirty; leaving a dirty page asks Save / Discard / Stay. Escape goes back one level and closes only at the root; a search field with text keeps it. Drops the sidebar, the keep-visited-pages-mounted map, the per-section dirty dots and the validate-all-then-submit-all loop. The gear now opens the index; the drawer's Edit still deep-links to the agent page.
- Team and crew-assignment pages expose a SectionHandle and report dirty, so leaving them prompts like every other page; their inline Save buttons are gone (the sticky bar is the one save path). Remove-from-crew stays an immediate action. - Creating the Main moves the page to the new agent (submit returns createdId), so Discard + Save can no longer create a second one; the createdAgentId workaround is deleted. The Main editor is chosen by the roster's isDefault, not a possibly stale defaultWorkspaceAgentId. - Focus: the first index row when the modal opens at the index or the origin row is gone; Stay (and a failed Save from the prompt) returns focus to what triggered the leave; Discard focuses the page heading. - Tests: overlay click on a dirty page, failed Save from the prompt, dirty Team/crew pages, create Main -> Discard -> Save, focus fallbacks.
|
Delta vs |
…s after Save A create now moves to the new agent's page before awaiting onChanged, so a Save during the refetch updates it instead of attempting a second create, and Back/close is no longer pulled back afterwards. A non-create save focuses the page heading, since the save bar unmounts with its button. Tests cover both, plus failed Team and crew saves.
|
|
The workspace settings modal becomes a fixed-size window (1200x800, or the viewport less 24 px when smaller) with a sidebar that always lists every page — General, Schedule, Team, the Main, each crew member, Add to crew — instead of a root index you drill into and back out of. Pages are laid out for the window (two columns that share its height) rather than a 720 px column that scrolls. Kept from the previous iteration: the per-page draft and save bar, Save / Discard / Stay on any way out of a dirty page (now including a sidebar click), the create-then-switch for the Main, focus on the page title after Save. Changed: with no index level, Escape goes innermost first — answer the leave question, let a search field clear, leave a page's drill-in view (new optional SectionHandle.back), then close. Sidebar navigation keeps focus on the sidebar item. Fixes Stay never receiving focus: React reused the Discard button's node for Stay, so its autoFocus did not run. General and Schedule move to WorkspacePages.tsx; shared controls (page layouts, panels, switch, path-grant and prefix editors) to SettingsForm.module.css and ListEditors.tsx, used by Team and crew too.
The agent form (the workspace's Main, and shared definitions in the library) is rebuilt as an overview that fits the window, with drill-in views for what does not: - Runs on: a single select of enabled connections labelled like the chat bar. Picking writes a one-element list; a legacy multi-entry list is left as is until the user picks, and the hint says the extra entries are never used. A gone or disabled connection is shown as such. No backend change. - MCP servers: a dropdown of checkboxes whose trigger names what is on. It joins the overlay stack, so Escape closes it and not the window. - Skills, sources first: one row per source with its selected count; opening one shows only that source's skills as a compact tile grid, with the focused skill's description in a fixed strip. A search on the overview finds skills across sources. - Local access: a summary on the overview, edited in its own view (paths | shell, web, D-Bus). The blocked-prefix list now shows under Full as well as Restricted, since local.rs applies it in both. back() on the handle leaves a drill-in view, and focus returns to the control that opened it. The form no longer draws its own heading; the window title and the library editor already do.
- The save bar moves into the page header, so no footer height is reserved while nothing is unsaved, and the skill search moves into the Skills panel header. A 9-source overview now fits a 652 px window. - Escape inside a drill-in view of the agent library editor goes back instead of closing global Settings and dropping the draft. - The MCP popover renders inside the dialog, after its trigger: Tab past the end closes it, Shift+Tab reaches the trigger. - The agent form keeps its skeleton until deps load, so no false "connection is gone" or empty-list warnings flash. - Select all / Clear in a source act on the filtered skills. - Accurate legacy-connection hint, subtitle and save-error tooltips, useReportDirty instead of a copy, unused `details` prop and CSS removed. - Tests: legacy connection list kept on save, dirty tracking in both drill-in views, filtered Select all, deps loading, library Escape, MCP Tab order.
|
Settings redesigned from scratch after owner feedback (design: page sidebar, fixed-size dialog, agent page as a one-screen overview, skills browsed source-first, MCP dropdown with checkboxes, single 'Runs on' model choice). Commits a89265a, 8382f71, 6164daf. Review v2-r1 needs_fixes → all 4 majors fixed in 6164daf (fits at 1366×768 per Chromium measurement; multi-connection save test; library Esc steps back; MCP popover focus stays in dialog). Settings vitest 119 pass, lint + tsc clean. Not verified in WebKitGTK; review r2 in progress. |
- Schedule: re-sync the draft on the saved schedule's value, so the 5 s details poll, Run now and Pause no longer discard an unsaved edit. - Team: a failed policy load shows only the error and refuses to save, instead of an empty form that would overwrite the stored policy. - Library editor: focusable root keeps Escape inside it; Escape in a search field with text clears it instead of closing Settings. - Layout: Skills header search and count shrink; the save bar shrinks and ellipsizes before the page title does; the asking state colours the whole bar border. - Test that the overview's Clear all keeps unknown skill ids.
|
c280aae — review v2-r2 fixes: Schedule draft no longer wiped by the 5 s details poll / Run now / Pause (reset keyed on value; pre-existing bug); Team page no longer shows an editable empty form when the policy fails to load (pre-existing, could overwrite stored settings); skills header shrinks at 961–1130 px; library editor keeps focus for Esc; amber leave bar; title min width; Clear-all test. Prod +49/−21, tests +55. Settings vitest 122 pass, lint + tsc clean. Not verified in WebKitGTK. |
The app Settings dialog had its own older shell (SettingsModal.module.css): 980×760, a 14 px sidebar, a blurred backdrop and an unbounded content column. Workspace settings is 1200×800 with a 13 px sidebar. Both now use one stylesheet, SettingsShell.module.css, so they are the same window. The library agent editor already used the workspace agent form, but sat in a content-sized column under a title, a face row and a footer, so the form never got a height to fill and the pane scrolled (479 px over at 1249×995). The editor now fills the pane: Save/Archive share the breadcrumb row and the description sits beside the face picker. Measured in headless Chromium at 1249×995: no scroll; at a 1366×768 screen it still scrolls by 106 px.
Four things repainted already-shown content on a navigation: - The page area had `animation: fadeIn` and is keyed by page, so every page switch, Discard and post-create hop faded the whole pane in from opacity 0. The fade is gone; the window's open animation stays. - The modal stayed mounted while closed and reset its page in an effect. That effect runs at default priority after the open commit, so a reopen painted the page it was closed on (and started its fetch) before the requested one. The window now mounts per opening, keyed by the requested page, and the reset effect is deleted. - Page skeletons replaced the pane for the few ms a local load takes, then gave way to the real layout. They now stay invisible for 300 ms. - An agent's sidebar row grew from 36 to 48 px when its model name arrived with the connections, moving every row below it. The line is reserved. Also, the app Settings Agents tab said "No agents yet" on every visit until the library answered; the gallery now waits for that first answer.
- Pages no longer repeat the window header's title (Agents, Skills, MCP Servers, Applications, Appearance); About's CLAI heading is an h3. - App Settings mounts only while open, keyed by the requested tab and agent, like workspace settings; the render-phase reset state is gone. Focus starts on the active sidebar item. - The Agents tab shows the delayed skeleton while the library is first read, and only the error with Retry if that read fails. - The agent editor zeroes the form's page padding through a custom property instead of a descendant selector; its back link and title are no longer a breadcrumb nav. - Drop the unused shell copy of .navAdd/.navPlaceholder and correct the .body scrolling comment.
The owner sees a dialog flicker over and under the window behind it as it opens, in WebKitGTK only, and only during the open. Nothing in the stacking changes then: modal overlays sit at z-index 10000+, portaled to <body>, and nothing else in the app is above 1000. What does change is compositing: the backdrop fades its opacity in, the dialog animates opacity and transform, and several backdrops also blur what is behind them. Each one makes WebKit promote the layer for the animation and demote it after. Every modal overlay now appears at once with no backdrop-filter: the settings shell, the MCP/provider form modal, ConfirmDialog, ProgressDialog, CommandHelpModal and the MCP server selector. The keyframes that nothing uses any more are deleted.
PR 1 of the settings redesign (
plans/settings-redesign.mdin the manager workspace). Shell only: page contents, SkillPicker, MCP widget, backend and the app-level Settings modal are untouched.What changes
Deleted
Sidebar +
NavItemdirty dots, the keep-visited-pages-mounted map and its helpers, the validate-every-dirty-section-then-submit loop (never atomic), thewindow.confirmon close.createdAgentIdstays: a page now remains open after save, so creating the Main and saving again would otherwise create a second agent.Size
Production +435/−404, tests +161/−6 (7 files). Most churn is
WorkspaceSettingsModal.tsxrewritten.Tests
8 new cases (index→page focus round trip, Esc semantics at root/page/search field, bar only when dirty + Discard resets, leave prompt Stay/Esc/Discard/Save, saving one page writes only that page, failed validation keeps page open). Five deliberate breakages (no leave guard, no search check, bar always shown, no focus move, Esc always closing) each failed at least one test.
Not verified
No app run: layout/slide-in look, whether Esc natively clears a WebKitGTK search field, runtime skill counts. Known rough edges: after creating the Main from "Main — set up" the page keeps that title until you go back; removing a crew member returns to the index (was Team).
Code review in progress; fixes will follow as commits. Draft — owner merges.