Integrate reviewed truthful TrueNAS setup acceptance help

Retain both exact specialist commits and their rendered-help evidence. Existing documentation and verification only; no runtime, dependency or product-surface expansion. Full frontend suites/build remain unverified after two guest-readiness failures; rendered Chromium/WebKit and focused static evidence are proportionate to this diff.

Contract-Neutral: Existing help and verification only; no runtime contract changes.
Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-10-04 04:18:11 +01:00
5 changed files with 138 additions and 20 deletions
+19 -10
View File
@@ -9,8 +9,13 @@ Pulse v6 includes first-class monitoring for **TrueNAS SCALE** and **TrueNAS COR
are listed under **Platform connections**.
3. Enter the TrueNAS URL (e.g., `https://truenas.local`), the API key, and the
username that owns the key.
4. Click **Test Connection** → **Save**.
5. Data appears within one configured polling cycle (60 seconds by default).
4. Click **Test Connection**, then **Save**. The test reads system information
on a separate connection; it does not validate inventory or metric collection.
5. Leave the saved connection enabled and allow at least one configured polling
interval (60 seconds by default). Check that the appliance and expected
inventory appear. If they do not, follow the [polling checks](#stale-truenas-data)
without repeatedly testing or restarting; an elapsed interval is not proof
that a poll completed.
## Creating a TrueNAS API Key
@@ -155,9 +160,11 @@ its trusted HTTPS origin without disabling certificate verification.
### No data appearing after adding connection
- Allow one configured polling cycle (60 seconds by default), not a fixed
30-second wait. Check that the saved connection is enabled.
- **Test Connection** checks authentication and the selected transport, not
successful collection of every metric. The legacy REST diagnostic is
expected for recognized CORE 13 systems; it is not itself a connection error.
- **Test Connection** reads system information on a separate connection. Pools,
datasets, disks and alerts can still fail during ordinary polling, even when
the test succeeds. A successful test also does not establish live CPU, memory
or History readings. The legacy REST diagnostic is expected for recognized
CORE 13 systems; it is not itself a connection error.
- Inspect a bounded local log excerpt for TrueNAS-related errors:
```bash
journalctl -u pulse -n 100 --no-pager | grep -i truenas
@@ -236,11 +243,13 @@ collection step.
| No timestamps advance, or no completed attempt is recorded | Check that the connection and integration are enabled, then preserve the bounded local error above. This is not proof of an invalid key. |
| Reconnects or TrueNAS sign-ins increase while `observed.collectedAt` advances | Session turnover alone does not establish failed authentication or stopped polling. Record the timing and any existing close/error message separately from the data freshness. |
**Test Connection** checks connectivity and authentication, not a complete
poll. Testing a saved connection can update `lastAttemptAt` and `lastSuccessAt`
and reset its failure count without refreshing `observed.collectedAt`. Record
any manual test and its time separately; a successful test is not evidence
that missing data or stopped polling has recovered.
**Test Connection** is not a complete poll. Some older builds, including Pulse
6.4.1 and 6.4.5, also let a saved-connection test update `lastAttemptAt` and
`lastSuccessAt` and reset its failure count without refreshing
`observed.collectedAt`. Record any manual test and its time separately, and
use the inventory observation time rather than the test time to check freshness.
A successful test is not evidence that missing data or stopped polling has
recovered.
An `app.stats` error such as **Apps are not available** concerns Apps
collection, not necessarily the key. Check the existing Apps status in
@@ -22,6 +22,7 @@ const targets: Record<string, string> = {
malformed: '/docs/API#%invalid',
missing: '/docs/API#does-not-exist',
troubleshooting: '/docs/TROUBLESHOOTING#recovery-mode',
truenas: '/docs/TRUENAS',
};
window.history.replaceState({}, '', targets[scenario] ?? targets.plain);
@@ -0,0 +1,81 @@
// The real Docs page/router/styles and shipped TrueNAS help, without a backend.
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { chromium, webkit } = require('playwright');
(async () => {
const root = '/workspace/frontend-modern';
const artifacts = path.join(root, 'node_modules', 'truenas-connection-help-browser');
fs.mkdirSync(artifacts, { recursive: true });
const { createServer } = await import(path.join(root, 'node_modules/vite/dist/node/index.js'));
const server = await createServer({
root,
configFile: path.join(root, 'vite.config.ts'),
cacheDir: path.join(root, 'node_modules', '.vite-truenas-connection-help'),
server: { host: '127.0.0.1', port: 5250, strictPort: true },
optimizeDeps: { noDiscovery: true, include: [] },
});
const results = [];
let browser;
try {
await server.listen();
for (const [engine, width] of [['chromium', 1280], ['webkit', 390]]) {
browser = await { chromium, webkit }[engine].launch(engine === 'chromium'
? { headless: true, channel: 'chromium', args: ['--no-sandbox'] }
: { headless: true });
const page = await browser.newPage({ viewport: { width, height: 900 },
...(engine === 'webkit' ? { isMobile: true, hasTouch: true } : {}) });
const errors = [];
page.on('pageerror', (error) => errors.push(error.message));
page.on('console', (message) => {
if (message.type() === 'error') errors.push(message.text());
});
await page.goto('http://127.0.0.1:5250/browser-tests/docs-fragment-navigation.html?scenario=truenas',
{ waitUntil: 'domcontentloaded', timeout: 60_000 });
const quickStart = page.getByRole('heading', { name: 'Quick Start', exact: true });
await quickStart.waitFor();
if (engine === 'webkit') {
await page.evaluate(async () => {
document.documentElement.classList.add('dark');
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
await Promise.all(document.getAnimations().map((animation) => animation.finished.catch(() => {})));
});
}
const article = await page.locator('article').innerText();
for (const text of ['it does not validate inventory or metric collection',
'an elapsed interval is not proof that a poll completed',
'Some older builds, including Pulse 6.4.1 and 6.4.5',
'use the inventory observation time rather than the test time',
'do not copy a token or cookie', 'Do not post the full connection response'])
assert.ok(article.includes(text), text);
assert.ok(!article.includes('Data appears within one configured polling cycle'));
await quickStart.evaluate((heading) => heading.scrollIntoView({ block: 'start' }));
await page.screenshot({ path: path.join(artifacts, `${engine}-setup.png`) });
const checks = page.getByRole('link', { name: 'polling checks', exact: true }).first();
await checks.focus();
await page.keyboard.press('Enter');
await page.waitForFunction(() => {
const heading = document.getElementById('stale-truenas-data');
return heading && heading.getBoundingClientRect().top >= 0
&& heading.getBoundingClientRect().top < innerHeight;
});
assert.ok(page.url().endsWith('/docs/TRUENAS#stale-truenas-data'));
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1));
await page.screenshot({ path: path.join(artifacts, `${engine}-polling.png`) });
assert.deepEqual(errors, []);
results.push({ engine, version: browser.version(), width,
probeScope: true, noGuaranteedPoll: true, versionQualifiedWarning: true,
keyboardPollingLink: true, noDocumentOverflow: true, errors });
await browser.close();
browser = undefined;
}
const result = { result: 'passed', playwright: require('playwright/package.json').version,
scope: 'shipped help rendering/navigation, not native TrueNAS polling', results };
fs.writeFileSync(path.join(artifacts, 'result.json'), JSON.stringify(result, null, 2) + '\n');
console.log(JSON.stringify(result));
} finally {
if (browser) await browser.close();
await server.close();
}
})().catch((error) => { console.error(error); process.exitCode = 1; });
+19 -10
View File
@@ -9,8 +9,13 @@ Pulse v6 includes first-class monitoring for **TrueNAS SCALE** and **TrueNAS COR
are listed under **Platform connections**.
3. Enter the TrueNAS URL (e.g., `https://truenas.local`), the API key, and the
username that owns the key.
4. Click **Test Connection** → **Save**.
5. Data appears within one configured polling cycle (60 seconds by default).
4. Click **Test Connection**, then **Save**. The test reads system information
on a separate connection; it does not validate inventory or metric collection.
5. Leave the saved connection enabled and allow at least one configured polling
interval (60 seconds by default). Check that the appliance and expected
inventory appear. If they do not, follow the [polling checks](#stale-truenas-data)
without repeatedly testing or restarting; an elapsed interval is not proof
that a poll completed.
## Creating a TrueNAS API Key
@@ -155,9 +160,11 @@ its trusted HTTPS origin without disabling certificate verification.
### No data appearing after adding connection
- Allow one configured polling cycle (60 seconds by default), not a fixed
30-second wait. Check that the saved connection is enabled.
- **Test Connection** checks authentication and the selected transport, not
successful collection of every metric. The legacy REST diagnostic is
expected for recognized CORE 13 systems; it is not itself a connection error.
- **Test Connection** reads system information on a separate connection. Pools,
datasets, disks and alerts can still fail during ordinary polling, even when
the test succeeds. A successful test also does not establish live CPU, memory
or History readings. The legacy REST diagnostic is expected for recognized
CORE 13 systems; it is not itself a connection error.
- Inspect a bounded local log excerpt for TrueNAS-related errors:
```bash
journalctl -u pulse -n 100 --no-pager | grep -i truenas
@@ -236,11 +243,13 @@ collection step.
| No timestamps advance, or no completed attempt is recorded | Check that the connection and integration are enabled, then preserve the bounded local error above. This is not proof of an invalid key. |
| Reconnects or TrueNAS sign-ins increase while `observed.collectedAt` advances | Session turnover alone does not establish failed authentication or stopped polling. Record the timing and any existing close/error message separately from the data freshness. |
**Test Connection** checks connectivity and authentication, not a complete
poll. Testing a saved connection can update `lastAttemptAt` and `lastSuccessAt`
and reset its failure count without refreshing `observed.collectedAt`. Record
any manual test and its time separately; a successful test is not evidence
that missing data or stopped polling has recovered.
**Test Connection** is not a complete poll. Some older builds, including Pulse
6.4.1 and 6.4.5, also let a saved-connection test update `lastAttemptAt` and
`lastSuccessAt` and reset its failure count without refreshing
`observed.collectedAt`. Record any manual test and its time separately, and
use the inventory observation time rather than the test time to check freshness.
A successful test is not evidence that missing data or stopped polling has
recovered.
An `app.stats` error such as **Apps are not available** concerns Apps
collection, not necessarily the key. Check the existing Apps status in
@@ -61,6 +61,24 @@ function getRuntimeSourceFiles(dir: string): string[] {
}
describe('docsLinks', () => {
it('keeps TrueNAS setup acceptance separate from a system-information probe', () => {
const truenas = readFileSync(path.join(repoRoot, 'docs', 'TRUENAS.md'), 'utf8');
const setup = truenas.split('## Quick Start')[1].split('## Creating a TrueNAS API Key')[0];
expect(setup).toContain('it does not validate inventory or metric collection');
expect(setup).toContain('an elapsed interval is not proof');
expect(setup).toContain('[polling checks](#stale-truenas-data)');
expect(setup).not.toContain('Data appears within one configured polling cycle');
const noData = truenas
.split('### No data appearing after adding connection')[1]
.split('### Inventory works')[0];
expect(noData).toContain('Pools,\n datasets, disks and alerts can still fail');
expect(noData).toContain('does not establish live CPU, memory');
expect(truenas).toContain('Some older builds, including Pulse\n6.4.1 and 6.4.5');
expect(truenas).toContain('use the inventory observation time rather than the test time');
expect(truenas).toContain('do not copy a token or cookie');
expect(truenas).toContain('Do not post the full connection response');
});
it('keeps restored Proxmox node network details in the candidate packet', () => {
const releaseNotes = readFileSync(
path.join(repoRoot, 'docs', 'releases', 'RELEASE_NOTES_v6.4.0-rc.1.md'),