Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 113 additions & 6 deletions apps/web/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,125 @@
flex-direction: column;
}

.shell-main-toolbar {
position: absolute;
top: 0.5rem;
right: 0.75rem;
z-index: 10;
.shell-main-content {
display: flex;
min-height: 0;
flex: 1;
flex-direction: column;
}

.shell-main-content {
/* Column 2: three-band contextual panel. */
.shell-contextual-panel {
display: flex;
width: var(--shell-contextual-width);
flex-shrink: 0;
flex-direction: column;
gap: 0;
overflow: hidden;
border-right: 1px solid var(--border);
background: var(--card);
}

.panel-band {
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 0.75rem;
border-bottom: 1px solid var(--border);
min-height: 0;
}

.panel-band-page-specific {
flex: 1;
overflow-y: auto;
border-bottom: none;
}

.panel-page-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 0.5rem;
}

.panel-page-identity {
min-width: 0;
}

.panel-page-title {
margin: 0;
font-size: 0.9375rem;
font-weight: 600;
letter-spacing: -0.01em;
color: var(--foreground);
}

.panel-page-subtitle {
margin: 0.125rem 0 0;
font-size: 0.75rem;
line-height: 1.35;
color: var(--muted-foreground);
}

.panel-page-tools {
display: flex;
flex-shrink: 0;
align-items: center;
gap: 0.125rem;
}

.panel-page-actions {
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
}

.panel-band-heading {
margin: 0;
font-size: 0.6875rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--muted-foreground);
}

.panel-band-subheading {
margin: 0;
padding: 0.25rem 0.5rem 0.125rem;
font-size: 0.6875rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--muted-foreground);
}

.panel-muted {
margin: 0;
font-size: 0.75rem;
line-height: 1.4;
color: var(--muted-foreground);
}

.panel-stack {
display: flex;
flex-direction: column;
gap: 0.125rem;
}

.panel-stack-group {
display: flex;
flex-direction: column;
gap: 0.125rem;
}

/* Page-local toolbars replace TopBar action clusters (search, view toggle)
that still need component state on the page. Identity lives in the panel. */
.page-toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem 0;
}

