feat(dashboardapi): recursive subtree discovery + measurement-name/template parity
Generate dashboards for an entire parent-child subtree from a single root
registration (pre-order, cycle/diamond-safe), so wiring only the subtree root
(e.g. pumpingStation) to dashboardAPI yields dashboards for every descendant.
Fix two contract drifts that left generated panels blank against live telemetry:
- _measurement var now mirrors outputUtils.formatMsg (general.name ||
<softwareType>_<id>); previously it always used the fallback form, so any
named node's dashboard queried a non-existent series.
- pumpingStation template field keys realigned to emitted telemetry
(flow.*.{upstream,out,overflow}, netFlowRate.measured, inflowLevel/
outflowLevel/overflowLevel, maxVolAtOverflow/minVolAt{Inflow,Outflow}).
Adds template alias resolution (softwareType -> shared template file) and
locks parity with slice44/45/46 tests + output manifest. 67/67 pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
50
test/basic/slice45-template-aliases.basic.test.js
Normal file
50
test/basic/slice45-template-aliases.basic.test.js
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const DashboardApi = require('../../src/specificClass.js');
|
||||
|
||||
// softwareType (as reported at runtime, lowercased) -> the template that must resolve.
|
||||
const CASES = [
|
||||
['rotatingmachine', 'machine.json'],
|
||||
['machinegroupcontrol', 'machineGroup.json'],
|
||||
['pumpingstation', 'pumpingStation.json'],
|
||||
['valvegroupcontrol', 'valveGroupControl.json'],
|
||||
['diffuser', 'aeration.json'],
|
||||
['measurement', 'measurement.json'],
|
||||
['reactor', 'reactor.json'],
|
||||
['settler', 'settler.json'],
|
||||
['valve', 'valve.json'],
|
||||
['monster', 'monster.json'],
|
||||
];
|
||||
|
||||
for (const [softwareType, file] of CASES) {
|
||||
test(`softwareType '${softwareType}' resolves to ${file}`, () => {
|
||||
const api = new DashboardApi({});
|
||||
const resolved = api._templateFileForSoftwareType(softwareType);
|
||||
assert.ok(resolved, `expected a template path for ${softwareType}`);
|
||||
assert.ok(resolved.endsWith(file), `expected ${file}, got ${resolved}`);
|
||||
});
|
||||
}
|
||||
|
||||
test('resolution is case-insensitive (camelCase softwareType still resolves)', () => {
|
||||
const api = new DashboardApi({});
|
||||
assert.ok(api._templateFileForSoftwareType('rotatingMachine').endsWith('machine.json'));
|
||||
assert.ok(api._templateFileForSoftwareType('machineGroupControl').endsWith('machineGroup.json'));
|
||||
});
|
||||
|
||||
test('rotatingmachine now builds a dashboard (was: no template found)', () => {
|
||||
const api = new DashboardApi({});
|
||||
const built = api.buildDashboard({
|
||||
nodeConfig: { general: { id: 'rm-1', name: 'Pump A' }, functionality: { softwareType: 'rotatingmachine' } },
|
||||
positionVsParent: 'downstream',
|
||||
});
|
||||
assert.ok(built, 'expected a built dashboard, not null');
|
||||
assert.equal(built.softwareType, 'rotatingmachine');
|
||||
});
|
||||
|
||||
test('unknown softwareType still returns null (no template)', () => {
|
||||
const api = new DashboardApi({});
|
||||
assert.equal(api._templateFileForSoftwareType('totally-unknown-type'), null);
|
||||
});
|
||||
Reference in New Issue
Block a user