fix(web): pause plan, heating, settings, and card polls when hidden - #1177
fix(web): pause plan, heating, settings, and card polls when hidden#1177frahlg wants to merge 1 commit into
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_26a075e4-948f-41e5-8fc8-19f95a08bcd2) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4450d42710
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (!window._evStatusTimer) { | ||
| window._evStatusTimer = setInterval(function () { |
There was a problem hiding this comment.
Restart the EV timer after rerendering the tab
When the provider selector calls ctx.renderTab("ev"), the existing timer is still active, so this condition preserves an interval whose callback closes over the previous refresh function and its now-detached el. The newly rendered badge gets the immediate refresh but no subsequent interval updates, leaving its charger status stale until the tab is left for at least one timer tick or the modal is reopened; clear the existing timer whenever after installs the new callback.
Useful? React with 👍 / 👎.
| } | ||
| return; | ||
| } | ||
| pollPlan(); |
There was a problem hiding this comment.
Coalesce the plan refresh when visibility returns
If the tab is hidden while a plan fetchAll() is in flight and restored before it settles, this unconditional call starts another six-endpoint batch because fetchAll has no in-flight or revision guard. The two batches can both render, allowing the later-settling older refresh to overwrite the catch-up result while also doubling load on the box; defer the catch-up until the active refresh settles or abort/sequence the old request.
Useful? React with 👍 / 👎.
Plan, heating, settings, history/savings/price cards, loadpoints and twins now follow the same visibilitychange rule as status polling: clear the timer while document.hidden, then one fetch and one timer on return. Settings EV and System timers also stop when the modal closes. Energy-flow particles skip rAF while hidden. Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
4450d42 to
64dfd25
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a6baaade-b01b-4750-8cbe-8bf23bb5402d) |
miravoss26
left a comment
There was a problem hiding this comment.
Consistent visibility-pause pattern applied across plan, heating, history/savings/price cards, loadpoints/twins, Settings EV/System, and the energy-flow particle rAF loop: clear timers on visibilitychange → hidden, one fetch + one fresh timer on → visible. Heating's queued-refresh-while-hidden edge case is handled explicitly (waiters resolve without a stale catch-up fetch). Settings EV/System additionally stop via a MutationObserver on the modal's hidden class, which is the right hook since those timers are scoped to the modal being open, not just tab visibility.
Spot-checked ftw-energy-flow.js, ftw-history-card.js, ftw-price-chart.js, ftw-savings-card.js, and heating.js — the _syncPolling/syncHeatingPolling refactors are equivalent to the old _restartPolling plus the new hidden-check, no dropped isConnected guards. hidden-tab-polls.test.mjs (269 new lines) exercises heating and EV-settings with real timer/DOM mocks, not just source-pattern assertions. All CI green, no security surface here (client-side polling/animation only).
Safe to merge from my read.
Closes #1141.
Status polling in
app.jsalready respectsdocument.hidden. Plan, heating, dashboard cards, loadpoints/twins, and the Settings EV/System tabs did not. They kept hitting the box (plan's 30s/api/configbeing the worst) after the tab was backgrounded, and Settings timers kept firing after the modal closed.What changed
Same pattern as
syncStatusPollinginapp.js: onvisibilitychange, clear the timer while hidden; on return, one fetch and exactly one timer.web/plan.js) — 30s plan bundle and 5s strategy hintweb/heating.js) — 30s live refresh; a queued overlap does not catch up while hiddenhiddenrequestAnimationFramewhile hidden (helps perf(web): stop dashboard render loops when their view is hidden #881 paint; CSS dash animation is unchanged)Resume is one fetch so the first visible frame is current. If
document.hiddenis missing, polling continues.Left for other PRs
web/settings/tabs/ha.js) still polls after close — open PR feat(modbus): share one TCP session per device and proxy it #1003 has that file.settings.js,settings/tabs/control.js,weather.js, orindex.html(open PR feat(web): the Control tab owns the forecast inputs; no Weather tab #1052).web/models.jsadvanced poll is unchanged (not in the allowed overlap set).#881 stays open for remaining energy-flow/chart paint (CSS dash animation, chart 30fps loop already pauses in
app.js). This PR only paused the particle rAF and the network polls.Tests
web/hidden-tab-polls.test.mjsdrives heating (pause / single-flight / resume-one-fetch, dormant hidden start) and the EV settings timer (hidden + close). Source matches cover the other pollers.node --test web/— 587 pass. (npm teston Node 20 does not expand the quoted glob inpackage.json; CI Node is new enough.)Visual check
AGENTS.md: a human must inspect the rendered UI. This environment cannot do a real browser pass. Please confirm:
Note
Low Risk
Client-side polling and animation only; behavior is additive pause/resume with tests, with no auth or data-path changes.
Overview
Background tabs and closed Settings modals no longer keep hammering the box with timers that
app.jsstatus polling already respected.Visibility (
document.hidden) — Plan (30s bundle + 5s strategy hint), heating (30s), history/savings/price cards (~5 min), and advanced-mode loadpoints/twins (10s) now listen forvisibilitychange, clear intervals while hidden, and on return run one fetch then a single interval. Heating also skips a queued post-refresh catch-up if the tab went hidden mid-flight.Settings EV & System — 5s status polls run only while the settings modal is open and the document is visible; a
MutationObserveron the modal’shiddenclass stops the timer when the modal closes.Energy-flow diagram — Particle
requestAnimationFrameloops stop when the tab is hidden and resume when shown (CSS dash animation unchanged).New
web/hidden-tab-polls.test.mjsexercises heating and EV settings behavior; source assertions cover the other pollers.Reviewed by Cursor Bugbot for commit 64dfd25. Bugbot is set up for automated code reviews on this repo. Configure here.