diff --git a/web/app.js b/web/app.js index bfc716d..5f3b658 100644 --- a/web/app.js +++ b/web/app.js @@ -504,7 +504,11 @@ function updateSudForecast(doc) { sudEmpty = sudSchedule.length === 0; if (isNewSchedule) { sudStepDescr = null; - sudStepIndex = null; + // sudStepIndex is NOT reset here: Step messages are the authoritative + // source. If a Step already arrived before this Json (e.g. from the + // global-state replay), resetting would leave the schedule built but + // the index null, causing grain/level to vanish until the next step + // change. The Step handler always overwrites it anyway. sudStepType = null; sudHoldRemaining = 0; forecastStepStarts = {}; @@ -624,7 +628,15 @@ function onTempCtrlChanged(msg) { } function onSudChanged(msg) { - for (const key of Object.keys(msg)) { + // Json must be processed before Step: both can arrive in the same + // global-state replay message, but Step was inserted into global_state + // first (at brew start), so it precedes Json in server key order. + // Processing Step first would set sudStepIndex before the schedule + // exists, then Json would reset it to null (isNewSchedule=true on + // first/reloaded connect) with no subsequent Step to restore it. + const keys = ['Json', ...Object.keys(msg).filter(k => k !== 'Json')]; + for (const key of keys) { + if (!(key in msg)) continue; if (key === 'Json') { // A standalone reply to a just-sent {Save: true} (see // btn-sud-save's handler below) - not a schedule update to