You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4b4ab24
Browse filesBrowse the repository at this point in the historyBrowse files
improvement(menus): one separator per menu, before the destructive action (#6974)
* improvement(menus): one separator per menu, before the destructive action
Menus banded themselves into semantic groups — navigation, status, edit,
copy, destructive — behind two to four separators each. No toolbar in the
app renders a divider: every header is a flat gap-1 chip row and every
bulk action bar a flat gap-[5px] run. The bands therefore taught a
taxonomy the user met on no other surface, and because each band is
conditional, the same action landed in a different group depending on
which siblings happened to be visible. Pin sat alone in one caller of the
shared workflow menu and beside Duplicate in another.
Every menu now carries at most one rule, immediately before the
destructive group. Order is untouched, so the toolbar-mirroring the
ordering rule requires is unaffected.
Two separator bugs fixed. The logs row menu had two unconditional
separators above conditional items, so a log already filtered by its
workflow with no active filters ended on a dangling rule. The shared
workflow menu guarded its destructive rule on showLeave alone while the
Leave item required showLeave && onLeave, so a caller passing showLeave
from a permission check with a conditional onLeave would trail a rule
under the last item; every term in both guards is now the exact render
condition of the item it stands for.
Removes groupNonDestructiveActions and separateNavigationAction. Between
them they moved one separator for one caller, four of six branches were
unreachable, and separateNavigationAction had no observable effect
anywhere in the repo.
The separator matrix was previously untested, which is how the showLeave
asymmetry survived; it now has invariants including a flag sweep.
* fix(menus): build every separator guard from its items' exact conditions
Review caught two places where the grouping rule and the code disagreed.
The tables row menu guarded its rule on `onMove` while the Move submenu
needs a non-empty `moveOptions`, so a table whose other actions were all
absent and whose move list was empty would draw the rule with nothing
above it — the exact looseness the rule warns about.
The logs row menu puts its one rule after Retry and Cancel Run rather
than before a destructive group, which the rule as written did not
cover. Retry is the primary action on a failed run and belongs at the
top; the rule now describes the separator as fencing the consequential
group at whichever end it sits, and names the logs menu as the one place
that group leads.
Also aligns three empty-space menu labels with the header chips they
mirror: "Add document" and "Create chunk" were the only create actions
not matching their toolbar, and the files menu said "Upload file" where
its header says "Upload".
Run order in the two column run menus now matches the action bar and the
row menu — incomplete before all, not all before incomplete.
* fix(menus): apply the one-rule grouping to the folder context menu
The folder row menu kept a separator at its canEdit permission boundary
plus one before Delete — the same shape already corrected in the file
row menu, missed because the sweep that found it did not cover this
file. Open and Pin above are unconditional, so the surviving rule is
always backed on both sides.
Also records the standing exception the sweep surfaced: the text editor,
terminal, and browser page menus emulate native OS menus, whose banding
the user learns outside Sim. That is the ordering rule's own principle —
mirror the surface they already read — so those keep their banding while
our own resource and row menus, whose toolbars are flat, take one rule.
* fix(menus): keep empty-row actions together
Platform-only entries (desktop **Browser** and **Terminal**) trail the shared set rather than interleaving, so the common prefix is identical on every platform.
28
28
29
+
## Grouping: one rule, against the consequential group
30
+
31
+
Order is governed above. **Separators are governed here** — and the answer is: use at most one.
32
+
33
+
Put a single `DropdownMenuSeparator` against the **consequential group** — the actions that
34
+
delete, detach, or change a run — and nowhere else. Everything on the other side of it runs
35
+
uninterrupted in toolbar-mirroring order.
36
+
37
+
That group trails in almost every menu, so in practice the rule reads "one rule immediately
38
+
before Delete / Leave / Close / Hide". It leads in exactly one place: the **logs row menu**,
39
+
where `Retry` and `Cancel Run` are the primary actions on a failed run and sit at the top, with
40
+
the rule beneath them. Ordering follows the surface (see "The rule" above); the separator simply
41
+
fences whichever end the consequential group occupies. A menu whose consequential actions are
42
+
merely *disabled* still gets no extra rule — `disabled` is not a group.
43
+
44
+
```tsx
45
+
// ✗ Bad — four semantic bands the user meets nowhere else
This is the failure that put a dangling rule at the bottom of the logs row menu, where two
86
+
unconditional separators sat above conditional items.
87
+
88
+
**Do not add a prop to move a rule.** The shared workflow context menu grew
89
+
`groupNonDestructiveActions` and `separateNavigationAction` for this; between them they moved one
90
+
separator for one caller, four of six branches were unreachable, and `separateNavigationAction`
91
+
had no observable effect anywhere in the repo. Both are gone. A menu that wants different
92
+
grouping wants the standard grouping.
93
+
29
94
## Encode the order once
30
95
31
96
An order duplicated across surfaces is an order that will drift. Export **one** constant and sort by it — do not hand-maintain a matching literal per menu.
Copy file name to clipboardExpand all lines: CLAUDE.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -386,7 +386,9 @@ Co-locate a `search-params.ts` per feature exporting the parser map (single sour
386
386
387
387
A list orders itself the way the user already reads the same things somewhere else. Resource menus (`+` attach, `@` mention, resource-tab `+`) mirror the **sidebar** top-down; a row or root **context menu** mirrors that surface's **toolbar**, left-to-right becoming top-to-bottom; tab strips mirror their nav. Platform-only entries (desktop Browser, Terminal) trail the shared set.
388
388
389
-
Encode the order in ONE exported constant and sort by it — never a hand-maintained literal per menu (`RESOURCE_MENU_ORDER` / `byResourceMenuOrder` in `home/components/mothership-view/components/resource-registry`). Render mixed item kinds in a single ordered pass; emitting all submenu-backed families and then all flat ones silently pins every submenu to the top no matter what the constant says. Divergence is allowed only for search ranking, user-controlled ordering, and recency. Full rule in `.claude/rules/sim-list-ordering.md`.
389
+
Encode the order in ONE exported constant and sort by it — never a hand-maintained literal per menu (`RESOURCE_MENU_ORDER` / `byResourceMenuOrder` in `home/components/mothership-view/components/resource-registry`). Render mixed item kinds in a single ordered pass; emitting all submenu-backed families and then all flat ones silently pins every submenu to the top no matter what the constant says. Divergence is allowed only for search ranking, user-controlled ordering, and recency.
390
+
391
+
**Grouping**: at most ONE `DropdownMenuSeparator` per menu, fencing the consequential group — immediately before Delete/Leave/Close/Hide in almost every menu, and immediately after Retry/Cancel Run in the logs row menu, where those lead. No toolbar in the app renders a divider, so multi-band menus teach a taxonomy that exists on no other surface. Build each separator's guard from the EXACT render conditions of the items on both sides — a looser guard is what leaves a dangling rule when its group is conditional. Never add a prop to move a rule. Full rule in `.claude/rules/sim-list-ordering.md`.
Copy file name to clipboardExpand all lines: apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/components/browser-session/browser-tab-strip.tsx
-2Lines changed: 0 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -216,9 +216,7 @@ export function BrowserTabStrip({
Copy file name to clipboardExpand all lines: apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/components/chunk-context-menu/chunk-context-menu.tsx
Copy file name to clipboardExpand all lines: apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/document-context-menu/document-context-menu.tsx
+3-11Lines changed: 3 additions & 11 deletions
Original file line number
Diff line number
Diff line change
@@ -71,6 +71,7 @@ export function DocumentContextMenu({
Copy file name to clipboardExpand all lines: apps/sim/app/workspace/[workspaceId]/knowledge/components/knowledge-base-context-menu/knowledge-base-context-menu.tsx
0 commit comments