feat(automations): the terminal menu's automations open on hover, like snippets - #72
Merged
Merged
Conversation
…e snippets plan/029 gave `Terminal/ContextMenu` a hover flyout, and the automations armed on a terminal were still spread into it as one flat `Automation: <name>` row per rule — the shape chosen back when this host had no submenu machinery at all, which put a terminal's rules in among Copy/Paste/Clear and grew the menu by a row each. They nest now: one `Automations (N)` row that opens the rules on hover, each carrying this terminal's state in the dimmed column and opening that rule's editor. The row that OPENS the list is `armedMenuLabel`, shared with the accordion the pane and canvas menus render, so the two cannot be renamed apart. `armedEntryViews` already decided which rules, in what order, and in whose words — only the shape follows the host. Still zero-or-one item, so nothing is drawn when nothing is armed: a parent over an empty panel is the item that looks live and does nothing. Gates: `bun run typecheck` clean, `bunx jest` 3531 passed / 206 suites. Both new guards mutation-checked — hard-coding the parent's label, and dropping `closeMenuOnSelect`, each fail exactly one assertion.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The armed automations were spread into the terminal's right-click menu as one flat row per rule —
⚡ Automation: Watch the build,⚡ Automation: Answer the prompt— sitting in among Copy, Paste,Clear and Mute, and growing the menu by a row for every rule.
They nest now, in the shape Snippets and Command History already use:
⚡ Automation: <name>× N, inline⚡ Automations (N) ▸→ hover → the rulesEach flyout row still opens that rule's editor and closes the menu, exactly as the flat rows did.
Why this is a change rather than a fix
The flat shape was not an oversight — it was the documented decision at the time, and the comment
said so: "a menu with no submenu machinery cannot nest, and an
Automations ▸row that openednothing would be the disabled-looking item this repo keeps refusing to ship."
plan/029(Snippets,#70) built that machinery, and the reason expired the day it merged. That paragraph is rewritten in
place rather than appended to, so the file does not assert both.
The shared half
armedEntryViewsalready decided which rules are offered, in what order, and in whose words — thetab badge, the pane title, the two accordion menus and this flyout all read it. What was still
duplicated was the row that opens the list:
views.length === 1 ? 'Automation' : 'Automations (N)'was a literal inside the accordion, and the flyout parent needed the same text. It isarmedMenuLabelnow, lifted rather than copied, and a test compares the flyout parent's label withthe accordion header's own text node for equality —
toContainwould have passed a parenthard-coded to
Automationsagainst a header readingAutomations (2), which is the exact drift theextraction exists to stop.
Two menu systems, two shapes, one vocabulary:
PaneContextMenuandCanvasNodeMenuhave nopositioning machinery and keep the accordion (
TabContextMenu.csssettles that shape for the ColorSchema panel in as many words);
Terminal/ContextMenuhas an edge-aware flyout, so it opens one.Details worth naming
said to a host that spreads its items. A parent row over an empty panel is the item that looks
live and does nothing.
rows, soContextMenu's own case-insensitive filter overlabel+detaildoes the searching. Snippets takes the function form becausefilterSnippetsalso owns#tagmatching and the flatten-on-search rule; there is no equivalent for a handful of rulesnamed by their author.
closeMenuOnSelect: true, stated per row. The flyout's default is to keep the menu up, andthe flat rows it replaces always closed it — an editor opening behind a menu that stayed is two
surfaces both believing they have the keyboard.
emptyRowis reachable only by typing. The parent does not exist when nothing is armed, so"no automations at all" never renders inside the panel.
Terminal/ContextMenuisimport type, so no part of that module — least ofall its stylesheet — reaches
PaneContextMenuorCanvasNodeMenu, which mount the component fromthe same file.
Gates
bun run typecheckclean ·bunx jest3531 passed / 206 suites · CI green ona4405a1(Rust Tests Linux/Windows/macOS, e2e) · Tam's GUI pass — signed off ("sign off for GUI, it
works"), run from the
wt-watchdogworktree at this head.Both new guards were mutation-checked: hard-coding the parent's label to
Automations, and droppingcloseMenuOnSelect, each fail exactly one assertion — the shared-label test and the hover testrespectively, and neither killed the other's mutant.
The hover test drives a real
ContextMenu: it asserts the panel is absent, delivers amouseoverwith
relatedTarget: null(React synthesisesmouseenterfrom that; amouseovercarrying anin-tree
relatedTargetis a silent no-op that looks exactly like a missing handler), then assertsthe two rows, their state column, that clicking the second opens
r2and thatonClosefired.Not tested here
Tam tests the UI himself. The flyout's own behaviour — placement, edge flipping, the hover-close
grace period, keyboard navigation — is
contextMenuFlyout.test.tsx's, unchanged by this PR.