Skip to content

V2 settings: rebuild the Stats tab to match the classic profile stats page - #1397

Merged
Paul Lizer (paullizer) merged 2 commits into
paullizer-react-v2-uifrom
paullizer-v2-stats-page
Sep 3, 2026
Merged

V2 settings: rebuild the Stats tab to match the classic profile stats page#1397
Paul Lizer (paullizer) merged 2 commits into
paullizer-react-v2-uifrom
paullizer-v2-stats-page

Conversation

@paullizer

@paullizer Paul Lizer (paullizer) commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

What this does

Rebuilds the Stats tab on the V2 Settings page so it covers what the classic profile page's stats tab covers, and removes the account menu's Profile entry now that it leads nowhere V2 does not already reach.

Base branch: this stacks on paullizer-react-v2-ui, not Development. application/v2_ui only exists there.

Why

The V2 Stats tab was a placeholder — four hand-rolled SVG sparklines, a 7/30/90 selector, no totals. The classic page had considerably more, and the account menu offered Profile as the way to get to it. Keeping both entries asked the user to choose between two destinations for personal settings without the information to make the choice, so the placeholder had to become the real thing before the second entry could go.

What the tab gained

Before Now
Window 7 / 30 / 90 + custom start–end range, validated client-side before it is sent
Totals none conversations, messages, documents, sign-ins, plus last sign-in
Charts 4 SVG sparklines sign-ins (line), conversations created vs deleted (grouped bars), documents uploaded vs deleted (grouped bars), tokens (line, scaled to millions), storage (doughnut)
Export none CSV dialog — 5 sections, its own period, matching the classic export column for column
Account none name, email, user id

The four totals are lifetime cached figures, and the tab now says when they were last worked out. That distinction is the classic page's and the placeholder had lost it — without the stamp, the cards read as figures for the period on screen.

No backend change

GET /api/user/activity-trends and GET /api/user/settings already returned everything, including custom start_date/end_date windows and the cached metrics block. The whole change is in the SPA. The CSV is assembled in the browser from those same two responses, the way the classic page does it; an export endpoint would be a second implementation of totals that are on screen at the time.

Charts

Drawn with the Chart.js already vendored at application/v2_ui/public/vendor/chartjs-4.5.1/, loaded on demand. The loader moves out of InlineChart.tsx into lib/chartRuntime.ts and is shared, so whichever of the two draws first fetches and evaluates the script and the other reuses it.

It is not an npm dependency, so the main bundle is unchanged, and the bytes are served from the app's own origin — default-src 'self' is untouched. The previous "plain SVG is enough" note in StatsTab.tsx argued against adding a charting package to package.json; that is still true and still enforced by the test, but it never applied to a library the repository already ships.

Account menu

Profile is removed; Settings is the single destination. The /profile?tab=groups and /profile?tab=public-workspaces links inside the Groups and Public tabs stay — those are the "open in the classic UI" fallback for tabs V2 has not rebuilt, not profile navigation, and removing them would leave those capabilities unreachable.

Verification

Beyond typecheck, build and the test suite, the built bundle was rendered in headless Chromium against stubbed endpoints, asserting behaviour rather than source:

  • all five canvases draw real pixels, in light and dark, and redraw on the theme switch
  • a reversed custom range is refused client-side with a message about the dates; a valid one reloads and relabels from the server's own window.label
  • the export dialog downloads a CSV containing the right totals, sections and columns
  • the account menu has no Profile, and there are no console or page errors
python .\functional_tests\test_v2_stats_parity.py     # 7 checks, new
node   .\functional_tests\test_v2_stats_logic.mjs     # 31 checks, new
python .\functional_tests\test_v2_settings_tabs.py    # stats case reworked
python .\functional_tests\test_v2_ui_local_assets.py
cd application\v2_ui; npm run typecheck; npm run build

The full V2 and docs suite passes — 12/12 files, including test_docs_app_surface_coverage.py and test_docs_site_quality.py.

