Skip to content

Commit 1940571

Browse files
feat(wizard/sampledvaluecontrol): allow removing including referenced elements (openscd#536)
1 parent 2b11ae8 commit 1940571

File tree

4 files changed

+210
-1
lines changed

4 files changed

+210
-1
lines changed

src/wizards/sampledvaluecontrol.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ import '../wizard-select.js';
1212
import '../wizard-textfield.js';
1313
import {
1414
cloneElement,
15+
Delete,
1516
EditorAction,
1617
getValue,
1718
identity,
1819
isPublic,
20+
newActionEvent,
1921
newSubWizardEvent,
22+
newWizardEvent,
2023
selector,
2124
Wizard,
2225
WizardActor,
@@ -43,6 +46,52 @@ function getSMV(element: Element): Element | null {
4346
);
4447
}
4548

49+
export function removeSampledValueControlAction(element: Element): Delete[] {
50+
if (!element.parentElement) return [];
51+
52+
const dataSet = element.parentElement!.querySelector(
53+
`DataSet[name="${element.getAttribute('datSet')}"]`
54+
);
55+
const sMV = getSMV(element);
56+
57+
const singleUse =
58+
Array.from(
59+
element.parentElement.querySelectorAll<Element>(
60+
'ReportControl, GSEControl, SampledValueControl'
61+
)
62+
).filter(
63+
controlblock =>
64+
controlblock.getAttribute('datSet') === dataSet?.getAttribute('name')
65+
).length <= 1;
66+
67+
const actions: Delete[] = [];
68+
69+
actions.push({
70+
old: {
71+
parent: element.parentElement!,
72+
element,
73+
},
74+
});
75+
76+
if (dataSet && singleUse)
77+
actions.push({
78+
old: {
79+
parent: element.parentElement!,
80+
element: dataSet,
81+
},
82+
});
83+
84+
if (sMV)
85+
actions.push({
86+
old: {
87+
parent: sMV.parentElement!,
88+
element: sMV,
89+
},
90+
});
91+
92+
return actions;
93+
}
94+
4695
interface ContentOptions {
4796
name: string | null;
4897
desc: string | null;
@@ -208,6 +257,17 @@ export function editSampledValueControlWizard(element: Element): Wizard {
208257
}}}"
209258
></mwc-button>`
210259
: html``,
260+
html`<mwc-button
261+
label="${translate('remove')}"
262+
icon="delete"
263+
@click=${(e: MouseEvent) => {
264+
const deleteActions = removeSampledValueControlAction(element);
265+
deleteActions.forEach(deleteAction =>
266+
e.target?.dispatchEvent(newActionEvent(deleteAction))
267+
);
268+
e.target?.dispatchEvent(newWizardEvent());
269+
}}
270+
></mwc-button>`,
211271
],
212272
},
213273
];

test/integration/wizards/sampledvaluecontrol-wizarding-editing.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,32 @@ describe('Wizards for SCL element SampledValueControl', () => {
238238
?.textContent?.trim()
239239
);
240240
});
241+
242+
it('removes the SampledValueControl element and its referenced elements on remove button click', async () => {
243+
expect(
244+
doc.querySelector(
245+
'IED[name="IED3"] SampledValueControl[name="MSVCB01"]'
246+
)
247+
).to.exist;
248+
expect(doc.querySelector('IED[name="IED3"] DataSet[name="PhsMeas1"]'))
249+
.to.exist;
250+
expect(doc.querySelector('SMV[cbName="MSVCB01"]')).to.exist;
251+
252+
const deleteButton = <Button>(
253+
element.wizardUI.dialog!.querySelector('mwc-button[icon="delete"]')!
254+
);
255+
await deleteButton.updateComplete;
256+
deleteButton.click();
257+
258+
expect(
259+
doc.querySelector(
260+
'IED[name="IED3"] SampledValueControl[name="MSVCB01"]'
261+
)
262+
).to.not.exist;
263+
expect(doc.querySelector('IED[name="IED3"] DataSet[name="PhsMeas1"]'))
264+
.to.not.exist;
265+
expect(doc.querySelector('SMV[cbName="MSVCB01"]')).to.not.exist;
266+
});
241267
});
242268
});
243269
});

test/unit/wizards/__snapshots__/sampledvaluecontrol.test.snap.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ snapshots["Wizards for SCL element SampledValueControl define an edit wizard tha
125125
SignatureAndEncryption
126126
</mwc-list-item>
127127
</wizard-select>
128+
<mwc-button
129+
icon="delete"
130+
label="[remove]"
131+
>
132+
</mwc-button>
128133
</div>
129134
<mwc-button
130135
dialogaction="close"

test/unit/wizards/sampledvaluecontrol.test.ts

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ import { SinonSpy, spy } from 'sinon';
44
import '../../mock-wizard.js';
55
import { MockWizard } from '../../mock-wizard.js';
66

7-
import { isUpdate, Update, WizardInput } from '../../../src/foundation.js';
7+
import {
8+
isDelete,
9+
isUpdate,
10+
Update,
11+
WizardInput,
12+
} from '../../../src/foundation.js';
813
import {
914
editSampledValueControlWizard,
15+
removeSampledValueControlAction,
1016
selectSampledValueControlWizard,
1117
} from '../../../src/wizards/sampledvaluecontrol.js';
1218
import fc, { integer } from 'fast-check';
@@ -265,6 +271,118 @@ describe('Wizards for SCL element SampledValueControl', () => {
265271
'Signature'
266272
);
267273
});
274+
275+
describe('contains a remove button that', () => {
276+
const ln01smv = <Element>new DOMParser().parseFromString(
277+
`<LN0 lnClass="LLN0" lnType="myType">
278+
<DataSet name="myDataSet"/>
279+
<DataSet name="myDataSet2"/>
280+
<SampledValueControl name="myName" datSet="myDataSet"/>
281+
<ReportControl name="myName2" datSet="myDataSet2"/>
282+
</LN0>`,
283+
'application/xml'
284+
).documentElement;
285+
286+
const ln02smv2 = <Element>new DOMParser().parseFromString(
287+
`<LN0 lnClass="LLN0" lnType="myType">
288+
<DataSet name="myDataSet"/>
289+
<SampledValueControl name="myName" datSet="myDataSet"/>
290+
<SampledValueControl name="myName2" datSet="myDataSet"/>
291+
</LN0>`,
292+
'application/xml'
293+
).documentElement;
294+
295+
const ln02gse = <Element>new DOMParser().parseFromString(
296+
`<LN0 lnClass="LLN0" lnType="myType">
297+
<DataSet name="myDataSet"/>
298+
<SampledValueControl name="myName" datSet="myDataSet"/>
299+
<GSEControl name="myName2" datSet="myDataSet"/>
300+
</LN0>`,
301+
'application/xml'
302+
).documentElement;
303+
304+
const ln02rp = <Element>new DOMParser().parseFromString(
305+
`<LN0 lnClass="LLN0" lnType="myType">
306+
<DataSet name="myDataSet"/>
307+
<ReportControl name="myName" datSet="myDataSet"/>
308+
<SampledValueControl name="myName2" datSet="myDataSet"/>
309+
</LN0>`,
310+
'application/xml'
311+
).documentElement;
312+
313+
const missingparent = <Element>(
314+
new DOMParser().parseFromString(
315+
`<SampledValueControl name="myName" datSet="myDataSet"/>`,
316+
'application/xml'
317+
).documentElement
318+
);
319+
320+
it('removes SampledValueControl and its referenced DataSet if no other SampledValueControl is assigned', () => {
321+
const sampledValueControl = ln01smv.querySelector(
322+
'SampledValueControl'
323+
)!;
324+
const actions = removeSampledValueControlAction(sampledValueControl);
325+
expect(actions.length).to.equal(2);
326+
expect(actions[0]).to.satisfy(isDelete);
327+
expect(actions[0].old.element).to.equal(sampledValueControl);
328+
expect(actions[1]).to.satisfy(isDelete);
329+
expect(actions[1].old.element).to.equal(
330+
ln01smv.querySelector('DataSet')
331+
);
332+
});
333+
334+
it('does not remove DataSet with another SampledValueControl referenced', () => {
335+
const sampledValueControl = ln02smv2.querySelector(
336+
'SampledValueControl'
337+
)!;
338+
const actions = removeSampledValueControlAction(sampledValueControl);
339+
expect(actions.length).to.equal(1);
340+
expect(actions[0]).to.satisfy(isDelete);
341+
expect(actions[0].old.element).to.equal(sampledValueControl);
342+
});
343+
344+
it('does not remove DataSet with another GSEControl referenced', () => {
345+
const sampledValueControl = ln02gse.querySelector(
346+
'SampledValueControl'
347+
)!;
348+
const actions = removeSampledValueControlAction(sampledValueControl);
349+
expect(actions.length).to.equal(1);
350+
expect(actions[0]).to.satisfy(isDelete);
351+
expect(actions[0].old.element).to.equal(sampledValueControl);
352+
});
353+
354+
it('does not remove DataSet with another ReportControl referenced', () => {
355+
const sampledValueControl = ln02rp.querySelector(
356+
'SampledValueControl'
357+
)!;
358+
const actions = removeSampledValueControlAction(sampledValueControl);
359+
expect(actions.length).to.equal(1);
360+
expect(actions[0]).to.satisfy(isDelete);
361+
expect(actions[0].old.element).to.equal(sampledValueControl);
362+
});
363+
364+
it('does not remove with missing parent element', () => {
365+
const actions = removeSampledValueControlAction(missingparent);
366+
expect(actions.length).to.equal(0);
367+
});
368+
369+
it('removes referenced SMV element in the Communication section', () => {
370+
const sampledValueControl = doc.querySelector(
371+
'IED[name="IED3"] SampledValueControl'
372+
)!;
373+
const actions = removeSampledValueControlAction(sampledValueControl);
374+
expect(actions.length).to.equal(3);
375+
expect(actions[0]).to.satisfy(isDelete);
376+
expect(actions[0].old.element).to.equal(sampledValueControl);
377+
expect(actions[1]).to.satisfy(isDelete);
378+
expect(actions[2]).to.satisfy(isDelete);
379+
expect(actions[2].old.element).to.equal(
380+
doc.querySelector(
381+
'Communication SMV[ldInst="MU01"][cbName="MSVCB01"]'
382+
)
383+
);
384+
});
385+
});
268386
});
269387

270388
describe('define a select wizard that', () => {

0 commit comments

Comments
 (0)