Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

--- develop ---

* issue#444: Brighten Dark theme red row markers while preserving panel header colors
* issue#442: Keep Carrot theme status indicators legible on coral details titlebars and light table rows
* issue#440: Give Cacti theme severity indicators contrasting colors for dark details titlebars and light table rows
* issue: Fix the dashboard page not scrolling with the mouse wheel over chart panels: charts were sized from the whole card (header included) and overflowed the card body, turning it into a nested scroller that captured the wheel; charts now keep their server-sized height (which also stops pie/treemap charts growing on every window resize) and card bodies no longer scroll vertically
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ The Carrot fixture checks status markers on light rows and a contrasting
details badge that works with existing coral titlebars. See
[Carrot theme validation](docs/carrot-theme.md) for screenshots and tests.

![Dark theme dashboard with seeded measurements and alerts](images/dark-theme-dashboard.png)

The Dark fixture includes a visible red row marker for the failed device.
See [Dark theme validation](docs/dark-theme.md) for screenshots and tests.

## Requirements

- Cacti 1.2.17 or later (the `compat` value in the `INFO` file). The plugin is
Expand Down
5 changes: 5 additions & 0 deletions css/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,8 @@
.color_grey, .color_grey i {
color: black !important;
}

/* Row alerts need a brighter red than the header's white-text surface. */
.inpa_sq.color_red {
background: #ff6b6b !important;
}
44 changes: 44 additions & 0 deletions docs/dark-theme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Dark theme validation

Dark's red row marker uses a brighter red against dark table rows. The panel
header retains its darker red background and white text. Existing details
status dots remain unchanged.

## Seeded browser E2E fixture

The screenshots render the actual plugin and core Dark stylesheets with
synthetic devices, ping times, poller totals, and warning/error messages.
They do not show a live Cacti installation or production monitoring data.

![Dark dashboard with populated response times and alert panels](../images/dark-theme-dashboard.png)

The E2E test opens and closes the real jQuery UI details dialog and checks
that its alert data is visible.

![Dark details dialog with synthetic warning and error messages](../images/dark-theme-status.png)

## Reproduce

Use the setup in [Cacti theme validation](cacti-theme.md). With `CACTI_ROOT`
pointing to the adjacent core checkout, run from the plugin root:

```sh
NODE_PATH="$CACTI_ROOT/tests/e2e/node_modules" mise exec node@22 -- node \
"$CACTI_ROOT/tests/e2e/node_modules/@playwright/test/cli.js" test \
--config tests/e2e/playwright.config.cjs
```

Set `UPDATE_THEME_SCREENSHOTS=1` to regenerate the screenshots. The suite
checks all four status colors on odd, even, and page surfaces and includes
linear-gradient endpoints in its contrast calculation.

After committing, measure the changed CSS lines:

```sh
mise exec python@3.12 -- python "$CACTI_ROOT/tests/tools/report_changed_coverage.py" \
--base fix/carrot-theme-status-contrast --language css --minimum 100 \
--browser-root tests/e2e/test-results
```

Use `origin/develop` after the parent branch merges. This measures changed CSS
coverage, not whole-plugin coverage or testing against a live installation.
Binary file added images/dark-theme-dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/dark-theme-status.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 16 additions & 7 deletions tests/e2e/cacti-theme.spec.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ async function installCss(page, file) {
await page.addStyleTag({ url: 'http://cacti-theme.test/' + path });
}

for (const theme of ['cacti', 'carrot']) {
for (const theme of ['cacti', 'carrot', 'dark']) {
test(`${theme} seeded dashboard displays measurements and opens alert details`, async ({ page }, info) => {
await page.setViewportSize({ width: 1140, height: 520 });
await page.setContent(readFileSync(resolve(root, 'tests/fixtures/Ui/cacti-theme.html'), 'utf8').replaceAll('Cacti theme', `${theme === 'carrot' ? 'Carrot' : 'Cacti'} theme`));
await page.setContent(readFileSync(resolve(root, 'tests/fixtures/Ui/cacti-theme.html'), 'utf8').replaceAll('Cacti theme', `${theme[0].toUpperCase() + theme.slice(1)} theme`));
for (const file of [resolve(core, `include/themes/${theme}/jquery-ui.css`), resolve(core, `include/themes/${theme}/main.css`), resolve(core, 'include/fa/css/all.css'), resolve(root, 'includes/cards/cards.css'), resolve(root, 'css/common.css'), resolve(root, `css/${theme}.css`)]) {
await installCss(page, file);
}
Expand Down Expand Up @@ -65,7 +65,7 @@ test.afterEach(async ({ page }, info) => {
writeFileSync(info.outputPath('changed-coverage.json'), JSON.stringify(coverage));
});

for (const theme of ['cacti', 'carrot']) {
for (const theme of ['cacti', 'carrot', 'dark']) {
for (const row of ['odd', 'even', '']) {
test(`${theme} severity indicators contrast with titlebars and ${row || 'white'} rows`, async ({ page }) => {
await page.setContent('<!DOCTYPE html><div id="overlay_detail">' + ['green', 'red', 'yellow', 'grey'].map(color =>
Expand All @@ -85,17 +85,26 @@ for (const theme of ['cacti', 'carrot']) {
v /= 255;
return v <= .04045 ? v / 12.92 : ((v + .055) / 1.055) ** 2.4;
}).reduce((sum, v, i) => sum + v * [.2126, .7152, .0722][i], 0);
const over = (fg, bg) => bg.map((v, i) => fg[i] * fg[3] + v * (1 - fg[3]));
return elements.map(element => {
const square = element.id.startsWith('square-');
let bg = [255, 255, 255];
let surfaces = [[255, 255, 255]];
const ancestors = [];
for (let e = square ? element.parentElement : element; e; e = e.parentElement) ancestors.unshift(e);
for (const e of ancestors) {
const c = rgba(getComputedStyle(e).backgroundColor);
bg = bg.map((v, i) => c[i] * c[3] + v * (1 - c[3]));
surfaces = surfaces.map(bg => over(c, bg));
const image = getComputedStyle(e).backgroundImage;
if (image.startsWith('linear-gradient(')) {
const stops = (image.match(/rgba?\([^)]+\)/g) || []).map(rgba);
surfaces = surfaces.flatMap(bg => stops.map(stop => over(stop, bg)));
}
}
const style = getComputedStyle(element), foreground = lum(rgba(square ? style.backgroundColor : style.color)), surface = lum(bg);
return { id: element.id, ratio: (Math.max(foreground, surface) + .05) / (Math.min(foreground, surface) + .05) };
const style = getComputedStyle(element), color = rgba(square ? style.backgroundColor : style.color);
return { id: element.id, ratio: Math.min(...surfaces.map(bg => {
const foreground = lum(over(color, bg)), surface = lum(bg);
return (Math.max(foreground, surface) + .05) / (Math.min(foreground, surface) + .05);
})) };
});
});
expect(indicators).toHaveLength(8);
Expand Down
Loading