Skip to content

feature: estimated watts, sortable fleet table, and page-timer refresh - #54

Merged
TheWitness merged 2 commits into
developfrom
feature/estimated-watts
Oct 16, 2026
Merged

TheWitness merged 2 commits into
developfrom
feature/estimated-watts

Conversation

@TheWitness

Copy link
Copy Markdown
Member

Summary

Adds estimated wattage for UPSes that do not report real output power, makes the Fleet Dashboard UPSes table sortable, and fixes the dashboard auto-refresh following the user to other pages.

1. Estimated watts (nominal power x load % / 100)

New apcupsd_estimate_watts() in includes/functions.php (unit-tested) so every view derives the figure the same way. It returns null for missing, non-numeric or negative inputs, or when the nominal power is not a positive rating. Load above 100% is not clamped.

  • Fleet Dashboard, Overview: a new "Est. Power" tile showing the fleet total.
  • Fleet Dashboard, new "Fleet Power" card: a gauge of total estimated watts against the rated capacity of the UPSes counted, with a "Counted N of M enabled UPSes" note.
  • Fleet Dashboard, UPSes card: an "Est. Power" column and a "Fleet Total" footer row.
  • UPSes list (upses.php): a sortable "Est. Power" column, computed in SQL and validated as a sort column through the existing header definitions.

Only enabled UPSes contribute to totals. A disabled UPS shows N/A because its last reading is no longer polled. The fleet figures come from the latest poll, not an RRD window.

2. Sortable Fleet Dashboard table

Columns UPS, Status, Load, Charge, Time Left, Est. Power and Last Updated are sortable. I read "Charts" in the request as the Charge column; the table has no chart column.

  • Numbers sort largest first on the first click and text A-Z, and clicking again toggles.
  • N/A values always sort last and ties keep server order.
  • The choice is stored in localStorage (keyed by column, not position) and re-applied after card refreshes, added cards and the maximize dialog.
  • Headers are real <button>s with aria-sort; there are no inline handlers (CSP-safe).

3. Auto-refresh no longer follows you to other pages

Both dashboards used set_page_refresh(), which parks the interval in the PHP session until some page's footer consumes it, so the dashboard's interval and refreshPage could be applied to whichever page rendered next. They now set Cacti's refreshMSeconds, refreshPage and refreshIsLogout globals from a ready callback and call setupPageTimeout(), the same way core's graph_view.php does. Nothing is stored in the session; Cacti already clears its timer when navigating, and the next page's footer re-emits its own values. The callback only applies while the dashboard grid is still on the page. I did not add a plugin-side timer or navigation handler.

I could not reproduce the stale-refresh symptom without a live Cacti, so this change follows the cause I identified from core's global_session.php and layout.js; please confirm it on a live install.

Notes

Validation

  • Pest: 96 tests pass in a scratch Cacti layout, including the new EstimatedWattsTest and DashboardRefreshTest.
  • The check-i18n-pot.php gate passes.
  • The fleet card renderers were executed with stubbed Cacti functions; the output, escaping and arithmetic were checked (for example 12% of 1500 W is 180 W).
  • The sorter was exercised in a real browser against the rendered table: first-click direction, toggling, N/A last, footer stays put, persistence across reload, aria-sort, and server-order ties.
  • Not tested: a live Cacti with real UPS data, the CI patch-coverage job (no coverage driver locally), and the refresh behaviour in a real browser session.

- Estimate each UPS's power as nominal power x load % for UPSes that do not
  report real wattage (apcupsd_estimate_watts()). Show it on the Fleet
  Dashboard as an "Est. Power" tile, a new "Fleet Power" gauge card (total
  estimated watts against rated capacity) and an "Est. Power" column with a
  fleet total in the UPSes card, and as a sortable "Est. Power" column in the
  UPSes list.
- Make the Fleet Dashboard UPSes table sortable by UPS, Status, Load, Charge,
  Time Left, Est. Power and Last Updated. N/A values sort last, ties keep
  server order, and the choice persists in the browser across refreshes.
