feat(desktop): plan menu icons, no ellipses, and Delete asks in a standard modal

Merged
DA
11d ago
+687-216

Three changes to a plan's menu, which the toolbar ⋯ and the sidebar right-click share (desktop/plan-actions.tsx).

1. Icons

Every menu item now starts with a muted 16px glyph from @sidecar/panel, so they share the panel's stroke weight:

  • Copy plan: copy
  • Reveal in Finder: open folder. This is a new FolderOpenIcon, drawn from the existing FolderIcon shape.
  • Choose folder / Change folder: folder
  • Delete plan: trash, red along with the label

Every item reserves the icon column even with no icon, so the labels line up.

2. No "…"

The menu labels are now Choose folder, Change folder, and Delete plan. I also dropped the ellipsis from the toolbar's Choose folder button. It shows at the same time as the menu's Choose folder, so leaving it would have put two spellings side by side. Other surfaces are unchanged.

3. Delete asks in a standard modal

The swap that turned the ⋯ or the sidebar row into Cancel/Delete is gone. Choosing Delete plan now opens a centred role="alertdialog" with aria-modal, labelled by its title and described by its body, over a dimmed window:

Delete plan?
“Teammate invitations” will be permanently deleted, along with its board and transcript. This can’t be undone.
[Cancel] [Delete]

  • The wording matches what delete does. plan-store.ts#deletePlan removes the plan row and its document, and the board and command rows go with it by cascade. It also marks the plan's conversation (the transcript) as deleted, and the sweep purges it 30 days later. Nothing in the app can restore it.
  • Focus: Cancel gets focus first. Tab stays on the two buttons. Enter does whatever the focused button does, so it deletes only when Delete is focused. Escape, a click on the dimmed window, or Cancel closes the dialog and puts focus back on whatever opened it (the ⋯ or the sidebar row). Escape closes only the dialog, not the plan behind it.
  • While deleting: both buttons are disabled and Delete reads "Deleting…". If the delete is refused, the dialog stays open, shows the reason (role="alert"), and lets you retry or cancel.
  • Motion: the backdrop fades and the card fades and scales in, timed with the existing motion tokens (--duration-quick, --duration-fast/--spring-fast). Reduced motion already sets those tokens to 1ms, so nothing moves.
  • One reusable piece: settings/confirm-dialog.tsx has ConfirmDialog and useConfirmDialog, which future destructive desktop actions can use. It sits on confirm-state.ts's useConfirm, so the dialog still closes when its plan disappears (the plan is now checked against the list and the drawn plan, where it used to be hard-coded subject: true), when the tab goes off screen, or when the plan changes (the toolbar button is keyed by plan). useConfirmDialog also clears a displayed refusal on those same terms.
  • Removed: DeletePlanButton and the unused onDelete prop on PlanDocumentView (planning/planning-parts.tsx), plus their CSS and the sidebar's credential-* overrides. ConfirmSwap stays because the settings account rows still use it.
  • Renderer guide: the "Confirms" paragraph in renderer/AGENTS.md now describes the dialog, as the task approved. Nothing else in that file changed.
  • Session replay: the plan name appears only as text nodes, which session-replay.ts masks (maskTextSelector: "*"). The dialog's accessible name and description come from aria-labelledby and aria-describedby ids rather than an aria-label. A test checks that no attribute in the dialog contains the plan name.

Tests (plan-actions.test.ts, through DesktopPlans and SidebarPlan)

  • Menu labels have no "…", every item has an icon, and the toolbar text has no "…".
  • Delete opens a modal alertdialog named "Delete plan?" whose description names the plan, with Cancel focused. Delete deletes, from both the ⋯ and a sidebar row.
  • Cancel, Escape, and a click on the backdrop each leave the plan in place and return focus to the ⋯. Escape doesn't reach the window. A click inside the card doesn't dismiss.
  • Tab and Shift-Tab wrap between the two buttons.
  • While a delete runs, both buttons are disabled and Escape is ignored. A refusal stays in the dialog, and Cancel then dismisses it.
  • The dialog closes when its plan leaves the list and doesn't reappear when the plan comes back. It also closes when the tab goes off screen.
  • No attribute contains the plan name.

I checked that the plan-disappears test fails with the old subject: true.

./scripts/check.sh exits 0.

Mac verification

CI could not verify the Mac UI, and ./scripts/verify.sh was not run. I built this on a Linux cloud VM, and CI builds nothing for the Mac. LUKE-159 is the manual Mac pass. In headless Chrome, I rendered the real DesktopPlans with the built stylesheet and screenshotted the menu with its icons and the dialog. Still to check on a Mac: the backdrop's no-drag over the toolbar's drag strip, and the animation timing.

🤖 Generated with Claude Code


Open workspace in Conductor


Devin Review