11 Commits
Author SHA1 Message Date
TheWitnessandCopilot bef1ad80a0 Fix alert audio not rendering: resolve sounds dir from plugin root (#278)
getMonitorSound() used __DIR__ . '/sounds/' after the controller moved to includes/, so the sound file was never found and the audio element was never printed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-16 15:20:41 -04:00
TheWitness 5f96b8b7e2 Monitor 3.0 board: full-width grouping cards, Tree ordering, and the Status->Events filter model (#274)
* Monitor: flex grouping cards to full width, order Tree cards by device count

* Monitor: drop inaccurate Site/Template ordering comparison from changelog

* CI: install the declared thold dependency so Monitor can install under Cacti's new install-failure reporting

* Monitor: remove the filter-status/criticality footer and prompt from the board

* Monitor: give the busiest grouping cards (span 3-4) a full row so their tiles span the page

* Monitor: changelog for full-width busy cards and footer removal

* Monitor: drop Site grouping header, tighten tile uptime spacing, add List column tips

* Monitor: add clickable List-view thold/servcheck/ping/criticality pills with filter toggles

* Monitor: unit tests for new filter branches and thold/servcheck count helpers

* Monitor: selectable status pill, fallback/empty pills, hide absent plugin columns, tile sizing, dialog UX

* Monitor: center and keep clickable the tile hostname, remove 'Names only' view option (backend retained)

* Monitor: multi-select Events filter + Events column (additive), Status becomes scope-only Show

* Monitor: apply the Events multi-select on dropdown close (and on change for native selects)

* Add All criticality, Device Template multi-select, servcheck scope

- Add an "All" option to the Criticality filter. Its value (-1) matches the
  default and the pill "clear to default" action, which previously set the
  select to a non-existent option and submitted crit=null, tripping
  validate_store_request_vars.
- Convert the Device Template filter to a checkbox multi-select (like Events)
  and actually apply it: renderWhereJoin now adds
  h.host_template_id IN (...) for the template grouping (0 = Non-Templated).
  Previously the template selection was never applied, so all hosts returned.
- Persist the template selection as a user setting and serialize the
  multi-value for request/save payloads.
- Add a "Devices without Service Checks" scope to the Show filter, shown only
  when the servcheck plugin is installed and permitted.
- Tests + regenerated .pot.

* Update template escaping assertions for the multiselect markup

* Cover empty-template branch in renderWhereJoin

* Left-align Actions glyph and harden Device Detail Panels dialog layout

- Left-align the List-view Actions column header and fa-layer-group glyph.
- Stack the detail panels as plain blocks and force the jQuery UI dialog
  content box to always fill the dialog width, so the panels can no longer
  collapse into a narrow right-hand strip.

* Size the detail dialog to its content instead of forcing overflow

The #monitorPanelDialog overflow override (higher specificity than the
theme's .ui-dialog .ui-dialog-content) turned the content into a fixed-height
scroll box that fought the theme's overflow:visible and squashed the panels.
Use height:auto (capped by maxHeight) and stop overriding overflow so the
dialog sizes to its content and the theme governs scrolling.

* Anchor the detail dialog 300px from the top instead of centering

* Make the detail panels dialog non-modal

* Move Notes out of the List view into the detail dialog

The Notes column consumed a lot of horizontal space in List view. Drop it
from the table and surface the notes in the Host Information panel of the
Device Detail Panels dialog instead (shown only when the device has notes).

* Add device-edit action icon and Devices filter button (realm-gated)

List view: add a pen-square action icon linking to host.php?action=edit for
users with the host.php (device edit) realm, beside the detail-panels icon.
Filter bar: add a Devices button (right of Acknowledge) that opens the Cacti
Devices page, shown only to users with the same realm. Also move the detail
dialog anchor from top+300 to top+150.

* Anchor the detail dialog at top+80

* List view: replace Hostname column with a Graphs action glyph

Remove the Hostname column and add an orange fas fa-chart-line Graphs glyph
(.monitorGraph, matching HMIB's colour) to the Actions column, linking to the
device's graphs where the hostname hyperlink used to point.

* List columns + filter layout refinements

- List columns reordered to Description, Location, Site, ID; add a Location
  column; Averages, Length in Status, Last Fail are now the last three
  columns, all right-aligned.
- rfilter Search now also matches the device location.
- Filter: move the Events multiselect to the second row (right of Search) and
  the Rows dropdown to the second row (left of Refresh); rename that dropdown
  from Devices to Rows.
- Add a renderWhereJoin test for the description/location rfilter search.

* Monitor: realm-gate service-check scope/column, persist events+template, legacy status reset, failed_svc independent, defer list counts, pill keyboard a11y, PHPDoc/changelog fixes
2026-10-12 06:26:35 -04:00
TheWitness 417d10a7df Monitor: flow large grouping cards across page, add Tree grouping cards, fix down-group header contrast (#273)
* Monitor: flow large grouping cards across page, add Tree grouping cards, fix down-group header contrast

- Large grouping cards now span multiple grid columns (data-span) so a device template with many devices flows across the page instead of forming one tall, narrow column that scrolls off screen; grid switched to auto-fill + dense flow for predictable spanning.

- Tree grouping now renders as card panels (one per tree, plus a Non-Tree card) consistent with the Site and Device Template groupings, instead of the legacy section layout.

- Grouping card title colours are now !important so Cacti core device-status classes can't override them and leave unreadable text on a coloured header (e.g. a down device template).

* Monitor: address review - cap card spans responsively, size tree trim length from rendered hosts, persist tree card order

- CSS: establish the grouping grid as a query container and cap each card's span to the tracks actually available (container queries) so wide cards never force an implicit track / horizontal overflow on narrow layouts.

- renderTree cards: derive the default-view trim length from the hosts actually rendered (tree + Non-Tree), matching the Site/Template paths, instead of a tree-only measure that could trim against unrelated devices or collapse to 0.

- saveCardOrder: allow the tree grouping and preserve string group ids (tree_<id>/nontree) via a safe character allowlist instead of casting to int, so tree card drags persist.

- Share the Non-Tree label through a helper so the string multiset is unchanged.

* Monitor: harden saveCardOrder id typing and card render formatting

- Cast preg_replace result to string for strict typing.

- Avoid mixing list destructuring with aligned assignments in the tree card builder.
2026-10-11 09:43:27 -04:00
TheWitness 11c7e46706 Monitor: Rows filter, servcheck status, Tiles sizing, device-detail panels, dashboard properties & grouping cards (#272)
* feat: servcheck hover integration, list-only Rows filter, fix Tiles & Time tile box

Rows filter now only paginates/shows on the List view; non-list views show all devices. Add plugin_servcheck hover status + glyph alongside thold/syslog. Fix Tiles & Time tiles overflowing their bounding box via min-height.

* fix(review): servcheck schema compat, realm-gated status, POT, tests

- getHostTriggeredServchecks adapts to servcheck v0.3 (lastcheck/failures) and v0.4 (last_check/last_result) schemas and guards a missing table

- Gate the hover status promotion behind the servcheck_test.php realm, matching the glyph link

- Regenerate locales/po/cacti.pot for 'View Failing Service Check'

- Add unit coverage for the servcheck helper (disabled/empty/missing-table exits, bound params, v0.3 & v0.4 predicates)

* feat: distinct Service Check Failed status + List-view Actions detail panels

- Add status 10 (Service Check Failed) with legend chip, tile/list colour and status-filter coverage via a realm-gated, schema-aware checkServchecks() host set

- Add a non-sortable Actions column to the List view opening a modal of intropage-style cards: host info, data collection timing, service checks, thresholds, last-hour syslog, and device links

- Regenerate cacti.pot; add unit coverage for checkServchecks() and the servcheck status filter

* feat: dashboard properties JSON + colorized draggable grouping card panels

- Restructure plugin_monitor_dashboards to a JSON properties column; migrate the legacy url into it and drop the url column on upgrade; load/save dashboards via the structure

- Render Site and Device Template groupings as a responsive grid of draggable card panels, titles coloured by each group's worst device status, with per-dashboard/per-user persisted ordering

- Add unit coverage for the url->properties migration and db stubs

* fix(review): secure device panels, schema-aware not-tested, IPv6 link, thold realm

- Enforce is_device_allowed() on ajax_hostpanel and ajax_status so a user cannot pull details for a device off their board

- Gate the Thresholds card behind thold's thold_graph.php realm

- Select the schema-specific servcheck check time (lastcheck/last_check) and use it so never-run v0.3 checks report Not tested

- Bracket IPv6 literals in the Open Actual Device link

* fix(review): ownership-aware card order + request helper for order array

- Save/read grouping card order via the dashboard only when the user owns it; shared/read-only dashboards and no-dashboard fall back to the per-user monitor_cardorder setting so reorders persist

- Read the posted order through get_nfilter_request_var() instead of \ directly
2026-10-10 19:12:57 -04:00
TheWitnessandTheWitness 8f877c53fd Load syslog helpers in a version-independent way (#268)
* Load syslog helpers in a version-independent way

The syslog 2.x restructure moved its DB helpers from the plugin root (config.php / functions.php) to includes/database.php and includes/functions.php. Monitor still require()d the old root paths, so on a current syslog install syslog_db_fetch_cell_prepared() was undefined and the monitor AJAX status handler fatally errored (disabling the plugin). Detect which layout is present and include the matching files.

* monitor: initialize the Syslog DB connection via syslog_connect()

Load setup.php and call syslog_connect() so the per-device Syslog link queries run against the configured Syslog database (which may be a separate connection) instead of falling back to Cacti's default connection. Also reword the layout comment to describe the includes/ vs root layout distinction rather than tying it to a specific Syslog release.

---------

Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com>
2026-10-07 20:59:30 -04:00
TheWitness 3c286de812 Theme filter dropdowns via select2 so they follow the Cacti theme (#267)
drawFilterDropdown() emitted bare <select> elements with no select2 class, so Cacti's applySkin() never converted them and they rendered unthemed (e.g. the Criticality filter on dark themes). Add class=select2-nosearch so core themes them like every other Cacti dropdown. The select2 class helpers arrived in Cacti 1.2.32, so the class is gated behind version_compare(CACTI_VERSION, '1.2.32', '>=') to preserve the 1.2.29 support floor. Closes #265.
2026-10-07 20:59:27 -04:00
TheWitnessandTheWitness 51865b308a Use a CSS class for the status legend footer instead of inline styles (#264)
* Pin status legend to the bottom of the page (match MacTrack)

Wrap the monitor legend render in the same fixed-position footer container MacTrack uses, so the legend stays pinned to the bottom of the viewport.

* Use a CSS class for the legend footer instead of inline styles

Replace the inline fixed-position wrapper around the status legend with a
plugin-specific *LegendFooter class defined in the plugin's stylesheet. The
class lays the legend out as a centered footer in normal document flow, so it
no longer sits outside flow and overlay the final rows, pagination, or action
controls at the bottom of the page.

---------

Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com>
2026-10-07 20:59:23 -04:00
TheWitness 38bdabf90f monitor: use CSS Grid for truly equal-width legend chips (#263)
* monitor: use CSS Grid for truly equal-width legend chips

The .monitorLegend flex: 1 1 0 + flex-wrap layout distributes free space per wrapped line, so a partial last row stretched its chips wider than full rows. Switch to a grid (repeat(auto-fill, minmax(var(--monitor-chip-min), 1fr))) so every chip shares an equal column across all rows. The longest-label seed (--monitor-chip-min from includes/controller.php) still drives the column minimum.

* monitor: use auto-fit so chips fill the legend width when they fit on one row

Review follow-up (#263): auto-fill retains empty implicit columns on wide viewports, leaving unused slots so the chips do not fill the legend width. auto-fit collapses the empty tracks while keeping equal shared columns across wrapped rows.

* monitor: extract monitor_legend() and add unit coverage

The status legend was rendered inline in includes/controller.php, so it had no unit coverage like the thold/servcheck/mactrack/syslog legends. Extract it into monitor_legend(array \, array \) in includes/functions.php (in the phpunit coverage source set) and add MonitorLegendTest.php asserting the exact calc(Nch + 1.5rem) longest-label value. No behaviour change.

* monitor: escape status-legend chip labels at output

Defence-in-depth: wrap the legend chip display text in html_escape() so markup or HTML entities in a translated label cannot alter the legend DOM. Applied consistently across the thold/monitor/servcheck/mactrack/syslog fleet legends. The chip-min sizing still measures the unescaped label length, so layout is unchanged.
2026-10-07 13:20:26 -04:00
TheWitness 43a183e0d3 Monitor: keep legend chips equal width using the longest label (#262)
With flex:1 1 0 + min-width:max-content each chip's floor was its own text width, so the chips grew to unequal widths. CSS can't measure the widest sibling, so controller.php now computes the longest legend label and passes it as a --monitor-chip-min CSS variable (longest label + 1.5rem); the chips use it as a shared min-width (falling back to max-content). Every chip now shares one minimum, so they stay equal width as the legend wraps responsively.
2026-10-07 09:13:07 -04:00
TheWitnessandCopilot Autofix powered by AI f50de0c632 Monitor: redesign status legend as theme-appropriate colour chips (#260)
* Monitor: redesign status legend as theme-appropriate colour chips

Match the thold and syslog legends: render the status key as an evenly sized, wrapping flex row of rounded, solid-colour chips with white text (controller.php now emits .monitorLegend/.monitorLegendItem instead of the old fixed-position .monitor_legend bar). Chip colours are scoped under .monitorLegend so the device tiles keep their subtle tints. The standard solid palette lives in css/monitor.css and applies to every theme; css/deepness.css overrides the Up chip to emerald to harmonise with the Deepness palette. Removed the now-dead per-theme .monitor_legend overrides (midwinter previously hid the legend via display:none; it now shows chips like the other themes).

* Update background color for deviceUpFull class

Change background color for deviceUpFull class to better match Deepness palette.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Change background color for deviceUpFull

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-10-07 07:28:04 -04:00
TheWitnessandCopilot 66358e0998 Adopt plugin table API and relocate schema to includes/database.php (#254)
* Relocate schema to includes/database.php via plugin table API + db_update_table upgrade

* CI: allowlist unmeasured schema bootstrap and web entry points

* CI: keep include_once for the settings-page-only lib/reports.php load (uncoverable)

* Add manifest.json + upgrade-time file pruning; consolidate themes/ into css/

* database: keep user-owned dashboards table across uninstall

api_plugin_db_table_create() records plugin_monitor_dashboards in
plugin_db_changes, so api_plugin_db_changes_remove() (run by
api_plugin_uninstall() after plugin_monitor_uninstall()) would drop it
even though monitor_drop_tables() intentionally leaves it in place. Remove
the 'create' ownership record after provisioning (install and upgrade
paths) so user dashboards survive an uninstall. Adds a regression test.

* Prune phpunit.xml on upgrade and ignore markdown-lint configs

phpunit.xml ships in the repo for CI but is a dev-only test artifact, so it
is removed from manifest.json 'expected', pruned from installs on upgrade
(like tests/), and excluded from the manifest drift check.

The retired markdown-lint configs (.mdlrc, .md_style.rb) are deleted, and
.md* is now ignored like .git*: protected from pruning and excluded from
drift if it reappears.

* Move libraries into includes/, flatten css, drop sonar config

db_functions.php, monitor_render.php and monitor_controller.php move into
includes/ (the latter two lose the monitor_ prefix, becoming render.php and
controller.php); monitor.php and the tests load them from there. Each per-theme
stylesheet css/<theme>/monitor.css becomes css/<theme>.css so users can drop
their own css/<theme>.css into the css base, and plugin_monitor_page_head()
looks there, falling back to css/monitor.css. The unreferenced
sonar-project.properties is removed. Old paths are tombstoned so existing
installs drop the stale copies on upgrade.

* Rename includes/db_functions.php to includes/functions.php

Follows the fleet convention for the plugin's shared library filename; monitor.php,
the measured-source list and the unit test load it from the new name.

* Regenerate cacti.pot for the includes/ file relocations

Moving the plugin's library files into includes/ changed the source-reference
lines in the translation template; regenerate it so the 'Verify translation
template' CI check passes.

* Harden prune against tampered-manifest path traversal

The upgrade-time prune now rejects any tombstone containing '.'/'..' segments
(which could escape the plugin directory or resolve to its root) and treats
ancestors of whitelist entries as protected, so a tombstone on a parent
directory can no longer delete a whitelisted file beneath it.

* docs: update and align the Project Structure block

Point the structure tree at the relocated files (libraries now under
includes/, data files under docs/, stylesheets under css/) and align the
trailing '# ...' comments to a single column so they no longer drift right.

* docs/tests: standardize test header and correct manifest-contract notes

- Use the full license header (from the plugin's own setup.php) in
  tests/Unit/PruneFilesTest.php instead of the abbreviated copyright banner.
- Document that the manifest drift check and the upgrade-time prune also
  handle phpunit.xml and .md* files, matching the implemented behavior.

* refactor: rename prune helpers to the plugin-slug function prefix

The repository naming contract reserves the plugin_<name>_ prefix for plugin
lifecycle / hook-registration functions; all other functions use the plain
<name>_ prefix. Rename the internal upgrade helpers accordingly:

  plugin_<name>_prune_files() -> <name>_prune_files()
  plugin_<name>_rmtree()      -> <name>_rmtree()

The call site, unit tests, and the copilot-instructions.md references are
updated to match. No behavioral change.

* chore: set the Cacti compatibility floor to 1.2.29

Align the compat metadata (and the contributor-guide references) with the
team decision to standardize the minimum supported Cacti version at 1.2.29;
the previously proposed 1.2.32 floor was not adopted.

* Bump plugin version to 3.0 so the upgrade-time cleanup migration runs

Add a 3.0 CHANGELOG section for this cycle's schema/manifest work and set
INFO version = 3.0 so existing 2.9 installs detect the version change and
run the schema refresh and manifest-based file prune.

---------

Co-authored-by: Copilot <copilot@users.noreply.github.com>
2026-10-01 01:39:53 -05:00