mirror of
https://github.com/Cacti/cacti.git
synced 2026-11-03 10:37:46 +09:00
fix/test-config-layout-develop
3646
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
356f4ae813 |
fix(graphs): tree content reveal, filter dialog columns, single-column centering (#8365)
* fix(graphs): reveal graph content area after tree branch loads The jstree select_node handler hides .cactiGraphContentArea (#navigation_right) before loading a branch's graphs via AJAX to avoid flashing the previous branch, but the only re-show was coupled to a window resize event that does not fire after the AJAX load. On themes that hide .cactiGraphContentArea by default (e.g. Deepness) the content area stayed display:none and the graphs/filters were invisible. Re-show it on loadUrl completion. * fix(filter): keep the Edit Filter dialog columns from collapsing The modern filter Edit dialog is created with jQuery UI width:'auto'. Its body is a table-based label/field grid, which jQuery UI measures at min-content, collapsing the dialog content to a sliver and pushing the fields off to the right. Floor the content min-width so the columns lay out. Validated in Deepness and Dark. * fix(graphs): centre single-column graphs in the graph view graphWrapperOuter > div:first-child is width:fit-content inside a (full-width for one column) flex wrapper, so the graph rendered flush-left. Add auto horizontal margins so it centres; the absolutely-positioned drilldown toggle continues to track the graph. * fix(graphs): don't re-show content area on aborted branch load A superseding tree branch click aborts the in-flight loadUrl; its .always() must not re-show the content area the new selection just hid, or stale graphs flash while the new branch loads. Skip completions whose textStatus is 'abort'. |
||
|
|
4d11070ced |
feat: expose RRDtool 1.11 graph axis controls (#8356)
* feat: expose RRDtool 1.11 graph axis controls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: constrain axis template inheritance checkboxes Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): exercise native aggregate validation and enforce coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: share changed-code coverage contracts and enforce shell policy Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(ci): run request coverage with portable path matching Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: retain bootstrap coverage and validate request dispatch Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: synchronize native coverage fixture dispatch Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: measure coverage at the exact PR revision Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
8acc5ec916 |
feature: theme-aware graph drilldown action menu (per-theme CSS palette) (#8355)
Label the open graph drilldown strip (layout.js labelGraphDrilldownIcons), shorten the action titles, and restyle the strip as a table menu. Each theme's main.css declares the --cacti-dd-* custom properties (foreground, hamburger/panel backgrounds, hairline border, hover accent) that include/css/graph_drilldown.css consumes via var() with a dark fallback, so each theme gets an appropriate light or dark look with its own accent and the hamburger reads correctly on light themes. Themes without a block (e.g. midwinter) use the dark fallback. Regenerates the affected locales/po/cacti.pot entries for the shortened titles. Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com> |
||
|
|
c749790d84 |
fix(security): [develop] require CSRF-protected POST for link and plugin reordering (#8278)
* security: require CSRF-protected POST for link and plugin reordering (#7454) Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): share POST and token guards for reorder actions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
ce6ab6e0b3 |
fix(auth): [develop] preserve SAML POST callback sessions (#8333)
* fix(auth): preserve SAML POST callback sessions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(auth): filter SAML inputs before bootstrap Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
5f72f1a03c |
fix(security): [develop] require protected POSTs for administrative mutation endpoints (#8331)
* fix(csrf): require POST for administrative mutation endpoints Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(csrf): support token-checking mutation helper Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
49c95bef63 |
fix(deps): track legacy browser assets and remove patch-package (#8330)
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
ac50e0e0d0 |
fix(csrf): restrict XHR tokens to same-origin requests (#8329)
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
9a3a7dfce0 |
fix(graphs): [develop] correct opacity, redraw and realtime retries (#8328)
* fix(theme): enable graph opacity without selectmenu Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(changelog): describe theme fix Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(graph): restore redraw URLs and retry realtime failures Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
6e5078c929 |
fix(theme): [develop] restore Midwinter navigation, search and filter controls (#8327)
* fix(theme): restore Midwinter navigation and kiosk controls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(changelog): describe theme fix Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(navigation): preserve filters and restore search and keyboard controls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
f28071eb67 |
fix(theme): [develop] restore Midwinter login controls, form state and notifications (#8326)
* fix(theme): preserve Midwinter authentication controls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(changelog): describe theme fix Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(ui): preserve form state and notification lifecycles Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: replace the blinking timer during skin setup Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
f39e74c65c |
Graph drilldown: keep hamburger fixed, icons reachable, hide on graph leave (#8315)
* Graph drilldown: keep hamburger fixed, icons reachable, hide on graph leave The action-icon strip now slides down below the hamburger (flex column) instead of the hamburger dropping to the bottom of the icons. Closing is driven by leaving the whole graph rather than the small icon strip, so the mouse can move from the hamburger onto the icons without the strip closing. Leaving the graph also blurs the hamburger so it no longer lingers after interacting with it. * changelog: graph drilldown interaction fixes (#8315) * Graph drilldown: tolerate tooltip-induced mouseleave, drop hamburger title A native tooltip appearing over a drilldown icon fires a spurious mouseleave on the graph (relatedTarget null), which closed the strip. Defer the close and re-check the graph is genuinely not hovered first, so the icon tooltips no longer destabilize it. Also drop the hamburger's redundant title (its aria-label stays). * Graph drilldown: widen the close grace period to 500ms * Graph drilldown: tie hamburger visibility to the graph image Reveal the hamburger while the pointer is over the graph image (or the toggle overlaid on it) rather than anywhere in the graph cell, so moving off the image hides it after the grace period. Entering a different graph now immediately hides and closes any other graph's open strip. * Graph drilldown: lift the open graph so its strip clears thumbnails below With thumbnails a short graph's open icon strip overflows onto the graph below; sibling graphs paint in DOM order, so that graph rendered on top of the strip, making the icons unclickable and stealing the hover (which closed the strip). Raise the open graph (.graphDrillActive, position:relative; z-index) so its overflowing strip stays on top and the graph beneath is not hovered. * Graph drilldown: reveal via :focus-visible and stop blurring to preserve keyboard focus * fix(ui): preserve graph action focus during pointer navigation Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(ui): cover graph drilldown interactions and gate PR coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: measure committed PR changes on a policy-compliant runner Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
49e14c9785 |
Filter dialog: theme-aware close glyph, titlebar height matches table header, Deepness input theming (#8312)
* Filter dialog: theme-aware close glyph, titlebar height matches tableHeader, Deepness input theming - Replace the non-theme-aware inverted sprite close icon with a theme-coloured x glyph (color: inherit) across all 10 themes that style cactiFilterDialog. - Set the titlebar height/line-height to match each theme's cactiTableTitleRow height instead of 10px padding that made the dialog header taller than table headers. - Deepness: re-apply theme field colours to dialog inputs/selects/textareas with higher specificity so jQuery UI .ui-widget-content .ui-state-default no longer overrides them. * changelog: filter dialog theme consistency (#8312) * Filter dialog: theme select focus border; raspberry titlebar 28px to match table header box * test(ui): cover filter dialogs across all changed themes Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: measure committed PR changes on a policy-compliant runner Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
97e67c6777 |
security: harden browser rendering and review CodeQL boundaries (#8298)
* security: harden browser history and dependency option merging Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: record CodeQL triage decisions and follow-up scope Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: wait for history reload before inspecting browser storage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: isolate HTMX history from the legacy navigation handler Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: build CodeQL assets through controlled dependency installs Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: render form validation messages as plain text Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: verify drag rows and color input security boundaries Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: verify tree navigation rename and datetime input boundaries Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: harden menu rendering and complete CodeQL caller review Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: centralize menu rendering and stabilize certificate CI Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: align certificate expectation with parallel web PR Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
08d0f94f24 |
Fix develop client behavior, popup isolation and PHP method visibility (#8292)
* fix(core): correct client state and declare public method contracts Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(security): isolate Midwinter external homepage popup Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(client): isolate menu state and simplify validated JavaScript guards Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(auth): use certificate expiry truth in rendering assertions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(js): remove unused local storage while retaining initializer calls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(js): encode inline translated values through the shared JSON boundary Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style(js): wrap encoded translation literals without changing messages Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(client): remove unused checkbox reads from graph resizing Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(client): declare repeated function locals once Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(ui): run column width regression in browser CI Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
d7ec67c4cf |
Persist table column widths across request actions (#8309)
* Persist table column widths across request actions Column widths are stored in localStorage keyed by the table id, but html_start_box() derives that id from the request action/report/tab, so a filter refresh (action change/go) reloads the same table under a different id and the saved widths are not restored. Emit a stable, action-independent data-colsizing key on each cactiTable and use it in saveTableWidths(), while keeping the DOM id unchanged. * changelog: 8309 table column width persistence * Column width persist: keep per-view key, normalize only filter-refresh actions The previous key dropped the action/report/tab entirely, so distinct table schemas at the same page+ordinal (e.g. support.php processes vs background tabs, utilities.php view_snmp_cache vs view_poller_cache) collapsed into one localStorage entry and applied widths from the wrong schema. Retain the stable logical-view discriminator (tab/report, or a non-transient action) in the data-colsizing key and normalize only the transient filter-refresh actions (go/change/clear/reset), so widths still survive a filter change but never cross unrelated schemas. * Use short array syntax for the colsizing normalization list (php-cs-fixer) |
||
|
|
e25a67c31f |
Common graph drilldown hamburger toggle across all themes (#8308)
* Graph drilldown: common hamburger toggle across all themes The graph action icons were revealed by hovering to the right of the graph, implemented per-theme (dark/midwinter/sunrise main.js) and always-on elsewhere. Hide the icons by default behind a small fa-bars hamburger overlaid on the graph's top-right. Clicking it opens the icon strip, which stays until a second click, leaving the strip, or an outside click. The behaviour is now centralized in include/layout.js (initGraphDrilldown) and include/css/graph_drilldown.css, and the per-theme hover JS is removed. * changelog: 8308 feature fragment * Graph drilldown: address review (a11y, positioning, spikekill, POT) - Anchor the toggle to the shrink-wrapped graph holder (width:fit-content) so the hamburger sits on the graph's top-right, not the full-width column edge. - Keep the hamburger focusable while visually hidden (opacity instead of display:none); reveal on hover, keyboard focus, open, and hover-less devices. - Expose aria-expanded on the toggle and update it in every open/close path; add aria-haspopup/aria-label. - Close any open SpikeKill submenu (spikeKillClose) when the strip closes or switches, matching the removed per-theme handlers. - Remove the now-duplicate Midwinter top-right ellipsis pseudo-element. - Add the new 'Graph Actions' msgid to locales/po/cacti.pot. |
||
|
|
533f3b5a04 |
Harmonize DateTimePicker styling with each theme palette (#8287)
* Harmonize DateTimePicker styling with each theme palette The jQuery UI datepicker and timepicker addon rendered with the stock ThemeRoller texture-image backgrounds and a generic gray/green look that did not match any theme (most visible in the deepness dark theme). Add per-theme, picker-scoped overrides to every theme's jquery.timepicker.css so the popup surface, header, weekday labels, day cells, selected/hover/today states, Now/Done buttons, and the time sliders use each theme's own accent and content colors. Rules are scoped to .ui-datepicker so other jQuery UI widgets are unaffected. * Address DateTimePicker a11y review (develop) - Reset the nav-icon filter on prev/next hover (cacti, paw, raspberry) so the dark jQuery UI sprite stays visible on the pale hover tint. - Give carrot and hollyberry a dark header title + dark nav icons so the month/year text clears AA on the light-ish accent header. - Carrot: move to the theme's darker orange (#d2691e) for the today outline and sliders, and use a dark foreground on the orange selected-day/button fills. - cacti and hollyberry: dark foreground on the accent selected-day/button fills to clear 4.5:1. - paper-plane and sunrise: invert the icon sprite to white so the arrows are visible on their dark headers. - dark and modern: add an explicit focus outline on the time-slider handles (both themes suppress the browser outline globally). - midwinter: rebuild the override on the theme palette variables so the picker follows dark/light mode, with the theme blue as a fixed AA accent. |
||
|
|
bfa3efb7a9 |
Add a jQuery rebind() helper and roll it out across the core UI (#8279)
* Add a jQuery rebind() helper and roll it out across the core UI Add $.fn.rebind(events[, selector], handler...) to include/layout.js as a shorthand for the common off(events).on(events, ...) re-attach idiom, then convert the matching chained calls across the core JavaScript and inline PHP handlers to use it. Only pairs whose off() and on() events (and delegated selector) match are converted; off() with no arguments is left as-is since it intentionally clears every handler. * changelog: add 8279.feature fragment * tests: update layout.js JS tests for the rebind() helper * tests: assert the cactiPostAction handler via rebind() * rebind: preserve the delegated selector for the two-argument event-map overload; add helper tests |
||
|
|
f54da33bef |
themes(deepness): harmonize all greens to the emerald palette (#8234)
* themes(deepness): harmonize all greens to the emerald palette * docs: changelog.d/8234.issue (deepness green harmonization) * themes(deepness): distinct active-state green + sync themeroller url Address review: give .ui-state-active a darker emerald (#083f2e) so persistent selection stays distinct from the #0c5f44 hover/focus state, and update the themeroller URL's hover/active colors and textures (flat) to match the de-olived declarations. |
||
|
|
c4a8c552a6 |
security: require POST+CSRF for GET-triggered purge/disable actions (GHSA-x664-x4hf-p9xh) (#8236)
* security: require POST+CSRF for GET-triggered purge/disable actions (GHSA-x664-x4hf-p9xh) * style: align rrdcheck purge array operators for php-cs-fixer |
||
|
|
9df1923c83 |
themes: use a clean green for .deviceUp instead of muddy olive (#8231)
* themes: use a clean green for .deviceUp instead of muddy olive The device-status/good-message color .deviceUp was rgba(148,179,107,0.8), a desaturated olive that reads as a muddy warm tone (easily confused with warning/bad) - most visibly on the jQuery UI message dialog, where core wraps MESSAGE_LEVEL_INFO text in <span class=deviceUp>. Align these themes with the clean green rgba(40,180,40) already used by the deepness, modern and paw themes. Applies to device-status text everywhere the class is used. * changelog: add fragment for .deviceUp green recolor (#8231) |
||
|
|
22ab16cac9 |
themes: unify login page styling across all core themes (#8230)
* themes: unify login page styling across all core themes Flatten the dark themes' login page/card gradients (dark, paper-plane) to flat surfaces, give every theme a clean bordered login card, and add a browser -webkit-autofill override per theme so saved credentials keep the theme's input colors instead of the browser's olive tint. Re-point the Deepness and MidWinter themes' login styling from the legacy .login*/.cactiLogin* classes to develop's .cactiAuth* markup (including .cactiAuthLeft, which auth_login.php targets) so their login pages render correctly. Light themes keep their signature login backdrops. * changelog: add fragment for login page theme unification (#8230) |
||
|
|
6f57c319dd |
midwinter: colour the graph drilldown action icons from the theme palette (develop port of #8228) (#8229)
* midwinter: colour the graph drilldown action icons using theme-palette variables (distinct task-appropriate hues, dark + light modes) * changelog: add fragment for midwinter graph drilldown icon colours (#8229) |
||
|
|
30db858d3f |
deepness: deep-dark login page with a bordered login box (#8224)
* deepness: deep-dark login background with a bordered, slightly-greyer login box Drop the emerald loginBody gradient for a flat deep-dark page (var(--dp-page)), give the login box a flat slightly-greyer tint (var(--dp-panel-alt)) with a thin var(--dp-border) border, and override -webkit-autofill so the username/password fields no longer show the olive autofill tint. * docs: add CHANGELOG entry for #8224 (Deepness login restyle) * deepness: use input surface for login autofill override The -webkit-autofill inset box-shadow used var(--dp-panel-alt) (the login card surface) instead of var(--dp-panel) used by the standard text/password inputs. Autofilled credentials therefore took on the card color rather than the normal input appearance. Use var(--dp-panel) so the override only removes Chrome's autofill tint. |
||
|
|
4d618e1869 |
Dark theme: theme-appropriate host status pills (develop) (#8223)
* dark theme: add theme-appropriate host status pills Port the translucent host status pills (.deviceStatus) to develop's Dark theme with colors anchored to the theme's olive/sage palette: Up olive rgba(148,179,107)/rgba(167,217,134), Down muted brick red, Recovering theme orange #ff8f1e, Error theme purple #750F7D, Unknown theme blue #0072B5, Disabled theme grey #a1a1a1. The deviceStatus hook already ships in get_colored_device_status() on develop. * changelog: 8223.feature dark theme host status pills * dark: opaque dark backing for status pills on selected/hover rows On tr.selected (opaque light-olive gradient) and tr.selectable:hover the translucent .deviceStatus pills let the bright row show through, dropping the light !important status text below WCAG contrast. Back the pills with the theme base (#161616) in those states; per-state border/text colors still convey status. --------- Co-authored-by: TheWitness <larry@thewitness.org> |
||
|
|
2e8afef8f7 |
issue: align Deepness console icon sizing/alignment with Modern (#8221)
* deepness: match modern console icon sizing/alignment and drop sub-menu indent Port modern's .menu_glyph size/alignment (18px, 22px width, padding-right:0, inline-block), add line-height:20px to .menuitem span, bump legacy i.fa to 15px with text-align:left, and remove the 32px sub-menu indent (#nav li ul li a now flush at 5px like the top-level items). * docs: add CHANGELOG entry for #8221 (Deepness console icon alignment) |
||
|
|
35e7181ded |
issue: skin the modern filter Edit dialog for the Deepness theme (#8220)
* issue: skin the modern filter Edit dialog for the Deepness theme The Deepness theme received the modern filter *bar* rules (#8219) but not the .ui-dialog.cactiFilterDialog skin the other themes carry, so the filter Edit dialog fell back to the default jQuery UI themeroller look (mismatched titlebar gradient, unstyled buttonpane). Port the scoped dialog block used by the other themes, using Deepness's emerald palette variables (--dp-accent-deep titlebar/primary button, --dp-border buttonpane divider). * issue#8220: reference PR number in CHANGELOG entry to satisfy the format gate |
||
|
|
4430210a85 |
issue: fix Deepness theme modern filter bar stacking vertically (#8219)
* issue: fix Deepness theme modern filter bar stacking vertically The Deepness theme (added in #8206) shipped include/themes/deepness/main.css without the modern filter-bar display rules the other themes carry, so .filterColumn/.filterColumnButton divs fell back to display:block and the Layouts/Search/Rows controls and action buttons stacked vertically. Port the .filterRow/.filterColumn/.filterColumnButton table-display rules and the .cactiFilterModernBar rules from the modern theme. * docs: add CHANGELOG entry for #8219 (Deepness filter bar fix) * issue#8219: port icon-rotate and barSep modern-bar rules to Deepness html_filter.php adds icon-rotate to the Refresh glyph and emits empty barSep separator spans. Deepness lacked both rules, so the refresh action had no spin feedback and the separators were invisible. Add .icon-rotate and .cactiFilterModernBar .barSep (using the dark-theme rgba(128,128,128,0.45) separator colour, matching the dark/carrot/paper-plane themes). |
||
|
|
e7d389f4a1 |
deepness: make left-menu glyphs the light text colour always (#8216)
The .menu_parent fa/fas/fab/far/fal icons used var(--dp-accent) (emerald). Switch to var(--dp-text) so the console navigation glyphs stay light in every state. |
||
|
|
f66bf80c41 |
themes: render legacy raw filter checkboxes as toggle switches (#8214)
The common filter class already renders filter checkboxes as text-first toggle sliders. This adds the equivalent styling for legacy plugin filters that still emit a raw <input type=checkbox> inside .filterTable, so they match until they adopt the new filter class. Each theme's filter toggle mirrors that theme's own checkboxSlider (colours, radius, 0.4s). form_checkbox()/common-filter sliders (class formCheckbox) are excluded via :not(.formCheckbox). Track radius is !important to beat .ui-corner-all. |
||
|
|
40d648cef3 |
fix: The horizontal scroll bar should not be visible unless it has to be (#8212)
* fix: horizontal scroll bar should not be visible unless it has to be Port of #8211 to develop. Let overflow-x fall back to 'auto' instead of 'visible' so a horizontal scroll bar only appears when content actually overflows, and drop the resizable handle from the last visible column in applyTableSizing() so resizing it cannot force the page wider than the viewport. * Fix resizable destruction for visible table headers Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: TheWitness <larry@thewitness.org> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
16f62713c5 |
paper-plane: dark-mode refinements (readable forms/rows, consistent button system) (#8207)
* paper-plane: dark-mode refinements (readable forms/rows, consistent button system) * tests: make CactiErrorHandler suppression test hermetic against leaked IN_CACTI_INSTALL The three suppression cases eval a sandboxed copy of CactiErrorHandler to exercise the error_reporting() mask and logging path. Pest runs the whole suite in one process, and tests/integration/BoostProcessTableUpgradeIntegrationTest defines the global IN_CACTI_INSTALL constant at collection time. A constant cannot be unset, so the handler short-circuited to true before reaching the branch under test, failing 'an enabled level is logged and reported to PHP as unhandled'. Strip the install-mode guard from the sandboxed copy so the case is independent of collection order. --------- Co-authored-by: TheWitness <larry@thewitness.org> |
||
|
|
2780258e7c |
Add 'Deepness' dark emerald-green theme to develop (with billboard overload CSS) (#8206)
* Add 'Deepness' theme to develop; midwinter billboard + deviceStatus hook Forward-ports the Deepness theme (1.2.x #8202 + #8205) to develop as one change: the full include/themes/deepness/ theme (emerald-dark :root palette, Paw layout/top-tab JS, full billboard.js 3.13 overload CSS, dark widget CSS), the themes allowlist entry, the i18n_themes name, the midwinter billboard overload rules, and the shared 'deviceStatus' hook class in get_colored_device_status() that the theme styles as status pills. Paper-plane is intentionally untouched (worked separately). The lib/html.php favicon/arrow tweaks from 1.2.x are omitted - develop handles those via get_md5_include_icon()/get_theme_paths() and the theme's own .actionsDropdownArrow CSS. * deepness: align main.js with Paw parent (drop stale host_id autocomplete & graphDrillDown, fix search-icon/handler leaks) * deepness: drop bundled billboard.css (obsolete per-theme file; central include/css/billboard.css + main.css .bb overloads cover it) * i18n: add 'Deepness' theme name to cacti.pot translation template * Deepness: apply php-cs-fixer formatting and refresh sink inventory baseline php-cs-fixer fixes the single-quote and // comment style in the deepness theme index.php/rrdtheme.php files, and the sink inventory baseline records the header_redirect sinks in the new deepness index.php files. * tests: stop the boost upgrade integration test leaking IN_CACTI_INSTALL BoostProcessTableUpgradeIntegrationTest defined IN_CACTI_INSTALL at file (collection) scope, so it was set for the whole shared pest process and made CactiErrorHandler() take its install-mode early-return. That broke CactiErrorHandlerSuppressionTest ('an enabled level is logged...' expected false, got true) in the pest coverage gate and the locked integration job. The upgrade files required here do not check the constant at load time (only lib/database.php does, at runtime inside its schema probes), so define it in beforeEach after the DB connects instead -- it is never set at collection time and, with no DB in CI, the test skips without defining it. Full pest suite: 2664 passed, 0 failed. |
||
|
|
1dc9961e03 | fix displayin js code after last collapsible row (#8200) | ||
|
|
2c791b3db8 |
Fix printing of the detailed graph view on develop (#8193)
* Fix detailed graph print layout on develop * Reference develop PR 8193 in changelog fragment --------- Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
4298f2ae33 |
feature: Search box on the modern filter bar + null-safe tablesorter trim (#8194)
* Surface the Search box on the modern filter bar Route the Search textbox (filter/rfilter) onto the modern filter bar, just right of the Rows selector, instead of only inside the Edit dialog. Pressing Enter in it applies the filter via the page's configured change function (filter=/rfilter= as appropriate), bound with event delegation so it survives ajax content reloads. field_is_bar() now keeps the search textbox on the bar and it is ordered Rows, Search, Refresh. * Null-safe tablesorter $.trim rewrite in the sync-js transform The jQuery 4 compatibility rewrite turned \$.trim(x) into (x).trim(), which throws when a custom textExtraction/parser returns a non-string or null (jQuery coerced values and mapped nullish to ''). Rewrite to String((x) ?? '').trim() - the inner parens keep || expressions from forming an illegal unparenthesized 'a || b ?? ''' - and regenerate include/js/jquery.tablesorter.js. Updates the sync-js fixture test accordingly. * Add changelog entries for the modern-bar Search and tablesorter trim fix * Add a Clear glyph button to the modern filter bar Place an eraser (ti ti-eraser) Clear button just right of Refresh on the modern bar, wired to the page's clear action, so the filter can be reset without opening the Edit dialog. The eraser matches the timespan/generic Clear glyph and stays visually distinct from Delete's trash glyph. * Give bar-routed Search a persistent label when a page omits friendly_name The log viewer (clog) defines rfilter without a friendly_name because it shared the adjacent matches field's Search label. Routed onto the modern bar it would show only the placeholder, which disappears after entry. Default a bar-routed filter/rfilter without a friendly_name to Search, scoped to the modern bar so legacy pages are unchanged. * Apply the filter when the search glyph is clicked The ti ti-search magnifying glass added after filter/rfilter inputs was decorative. A delegated click now submits the input's form, or on the modern bar (no form) triggers Enter, so clicking it applies the filter. * Use the legacy filter on Console > Management > Sites The Sites list gains nothing from saved layouts; set render_layouts = false so it renders the classic legacy filter. * Restore Search in the Edit dialog and glyph-ify Purge Mirror the bar Search into the Edit dialog (synced to the canonical bar input on open and on edit) so a saved layout's search term is visible and editable there without duplicating the input id; the bar stays the source of truth and nothing persists to a layout until it is saved. Also force a ti ti-flame glyph for the page-action Purge button. * Order Search before Rows on the modern bar to match legacy filters * Narrow the modern-bar regex Search to the normal filter width The rfilter (regex Search) input on the modern bar renders at size=55, much wider than the size=30 normal filter. Cap it at 30ch via .cactiFilterModernBar input#rfilter in every theme except Midwinter, which the user asked to leave as-is. * Document the modern-bar Clear, Purge glyph, dialog Search, and Sites legacy filter in the changelog * Glyph-ify the clog Rotate button Force a ti ti-rotate glyph for the page-action Rotate button (clog log rotation), matching the Purge/Save/Clear glyph treatment. --------- Co-authored-by: TheWitness <TheWitness@users.noreply.github.com> |
||
|
|
2a44c7a791 |
feature: modern filter bar polish (Rows/Refresh on bar, dialog button labels, separators) (#8191)
* fix: label modern dialog apply/clear with the page button text; show Rows on the bar
The dialog apply button was hardcoded 'Search', which mismatched the page's submit label (e.g. 'Go') and collided with pages that have a filter field named Search (clog). It now uses the configured go/clear button display text. Also route the 'rows' field to the modern bar alongside timespan/refresh so the per-page Rows selector stays visible.
* feature: always label the row-count selector 'Rows'
emit_field() forces the 'rows' field friendly_name to Rows regardless of page-specific naming (Devices, Trees, ...), in both legacy and modern filters. Refresh already renders on the modern bar via field_is_bar.
* feature: order modern bar selectors (Rows, Refresh) and separate them from the buttons
Rows renders first and Refresh second on the modern filter bar, and a vertical separator now divides the selectors (Layouts, Rows, Refresh) from the layout action buttons.
* changelog: 8191.feature fragment for modern filter bar polish
* jQuery 4: replace removed $.isFunction in bundled plugins
jQuery 4.0 removed $.isFunction. contextMenu, colorpicker and timepicker are hand-vendored orphans fixed in place; tablesorter is npm-managed, so it is also rewritten at sync time in build/sync-js.mjs so a rebuild reproduces the fix (no-ops once the upstream fix is released and the pin is bumped).
* Render the Thumbnails and Business Hours graph filter checkboxes as Cacti toggles
* fix: address review — update modern JS docblock and strengthen bar/label tests
Rewrite the create_modern_javascript docblock to describe the page-configured apply/clear labels (and document the change/clear callback params). Extend FilterLayoutsTest to assert the selector|button separator, the applied Rows-then-Refresh ordering, and both go/clear label lookups, and that the hardcoded Search dialog label is gone.
* Filter bar polish: toggle-style filter checkboxes and flicker-free layout buttons
Render the shared filter_checkbox field as a Cacti toggle switch (.checkboxSwitch/.checkboxSlider) so every page's filter checkboxes match the rest of the UI, and start the layout Rename/Delete/Save As buttons hidden so layoutUpdateButtons() reveals them only when applicable instead of flashing visible on load.
* Modern filter: move the timespan selector onto its own second filter line
Timespan controls were rendered inline on the single modern filter bar. Route method=timespan fields into a separate group and emit them as a second filterTable row so the bar isn't overcrowded, matching the legacy multi-row layout. Applies to every modern filter with a timespan (the graph view pages).
* Modern filter: keep toggle checkboxes on the bar with a visible label and tooltip
filter_checkbox fields now count as bar fields so the Thumbnails/Business Hours toggles sit on the single bar instead of the Edit dialog. Their label used .checkboxLabel (display:none by design for forms), which hid the text; switch to .checkboxLabelWanted and always set a title tooltip from the field's title/friendly_name so each toggle is self-describing.
* Modern filter: toggles back in the dialog, restrict auto-apply to bar fields, drop dialog Clear
- Move filter_checkbox toggles back into the Edit dialog (field_is_bar no longer claims them) and render them as a form row: friendly name in the label column, toggle in the value column.
- In modern mode only bar selectors (Rows, Refresh) and the Layout selector auto-trigger a filter change; dialog field changes/clicks no longer call applyFilter (gate changeChain/clickChain on !use_modern_filter() || field_is_bar). Legacy keeps auto-applying on change (text inputs still excluded).
- Remove the Clear button from the modern Edit dialog and the now-unused clearLabel; update the dialog-labels test accordingly.
* Fix filter toggle vertical alignment across themes
The generic .filterTable .filterColumn label { vertical-align: -10% } nudge (meant for text labels) out-specified .checkboxSwitch and dragged the toggle switch down, which also pulled the adjacent label baseline low in the Edit dialog and misaligned the toggle on the legacy filter bar. Add a higher-specificity label.checkboxSwitch { vertical-align: middle } in every theme carrying the rule (midwinter has no such rule).
* Hide the filter search glyph in the modern Edit dialog
Theme main.js appends a ti-search glyph after #rfilter, positioned for a table cell; in the modern Edit dialog #rfilter sits in a wide div (no td), so the glyph wraps below the field. Skip the injection when #rfilter is inside .cactiFilterEditTable (modern dialog); legacy, which has no such ancestor, keeps the glyph.
* jQuery 4: full removed-API sweep of bundled plugins
Replace every jQuery-4-removed helper across the vendored plugins: \$.trim -> String.prototype.trim, \$.isArray -> Array.isArray, \$.proxy -> Function.prototype.bind, \$.parseJSON -> JSON.parse, \$.type -> typeof/\$.isPlainObject, \$.isWindow -> native window check (plus the earlier \$.isFunction). Orphans (colorpicker, timepicker, multiselect, multiselect.filter, tableDnD) are fixed in place; the npm-managed tablesorter core+widgets are rewritten at sync time in build/sync-js.mjs so a rebuild reproduces the fix.
* Modern filter dialog: non-modal, Apply gated on save, Save keeps dialog open
- Rename the dialog apply action to Apply and disable it until the (new or changed) filter is saved (layoutDirty tracking); Close just closes without applying.
- Save no longer reloads the page: it reflects the saved layout in the selector and re-enables Apply, keeping the dialog open.
- Dialogs are now modal: false.
- Switch the layout selector change from a full document.location reload to an AJAX loadUrl().
- Vertically center the modern bar cells so the barSep separator lines up between the buttons.
* Modern filter: add layout to the filter's session variable structure
Register layout (FILTER_VALIDATE_INT, default 0) in sanitize_filter_variables() alongside page so the selected layout is validated and stored in the filter's session object and persists across page views.
* Modern filter: Graph Template amalgam on line 2, timespan on line 3
Tag the Graph Template + Source/Order/CF/Measure group ('bar' => true on graph_template_id and the html_graph_order_filter_array() metrics) so create_modern_filter renders it as its own second filter line on Graph View and Tree View, pushing the timespan to the third line. These bar fields also auto-trigger the filter so the Template->Source->Order callback chain works on the main bar.
* Fix graph_template_id multi-select: allow comma lists, type get_host_graph_list correctly
get_host_graph_list() immediately transforms graph_template_id via html_transform_graph_template_ids() (handles cg_/dq_ prefixes and comma lists), so its parameter is a string, not an int -- correct the type hint and docblock. Also widen the preview and listview graph_template_id validation regexp to accept a comma-separated list like 'cg_118,cg_106,cg_119', matching the tree filter.
* Modern filter: hide the whole cell for hidden layout buttons to even out bar separator spacing
The Rename/Delete/Save As buttons hid only the <button>, leaving their table-cell (with padding) in the bar, so the separator after them was pushed away from Edit. Put the display:none on the .filterColumnButton cell and toggle the cell in layoutUpdateButtons so hidden buttons take no space and the separators sit evenly between the visible buttons.
* Remove legacy .drop-callback/makeCallbacks() autocomplete widget
The Device dropdown and other form_callback() lookups now always use the
ajax-backed select2 selectmenu. Drop the old makeCallbacks() jQuery-UI
autocomplete entirely and have form_callback() render the select2-callback
<select> by default, keeping the plain full-list <select> only when the
'autocomplete' config option is enabled.
* Carry selected layout through the modern dialog Apply action
The layout_save callback already returns the new layout id (and url), and
layoutDialogSave() selects it in #filter_layout. The dialog Apply button,
however, ran the plain filter apply (applyFilter()) which rebuilds the URL
from the field values and omits filter_layout, so the page reloaded as
(New Filter). Apply now navigates to the selected layout's data-url (which
includes filter_layout=<id>) when a layout is selected, falling back to the
normal filter apply when none is.
* Fix Filter Layouts manage page table and use jQuery UI dialogs for delete/rename
The management table was opened with html_start_box(\ = true), emitting a
<div> instead of a <table>, so the header and rows rendered unstyled and
run-together. Switch it to table mode.
Replace the generic confirm()-based delete with a CDEF-style jQuery UI
confirmation dialog loaded over ajax, and add a Rename action that opens a
matching jQuery UI dialog with a name field. Both post to the existing
layout_delete/layout_rename handlers on confirm.
* Use jQuery UI dialogs for filter-bar layout rename/delete; drop rename from manage page
The filter bar (modern and legacy) was still using native prompt()/confirm()
for the layout Rename and Delete actions - convert both to jQuery UI dialogs
(a name-entry dialog for rename, a confirm dialog for delete).
On the Filter Layouts management page, remove the rename action entirely and
instead link the layout name to its page (with filter_layout set) as an edit
link; keep the Delete confirmation dialog and Publish action.
* Rework Layouts manage page: preset filter bar + actions dropdown; rename to Layouts
Model layouts.php on the preset pages (CDEFs, etc.): add the standard
CactiTableFilter search bar in the legacy look, a sortable list with a
checkbox column, a pager, and a draw_actions_dropdown with Delete, Make
Global (publish), and Make Local (reassign to the current user). The
unimpressive per-row action icons and ajax dialogs are replaced by the
checkbox/confirmation flow. Make Global/Make Local are admin-only.
Treat layouts.php as a filter_layouts preset page so its own filter bar
does not offer the layout dropdown. Rename the page title and Console
Presets menu entry from 'Filters'/'Filter Layouts' to 'Layouts'.
* Show friendly page name in the Layouts list Page column
Map the stored page basename to the Console navigation title (e.g. host.php
=> Devices) via a layouts_page_name() lookup against \, falling
back to the raw basename. The Page column is now nosort since the displayed
label no longer matches the sortable database value.
* Fix filter search TypeError: use filter_options key in default search field
sanitize_filter_variables() reads a field's callback options from the
'filter_options' key, but the default search field in create_default() stored
them under 'options', so the key never reached validate_store_request_vars().
That left FILTER_CALLBACK with no callback and raised 'filter_var(): Option
must be a valid callback' whenever a table filter was searched.
* Address PR scan findings: tablesorter useless conditional + layouts SQL
- jquery.tablesorter.js: drop the redundant 'str &&' guard inside the
already-truthy 'str ?' branch of the digit and currency parsers (CodeQL
useless-conditional). Add a matching sync-js transform rule so a rebuild
from upstream keeps the simplification.
- layouts.php: fully parameterize the management list queries with bound
'?' parameters for the search term and user id, and build the LIMIT from
explicit (int) page/rows, so no request variable reaches the SQL string
(Semgrep cacti-request-var-in-sql).
* Address PR review: colorpicker trim, tablesorter JSON guard, bar separator, i18n
- jquery.colorpicker.js: _setAltField() iterated index <= properties.length, so
the last pass read properties[undefined]; \$.trim(undefined) was '' but native
.trim() throws. Iterate with < so no TypeError.
- jquery.tablesorter.widgets.js: the retrieveValue feature-check still tested the
removed \$.parseJSON; under jQuery 4 it was always falsy so saved widget state
never loaded. Test native window.JSON.parse instead, and add a matching
build/sync-js.mjs transform rule so a rebuild keeps the guard.
- html_filter.php: the Layouts selector is always rendered, so emit the
selector-to-button separator unconditionally (graph preview routes fields to
the amalgam/timespan lines, leaving the bar line without it before).
- changelog/i18n: reword 8191.feature to describe the Apply (save-gated) dialog
action, and add the new layouts.php/html_filter.php msgids to cacti.pot.
* Add tablesorter transform coverage to the sync-js test
Feed a fixture containing every removed jQuery 4 utility (\$.isFunction,
\$.trim, \$.type ===string/object, \$.isWindow, \$.isArray, \$.parseJSON calls
and the bare if (\$.parseJSON) guard) plus the CodeQL str && simplification
through syncAssets, and assert the synced tablesorter output contains the
native equivalents and none of the removed APIs. Previously the transform ran
against a generic stub, so an incomplete rewrite could pass unnoticed.
* Apply php-cs-fixer: comment style, alignment, and single-quote strings
Run through the project php-cs-fixer config (the mandatory pre-PR check):
line comments for the input-validation banners, aligned assignment, and
single-quoted strings where no interpolation is used. No behaviour change.
* Render the filter Go action as a refresh glyph button (modern + legacy)
Replace the 'Go' text submit with a compact 'ti ti-refresh' glyph button
titled 'Refresh page' for every page filter:
- emit_field() forces the glyph/title on any 'go' submit, so both the shared
default and pages that define their own 'go' get it on the legacy filter.
- The modern bar (which has no form) gets a JS-wired #layout_refresh glyph
button right of Edit that loadUrl()s the selected layout url (carrying
filter_layout) or the page change callback.
Add the 'Refresh page' msgid to cacti.pot and note it in 8191.feature.
* Add a Tabler .icon-rotate spin class and use it for refreshing icons
Tabler ships only the icon webfont, with no fa-spin equivalent, so spinning
reload icons stopped animating (e.g. the Troubleshooting > Data Sources
auto-refresh indicator). Define .icon-rotate in every theme (reusing the
globally loaded fa-spin keyframes) and apply it:
- the modern filter refresh button spins while it loads,
- the realtime graph drill-down loader switches from fa-spin to icon-rotate,
- the data_debug auto-refresh indicators spin again.
* tests: sync FilterLayouts assertions with the reworded separator comment and dw.addClass
The source scan expected the old 'Separate the selectors' comment and a chained
.dialog('widget').addClass() form; update to the current reworded comment and
the 'var dw' + dw.addClass('cactiFilterDialog') the dialog now uses.
* Glyph-ify the timespan Refresh/Clear and the generic Clear action
Replace the timespan 'Refresh' text button with a spinning ti ti-refresh glyph
and 'Clear' with a ti ti-eraser glyph (also fixing a stray double </span>), and
make the generic filter Clear a ti ti-eraser glyph button across legacy and
modern via emit_field (button case now honours a 'glyph' key). The timespan
refresh icon spins (icon-rotate) while it reloads.
* Glyph-ify filter Import/Export, layout, and modern-bar action buttons
Force ti-table-import / ti-table-export glyphs for any filter button named import/export (centralized in emit_field like go/clear), so page-defined Import/Export buttons and the modern bar's always-visible action strip render consistent Tabler glyphs. Add a glyph parameter to layout_button() and glyph the Edit/Rename/Delete/Save As/Save/New/Publish buttons across the modern bar and legacy layouts row.
* Use table-import/table-export glyphs for cactiTableButton Import/Export icons
The filter header Export/Import icons injected into cactiTableButton used generic chevron-down/chevron-up glyphs; switch them to ti ti-table-export / ti ti-table-import to match the rest of the glyph theme.
* Glyph-ify the Save Filter Defaults button on the filter bar
The has_save 'Save' action rendered as a text button on the modern bar (and legacy filter); force a ti ti-device-floppy glyph via emit_field like go/clear/import/export so it matches the rest of the glyph theme.
* Regenerate tree-view graphs when applying a saved filter layout
The modern layout selector loaded a layout's saved data-url (action=tree) directly, so on the Graph Tree view it pulled the tree shell instead of regenerating graphs. Route the layout-url loads (selector change, refresh button, and dialog Apply) through correctUrlParameters() so action=tree becomes action=tree_content and graphs reload into #main, matching applyGraphFilter(). No-op on non-tree pages.
* Keep timespan controls working after ajax reloads and tip custom date fields
On the Graph Preview page the predefined_timespan change and tsrefresh/tsclear/shift click handlers were bound directly inside the filter's inline ready script, so an ajax content reload that replaced the timespan controls dropped the bindings (a full page refresh restored them). Bind them with namespaced event delegation on document so they survive content replacement and never double-bind. Add tooltips to the custom start/end date inputs telling the user to click Refresh to apply the range, plus POT entries and a changelog note.
* Record layouts.php static redirect in the sink inventory baseline
The sink and architectural hotspot guard flagged inventory drift: layouts.php's static header('Location: layouts.php') redirect (no request input) was never added to the tracked baseline. Refresh the baseline via tests/security/build_sink_inventory.sh to record it.
* Fix layout Save-As dialog state and use cacti_redirect in layouts.php
Address review findings: (1) use cacti_redirect('layouts.php') instead of a raw header()+exit so the standard redirect checks run (and drop the now-unneeded sink-inventory entry); (2) reset the dialog's force-new flag after the first successful save so later saves update the created layout instead of creating duplicates; (3) preserve an existing dirty state when reopening the Edit dialog so pending edits are not silently discarded by Apply.
* Drop stale layout msgids from the translation template
Remove the Filter Layouts, Published to all users, Publish to all users, and No Filter Layouts Found msgids that this PR replaced (now Layouts, Make Global, Make Local, No Layouts Found); all four are absent from PHP. Keeps the surgically-maintained POT in sync with the shipped strings.
---------
Co-authored-by: TheWitness <TheWitness@users.noreply.github.com>
|
||
|
|
1c96e16a3f |
support: recommend supported DB releases and fix MariaDB detection (#8186)
* support: recommend supported DB releases and fix MariaDB detection - Update the database version recommendation to the supported release streams (MariaDB 10.5+, MySQL 8.0+, e.g. the defaults on RHEL 9) and make the recommended '>=' threshold database-aware instead of a flat 5.6. - Fix MariaDB being mis-detected as MySQL when the version suffix capitalization differs: use case-insensitive matching (stripos/str_ireplace) in get_mysql_info() and the connection setup. This drives the '%s Tuning' header and all MySQL/MariaDB branching on the Technical Support page. - Remove dead code that special-cased MySQL < 8.0 (now unsupported): the '(MySQL && < 8.0) || MariaDB' guards in support.php and lib/utility.php collapse to just 'MariaDB'. * support: reference Rocky Linux 9 instead of RHEL 9 in DB recommendation * support: change RHEL font-path comment to Rocky * docs: update System Requirements and DB recommendation for 1.3.x - README: raise minimums (develop: MariaDB 10.11+, MySQL 8.4+, PHP 8.3+; 1.2.x column: MariaDB 10.5+, MySQL 8.0+, PHP 8.2+, RRDtool 1.7+), set Net-SNMP 5.9+ floor, mark php-snmp fully supported, and note upcoming PHP 8.6 support speeding up Script/Script Server collection. - Bump the develop DB recommendation to MariaDB 10.11+/MySQL 8.4+ to match the 1.3.x minimum. --------- Co-authored-by: TheWitness <TheWitness@users.noreply.github.com> |
||
|
|
5403cf75bb |
feature: user-defined filter layouts with administrator publishing (#8185)
* feature: user-defined filter layouts with administrator publishing
Add a render_layouts toggle to the CactiTableFilter class so list pages
offer Save / New / Rename / Delete controls for saved filter layouts,
modelled on the monitor plugin. Layouts persist to a new user_layouts
table (id, user_id, page, name, url). The toggle defaults on for every
page except the Console > Presets pages (CDEFs, VDEFs, Colors, GPRINTs,
Data Profiles, SNMP), where it is off.
Each user manages their own layouts from any filter. Administrators who
hold the Settings/Utilities realm can publish a layout to all users
(moving it to user_id = 0) from the filter, and from a new
Console > Presets > Filters management page (layouts.php) where they can
view and manage every user's layouts. Published layouts appear for all
users on that page.
Layout create/rename/delete/publish requests are handled centrally by
filter_layouts_handle_request(), invoked from include/auth.php after the
user has been authorized for the current page, so the controls work on any
filter page while publishing stays gated on the realm. layouts.php itself
is mapped to the Settings/Utilities realm so the Presets > Filters menu
pick is administrator-only.
Schema added to cacti.sql, install/upgrades/1_3_0.php, and
docs/audit_schema.sql. Adds tests/Unit/FilterLayoutsTest.php covering the
URL-safety validation, preset-page defaults, and the request/permission
wiring.
* changelog: 8185.feature fragment for filter layouts
* chore: enforce LF line endings via .gitattributes and normalize new files
* fix: address review - attribute-escape layout options, honor failed/non-editable layout ops, regenerate cacti.pot, move test to Unit/Ui/Html
* chore: renormalize pre-existing CRLF files to LF per .gitattributes
* chore: keep vendored JS (big.js, tablesorter) byte-identical to upstream and exclude from LF normalization
* style: apply php-cs-fixer formatting and resolve PHPStan level 8 findings in filter layouts
* ci: re-trigger checks on current head
* refactor: store filter layouts as a versioned JSON document in a TEXT data column
Replace the user_layouts.url varchar(1024) column with a data TEXT column holding a versioned {version,page,filter} document. The navigable url is rebuilt server-side from the document (page basename + rebuilt query) plus the filter_layout marker, removing the stored-url redirect/XSS surface and making the backend forward-compatible with a structured query builder without a further schema change.
* feature: add Modern/Legacy page filter format with an Edit dialog for filters
Modern (default) collapses the filter to a Layouts selector plus an Edit dialog holding the Filter Name and all filter fields; Save and Publish live in the dialog, with Edit/Rename/Delete/Save As on the bar and time controls/refresh kept on the bar. Legacy keeps the classic inline filter. The format is a per-user General setting (page_filter_format). Field rendering is factored into emit_field() so both layouts share one source.
* fix: render page-action buttons (import, export, sort) on the modern filter bar
Import, Export, Purge, Save, and sort ascending/descending are page actions, not filter inputs, so they render on the bar beside the Layouts selector instead of inside the Edit dialog. Only go/clear are dropped from the bar; the dialog keeps the Search/Clear footer.
* feature: render the modern Edit dialog one filter variable per row
The dialog no longer mirrors the inline filter's multi-field row packing; each filter variable renders on its own row (label + control) for a clean, responsive form. Hidden/validate fields stay in the form without an empty visible row. Rows carry a cactiFilterEditRow hook for label-column alignment styling.
* feature: align the modern edit dialog one-per-row and skin it per theme
Render all dialog fields in a single table so the label column aligns via the existing table-cell layout. Tag the dialog widget with cactiFilterDialog and add a scoped skin to the modern theme (slate titlebar, styled button pane, accented primary action). Add a bar separator between layout and page-action buttons.
* feature: skin the modern filter Edit dialog across the classic themes
Add the scoped .cactiFilterDialog skin (accent titlebar, white title/close, styled button pane with an accented primary action) to cacti, carrot, dark, hollyberry, paper-plane, paw, raspberry, and sunrise, each using its own brand accent. The skin is accent-only and inherits each theme's dialog surface, so it works on light and dark themes. MidWinter is intentionally skipped (its variable-based CSS is handled in a separate Epic).
* fix: delete a user's saved filter layouts when the user is removed
user_remove() now deletes the user's own user_layouts rows alongside their other per-user data. Scoped to user_id so published (user_id = 0) layouts remain available to everyone.
* fix: address PR review — PHPStan return type, escaping, callbacks, SQL columns, mb truncation, contrast, POT
- create_filter(): cast both ob_get_clean() returns to string and drop the now-unused PHPStan baseline entry (fixes Level 6 failure).
- Edit dialog title now uses html_escape_attr() (attribute-context double-encoding).
- Modern Search/Clear honor the page's configured go/clear callbacks instead of hardcoding applyFilter()/clearFilter().
- filter_layouts_get() and layouts.php select explicit columns instead of *.
- Layout name truncation uses mb_substr() to avoid cutting multibyte codepoints.
- layouts.php management callback checks result.ok before reloading.
- carrot/paper-plane dialog accents darkened to meet WCAG AA (>=4.5:1) with white text.
- Added the new translatable msgids (Page Filter Format, Filters, Edit Filter, Filter Name, Save As, ...) to cacti.pot.
* fix: resolve Semgrep reflected-xss by reading filter_layout inside layout_select
The request var is no longer passed into layout_select() as a parameter (which Semgrep tracked parameter-to-return to the print sink); it is read internally like create_filter(), and the option markup remains escaped. No behavior change.
---------
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
Co-authored-by: TheWitness <TheWitness@users.noreply.github.com>
|
||
|
|
f79dc15c08 |
Port #8166 SNMP credential cache + procedural SNMPv3 (with #8171/#8172 follow-ups) to develop (#8174)
* Port #8166 SNMP credential cache + procedural SNMPv3 to develop Ports the shared SNMPv3 credential cache and procedural SNMPv3 routing from the 1.2.x feature (merged as #8166) onto develop, adapted to develop's refactored SNMP layer. Parts of the 1.2.x change that do not apply to develop are omitted: the cacti_exec() idle-timeout rewrite (develop has no cacti_exec()), the PHP floor bump and composer/doc changes (develop is already 8.3+), and the cmd.php max_oids batching (develop's cmd.php already collects SNMP in-process through persistent sessions, so the per-item spawn the batching removed does not occur). - lib/cache.php: new cross-process \Cacti\Cache\SharedCache (file + POSIX shared-memory + process-local tiers, optional AES-256-GCM sealing). Loaded via lib/snmp.php (the Cacti\Cache\ namespace is not PSR-4 autoloaded). The crypto helpers it seals with already live in develop's lib/auth.php, loaded by global.php, so no duplicate was added. - lib/snmp.php: snmp_get_method() now routes SNMPv3 get/getnext to the procedural snmp3_*() calls when the running PHP supports the configured auth/privacy tokens and no context/engine id is set (SHA-224/384 and AES-192/256[C] stay on the binary before PHP 8.6); the three single-get functions gain the procedural v3 path with \Throwable handling; adds the credential-cache subsystem, protocol-option/MD5-DES helpers, snmp_native_protocol(), snmp_format_agent() and cacti_snmp_get_multi(); the binary v3 auth builder consults the cache when enabled. - poller.php / script_server.php: prime / load the shared cache. - poller_maintenance.php: daily out-of-band cache rebuild on every collector (per-poller lastrun marker). - lib/api_device.php / lib/utility.php: bump snmp_cred_version only on v3 credential add/change (and propagate the token to the affected remote poller). - include/global.php: resolve and create the private cache/ directory. - include/global_settings.php: add 'Enable Credential Cache' and 'Enable MD5 and DES for SNMPv3' settings (both off by default); default new-device v3 auth/privacy to SHA/AES instead of legacy MD5/DES. - host.php / automation_snmp.php: drop MD5/DES from the pickers when disabled and default new records to SHA/AES on upgraded installs. - include/config.php.dist: document $config['cache_dir']. - tests/Unit/Core/Cache/SharedCacheTest.php: SharedCache behaviour coverage. - tests/security/baselines: baseline the two new lib/cache.php sinks. * Incorporate #8171: binary fallback for unsupported SNMPv3 protocols Layers PR #8171 onto the develop port so an SNMPv3 device whose auth/privacy protocols the running PHP's ext-snmp cannot service natively (e.g. AES-256 before PHP 8.6) no longer fatals the poller or device-edit screen. - lib/snmp.php: add CactiSnmpBinarySession, a session stand-in exposing the get/getnext/walk/close interface the cacti_snmp_session_*() helpers use and delegating each call to cacti_snmp_*() -> the Net-SNMP binary. cacti_snmp_session() returns it when php-snmp is absent or the v3 protocol is not natively serviceable, so cmd.php/host.php collect these devices via the binary on pre-8.6 and switch to the in-process path on 8.6 with no caller change. v1/v2 snmpget/snmp2_get now go through snmp_format_agent(). The ERRNO_TIMEOUT check tolerates php-snmp being absent. Drop the vendored classSNMP.php compatibility shim and its include (and the Yandex attribution). - cmd.php: open_snmp_session() returns the down sentinel when a host is already marked down this run, instead of returning an unset (null) [] that cacti_snmp_session_get() then dereferenced (TypeError). - lib/ping.php: ping_snmp() runs the availability check through the procedural cacti_snmp_get()/getnext() path so an unsupported protocol falls back to the binary instead of raising a ValueError in SNMP::setSecurity(). * Incorporate #8172: retire include/vendor/phpsnmp, relocate into lib Follow-up to #8171 on the develop port. After classSNMP.php was removed, the include/vendor/phpsnmp/ directory held only Cacti-owned files; this retires it. - lib/snmp.php: the ext-snmp subclass that carried Cacti's bulk_walk_size / value_output_format (previously vendor/phpsnmp/extension.php) is now declared directly as CactiSnmpNativeSession, guarded by CACTI_PHP_SNMP; the include and the 'use phpsnmp\SNMP' alias are gone, and new SNMP(...) / SNMP::VERSION_* now reference the native \SNMP and the new subclass. - lib/mib_parser.php: moved from include/vendor/phpsnmp/mib_parser.php; lib/mib_cache.php includes it via __DIR__. - Remove include/vendor/phpsnmp/extension.php and index.php (directory retired). - tests: SnmpCoverageTest uses \SNMP::ERRNO_TIMEOUT now that phpsnmp\SNMP is gone; drop the stale include/vendor/phpsnmp/ entry from the vendor-policy allowlist. develop's sink baseline tracks constant-based includes differently than 1.2.x, so no baseline refresh was needed here. * Address PR #8174 review: snmp_get_method params, v3 walk, getnext agent, cache bump, CHANGELOG - lib/snmp.php: restore $php_snmp as the 6th snmp_get_method() parameter and move the new $auth_proto/$priv_proto after it (callers pass them by name), so the positional $php_snmp used by SnmpCoverageTest and others keeps working. - lib/snmp.php: keep every SNMPv3 operation except get/getnext on the Net-SNMP binary - the native walk branch implements only v1/v2, so a v3 walk reaching the procedural gate would have silently returned empty when path_snmpbulkwalk is missing. - lib/snmp.php: cacti_snmp_getnext() v1/v2 branches now use snmp_format_agent() like get/get_raw, so an IPv6 literal / non-default port is bracketed. - lib/api_device.php: bump snmp_cred_version only when the host's v3 membership or one of the cached credential fields actually changed, instead of on every save of a v3 device. - CHANGELOG: move the #8171 entry into the issue block and the #8166 entries into the feature block, matching the established section ordering. * Fix CI: unbracket IPv4/DNS SNMP targets, inline auth-cache SQL columns, apply phpcsfixer standard * Refresh sink inventory baseline after short-array normalization * Restore lib/snmp.php 100% coverage after aligning v3 routing to 1.2.x - update the three SnmpCoverageTest assertions that still encoded develop's pre-port behavior: v3 snmp_get_method now returns PHP, an unsupported- protocol v3 session returns the binary-delegating session object, and the v3 cacti_snmp_get path runs natively - add a v3 noAuthNoPriv user to the snmp-coverage snmpd fixture so native snmp3_get is exercised deterministically - add tests covering the ported subsystems to 100%: shared auth cache, binary-delegating session, protocol pickers, v3 credential args, cacti_snmp_get_multi, and the cacti_get_snmpv3_auth cache path - snmp_auth_cache_load uses a resettable process guard so its enabled and disabled branches are both coverable in a single process * Resolve phpstan errors in the relocated SNMP MIB parser and ported snmp.php - lib/mib_parser.php: type the MibParser properties, add parameter/return types, guard file_get_contents()/preg_split() against false, correct the parse_bracket_token delimiter params (string, not integer), and drop the unreachable return after trigger_error(E_USER_ERROR) - now phpstan clean - lib/mib_cache.php: drop the redundant isset($mp->oids) guard (the typed property is always initialized; $mp->mib is the real check) - lib/snmp.php: type the CactiSnmpBinarySession and CactiSnmpNativeSession properties/methods and pass bool to snmp_set_quick_print() - .phpstan.neon: ignore greaterOrEqual.alwaysFalse alongside the existing greater.alwaysFalse (the PHP_VERSION_ID >= 80600 forward-compat gate) - regenerate phpstan-baseline.neon for the irreducible ext-snmp stub strictness (snmp3_get literal-union protocols, int<-1,max> timeouts) in the ported procedural v3 path, the new lib/cache.php shmop stubs, and the $config array-shape offsets in include/global.php * Make the v3 getter catch coverage net-snmp-build-independent The DES-rejection trick that drove the procedural snmp3_get()/snmp3_getnext() try/catch blocks only works on net-snmp builds compiled without DES; CI's Debian net-snmp accepts DES, so those catches went uncovered (98.3%). - extend the existing native_get injection seam (already on cacti_snmp_get) to cacti_snmp_get_raw, cacti_snmp_getnext, and cacti_snmp_get_multi, and drive the catch blocks with a throwing native getter in the test - mark the seam-less cacti_snmp_session() setSecurity catch with @codeCoverageIgnore (it only throws for a protocol the running net-snmp rejects, which is not portably reproducible in the fixture) * Exclude ext-snmp/PHP-8.6-gated defensive branches from snmp coverage Two branches in lib/snmp.php are unreachable on the PHP 8.3 + ext-snmp coverage runner and were only "covered" locally via opcache dead-code elimination: - snmp_get_method()'s !function_exists('snmp3_get') fallback (ext-snmp always provides snmp3_get) - snmp_php_v3_protocols_supported()'s PHP_VERSION_ID >= 80600 block (SHA-224/384 and AES-192/256 tokens are only accepted on PHP 8.6+) Mark both with @codeCoverageIgnore so the 100% gate is deterministic across runners regardless of opcache settings. * Account for the #8166 SNMPv3 credential-cache gate query in the batching test poller_update_poller_cache_from_buffer() now runs one SELECT per flush to decide whether the flush touched SNMPv3 poller items before bumping the shared credential-cache version (matching 1.2.x). UpdateDataQueryCacheBatchingIntegrationTest counted 4 statements per flush; update it to 5 (and 3 per-row flushes to 15, 1 batched flush to 5). The guard's intent - batching issues fewer statements than per-row flushes - still holds. * Port #8175: group SNMP options under an SNMP Behavior section Mirror the 1.2.x settings reorganization (#8175) on develop. develop already keeps the SNMP options in a dedicated SNMP tab, so add an "SNMP Behavior" spacer there, order the behavior options as md5/des, credential cache, max get size, bulkwalk fetch size, and move "Disable increasing OID Check" out of the Poller tab to sit last in that group. Display-only; no settings added or removed and no behavior change. Adds the "SNMP Behavior" heading to cacti.pot. * fix: complete dependabot htmx 2.0.10 to 2.0.11 bump Dependabot bumped package.json and package-lock.json to htmx.org 2.0.11 (PR 8179) but left the vendored include/js/htmx.js, its version marker, and the pinned SRI constant at 2.0.10. The htmx-filters CI workflow runs npm ci, which regenerates include/js/htmx.js from the 2.0.11 package, so HtmxTest's runtime sha384 no longer matches the HTMX_2_0_10_SRI constant and the integrity assertion fails. Complete the bump: regenerate the vendored include/js/htmx.js to the 2.0.11 build, bump include/js/htmx.js.version to 2.0.11, rename HTMX_2_0_10_SRI to HTMX_2_0_11_SRI with the recomputed sha384 hash, and update the version/integrity assertions in tests/Unit/Ui/Html/HtmxTest.php and tests/HandOff/HtmxLoaderHandOffTest.php. package.json and package-lock.json match the values dependabot already landed on develop. * settings: move SNMP Agent Support under the SNMP Behavior spacer Relocate the enable_snmp_agent setting (SNMP Agent Support Enabled) so it is the first item under the SNMP Behavior spacer instead of sitting in the Poller General group, grouping it with the other SNMP behavior options. * Address PR #8174 review: keep SHA-224/384 on the binary, honor port on transport targets Resolves the two still-valid Copilot review findings on lib/snmp.php that were left unresolved (only marked outdated after later commits shifted their lines). - snmp_php_v3_protocols_supported(): drop SHA224/SHA384 from the native auth allowlist. ext-snmp's SNMP::setSecurity()/snmp3_*() only map MD5/SHA/SHA256/ SHA512 - there is no SHA-224/SHA-384 mapping on any build, including PHP 8.6 (verified against php-src ext/snmp/snmp.c), so routing those tokens to the procedural path raised a ValueError instead of using the binary. They now always fall back to the Net-SNMP binary. The AES-192/256 privacy tokens that ext-snmp does add on 8.6 stay gated behind PHP_VERSION_ID >= 80600. - snmp_format_agent(): a udp/tcp transport-qualified target that omits a port now has the configured non-default port appended (udp6:[2001:db8::1] + 1161 -> udp6:[2001:db8::1]:1161), matching the Net-SNMP binary path. Targets that already carry a port, and unix: sockets (no port), are left untouched. - SnmpCoverageTest: cover the new transport-target branches; lib/snmp.php stays at 100%. |
||
|
|
7b551eea72 |
chore: normalize CRLF line endings to LF across Cacti-owned files (#8156)
Excludes vendored packages, third-party JS, patches, and the Win32 probe fixture. Pure EOL change; guards pass and php -l is clean. |
||
|
|
41e6d9e033 |
security: consolidate verified GHSA fixes for develop (batch 4) (#8145)
* security: consolidate verified GHSA fixes for develop (batch 4) Develop counterparts of the 1.2.x batch-4 fixes in #8144, re-verified against current develop HEAD. - GHSA-4rmr-wvjq-qxc2: include/auth.php Basic Auth and guest branches fall through to the per-page realm check instead of returning early. - GHSA-j67j-wpm4-9g3x: the pre-dispatch update_policy branch in user_admin.php and user_group_admin.php requires a CSRF-token POST. The denylist -> allowlist redesign is tracked for 1.3 in #8143. - GHSA-2p3x-f5jm-rg6p: the View-Graphs -> poller RCE chain is broken by the realm check (4rmr), the update_policy guard (j67j) and shell-free webhits (x5pw). - GHSA-x5pw-cg7j-mj4r: scripts/webhits.pl runs wc through a shell-free list-form open. - GHSA-9737-rqh3-h7fh: names interpolated into raise_message() now use __esc() across the UI; URL- and HTML-bearing messages are excluded. - GHSA-9x9h-2577-9w86: the colordropdown input is built as a node and the label is no longer round-tripped through parseHTML (the list item already used createTextNode on develop). - GHSA-h96j-8xhc-2p3w: remote_agent.php authorizes on $_SERVER['REMOTE_ADDR'], not get_client_addr(), which honours client-settable proxy headers. Regression guards under tests/Unit/Security/{Auth,Csrf,Xss,ShellInjection}. php -l, check-changelog.py and the sink/architectural baselines all pass. * chore: reference PR #8145 on the batch-4 1.3.0-dev CHANGELOG entries * security: resolve develop merge - keep id-only xmlerror unescaped (matches #8141 h745 test) * security(GHSA-j67j): use REQUEST_METHOD POST guard instead of raw \ (hardening-pattern-guard) * security(GHSA-9737): fix review findings - drop double-encoding in __esc, escape missed name sinks, correct plugins format-arg count |
||
|
|
0055dd00cc |
security: consolidate verified GHSA fixes for develop (batch 3) + CHANGELOG CVE reconciliation (#8141)
* security: consolidate verified GHSA fixes for develop (batch 3) Develop counterparts of the 1.2.x fixes in #8138, each re-verified against develop HEAD. - GHSA-77pr-g949-4v5f: spikekill.php also requires is_graph_allowed() on the target graph, not just the Spike Kill realm. - GHSA-w3qw-762w-6g9v: the include/global.php GET action guard fails closed on an array-form action[] before the scalar denylist comparison. - GHSA-xhpr-w454-cc9w: update_poller_cache() casts the stored output_type to int before interpolation. - GHSA-j3px-vw6r-g25x: graphs_new.php escapes stored snmp_index via db_qstr() in the data-query IN() pivot. - GHSA-h745-3r76-g253: graphs_new.php escapes the data-query and field names in the XML parse error messages (__ -> __esc). GHSA-297h-95ff-r767 does not apply on develop: the clog log-file selector renders through the drop_array filter framework, which escapes. tests/Unit/Security/ConsolidatedBatch3Test.php adds source-scanning regression guards. CHANGELOG (1.3.0-dev) updated; php -l, the security baselines, and check-changelog.py all pass. * chore: lead 1.3.0-dev security CHANGELOG entries with the GHSA id Normalize the 1.3.0-dev -security entries to the approved "-security: GHSA-xxxx [CVE-xxxx] Description" form, moving the advisory id to the front. CVE tokens are omitted because none of these advisories have a CVE issued yet (verified via the repository security-advisories API). Covers the five batch-3 entries plus the pre-existing entries that still used the trailing (GHSA-xxxx) form. * chore: use the -security#GHSA-xxxx: form for the 1.3.0-dev CHANGELOG entries Correct the batch-3 and reconciled 1.3.0-dev -security entries to the approved "-security#GHSA-xxxx: CVE-yyyy Description" form (GHSA id in the prefix). No CVE tokens are added because none of these advisories have a CVE issued yet (verified via the repository security-advisories API). * test: split batch-3 security guards into vulnerability-class files; reconcile CHANGELOG - Move the ConsolidatedBatch3Test.php guards into the matching Auth, Csrf, SqlInjection and Xss folders with behavior-based filenames, and strengthen them per review: the GET-guard test asserts the array branch actually returns 405 and exits; the snmp_index test rejects both raw concatenation branches; the parse-error test asserts every name-bearing message uses __esc(). - Append this pull request number to the five new 1.3.0-dev security entries. - Add issued CVE identifiers to the older -security#GHSA CHANGELOG entries (verified via the repository security-advisories API). Entries with no CVE yet, entries that already carried a CVE, and non-GHSA lines are unchanged. |
||
|
|
3ab4c69fb7 |
PHPStan Level 8 - Phase 1 Conversion (#8135)
* PHPStan Level 8 - Phase 1 Conversion
Reduces the real (no-baseline) PHPStan level 8 error count from ~2,724 to 425
and regenerates phpstan-baseline.neon accordingly (8,941 -> 1,921 lines).
Core type-safety changes
- lib/database.php: narrow db_fetch_row()/db_fetch_row_prepared() to return
array (was bool|array) and db_fetch_assoc()/db_fetch_assoc_prepared() to
return array (was mixed); the _prepared workers coerce the connection-failure
path to an empty array so the declared type is honest. empty()/cacti_sizeof()
checks are unaffected.
- lib/database.php: narrow $db_conn guards from is_object() to instanceof PDO in
the transaction/quote/insert-id helpers so the PDO calls resolve.
- lib/mib_cache.php: the fluent MibCache methods mib()/object()/table()/row()
now return self instead of a bare object so chained calls type-check.
Type-safety casts and guards (mechanical, behaviour-preserving)
- Cast string|false/|null builtin results feeding string parameters
(json_decode, base64_encode, trim, htmle, preg_replace, explode, etc.).
- Cast int|string / int|false values feeding int id/pid parameters.
- Guard resource|false fopen()/popen() handles before fwrite/fclose/fread, and
wrap foreach over array|false/list|false results with `?: []`.
Genuine bugs found and fixed
- cli/add_tree.php / lib/api_tree.php: site tree nodes could not be created via
the CLI - the --site-id option was never parsed, $nodeTypes had no 'site'
entry (passing null to api_tree_item_save(int $type) -> TypeError), and
api_tree_item_save() never persisted site_id. All three fixed.
- tree.php: leaves_exist() is typed : int but returned db_fetch_assoc_prepared()
(an array of rows) for a SELECT COUNT(*); now uses db_fetch_cell_prepared()
and returns the scalar count.
- lib/mib_cache.php: $entries_per_object was a float (division / ceil) used as
an array key (PHP 8.1 implicit float-to-int key deprecation); now cast to int.
Config
- .phpstan.neon: add notIdentical.alwaysTrue and booleanAnd.alwaysFalse to the
existing always-true/false ignore family (same "PHPStan gets confused"
dynamic-constant cause already covered by identical.alwaysTrue,
notEqual.alwaysTrue, booleanAnd.leftAlwaysTrue, etc.).
- phpstan-baseline.neon: regenerated; the remaining 425 entries are the
untouched long tail for Phase 2.
* Remove redundant @phpstan-ignore comments
Follow-up cleanup for the level 8 Phase 1 work. Removes 14 inline
@phpstan-ignore comments that no longer suppress any reported error:
- cli/repair_database.php: `@phpstan-ignore booleanAnd.alwaysFalse` is now
covered by the global booleanAnd.alwaysFalse ignore added to .phpstan.neon.
- 13 others (host.php, include/global.php, include/session.php,
lib/api_automation.php x2, lib/functions.php x2, lib/html_utility.php x2,
lib/installer.php, lib/package.php, lib/reports.php, lib/rrd.php) no longer
match any reported error after the type-safety fixes (e.g. the
db_fetch_row_prepared() return-type narrowing removed the offset-assign
errors the api_automation ignores were suppressing).
Verified with reportUnmatchedIgnoredErrors enabled: 0 unmatched ignores
remain and the full level 8 run still reports 0 errors.
* ci: satisfy validator ratchet and refresh security sink baselines
- lib/api_tree.php: give the new tree-item site_id a real numeric
constraint ('^[-0-9]+$', matching html_reports.php) instead of an
empty regex, so the validator constraint ratchet passes without
bumping its baseline.
- tests/security/baselines: refresh the three sink/hotspot signatures
whose code text changed from the (string) casts added in this branch
(lib/poller.php setsid, cli/rrdresize.php json_encode, lib/import.php
simplexml_load_string).
* ci(js): allow DOMPurify 3.4.16 and update sync_js pin test
The dependabot bump (#8134) moved package.json/package-lock.json to
DOMPurify 3.4.16 on develop but left tests/js/sync_js.test.mjs pinned to
3.4.15, so the PR merge commit fails the 'DOMPurify is pinned' contract.
Bring package.json/package-lock.json to 3.4.16 (matching develop) and
update the pin test to expect 3.4.16.
* test: update sql.php null-handling assertion for the (string) cast
This branch changed scripts/sql.php from trim(\ ?? '') to
trim((string) \) (the phpstan-safe form that coerces both null and
false from shell_exec()). Update SqlScriptsTest's null-return assertion
to match the new cast instead of the removed '?? ''.
* fix: address Copilot review - ownership IDs, fopen guards, mib_cache bound
- chown()/chgrp(): pass integer UID/GID from fileowner()/filegroup()
(guarding the false lookup) instead of string-casting them, which made
them resolve account/group names like '1001' and fail. Covers
lib/api_device.php, lib/boost.php and poller_maintenance.php (x2).
- fopen() failure now short-circuits instead of reporting success:
lib/package.php returns false, lib/clog_webapi.php and utilities.php
render an error, and snmpagent_mibcachechild.php skips the cache write
and sentinel unlink so a concurrent writer's lock is preserved.
- lib/mib_cache.php: keep the float quotient as the loop bound and cast
only the array offset, so a non-even entries/columns split no longer
truncates the loop and drops a cached row.
* revert: keep db_fetch_* returning false on error; baseline Level 8 instead
Per review, restoring the intentional fail-safe: db_fetch_row[_prepared]()
return bool|array and db_fetch_assoc[_prepared]() return mixed again, so a
genuine SQL error (not just a missing connection) is signalled as false and
the === false checks in cdef_is_in_use(), boost_process_* and aggregate.php
work as before. Dropped the is_array() ? : [] coercion.
Level 8 stays green by regenerating phpstan-baseline.neon to capture the
re-introduced bool|array/mixed call-site errors (the ~1,850 the narrowing
had eliminated). Tightening those callers to drop them from the baseline is
Phase 2 work.
---------
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
|
||
|
|
6251fed1dc |
Make the drop_multi form method use Select2 by default (#8130)
* form_multi_dropdown: default drop_multi to select2, keep legacy opt-in The drop_multi form method now renders a select2 'N Selected' multi dropdown by default instead of the legacy jquery-multiselect widget, closing a gap left from the earlier select2-multi-count work (html_graph/html_tree already opted in explicitly). A caller keeps the legacy jquery-multiselect widget by including 'multiselect' in its field class; the Scheduler fields used by Automation Networks (lib/api_scheduler.php), Data Source Profiles consolidation functions (global_form.php) and the Settings selective-debug/spikekill pickers (global_settings.php) are marked accordingly so their existing per-page .multiselect() initializers keep working unchanged. Also drops the duplicate class concatenation the old code emitted. * settings: convert selective debug and spikekill template pickers to select2 Mirror of the 1.2.x conversion. Drop the inline .multiselect() initializers for the Logging-tab Selective File/Plugin Debug pickers and the Spikes-tab 'Graph Templates to Spike Kill' picker, and remove their 'multiselect' opt-in class, so applySkin() renders them as the select2 'N Selected' multi dropdown. Each keeps its wording via per-field select_all_text/select_count_text (the select2-multi-count data-attribute mechanism used for graph_template_id): 'Select File(s)'/'Files Selected', 'Select Plugin(s)'/'Plugins Selected', and 'Select Template(s)'/'Templates Selected'. Empty stays the placeholder text (poller_spikekill.php treats no selection as none). * settings: align array operators in debug/spikekill defs (php-cs-fixer) * html_form: legacy opt-in strips select2-multi-count; add drop_multi tests; fix stale docblock When a drop_multi field carries both 'multiselect' and 'select2-multi-count', the legacy opt-in now wins: the select2-multi-count token is stripped so applySkin() does not also decorate the field and collide with the page's own .multiselect() init. Adds tests/Unit/Ui/Html/FormMultiDropdownSelect2Test.php covering the default injection, legacy opt-in, preserved plugin class, no duplication, and the both-token precedence (either order collapses to the legacy widget). Also drops the stale 'Settings selective debug' example from the helper comment since this PR converts those fields to select2. |
||
|
|
d4b8cd3814 |
fix: align Force Uninstall icon (.piforceremove) on the Plugins page (#8110)
* fix: align Force Uninstall icon by adding .piforceremove to icon-padding rule The orphaned-plugin (-5) control introduced in #8107 renders a .piforceremove anchor, but that class was missing from the plugin-action icon padding rule, so the icon lost its 0 3px padding and misaligned in the Actions column. Add .piforceremove alongside .pierror in every theme stylesheet. * fix: align Force Uninstall confirm wording to standard 'Otherwise click Cancel.' pattern develop counterpart of the #8109 dialog copy fix. develop already uses the non-modal displayDialog() with a plain-text message, so only the closing sentence is aligned to the house pattern (with trailing period). cacti.pot msgid updated to match. * fix: bump midwinter core.css cache-buster hash to match the updated file The Force Uninstall (.piforceremove) alignment change edited include/themes/midwinter/css/media/core.css, changing its content md5 to afd5bc6f4d45884846ab715f1583123c, but main.css still imported it with the old ?ad4ed321... query string. Browsers holding the pre-change stylesheet in cache would keep the icon misaligned. Update the import hash so the change is picked up. --------- Co-authored-by: TheWitness <copilot@users.noreply.github.com> |
||
|
|
8a73fc6703 |
tree: Tabler glyphs for jsTree nodes with per-type theme colors and glyph carets (#8101)
* tree: replace jsTree node PNGs with Tabler glyphs, per-type theme colors, and glyph open/close carets * tree: center carets to 20px node row, remove indent dotted lines, add dots:false to editor source tree * tree: center jsTree carets with flexbox so alignment is glyph-height independent * tree: vertically center node glyph with its label text (vertical-align middle) * tree: preserve jsTree loading throbber and add default folder glyph Scope the .jstree-ocl reset and caret glyph content to :not(.jstree-loading) so AJAX expansion keeps its loading indicator, and register a 'ti ti-folder' glyph (with per-theme color) for the untyped 'default' branch type so branch nodes are not left with a blank icon. |
||
|
|
e29581b68a |
Make package/diff viewer colors theme-aware (#8093)
* Make package/diff viewer colors theme-aware The jfcherng/php-diff Inline renderer output is styled by each theme's Diff.css, but every theme shipped an identical copy that hard-coded a light palette (color: black, background: #fff, opaque #fbe1e1/#e1fbe1 add/remove tints). Inside the diff dialog this painted a light box with dark text over dark themes (dark, sunrise, paper-plane) and over midwinter's dark color-mode, so the modal did not match the theme. Derive the base surface from the themed dialog instead of hard-coding it (color: inherit, background: transparent, neutral translucent borders and gutters) and express the add/remove/replace highlights as translucent rgba overlays that read correctly on both light and dark surfaces. Light themes render essentially as before; dark themes now inherit their dark surface and light text. Applied to every theme so the shared stylesheet stays identical. * Band diff code columns on dark themes On the dark themes the unchanged (context) code column and the line-number gutter read too similarly, making the actual diff on the right hard to pick out. Give the context old/new code cells a subtle dark band (rgba(0,0,0,.25)) so the code reads as a panel distinct from the lighter line-number gutter. Applied to dark, sunrise and paper-plane; for midwinter the band is scoped to its dark color-mode only. Light themes are unchanged. |
||
|
|
46908e350b |
fix(ci): pin htmx.org back to 2.0.10 to match vendored asset and SRI (#8091)
* fix(ci): pin htmx.org back to 2.0.10 to match vendored asset and SRI The npm group bump #8085 raised htmx.org to 4.0.0, but the vendored include/js/htmx.js, the HTMX_2_0_10_SRI integrity constant, and the htmx.js.version file were not regenerated. CI's 'Build managed JavaScript' step (build/sync-js.mjs) copies node_modules/htmx.org/dist/htmx.js, so it shipped 4.0.0 while htmx_script_tag() still emitted the 2.0.10 SRI, failing tests/Unit/Ui/Html/HtmxTest. Revert htmx.org to the vendored/pinned 2.0.10; a real htmx 4.x upgrade should be a separate, tested PR. * fix(htmx): sync version file, tests and docs to vendored 2.0.10 |