feat(analytics): PR-D -- Usage Analytics v1 frontend dashboard - #40
Merged
Conversation
Fourth and final sub-PR. Frontend for the /analytics/* API (#39 PR-C). - analytics.ts: data layer, mirroring interactions.ts's own shape -- typed fetch wrappers for all 7 GET endpoints plus exportAnalyticsCsv (fetched, not a bare <a href>, so Authorization can be attached; blob download). /analytics/performance's response type pins org_id/team_id to `null` and scope to 'platform' at the type level, matching the backend's own hard requirement that those numbers are never presented as tenant-scoped. - pages/AnalyticsDashboard.tsx: reuses the existing DashboardGrid/ MetricCard widget family (PR10) and recharts (already a dependency, already used by BillingPage.tsx/EcosystemPage.tsx -- same chart colors, no new visual system). Overview cards, a queries/active-users trend line chart, DAU/WAU/MAU, a service breakdown table, performance cards (explicitly labeled platform-wide), 7d/30d/90d date presets, CSV export, and an organization filter shown only to a platform_admin (an org_admin/team_admin's scope is already fixed server-side to their own org/team). Null values render as "--", never a fabricated number, same convention DashboardPage.tsx already established. - auth.ts: canSeeAnalytics(), a UX-only mirror of the backend's require_analytics_scope matrix (platform_admin/org_admin/team_admin allowed, regular member denied) built from the SessionUser fields Phase 1 PR3/Team Management v0.8.0 already put there (orgRoles, teamRole) -- no new claim, no new auth mechanism. - navigation.ts / AdminApp.tsx: wired in exactly like 'interactions' was -- one NAV entry (Business section, next to Billing) gated by canSeeAnalytics, one switch case rendering AnalyticsDashboard. Test plan: `npm test` -- 474 passed (38 files), no regressions. AnalyticsDashboard.test.tsx (10 tests): loads and renders live data, date-range re-fetch, API failure + retry, 403 permission-denied state, empty-data state, null-value "--" rendering, CSV export (success + failure), organization filter shown only for a platform_admin. `tsc -b` and `vite build --mode admin` both clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fourth and final sub-PR implementing Usage Analytics v1 (#37 PR-A, #38 PR-B, #39 PR-C). Frontend for the merged
/analytics/*API.analytics.ts-- typed data layer for all 7 GET endpoints + CSV export (fetched with Authorization, not a bare link)./analytics/performance's type pinsorg_id/team_idtonull, matching the backend's hard requirement that those numbers are never tenant-scoped.pages/AnalyticsDashboard.tsx-- reuses the existingDashboardGrid/MetricCardfamily (PR10) and recharts (already used byBillingPage.tsx/EcosystemPage.tsx, same colors -- no new visual system, per the task brief's own instruction). Overview cards, trend chart, DAU/WAU/MAU, service table, performance cards, 7d/30d/90d presets, CSV export, org filter (platform_admin only).auth.ts--canSeeAnalytics(), UX mirror of the backend's RBAC matrix, built from existingSessionUserfields (no new claim).navigation.ts/AdminApp.tsx-- wired exactly likeinteractionswas.Test plan
npm test: 474 passed (38 files), zero regressions.AnalyticsDashboard.test.tsx(10 tests): load, date-range re-fetch, API failure + retry, 403 state, empty-data state, null → "--" rendering, CSV export success/failure, org filter visibility by role.tsc -bandvite build --mode adminboth clean.🤖 Generated with Claude Code