feat(planning): one menu of plan actions, from the toolbar's ⋯ and a sidebar right-click
A plan now has one set of actions, and you can reach them two ways:
- Toolbar ⋯: an icon button at the top right of the plan page opens a dropdown.
- Sidebar right-click: right-clicking any plan in the sidebar opens the same menu at the pointer, for that plan. The plan doesn't have to be the open one, and acting on it doesn't navigate.
Toolbar, left to right, as agreed for PRs 3 and 4: [title / folder] … [Choose folder… (only while no folder is set)] [Document|Board] [Copy plan] [⋯]. PR 4 removes the switch and adds the right-panel toggle after ⋯. The Close-plan X and the standalone trash button are gone. Copy plan stays a visible labeled button.
Menu contents (only the actions that apply)
- Copy plan: only for the open plan whose document has loaded. The sidebar list carries summaries, not documents, so there is nothing to copy for another plan.
- Reveal in Finder and Change folder… when the plan has a folder on this Mac; Choose folder… when it doesn't.
- Delete plan…: red, last, after a rule. Choosing it doesn't delete. The control that opened the menu (the ⋯, or the plan's sidebar row) turns into the existing
ConfirmSwapquestion (Cancel / Delete plan) throughuseConfirm, whichrenderer/CLAUDE.mdrequires for anything irreversible. In the toolbar the question is mounted only while it's asked, so the ⋯ doesn't keep an empty gap the width of the hidden answers. - Rename… is left out. Neither the host nor the gateway supports renaming a plan (no rename act or gateway method). Follow-up: a
planning.renamegateway method plus act, then a menu item.
Design choice: one small renderer-drawn menu, not Menu.popup
Both entry points render the same ActionMenu (desktop/plan-actions.tsx), so they look identical by construction. A native macOS menu can't draw Delete in red, and it would need a new act carrying the item list plus a round trip for the answer. The menu handles role="menu"/menuitem, focus on the first item, ↑/↓/Home/End, and Escape or Tab to close with focus back on the opener. Escape stops there, so it doesn't also leave the plan. A press outside the menu, a window blur, or a resize also closes it. It's portaled to <body>, measured before paint and clamped inside the window, and marked no-drag over the toolbar's drag strip. A sidebar row with its menu open gets a ring, as in Finder. Labels are static text, and session replay masks text nodes as before.
New act: planning.revealFolder
The act names a plan id, not a path. Main looks up the folder in its own planning view and calls shell.showItemInFolder, so the panel can only reveal a folder the host already holds for one of its plans. It's refused for a plan with no folder and for any window other than the panel. A fixture run never sends it.
onChooseFolder and onDeletePlan now take a plan id so the sidebar can act on a plan that isn't open; the host already supported both for any plan. DeletePlanButton is no longer exported (knip): only planning-parts' own header still uses it.
Tests
plan-actions.test.ts(jsdom, throughDesktopPlansandSidebarPlan):- the ⋯ menu's items with and without a folder; the toolbar has no close or delete of its own
- right-click targets the clicked plan, opens at the pointer, and navigates nowhere
- Delete asks before deleting from both entry points
- keyboard navigation, and Escape closes the menu alone with focus returned
- an outside press closes the menu, and so does a second ⋯ press
planning-acts.test.ts: Reveal in Finder shows the held folder, and is refused for a folderless plan and for the voice window.use-plans-tab.test.ts: delete names the plan.
./scripts/check.sh exits 0.
Mac verification
CI could not verify the Mac UI, and ./scripts/verify.sh was not run. This was built on a Linux cloud VM, and CI builds nothing for the Mac. LUKE-159 is the manual Mac pass. I rendered the real components with the real stylesheet in headless Chrome to check: the ⋯ menu, the sidebar context menu, and both delete confirms. The native Finder reveal and the window drag-region behavior still need checking on a Mac.
🤖 Generated with Claude Code