fix: move board notifications

- Remove the board-level shell title bar
- Move notifications into the board header
- Keep sidebar offset only on session routes
This commit is contained in:
codebanditssss 2026-06-30 19:53:33 +05:30
parent 78cbe22928
commit 62bee4f568
3 changed files with 72 additions and 73 deletions

View File

@ -6,6 +6,7 @@ import { type AttentionZone, type WorkspaceSession, attentionZone, workerSession
import { useSessionScmSummary, type SessionPRSummary } from "../hooks/useSessionScmSummary";
import { useWorkspaceQuery, workspaceQueryKey } from "../hooks/useWorkspaceQuery";
import { DashboardSubhead } from "./DashboardSubhead";
import { NotificationCenter } from "./NotificationCenter";
import { OrchestratorIcon } from "./icons";
import { NewTaskDialog } from "./NewTaskDialog";
import { spawnOrchestrator } from "../lib/spawn-orchestrator";
@ -126,6 +127,7 @@ export function SessionsBoard({ projectId }: SessionsBoardProps) {
const actions = projectId ? (
<>
<NotificationCenter />
<button
aria-label="New task"
className="dashboard-app-header__accent-btn"
@ -146,7 +148,9 @@ export function SessionsBoard({ projectId }: SessionsBoardProps) {
{isSpawning ? "Spawning..." : orchestrator ? "Orchestrator" : "Spawn Orchestrator"}
</button>
</>
) : undefined;
) : (
<NotificationCenter />
);
return (
<div className="flex h-full min-h-0 flex-col bg-background text-foreground">

View File

@ -2,7 +2,6 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useNavigate, useParams } from "@tanstack/react-router";
import { GitBranch, LayoutDashboard, PanelRightClose, PanelRightOpen, Plus, Square, Trash2 } from "lucide-react";
import { useState } from "react";
import { NotificationCenter } from "./NotificationCenter";
import {
findProjectOrchestrator,
isOrchestratorSession,
@ -70,11 +69,13 @@ export function ShellTopbar() {
// removed, or data still loading) shows an empty crumb — never the raw
// route slug. "agent-orchestrator" is the root-board crumb only.
const projectId = session?.workspaceId ?? params.projectId;
const isProjectBoardRoute = !isSessionRoute && Boolean(projectId);
const project = projectId ? all.find((workspace) => workspace.id === projectId) : undefined;
const projectLabel = project?.name ?? session?.workspaceName ?? (projectId ? "" : "agent-orchestrator");
const projectLabel = session?.workspaceName ?? "";
const orchestrator = projectId ? findProjectOrchestrator(all, projectId) : undefined;
if (!isSessionRoute) {
return null;
}
const openBoard = () =>
projectId ? void navigate({ to: "/projects/$projectId", params: { projectId } }) : void navigate({ to: "/" });
@ -132,7 +133,7 @@ export function ShellTopbar() {
return (
<header className={cn("dashboard-app-header", isMac && "is-under-titlebar-nav")} style={dragStyle}>
<div className="session-topbar__lead">
{isSessionRoute && isOrchestrator ? (
{isOrchestrator ? (
<div className="topbar-project-pills-group">
<div className="topbar-project-line">
<span className="dashboard-app-header__project">{projectLabel}</span>
@ -145,7 +146,7 @@ export function ShellTopbar() {
</span>
</div>
</div>
) : isSessionRoute ? (
) : (
<div className="session-topbar__identity">
<div className="session-topbar__branch">
<GitBranch className="h-3 w-3 shrink-0" aria-hidden="true" />
@ -153,79 +154,70 @@ export function ShellTopbar() {
</div>
{session ? <SessionStatusPill session={session} /> : null}
</div>
) : isProjectBoardRoute ? null : (
<div className="topbar-project-line">
<span className="dashboard-app-header__project">{projectLabel}</span>
</div>
)}
</div>
<div className="dashboard-app-header__spacer" />
<div className="dashboard-app-header__actions">
<NotificationCenter style={noDragStyle} />
{isSessionRoute ? (
{isOrchestrator ? (
<>
{isOrchestrator ? (
<>
<button
aria-label="New task"
className="dashboard-app-header__primary-btn"
onClick={openNewTask}
style={noDragStyle}
type="button"
>
<Plus className="h-3.5 w-3.5" aria-hidden="true" />
New task
</button>
<button
aria-label="Open Kanban"
className="dashboard-app-header__accent-btn"
onClick={openBoard}
style={noDragStyle}
type="button"
>
<LayoutDashboard className="h-3.5 w-3.5" aria-hidden="true" />
Kanban
</button>
</>
) : null}
{/* Kill control sits beside the orchestrator link for active workers
moved here from the inspector's Summary "Danger zone". */}
{!isOrchestrator && session && sessionIsActive(session) ? <TopbarKillButton session={session} /> : null}
{!isOrchestrator && (
<button
aria-label="Open orchestrator"
className="dashboard-app-header__primary-btn dashboard-app-header__primary-btn--compact"
disabled={isSpawning}
onClick={() => void openOrchestrator()}
style={noDragStyle}
type="button"
>
<OrchestratorIcon className="h-3.5 w-3.5" aria-hidden="true" />
{isSpawning ? "Spawning…" : "Orchestrator"}
</button>
)}
{/* Inspector collapse (worker sessions only — orchestrators have no rail). */}
{!isOrchestrator && (
<button
aria-label={isInspectorOpen ? "Close inspector panel" : "Open inspector panel"}
aria-pressed={isInspectorOpen}
className="dashboard-app-header__icon-btn"
onClick={toggleInspector}
style={noDragStyle}
title={`${isInspectorOpen ? "Close" : "Open"} inspector · ⌘⇧B`}
type="button"
>
{isInspectorOpen ? (
<PanelRightClose className="h-[15px] w-[15px]" aria-hidden="true" />
) : (
<PanelRightOpen className="h-[15px] w-[15px]" aria-hidden="true" />
)}
</button>
)}
<button
aria-label="New task"
className="dashboard-app-header__primary-btn"
onClick={openNewTask}
style={noDragStyle}
type="button"
>
<Plus className="h-3.5 w-3.5" aria-hidden="true" />
New task
</button>
<button
aria-label="Open Kanban"
className="dashboard-app-header__accent-btn"
onClick={openBoard}
style={noDragStyle}
type="button"
>
<LayoutDashboard className="h-3.5 w-3.5" aria-hidden="true" />
Kanban
</button>
</>
) : null}
{/* Kill control sits beside the orchestrator link for active workers
moved here from the inspector's Summary "Danger zone". */}
{!isOrchestrator && session && sessionIsActive(session) ? <TopbarKillButton session={session} /> : null}
{!isOrchestrator && (
<button
aria-label="Open orchestrator"
className="dashboard-app-header__primary-btn dashboard-app-header__primary-btn--compact"
disabled={isSpawning}
onClick={() => void openOrchestrator()}
style={noDragStyle}
type="button"
>
<OrchestratorIcon className="h-3.5 w-3.5" aria-hidden="true" />
{isSpawning ? "Spawning…" : "Orchestrator"}
</button>
)}
{/* Inspector collapse (worker sessions only — orchestrators have no rail). */}
{!isOrchestrator && (
<button
aria-label={isInspectorOpen ? "Close inspector panel" : "Open inspector panel"}
aria-pressed={isInspectorOpen}
className="dashboard-app-header__icon-btn"
onClick={toggleInspector}
style={noDragStyle}
title={`${isInspectorOpen ? "Close" : "Open"} inspector · ⌘⇧B`}
type="button"
>
{isInspectorOpen ? (
<PanelRightClose className="h-[15px] w-[15px]" aria-hidden="true" />
) : (
<PanelRightOpen className="h-[15px] w-[15px]" aria-hidden="true" />
)}
</button>
)}
</div>
<NewTaskDialog
open={isNewTaskOpen}

View File

@ -1,4 +1,4 @@
import { createFileRoute, Outlet, useNavigate } from "@tanstack/react-router";
import { createFileRoute, Outlet, useMatchRoute, useNavigate } from "@tanstack/react-router";
import { useQueryClient } from "@tanstack/react-query";
import { type CSSProperties, useCallback, useEffect } from "react";
import { ShellTopbar } from "../components/ShellTopbar";
@ -40,11 +40,14 @@ function errorMessage(error: unknown) {
// instead of Zustand. The daemon-status effect runs here exactly once.
function ShellLayout() {
const navigate = useNavigate();
const matchRoute = useMatchRoute();
const queryClient = useQueryClient();
const workspaceQuery = useWorkspaceQuery();
const workspaces = workspaceQuery.data ?? [];
const daemonStatus = useDaemonStatus(queryClient);
const { theme, setTheme, isSidebarOpen, toggleSidebar } = useUiStore();
const isSessionRoute = Boolean(matchRoute({ to: "/projects/$projectId/sessions/$sessionId", fuzzy: true })) ||
Boolean(matchRoute({ to: "/sessions/$sessionId", fuzzy: true }));
const updateWorkspaces = useCallback(
(updater: (workspaces: WorkspaceSummary[]) => WorkspaceSummary[]) => {
@ -185,7 +188,7 @@ function ShellLayout() {
>
<Sidebar
daemonStatus={daemonStatus}
underTopbar
underTopbar={isSessionRoute}
onCreateProject={createProject}
onRemoveProject={removeProject}
workspaceError={workspaceQuery.isError ? errorMessage(workspaceQuery.error) : undefined}