[Frontend] Fold the Recording Dashboard and SessionDetail's recording panel into one live-session screen #386

Closed
opened 2026-08-25 20:42:23 +00:00 by claude-bot · 2 comments
Contributor

Impact: MEDIUM

Found in the August 2026 session lifecycle review (#319).

What the user experiences

A GM managing a live session has to juggle three partially-overlapping screens — SessionDetail, RecordingDashboard, and SessionShelf — with incomplete links between them. AudioStatusSection on SessionDetail and the standalone RecordingDashboard show heavily overlapping recording/attendance state with different labels for the same toggle ("Present"/"Absent" on one, "✓ Here"/"Absent" on the other) and different summary affordances (editable on one, read-only on the other, with nothing telling the user editing lives elsewhere). The Recording Dashboard's own entry link is labelled "Dashboard →" — which in a product that already has a page called "Dashboard" reads as "go home", not "recording controls" — and it only appears once a session leaves the proposed state, so a GM cannot even reach recording controls to test them before confirming a time.

Evidence

  • webapp/frontend/src/pages/SessionDetail.jsx:110-415 (AudioStatusSection) and webapp/frontend/src/pages/RecordingDashboard.jsx (539 lines) — overlapping state, different labels for the same attendance toggle (SessionDetail.jsx:1385,1404 vs RecordingDashboard.jsx:435).
  • webapp/frontend/src/pages/SessionDetail.jsx:317-357 (editable summary) vs webapp/frontend/src/pages/RecordingDashboard.jsx:496-506 (read-only), with no indication on the read-only copy that editing exists elsewhere.
  • webapp/frontend/src/pages/SessionDetail.jsx:193-199 — the sole inbound link to the Recording Dashboard, labelled "Dashboard →", GM-only.
  • webapp/frontend/src/pages/SessionDetail.jsx:121-122showForGm = isGm && ["confirmed","in_progress","completed"].includes(session.status); a session still proposed has no path to the recording dashboard at all.
  • No link exists from SessionShelf — the surface a GM actually has open during play — to the Recording Dashboard, or from the campaign page or dashboard.

Why it matters for a hosted product

Three partial screens for one live-session job means a GM has to remember which screen has which control, and the mislabelled "Dashboard →" entry point actively works against discovery in a product that already overloads the word "Dashboard".

Proposed fix

Fold the Recording Dashboard's live-status panel (its strongest feature — SSE stream, elapsed timer, per-speaker capture, "Present, not captured yet") into SessionDetail, or fold SessionDetail's recording panel away in favour of the standalone dashboard — either direction is acceptable, but pick one canonical live-session screen rather than maintaining two. Rename the entry link away from "Dashboard →" regardless of which direction is chosen. Make the recording controls reachable from a proposed session so a GM can test recording ahead of confirming a time. This is the audit's C4.

Acceptance criteria

  • There is one canonical screen for live-session recording controls and status, not two with divergent labels for the same data.
  • The entry link to that screen is not labelled "Dashboard →".
  • Recording controls are reachable for a session in proposed status, not only confirmed/in_progress/completed.
  • The attendance toggle uses the same label wherever it appears.
**Impact: MEDIUM** Found in the August 2026 session lifecycle review (#319). ## What the user experiences A GM managing a live session has to juggle three partially-overlapping screens — `SessionDetail`, `RecordingDashboard`, and `SessionShelf` — with incomplete links between them. `AudioStatusSection` on `SessionDetail` and the standalone `RecordingDashboard` show heavily overlapping recording/attendance state with different labels for the same toggle ("Present"/"Absent" on one, "✓ Here"/"Absent" on the other) and different summary affordances (editable on one, read-only on the other, with nothing telling the user editing lives elsewhere). The Recording Dashboard's own entry link is labelled "Dashboard →" — which in a product that already has a page called "Dashboard" reads as "go home", not "recording controls" — and it only appears once a session leaves the `proposed` state, so a GM cannot even reach recording controls to test them before confirming a time. ## Evidence - `webapp/frontend/src/pages/SessionDetail.jsx:110-415` (`AudioStatusSection`) and `webapp/frontend/src/pages/RecordingDashboard.jsx` (539 lines) — overlapping state, different labels for the same attendance toggle (`SessionDetail.jsx:1385,1404` vs `RecordingDashboard.jsx:435`). - `webapp/frontend/src/pages/SessionDetail.jsx:317-357` (editable summary) vs `webapp/frontend/src/pages/RecordingDashboard.jsx:496-506` (read-only), with no indication on the read-only copy that editing exists elsewhere. - `webapp/frontend/src/pages/SessionDetail.jsx:193-199` — the sole inbound link to the Recording Dashboard, labelled "Dashboard →", GM-only. - `webapp/frontend/src/pages/SessionDetail.jsx:121-122` — `showForGm = isGm && ["confirmed","in_progress","completed"].includes(session.status)`; a session still `proposed` has no path to the recording dashboard at all. - No link exists from `SessionShelf` — the surface a GM actually has open during play — to the Recording Dashboard, or from the campaign page or dashboard. ## Why it matters for a hosted product Three partial screens for one live-session job means a GM has to remember which screen has which control, and the mislabelled "Dashboard →" entry point actively works against discovery in a product that already overloads the word "Dashboard". ## Proposed fix Fold the Recording Dashboard's live-status panel (its strongest feature — SSE stream, elapsed timer, per-speaker capture, "Present, not captured yet") into `SessionDetail`, or fold `SessionDetail`'s recording panel away in favour of the standalone dashboard — either direction is acceptable, but pick one canonical live-session screen rather than maintaining two. Rename the entry link away from "Dashboard →" regardless of which direction is chosen. Make the recording controls reachable from a `proposed` session so a GM can test recording ahead of confirming a time. This is the audit's C4. ## Acceptance criteria - [ ] There is one canonical screen for live-session recording controls and status, not two with divergent labels for the same data. - [ ] The entry link to that screen is not labelled "Dashboard →". - [ ] Recording controls are reachable for a session in `proposed` status, not only `confirmed`/`in_progress`/`completed`. - [ ] The attendance toggle uses the same label wherever it appears.
Author
Contributor

Picking this up as v4.3.0 phase 8 (#514), the last item. As recorded on #514, SessionDetail becomes the canonical live-session screen: the Recording Dashboard's live panel (SSE stream, elapsed timer, per-speaker capture, "present, not captured yet", and the connection-lost state #377 just gave it) moves into the session page's recording section as its own component; the old /sessions/:id/recording address redirects there so bookmarks keep working; the "Recording →" link goes away, the shelf gets a link to the panel, the controls are reachable on a proposed session (with a clear reason if the backend refuses to start one), and the attendance toggle gets one label everywhere.

Picking this up as v4.3.0 phase 8 (#514), the last item. As recorded on #514, `SessionDetail` becomes the canonical live-session screen: the Recording Dashboard's live panel (SSE stream, elapsed timer, per-speaker capture, "present, not captured yet", and the connection-lost state #377 just gave it) moves into the session page's recording section as its own component; the old `/sessions/:id/recording` address redirects there so bookmarks keep working; the "Recording →" link goes away, the shelf gets a link to the panel, the controls are reachable on a proposed session (with a clear reason if the backend refuses to start one), and the attendance toggle gets one label everywhere.
Author
Contributor

Done in the #386 PR (auto-merging on green); ships with v4.3.0.

SessionDetail is now the one screen. The Recording Dashboard's live half moved into a new components/RecordingPanel.jsx: the SSE stream with its polling fallback and reconnect, the #377 three-state connection machine (last known state kept, "Connection lost, retrying…" with how stale it is, "Unknown" when the server has never answered), the elapsed clock, per-speaker capture, "Present, not captured yet", the #327 capture tripwire, and Start/Stop with "End session when stopping recording". Extracted rather than inlined because SessionDetail.jsx was already 1,800 lines. The editable summary stays where it was and nothing read-only duplicates it any more.

/sessions/:id/recording is now a redirect to /sessions/:id#recording, kept alongside the other legacy routes so bookmarks and older Discord embeds still land somewhere useful; RecordingDashboard.jsx and its test file are gone, their behaviour and tests moved. The "Recording →" entry link is gone (the panel is right there), and the shelf, the surface a GM has open during play, gained a Recording link straight to the anchor.

On proposed: no backend change was needed. POST /sessions/{id}/record/start gates on get_session_for_gm and nothing else; there has never been a status rule, so the confirmed-only entry link was hiding a capability that already worked, at exactly the moment a GM wants to check the bot can hear the table. The panel is there from proposed onwards and says so. Where a recording genuinely cannot start (the campaign is not connected to a Discord server, which is the backend's own 400), the button is disabled with the reason on the page rather than hidden.

The attendance toggle now reads "Present" / "Absent" in the one place it appears; the "✓ Here" copy went with the dashboard. The roster is also available from in_progress rather than only completed, so the mid-session roster the dashboard carried is not lost.

One thing the move forced: the live status is per Discord guild, not per session. On a page you opened deliberately that did not matter; on every session page of a campaign it does, or tonight's recording would light up last March's session as "Recording in progress". The payload carries the session id it belongs to, so a recording of another session is reported as exactly that and Start is refused rather than offered.

Also removed the frontend's approveAudio wrapper: it called the backend's documented deprecated shim for /approve, and the dashboard's "Approve transcript" button was its only caller; the session page's "Approve summary" is the same action against the non-deprecated endpoint. The shim itself is untouched. One thing to revisit if a deployment ever grows: the panel opens the SSE stream (one Redis pubsub connection) on every GM session-page view; gating it by status reintroduced the visibility holes this issue exists to remove, so it is left ungated, GM-only.

Frontend suite: 64 files / 799 tests passing, eslint clean apart from the pre-existing CampaignDetail.jsx warning, vite build clean.

Done in the #386 PR (auto-merging on green); ships with v4.3.0. `SessionDetail` is now the one screen. The Recording Dashboard's live half moved into a new `components/RecordingPanel.jsx`: the SSE stream with its polling fallback and reconnect, the #377 three-state connection machine (last known state kept, "Connection lost, retrying…" with how stale it is, "Unknown" when the server has never answered), the elapsed clock, per-speaker capture, "Present, not captured yet", the #327 capture tripwire, and Start/Stop with "End session when stopping recording". Extracted rather than inlined because `SessionDetail.jsx` was already 1,800 lines. The editable summary stays where it was and nothing read-only duplicates it any more. `/sessions/:id/recording` is now a redirect to `/sessions/:id#recording`, kept alongside the other legacy routes so bookmarks and older Discord embeds still land somewhere useful; `RecordingDashboard.jsx` and its test file are gone, their behaviour and tests moved. The "Recording →" entry link is gone (the panel is right there), and the shelf, the surface a GM has open during play, gained a **Recording** link straight to the anchor. On `proposed`: no backend change was needed. `POST /sessions/{id}/record/start` gates on `get_session_for_gm` and nothing else; there has never been a status rule, so the confirmed-only entry link was hiding a capability that already worked, at exactly the moment a GM wants to check the bot can hear the table. The panel is there from `proposed` onwards and says so. Where a recording genuinely cannot start (the campaign is not connected to a Discord server, which is the backend's own 400), the button is disabled with the reason on the page rather than hidden. The attendance toggle now reads "Present" / "Absent" in the one place it appears; the "✓ Here" copy went with the dashboard. The roster is also available from `in_progress` rather than only `completed`, so the mid-session roster the dashboard carried is not lost. One thing the move forced: the live status is per Discord *guild*, not per session. On a page you opened deliberately that did not matter; on every session page of a campaign it does, or tonight's recording would light up last March's session as "Recording in progress". The payload carries the session id it belongs to, so a recording of another session is reported as exactly that and Start is refused rather than offered. Also removed the frontend's `approveAudio` wrapper: it called the backend's documented deprecated shim for `/approve`, and the dashboard's "Approve transcript" button was its only caller; the session page's "Approve summary" is the same action against the non-deprecated endpoint. The shim itself is untouched. One thing to revisit if a deployment ever grows: the panel opens the SSE stream (one Redis pubsub connection) on every GM session-page view; gating it by status reintroduced the visibility holes this issue exists to remove, so it is left ungated, GM-only. Frontend suite: 64 files / 799 tests passing, eslint clean apart from the pre-existing `CampaignDetail.jsx` warning, `vite build` clean.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#386
No description provided.