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
6 changes: 0 additions & 6 deletions apps/web/src/pages/library-page.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
/* Artifacts and Skills list pages (mockups: artifacts.html, skills.html). */
.page-lede {
margin: 0 0 var(--space-4, 1rem);
color: var(--ink-soft);
font-size: 0.9375rem;
}

.library-row-title {
display: inline-flex;
align-items: center;
Expand Down
21 changes: 10 additions & 11 deletions apps/web/src/pages/library-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
MenuContent,
MenuItem,
MenuTrigger,
PageShell,
RichEmptyState,
SelectionCheckbox,
Skeleton,
Expand Down Expand Up @@ -75,6 +74,7 @@ import {
uploadArtifactFiles,
uploadMimeTypeFromSource,
} from "../shell/library-artifacts";
import { PageLayout } from "../shell/page-layout";
import { StageTopBar } from "../shell/stage-top-bar";

const SORT_LABEL: Record<ArtifactSort, string> = {
Expand Down Expand Up @@ -499,8 +499,7 @@ export function LibraryPage({
) : null}
<div className="flex min-h-0 flex-1">
<div className="min-h-0 min-w-0 flex-1 overflow-auto">
<PageShell width="full" className="page-fill">
<p className="page-lede px-4 sm:px-7">Everything your workers made. Yours to keep.</p>
<PageLayout title="Artifacts" subtitle="Everything your workers made. Yours to keep.">
{artifacts.length === 0 ? (
<RichEmptyState
icon={<Stack />}
Expand All @@ -514,7 +513,7 @@ export function LibraryPage({
description={`No file matches "${activeQuery}".`}
/>
) : (
<div className="px-4 pb-5 sm:px-7">
<div>
<ArtifactRows
artifacts={visible}
now={now}
Expand All @@ -524,7 +523,7 @@ export function LibraryPage({
/>
</div>
)}
</PageShell>
</PageLayout>
</div>
{activeSelected !== null ? (
<div className="hidden w-[min(28rem,40%)] shrink-0 md:flex md:flex-col">
Expand Down Expand Up @@ -622,13 +621,13 @@ export function LibraryRoute({ path }: { readonly path: string }) {
return (
<div className="flex h-full min-h-0 flex-col">
<StageTopBar crumbs={[{ label: "Artifacts" }]} />
<PageShell width="full" className="page-fill">
<PageLayout title="Artifacts" subtitle="Everything your workers made. Yours to keep.">
<RichEmptyState
icon={<Stack />}
title="Select a workbench"
description="Open a workbench to browse the artifacts it owns."
/>
</PageShell>
</PageLayout>
</div>
);
}
Expand All @@ -637,13 +636,13 @@ export function LibraryRoute({ path }: { readonly path: string }) {
return (
<div className="flex h-full min-h-0 flex-col">
<StageTopBar crumbs={[{ label: "Artifacts" }]} />
<PageShell width="full" className="page-fill">
<PageLayout title="Artifacts" subtitle="Everything your workers made. Yours to keep.">
<RichEmptyState
icon={<Stack />}
title="Artifacts not configured"
description="Artifacts isn't set up yet. Ask your workbench admin to finish setup."
/>
</PageShell>
</PageLayout>
</div>
);
}
Expand All @@ -652,7 +651,7 @@ export function LibraryRoute({ path }: { readonly path: string }) {
return (
<div className="flex h-full min-h-0 flex-col">
<StageTopBar crumbs={[{ label: "Artifacts" }]} />
<PageShell width="full" className="page-fill">
<PageLayout title="Artifacts" subtitle="Everything your workers made. Yours to keep.">
{page.kind === "loading" ? (
<ListSkeleton />
) : page.kind === "unauthenticated" ? (
Expand All @@ -664,7 +663,7 @@ export function LibraryRoute({ path }: { readonly path: string }) {
description={describeApiError({ status: page.status }, "loading your artifacts")}
/>
)}
</PageShell>
</PageLayout>
</div>
);
}
Expand Down
10 changes: 6 additions & 4 deletions apps/web/src/pages/routines-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { GlobalRoutineRow } from "../global-routines";
import { routineDetailPath } from "../global-routines";
import { Link } from "../navigation";
import { benchLink, useFromBench } from "../shell/page-crumbs";
import { PageLayout } from "../shell/page-layout";
import { StageTopBar } from "../shell/stage-top-bar";
import { RoutinePill, formatWhen, routineState, useRoutineRuns } from "./routine-ui";

Expand Down Expand Up @@ -81,9 +82,10 @@ export function GlobalRoutinesList({
.includes(needle),
);
return (
<div className="routines-page">
<h1>Workflows</h1>
<p className="routines-lede">Deployed workflows, when they run, and how the last run went.</p>
<PageLayout
title="Workflows"
subtitle="Deployed workflows, when they run, and how the last run went."
>
<input
className="routines-filter"
placeholder="Filter workflows"
Expand All @@ -101,7 +103,7 @@ export function GlobalRoutinesList({
/>
))}
</ul>
</div>
</PageLayout>
);
}

Expand Down
22 changes: 0 additions & 22 deletions apps/web/src/pages/routines.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,6 @@
font-size: 13.5px;
}

.routines-page {
display: flex;
flex-direction: column;
gap: 16px;
max-width: 960px;
width: 100%;
margin: 0 auto;
padding: 24px 16px;
}

.routines-page h1 {
margin: 0;
font-size: 24px;
font-weight: 800;
}

.routines-lede {
margin: 0;
color: var(--ink-3);
font-size: 13.5px;
}

.routine-rows {
list-style: none;
margin: 0;
Expand Down
14 changes: 8 additions & 6 deletions apps/web/src/pages/skills-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// catalog — skills are authored here, private by default or shared.

import {
PageShell,
Button,
EmptyState,
RichEmptyState,
Expand All @@ -29,6 +28,7 @@ import { CreateSkillDialog, type SkillCreateInput } from "./create-skill-dialog"
import { useBench } from "../bench-context";
import { SKILLS_PATH_PREFIX } from "../path-ids";
import { skillDisplayName } from "../skill-display-name";
import { PageLayout } from "../shell/page-layout";
import { StageTopBar } from "../shell/stage-top-bar";

type RegistryState =
Expand Down Expand Up @@ -113,12 +113,15 @@ export function SkillsPage({
<StageTopBar
crumbs={crumbs}
{...(filter === undefined ? {} : { filter: { label: "Filter skills", ...filter } })}
actions={actions}
/>
<div className="min-h-0 flex-1 overflow-y-auto">
<PageShell width="full" className="page-fill">
<PageLayout
title="Skills"
subtitle="Know-how your workers draw on. Ask for more in any bench."
actions={actions}
>
{body}
</PageShell>
</PageLayout>
</div>
</div>
);
Expand Down Expand Up @@ -189,8 +192,7 @@ export function SkillsPage({
description={`Nothing matches “${query.trim()}”.`}
/>
) : (
<div className="px-4 pb-5 sm:px-7">
<p className="page-lede">Know-how your workers draw on. Ask for more in any bench.</p>
<div>
<Table aria-label="Skills">
<TableHeader>
<TableRow>
Expand Down
44 changes: 33 additions & 11 deletions apps/web/src/pages/workers-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// the sidebar's "+" menu.

import { useState } from "react";
import { Button, PageShell, RichEmptyState, toast } from "@corbits/react-ui";
import { Robot } from "@/lib/icons";
import { Button, RichEmptyState, toast } from "@corbits/react-ui";
import { Plus, Robot } from "@/lib/icons";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { reportError } from "@corbits/error-sink";

Expand All @@ -15,7 +15,9 @@ import { describeRestartFailure, redeployWorkbenchAgent } from "../workbench-cre
import { useBench } from "../bench-context";
import { Link } from "../navigation";
import { useTenantQuery } from "../routines-api";
import { PageLayout } from "../shell/page-layout";
import { StageTopBar } from "../shell/stage-top-bar";
import { CreateAgentPanel } from "./create-agent-panel";
import { WORKERS_PATH_PREFIX } from "../path-ids";

export type WorkerTone = "working" | "ready" | "idle";
Expand Down Expand Up @@ -94,7 +96,7 @@ export function WorkersRosterList({
<RichEmptyState
icon={<Robot />}
title="No workers yet"
description="Create a worker, a name and instructions, from the + menu and it appears here."
description="Create one with New worker and it appears here."
/>
);
}
Expand Down Expand Up @@ -202,22 +204,32 @@ export function WorkersRoute() {
benchMemberships.find((member) => member.tenantId === selectedTenantId)?.tenantName ??
"This workbench";

const queryClient = useQueryClient();
const [createOpen, setCreateOpen] = useState(false);

return (
<div className="flex h-full min-h-0 flex-col">
<StageTopBar
crumbs={[{ label: "Workers" }]}
subtitle="Each worker keeps its memory and asks before it writes anywhere."
/>
<StageTopBar crumbs={[{ label: "Workers" }]} />
<div className="min-h-0 flex-1 overflow-auto">
<PageShell width="full" className="page-fill">
<PageLayout
title="Workers"
subtitle="Each worker picks a name, keeps its memory, and asks before it writes anywhere."
actions={
selectedTenantId === null ? undefined : (
<Button size="sm" onClick={() => setCreateOpen(true)}>
<Plus /> New worker
</Button>
)
}
>
{selectedTenantId === null ? (
<RichEmptyState
icon={<Robot />}
title="Select a workbench"
description="Pick a workbench from the switcher to see its workers."
/>
) : (
<div className="px-4 pb-5 sm:px-7">
<>
<QueryView query={agentsQuery} label="your workers" skeleton="rows">
{(agents) => (
<WorkersRosterList
Expand All @@ -227,9 +239,19 @@ export function WorkersRoute() {
/>
)}
</QueryView>
</div>
<CreateAgentPanel
open={createOpen}
onOpenChange={setCreateOpen}
tenantId={selectedTenantId}
onCreated={() => {
void queryClient.invalidateQueries({
queryKey: tenantKeys.agents(selectedTenantId),
});
}}
/>
</>
)}
</PageShell>
</PageLayout>
</div>
</div>
);
Expand Down
42 changes: 42 additions & 0 deletions apps/web/src/shell/page-layout.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* One page column for the library pages (mockup .page / .page-narrow / .page-head). */
.page-layout {
width: 100%;
max-width: calc(864px + 48px);
margin: 0 auto;
padding: 32px 24px 64px;
box-sizing: border-box;
}

.page-layout-head {
display: flex;
align-items: flex-end;
gap: 16px;
margin-bottom: 24px;
}

.page-layout-head > div:first-child {
flex: 1;
min-width: 0;
}

.page-layout-head h1 {
margin: 0;
font-size: 26px;
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1.2;
}

.page-layout-lede {
margin: 6px 0 0;
max-width: 60ch;
color: var(--ink-2);
font-size: 15px;
}

.page-layout-actions {
display: flex;
flex: none;
align-items: center;
gap: 8px;
}
30 changes: 30 additions & 0 deletions apps/web/src/shell/page-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { ReactNode } from "react";

import "./page-layout.css";

export function PageLayout({
title,
subtitle,
actions,
children,
}: {
readonly title: string;
readonly subtitle?: ReactNode;
readonly actions?: ReactNode;
readonly children: ReactNode;
}) {
return (
<div className="page-layout">
<div className="page-layout-head">
<div>
<h1>{title}</h1>
{subtitle !== undefined ? <p className="page-layout-lede">{subtitle}</p> : null}
</div>
{actions !== undefined && actions !== null ? (
<div className="page-layout-actions">{actions}</div>
) : null}
</div>
{children}
</div>
);
}
Loading