Skip to content

fix(ui): show StatUnavailable when KPI source queries fail (#8818) - #8933

Closed
kurosawareiji7007-hub wants to merge 1 commit into
JSONbored:mainfrom
kurosawareiji7007-hub:fix/ui-stat-phase-8818-v5
Closed

fix(ui): show StatUnavailable when KPI source queries fail (#8818)#8933
kurosawareiji7007-hub wants to merge 1 commit into
JSONbored:mainfrom
kurosawareiji7007-hub:fix/ui-stat-phase-8818-v5

Conversation

@kurosawareiji7007-hub

Copy link
Copy Markdown
Contributor

Closes #8818

Supersedes closed #8926 (maintainer: StatUnavailable not uniformly sized across viewports), #8905, #8901, #8899.

Summary

Four KPI surfaces rendered a confident 0 / "no positions" / "Unset" when their source useQuery failed. Wired each through statPhase + StatUnavailable.

StatUnavailable now uses h-[1em] so error tiles match the parent KPI value-line height (StatTile display metrics) instead of collapsing to text-sm beside numeric neighbours.

What changed

  1. /subnets Total stake — statPhase(economicsRes)
  2. /accounts/<ss58> Positions — portfolioPhase={statPhase(portfolioResult)} into AccountKpiBand
  3. /subnets/<netuid>?tab=activity ActivityEventRollup — independent phases; dual failure still renders Unavailable tiles
  4. /chain/governance Sudo key — error → StatUnavailable

Test plan

  • Source-assertion suites for all four sites
  • Forced-503 capture with wait for visible Unavailable (account/subnets/sudo/subnet rollup)
  • Confirmed after account shot shows Positions → Unavailable (not portfolioResult is not defined)
  • Full Desktop/Tablet/Mobile × Light/Dark before/after matrix (fixed viewport, mg-theme)
  • CI green on this PR

Screenshots

Blocked: /api/v1/economics, .../portfolio, .../event-summary, .../axon-removals, /api/v1/sudo/key.

/subnets Total stake

Viewport · Theme Before After
Desktop · Light
before

after
Desktop · Dark
before

after
Tablet · Light
before

after
Tablet · Dark
before

after
Mobile · Light
before

after
Mobile · Dark
before

after

Account Positions KPI

Viewport · Theme Before After
Desktop · Light
before

after
Desktop · Dark
before

after
Tablet · Light
before

after
Tablet · Dark
before

after
Mobile · Light
before

after
Mobile · Dark
before

after

/subnets/1?tab=activity Activity rollup

Viewport · Theme Before After
Desktop · Light
before

after
Desktop · Dark
before

after
Tablet · Light
before

after
Tablet · Dark
before

after
Mobile · Light
before

after
Mobile · Dark
before

after

Governance Sudo key

Viewport · Theme Before After
Desktop · Light
before

after
Desktop · Dark
before

after
Tablet · Light
before

after
Tablet · Dark
before

after
Mobile · Light
before

after
Mobile · Dark
before

after

…#8818)

Phase Total stake, Positions, ActivityEventRollup, and Sudo key through
statPhase so a failed request cannot fabricate 0 / no positions / Unset.
Pass portfolioPhase into AccountKpiBand. Size StatUnavailable with h-[1em]
so error tiles match neighbouring KPI value-line height.
@loopover-orb

loopover-orb Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-31 13:32:04 UTC

9 files · 1 AI reviewer · no blockers · CI green · clean

⏸️ Suggested Action - Manual Review

  • Touches a guarded path — held for manual review: This PR changes guardrail-protected path(s): apps/ui/src/components/metagraphed/states.tsx (matched apps/ui/**), apps/ui/src/routes/accounts-positions-kpi.test.ts (matched apps/ui/**), apps/ui/src/routes/-accounts-ss58-page.tsx (matched apps/ui/**), apps/ui/src/routes/subnets-activity-rollup.test.ts (matched apps/ui/**), apps/ui/src/routes/-subnets-index-page.tsx (matched apps/ui/**), and 4 more.

Review summary
This PR consistently threads `statPhase()` through four independent KPI/stat surfaces (subnets Total stake, account Positions, subnet ActivityEventRollup, sudo key) so a failed source query renders `StatUnavailable` instead of a fabricated `0`/`"no positions"`/`"Unset"`, closing #8818. The phase branching (pending/error/ready) is applied correctly at each call site — e.g. The screenshot evidence (red 'Unavailable' next to 'Total stake' in the after shots) corroborates the described behavior with no visible regression. CI (test/ui/typecheck) is green on this exact commit, and the `StatUnavailable` height fix (`h-[1em]`) is a reasonable, self-contained visual tweak.

Nits — 6 non-blocking
  • `ActivityEventRollup`'s new guard (`-subnets-netuid-page.tsx`) only suppresses the section while BOTH queries are still `pending`; a `ready` response where the API genuinely returns no `data` for either source (previously hidden by the old `!summary && !axon` check) will now render 4 tiles with zeroed/dash values instead of disappearing — confirm this edge case is intended.
  • The new `.test.ts` files (`subnets-activity-rollup.test.ts`, `sudo-key-card.test.ts`, `accounts-positions-kpi.test.ts`) assert on raw source-code substrings rather than actual rendered output, so they can't catch a logic regression that keeps the same tokens present but wires them incorrectly — same weak convention as the pre-existing `subnets-total-stake-tile.test.ts` this PR extends.
  • `summaryValue(formatNumber(summary?.total_events))` in `-subnets-netuid-page.tsx` eagerly evaluates `formatNumber` on every render regardless of phase (JS evaluates the argument before the ternary inside the helper runs) — harmless since `formatNumber` tolerates `undefined`, but slightly wasteful and less clear than checking phase before formatting.
  • The near-identical pending/error/ready ternary is now duplicated across four files (`-subnets-netuid-page.tsx`, `-accounts-ss58-page.tsx`, `-subnets-index-page.tsx`, `-sudo-index-page.tsx`) — a small shared `renderStat(phase, {pending, error, ready})` helper would cut the repetition.
  • `states.tsx:369`'s comment cites issue `fix(ui): four stat surfaces render a fabricated 0 (and /sudo a false "Unset") when their query failed #8818` as a magic reference for the `h-[1em]` sizing rationale; fine as-is but worth a shared constant/doc if more surfaces start depending on this exact sizing contract.
  • Touches a guarded path — held for manual review — A maintainer must review and merge this change.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ⚠️ Gate result — Not blocking (Advisory; not blocking this PR.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8818, #8926
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 (2 linked issues).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 102 registered-repo PR(s), 33 merged, 51 issue(s).
Contributor context ✅ Confirmed Gittensor contributor kurosawareiji7007-hub; Gittensor profile; 102 PR(s), 51 issue(s).
Linked issue satisfaction

Addressed
The diff updates all four sites named in the issue (subnets masthead total stake, accounts Positions tile, subnets-netuid ActivityEventRollup, and sudo key card) to route through statPhase/StatUnavailable instead of fabricating 0/Unset on query failure, removing the cited `?? 0` fallbacks and the null-swallowing early return in ActivityEventRollup so a dual-failure still renders four Unavailable t

Review context
  • Author: kurosawareiji7007-hub
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: TypeScript
  • Official Gittensor activity: 102 PR(s), 51 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
/-accounts-ss58-page desktop before /-accounts-ss58-page
before /-accounts-ss58-page
after /-accounts-ss58-page
after /-accounts-ss58-page
diff /-accounts-ss58-page
diff /-accounts-ss58-page
/-accounts-ss58-page mobile before /-accounts-ss58-page (mobile)
before /-accounts-ss58-page (mobile)
after /-accounts-ss58-page (mobile)
after /-accounts-ss58-page (mobile)
diff /-accounts-ss58-page (mobile)
diff /-accounts-ss58-page (mobile)
/-subnets-index-page desktop before /-subnets-index-page
before /-subnets-index-page
after /-subnets-index-page
after /-subnets-index-page
/-subnets-index-page mobile before /-subnets-index-page (mobile)
before /-subnets-index-page (mobile)
after /-subnets-index-page (mobile)
after /-subnets-index-page (mobile)
diff /-subnets-index-page (mobile)
diff /-subnets-index-page (mobile)

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

Scroll preview
Route Before (production) After (this PR's preview)
/-accounts-ss58-page before /-accounts-ss58-page (scroll)
before /-accounts-ss58-page (scroll)
after /-accounts-ss58-page (scroll)
after /-accounts-ss58-page (scroll)
/-subnets-index-page before /-subnets-index-page (scroll)
before /-subnets-index-page (scroll)
after /-subnets-index-page (scroll)
after /-subnets-index-page (scroll)

A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show.

🟩 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

@superagent-security

Copy link
Copy Markdown

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

@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.93%. Comparing base (60dbad2) to head (b871080).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8933   +/-   ##
=======================================
  Coverage   97.93%   97.93%           
=======================================
  Files         449      449           
  Lines       31546    31546           
  Branches    11778    11778           
=======================================
  Hits        30895    30895           
  Misses        150      150           
  Partials      501      501           
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix or unsolicited PR — scores a 0.05x multiplier. label Jul 31, 2026
@loopover-orb loopover-orb Bot added manual-review Gittensor contributor context gittensor:priority Maintainer-selected Gittensor priority — scores a 1.5x multiplier. Reserved for outstanding work. labels Jul 31, 2026

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Does not look good on desktop/tablet - looks fine on mobile.

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix or unsolicited PR — scores a 0.05x multiplier. gittensor:priority Maintainer-selected Gittensor priority — scores a 1.5x multiplier. Reserved for outstanding work. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(ui): four stat surfaces render a fabricated 0 (and /sudo a false "Unset") when their query failed

2 participants