feat(ui): last-refresh meta + manual refresh on the analytics and maintainer headers#4705
Conversation
…ntainer headers Adds a shared RefreshMeta primitive (relative-time label + refresh button reusing StateActionButton/RefreshCw) and a pure relativeTimeFromNow helper, stamps loadedAt in useApiResource on a successful load, and adopts the control on the analytics header pill row and the maintainer dashboard header row. The label re-renders on a coarse 30s tick and the control stays hidden until the first successful load, since StateBoundary already covers loading/error/empty refresh affordances. Scoped to the dashboard headers per the issue — no StateBoundary refactor.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-10 15:26:31 UTC
✅ Suggested Action - Approve/Merge
Review summary Nits — 5 non-blocking
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
Visual preview
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 Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Summary
RefreshMetaprimitive (apps/gittensory-ui/src/components/site/refresh-meta.tsx): alast refresh Xm agolabel plus a manual refresh button, reusingStateActionButton+ theRefreshCwicon already used byStateBoundary's refresh affordances so the control reads consistently.relativeTimeFromNow(timestampMs, nowMs)helper toapps/gittensory-ui/src/lib/utils.tswith unit tests across every bucket boundary (seconds → minutes → hours → days) and a clamp for marginally-future timestamps.useApiResourcewith aloadedAtstamp (set when a load succeeds,nullwhile loading/on error/disabled) so headers can show refresh recency without any new fetch plumbing;reloadis unchanged and is what the button calls.app.analytics.tsx) and on the maintainer dashboard header row. The maintainer adoption lives at the top ofMaintainerDashboardView(inmaintainer-panel.tsx) rather than the route'sPageHeaderbecause the maintainer resource is created behind the session/role check inside the panel — the route header renders before any data exists to describe.RefreshMetarenders nothing until the first successful load since the loading/error/empty states already carry their own retry/refresh affordances inStateBoundary.Scoped to the dashboard headers only, per the issue — no
StateBoundaryrefactor.Closes #2219
Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #123) — a linked open issue is required for every contributor PR.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coveragelocally;codecov/patchrequires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateIf any required check was skipped, explain why:
npm run test:cirun locally. The diff is confined toapps/gittensory-ui/**(Codecov-exempt paths); the new helper, hook field, and component are still fully unit-tested (11 new cases: every relative-time bucket boundary + future-clamp,loadedAton success/error/disabled, label tick, refetch-on-click, disabled-while-refreshing, null-before-first-load, interval cleanup).Safety
UI Evidencesection below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. SVG screenshots are not used as review evidence. Review-only screenshots or recordings are not committed to the repository.UI Evidence
/app/analyticsheader — refresh meta joins the status pill rowbefore: pills only, no refresh affordance
after:
last refresh just now+ Refresh button beside the boundary badge/app/maintainer— dashboard header row above the metric cardsbefore: metrics start with no refresh recency
after: right-aligned
last refreshmeta + Refresh above the cardsNotes
RefreshMeta—StateBoundaryalready renders retry/refresh there; this control only describes a successfully loaded dashboard.