Skip to content

Redesign: Overview route (index.tsx) — StateBoundary + skeletons + optional chart adoption #6509

Description

@JSONbored

Context

apps/loopover-miner-ui/src/routes/index.tsx (the Overview route) renders three SummaryCards in a grid sm:grid-cols-3 — Run activity (repos tracked, currently-working count), Portfolio queue (total/queued/in-progress/done + oldest-queued age), and Claims (active/total). Each card independently polls its own endpoint via usePolledFetch (apps/loopover-miner-ui/src/lib/use-polled-fetch.ts), hitting fetchRunStates, fetchPortfolioQueue, and fetchLedgers every 10s (DEFAULT_POLL_INTERVAL_MS, lib/use-polled-fetch.ts:5). Loading/empty/error states are handled by a hand-rolled Fallback() helper plus inline <p> text literals local to index.tsx — the same repeated pattern the miner-ui audit found duplicated (with only the wording changed) across the other three routes (run-history.tsx:26-42, portfolio.tsx:39-56, ledgers.tsx:117-134). Because the poll cycle re-renders every 10s, a flat gray sentence like "Loading local run state…" is what a user sees, not a shimmer/placeholder shape — there is no skeleton anywhere in the app today.

@loopover/ui-kit/components/skeleton.tsx (packages/loopover-ui-kit/src/components/skeleton.tsx) already exists in the shared package both apps depend on, but is imported nowhere under apps/loopover-miner-ui/src (confirmed by grep). Likewise packages/loopover-ui-kit/src/components/chart.tsx ships in the same package but has zero usages anywhere in the miner UI — every metric today is a bare digit in a <dd>/<span> (e.g. index.tsx:24, portfolio.tsx:64-66), including the queued/in-progress/done breakdown that fetchPortfolioQueue already returns as structured counts (the same counts portfolio.tsx renders as three separate status-count Cards).

