Skip to content

fix: count every instrument edition on the dashboard - #1893

Merged
joshunrau merged 8 commits into
mainfrom
fix/dashboard-edition-counts
Nov 10, 2026
Merged

joshunrau merged 8 commits into
mainfrom
fix/dashboard-edition-counts

Conversation

@thomasbeaudry

@thomasbeaudry thomasbeaudry commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1886, and reworks the dashboard's dialogs and trend charts.

Fix (#1886)

Records dialog counts every edition. A record keeps the id of the edition it was collected with, but the dialog matched records only against each instrument's latest edition. It now loads allEditions instrument info and counts each record under its instrument's internal.name. The rows add up to the "Total Records" card. (Records whose instrument the group can no longer access still count in the card but have no row.)

"Total Instruments" counts what its dialog lists. InstrumentsService.count used to call find({}, {}) with no ability and no group, so it counted every edition and series in the database. It now takes the current user and the group and applies the dialog's rule: the latest edition of each instrument from findInfo, narrowed to the group's accessibleInstrumentIds. The group lookup is scoped with accessibleQuery(ability, 'read', 'Group'), and a group it cannot find throws NotFoundException. GET /v1/summary passes @CurrentUser().

Dashboard changes

  • Dialogs: the Users, Available Instruments and Number of Records dialogs are libui DataTables, each with a search bar and sortable columns (SortableHeader). The records dialog lists the most records first. Instrument kinds show as InstrumentKindCell colour tags. The tables are shown as plain text, with no frame, row or cell borders, under larger bold headers.
  • Chart time windows: each trend card has a time window in its top right corner, on the title's row:
    • The options are Default (the original 5 points, 30 days apart), Last Month, Last 3 or 6 Months, Last Year, Last 2 or 5 Years, and All Time.
    • Points step weekly for a month, monthly up to a year, every 3 months for 2 years and yearly for 5 years. Day steps are fixed-length so a daylight saving change cannot stretch them.
    • All Time takes the shortest window that reaches back past every item. Past 5 years it doubles the span from 10 years, drawn as 6 points.
    • An axis reaching back more than a year is labelled by month and year.
    • GET /v1/summary takes recordTrendWindow and subjectTrendWindow ($SummaryQueryParams, parsed with ParseSchemaPipe), so the two charts are independent. Omitting both gives the previous response.
  • Legend: the records and sessions legend is centred on the card rather than the plot area, a line below the chart, with its items spaced evenly.

Verification

  • Unit tests:
    • dashboard.test.tsx: should count the records of every edition, so older editions are not dropped from the dialog, plus dialog search and sort, kind tags, window selection and axis labels.
    • instruments.service.test.ts (count): edition rule, group narrowing, group lookup scoped by ability, missing group rejected.
    • summary.service.test.ts: should count instruments with the same edition rule and group scope as the instruments dialog, plus point spacing for each window, independent windows, and the All Time window choice.
    • TrendWindowSelect.test.tsx and useSummaryQuery.test.ts: the window options, and the query key treating an omitted window as the default.
  • e2e: testing/src/specs/dashboard.spec.ts.
    • should count the records of every edition of an instrument, matching both cards to their dialogs creates edition 1, a group, then edition 2, with 3 + 2 records. Against the old code it fails with the row showing 2 instead of 5.
    • Further cases cover user search, borderless tables and header sizes, the time window refetch and its alignment with the title, and the legend's centring.
  • pnpm lint passes in all 34 workspaces (run twice). pnpm test:coverage: 100% statements, branches, functions and lines, 5561 passed; the run exits 1 on one unhandled rejection that main's remote-assignment.test.tsx raises during teardown (window is not defined in a libui Form submit), untouched by this branch. pnpm test:e2e: 385 passed, 4 failed: record-file-deletion needs S3 locally, and instrument-hub and subject-detail (chromium and firefox) passed when re-run serially (16/16).

Notes

  • instrument-hub.spec.ts now searches for the series it creates. The hub list is paginated over the shared catalog, and the instrument this branch's dashboard spec adds pushed that series off the first page in CI.
  • A user whose permission set holds no rule on Group would now get a 500 from GET /v1/summary?groupId=…, because accessibleQuery throws. Every base permission level holds read Group.
  • Changing a chart's window refetches the whole summary, counts included, because the counts and trends share an endpoint.
  • Dashboard downloads every instrument record in the group to count records per instrument #1714 (moving per-instrument record counts to the API) must keep counting by instrument name.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

thomasbeaudry and others added 6 commits November 9, 2026 17:00
The records dialog matched records only against each instrument's latest
edition, dropping the records of older editions; it now counts each record
under its instrument's name. The Total Instruments card counted every edition
in the database; it now counts the latest edition of each instrument the group
may administer, the same set its dialog lists.

Fixes #1886

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Number of Records dialog is now a DataTable: a search bar, sortable
Title and Number columns, and the instruments with the most records first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Users and Available Instruments dialogs become searchable, sortable
tables like the records dialog, with each instrument kind shown as its
colour tag. All three dialogs show their tables as plain text, without
borders, under larger bold column headers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The legend spans the whole card rather than the plot area, sits a line
below the chart, and spaces its two items evenly apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each trend card has a time window in its top right corner: Default (the
original five points thirty days apart), the last month, 3 or 6 months, the
last year, 2 or 5 years, or all time. Points are spaced to suit the window,
all time takes the shortest window holding every item, and an axis reaching
back more than a year is labelled by month and year. GET /v1/summary takes
recordTrendWindow and subjectTrendWindow, so the two charts are independent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@joshunrau

Copy link
Copy Markdown
Collaborator

@thomasbeaudry pnpm test:e2e: 385 passed, 4 failed

thomasbeaudry and others added 2 commits November 9, 2026 17:32
The hub list is paginated over the shared catalog, so an instrument another
spec adds can push the new series off the first page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@joshunrau
joshunrau merged commit ba73f8f into main Nov 10, 2026
6 checks passed
@thomasbeaudry
thomasbeaudry deleted the fix/dashboard-edition-counts branch November 10, 2026 01:06
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.

Dashboard drops records of older instrument editions and counts instruments differently from its dialog

2 participants