Skip to content

5. Batch D — Read-only analytics (DashboardLayout)

D1. Platform dashboard — tab platform-dashboard (global, superadmin)

Section titled “D1. Platform dashboard — tab platform-dashboard (global, superadmin)”
  • Route /admin/platform-dashboard · PlatformDashboardPanel.tsx.
  • Job: “is the deployment healthy, and what needs me?”
  • Reference: org1/org2 (greeting, stat cards, callouts, list + rail).
  • Layout: DashboardLayout.
    • greeting “Checked {relative time}”, title “Platform”, actions: outline “Run checks now” (replaces “Refresh dashboard and checks”; there is no primary).
    • callouts: one per error problem (max 2, then “+{n} more in Problems”): “{message}” → “Inspect”.
    • stats: one card per tenant state (Live / Hidden / Archived …) [loaded] · Failed emails [loaded] · Failed notifications [loaded].
    • main sections: Problems (rows: status pill Error/Warning/OK + message + inline “Inspect”) · Tenant usage (rows per tenant; click opens a drawer with UsageTable) · Scheduler freshness (rows: job, last run, status pill).
    • rail: “Backups” at-a-glance card (Last result, Last success, Automatic on/off, Offsite destinations with state pills, link “Backup settings →”) and “Delivery” card (link “Platform settings →”).
  • States: checks running: skeleton rows in Problems · all clear: success callout “All checks passed.” · load error: standard.
  • Route /admin/usage · TenantUsagePanel.tsx (UsageTable is shared with D1).
  • Job: “how close is this space to its limits?”
  • Reference: mgr2 progress stat card.
  • Layout: DashboardLayout.
    • title “Usage & limits”, greeting “Counters reset with each quota period.”, actions outline “Refresh”.
    • callouts: any resource over its limit: “{resource} is over its limit.” (danger tint). Self-hosted (unmanaged): info callout “This deployment has no managed limits. Storage isn’t tracked in self-hosted mode.”
    • main: a grid of progress stat cards, one per resource: label · “{used} of {limit}” · progress bar (warn ≥ 80%, danger > 100%) · “Unlimited” when no limit. The table is kept as an accessible alternative (“Show as table”).
  • Merge option: this could become a “Plan & usage” section of Makerspace settings. It stays a tab now, because the tab key and gate exist. Owner decision.
  • States: standard skeleton cards; error with “Try again”.

D3. Organization analytics — tab organization-analytics

Section titled “D3. Organization analytics — tab organization-analytics”
  • Route /admin/organization-analytics · panels/OrganizationAnalyticsPanel.tsx.
  • Job: compare an organization’s spaces and see its combined total.
  • Reference: org2 stats + list.
  • Layout: DashboardLayout.
    • title “Organization analytics”, greeting “Your organization’s spaces, side by side.”
    • actions: none. Controls row under the title: Organization picker (a select fed by the existing useOrganizations list. This replaces the raw numeric “Organization ID” input) and Report select.
    • stats: the organization-total metrics as stat cards (first 4).
    • main: “Breakdown by space” — one card per space with its table (stacked on mobile).
  • States: nothing selected: “Pick an organization to see its numbers.” · no spaces: “This organization doesn’t own any spaces with reports yet.” · error with “Try again”.

D4. Makerspace picker (superadmin, pre-workspace)

Section titled “D4. Makerspace picker (superadmin, pre-workspace)”
  • Route any /admin/* when superadmin has no selection · MakerspacePicker.tsx (rendered by StaffApp gate).
  • Job: choose which space to operate.
  • Reference: org1 Home (“Your organisations” cards).
  • Layout: DashboardLayout, ideally inside AppShell in a no-workspace mode (the sidebar shows only global items, Platform dashboard and Organizations, and the switcher card reads “Choose a space”). See gap §11.4. Fallback if the shell cannot render without a workspace: the same body in CenteredCardLayout wide variant.
    • greeting “{weekday, date}”, title “Good morning, {name}” (time-aware), subtitle “Choose a space to work in.”
    • toolbar: search “Name, code or slug” (new, client-side; needed past ~10 spaces).
    • main: card grid. Card = space avatar tile · name · code as meta · “Superadmin access: off” warn pill when relevant · whole card clickable (“Open {name}”).
  • States: none exist: “No spaces yet. Create one from Users › Create makerspace, or from the control plane.” (today: “Create one from the Django control plane”).