Skip to content

Commit 965f10a

Browse files
feat(wizards/lnode): add edit wizard (openscd#778)
* feat(wizards/lnode): add edit wizard * test(wizards/lnode): add editing integration * test(wizards/lnode): fix snapshots * refactor(translation/de): better localization
1 parent 8ee23fc commit 965f10a

File tree

14 files changed

+505
-10
lines changed

14 files changed

+505
-10
lines changed

src/editors/substation/bay-editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export class BayEditor extends LitElement {
7272

7373
/** Opens a [[`WizardDialog`]] for editing `LNode` connections. */
7474
openLNodeWizard(): void {
75-
const wizard = wizards['LNode'].edit(this.element);
75+
const wizard = wizards['LNode'].create(this.element);
7676
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
7777
}
7878

src/editors/substation/conducting-equipment-editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export class ConductingEquipmentEditor extends LitElement {
6464
}
6565

6666
private openLNodeWizard(): void {
67-
const wizard = wizards['LNode'].edit(this.element);
67+
const wizard = wizards['LNode'].create(this.element);
6868
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
6969
}
7070

src/editors/substation/l-node-editor.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from 'lit-element';
99

1010
import '../../action-icon.js';
11-
import { identity, newActionEvent } from '../../foundation.js';
11+
import { identity, newActionEvent, newWizardEvent } from '../../foundation.js';
1212
import {
1313
automationLogicalNode,
1414
controlLogicalNode,
@@ -27,6 +27,7 @@ import {
2727
systemLogicalNode,
2828
transformerLogicalNode,
2929
} from '../../icons/lnode.js';
30+
import { wizards } from '../../wizards/wizard-library.js';
3031

3132
export function getLNodeIcon(lNode: Element): TemplateResult {
3233
const lnClassGroup = lNode.getAttribute('lnClass')?.charAt(0) ?? '';
@@ -75,6 +76,11 @@ export class LNodeEditor extends LitElement {
7576
return this.element.getAttribute('iedName') === 'None' ?? false;
7677
}
7778

79+
private openEditWizard(): void {
80+
const wizard = wizards['LNode'].edit(this.element);
81+
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
82+
}
83+
7884
remove(): void {
7985
if (this.element)
8086
this.dispatchEvent(
@@ -93,6 +99,12 @@ export class LNodeEditor extends LitElement {
9399
?secondary=${this.missingIedReference}
94100
?highlighted=${this.missingIedReference}
95101
><mwc-icon slot="icon">${getLNodeIcon(this.element)}</mwc-icon
102+
><mwc-fab
103+
slot="action"
104+
mini
105+
icon="edit"
106+
@click="${() => this.openEditWizard()}}"
107+
></mwc-fab
96108
><mwc-fab
97109
slot="action"
98110
mini

src/editors/substation/powertransformer-editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export class PowerTransformerEditor extends LitElement {
6666
}
6767

6868
private openLNodeWizard(): void {
69-
const wizard = wizards['LNode'].edit(this.element);
69+
const wizard = wizards['LNode'].create(this.element);
7070
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
7171
}
7272

src/editors/substation/substation-editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class SubstationEditor extends LitElement {
7878

7979
/** Opens a [[`WizardDialog`]] for editing `LNode` connections. */
8080
openLNodeWizard(): void {
81-
const wizard = wizards['LNode'].edit(this.element);
81+
const wizard = wizards['LNode'].create(this.element);
8282
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
8383
}
8484

src/editors/substation/voltage-level-editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class VoltageLevelEditor extends LitElement {
8888

8989
/** Opens a [[`WizardDialog`]] for editing `LNode` connections. */
9090
openLNodeWizard(): void {
91-
const wizard = wizards['LNode'].edit(this.element);
91+
const wizard = wizards['LNode'].create(this.element);
9292
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
9393
}
9494

src/translations/de.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ export const de: Translations = {
6060
sampleRate: 'Abtastrate zu Telegram hinzufügen',
6161
security: 'Potentiel in Zukunft für z.B. digitale Signature',
6262
synchSourceId: 'Identität der Zeitquelle zu Telegram hinzufügen',
63+
iedName: 'Referenziertes IED',
64+
ldInst: 'Referenziertes logisches Gerät',
65+
prefix: 'Präfix des logischen Knotens',
66+
lnInst: 'Instanz des logischen Knotens',
6367
},
6468
settings: {
6569
title: 'Einstellungen',

src/translations/en.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ export const en = {
5858
sampleRate: 'Add sample rate to SMV packet',
5959
security: 'Potential future use. e.g. digital signature',
6060
synchSourceId: 'Add sync source id to SMV packet',
61+
iedName: 'Referenced IED',
62+
ldInst: 'Referenced Logical Device',
63+
prefix: 'Prefix of the Logical Node',
64+
lnInst: 'Instance of the Logical Node',
6165
},
6266
settings: {
6367
title: 'Settings',

src/wizards/lnode.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import { MultiSelectedEvent } from '@material/mwc-list/mwc-list-foundation';
1212
import '../filtered-list.js';
1313
import {
1414
Create,
15+
cloneElement,
1516
createElement,
1617
EditorAction,
1718
getChildElementsByTagName,
19+
getValue,
1820
identity,
1921
isPublic,
2022
newLogEvent,
@@ -26,6 +28,7 @@ import {
2628
WizardInputElement,
2729
WizardMenuActor,
2830
} from '../foundation.js';
31+
import { patterns } from './foundation/limits.js';
2932

3033
const maxLnInst = 99;
3134
const lnInstRange = Array(maxLnInst)
@@ -489,3 +492,130 @@ export function lNodeWizard(parent: Element): Wizard {
489492

490493
return lNodeReferenceWizard(parent);
491494
}
495+
496+
interface ContentOptions {
497+
iedName: string | null;
498+
ldInst: string | null;
499+
prefix: string | null;
500+
lnClass: string | null;
501+
lnInst: string | null;
502+
reservedLnInst: string[];
503+
}
504+
505+
function contentLNodeWizard(options: ContentOptions): TemplateResult[] {
506+
const isIedRef = options.iedName !== 'None';
507+
508+
return [
509+
html`<wizard-textfield
510+
label="iedName"
511+
.maybeValue=${options.iedName}
512+
helper="${translate('scl.iedName')}"
513+
helperPersistent
514+
disabled
515+
></wizard-textfield>`,
516+
html`<wizard-textfield
517+
label="ldInst"
518+
.maybeValue=${options.ldInst}
519+
helper="${translate('scl.ldInst')}"
520+
helperPersistent
521+
nullable
522+
disabled
523+
></wizard-textfield>`,
524+
html`<wizard-textfield
525+
label="prefix"
526+
.maybeValue=${options.prefix}
527+
helper="${translate('scl.prefix')}"
528+
pattern="${patterns.asciName}"
529+
maxLength="11"
530+
helperPersistent
531+
nullable
532+
?disabled=${isIedRef}
533+
></wizard-textfield>`,
534+
html`<wizard-textfield
535+
label="lnClass"
536+
.maybeValue=${options.lnClass}
537+
helper="${translate('scl.lnClass')}"
538+
helperPersistent
539+
disabled
540+
></wizard-textfield>`,
541+
html`<wizard-textfield
542+
label="lnInst"
543+
.maybeValue=${options.lnInst}
544+
helper="${translate('scl.lnInst')}"
545+
helperPersistent
546+
type="number"
547+
min="1"
548+
max="99"
549+
.reservedValues=${options.reservedLnInst}
550+
?disabled=${isIedRef}
551+
></wizard-textfield>`,
552+
];
553+
}
554+
555+
function updateLNodeAction(element: Element): WizardActor {
556+
return (inputs: WizardInputElement[]): EditorAction[] => {
557+
const attributes: Record<string, string | null> = {};
558+
const attributeKeys = ['iedName', 'ldInst', 'prefix', 'lnClass', 'lnInst'];
559+
560+
attributeKeys.forEach(key => {
561+
attributes[key] = getValue(inputs.find(i => i.label === key)!);
562+
});
563+
564+
let lNodeAction: EditorAction | null = null;
565+
if (
566+
attributeKeys.some(key => attributes[key] !== element.getAttribute(key))
567+
) {
568+
const newElement = cloneElement(element, attributes);
569+
lNodeAction = {
570+
old: { element },
571+
new: { element: newElement },
572+
};
573+
return [lNodeAction];
574+
}
575+
576+
return [];
577+
};
578+
}
579+
580+
export function editLNodeWizard(element: Element): Wizard {
581+
const [iedName, ldInst, prefix, lnClass, lnInst] = [
582+
'iedName',
583+
'ldInst',
584+
'prefix',
585+
'lnClass',
586+
'lnInst',
587+
].map(attr => element.getAttribute(attr));
588+
589+
const reservedLnInst = getChildElementsByTagName(
590+
element.parentElement,
591+
'LNode'
592+
)
593+
.filter(
594+
sibling =>
595+
sibling !== element &&
596+
sibling.getAttribute('lnClass') === element.getAttribute('lnClass')
597+
)
598+
.map(sibling => sibling.getAttribute('lnInst')!);
599+
600+
return [
601+
{
602+
title: get('wizard.title.edit', { tagName: 'LNode' }),
603+
element,
604+
primary: {
605+
label: get('save'),
606+
icon: 'save',
607+
action: updateLNodeAction(element),
608+
},
609+
content: [
610+
...contentLNodeWizard({
611+
iedName,
612+
ldInst,
613+
prefix,
614+
lnClass,
615+
lnInst,
616+
reservedLnInst,
617+
}),
618+
],
619+
},
620+
];
621+
}

src/wizards/wizard-library.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
} from './conductingequipment.js';
88
import { editConnectivityNodeWizard } from './connectivitynode.js';
99
import { createFCDAsWizard } from './fcda.js';
10-
import { lNodeWizard } from './lnode.js';
10+
import { editLNodeWizard, lNodeWizard } from './lnode.js';
1111
import { editOptFieldsWizard } from './optfields.js';
1212
import { createSubstationWizard, substationEditWizard } from './substation.js';
1313
import { editTerminalWizard } from './terminal.js';
@@ -313,7 +313,7 @@ export const wizards: Record<
313313
create: emptyWizard,
314314
},
315315
LNode: {
316-
edit: lNodeWizard,
316+
edit: editLNodeWizard,
317317
create: lNodeWizard,
318318
},
319319
LNodeType: {

0 commit comments

Comments
 (0)