test_v2_stats_parity.py pins names: every trend field, query parameter and metrics key the tab reads is checked to exist server-side, each classic surface is checked to have a counterpart, and both chart consumers are checked to share the vendored runtime. test_v2_stats_logic.mjs executes userStats.ts directly under Node against the cases that render perfectly while being wrong — a window sent as the wrong pair of parameters, a sparse series drawn against the wrong dates, the token series read by the wrong key, an export whose columns have slipped by one.

Two judgment calls worth a look

  1. The classic "Dark Mode: Enabled/Disabled" badge is not reproduced on the account card. The V2 rail has a live theme toggle a few inches away; a second, read-only echo of it adds nothing. Trivial to restore if you disagree.
  2. The token chart's y-axis got a "Millions of tokens" title that the classic page does not have. Rendering showed an unlabelled 0–3.0 axis beside a 47,188,095 total, which reads as a contradiction. (The classic chart is worse here: its precision: 0 ticks collapse every sub-million day to zero.)

Documentation and version

  • New docs/explanation/features/V2_STATS_TAB_PARITY.md
  • docs/explanation/features/REACT_V2_UI.md updated: personal settings, the vendored library table, the shared loader, the account menu, and the test table
  • Release notes under v0.261.041
  • config.py0.261.041. Nothing under deployers/, so deployers/version.txt is untouched

Out of scope

The Preferences tab, deliberately — this change is scoped to Stats.

Rebased onto a moved base

The conversation export (#1395) and admin appearance parity (#1396) PRs landed while this was open and took 0.261.039 and 0.261.040. origin/paullizer-react-v2-ui has been merged in and this change renumbered to 0.261.041, with its release-notes entries moved to a new section above both.

The three conflicts were all version-related. The other two were additive on both sides — the test table in REACT_V2_UI.md keeps the conversation export row alongside the two stats rows, and the release notes keep every section.

Worth noting for review: the base's changes to InlineChart.tsx did not touch the Chart.js loader and introduced no second loader of its own, so lib/chartRuntime.ts remains the only one after the merge. Re-verified post-merge — typecheck and build clean, 19 functional test files pass including the base's own conversation export and admin appearance tests, and the Stats tab still renders all five charts in both themes.

… page

The V2 Stats tab was a placeholder: four hand-rolled SVG sparklines, a 7/30/90
selector, and no totals. The classic profile page's stats tab has considerably
more, and all of it is already served by /api/user/activity-trends and
/api/user/settings, so this is entirely a client change.

Stats now covers lifetime totals with the stamp that qualifies them, a custom
start-end range alongside the presets, sign-in and token line charts, created-
versus-deleted bars for conversations and documents, a storage ring, a CSV
export matching the classic one column for column, and the account card.

Charts are drawn with the Chart.js already vendored under public/vendor/ and
loaded on demand. The loader moves to lib/chartRuntime.ts and is shared with the
inline chat charts, so whichever draws first pays for the script. Nothing is
added to the main bundle and nothing is fetched from outside the application.

The account menu's Profile entry is removed. It was a second destination for
personal settings that existed because the classic profile page held the stats;
with those rebuilt it leads nowhere V2 does not already cover. The classic deep
links inside the Groups and Public tabs stay, since those tabs are unbuilt.

Verified by rendering the built bundle against stubbed endpoints: all five
charts draw in both themes, a reversed custom range is refused client-side, a
valid one relabels from the server, and the export downloads a correct CSV.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Three conflicts, all from the base branch renumbering under this one. The
conversation export and admin appearance parity PRs landed while this was open
and took 0.261.039 and 0.261.040, so the version bump here moves to 0.261.041
and the release notes entries move to a new section above both.

The other two were additive on both sides: the test table in REACT_V2_UI.md
keeps the conversation export row alongside the two stats rows, and the release
notes keep every section.

Nothing in the merge disturbs the shared Chart.js loader. The base's changes to
InlineChart.tsx did not touch it, and it added no second loader of its own, so
lib/chartRuntime.ts remains the only one.

Verified after merging: typecheck and build clean, 19 functional test files pass
including the base branch's own conversation export and admin appearance tests,
and the Stats tab still renders all five charts in both themes against the
rebuilt bundle.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@paullizer
Paul Lizer (paullizer) merged commit ee854c5 into paullizer-react-v2-ui Sep 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant