When generateDashboardsForGraph builds a root dashboard for a parent (e.g. pumpingStation) and a set of child dashboards (e.g. measurements), it now removes any non-row panel from the root whose meta.emittedFields are fully covered by panels declared in any child dashboard. Result: the parent shows only metrics its children don't already plot, eliminating redundant rendering of the same series in two dashboards. - config/pumpingStation.json: 11 non-row panels annotated with meta.emittedFields (Direction, Time Left, Flow Source, Fill %, Level (x2), Volume, Net Flow Rate, Inflow+Outflow, Heights, Volume Limits). - src/specificClass.js: generateDashboardsForGraph runs the parent-panel filter after composing children; row panels always kept; panels without emittedFields declaration always kept (no silent removal). - test/basic/slice39-no-duplication.basic.test.js: 4 cases — annotation presence, child-covered removal, no-overlap preservation, row preservation. Closes #39
103 lines
3.9 KiB
JavaScript
103 lines
3.9 KiB
JavaScript
'use strict';
|
|
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
|
|
const DashboardApi = require('../../src/specificClass.js');
|
|
|
|
function makeChild(id, softwareType) {
|
|
return {
|
|
config: {
|
|
general: { id, name: id },
|
|
functionality: { softwareType, positionVsParent: 'downstream' },
|
|
},
|
|
};
|
|
}
|
|
|
|
function makeRoot(softwareType, children) {
|
|
const map = new Map();
|
|
for (const c of children) {
|
|
map.set(c.config.general.id, {
|
|
child: c,
|
|
softwareType: c.config.functionality.softwareType,
|
|
position: 'downstream',
|
|
});
|
|
}
|
|
return {
|
|
config: {
|
|
general: { id: 'root-1', name: 'PS-North' },
|
|
functionality: { softwareType, positionVsParent: 'atequipment' },
|
|
},
|
|
childRegistrationUtils: { registeredChildren: map },
|
|
};
|
|
}
|
|
|
|
test('pumpingStation template has emittedFields on every non-row panel', () => {
|
|
const api = new DashboardApi({});
|
|
const dash = api.loadTemplate('pumpingStation');
|
|
const annotated = dash.panels.filter((p) => p.type !== 'row' && p?.meta?.emittedFields);
|
|
const nonRowPanels = dash.panels.filter((p) => p.type !== 'row');
|
|
assert.equal(annotated.length, nonRowPanels.length,
|
|
`expected all ${nonRowPanels.length} non-row panels annotated, got ${annotated.length}`);
|
|
});
|
|
|
|
test('child-covered fields remove duplicate parent panels', () => {
|
|
const api = new DashboardApi({});
|
|
|
|
// Parent + 1 child with a fake template that emits 'level' (matches one of
|
|
// the pumpingStation parent's panels). The parent's "Level" panel should
|
|
// be removed when the child covers it.
|
|
const child1 = makeChild('child-1', 'measurement');
|
|
const root = makeRoot('pumpingStation', [child1]);
|
|
|
|
// Pre-count parent panels with the 'level' emitted field.
|
|
const parentTemplate = api.loadTemplate('pumpingStation');
|
|
const parentLevelPanels = parentTemplate.panels.filter(
|
|
(p) => p?.meta?.emittedFields?.includes('level')
|
|
);
|
|
assert.ok(parentLevelPanels.length > 0, 'parent has level panels in template');
|
|
|
|
// Monkey-patch the child's dashboard to claim it covers 'level'.
|
|
const origLoad = api.loadTemplate.bind(api);
|
|
api.loadTemplate = function (type) {
|
|
const dash = origLoad(type);
|
|
if (type === 'measurement' && dash) {
|
|
// Inject emittedFields = ['level'] on first non-row panel.
|
|
const firstPanel = dash.panels.find((p) => p.type !== 'row');
|
|
if (firstPanel) (firstPanel.meta ||= {}).emittedFields = ['level'];
|
|
}
|
|
return dash;
|
|
};
|
|
|
|
const result = api.generateDashboardsForGraph(root);
|
|
const rootResult = result[0];
|
|
const rootLevelPanels = rootResult.dashboard.panels.filter(
|
|
(p) => p?.meta?.emittedFields?.includes('level')
|
|
);
|
|
assert.equal(rootLevelPanels.length, 0,
|
|
'level panel(s) should be removed from parent when child covers them');
|
|
});
|
|
|
|
test('parent panels are kept when no child covers their fields', () => {
|
|
const api = new DashboardApi({});
|
|
const child1 = makeChild('child-1', 'measurement'); // measurement.json has no emittedFields
|
|
const root = makeRoot('pumpingStation', [child1]);
|
|
const result = api.generateDashboardsForGraph(root);
|
|
const rootResult = result[0];
|
|
const beforeTemplate = api.loadTemplate('pumpingStation');
|
|
const beforeNonRow = beforeTemplate.panels.filter((p) => p.type !== 'row').length;
|
|
const afterNonRow = rootResult.dashboard.panels.filter((p) => p.type !== 'row').length;
|
|
assert.equal(afterNonRow, beforeNonRow,
|
|
'no panels should be removed when no child declares overlapping fields');
|
|
});
|
|
|
|
test('row panels are never removed (structural)', () => {
|
|
const api = new DashboardApi({});
|
|
const child1 = makeChild('child-1', 'measurement');
|
|
const root = makeRoot('pumpingStation', [child1]);
|
|
const result = api.generateDashboardsForGraph(root);
|
|
const rootRows = result[0].dashboard.panels.filter((p) => p.type === 'row');
|
|
const templateRows = api.loadTemplate('pumpingStation').panels.filter((p) => p.type === 'row');
|
|
assert.equal(rootRows.length, templateRows.length, 'all row panels preserved');
|
|
});
|