mirror of
https://github.com/Cacti/plugin_thold.git
synced 2026-10-23 11:36:57 +09:00
* thold: keep legend chips equal width using the longest label The Thold/Host/Log status legends used flex:1 1 0 with no shared minimum, so chips grew to unequal widths (and could clip their labels when tight). CSS can't measure the widest sibling, so the three legend renderers now compute the longest label and emit it as a --thold-chip-min CSS variable (calc(<longest>ch + 1.5rem)); every theme's .tholdLegendItem uses it as a shared min-width (falling back to max-content). All chips share one minimum, so they stay equal width as the legend wraps. Updated TholdLegendTest assertions to match the new container markup. * thold: use CSS Grid for truly equal-width legend chips; assert exact chip min Review follow-up (#847). The 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 - chips were not equal across rows. Switch .tholdLegend to a grid (repeat(auto-fill, minmax(var(--thold-chip-min), 1fr))) so every chip shares an equal column across all rows. The longest-label seed still drives the column minimum. Tests now assert the exact computed calc(Nch + 1.5rem) value instead of mere presence. * thold: use auto-fit so chips fill the legend width when they fit on one row Review follow-up: auto-fill keeps empty implicit tracks, so on a wide viewport where all chips fit in one row they no longer stretch to fill the legend (as they did under flex). auto-fit collapses the empty tracks while still sharing equal columns when the legend wraps to multiple rows. * thold: 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.
107 lines
3.8 KiB
PHP
107 lines
3.8 KiB
PHP
<?php
|
|
/*
|
|
+-------------------------------------------------------------------------+
|
|
| Copyright (C) 2004-2026 The Cacti Group |
|
|
| |
|
|
| This program is free software; you can redistribute it and/or |
|
|
| modify it under the terms of the GNU General Public License |
|
|
| as published by the Free Software Foundation; either version 2 |
|
|
| of the License, or (at your option) any later version. |
|
|
+-------------------------------------------------------------------------+
|
|
| Cacti: The Complete RRDtool-based Graphing Solution |
|
|
+-------------------------------------------------------------------------+
|
|
| http://www.cacti.net/ |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
/**
|
|
* Rendering of the three status legends: thold_legend(), host_legend() and
|
|
* log_legend().
|
|
*
|
|
* Each renderer walks its state-definition global and prints one
|
|
* .tholdLegendItem chip per state, carrying the state's own CSS class and its
|
|
* display label. The state arrays live in includes/arrays.php; html_start_box()
|
|
* and html_end_box() are no-op stubs from the bootstrap, so only the chip
|
|
* markup reaches the output buffer.
|
|
*/
|
|
final class TholdLegendTest extends TestCase {
|
|
/**
|
|
* @return void
|
|
*/
|
|
public static function setUpBeforeClass(): void {
|
|
self::loadPluginSource('includes/functions.php');
|
|
|
|
// Publishes $thold_states, $thold_host_states and $thold_log_states.
|
|
self::loadPluginSourceAlways('includes/arrays.php');
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function test_thold_legend_renders_one_chip_per_threshold_state(): void {
|
|
ob_start();
|
|
thold_legend();
|
|
$output = ob_get_clean();
|
|
|
|
$states = $GLOBALS['thold_states'];
|
|
|
|
$expected = 0;
|
|
foreach ($states as $state) {
|
|
$expected = max($expected, mb_strlen($state['display']));
|
|
}
|
|
|
|
$this->assertStringContainsString('<div class="tholdLegend" style="--thold-chip-min: calc(' . $expected . 'ch + 1.5rem)">', $output);
|
|
$this->assertSame(count($states), substr_count($output, 'tholdLegendItem'));
|
|
|
|
foreach ($states as $state) {
|
|
$this->assertStringContainsString('<div class="tholdLegendItem ' . $state['class'] . '">' . $state['display'] . '</div>', $output);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function test_host_legend_renders_one_chip_per_device_state(): void {
|
|
ob_start();
|
|
host_legend();
|
|
$output = ob_get_clean();
|
|
|
|
$states = $GLOBALS['thold_host_states'];
|
|
|
|
$expected = 0;
|
|
foreach ($states as $state) {
|
|
$expected = max($expected, mb_strlen($state['display']));
|
|
}
|
|
|
|
$this->assertStringContainsString('<div class="tholdLegend" style="--thold-chip-min: calc(' . $expected . 'ch + 1.5rem)">', $output);
|
|
$this->assertSame(count($states), substr_count($output, 'tholdLegendItem'));
|
|
|
|
foreach ($states as $state) {
|
|
$this->assertStringContainsString('<div class="tholdLegendItem ' . $state['class'] . '">' . $state['display'] . '</div>', $output);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function test_log_legend_renders_one_chip_per_log_state_using_short_labels(): void {
|
|
ob_start();
|
|
log_legend();
|
|
$output = ob_get_clean();
|
|
|
|
$states = $GLOBALS['thold_log_states'];
|
|
|
|
$expected = 0;
|
|
foreach ($states as $state) {
|
|
$expected = max($expected, mb_strlen($state['display_short']));
|
|
}
|
|
|
|
$this->assertStringContainsString('<div class="tholdLegend" style="--thold-chip-min: calc(' . $expected . 'ch + 1.5rem)">', $output);
|
|
$this->assertSame(count($states), substr_count($output, 'tholdLegendItem'));
|
|
|
|
foreach ($states as $state) {
|
|
$this->assertStringContainsString('<div class="tholdLegendItem ' . $state['class'] . '">' . $state['display_short'] . '</div>', $output);
|
|
}
|
|
}
|
|
}
|