Page and route#
/jobs, rendered by Jobs() in walmart-mvp/frontend/src/pages/Jobs.tsx, mounted through walmart-mvp/frontend/src/App.tsx's router outlet.
What the reader sees#
Every batch of parts imported, one row per job, showing its part count, current pipeline stage, and how many parts still need review. A two-facet toolbar narrows by stage and owner; clicking a row expands a stage-by-stage progress tracker and the parts inside that job. A "New job" button routes to the import flow.
Layer 1: shell#
walmart-mvp is the kit's one real AppShell consumer (packages/ui/docs/app-shell.md:15). App.tsx mounts one AppShell instance for both the authenticated and the auth-boot states, deliberately the same instance so the two can never visually drift (App.tsx:436-453, 501-539; the source comment at app-shell.md:45 names this directly). The shell supplies logo, nav built from buildNav() (App.tsx:64-105), a WorkspaceSwitcher in sidebarTop (App.tsx:506-514), and a SidebarUserMenu in sidebarFooter (App.tsx:515-519). topbar.title is a breadcrumb-shaped Crumb component (App.tsx:142-156, 440, 505); search, actions, and user go unused, matching app-shell.md:26's note that this is the only shipped consumer and it only fills title.
Jobs.tsx itself renders no shell chrome. Its outermost element is a content wrapper, <div className="mx-auto flex max-w-400 flex-col gap-6"> (Jobs.tsx:831), inside whatever <Outlet> the shell's content area provides.
Layer 2: composition#
docs/design-language/09-page-composition.md's "Portable checklist (for walmart-mvp)" (09-page-composition.md:59-66) is the doc's own bridge from speedway's shell to a second consumer app; it asks for one default reading width and fixed composition order. Jobs.tsx opens with PageTitle (:832-855), then a conditional PageError/TableSkeleton/EmptyState/Card branch (:884-998) holding the toolbar and table, matching doc 9 §A4's order even though walmart has no ShellHandle-driven layout mode of its own.
Layer 3: primitives#
| Primitive | Props as called | file:line | Contract doc |
|---|---|---|---|
PageTitle | Icon={appIcon.jobs}, title="Jobs", subtitle, titleExtra (a clickable StatusPill filter toggle), actions (Refresh + New job) | Jobs.tsx:832-882 | packages/ui/docs/page-title.md (its own Sanctioned-combinations example, cited at page-title.md:46) |
StatusPill | kind="review", count={...}, wrapped in a <button aria-pressed> for the "in review" title-side filter | Jobs.tsx:845-852 | packages/ui/docs/status.md (its own Sanctioned-combinations example, cited at status.md:39) |
Card | shadow="sm", wraps the toolbar and table as one surface | Jobs.tsx:912 | packages/ui/docs/card.md |
DataTable<JobListEntry> | bleed, showSearch, renderRowDetail, expandedKeys, rowMenu, minWidth="1400px", className="table-fixed" | Jobs.tsx:951-996 | packages/ui/docs/table.md |
Tooltip | wraps the Stage pill when onStageClick is set, and the flagged-count link | Jobs.tsx:130-142, 166-177 | packages/ui/docs/tooltip.md |
EmptyState | Icon={appIcon.jobs}, title="No jobs yet", action a real Button (not raw daisyUI) | Jobs.tsx:899-910 | packages/ui/docs/empty-state.md |
ConfirmModal<JobListEntry> | preset="delete", message a function of the row, onConfirm={confirmDeleteJob} | Jobs.tsx:1004-1014 | inherits Button's promisify guard (button.md:94-97) |
Layer 4: patterns#
- Workflow stepper (
/patterns/workflow-stepper):StageStepper(Jobs.tsx:363-492), rendered insiderenderRowDetail(Jobs.tsx:959-966), draws the pattern's own "numbered knobs, completion-colored connectors" directly, including a done/active/blocked tri-state per stage circle (Jobs.tsx:384-433). - Shape-matched skeleton (
/patterns/shape-matched-skeleton):TableSkeleton<JobListEntry>with a matchingToolbarSkeleton(Jobs.tsx:897) mirrors the real toolbar's facet count so nothing resizes when data lands.
Layer 5: canon rules in force#
packages/ui/docs/app-shell.md:15, 45:AppShellmounted once for both boot and loaded states.docs/design-language/08-navigation-and-shell.md§B (:44-45): nav badges render nothing when a count isundefined, matchingApp.tsx:51-62'sCountPillreturningnullonvalue == null.docs/design-language/06-tables.md§A4 (:26-27): columns encode meaning via factories;buildJobsColumns(Jobs.tsx:77-246) builds each cell explicitly rather than letting a raw value fall through.packages/ui/docs/page-title.mdandpackages/ui/docs/status.mdboth cite this exact page'stitleExtrablock as their own Sanctioned-combinations reference example, not merely a compliant usage elsewhere.
Lapses#
FacetToolbar duplicates the kit's FacetBar. Jobs.tsx:913-950 renders FacetToolbar (walmart-mvp/frontend/src/components/FacetToolbar.tsx), an app-local component with its own Facet/MultiFacet types, rather than the kit's FacetBar<T>. This is not an oversight; packages/ui/docs/table.md:159-174 states plainly that FacetBar shipped 2026-08-14 and "both real apps use bespoke toolbars today; they adopt FacetBar at their next deliberate kit upgrade." The fix is that upgrade, not a patch to this page.
A page width hand-typed differently from a sibling page. Jobs.tsx:831 wraps its content in max-w-400; walmart-mvp/frontend/src/pages/ImportParts.tsx:295 wraps its own content in max-w-6xl. docs/design-language/09-page-composition.md's portable checklist for walmart-mvp asks for "one default reading width..., applied by container class, never per-element" (09-page-composition.md:62). Two different hand-typed max-widths on two sibling pages of the same app is exactly the per-element drift that checklist item warns against. Neither page reads as visibly broken alone; the drift only shows up by reading both, which is what this pair of docs does.
See also#
docs/breakdowns/04-walmart-import.md, the sibling page carrying the other half of the width-class finding above.packages/ui/docs/app-shell.md, the shell this page and every other walmart-mvp page sits inside./patterns/workflow-stepper, the pattern page this jobs table's expanded row instantiates.