fix(web,api): soft-delete filter, StrictMode hub, one-click Stop, quick timer#3
Merged
Merged
Conversation
…ck timer, dashboard polish Follow-up on the apple-ux-pass branch addressing issues found during in-browser testing, plus a small new feature. Server - AppDbContext: query filters for Event / Room / ScheduleItem now also exclude rows whose DeletedAtUtc is set. Before this fix, deletes were soft-deletes but the list/get endpoints kept returning the same rows, so the UI showed "deleted" items reappearing. Callers that need to see tombstones must use IgnoreQueryFilters() (audit, undo, purge jobs). Hub / connection - useTimerHub: move hub instantiation back inside the effect (was hoisted into useMemo). With React 18 StrictMode the same hub object survived the dev-mode double-mount, so .start() ran twice on the same connection and rejected with "Cannot start a HubConnection that is not in the 'Disconnected' state." A fresh per-mount hub fixes it. - useEventRoomSnapshots: catch each per-room resync individually and run the hub at LogLevel.Critical so expected per-room Forbidden rejections on the dashboard (RoomOperator scoped to a subset, Viewer with no hub access) don't surface as red errors. Presence fetch falls back to empty on Forbidden. - TimerHub: accept an optional LogLevel so consumers can opt down to Critical for read-only dashboards. Operator console - Stop is a one-click Button again. The hold-to-confirm pattern was too strict for the normal "speaker finished, end the session" flow; Skip and Reset remain hold-to-confirm in the More menu where the destructive risk lives. - OperatorHero gains an empty-state "Quick timer" CTA when the room has no current item and no upcoming item. - New QuickTimerSheet: title + MM:SS duration + 5/10/15/30 min presets. Creates a one-off schedule item (scheduledStartUtc=now, preRoll=0) and starts it via hub.startItem. Lets operators run an ad-hoc countdown without authoring a schedule first. Misc dashboard - Picks up the surrounding edits already on the branch: presence pill on LobbyCard, Live · N/M rooms running in EventIdentity, Show mode entry, RehearsalControls + useRehearsalClock + lib/rehearsal, PreflightPanel + lib/preflight, useToast moved to its own toastContext file, plus the matching new tests. Verification - tsc clean, 73/73 tests pass (4 new — preflight + rehearsal), build succeeds. - Manual: delete a schedule item now actually removes it; Stop ends the session on a single click; signing in on a fresh tab no longer fires StrictMode "cannot start HubConnection" errors; Quick timer starts immediately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Follow-up to #2, addressing issues found during in-browser testing of the apple-ux-pass plus one small new feature.
Server
AppDbContextquery filters forEvent/Room/ScheduleItemnow also exclude rows whoseDeletedAtUtcis set. Before this, deletes were soft-deletes but the list endpoints still returned the same rows, so the UI showed "deleted" items reappearing immediately. Callers that need to see tombstones (audit, undo, purge jobs) must useIgnoreQueryFilters(), per the existing convention.Hub / connection
useTimerHub) — moved hub instantiation back inside the effect (it had been hoisted intouseMemo). With React 18 StrictMode the same hub object survived the dev-mode double-mount, so.start()ran twice on the same connection and rejected withCannot start a HubConnection that is not in the 'Disconnected' state.A fresh per-mount hub fixes it.useEventRoomSnapshots) — each per-roomresyncis caught individually, and the underlying connection runs atLogLevel.Criticalso expected per-roomForbiddenrejections on the dashboard (RoomOperator scoped to a subset, Viewer with no hub access) don't surface as red errors. Presence fetch falls back to empty presence on Forbidden.TimerHubnow accepts an optionalLogLevelso consumers can opt down toCriticalfor read-only multi-room dashboards.Operator console
QuickTimerSheet(title + MM:SS duration + 5/10/15/30 min presets); creates a one-off schedule item (scheduledStartUtc = now,preRoll = 0) and starts it viahub.startItem.OperatorHeroshows the CTA when the room has no current item and no upcoming item.Dashboard / surroundings (already on this branch)
LobbyCard(lobby displays connected).EventIdentitystatus pill now readsLive · N/M rooms running.RoomShowModePage+Show modebutton.RehearsalControls+useRehearsalClock+lib/rehearsalfor offline pacing.PreflightPanel+lib/preflightfor pre-show checks.useToastmoved into its owntoastContext.tsfile (fast-refresh hygiene).Test plan
tsc -bcleannpm test— 16 test files, 73 tests pass (4 new: preflight + rehearsal)npm run buildsucceedsOperatorHeroempty state and starts an ad-hoc countdownDeploy notes
This includes a backend change (
AppDbContext). The Docker image needs rebuilding;docker compose build app && docker compose up -d appis sufficient locally. No DB migration required — theDeletedAtUtccolumns already exist.🤖 Generated with Claude Code