/* Column 4: collapses to zero width rather than being merely hidden, so the
Expand Down
54 changes: 19 additions & 35 deletions apps/web/src/pages/agents-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@ import {
TableHeader,
TableRow,
Tabs,
TopBar,
TopBarActions,
TopBarTitle,
ViewToggle,
formatRelativeTime,
} from "@corbits/react-ui";
import type { BadgeTone, ViewMode } from "@corbits/react-ui";
import { Bot, Copy, Plus, Workflow } from "lucide-react";
import { useState } from "react";
import { Bot, Copy, Workflow } from "lucide-react";
import { useEffect, useState } from "react";
import type { ReactNode } from "react";
import { useQueryClient } from "@tanstack/react-query";

Expand All @@ -30,7 +27,6 @@ import type { AgentDirectoryData } from "../agents-api";
import type { APIQuery } from "../api";
import { useAgentDirectory } from "../agents-api";
import { useBench } from "../bench-context";
import { countProp } from "../optional-props";
import { tenantKeys } from "../query-client";
import { QueryView } from "../query-view";
import { CreateAgentDialog } from "./create-agent-dialog";
Expand Down Expand Up @@ -275,40 +271,28 @@ export function AgentsPage({
const [viewMode, setViewMode] = useState<ViewMode>("grid");
const [tab, setTab] = useState<AgentsTab>(initialTab);
const [createOpen, setCreateOpen] = useState(false);

const isReady = directory.kind === "ready";
const canCreate =
directory.kind === "ready" && directory.data.tenantId !== "";

useEffect(() => {
const onCreate = () => {
if (canCreate) setCreateOpen(true);
};
window.addEventListener("workbench:agents:create", onCreate);
return () =>
window.removeEventListener("workbench:agents:create", onCreate);
}, [canCreate]);

return (
<>
<TopBar>
<TopBarTitle
{...countProp(
isReady
? purposeAgentDefinitions(directory.data.definitions).length
: undefined,
)}
subtitle="Agent definitions this bench can launch, and the instances running from them"
>
Agents
</TopBarTitle>
<TopBarActions>
<LibrarySearchInput
label="Search agents"
value={query}
onChange={setQuery}
/>
<ViewToggle mode={viewMode} onChange={setViewMode} />
<Button
type="button"
onClick={() => setCreateOpen(true)}
disabled={!canCreate}
>
<Plus /> Create agent
</Button>
</TopBarActions>
</TopBar>
<div className="page-toolbar">
<LibrarySearchInput
label="Search agents"
value={query}
onChange={setQuery}
/>
<ViewToggle mode={viewMode} onChange={setViewMode} />
</div>
<PageShellBody>
<QueryView query={directory} label="your agents">
{(data) => {
Expand Down
13 changes: 0 additions & 13 deletions apps/web/src/pages/approvals-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import {
DialogTitle,
EmptyState,
PageShell,
TopBar,
TopBarTitle,
} from "@corbits/react-ui";
import type { ApprovalRequest } from "@corbits/react-ui";
import { ShieldCheck } from "lucide-react";
Expand All @@ -36,7 +34,6 @@ import {
NeedsYouSchema,
useAPIQuery,
} from "../api";
import { countProp } from "../optional-props";
import type { APIQuery, NeedsYouItem } from "../api";
import { useBench } from "../bench-context";
import { tenantKeys } from "../query-client";
Expand All @@ -61,16 +58,6 @@ export function ApprovalsPage({

return (
<>
<TopBar>
<TopBarTitle
{...countProp(
approvals.kind === "ready" ? approvals.data.length : undefined,
)}
subtitle="Requests waiting on a human decision, on the current bench"
>
Approvals
</TopBarTitle>
</TopBar>
<PageShell width="full" className="page-fill">
<QueryView query={approvals} label="approvals">
{(rows) =>
Expand Down
94 changes: 37 additions & 57 deletions apps/web/src/pages/home-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import {
Skeleton,
StatGrid,
StatTile,
TopBar,
TopBarTitle,
} from "@corbits/react-ui";
import type { ReactNode } from "react";

Expand All @@ -18,7 +16,6 @@ import { PrincipalsSchema, ProfileSchema, RunsSchema } from "../api";
import type { APIQuery, PrincipalsPage, Profile, RunsPage } from "../api";
import { Link } from "../navigation";
import { purposeRuns } from "../purpose-runs";
import { subtitleProp } from "../optional-props";
import { SignedOutNotice } from "../query-view";

const SHORTCUTS = [
Expand Down Expand Up @@ -69,60 +66,43 @@ export function HomePage({
const greeting =
profile.kind === "ready" ? `Welcome back, ${profile.data.name}` : "Welcome";
return (
<>
<TopBar>
<TopBarTitle
{...subtitleProp(
profile.kind === "ready" ? profile.data.email : undefined,
)}
>
Home
</TopBarTitle>
</TopBar>
<PageShell width="full" className="page-fill">
{profile.kind === "unauthenticated" ? (
<SignedOutNotice />
) : (
<>
<Section
title={greeting}
description="A live snapshot of your benches and what is running in them."
>
<StatGrid>
<StatTile label="Benches" value={tileValue(principals)} />
<StatTile
label="Active workflows"
value={workflowTileValue(runs)}
/>
</StatGrid>
</Section>
<Section
title="Jump in"
description="The main surfaces of this workbench."
>
<div className="card-grid">
{SHORTCUTS.map((shortcut) => (
<Link
key={shortcut.to}
to={shortcut.to}
className="card-link"
>
<Card>
<CardHeader>
<CardTitle>{shortcut.title}</CardTitle>
<CardDescription>
{shortcut.description}
</CardDescription>
</CardHeader>
</Card>
</Link>
))}
</div>
</Section>
</>
)}
</PageShell>
</>
<PageShell width="full" className="page-fill">
{profile.kind === "unauthenticated" ? (
<SignedOutNotice />
) : (
<>
<Section
title={greeting}
description="A live snapshot of your benches and what is running in them."
>
<StatGrid>
<StatTile label="Benches" value={tileValue(principals)} />
<StatTile
label="Active workflows"
value={workflowTileValue(runs)}
/>
</StatGrid>
</Section>
<Section
title="Jump in"
description="The main surfaces of this workbench."
>
<div className="card-grid">
{SHORTCUTS.map((shortcut) => (
<Link key={shortcut.to} to={shortcut.to} className="card-link">
<Card>
<CardHeader>
<CardTitle>{shortcut.title}</CardTitle>
<CardDescription>{shortcut.description}</CardDescription>
</CardHeader>
</Card>
</Link>
))}
</div>
</Section>
</>
)}
</PageShell>
);
}

Expand Down
Loading
Loading