diff --git a/README.md b/README.md index 43032be..aea8d68 100644 --- a/README.md +++ b/README.md @@ -540,9 +540,11 @@ unresolved - every step still needs `default.step` merged in), and the `StepPlate`/`_update_step_plates()`/`update_status_step_label()` logic behind the Progress tab and status line. New/Load/Save (a plain ``/`FileReader` and a `Blob`/`` standing in -for the desktop app's native file dialogs) and Start/Stop are wired up too -- see `web/TODO.md` for what's still missing (Pause/Confirm, `WAIT_USER` -surfacing, and more). Deliberately deferred rather than stubbed: the +for the desktop app's native file dialogs), Start/Stop, and Confirm (a +plain `` pops with the step's message on `WAIT_USER` and sends +Confirm when dismissed) are all wired up too - see `web/TODO.md` for +what's still missing (Pause, and more). Deliberately deferred rather than +stubbed: the Automatic tab's forecast-vs-actual plot and the live Plot tab's strip charts - both need a charting approach, revisit once Manual + Progress are validated. diff --git a/web/TODO.md b/web/TODO.md index 282ba6e..66acb5e 100644 --- a/web/TODO.md +++ b/web/TODO.md @@ -7,22 +7,19 @@ flagged as deferred in the plan, or only noticed once the port was done and checked against the Qt source side by side. - [x] **No way to actually run a brew.** ~~There's no Start/Pause/Stop/ - Confirm anywhere in `web/index.html`~~ Start/Stop are now wired up - (`btn-sud-start`/`btn-sud-stop` in `app.js`, gated by `updateSudActions()` - mirroring `update_sud_actions()`'s enabled/disabled logic). Still - missing: Pause, and `{"Sud": {"Confirm": true}}` - that one needs - `sudUserMessage`/`sudState` (next item) to know *when* it's actually - waiting on one. + Confirm anywhere in `web/index.html`~~ Start/Stop/Confirm are now wired + up (`btn-sud-start`/`btn-sud-stop` in `app.js`, gated by + `updateSudActions()` mirroring `update_sud_actions()`'s + enabled/disabled logic; Confirm via the `#sud-message-dialog` below). + Still missing: Pause - trivial to add the same way as Start/Stop + whenever it's actually needed. -- [ ] **`WAIT_USER` never surfaces to the user.** `sudUserMessage` is - tracked in `app.js` but nothing ever shows it - `show_user_message()` - (`client/brewpi_gui.py:877-882`) pops a modal the instant `WAIT_USER` is - newly entered (`prev_state != WAIT_USER`) and sends `Confirm` itself - when the user dismisses it. Needs the same "newly entered" edge - detection in `onSudChanged()`'s `State` branch (the `wasRunning` - tracking there is close, but checks running-vs-not, not specifically - the `WAIT_USER` transition) plus a modal (a plain `` works, - no library needed) that sends `Confirm` on close. +- [x] **`WAIT_USER` never surfaces to the user.** `showUserMessage()` + pops `#sud-message-dialog` (a plain ``, no library) the instant + `WAIT_USER` is newly entered (`onSudChanged()`'s `State` branch tracks + `prevState` for this), and sends `{"Sud": {"Confirm": true}}` on the + dialog's `close` event - covers both the OK button and Escape, mirrors + `show_user_message()` (`client/brewpi_gui.py:877-882`). - [x] **No schedule management.** New/Load/Save are now wired up in `app.js`: Load is `` + `FileReader` + diff --git a/web/app.js b/web/app.js index 0044264..33524c3 100644 --- a/web/app.js +++ b/web/app.js @@ -9,6 +9,7 @@ const CHANNELS = ['Pot', 'Sensor', 'Heater', 'Stirrer', 'TempCtrl', 'Sud', 'Syst // "running" - mirrors client/brewpi_gui.py's SUD_RUNNING_STATES. const RUNNING_STATES = new Set(['SudState.RAMPING', 'SudState.HOLDING', 'SudState.WAIT_USER']); const PAUSED_STATE = 'SudState.PAUSED'; +const WAIT_USER_STATE = 'SudState.WAIT_USER'; let ws = null; let connected = false; @@ -306,6 +307,14 @@ function updateSudActions() { document.getElementById('btn-sud-stop').disabled = !(running || paused); } +// Mirrors client/brewpi_gui.py's show_user_message(): the Sud is already +// blocked in WAIT_USER server-side - dismissing this dialog (OK or Escape, +// both fire the dialog's 'close' event) is what unblocks it. +function showUserMessage(message) { + document.getElementById('sud-message-text').textContent = message; + document.getElementById('sud-message-dialog').showModal(); +} + function downloadJson(doc) { const blob = new Blob([JSON.stringify(doc, null, '\t')], {type: 'application/json'}); const url = URL.createObjectURL(blob); @@ -462,6 +471,7 @@ function onSudChanged(msg) { } } else if (key === 'State') { const newState = msg.State; + const prevState = sudState; const isRunningNow = RUNNING_STATES.has(newState); if (isRunningNow && !wasRunning) { elapsed = 0; @@ -470,6 +480,9 @@ function onSudChanged(msg) { } wasRunning = isRunningNow; sudState = newState; + if (newState === WAIT_USER_STATE && prevState !== WAIT_USER_STATE && sudUserMessage) { + showUserMessage(sudUserMessage); + } updateStepPlates(); updateSudActions(); } else if (key === 'UserMessage') { @@ -661,6 +674,9 @@ document.getElementById('btn-sud-start').addEventListener('click', () => { document.getElementById('btn-sud-stop').addEventListener('click', () => { sendMsg('Sud', {Stop: true}); }); +document.getElementById('sud-message-dialog').addEventListener('close', () => { + sendMsg('Sud', {Confirm: true}); +}); document.querySelectorAll('.tab-btn').forEach((btn) => { btn.addEventListener('click', () => { diff --git a/web/index.html b/web/index.html index 8b809ea..eda2405 100644 --- a/web/index.html +++ b/web/index.html @@ -102,6 +102,13 @@ + +

+
+ +
+
+