Skip to content

Commit 10343c6

Browse files
feat(wizards/smvopts): add edit wizard (openscd#547)
* feat(translations): add smvOpts related * feat(wizards/smvopts): add edit wizard * feat(wizards/sampledvaluecontrol): add smvopts button * fix(translation): spelling Co-authored-by: danyill <[email protected]> * fix(translations): spelling Co-authored-by: danyill <[email protected]> Co-authored-by: danyill <[email protected]>
1 parent d557d26 commit 10343c6

File tree

8 files changed

+371
-2
lines changed

8 files changed

+371
-2
lines changed

src/translations/de.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ export const de: Translations = {
4040
smpMod: 'Abtast-Art',
4141
smpRate: 'Abtastrate',
4242
nofASDU: 'Abtastpunkte pro Datenpacket',
43+
SmvOpts: 'Optionale Informationen',
44+
refreshTime: 'Zeitstempel des Abtastwertes zu Telegram hinzufügen',
45+
sampleRate: 'Abtastrate zu Telegram hinzufügen',
46+
dataSet: 'Datensatznamen zu Telegram hinzufügen',
47+
security: 'Potentiel in Zukunft für z.B. digitale Signature',
48+
synchSourceId: 'Identität der Zeitquelle zu Telegram hinzufügen',
4349
},
4450
settings: {
4551
title: 'Einstellungen',
@@ -51,7 +57,7 @@ export const de: Translations = {
5157
selectFileButton: 'Datei auswählen',
5258
loadNsdTranslations: 'NSDoc-Dateien hochladen',
5359
invalidFileNoIdFound: 'Ungültiges NSDoc; kein \'id\'-Attribut in der Datei gefunden',
54-
invalidNsdocVersion: '???'
60+
invalidNsdocVersion: 'Die Version {{ id }} NSD ({{ nsdVersion }}) passt nicht zu der geladenen NSDoc ({{ nsdocVersion }})'
5561
},
5662
menu: {
5763
new: 'Neues projekt',

src/translations/en.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,13 @@ export const en = {
3737
multicast: 'SMV acc. to IEC 61850 9-2',
3838
smpMod: 'Sample mode',
3939
smpRate: 'Sample rate',
40-
nofASDU: 'Samples per paket',
40+
nofASDU: 'Samples per packet',
41+
SmvOpts: 'Optional Information',
42+
refreshTime: 'Add timestamp to SMV packet',
43+
sampleRate: 'Add sample rate to SMV packet',
44+
dataSet: 'Add DataSet name to SMV packet',
45+
security: 'Potential future use. e.g. digital signature',
46+
synchSourceId: 'Add sync source id to SMV packet',
4147
},
4248
settings: {
4349
title: 'Settings',

src/wizards/sampledvaluecontrol.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
import { securityEnableEnum, smpModEnum } from './foundation/enums.js';
2929
import { maxLength, patterns } from './foundation/limits.js';
3030
import { editSMvWizard } from './smv.js';
31+
import { editSmvOptsWizard } from './smvopts.js';
3132

3233
function getSMV(element: Element): Element | null {
3334
const cbName = element.getAttribute('name');
@@ -224,6 +225,7 @@ export function editSampledValueControlWizard(element: Element): Wizard {
224225
const securityEnable = element.getAttribute('securityEnabled');
225226

226227
const sMV = getSMV(element);
228+
const smvOpts = element.querySelector('SmvOpts')!;
227229

228230
return [
229231
{
@@ -257,6 +259,16 @@ export function editSampledValueControlWizard(element: Element): Wizard {
257259
}}}"
258260
></mwc-button>`
259261
: html``,
262+
html`<mwc-button
263+
id="editsmvopts"
264+
label=${translate('scl.SmvOpts')}
265+
icon="edit"
266+
@click="${(e: MouseEvent) => {
267+
e.target?.dispatchEvent(
268+
newSubWizardEvent(() => editSmvOptsWizard(smvOpts))
269+
);
270+
}}}"
271+
></mwc-button>`,
260272
html`<mwc-button
261273
label="${translate('remove')}"
262274
icon="delete"

src/wizards/smvopts.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { html, TemplateResult } from 'lit-element';
2+
import { get, translate } from 'lit-translate';
3+
4+
import {
5+
cloneElement,
6+
getValue,
7+
Wizard,
8+
WizardAction,
9+
WizardActor,
10+
WizardInput,
11+
} from '../foundation.js';
12+
13+
interface ContentOptions {
14+
refreshTime: string | null;
15+
sampleRate: string | null;
16+
dataSet: string | null;
17+
security: string | null;
18+
synchSourceId: string | null;
19+
}
20+
21+
function contentSmvOptsWizard(option: ContentOptions): TemplateResult[] {
22+
return Object.entries(option).map(
23+
([key, value]) =>
24+
html`<wizard-checkbox
25+
label="${key}"
26+
.maybeValue=${value}
27+
nullable
28+
helper="${translate(`scl.${key}`)}"
29+
></wizard-checkbox>`
30+
);
31+
}
32+
33+
function updateSmvOptsAction(element: Element): WizardActor {
34+
return (inputs: WizardInput[]): WizardAction[] => {
35+
const attributes: Record<string, string | null> = {};
36+
const attributeKeys = [
37+
'refreshTime',
38+
'sampleRate',
39+
'dataSet',
40+
'security',
41+
'synchSourceId',
42+
];
43+
attributeKeys.forEach(key => {
44+
attributes[key] = getValue(inputs.find(i => i.label === key)!);
45+
});
46+
47+
if (
48+
!attributeKeys.some(key => attributes[key] !== element.getAttribute(key))
49+
)
50+
return [];
51+
52+
const newElement = cloneElement(element, attributes);
53+
return [{ old: { element }, new: { element: newElement } }];
54+
};
55+
}
56+
57+
export function editSmvOptsWizard(element: Element): Wizard {
58+
const [refreshTime, sampleRate, dataSet, security, synchSourceId] = [
59+
'refreshTime',
60+
'sampleRate',
61+
'dataSet',
62+
'security',
63+
'synchSourceId',
64+
].map(smvopt => element.getAttribute(smvopt));
65+
66+
return [
67+
{
68+
title: get('wizard.title.edit', { tagName: element.tagName }),
69+
element,
70+
primary: {
71+
icon: 'save',
72+
label: get('save'),
73+
action: updateSmvOptsAction(element),
74+
},
75+
content: [
76+
...contentSmvOptsWizard({
77+
refreshTime,
78+
sampleRate,
79+
dataSet,
80+
security,
81+
synchSourceId,
82+
}),
83+
],
84+
},
85+
];
86+
}

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ListItemBase } from '@material/mwc-list/mwc-list-item-base';
99
import { FilteredList } from '../../../src/filtered-list.js';
1010
import { WizardTextField } from '../../../src/wizard-textfield.js';
1111
import { selectSampledValueControlWizard } from '../../../src/wizards/sampledvaluecontrol.js';
12+
import { WizardCheckbox } from '../../../src/wizard-checkbox.js';
1213

1314
describe('Wizards for SCL element SampledValueControl', () => {
1415
let doc: XMLDocument;
@@ -239,6 +240,28 @@ describe('Wizards for SCL element SampledValueControl', () => {
239240
);
240241
});
241242

243+
it('opens a edit wizard for SMV on edit SMV button click', async () => {
244+
const editSmvOptsButton = <Button>(
245+
element.wizardUI.dialog!.querySelector(
246+
'mwc-button[id="editsmvopts"]'
247+
)!
248+
);
249+
expect(editSmvOptsButton).to.exist;
250+
251+
await editSmvOptsButton.updateComplete;
252+
editSmvOptsButton.click();
253+
await new Promise(resolve => setTimeout(resolve, 100)); // await animation
254+
255+
const macField = <WizardCheckbox>(
256+
element.wizardUI.dialog?.querySelector(
257+
'wizard-checkbox[label="refreshTime"]'
258+
)
259+
);
260+
await macField.updateComplete;
261+
262+
expect(macField).to.exist;
263+
});
264+
242265
it('removes the SampledValueControl element and its referenced elements on remove button click', async () => {
243266
expect(
244267
doc.querySelector(

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ 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="edit"
130+
id="editsmvopts"
131+
label="[scl.SmvOpts]"
132+
>
133+
</mwc-button>
128134
<mwc-button
129135
icon="delete"
130136
label="[remove]"
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* @web/test-runner snapshot v1 */
2+
export const snapshots = {};
3+
4+
snapshots["Wizards for SCL SmvOpts element define an edit wizard that looks like the latest snapshot"] =
5+
`<mwc-dialog
6+
defaultaction="close"
7+
heading="[wizard.title.edit]"
8+
open=""
9+
>
10+
<div id="wizard-content">
11+
<wizard-checkbox
12+
helper="[scl.refreshTime]"
13+
label="refreshTime"
14+
nullable=""
15+
>
16+
</wizard-checkbox>
17+
<wizard-checkbox
18+
helper="[scl.sampleRate]"
19+
label="sampleRate"
20+
nullable=""
21+
>
22+
</wizard-checkbox>
23+
<wizard-checkbox
24+
helper="[scl.dataSet]"
25+
label="dataSet"
26+
nullable=""
27+
>
28+
</wizard-checkbox>
29+
<wizard-checkbox
30+
helper="[scl.security]"
31+
label="security"
32+
nullable=""
33+
>
34+
</wizard-checkbox>
35+
<wizard-checkbox
36+
helper="[scl.synchSourceId]"
37+
label="synchSourceId"
38+
nullable=""
39+
>
40+
</wizard-checkbox>
41+
</div>
42+
<mwc-button
43+
dialogaction="close"
44+
label="[cancel]"
45+
slot="secondaryAction"
46+
style="--mdc-theme-primary: var(--mdc-theme-error)"
47+
>
48+
</mwc-button>
49+
<mwc-button
50+
dialoginitialfocus=""
51+
icon="save"
52+
label="[save]"
53+
slot="primaryAction"
54+
trailingicon=""
55+
>
56+
</mwc-button>
57+
</mwc-dialog>
58+
`;
59+
/* end snapshot Wizards for SCL SmvOpts element define an edit wizard that looks like the latest snapshot */
60+

0 commit comments

Comments
 (0)