You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add a Fleet (Summary) Dashboard with min/avg/max bullet charts - #71
Adds a Fleet (Summary) Dashboard — the aggregate counterpart to the per-device Dashboard — reached by the same dashboard glyph (same icon, first position) on the Summary tab's Device Type Summary Statistics rows. It replaces "boring tables" with visual, min/avg/max bullet charts and other graphics.
A draggable, add/remove card grid scoped to all devices or a single OS type (switchable in the toolbar). Cards:
Fleet Overview — stat tiles: devices, up / recovering / down / disabled (colour-coded), CPUs, logins, processes, total RAM.
Resource Utilization — min/avg/max bullet charts for CPU %, Memory %, Swap % (severity-tinted band + average marker) and Processes/host.
Device Status — a horizontal stacked bar (up/recovering/down/disabled) with a counted legend.
Storage Utilization — a used-% bullet plus total/used capacity.
Uptime Distribution — a min/avg/max uptime bullet.
OS Type Distribution — ranked horizontal bars per OS type.
Top Processes by CPU and Top Processes by Memory — fleet-wide, sortable, each row with a relative mini-bar.
Behaviour mirrors the per-device dashboard: drag/keyboard reorder, per-card refresh/maximize/remove, an "Add card" catalogue, an auto-refresh interval, and client-side sortable tables. Scope (OS type), card order, expanded state and the refresh interval all persist per user in settings_user. A stateful Fleet Dashboard tab appears after first use and remembers the last scope.
Implementation notes:
Aggregates come from hrSystem / hrStorage / hrSWRun scoped by host_type; the utilization stats only count up/recovering devices so stale values from down devices don't skew min/avg/max.
To avoid any risk to the merged per-device dashboard JS, this ships a self-contained controller (js/hmib_summary_dashboard.js) that reuses the shared .hmibDash* card CSS. (A future refactor could unify the two controllers behind one config-driven module.)
CSRF-checked AJAX endpoints summary_card / summary_layout / summary_refresh; nonce'd inline init with JSON_HEX_* hardening. All visuals are theme-adaptive via color-mix.
Related Issue
Follows the per-device Host Dashboard (#68) and its fixes (#69, #70).
Motivation and Context
The Summary tab's dense statistics tables are hard to scan. A card dashboard with bullet charts (which naturally express the min/avg/max spread across a fleet) and top-process panels gives an at-a-glance fleet view, customizable per user and per OS type.
How Has This Been Tested?
php -l clean on hmib.php; tests/bin/validate-manifest.php passes (new JS lives under the already-listed js/); locales/po/cacti.pot regenerated; JS/CSS brace-balanced. Needs a browser pass on a themed install to confirm the bullet charts, stacked/mini bars, drag/add/remove/refresh and the stateful tab, since CI doesn't exercise the UI.
Types of changes
Bug fix (non-breaking change which fixes an issue)
New feature (non-breaking change which adds functionality)
Breaking change (fix or feature that would cause existing functionality to change)
Checklist:
My code follows the code style of this project.
My change requires a change to the documentation.
I have updated the documentation repository accordingly.
…charts
A dashboard glyph (same icon/first position as the per-device dashboard) on the Summary tab's Device Type rows opens a Fleet Dashboard scoped to all devices or one OS type:
- Draggable add/remove card grid reusing the shared .hmibDash* card chrome, with its own self-contained controller (js/hmib_summary_dashboard.js) so the merged per-device dashboard JS is untouched.
- Cards: Fleet Overview (status + resource stat tiles), Resource Utilization (min/avg/max BULLET CHARTS for CPU/memory/swap/processes), Device Status (stacked bar), Storage Utilization (bullet + capacity), Uptime Distribution (bullet), OS Type Distribution (bars), and Top Processes by CPU and by Memory (sortable, with relative mini-bars).
- Aggregates come from hrSystem/hrStorage/hrSWRun scoped by host_type; utilization stats consider only up/recovering devices so down-device staleness does not skew min/avg/max.
- CSRF AJAX endpoints summary_card/summary_layout/summary_refresh; scope (OS type), card order, expanded state and refresh interval persist per user in settings_user. A stateful 'Fleet Dashboard' tab appears after first use and remembers the last scope.
- Visuals (bullet charts, stat tiles, stacked bar, distribution/mini bars) are theme-adaptive via color-mix; nonce'd inline init + JSON_HEX hardening.
…, snake_case)
- Storage bullet: gate the per-volume used% min/avg/max on host_status >= 2 so stale values from down/disabled hosts don't skew the live distribution, while keeping capacity totals over all volumes.
- OS Type Distribution card: apply the \ scope predicate and switch to db_fetch_assoc_prepared(), binding the translated 'Unknown' fallback so a locale apostrophe can't break the SQL.
- Top Processes by CPU/Memory: always join hrSystem and require host_status >= 2 so the AVG/MAX rankings use only live devices (the all-types scope previously had no host-status column at all).
- Rename the new camelCase locals (cpuSev/memSev/swSev/procScale/stoSev/upScale) to snake_case per the repo convention.
The fill is an empty <span> in normal inline flow, so its inline width and height: 100% are ignored and only the unfilled track is visible. Give the fill a block-level display so each OS distribution bar reflects its calculated width.
This issue also appears on line 681 of the same file.
Remove OS type limit or aggregate excess types
hmib.php:5149
This limit silently omits OS types after the first 15, and expanding the card cannot reveal them, so fleets with more than 15 types get an incomplete distribution. Remove the limit since the card already clips and expands its body, or explicitly aggregate the remainder into an “Other” row.
Preserve latest expanded state when replacing AJAX content
js/hmib_summary_dashboard.js:243
The request snapshots the expanded state before the AJAX call. If the user expands or collapses this card while the request is pending, the returned section restores the stale state even though the newer state was already persisted. Copy the current card's expanded class to fresh immediately before replacing it.
… bar fills, refresh race)
- Use -1 as the all-types sentinel instead of 0, since Cacti already uses 0 for the Unknown OS type. The Unknown Device Type row's glyph (ostype=0) now correctly scopes to untyped devices, and the scope picker gains an explicit Unknown option. All aggregate queries scope on host_type when ostype >= 0 (Unknown or a specific type) and span the whole fleet only for -1.
- OS Type Distribution: drop the LIMIT 15 so fleets with more than 15 types are fully represented (the card already clips/expands).
- Make the distribution-bar and top-process mini-bar fills block-level so their percentage widths actually render (an inline <span> ignored width/height).
- Top-process refresh: copy the card's current expanded class onto the fresh node before swapping, so toggling expand/collapse while a refresh is in flight is not reverted by the stale snapshot.
Summary row groups host types but link uses one arbitrary ID
hmib.php:3349
This link does not necessarily represent the devices in its Summary row. The row query groups by name, version (hmib.php:3231) but selects an ungrouped host_type; the shipped mappings already contain IDs 11 and 12 with the same name/version (includes/database.php:200-201). When both IDs have hosts, the row combines them while this glyph passes one arbitrary ID, so the Fleet Dashboard omits part of that row. Group the Summary by host-type ID, or pass a scope that matches the row's full name/version grouping.
AJAX card requests overwrite the remembered dashboard scope
hmib.php:4810
Persisting the scope inside this resolver also runs for summary_card AJAX calls. A refresh from an older dashboard tab can therefore overwrite the user's remembered scope, so another tab's next auto-refresh (whose URL omits ostype) unexpectedly jumps back. Only the main summary_dashboard navigation should update the preference; card requests should use their posted scope without saving it.
- Summary 'Device Type Summary Statistics' now groups by hrs.host_type instead of name/version, so each row maps to a single host_type and its Fleet Dashboard glyph scopes to exactly that type (previously rows merging two OID mappings with the same name/version, e.g. shipped ids 11 and 12, passed one arbitrary id and omitted the rest).\n- hmib_summary_resolve_type() only persists the chosen scope on the main summary_dashboard navigation (new \ arg); summary_card AJAX refreshes resolve without saving, so an older tab's refresh can no longer overwrite another tab's remembered scope.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The dashboard has keyboard accessibility defects and can display an incorrect scope after an OS type becomes unavailable.
0 open findings
Previously missed (3)
In code that hasn't changed since last review
Handle stale remembered types in the dashboard picker
hmib.php:5472
This picker only includes OS types that currently have devices, while hmib_summary_resolve_type() accepts any remembered positive ID without checking that it remains selectable. If the last device leaves a type—or an administrator deletes it (hmib_types.php:133-141)—the dashboard stays filtered to that stale ID, but no option is selected and the browser displays “All Types,” yielding misleading empty cards. Either validate/fall back the remembered scope or ensure the active scope remains represented in the picker.
Preserve focus when replacing a refreshed card
js/hmib_summary_dashboard.js:250
Replacing the card also removes the focused refresh button, so a keyboard user who refreshes one card loses focus to the document body. Preserve whether focus is still on a card tool immediately before the swap and move it to the corresponding tool in the fresh card; toolbar “Refresh all” should not steal focus because its focus remains outside the card.
Retain columnheader semantics for sortable table headers
js/hmib_summary_dashboard.js:318
Assigning role="button" removes the <th> element’s native columnheader role, but aria-sort is only valid on columnheader/rowheader; assistive technology may therefore ignore the announced sort state. Keep the header semantics and place the interactive sorting control inside it (or otherwise retain columnheader while exposing activation).
- resolve_type falls back to all-types when a remembered positive OS type no longer has any devices, so the picker (which lists only populated types) and the data stay consistent instead of showing empty cards mislabelled 'All Types'.\n- Card refresh preserves keyboard focus: if a tool button in the card was focused, focus moves to the same tool on the replacement node (refresh-all focuses a toolbar button outside the card and is unaffected).\n- Sortable headers keep their native columnheader role (dropped role=button) so aria-sort stays valid; tabindex + Enter/Space keydown already make them operable.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The extensive interactive UI and visual behavior still require the documented themed-browser validation.
0 open findings
Previously missed (1)
In code that hasn't changed since last review
Add distinct styling for Disabled status tile
hmib.php:5068
The Fleet Overview promises colour-coded status tiles, but Disabled uses the empty modifier and therefore has the same neutral styling as non-status tiles such as Devices and CPUs. Give it a dedicated disabled modifier and add matching disabled styling (consistent with the gray disabled segment in the status card).
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
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.
Description
Adds a Fleet (Summary) Dashboard — the aggregate counterpart to the per-device Dashboard — reached by the same dashboard glyph (same icon, first position) on the Summary tab's Device Type Summary Statistics rows. It replaces "boring tables" with visual, min/avg/max bullet charts and other graphics.
A draggable, add/remove card grid scoped to all devices or a single OS type (switchable in the toolbar). Cards:
Behaviour mirrors the per-device dashboard: drag/keyboard reorder, per-card refresh/maximize/remove, an "Add card" catalogue, an auto-refresh interval, and client-side sortable tables. Scope (OS type), card order, expanded state and the refresh interval all persist per user in
settings_user. A stateful Fleet Dashboard tab appears after first use and remembers the last scope.Implementation notes:
hrSystem/hrStorage/hrSWRunscoped byhost_type; the utilization stats only count up/recovering devices so stale values from down devices don't skew min/avg/max.js/hmib_summary_dashboard.js) that reuses the shared.hmibDash*card CSS. (A future refactor could unify the two controllers behind one config-driven module.)summary_card/summary_layout/summary_refresh; nonce'd inline init withJSON_HEX_*hardening. All visuals are theme-adaptive viacolor-mix.Related Issue
Follows the per-device Host Dashboard (#68) and its fixes (#69, #70).
Motivation and Context
The Summary tab's dense statistics tables are hard to scan. A card dashboard with bullet charts (which naturally express the min/avg/max spread across a fleet) and top-process panels gives an at-a-glance fleet view, customizable per user and per OS type.
How Has This Been Tested?
php -lclean onhmib.php;tests/bin/validate-manifest.phppasses (new JS lives under the already-listedjs/);locales/po/cacti.potregenerated; JS/CSS brace-balanced. Needs a browser pass on a themed install to confirm the bullet charts, stacked/mini bars, drag/add/remove/refresh and the stateful tab, since CI doesn't exercise the UI.Types of changes
Checklist: