Skip to content

fix(ui): add a content-shaped loading skeleton to the analytics dashboard#6949

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
galuis116:feat/analytics-dashboard-loading-skeleton
Jul 17, 2026
Merged

fix(ui): add a content-shaped loading skeleton to the analytics dashboard#6949
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
galuis116:feat/analytics-dashboard-loading-skeleton

Conversation

@galuis116

Copy link
Copy Markdown
Contributor

Summary

app.analytics.tsx's StateBoundary (lines ~164-176) had no loadingSkeleton prop, falling through to the generic centered spinner — the same gap #6816 just fixed for app.operator.tsx, relative to the same set of siblings (app.runs.tsx, miner-panel.tsx, maintainer-panel.tsx, dead-letter-queue-panel.tsx) that already provide a content-shaped skeleton.

Added AnalyticsDashboardSkeleton, mirroring the real dashboard's layout:

  • Header block (eyebrow + title + description + window-toggle/export controls)
  • Stat grid (the data.metrics section)
  • A grid of card-section placeholders approximating the dashboard's several analytics panels (weekly value, adoption/retention, command usefulness, gate precision, etc.)

Wired via loadingSkeleton={<AnalyticsDashboardSkeleton />} on the existing StateBoundary, following the exact same pattern as #6816 and its other siblings.

Test plan

  • New apps/loopover-ui/src/routes/app.analytics.test.tsx (2 tests, ProductAnalytics exported for direct testing, matching this repo's established pattern):
    • The custom skeleton (.animate-pulse blocks) renders during status: "loading", and neither the generic LoadingState title nor its spinner (.animate-spin) appears
    • No skeleton remains once the dashboard has real (status: "ready") data
    • Both passing
  • npm run ui:lint, npm run ui:typecheck — clean (0 errors)
  • git diff --check, npm run actionlint — clean
  • apps/** is outside Codecov's coverage.include — no patch-coverage obligation for this UI-only change; added the regression tests regardless per the issue's own Test Coverage Requirements note
  • No live screenshot: /app/analytics sits behind the same app-shell session-restoration gate documented in Operator dashboard loading state falls back to a generic spinner instead of a content-shaped skeleton #6816's PR (fix(ui): add a content-shaped loading skeleton to the operator dashboard #6945), which this sandbox can't get past without a real session. The skeleton reuses the same Skeleton primitive and layout shape already shipped (and visually verified) in MaintainerDashboardSkeleton/OperatorDashboardSkeleton — no new visual design to verify. The automated tests directly assert the actual DOM swap, which is the change's real surface area.

Closes #6817

…oard

app.analytics.tsx's StateBoundary had no loadingSkeleton, falling through to
the generic centered spinner -- the same gap JSONbored#6816 fixed for
app.operator.tsx, relative to app.runs.tsx/miner-panel.tsx/
maintainer-panel.tsx/dead-letter-queue-panel.tsx.

Adds AnalyticsDashboardSkeleton mirroring the real layout (header + window
toggle, stat grid, card sections) and wires it via loadingSkeleton on the
existing StateBoundary.

Closes JSONbored#6817
@galuis116
galuis116 requested a review from JSONbored as a code owner July 17, 2026 14:59
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 17, 2026
@loopover-orb

loopover-orb Bot commented Jul 17, 2026

Copy link
Copy Markdown

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-17 15:04:43 UTC

2 files · 1 AI reviewer · no blockers · readiness 98/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This mirrors the exact pattern from #6816 for app.operator.tsx: adds an AnalyticsDashboardSkeleton mimicking the header/stat/card layout and wires it into StateBoundary's loadingSkeleton prop, exporting ProductAnalytics for direct testability. The change is small, well-scoped, and the two new tests correctly assert the skeleton appears during loading (no spinner/title) and disappears once data is ready. The most notable detail is the export change of ProductAnalytics (previously unexported) purely to enable direct RTL testing, following the established repo convention seen in app.operator.tsx.

Nits — 5 non-blocking
  • apps/loopover-ui/src/routes/app.analytics.tsx:158 and :163 use bare literals (3, 4) for the stat/card skeleton counts; naming them (e.g. STAT_SKELETON_COUNT) would make the approximation intent clearer, though this matches the unnamed-literal style already used in the sibling MaintainerDashboardSkeleton.
  • The skeleton's 4-card grid approximates the real dashboard's variable number of conditionally-rendered panels (weeklyValueReport, gateEval, cycleTime, calibration, agentHealth, etc.) — a cosmetic mismatch only, not a functional issue.
  • No live screenshot was possible per the PR description due to the session-restoration gate; purely visual regressions (if any) wouldn't be caught by the DOM-based tests alone.
  • Consider extracting the shared skeleton-count constants across app.analytics.tsx and app.operator.tsx if more dashboards adopt this pattern, to avoid literal duplication.
  • If maintaining parity with the real dashboard is a goal, a brief comment noting the skeleton section counts are approximate (not 1:1) would preempt future confusion when panels are added/removed.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #6817
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 1952 registered-repo PR(s), 1282 merged, 52 issue(s).
Contributor context ✅ Confirmed Gittensor contributor galuis116; Gittensor profile; 1952 PR(s), 52 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: minor
Linked issue satisfaction

Addressed
The PR adds an AnalyticsDashboardSkeleton mirroring the header/stat-grid/card-section layout and wires it via loadingSkeleton on the StateBoundary in app.analytics.tsx, matching both deliverables, and includes regression tests exercising the loading and ready states.

Review context
  • Author: galuis116
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: not available
  • Official Gittensor activity: 1952 PR(s), 52 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Visual preview
Route Viewport Before (production) After (this PR's preview) Diff
/app/analytics/test desktop before /app/analytics/test
before /app/analytics/test
after /app/analytics/test
after /app/analytics/test
/app/analytics/test mobile before /app/analytics/test (mobile)
before /app/analytics/test (mobile)
after /app/analytics/test (mobile)
after /app/analytics/test (mobile)
/app/analytics desktop before /app/analytics
before /app/analytics
after /app/analytics
after /app/analytics
/app/analytics mobile before /app/analytics (mobile)
before /app/analytics (mobile)
after /app/analytics (mobile)
after /app/analytics (mobile)

Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit 3ade2dd into JSONbored:main Jul 17, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Product analytics dashboard loading state falls back to a generic spinner instead of a content-shaped skeleton

1 participant