- Fleet overview page with factory cards + recent jobs polling
- Job table with stage filter tabs
- Job detail page with events timeline, runs, artifacts, DAG subtree, SHIP action
- Budget page with usage bar, pause/resume controls
- API proxy route forwarding /api/fleet/* to platform-service
- Typed fleet-client.ts with graceful 404 degradation
- 16 unit tests for fleet-client (198 total tracker-web tests green)
- Added Fleet nav item to dashboard layout
- Full monorepo build + test green
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- packages/llm: use nullish coalescing (??) in GeminiProvider constructor
so explicit empty-string apiKey is not overridden by env var
- dashboards/admin-web,tracker-web: exclude .next/ from vitest test glob
to prevent Next.js internal test files from being picked up
- services/cowork-service: use platform-safe .kill() instead of SIGTERM
which is invalid on Windows
- packages/use-keyboard-shortcuts: add @testing-library/react devDep
- scripts/npmrc.template: use https:// for Gitea registry
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- UX-6 system banners DEFERRED: platform-service (:4003) is unreachable in this
environment, so there is no real broadcasts/maintenance feed to surface.
Per the wave's explicit condition, banners are not added against an empty feed.
Recorded in the waves list + Deferrals table with a follow-up.
- CC.1-CC.6 ticked: suite/build green every wave; dark-mode parity via the bridge;
zero new color literals; a11y labels on all new controls; charts/palette/motion
code-split via next/dynamic (chart chunk ~3.8 KB gzip); size:check has no
bundlesize config in-repo so gzip sizes recorded inline (follow-up logged).
- Add token-bridge guard test (CC.2/CC.3): asserts every --bl-* maps to an admin
var that flips under .dark and that the bridge contains no raw color literals.
Verify: typecheck+lint+build green (123 routes); vitest 22 files / 183 tests;
format:check no new failures (29 pre-existing); e2e 11 passed / 80 failed
(unchanged vs UX-1 baseline — environmental, no backend).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- @bytelyst/motion added workspace:* (importer-only lockfile change;
--frozen-lockfile clean).
- Dashboard overview only: KPI cards grid wrapped in StaggerList (from up,
50ms stagger); the Model-Usage / Recent-Users table row wrapped in Reveal.
- Primitives honor prefers-reduced-motion and resolve to opacity 1, so no
element is stranded transparent (no contrast/a11y regression); prefersReduced
is SSR-safe. Motion is confined to the auth-gated dashboard, not the public
e2e surfaces, per tracker-web's axe/opacity caution.
- vitest.config: inline @bytelyst/motion + react dedupe for the render test.
Tests: happy-dom asserts Reveal/StaggerList end visible and render all children.
Verify: typecheck+lint+build green (123 routes); vitest 21 files / 170 tests
(+2); format:check no new failures; e2e 11 passed / 80 failed (unchanged vs
UX-1 baseline — environmental).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- error.tsx -> ErrorPage (keep telemetry on mount; retry wired to Next reset).
- (dashboard)/loading.tsx -> LoadingSpinner inside the existing skeleton.
- not-found.tsx already used NotFoundPage (confirmed, unchanged).
- dashboard overview page.tsx header -> PageHeader (Refresh as actions; the
subtitle/last-updated line preserved directly below).
Rich detail headers (e.g. users/[id] back-button + plan/status badges) left
bespoke on purpose: PageHeader has no subtitle/badge slot, so forcing it would
regress them (additive-only rule). dashboard-components reads --color-* which
admin maps via @theme inline, so it themes in light + dark.
Verify: typecheck+lint+build green (123 routes); vitest 20 files / 168 tests
(+3 happy-dom chrome render tests); format:check no new failures; e2e 11 passed
/ 80 failed (unchanged vs UX-1 baseline — environmental).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Mount CommandRegistryProvider in (dashboard)/layout.tsx and a CommandMenu
that binds the global Cmd-K / Ctrl-K hotkey (useCommandPalette) and lazy-loads
the dialog via next/dynamic (own chunk; dynamic target is a local re-export
command-palette-dialog.tsx because the package declares only an `import`
export condition).
- src/lib/admin-commands.ts: pure builder for 21 navigate-mode commands across
the major surfaces (Users, Subscriptions, Licenses, Billing, Usage,
Broadcasts, Flags, Experiments, Audit, Ops, …) plus theme-toggle and sign-out
actions wired to the existing auth/theme contexts; onNavigate -> router.push.
- @bytelyst/command-palette added as workspace:* (importer-only lockfile change;
--frozen-lockfile clean).
- vitest.config: inline command-palette + dedupe react for the interaction test.
Tests: pure command-set assertions + a happy-dom Cmd-K/Ctrl-K interaction test
(react-dom/client + act, no new deps).
Verify: typecheck+lint+build green (123 routes); vitest 19 files / 165 tests
(+6); format:check no new failures; e2e 11 passed / 80 failed (unchanged vs
UX-1 baseline — environmental, no backend).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace all 5 direct recharts usages with the shared, token-themed SVG
primitives, lazy-loaded for bundle savings:
- dashboard, usage, users/[id], ops/client-logs, extraction/entity-chart
now render AreaChart/BarChart/Donut from @bytelyst/charts.
- new src/components/charts: next/dynamic wrappers (own chunk, ssr:false)
that dynamic-import a local static re-export (primitives.tsx) — the chart
packages declare only an `import` export condition, so a direct
import('@bytelyst/charts') trips Next's resolver.
- new src/lib/chart-data.ts: pure, finite-safe data mappers (unit-tested).
- recharts removed from package.json + the admin-web lockfile importer entry
(now fully unused). Lockfile delta is importer-only (+charts/+data-viz as
workspace:*, -recharts); no monorepo re-normalization; --frozen-lockfile clean.
- vitest.config: inline @bytelyst/{charts,data-viz} + dedupe react so the
SSR no-NaN render tests use a single React copy.
Fidelity notes (charts are single-series/vertical; StackedBar is charts 0.2.x):
stacked severity chart -> single bars colored by dominant severity; pie charts
-> Donut; horizontal bars -> vertical.
Verify: typecheck+lint+build green (123 routes); vitest 18 files / 159 tests
(+19); format:check no new failures; e2e 11 passed / 80 failed (unchanged vs
UX-1 baseline — failures are environmental, no backend).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Additive phase-1 foundation for ByteLyst UX integration:
- globals.css: bridge the shared --bl-* contract onto admin's shadcn OKLCH
ramp (surfaces/borders/text/accent/danger/focus) so @bytelyst/* components
theme correctly in light AND dark. Mappings reference admin --* vars that
flip under .dark, so parity is inherited with zero new color literals.
Status hues (success/warning/info) intentionally inherit design-tokens.
- eslint.config.mjs: no-restricted-imports ratchet forbidding direct
@bytelyst/ui imports outside the Primitives.tsx adapter seam.
- primitives-exports.test.ts: export-presence guard for the adapter surface.
- roadmap: author verified baseline audit + green/red gate table + e2e baseline.
Verify: typecheck+lint+build green; vitest 17 files / 140 tests (+29);
format:check no new failures (29 pre-existing, out of scope); e2e baseline
11 passed / 80 failed (80 environmental — no backend).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Mark UX-12.3 (rich-text) and UX-13.1 (NotificationCenter) as
🔒 blocked-on-backend rather than open — they are excluded from the ✅
count and each now carries a one-paragraph spec of the exact
platform-service change required:
- UX-12.3: server-side HTML sanitization (allowlist tags/attrs; strip
scripts/event-handlers/js: + data: URLs) on items.description +
comments.body write paths, so RichTextEditor/RichTextViewer can be
safely adopted.
- UX-13.1: emit notifications into platform-service's existing
notifications module on tracker events (new comment, status change,
vote milestone) targeted to the item author/subscribers with productId,
exposed via the /api/tracker proxy, so NotificationCenter binds a real
feed.
Add BACKEND_ENABLERS.md tracking both follow-ups (title, blocking item,
target module, acceptance criteria, backward-compat constraint —
platform-service is shared by 9 products). Update the Expand tracker line
and notes to show all client-only waves complete and these two
backend-blocked. Docs only — no source/dep/lockfile changes.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace the hand-rolled sticky top nav in the dashboard layout with the
shared AppShell (AppShellSidebar/AppShellNav/AppShellNavItem/AppShellMain/
AppShellSkipLink + mobile toggle + overlay). The sidebar keeps the
ProductSwitcher, user email and Sign out, and adds a ⌘K trigger (replays
the global hotkey) and a theme toggle. Nav items use aria-current for the
active route and client-side navigation; the skip-link targets the
focusable main region. AppShell exports are routed through the Primitives
adapter (CC.6 ratchet) and covered by the export-presence test.
AppShellPageHeader is intentionally not used so the per-page PageHeader
(UX-10) remains the single h1 per route (no duplicate headings).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add @bytelyst/motion (workspace:* + minimal lockfile importer entry).
Apply Reveal to the dashboard overview cards/charts (staggered) and the
items DataTable, and NumberFlow to the overview KPI totals. All motion
primitives no-op under prefers-reduced-motion.
The public /roadmap is intentionally left without entrance motion: the
offline @axe-core gate scans the page synchronously and the Reveal
transient sub-1 opacity trips color-contrast (a hard CC.4 a11y gate). The
dashboard/items surfaces are auth-gated and not axe-scanned, so they keep
the motion.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Mount the shared ToastProvider in providers.tsx and replace the inline
error/success banners across the overview, items list, board, item detail
and public roadmap with toast() calls — load errors, create, delete, vote,
status/priority/visibility updates, comment add, and idea submission. The
roadmap submit now toasts + closes the dialog instead of an in-modal
banner; the item-detail page keeps a single inline empty-state for the
hard "couldn't load this item" case.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add @bytelyst/command-palette (workspace:* + minimal lockfile importer
entry). Mount CommandRegistryProvider + a lazily-loaded CommandMenu in
providers.tsx, opened with ⌘K / Ctrl-K. Register navigate commands
(Overview/Items/Board/Roadmap), New item (navigates to items with ?new=1
which auto-opens the create modal), Toggle theme, Sign out, and per-product
Switch commands wired to setProductId. Command building lives in the pure
src/lib/command-registry.ts. Add command-menu.test.tsx (jsdom) asserting the
builder set and that the palette opens on ⌘K and lists commands.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add @bytelyst/charts + @bytelyst/data-viz as workspace:* deps (minimal
importer link entries in the lockfile). Replace the badge-pill breakdowns
on /dashboard with KpiCards (total/open/in-progress/done) and a dynamically
imported chart surface: Donut for By Status + By Type (centered total) and
a BarChart for By Priority, coloured from the bridged --bl-chart-* palette.
Pure transforms live in src/lib/overview-charts.ts (finite-coerced, no NaN
reaches the SVG); the heavy chart surface is split into overview-charts.tsx
and loaded via next/dynamic (ssr:false) to keep it out of the route bundle.
Add overview-charts.test.tsx rendering the surface with mocked stats via
react-dom/server (no NaN in paths) + transform unit tests; dedupe react in
vitest so the SSR render uses a single React instance.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace the bespoke local Modal (and its slate/blue/white chrome) with the
shared @bytelyst/ui Modal (Radix dialog — focus-trap/Esc/scroll-lock) for
both the Submit Idea and vote email-prompt dialogs. The dialog titles
become the accessible heading; form fields move to Input/Select/Textarea
and the submit-result message to AlertBanner. Behaviour preserved.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace the hardcoded slate-*/blue-*/white utility classes on /roadmap
with tokenized equivalents (bg-background/bg-card/text-foreground/
text-muted-foreground/border-border). Swap the type/priority pills to the
shared Badge, the status column/list markers to StatusDot tones, the stat
tiles to MetricCard, search/type filter to Input/Select, the Submit Idea
button to Button, and load/vote errors to AlertBanner. Behaviour, the
board/list SegmentedControl toggle, and the vote-button a11y attrs
(aria-pressed/aria-label) are preserved. The submit + email-prompt modals
are migrated to the shared Modal in UX-3.2.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace the bespoke total-count card chrome with the shared MetricCard on
the dashboard overview (breakdown cards stay until the UX-4 chart swap),
and surface load errors via AlertBanner. Wrap the items-list delete
confirm() in the accessible ConfirmDialog (focus-trapped AlertDialog)
instead of the native browser prompt.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace the raw search input, the three filter selects, the New Item
button, and the hand-rolled create modal with @bytelyst/ui Input/Select/
Field/Button/Modal (via the Primitives adapter). The shared Modal closes
the focus-trap/Esc/scroll-lock a11y gap. Swap the inline type/status/
priority cell pills to StatusBadge with token-driven tones.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Mark the cross-cutting items complete with evidence: full suite green per wave
(CC.1), dark-mode parity via the --bl-* bridge (CC.2), zero new color literals
(CC.3), offline axe on /login + /roadmap (CC.4), master ROADMAP left untouched
per default (CC.5), gzip-verified bundle budgets (CC.7), enforced 80% coverage
thresholds at 94/87/94/97 (CC.8). Add an Expand-waves status table with commit
SHAs and document the data-gated deferrals (UX-12.3, UX-13.1).
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add @bytelyst/notifications-ui as a workspace dep (minimal link: lockfile entry,
avoiding the env-specific full re-normalization). New SystemBanners component
mounts at the top of the dashboard shell:
- BannerStack renders dismissible system/maintenance notices from
NEXT_PUBLIC_SYSTEM_NOTICE (nothing when unset)
- Announcement shows a localStorage-dismissible "what's new" pill
Defer UX-13.1 (NotificationCenter): tracker has no notifications feed — the
/api/tracker proxy exposes only items/comments/votes/roadmap. The dep + an
import smoke test are in place so a future feed wiring starts from green.
All colors come from the bridged --bl-* tokens; no hardcoded literals.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>