Agent docs

Speedway: jobs list

The jobs list, layer by layer, a bespoke shell wrapping a work surface built almost entirely from one shared table component.

Page and route#

/workspaces/:id/jobs, the index route inside the jobs prefix (speedway/app/routes.ts:74-75). Rendered by speedway/app/routes/workspaces/jobs/jobs.tsx.

What the reader sees#

Every module run in the workspace, one row per job, each showing its current stage and how many parts still need review. A "New job" menu opens the create flow for a full workflow or a single module. A workspace with no jobs yet shows a create prompt instead of an empty table.

Layer 1: shell#

Every signed-in route sits inside one layout, speedway/app/routes/shell.tsx, registered once at routes.ts:24-123. Its ShellFrame component reads the deepest matched route's handle and renders WorkspaceNav, ShellCrumbs, and an OrgActivityRail around the page's own outlet (shell.tsx:84-106). jobs.tsx declares handle.nav = { active: "jobs", layout: "list" } (jobs.tsx:30-33), which does two things: it tells WorkspaceNav which sidebar item is active, explicitly rather than by a path-prefix match, and it tells ShellFrame to add the fit-viewport class to .ws-shell (shell.tsx:85), which bounds the page to the browser viewport so the table owns its own scroll instead of the whole page scrolling.

WorkspaceNav composes the kit's standalone Sidebar primitive directly (speedway/app/components/WorkspaceNav.tsx:13), not the kit's AppShell composite. packages/ui/docs/app-shell.md:17 names this choice explicitly: speedway "built its own two-layer chrome... before or instead of adopting" AppShell, and imports zero symbols from it. ShellCrumbs is speedway's own hand-built breadcrumb trail (speedway/app/components/ShellCrumbs.tsx), not the kit's Breadcrumbs primitive.

Layer 2: composition#

docs/app-patterns/12-primitives-and-rules.md sorts canon rules by whether a kit primitive already retires them; the page-level composition order itself is ruled by docs/design-language/09-page-composition.md. That doc names two archetypes (§A1) and its own use-case table calls the jobs list out directly: "layout:"list", table scrolls in card, PageTitle + NewJobMenu actions" (09-page-composition.md:53), a work surface, not a reading page.

Inside the page, JobsHeader (jobs.tsx:186-196) sits outside the Suspense boundary that streams the job list in (jobs.tsx:198-229), so the title and the "New job" action never blank while data loads; only the table area falls back to WorkspaceSkeleton (jobs.tsx:201-205). Once resolved, JobsView (jobs.tsx:231-288) renders the header again inside a LIST_PANEL flex column (jobs.tsx:258), followed by either the empty state or the table, matching doc 9 §A4's fixed order: breadcrumbs, then PageTitle pinned shrink-0, then the table.

Layer 3: primitives#

PrimitiveProps as calledfile:lineContract doc
PageTitleIcon={PAGE_META.jobs.Icon}, title="Jobs", subtitle="Each time you run a module...", actions={<NewJobMenu wid={wid} />}jobs.tsx:188-194packages/ui/docs/page-title.md
Dropdown + ButtonNewJobMenu's trigger: variant="text" shade color="success" Icon="Plus", opening a Dropdown panel of workflow and module linksspeedway/app/components/NewJobMenu.tsx:61-93packages/ui/docs/dropdown.md, packages/ui/docs/button.md
EmptyStateclassName="mt-10", Icon="Table", title="No jobs yet", description="Create a job from your files...", action is a raw <Link>jobs.tsx:260-275packages/ui/docs/empty-state.md
DataTable<JobRowVM> (inside JobsTable)minWidth={extraAction ? "1536px" : "1436px"}, renderRowDetail conditional on the row's own expandabilityspeedway/app/components/JobsTable.tsx:842-889packages/ui/docs/table.md
StatusPill (inside JobsTable)kind per stage (err/warn/ok/neutral), Icon={STATUS_ICON.*}JobsTable.tsx:147-210packages/ui/docs/status.md

JobsTable is the app's one shared table component, reused across the jobs page and every module tab (docs/design-language/06-tables.md:36, "one implementation, reused"). This doc did not re-derive JobsTable's internal row-click behavior from its 948 lines; the characterization above about which prop renders which stage pill is read directly from the file, but the broader "navigate-or-expand duality" claim in Layer 5 below is the canon's own claim, not this doc's independent finding.

Layer 4: patterns#

  • Sidebar anatomy (/patterns/sidebar-anatomy): the grouped rail, known-only counts, and identity footer that WorkspaceNav renders are the shape this pattern documents, though the pattern page itself is built from the kit's AppShell/Sidebar, not from speedway's own component.
  • Shape-matched skeleton (/patterns/shape-matched-skeleton): the WorkspaceSkeleton fallback rendered inside jobs.tsx's Suspense (jobs.tsx:201-205, ~/components/WorkspaceSkeleton) is speedway's own instance of the "page and placeholder share one container map" idea this pattern names.

Layer 5: canon rules in force#

  • docs/design-language/08-navigation-and-shell.md §A1 (:15): "chrome is infrastructure a route declares into, never markup a page repeats." jobs.tsx renders no chrome of its own; everything is ShellHandle and page content.
  • Same doc §A3 (:21): active state must be explicit, never inferred by prefix. WorkspaceNav reads handle.nav.active (jobs.tsx:32), not a path match.
  • Same doc §A7 (:33): breadcrumbs earn their row only two or more levels deep.
  • docs/design-language/09-page-composition.md §A3 (:23): viewport bounding is opt-in and named through layout: "list", never hand-built per page. §A4 (:26) fixes the composition order this page follows.
  • docs/design-language/06-tables.md §A2 (:20): "row click means exactly one thing per table." The doc's own §C (:69) characterizes JobsTable as satisfying this through a navigate-or-expand split, where the name link carries navigation and the row carries expansion; this doc cites that claim rather than re-deriving it.

Lapses#

A third instance of raw daisyUI button classes. jobs.tsx:267-273 fills EmptyState's action slot with a raw <Link className="btn btn-primary btn-sm"> rather than the kit's Button wrapped with linkAs. packages/ui/docs/button.md's Banned section (button.md:67) names raw daisyUI btn classes as "cautioned" and lists exactly two bounded, documented deviations (dense editable grids, the kit's own ModalFooter); this call site is not one of the two and is not flagged there. It is, however, the exact block empty-state.md cites as its own reference example for a true-empty state (empty-state.md:45), so the two contract docs disagree about whether this specific line is sanctioned or cautioned. Fix, if this page is ever touched again: swap the raw anchor for <Button href={...} linkAs={Link} content="New job" />, or update button.md's caution list to name this as a third documented deviation.

See also#

@versable-git/ui · reference, canon, and method, read in place