[feat] Reorganize the navigation rail to the Sidebar - #6738
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 SummarySummary by CodeRabbit
WalkthroughThe sidebar now uses shared release navigation, session search, keyboard shortcuts, and help menus across web and mobile. The standalone Agents entity and changelog banners were removed. Navigation sizing, selected colors, filtering, and drag-click handling were updated. ChangesSidebar navigation update
Priority: ➖ Normal Estimated code review effort: 4 (Complex) | ~45 minutes Merge Risk: 🔵 Low · up to One small repository-policy issue remains in a sidebar source comment; runtime navigation behavior is unaffected. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Railway Preview Environment
|
4ae0238 to
ea15a8e
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Advanced
Run ID: 39ddf9c8-c185-4b51-b0b9-a0f0a03bf703
📒 Files selected for processing (39)
web/mobile/src/features/nav/DrawerProjectSwitcher.tsxweb/mobile/src/features/nav/useMobileNavItems.tsxweb/oss/src/components/Sidebar/components/ProjectOrgSwitcher/index.tsxweb/oss/src/components/Sidebar/dynamic/useSidebarDynamicChildren.tsxweb/oss/src/components/Sidebar/hooks/useSidebarConfig/index.tsxweb/oss/src/components/Sidebar/scopes/bottomSection.tsxweb/oss/src/components/Sidebar/scopes/mainScope.tsxweb/oss/src/styles/theme/palette.tsweb/packages/agenta-navigation-ui/src/NavMenu.tsxweb/packages/agenta-navigation-ui/src/ProjectOrgSwitcher.tsxweb/packages/agenta-navigation-ui/src/SessionFilterMenu.tsxweb/packages/agenta-navigation-ui/src/SessionSearchButton.tsxweb/packages/agenta-navigation-ui/src/SessionSearchPalette.tsxweb/packages/agenta-navigation-ui/src/SidebarIconMenu.tsxweb/packages/agenta-navigation-ui/src/SidebarLogo.tsxweb/packages/agenta-navigation-ui/src/SidebarShell.tsxweb/packages/agenta-navigation-ui/src/SidebarToggleButton.tsxweb/packages/agenta-navigation-ui/src/index.tsweb/packages/agenta-navigation-ui/src/releaseItems.tsxweb/packages/agenta-navigation-ui/src/reorder/engine.tsweb/packages/agenta-navigation/src/banners/state.tsweb/packages/agenta-navigation/src/banners/types.tsweb/packages/agenta-navigation/src/dynamic/registry.tsweb/packages/agenta-navigation/src/dynamic/sessionsSource.tsweb/packages/agenta-navigation/src/dynamic/types.tsweb/packages/agenta-navigation/src/dynamic/useSidebarDynamicChildren.tsweb/packages/agenta-navigation/src/index.tsweb/packages/agenta-navigation/src/releases/changelog.jsonweb/packages/agenta-navigation/src/releases/index.tsweb/packages/agenta-navigation/src/reorder/applyOrder.tsweb/packages/agenta-navigation/src/reorder/manualOrder.tsweb/packages/agenta-navigation/src/supportLinks.tsweb/packages/agenta-navigation/tests/unit/manualOrder.test.tsweb/packages/agenta-navigation/tests/unit/sidebarChildren.test.tsweb/packages/agenta-sessions-ui/src/SessionRowActions.tsxweb/packages/agenta-ui/src/components/presentational/filter/FilterMenu.tsxweb/packages/agenta-ui/src/components/presentational/filter/index.tsweb/packages/agenta-ui/src/components/presentational/index.tsweb/packages/agenta-ui/src/styles/theme-variables.css
💤 Files with no reviewable changes (5)
- web/packages/agenta-navigation/src/reorder/applyOrder.ts
- web/packages/agenta-ui/src/components/presentational/index.ts
- web/oss/src/components/Sidebar/dynamic/useSidebarDynamicChildren.tsx
- web/packages/agenta-ui/src/components/presentational/filter/index.ts
- web/packages/agenta-ui/src/components/presentational/filter/FilterMenu.tsx
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.
| const moved = !next.every((id, index) => id === state.ids[index]) | ||
| // The pointerup's click dies when the gesture was really a drag: the order changed, or the | ||
| // pointer travelled far enough that nobody meant it as a click (a drag back to the origin | ||
| // must not navigate the row or toggle the heading). It does NOT die for a press that drifted | ||
| // a few pixels past DRAG_THRESHOLD_PX and landed where it started — suppressing that is what | ||
| // made a heading take two clicks to toggle. | ||
| if (moved || state.maxTravel > CLICK_TRAVEL_PX) suppressClick = true |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- engine outline ---'
ast-grep outline web/packages/agenta-navigation-ui/src/reorder/engine.ts
printf '%s\n' '--- engine excerpt ---'
sed -n '1,240p' web/packages/agenta-navigation-ui/src/reorder/engine.ts
printf '%s\n' '--- related symbols and tests ---'
rg -n --glob '!node_modules' --glob '!dist' 'endDrag|onPointerUp|CLICK_TRAVEL_PX|DRAG_THRESHOLD_PX|pointerY|maxTravel' web/packages/agenta-navigation-ui/src/reorder web/packages/agenta-navigation-ui -g '*test*' -g '*spec*' -g '*.ts' -g '*.tsx'Repository: Agenta-AI/agenta
Length of output: 15077
🤖 get_repo_knowledge executed:
get_repo_knowledge Agenta-AI/agenta /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/conventions /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/learnings
Length of output: 17047
🏁 Script executed:
sed -n '1,240p' web/packages/agenta-navigation-ui/src/reorder/engine.tsRepository: Agenta-AI/agenta
Length of output: 9133
🏁 Script executed:
#!/bin/bash
set -eu
cat -n web/packages/agenta-navigation-ui/src/reorder/engine.ts | sed -n '1,230p'
printf '%s\n' '--- tests and callers ---'
rg -n -C 4 'endDrag|onPointerUp|pointerup|CLICK_TRAVEL_PX|DRAG_THRESHOLD_PX|resolveDrop' web/packages/agenta-navigation-ui -g '*.ts' -g '*.tsx' -g '*test*' -g '*spec*'Repository: Agenta-AI/agenta
Length of output: 21611
Update the active pointer state before resolving the drop.
endDrag(true) uses state.pointerY for the drop index and state.maxTravel for click suppression. onPointerUp ignores its PointerEvent, so final movement after the last pointermove can produce a stale drop index or click-suppression decision. Update pointerX, pointerY, and maxTravel before calling endDrag(true). Add a regression test for this case.
There was a problem hiding this comment.
Fixed. onPointerUp now writes pointerX, pointerY and maxTravel from the release event before calling endDrag(true).
Worth noting the maxTravel half is on me: I added that dependency in this PR when I made click suppression depend on peak travel rather than suppressing unconditionally, so a stale value could have let a real drag's click through. The drop-index staleness predates it.
No regression test: @agenta/navigation-ui has no unit test setup (the package's tests live in @agenta/navigation, which does not contain the engine), so adding one means standing up a harness for a pointer-event integration test. I verified the two cases by driving synthetic pointer sequences against the running rail instead: a 6px drifting click toggles a group heading on the first click, and a 40px drag that returns to its origin still has its click suppressed.
| tabIndex={0} | ||
| aria-label="Search sessions" | ||
| title="Search sessions" | ||
| className="flex size-5 shrink-0 cursor-pointer items-center justify-center rounded text-colorTextTertiary hover:bg-colorFillQuaternary hover:text-colorText" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use the theme-aware focus ring. The browser ring remains visible, but the trigger has no project-defined focus state for light and dark themes. Add focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-focus-ring.
There was a problem hiding this comment.
Fixed. Added outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-focus-ring, matching what NavMenu's LeafRow already uses for its keyboard-reachable rows.
| enabled: Boolean(projectId) && search.length > 0, | ||
| staleTime: 30_000, | ||
| // Hold the previous rows while the next keystroke resolves, so the list does not blink. | ||
| placeholderData: (previous: SessionStream[] | null | undefined) => previous, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🤖 get_repo_knowledge executed:
get_repo_knowledge Agenta-AI/agenta /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/learnings /tmp/coderabbit-repo-knowledge/agenta-ai-agenta-4b53879a/conventions
Length of output: 17531
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- target excerpt ---'
sed -n '820,950p' web/packages/agenta-navigation/src/dynamic/sessionsSource.ts
printf '%s\n' '--- relevant symbols and imports ---'
rg -n -C 3 'sessionSearchQueryAtom|placeholderData|projectIdAtom|SessionStream|use.*Session|queryKey' web/packages/agenta-navigation/src/dynamic/sessionsSource.tsRepository: Agenta-AI/agenta
Length of output: 13271
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- package versions and query adapter bindings ---'
rg -n -C 3 '"jotai-tanstack-query"|"`@tanstack/react-query`"|"`@tanstack/query-core`"' web/package.json web/packages/*/package.json web/pnpm-lock.yaml pnpm-lock.yaml 2>/dev/null || true
printf '%s\n' '--- search atom consumers and project switch state ---'
rg -n -C 4 'sidebarSessionSearch(Query|Open|Results|Loading)Atom|projectIdAtom' web/packages/agenta-navigation/src web/packages/agenta-navigation 2>/dev/null | head -240
printf '%s\n' '--- local query helper context ---'
sed -n '135,170p' web/packages/agenta-navigation/src/dynamic/sessionsSource.tsRepository: Agenta-AI/agenta
Length of output: 40291
🌐 Web query:
TanStack Query v5 placeholderData function previousData previousQuery queryKey official documentation
💡 Result:
In TanStack Query v5, the placeholderData option allows a query to display specific data while it is in the pending state [1][2]. When a function is provided to placeholderData, it receives two arguments: (previousData, previousQuery) [2][3]. The function signature is: placeholderData: (previousData: TData | undefined, previousQuery: Query | undefined) => TData | undefined Arguments: 1. previousData: The data from the previously successful query, if available [2][3]. 2. previousQuery: The complete instance of the previous Query object [2]. This functionality is commonly used to implement paginated queries, where you can keep displaying "old" data while new data is being fetched, preventing UI loading states from jumping [1][4]. The library provides a built-in helper called keepPreviousData, which is an identity function that returns the previousData; using placeholderData: keepPreviousData is the standard way to achieve this behavior in v5 [4][3]. When placeholder data is active, the result object will have the isPlaceholderData flag set to true [1][2]. Unlike initialData, placeholderData is not persisted to the cache [1][5].
Citations:
- 1: https://tanstack.com/query/v5/docs/framework/react/guides/placeholder-query-data
- 2: https://tanstack.com/query/v5/docs/framework/react/reference/useQuery
- 3: https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5
- 4: https://tanstack.com/query/v5/docs/framework/react/guides/paginated-queries
- 5: https://tanstack.com/query/v5/docs/framework/vue/guides/placeholder-query-data
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- direct search atom consumers ---'
rg -n -C 5 'sidebarSessionSearch(Open|Query|Results|Loading)Atom' web --glob '*.{ts,tsx,js,jsx}' | head -220
printf '%s\n' '--- projectId declaration and writers ---'
rg -n -C 5 'export .*projectIdAtom|const projectIdAtom|set\(projectIdAtom|projectIdAtom,' web/packages/agenta-shared web/packages/agenta-navigation web/oss web 2>/dev/null | head -220Repository: Agenta-AI/agenta
Length of output: 30243
Scope placeholder data by project. When projectIdAtom changes, placeholderData can return session rows from the previous query while the project-keyed request loads. Compare previousQuery?.queryKey[1] with projectId and return undefined on mismatch. Otherwise, prior-project session metadata can render in the sidebar.
Source: Coding guidelines
There was a problem hiding this comment.
Fixed. placeholderData now compares previousQuery?.queryKey[1] with projectId and returns undefined on a mismatch, so it only holds rows within the same project.
This is the same guard keepPreviousDataWithinProject applies to the rail's own session queries a few hundred lines up in this file. I wrote the palette's atom without it, which is exactly the case that helper exists for.
fc965a2 to
4362add
Compare
ea15a8e to
4a7b7c2
Compare
4362add to
094afd9
Compare
4a7b7c2 to
b6d0b4e
Compare
b6d0b4e to
9a687bb
Compare
9a687bb to
423f5d3
Compare
📘 Docs preview
This comment updates in place on every push. |
Website previewPreview URL: https://pr-6738-agenta-website-preview.mahmoud-637.workers.dev Built from |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Advanced
Run ID: 5fe6dedb-b0cb-4678-b3ca-2ea2db9de9d8
📒 Files selected for processing (8)
web/mobile/src/features/nav/DrawerProjectSwitcher.tsxweb/mobile/src/features/nav/useMobileNavItems.tsxweb/oss/src/components/Sidebar/hooks/useSidebarConfig/index.tsxweb/packages/agenta-navigation-ui/src/SessionFilterMenu.tsxweb/packages/agenta-navigation-ui/src/SessionSearchButton.tsxweb/packages/agenta-navigation-ui/src/reorder/engine.tsweb/packages/agenta-navigation/src/dynamic/sessionsSource.tsweb/packages/agenta-navigation/src/index.ts
Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.
| const query = get(sidebarAgentActivityQueryAtomFamily(scopeId)) | ||
| return { | ||
| any: (query.data?.length ?? 0) > 0, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use a separate all-session query for sidebarHasAnySessionAtomFamily. sidebarAgentActivityQueryAtomFamily excludes trigger sessions for agent ranking. In an automation-only project, any is false, so SessionFilterMenu returns null and hides the Automation filter. Keep the ranking query chat-only and derive any from a project-scoped query that includes trigger sessions.
acb62ea to
782c8e4
Compare
423f5d3 to
2d943fb
Compare
Blank agent becomes New agent over one line of what it does, and the entry takes a tile like the templates under it so the menu reads as one list of alternatives rather than a button above a list.
A sticky header drops its own bottom margin, or a 4px slot of rows shows through as they pass under it. The first run pays it back as padding instead, so a row's hover fill no longer sits flush on the rule.
The header, the group headings and the rows each inset their content by 8px, so everything inside the table started 8px in from the column the page title and the toolbar keep — the first heading and the first cell under it both sat off that line. The inset goes from all of them at once. That is the part that matters: the header's content box has to stay identical to a row's, or the two resolve their grid tracks differently and every column but the first drifts off its cells. A row then takes the space back as bleed rather than as inset: its box grows 12px on each side and its padding gives the same 12px back, so the hover fill clears the text it covers while the text itself stays on the table's edge, and the content box — and so the tracks — never move.
The view a reader sets — which roster, whose agents, what state, how the rows group — and the pure derivation over it, kept out of the screen so the screen renders what this returns rather than deriving it mid-render. The same split sessionListView.ts makes next door. Type is deliberately absent from the predicates: it picks WHICH roster the screen fetches, so rows already match it by the time they arrive. Status is the one state an agent actually has here — whether a session of its own is blocked on a person. The design's Active/Paused/Needs-attention belongs to an automation, which has a trigger to pause; an agent has none.
…esign Brings the rail to option 1b of the Claude Design "Sidebar Reorg" project, and moves three things that were sitting in the wrong place. Density. Rows are 26px at 13px where they were 28px at 14px, the brand row is 32px with an 80x18 wordmark instead of 48px, and session titles drop to 12px with 10px status glyphs, so the session pane reads as a list under the nav rather than as more nav. Session rows line up with the nav. The 22px indent and the vertical guide line are gone for groups that carry no collapse control, which is what pushed every status dot out of the column the Home, Agents and Sessions icons share. Keyed on alwaysOpen rather than on the Sessions key: a group you cannot collapse is a section of the rail, and its rows are rail rows. The Evaluation group, which you do open, keeps its indent and its line. Agents is a plain row. Its dynamic child list is gone; an agent list in the rail was a second, shorter answer to a question the Agents page already answers in full, and the caret it needed made the row look like the Sessions group, which is the rail's only real list. That removed the last caller of sidebarAgentRanksAtomFamily, so it goes too, along with withManualAgentRanks and the 'agents' drag zone behind it. The agent headings under Sessions keep their own zone and their own counts. Releases leave the banner queue. They read as a "What's new?" list inside the help menu now. A release is news, not a task: it does not need clearing, and eleven of them queued two at a time made it feel like one. The queue keeps star-repo and the trial/upgrade banners EE injects, which are tasks. Help becomes an icon button on the switcher row, drawing the same flyout the collapsed rail draws. Book a call comes out and Keyboard shortcuts takes its place, which gives the shortcuts sheet a visible way in; it had been reachable only through a bare '?' hotkey that teaches nobody. Session search. A magnifier beside the filter opens a palette backed by a debounced server search. Filtering the rail's own fifty-row window would search the top of the list and call everything else missing, which is the one case a search exists for. The rail's filter uses the shared menu. SessionFilterMenu went from 220 lines to a section map over @agenta/ui/filter-menu, the same panel the automations list opens, and the superseded presentational/filter/FilterMenu is deleted; this was its last caller. Dark selection stops shouting. The selected row painted an olive wash with accent-yellow text and no ring, the loudest thing on a rail whose job is to sit still, and it disagreed with light. One rule in both themes now: a raised surface, a hairline, and the text left alone. Dark is #242424 on the #101010 rail with a #292929 ring, changed at the source in palette.ts with the tokens regenerated. Verified on the running mobile app throughout, measuring geometry in the DOM: session glyphs and nav icons both at left 20px, brand row exactly 32px, collapsed icons 28px with 4px between them, and the three bottom controls stepping evenly. tsc clean on oss and mobile, eslint clean, 82 navigation unit tests pass (down from 86: the four withManualAgentRanks cases described a helper that no longer exists).
Creators come from the org's member roster under the same cache key the settings screen already reads, so arriving from Settings costs no request and the two surfaces cannot disagree about a name. Archived agents need a second query: the shared apps list omits include_archived because the nav rail reads absence there as archived (#6457), so flipping it would break the rail. It is gated on the facet and keyed under agent-workflows, so archiving an agent invalidates both this list and the live one in the same pass.
The rail no longer draws a banner card. The Sidebar Reorg design has no card there, and after the changelog cards moved into the help menu's "What's new?" list and the star-repo ask went with them (the same menu links GitHub), nothing OSS or mobile showed was left. Drops the banner model (`@agenta/navigation` banners: config types, priority/dismissal atoms, the `additionalBannersAtom` seam), the `SidebarBanner`/`SidebarBanners` renderers, the OSS `SidePanel/Subscription` shim, and the footer mounts in the desktop main scope and the mobile scope. The `footer` slot on `SidebarScope` stays: it is shell contract, not banner code. EE: its `SidePanel/Subscription` shadow module injected trial/upgrade banners through the seam removed here, so it goes with this.
Additive package changes only: agentConfigSummary names the integration behind each gateway-connection tool, NextTriggersSection's row derivation moves into a useUpcomingTriggers hook a host with its own card chrome can call, and composioLogo is exported for any integration key outside PROVIDERS.
The roster is the shared ListTable — the frame the sessions and automations lists already use — with this app's columns, the shared agent kebab, and rename in place from a row rather than through a modal. Search sits in a ListTableToolbar beside the shared FilterMenu carrying Created by, Type, Status and Group by. A workflow becomes a row in one place, so no cell re-derives a creator's name or a waiting count from lookup maps handed down beside it. Every state is designed: skeleton, empty, no-match and a failed fetch with a retry — a request that never answered must not read as an empty project.
Reverts the density pass. Rows return to h-7 / 14px / leading-7 with their 4px margin, group headings to pt-2, session titles to the row's own size, and the status glyphs to 12/12/10. The 26px/13px column read as one packed list with no breathing room next to ChatGPT, Manus and the rail we shipped before. The alignment work stays: session glyphs still sit in the nav icons' column, and the logo and collapsed rail keep their smaller geometry.
The overview reads the way the Agent Overview design does: a description and an Open chat verb in the header, Home's composer with voice, then one activity list under Sessions | Automation runs tabs with the shared filter menu (status, window, grouping) instead of two stacked cards. The rail is three soft cards owned by this app — Configuration with stacked integration marks, Files with Open drive, Automations with a clock or bolt per trigger — built on the sessions table's frame and the entity-ui hooks, so no desktop chrome changes. Usage is dropped, as designed.
… map main replaced filterAgentWorkflows(workflows, latestRevisions) with selectAgentWorkflows over a per-project agent-flags map (#classify agents once per project), and this hook still called the old name — the mobile typecheck and image build failed on it after the rebase. ensureAgentFlags is the better fit anyway: the shared map already covers archived workflows, so the second round trip this hook used to make for their latest revisions is now a cache hit.
The gateway-tool surface is a list of connected apps (Gmail, Slack), and "tool" also names the tool CALLS a transcript shows — two things under one word. This app now says Integrations for the connected-app concept: the settings tab, its nav entries, the connections table, and the agent overview's config row. oss/ee keep their wording, so the rename is a mobile copy layer (web/mobile/src/lib/integrationsCopy.ts) over shared components that now take an optional copy prop and default to the old strings.
The shared filter menu's flyout is 188px, sized for words like "Last 30 days". Agent names are longer — "Search Console Assistant" truncated to "Search Consol…" — so a section can now ask for a `wide` flyout, which matches the panel's own 248px. Only the Agent facet opts in, in the rail's session filter and the sessions page's.
The description under the overview's title edits the way the name does: tap it (or Edit description in the kebab) and it becomes a one-line input; Enter commits, Esc cancels, blank clears. An agent with no description shows the same line as an 'Add a description' prompt, so the header keeps one shape. The line truncates at the composer column's width. Package pieces, all additive: useUpdateAgentDescription beside useRenameAgent, an optional Edit description entry on AgentActionsMenu, allowEmpty on useInlineRename, and updateWorkflow treating an empty description as a change rather than skipping the request.
Rows drop from 50px to 40px. ListTable gains a density prop rather than a global change, because the lists it frames are not the same length: sessions runs to hundreds of rows, where 13px above and below each is a screen of air per hundred, while an automations list is a dozen a reader scans once. Compact is 8px; the default is untouched, so the automations and agents tables keep their rhythm. The skeleton takes the same value as the rows, so loading holds the rhythm the rows arrive in. The rename input drops to the kebab's height, the tallest thing in a resting row, so a row being renamed stays the height of its neighbours. Its own lane above the agents page: that branch and the sessions one both edit ListTable, in that order, so this had nowhere lower to land without breaking one of them.
The Type row held only Active/Archived, two entries to say one bit; it is now an "Only archived" toggle row.
Repo rule (web/AGENTS.md): at most one short line per comment.
61f03be to
eb75bc2
Compare
13b405f to
aba8a76
Compare
…design [feat] Redesign the mobile agent overview
…rows [feat] Tighten the session rows
[feat] Redesign the mobile agents page
[feat] Call tools "integrations" in the mobile app
aac1f3e
into
feat/mobile-automations
Context
The navigation rail had drifted from the Sidebar Reorg design (option 1b in the Claude Design project). Rows were 28px at 14px where the design draws 26px at 13px, the brand row took 48px for what is an 18px wordmark, and session rows sat behind a 22px indent and a vertical guide line. That indent pushed every status dot out of the column the Home, Agents and Sessions icons share, so the rail read as two lists that did not line up.
Three things were also in the wrong place. The changelog shipped as sidebar banner cards you dismissed one at a time. Help and Docs took a full-width row in the footer, the widest thing there. And the Sessions group had its own filter popover, written before the shared one existed, so the automations list and the rail drew the same control two different ways.
Stacked on
feat/mobile-home-focus, so the base is that branch and this PR shows only its own commit. It replaces #6715, which was opened against a base that has since been rewritten.Changes
Density. Rows are 26px at 13px, the brand row is 32px with an 80x18 wordmark, and session titles drop to 12px with 10px status glyphs, so the session pane reads as a list under the nav rather than as more nav.
Session rows line up with the nav. The guide line and the 22px indent are gone for groups that carry no collapse control. Keyed on
alwaysOpenrather than on the Sessions key: a group you cannot collapse is a section of the rail, and its rows are rail rows. The Evaluation group, which you do open, keeps its indent and its line.Agents is a plain row. Its dynamic child list is gone. An agent list in the rail was a second, shorter answer to a question the Agents page already answers in full, and the caret it needed made the row look like the Sessions group, which is the rail's only real list. That removed the last caller of
sidebarAgentRanksAtomFamily, so it goes too, along withwithManualAgentRanksand theagentsdrag zone behind it. The agent headings under Sessions keep their own separate zone and their own counts.Releases leave the banner queue and read as a "What's new?" list inside the help menu. A release is news, not a task: it does not need clearing, and eleven of them queued two at a time made it feel like one. The queue keeps star-repo and the trial/upgrade banners EE injects, which are tasks.
Help becomes an icon button on the switcher row, drawing the same flyout the collapsed rail draws. Book a call comes out and Keyboard shortcuts takes its place, which gives the shortcuts sheet a visible way in. It had been reachable only through a bare
?hotkey.Session search. A magnifier beside the filter opens a palette backed by a debounced server search. Filtering the rail's own fifty-row window would search the top of the list and call everything else missing, which is the one case a search exists for.
The rail's filter uses the shared menu.
SessionFilterMenuwent from 220 lines to a section map over@agenta/ui/filter-menu, the same panel the automations list opens, and the supersededpresentational/filter/FilterMenuis deleted. This was its last caller.Empty states say less. An
alwaysOpengroup renders nothing at all when its source is ready with no rows, instead of "No sessions yet" under a heading that already says Sessions, and the filter control hides with it. A filter that matched nothing still speaks, because that state is one you have to act on, and the filter stays so you can widen it again. Placeholder lines render as prose rather than as rows, so they stop looking like broken sessions.Dark selection stops shouting. The selected row painted an olive wash with accent-yellow text and no ring, the loudest thing on a rail whose job is to sit still, and it disagreed with light. One rule in both themes now: a raised surface, a hairline, and the text left alone.
Before (dark):
bg #57572a,text #d1d151, no ringAfter (dark):
bg #242424on the#101010rail,text rgba(255,255,255,0.85),ring #292929Changed at the source in
palette.tswith the tokens regenerated.Tests
tsc --noEmitclean onossandmobile;eslintclean across the touched packages.pnpm --filter @agenta/navigation test: 82 pass. Down from 86 because the fourwithManualAgentRankscases described a helper that no longer exists./mthroughout, measuring geometry in the DOM rather than by eye: session glyphs and nav icons both atleft: 20px, brand row exactly 32px, collapsed icons 28px with 4px between them, and the rail's right-hand controls sharing one centre line at 237px.Four defects were found and fixed during review rather than shipped.
NavMenucomposed row classes withclsx, so a session row'stext-[12px]lost toROW_BASE'stext-[13px]on stylesheet order (both row renderers now usecn). The ported Agent filter row never checked "All agents", which is its default state. Nav rows compressed belowh-[26px]when the rail overflowed, because they could shrink and the scrolling group did not absorb it. And a group heading needed two clicks to toggle: a press that drifted past the 5px drag threshold armed a drag whose click was then suppressed even though nothing moved, so the suppression now needs the order to change or the pointer's peak travel to pass 12px.One thing a reviewer should weigh:
hideWhenEmptyis safe only on a group with no collapse control, and nothing enforces that. Set it on a collapsible entity and the group deadlocks, because empty children strip the caret, the key is never published as open, and the gated source can never fetch the rows that would bring the caret back. The constraint currently lives in a doc comment.Demo
Outstanding for the desktop rail. Every shared component was verified against the running mobile app on
/m, which mounts the sameSidebarShell,NavMenu,ProjectOrgSwitcher, filter menu and help menu, but I could not capture the desktop app on this branch. Worth a look there before merge.What to QA
/m: the mobile drawer and docked rail share every one of these components. Check the nav, the session list and the switcher there too.