Repository navigation
Chat voting: saved votes, new panel and immediate action (#400) - #401
Merged
Merged
Conversation
- 📊 Database: - Migration 0047 adds chat_vote_templates (revision, legacy_alias, last_used_at, shortcut index) - Non-empty legacy label settings move once into templates; aliases resolve via legacy_alias - LATEST_SCHEMA_MIGRATION bumped to 0047 - ✨ Features: - Template CRUD with revision check (409), cap of 100 per channel, same member guard as start - templateStartProblem gives one reason for panel, immediate action and !vote <shortcut> - !vote <shortcut> starts a template; unknown single tokens reply instead of starting - Immediate-action card with running status, End and a scrolling template list in the standard 192px card - 🎨 Style: - Panel: fixed live block above ListDetail, Saved | Recent list with one status row, inspector with fixed footer - Quick templates with undo toast, free-text switch card, duration segment with compact custom row, !vote prefix - 🛠 Improvements: - Serialized autosave flushed before start, switch and leave; 409 reloads with a toast - Settings editor drops the five label fields - The worker no longer reads or writes preset and legacy_written - 🧪 Tests: - Template migration, routes, repository, service and parser coverage - Panel, inspector and immediate-action component tests - Stability e2e restored and extended (custom duration, five free-text rows, overnight time, card height) Refs #400
- 🐛 Defects: - PATCH acknowledges via UPDATE … RETURNING so a concurrent write is never taken as our own revision - Autosave recomputes dirty state after each acknowledgment; flush awaits pending saves and drains later edits - Start keeps the latest acknowledged revision when recording usage - Unload saves use a cached CSRF token and keepalive without a fresh request - Migration 0047 keeps one-answer yes/no, 0/1, 1/2 and scale drafts; only options need two labels - Custom duration can be selected from a preset; mode is tracked separately - Immediate-action Start/End no longer depend on canManage; the server guard decides - Live block keeps one reserved height across loading, empty, error and running on mobile - Running markers and Recent refresh after card, chat or external starts and closes - 🧪 Tests: - Regression test per defect (repository, panel, card, migration, stability e2e) Refs #400
- 🐛 Defects: - Server-reported shortcut conflicts are kept until the shortcut changes, ending the save loop - Recovered drafts carry their base revision and snapshot; a newer remote edit leads to conflict recovery - Invalid CSRF tokens are refetched once for active mutations - Usage bookkeeping failures no longer turn a completed start into an error - Live-state and usage responses are sequenced so stale replies cannot roll the UI back - Immediate-action card keeps its loaded order after starts - Restored drafts select the matching duration segment - Usage refresh success clears the template error state - 🔒 Security: - Template create, update and delete write guarded audit records with actor and before/after - 🧪 Tests: - Regression test per defect Refs #400
- 🔄 Refactors: - Remove the autosave hook (debounce, queue, unload saves, draft recovery, blank reuse) and the quick-template undo toast - Inspector keeps one local draft with the dashboard SaveBar: Save, Discard, status, 409 reload, delete in the destructive slot - New votes stay local until the first Save; Start saves a dirty draft first and starts only on success - Discard confirmation when switching, closing or leaving with unsaved changes - 🐛 Defects: - PATCH acknowledges via UPDATE … RETURNING inside the guarded audit batch - Polling applies responses by sequence without starving slow connections - Immediate-action refresh merges configuration and membership in session order - Running notice keeps a fixed-height slot - 🧪 Tests: - Explicit-save flow, RETURNING under concurrency, slow polling, card refresh, notice slot Refs #400
# Conflicts: # src/modules/chat_voting/panel/index.tsx # src/modules/chat_voting/panel/service.ts # src/modules/chat_voting/routes.ts # src/worker/config.ts # tests/components/chat-voting-panel.test.tsx # tests/unit/chat-voting-routes.test.ts # tests/unit/sql-contract.test.ts # tests/worker/healthz.test.ts
- 🎨 Style: - Delete moves into the inspector header menu; Start gets its own fixed row above the standard SaveBar - 🐛 Defects: - The implicitly opened desktop template keeps its guarded draft across responsive changes - A second save of a new vote no longer remounts the inspector and drops pending edits - Template saves and deletes go through runModuleQueryWrite so stale reads cannot overwrite them - Escape closes the desktop Recent inspector (SubInspector) - 🧪 Tests: - Footer visibility at 1440, 1100, 760 and 390 px; one regression test per defect Refs #400
- 🎨 Style: - At inspector widths up to 480px the save status gets its own row inside the 64px bar - Header actions menu sits right next to the close button - 🐛 Defects: - A pending delete can no longer discard another template's draft - Reselecting a template after a remote save adopts its newer revision - A delayed Start only merges lastUsedAt and keeps newer configuration - Aborted loads no longer raise load-error notifications - 🧪 Tests: - Regression test per defect; status fits at 390px with a 20 % margin Refs #400
- 🐛 Defects: - Save and reload completions from a replaced inspector are ignored, so B's edits can never be written into A - Template usage timestamps update monotonically in the database and in the immediate-action cache - 🧪 Tests: - Delayed reload while editing another template; out-of-order starts keep the newest usage time - New-draft save test waits for the Save button instead of asserting synchronously Refs #400
# Conflicts: # src/dashboard/ui/ListToolbar.tsx # src/modules/chat_voting/panel/index.tsx
- 🐛 Defects: - A delayed conflict reload no longer overwrites edits made after Discard; duplicate reloads are ignored - A manual retry error clears on the next successful fetch even when the data is unchanged (useManualQueryFailure) - 🧪 Tests: - Delayed reload after Discard and edits, duplicate reload clicks, recovery after identical refreshes Refs #400
- 🐛 Defects: - Conflict Reload uses refetchModuleQueryData so cache and inspector hold the same revision; reselecting no longer rolls back - 🧪 Tests: - Reload followed by reselection keeps the newest revision Refs #400
|
This was referenced Oct 11, 2026
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.



Second slice of the chat voting rework (epic #397), after #399.
What changes
0047addschat_vote_templates(revision,legacy_alias,last_used_at, unique shortcut per channel). Non-empty legacy label settings move once into templates;!vote yesno/scale/01/12resolve their migrated template vialegacy_alias. The settings editor drops the five label fields.templateStartProblemgives one reason for the panel ▶, the immediate-action ▶ and!vote <shortcut>; unknown single tokens reply instead of starting.ListDetail; list with Saved | Recent, one 20 px status row (n/100, lock reason), flat rows, order fixed per session; inspector with question, answers, quick templates (undo toast), free-text switch card, duration segment with a compact custom row,!voteshortcut and a fixed footer (save status, Start, subtle Delete). Below 1280 px the inspector is an overlay that opens only on click.presetandlegacy_written; dropping those columns follows in a later PR, after this one runs in production.Deploy order
Production applies migrations by hand before the worker deploy.
0047only adds a table and reads settings, so it is safe while the #398 worker runs.0046must already be applied. Do not edit chat voting settings between applying0047and deploying the worker: label settings are copied once at migration time.Verification
pnpm run checkgreen (unit, worker, 118 e2e);module-panels-stability.spec.tsgreen with--repeat-each=10.Closes #400