- Drive the dashboard auto-refresh through Cacti's refreshMSeconds /
  refreshPage / refreshIsLogout globals (as graph_view.php does) instead of
  set_page_refresh(), which parked the interval in the session so it could
  follow the user to another page.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 16, 2026 16:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Fleet-table sorting loses the selected order when browser storage is unavailable or writes fail.

1 open finding
What changed in this PR

Adds estimated power reporting and sortable fleet data to the Cacti plugin, and changes dashboard refresh handling.

Changes:

  • Adds estimated wattage to fleet cards and UPS tables.
  • Adds persistent, accessible fleet-table sorting.
  • Uses Cacti’s page timer instead of session-based refresh settings.
File Description
upses.php Adds sortable estimated power column.
tests/​Unit/​EstimatedWattsTest.php Tests wattage calculation and feature wiring.
tests/​Unit/​DashboardRefreshTest.php Checks refresh integration patterns.
locales/​po/​cacti.pot Adds translation strings.
js/​apcupsd_dashboard.js Implements persistent table sorting.
includes/​functions.php Adds wattage estimation helper.
includes/​dashboard.php Adds fleet power displays and page-timer refresh.
css/​apcupsd.css Styles sorting controls and fleet totals.
CHANGELOG.md Documents features and refresh changes.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread js/apcupsd_dashboard.js
xmacan
xmacan previously approved these changes Oct 16, 2026
apcupsdDashApplySort() re-read localStorage after each click, so when storage
was blocked or a write failed the newly selected sort was lost (or an older
saved sort was reapplied). Hold the active sort state in memory, seed it once
from localStorage, and make persistence best-effort so sorting and direction
toggling work without storage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The page-timer change still needs live Cacti validation across dashboard refreshes and navigation.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

@TheWitness
TheWitness merged commit cd04638 into develop Oct 16, 2026
4 checks passed
@TheWitness
TheWitness deleted the feature/estimated-watts branch October 16, 2026 16:48
TheWitness added a commit that referenced this pull request Oct 16, 2026
… reuse apcupsd_estimate_watts()

- Share only the fixed-card arrangement across UPSes; store each UPS's graph
  cards (local_graph_id keys) in their own row with a graphs_slot marker so
  saving from one UPS no longer overwrites or hides another UPS's graphs.
- Persist a layout migrated from the per-UPS row or the pre-release combined
  map to the shared row on first read, with the existing 4096-char guard.
- Compute the per-UPS Estimated Power card with the shared
  apcupsd_estimate_watts() added in #54 instead of duplicating the formula.
- Add DashboardLayoutTest and a CHANGELOG entry.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
TheWitness added a commit that referenced this pull request Oct 16, 2026
… Power card (#51)

* dashboard: shared layout, hide N/A in info card, combine Cable/Driver, add Estimated Power card

* dashboard: keep graph cards per UPS, persist legacy layout migration, reuse apcupsd_estimate_watts()

- Share only the fixed-card arrangement across UPSes; store each UPS's graph
  cards (local_graph_id keys) in their own row with a graphs_slot marker so
  saving from one UPS no longer overwrites or hides another UPS's graphs.
- Persist a layout migrated from the per-UPS row or the pre-release combined
  map to the shared row on first read, with the existing 4096-char guard.
- Compute the per-UPS Estimated Power card with the shared
  apcupsd_estimate_watts() added in #54 instead of duplicating the formula.
- Add DashboardLayoutTest and a CHANGELOG entry.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* dashboard: exclude slave UPSes from fleet estimated power and show N/A

A slave's draw is already part of its master's, so leave it out of the
fleet power total, capacity and count, and show N/A for its Est. Power in the
Fleet Dashboard table.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* dashboard: preserve graph placement per run, keep shared slots for graphless UPSes, migrate each UPS's legacy graphs

- Store one graphs_slot marker per run of consecutive graph cards and one
  graph run per marker, so graphs interleaved with fixed cards keep their
  placement across a save/reload.
- When a UPS with no graphs saves, re-anchor the existing shared slots to the
  nearest surviving fixed card instead of dropping them.
- When the shared row already exists but a UPS has no graph row, migrate and
  persist that UPS's own legacy graph selection (per-UPS row, then combined
  map) before defaulting to all graphs; the shared fixed layout is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants