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
25 changes: 25 additions & 0 deletions .github/workflows/plugin-ci-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -335,3 +335,28 @@ jobs:
fi
fi
fi

result-theme-browser:
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1
with:
node-version: '22'
- name: Install existing browser tooling
working-directory: tests/E2E/playwright
run: |
npm ci --ignore-scripts
npx --no-install playwright install --with-deps chromium
- name: Check result foregrounds across theme row states
env:
THEME_TEST_OUTPUT: ${{ runner.temp }}/syslog-theme-contrast
run: node tests/E2E/playwright/theme-contrast-check.cjs
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
if: always()
with:
name: result-theme-browser
path: ${{ runner.temp }}/syslog-theme-contrast
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ composer.lock
phpstan.neon
phpstan-baseline.neon
phpstan-stubs.php
/tests/E2E/playwright/artifacts/
graphify-out/**
locales/po/*.po
locales/LC_MESSAGES/*.mo
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -553,3 +553,10 @@ nesting levels. Invalid searches return no results and CSV export rejects them.
Copyright (c) 2004-2026 - The Cacti Group, Inc.

Optional [Alarm Manager forwarding](docs/ALARM_MANAGER.md) uses Cacti native in-process hooks with existing Syslog email as fallback.

## Result theme regression fixture

![Synthetic Syslog interface alerts on a dark result surface](docs/images/result-theme-dark.png)

See [result theme tests](docs/RESULT_THEME_TESTS.md) for the populated light
fixture and browser reproduction command.
24 changes: 21 additions & 3 deletions css/search.css
Original file line number Diff line number Diff line change
Expand Up @@ -601,9 +601,9 @@
#syslog_workspace table { width: 100%; }
/* Severity row tints: a translucent hue per priority mixed over the live theme
surface, so the same rules read correctly on both light and dark themes. */
#syslog_workspace tr.syslogRow { --syslog-sev: transparent; background: color-mix(in srgb, var(--syslog-sev) 16%, transparent); }
#syslog_workspace tr.syslogRow:nth-child(even) { background: color-mix(in srgb, var(--syslog-sev) 22%, color-mix(in srgb, currentColor 5%, transparent)); }
#syslog_workspace tr.syslogRow:hover { background: color-mix(in srgb, var(--syslog-sev) 32%, color-mix(in srgb, currentColor 9%, transparent)); }
#syslog_workspace tr.syslogRow { --syslog-sev: transparent; color: var(--search-text); background: color-mix(in srgb, var(--syslog-sev) 16%, var(--search-card)); }
#syslog_workspace tr.syslogRow:nth-child(even) { background: color-mix(in srgb, var(--syslog-sev) 22%, var(--search-card)); }
#syslog_workspace tr.syslogRow:hover { background: color-mix(in srgb, var(--syslog-sev) 20%, var(--search-card)); }
#syslog_workspace tr.syslogRow td:first-child { border-left: 4px solid transparent; }
#syslog_workspace tr.syslogRow.logEmergency { --syslog-sev: #e5484d; }
#syslog_workspace tr.syslogRow.logAlert { --syslog-sev: #e5533b; }
Expand Down Expand Up @@ -1125,3 +1125,21 @@
width: 100%;
margin: 8px auto 0;
}

#syslog_workspace tr.syslogRow a,
#syslog_workspace tr.syslogRow a:hover {
color: var(--search-text) !important;
}
#syslog_workspace tr.syslogRow .syslogSeverity,
#syslog_workspace tr.syslogRow .syslogSeverity:hover {
color: var(--search-text);
background: var(--search-card);
}

/* Some host themes force their selected foreground and background. */
#syslog_workspace tr.syslogRow.selected {
color: var(--search-text) !important;
background: var(--search-card) !important;
outline: 1px solid var(--search-text);
outline-offset: -1px;
}
27 changes: 27 additions & 0 deletions docs/RESULT_THEME_TESTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Result theme regression checks

Result rows, links, and severity buttons use the foreground and card surface
sampled from the active Cacti theme. This keeps host selection colors from
replacing the foreground on a plugin-owned severity surface.

![Dark result fixture with synthetic interface alerts](images/result-theme-dark.png)

![Light result fixture with synthetic interface alerts](images/result-theme-light.png)

The screenshots contain two synthetic devices and interface-down messages.
They are browser component fixtures, not a running poller or database session.

Run with the existing Playwright dependency installed:

```sh
node tests/E2E/playwright/theme-contrast-check.cjs
```

Set `CHROMIUM_EXECUTABLE` to use an existing Chromium installation and
`THEME_TEST_OUTPUT` to choose the artifact directory (default
`tests/E2E/playwright/artifacts/theme-contrast`). The test checks light, dark, and muted dark palettes in resting,
hovered, selected, and selected-hovered rows. It also writes Chromium CSS
coverage to `changed-coverage.json`.

The Cacti theme compatibility suite additionally loads this plugin's real CSS
and theme-token JavaScript against all twelve host theme variants.
Binary file added docs/images/result-theme-dark.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 docs/images/result-theme-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions tests/E2E/playwright/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions tests/E2E/playwright/theme-contrast-check.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* Copyright (C) 2004-2026 The Cacti Group. GPL-2.0-or-later. */
const assert = require('node:assert/strict');
const { readFileSync, mkdirSync, writeFileSync } = require('node:fs');
const { resolve } = require('node:path');
const { chromium } = require('playwright');

(async () => {
const root = resolve(__dirname, '../../..');
const output = resolve(process.env.THEME_TEST_OUTPUT || resolve(__dirname, 'artifacts/theme-contrast'));
mkdirSync(output, { recursive: true });
const browser = await chromium.launch({ executablePath: process.env.CHROMIUM_EXECUTABLE || undefined });
const page = await browser.newPage();
await page.route('http://syslog-fixture.test/css/search.css', route => route.fulfill({ contentType: 'text/css', body: readFileSync(resolve(root, 'css/search.css'), 'utf8') }));
await page.coverage.startCSSCoverage({ resetOnNavigation: false });
try {
for (const [mode, foreground, surface] of [['light', 'rgb(35, 54, 47)', 'rgb(255, 255, 255)'], ['dark', 'rgb(238, 238, 238)', 'rgb(32, 32, 32)'], ['muted-dark', 'rgb(150, 155, 163)', 'rgb(0, 0, 0)']]) {
await page.setContent(`<!DOCTYPE html><style>
* { transition: none !important; }
body { background: ${surface}; }
tr.selected { color: white !important; background: blue !important; }
tr.selected a, tr.selected a:hover { color: white !important; }
button:hover { color: red; background: yellow; }
</style><div id="syslog_workspace" style="--search-text:${foreground};--search-card:${surface}">
<table><tbody>${[1, 2].map(id => `<tr class="syslogRow logWarning" id="row${id}"><td><a href="#device">edge-rtr-0${id}</a></td><td><button class="syslogSeverity syslogSeverity-warning">Warning</button></td><td>ifDown Gi1/0/24</td></tr>`).join('')}</tbody></table></div>`);
await page.addStyleTag({ url: 'http://syslog-fixture.test/css/search.css' });
for (const state of ['rest', 'hover', 'selected', 'selected-hover']) {
await page.mouse.move(0, 0);
if (state === 'selected') await page.locator('tr').evaluateAll(rows => rows.forEach(row => row.classList.add('selected')));
if (state.includes('hover')) await page.locator('#row1 button').hover();
for (const selector of ['#row1 a', '#row2 a', '#row1 button', '#row2 button']) {
assert.equal(await page.locator(selector).evaluate(element => getComputedStyle(element).color), foreground, `${mode} ${state} ${selector}`);
}
assert.equal(await page.locator('#row1 button').evaluate(element => getComputedStyle(element).backgroundColor), surface);
}
await page.screenshot({ path: resolve(output, `syslog-${mode}.png`), fullPage: true });
}
writeFileSync(resolve(output, 'changed-coverage.json'), JSON.stringify({ css: await page.coverage.stopCSSCoverage(), js: [] }));
console.log('PASS: three palettes of result links and severity buttons in four row states');
} finally {
await browser.close();
}
})().catch(error => { console.error(error); process.exitCode = 1; });
Loading