feat(dashboard): remove the top navbar, move its chrome into the sidebar - #1128
Merged
Conversation
Reclaim the full window height for the workspace (max space, like the old vike.dev). The global top navbar is gone; everything it held moves into the left sidebar, which becomes the app's chrome: - Brand mark + wordmark at the top of the sidebar. - Overview is its own item, pinned above the session list and given prominence, carrying the Human Queue count. - The project selector is a separate element (no longer fused with Overview). Its exact filter-vs-navigate behaviour is still open; today's navigate-on- select stays as the interim. - The utility controls (Local/remote connection, theme, notifications, Settings) sit in a sidebar footer. The controls are threaded into RunHistory as optional callbacks (no-op default), so its focused unit test still mounts the rail without wiring the shell; that test stubs the three chrome pieces that would otherwise drag telefunc into jsdom.
…cus ring Addressing feedback on the navbar removal: - Order is now New, Overview, then the project selector (Overview moved up out of the content into the header, directly under New). - New no longer takes an "active" fill: it is an action, not a view, so only the current nav item (Overview) is highlighted. Both used to look selected on the Overview. - The scroll viewport's focus ring is gone. It painted a green box down the sidebar edge whenever the rail took focus; a scroll region is not a control, so it stays focusable for keyboard scrolling but without the outline.
Refine the active rule so exactly one nav item is highlighted per view: New is active on a project's own launcher (project open, no run selected), and the Overview item is active on the Overview (no project). The two conditions are mutually exclusive, so they never both light up.
- Logo mark a touch bigger (h-5 -> h-6). - New and Overview now share the same box (h-9 px-2 gap-2), so their icons and labels line up exactly; New's default px-4 was insetting it past Overview. - Tighten the header gap (gap-3 -> gap-1) so New and Overview read as one nav group, with a little breathing room kept under the brand.
Replace the project-picker dropdown with a "Projects" nav row in the same style as Overview (icon + label + chevron). It expands into an indented sub-list of projects with the connecting rule the reference draws, each with the activated dot the picker used and the selected one highlighted, plus an "Add project" row. Selecting a project still navigates into it (the interim, pending the filter-vs- navigate call). Starts open when a project is selected so the active one shows. Retires ProjectPicker (and its test): nothing else used it.
- A little space below the logo and below the nav group (before Recents). - Drop the medium weight from the nav items (New/Overview/Projects) so they read as plain rows; the active fill still marks the current one. - Drop the bold from the session title in each Recents row.
Push New down with a clearer gap below the logo, and tighten the gap between the nav rows (New/Overview/Projects) so they stack as one compact group.
Let the nav rows (New/Overview/Projects) size to their content with py-1.5 padding rather than a fixed h-9 height. New overrides the button size default (h-9/py-2) with h-auto/py-1.5 to match.
- Projects nav no longer auto-opens on a project URL; it starts collapsed and you open it to switch projects. - Push the Recents label down a little and drop its medium weight.
… on hover - Keep the rows (and the active card) clear of the overlaid scrollbar (pr-3). - Drop the bold from the session title: it was inheriting the button base's font-medium, now overridden with font-normal. - Fade the truncated title's end (like the reference) and marquee it on row hover by exactly its overflow, so a long title reads without a tooltip. Self-measures via container-query units, so short titles never move; respects reduced-motion.
The title clipped at its own edge, a row-padding inside the card, so the cut sat mid-card. Bleed the title to the card border (cancel the row's px-2, re-add it as inner padding so the text still starts in the same place), and fade both borders while marqueeing so the title dissolves at each card edge.
Right-side inner padding was insetting the content box, so the marquee revealed only to a row-padding short of the border. Keep the inner pad on the left only (text still aligns with the subtitle), leaving the right free to reach the border.
Remove the negative margin and left inner padding; the title reads better clipped at its own edge.
…rows The card carries no horizontal padding now, so the title spans edge to edge and its clip/fade land on the border; the subtitle/badge row keeps its own px-2 inset.
…; pad the title The button base contributes px-4, so dropping my px-2 left the card padded, not flush. Force px-0 on the card and put px-2 on the title itself, so the text aligns with the subtitle while overflow still clips at the card border.
…lows A short title showed the fade gradient even though it was not truncated. Measure overflow in RunRow and gate the mask and the marquee on an is-overflowing class, so a title that fits shows plainly.
Widen the end gradient from 1.25rem to 3rem so a long title dissolves more.
- Drop the uppercase on the Recents label (plain "Recents"). - Make the label sticky to the top of the scroll, and add a sticky gradient strip under it (background -> transparent) so rows dissolve into the bg as they scroll up beneath the label.
…oser Make the gradient strip absolute (hanging just below the sticky label) instead of taking flow space, so the first row sits right under Recents; it still overlays the rows that scroll up beneath it.
Add rounded-none so the sticky label's background covers fully, with no rounded corners letting content peek through.
The strip dimmed the first row at rest. Drive its opacity from the rail's scroll position (the same scroll-timeline the chat log's scroll-fade uses): invisible at the top, fading in as the list scrolls, so it only overlays rows that pass under it.
Each toolbar reader blanked to empty on a session switch (use-async resets to the initial on any dep change) and refilled on its own timeline, so the left cluster vanished and popped and the GitHub/PR data arrived late, shifting the row. Add an opt-in keepPrevious to the async hooks and use it for the two display reads: git status (branch/dirty/PR) and the GitHub URL. The toolbar now keeps its resolved header visible and updates it in place instead of blanking. As a bonus, GitStatusBar no longer blanks when only its poll rate changes (prPending 10s->1s). Handoff is left as-is on purpose: its value also drives the push / Open PR buttons, so holding a stale copy could briefly offer the wrong action.
…chevron The chevron used to appear only when there were changes or an expandable handoff, so it popped in and out with the git/handoff data. Make it always available and give it a stable "about this run" panel: the agent and the spend so far (cost, tokens, cache, turns — folded from the #322 usage events), above the existing changes/handoff file detail (kept). Branch/dirty/PR stay in the bar row above, so they are not repeated. Starts collapsed.
Replace the row of icon buttons (GitHub, open folder, open in editor, Serve, Stop, Remove worktree, Delete, Open session) with a single ⋮ overflow menu, so the bar stops growing and shifting as a run's state changes. Serve keeps its state (Serve -> Open/Stop, or a picker submenu in a multi-app repo) and the editor keeps its preferred-editor submenu. The handoff's Push / Open PR stay visible in the bar, since they move the work forward rather than just opening it somewhere. - New SessionActionsMenu owns all of it; ConfirmDialog gains a controlled mode so Delete can open from a menu item (a menu item cannot also be a dialog trigger). - Retire DeleteSessionButton and RemoveWorktreeButton (their logic moved into the menu); WorkspaceActions stays for the project home. Coverage moves to a new SessionActionsMenu test (menu contents, folder target, delete-confirm flow).
Prefix the session name in the action bar with its project as a breadcrumb — "project / session" — so the toolbar says which project the session belongs to. The project part is muted and gives up width first, so a long project name truncates before the session name does. Threaded projectName from the page (already computed there) down through RunView and RunActionBar to GitStatusBar.
…tus line - Remove the bottom border from the session toolbar (RunActionBar). - The run's status line no longer repeats the session name: it showed the agent's self-reported name only when there was one, so the "stopped" banner read inconsistently (with a name for some sessions, without for others). The action bar's breadcrumb now names the session, so the run view hides it (showName=false) and the line just shows the state; the relay watch and project home keep it.
`pnpm dev` alone is the Vite dev server with no Telefunc context, so sendStart reports "starting a session is not enabled on this server" and you cannot start a run there (only the daemon has the startRun handler). Add `pnpm dev:daemon` (FRAMEWORK_DEV_DAEMON=1): a serve-only Vite plugin that brings up the daemon via the framework's own idempotent ensureDaemon (reusing one already running) and proxies /_telefunc (RPCs and the SSE Channel) to it, so the live-reload UI gets the full backend, run-starting included. The proxy middleware registers ahead of Telefunc's own and holds requests until the daemon is up. Default `pnpm dev` is unchanged (no daemon spawned). The daemon is detached and outlives the dev server; stop it with `the-framework stop`.
Tested pnpm dev:daemon end to end and fixed two issues: - Resolve the framework bin via import.meta.resolve, not require.resolve: the package is ESM-only (no CJS main), so require.resolve threw and the daemon never started. Pass it as binPath so ensureDaemon re-invokes the framework, not vite. - When the daemon is not up, the /_telefunc middleware now falls through to Vite's own handling instead of 503ing every request (which flooded telefunc client errors); reads keep working, only starting a run is unavailable. Verified: the dev server proxies /_telefunc to the daemon (same response as the daemon direct), "starting runs is enabled", no error flood.
suleimansh
marked this pull request as ready for review
July 24, 2026 22:08
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.
Closes #1127. Follow-up to #772.
Removes the global top navbar and moves everything it held into the left sidebar, so the workspace and right rail get the full window height (max space usage).
What moved
Implementation notes
+Pagedrops the<header>and threads the controls' callbacks (onDashboard,onSelectProject,onSettings,working,interventionCount) intoRunHistory, which now composes the sidebar chrome around the runs list.RunHistory's focused unit test still mounts the rail on its own; that test stubs the three chrome pieces (theme/notifications/connection) that would otherwise drag the preferences/devices telefunc shims into jsdom.Verification
pnpm typecheckclean;pnpm test423/423.pnpm build+ prerender succeed.Still open (parked, see #1127)
The project element's behavior: navigate into a project (today) vs filter the Overview session list. Kept navigate-on-select as the interim so nothing is blocked.