The LoadingState/EmptyState/ErrorState/StateBoundary primitives this issue is meant to adopt do not live in @loopover/ui-kit yet. They currently live app-locally at apps/loopover-ui/src/components/site/state-views.tsx, inside the main site app (apps/loopover-ui), which apps/loopover-miner-ui cannot import from directly — only @loopover/ui-kit is the real shared workspace package both apps consume (confirmed in the design-system audit: both apps declare "@loopover/ui-kit": ">=0.1.0 <2.0.0" and import @loopover/ui-kit/theme.css/@loopover/ui-kit/components/*; there is no cross-app import path between apps/loopover-ui and apps/loopover-miner-ui). #6244's audit (landed via PR #6474, docs(ui): audit ui-kit for existing chat-adjacent UI primitives, apps/loopover-ui/src/chat-ui-primitives-audit.md) confirmed these four primitives are "reusable as-is" and flagged that they need to be ported from apps/loopover-ui into @loopover/ui-kit proper before any other app can consume them — that port is scoped as its own separate issue (the state-views ui-kit port issue) and is a hard prerequisite for this one.

This issue is part of the visual/ui-kit polish track of the miner dashboard redesign (restyle-only — chat, the collapsible rail, and any nav/header changes are separate, independent tracks and out of scope here).

Requirements

⚠️ Read this before starting. This issue is blocked on a separate, not-yet-merged prerequisite: the issue that ports state-views.tsx's LoadingState/EmptyState/ErrorState/StateBoundary from apps/loopover-ui/src/components/site/state-views.tsx into @loopover/ui-kit (expected import path @loopover/ui-kit/components/state-views, following the same per-component-file convention as @loopover/ui-kit/components/skeleton and @loopover/ui-kit/components/scroll-area — confirm the exact export path against that issue's merged PR, do not assume it). Do not start implementation, and do not copy/duplicate state-views.tsx locally into apps/loopover-miner-ui as a workaround, until that port has merged. A PR that vendors a second local copy of these primitives instead of importing the shared @loopover/ui-kit version does not satisfy this issue.

  • Replace index.tsx's local Fallback() helper and its inline <p> loading/empty/error text with StateBoundary (and/or LoadingState/ErrorState/EmptyState as appropriate per card) imported from @loopover/ui-kit/components/state-views — not a locally re-implemented equivalent.
  • Add Skeleton placeholders (imported from @loopover/ui-kit/components/skeleton) for all three summary cards (Run activity, Portfolio queue, Claims) shown only before each card's own first successful fetch resolves. Once a card has data, subsequent 10s poll refreshes must keep showing the existing values — the skeleton must not re-flash on every poll cycle. (Track "has this card ever loaded" per-card, independently, since each card polls a different endpoint on its own schedule via its own usePolledFetch call.)
  • Render the Portfolio queue card's status breakdown (queued/in-progress/done, from the same fetchPortfolioQueue payload already used today) using @loopover/ui-kit/components/chart.tsx, using the existing --chart-1..5 tokens defined in packages/loopover-ui-kit/src/theme.css — do not hardcode new colors.
  • The Run activity card's chart adoption is explicitly out of scope for this issue. fetchRunStates/miner_run_state (apps/loopover-miner-ui/src/lib/run-history.ts, packages/loopover-miner/lib/run-state.js) only exposes current-moment state (repos tracked, currently-working count) with no time-series/history field, so a "trend" visual is not buildable from existing data without new backend plumbing — which this issue is explicitly forbidden from adding (see below). Do not add a client-only, page-load-scoped trend accumulator as a substitute; leave the Run activity card as a data card (optionally with a skeleton, no chart).
  • Do not modify apps/loopover-miner-ui/src/lib/ledgers.ts, apps/loopover-miner-ui/src/lib/portfolio-queue.ts, apps/loopover-miner-ui/src/lib/run-history.ts, or apps/loopover-miner-ui/src/lib/use-polled-fetch.ts (including the 10s DEFAULT_POLL_INTERVAL_MS poll cadence). This is a restyle-only change — no new endpoints, no new fetch calls, no changed polling behavior.
  • Do not modify apps/loopover-miner-ui/src/routes/run-history.tsx, portfolio.tsx, ledgers.tsx, or apps/loopover-miner-ui/src/routes/__root.tsx — those routes' analogous loading/error/skeleton adoption is scoped to separate sibling issues, not this one.
  • Every CONTRIBUTOR-authored visual PR against this repo requires before/after screenshots in the PR description (initial-load/skeleton state and populated state, at minimum) per house convention — a PR without them is subject to auto-close regardless of CI status.

Deliverables

  • index.tsx's Fallback()/<p>-literal loading/empty/error markup replaced with @loopover/ui-kit/components/state-views's StateBoundary/LoadingState/ErrorState/EmptyState
  • Skeleton placeholders (@loopover/ui-kit/components/skeleton) for all three summary cards, gated on each card's own first-successful-fetch, not re-triggered on later poll cycles
  • Portfolio queue status breakdown (queued/in-progress/done) rendered via @loopover/ui-kit/components/chart.tsx using existing --chart-* theme tokens
  • No changes to lib/ledgers.ts, lib/portfolio-queue.ts, lib/run-history.ts, lib/use-polled-fetch.ts, poll cadence, or any other route file
  • Before/after screenshots (initial load and populated state) attached to the PR

Test Coverage Requirements

apps/loopover-miner-ui sits under apps/**, which per this repo's Codecov config is not part of coverage.include — this PR will not be gated on a Codecov patch-coverage percentage the way a src/** change would be. That does not relax verification: if a component/route test already exists for this route (check for a routes/index.test.tsx or adjacent test file before assuming none exists) it must be updated to cover the new StateBoundary/Skeleton/chart render paths — the initial-load skeleton state, the post-load populated state (skeleton must not reappear), and the error state. If no such test currently exists for this route, add one exercising at minimum: (1) skeleton renders before first data resolves, (2) skeleton is gone and data renders after first resolve, (3) skeleton does not reappear on a second simulated poll tick, (4) the error path renders ErrorState instead of the old <p> text. In addition to any automated test, the before/after screenshots required above are the primary verification for this visual-only change.

Expected Outcome

The Overview route's loading/empty/error handling is consistent with the shared @loopover/ui-kit primitives instead of a locally hand-rolled Fallback()/<p> pattern; first page load shows skeleton placeholders instead of flat loading text on all three summary cards, with no skeleton flicker on subsequent 10s polls; the Portfolio queue card shows its queued/in-progress/done breakdown as a real chart instead of raw digits; no fetch/polling/data behavior changes anywhere in the route.

Links & Resources

  • apps/loopover-miner-ui/src/routes/index.tsx — the route being redesigned
  • apps/loopover-miner-ui/src/lib/use-polled-fetch.ts — polling hook (DEFAULT_POLL_INTERVAL_MS), not to be touched
  • apps/loopover-miner-ui/src/lib/portfolio-queue.ts, apps/loopover-miner-ui/src/lib/run-history.ts, apps/loopover-miner-ui/src/lib/ledgers.ts — the three data sources the summary cards read, not to be touched
  • apps/loopover-ui/src/components/site/state-views.tsx — current (pre-port) location of LoadingState/EmptyState/ErrorState/StateBoundary
  • apps/loopover-ui/src/chat-ui-primitives-audit.md (from PR docs(ui): audit ui-kit for existing chat-adjacent UI primitives #6474 / research: audit ui-kit for existing message/chat-adjacent UI primitives #6244) — confirms these primitives are reusable as-is
  • packages/loopover-ui-kit/src/components/skeleton.tsx, packages/loopover-ui-kit/src/components/chart.tsx, packages/loopover-ui-kit/src/theme.css — shared components/tokens to consume
  • The state-views ui-kit port issue — hard prerequisite, must merge before this issue starts
  • The sibling run-history / portfolio / ledgers route-redesign issues — same visual track, independent of this one, do not touch their files here
  • The dashboard header/nav restyle issue (__root.tsx) and the collapsible chat rail work — separate tracks, unrelated to this issue's scope

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:featureGittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.help wantedExtra attention is needed

    Projects

    Status
    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions