Skip to content

Commit

Permalink
feat(wizards/sampledvaluecontrol): add edit wizards accessable from s…
Browse files Browse the repository at this point in the history
…election (#510)

* feat(translation): add/fix SCL terms

* feat(wizards/sampledvaluecontrol): add edit wizard

* feat(zeroline): start sampledvaluecontrol as subwizard

* refactor(wizards/sampledvaluecontrol): import statements and update action

* test(wizards/sampledvaluecontrol): add integration tests

* fix(zeroline): remove incorrect SubWizard trigger

* fix(wizards/sampledvaluecontrol): add missing pattern
  • Loading branch information
JakobVogelsang committed Jan 26, 2022
1 parent 12e3644 commit fa468b7
Show file tree
Hide file tree
Showing 12 changed files with 817 additions and 24 deletions.
6 changes: 5 additions & 1 deletion src/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ export const de: Translations = {
qchg: 'Qualitätsanderung ist Auslöser',
dupd: 'Datenupdate ist Auslöser',
fixedOffs: 'Fester Offset',
securityEnabled: 'Aktive Sicherungsmaßnahmen',
securityEnable: 'Aktive Sicherungsmaßnahmen',
DataSet: 'Datensetz',
Communication: 'Kommunikation',
TrgOps: 'Triggerbedingungen',
OptFields: 'Optionale felder',
multicast: 'SMV nach IEC 61850 9-2',
smpMod: 'Abtast-Art',
smpRate: 'Abtastrate',
nofASDU: 'Abtastpunkte pro Datenpacket',
},
settings: {
title: 'Einstellungen',
Expand Down
6 changes: 5 additions & 1 deletion src/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ export const en = {
qchg: 'Trigger on quality change',
dupd: 'Trigger on data update',
fixedOffs: 'Fixed offset',
securityEnabled: 'Security enabled',
securityEnable: 'Security enabled',
DataSet: 'Dataset',
Communication: 'Communication',
TrgOps: 'Trigger options',
OptFields: 'Optional fields',
multicast: 'SMV acc. to IEC 61850 9-2',
smpMod: 'Sample mode',
smpRate: 'Sample rate',
nofASDU: 'Samples per paket',
},
settings: {
title: 'Settings',
Expand Down
8 changes: 8 additions & 0 deletions src/wizards/foundation/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@ export const predefinedBasicTypeEnum = [
];

export const valKindEnum = ['Spec', 'Conf', 'RO', 'Set'];

export const smpModEnum = ['SmpPerPeriod', 'SmpPerSec', 'SecPerSmp'];

export const securityEnableEnum = [
'None',
'Signature',
'SignatureAndEncryption',
];
5 changes: 3 additions & 2 deletions src/wizards/gsecontrol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
import { maxLength, patterns } from './foundation/limits.js';
import { editDataSetWizard } from './dataset.js';
import { editGseWizard } from './gse.js';
import { securityEnableEnum } from './foundation/enums.js';

function getGSE(element: Element): Element | null | undefined {
const cbName = element.getAttribute('name');
Expand Down Expand Up @@ -100,8 +101,8 @@ export function renderGseAttributes(
.maybeValue=${securityEnabled}
nullable
required
helper="${translate('scl.securityEnabled')}"
>${['None', 'Signature', 'SignatureAndEncryption'].map(
helper="${translate('scl.securityEnable')}"
>${securityEnableEnum.map(
type => html`<mwc-list-item value="${type}">${type}</mwc-list-item>`
)}</wizard-select
>`,
Expand Down
200 changes: 197 additions & 3 deletions src/wizards/sampledvaluecontrol.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,188 @@
import { html } from 'lit-element';
import { get } from 'lit-translate';
import { html, TemplateResult } from 'lit-element';
import { get, translate } from 'lit-translate';

import { identity, isPublic, Wizard } from '../foundation.js';
import '@material/mwc-list/mwc-list-item.js';
import { List } from '@material/mwc-list';
import { ListItemBase } from '@material/mwc-list/mwc-list-item-base';
import { SingleSelectedEvent } from '@material/mwc-list/mwc-list-foundation';

import '../filtered-list.js';
import '../wizard-select.js';
import '../wizard-textfield.js';
import {
cloneElement,
EditorAction,
getValue,
identity,
isPublic,
newSubWizardEvent,
selector,
Wizard,
WizardActor,
WizardInput,
} from '../foundation.js';
import { securityEnableEnum, smpModEnum } from './foundation/enums.js';
import { maxLength, patterns } from './foundation/limits.js';

interface ContentOptions {
name: string | null;
desc: string | null;
multicast: string | null;
smvID: string | null;
smpMod: string | null;
smpRate: string | null;
nofASDU: string | null;
securityEnable: string | null;
}

function contentSampledValueControlWizard(
options: ContentOptions
): TemplateResult[] {
return [
html`<wizard-textfield
label="name"
.maybeValue=${options.name}
helper="${translate('scl.name')}"
required
validationMessage="${translate('textfield.required')}"
pattern="${patterns.asciName}"
maxLength="${maxLength.cbName}"
dialogInitialFocus
></wizard-textfield>`,
html`<wizard-textfield
label="desc"
.maybeValue=${options.desc}
nullable
pattern="${patterns.normalizedString}"
helper="${translate('scl.desc')}"
></wizard-textfield>`,
html`<wizard-select
label="multicast"
.maybeValue=${options.multicast}
helper="${translate('scl.multicast')}"
disabled
>${['true', 'false'].map(
option =>
html`<mwc-list-item value="${option}">${option}</mwc-list-item>`
)}</wizard-select
>`,
html`<wizard-textfield
label="smvID"
.maybeValue=${options.smvID}
helper="${translate('scl.id')}"
required
validationMessage="${translate('textfield.nonempty')}"
></wizard-textfield>`,
html`<wizard-select
label="smpMod"
.maybeValue=${options.smpMod}
nullable
required
helper="${translate('scl.smpMod')}"
>${smpModEnum.map(
option =>
html`<mwc-list-item value="${option}">${option}</mwc-list-item>`
)}</wizard-select
>`,
html`<wizard-textfield
label="smpRate"
.maybeValue=${options.smpRate}
helper="${translate('scl.smpRate')}"
required
type="number"
min="0"
></wizard-textfield>`,
html`<wizard-textfield
label="nofASDU"
.maybeValue=${options.nofASDU}
helper="${translate('scl.nofASDU')}"
required
type="number"
min="0"
></wizard-textfield>`,
html`<wizard-select
label="securityEnable"
.maybeValue=${options.securityEnable}
nullable
required
helper="${translate('scl.securityEnable')}"
>${securityEnableEnum.map(
option =>
html`<mwc-list-item value="${option}">${option}</mwc-list-item>`
)}</wizard-select
>`,
];
}

function updateSampledValueControlAction(element: Element): WizardActor {
return (inputs: WizardInput[]): EditorAction[] => {
const attributes: Record<string, string | null> = {};
const attributeKeys = [
'name',
'desc',
'multicast',
'smvID',
'smpMod',
'smpRate',
'nofASDU',
'securityEnable',
];

attributeKeys.forEach(key => {
attributes[key] = getValue(inputs.find(i => i.label === key)!);
});

let sampledValueControlAction: EditorAction | null = null;
if (
attributeKeys.some(key => attributes[key] !== element.getAttribute(key))
) {
const newElement = cloneElement(element, attributes);
sampledValueControlAction = {
old: { element },
new: { element: newElement },
};
}

const actions: EditorAction[] = [];
if (sampledValueControlAction) actions.push(sampledValueControlAction);
return actions;
};
}

export function editSampledValueControlWizard(element: Element): Wizard {
const name = element.getAttribute('name');
const desc = element.getAttribute('desc');
const multicast = element.getAttribute('multicast');
const smvID = element.getAttribute('smvID');
const smpMod = element.getAttribute('smpMod');
const smpRate = element.getAttribute('smpRate');
const nofASDU = element.getAttribute('nofASDU');
const securityEnable = element.getAttribute('securityEnabled');

return [
{
title: get('wizard.title.edit', { tagName: element.tagName }),
element,
primary: {
icon: 'save',
label: get('save'),
action: updateSampledValueControlAction(element),
},
content: [
...contentSampledValueControlWizard({
name,
desc,
multicast,
smvID,
smpMod,
smpRate,
nofASDU,
securityEnable,
}),
],
},
];
}

export function selectSampledValueControlWizard(element: Element): Wizard {
const smvControls = Array.from(
Expand All @@ -13,6 +194,19 @@ export function selectSampledValueControlWizard(element: Element): Wizard {
title: get('wizard.title.select', { tagName: 'SampledValueControl' }),
content: [
html`<filtered-list
@selected=${(e: SingleSelectedEvent) => {
const identity = (<ListItemBase>(<List>e.target).selected).value;
const sampledValueControl = element.querySelector(
selector('SampledValueControl', identity)
);
if (!sampledValueControl) return;
e.target?.dispatchEvent(
newSubWizardEvent(() =>
editSampledValueControlWizard(sampledValueControl)
)
);
}}
>${smvControls.map(
smvControl =>
html`<mwc-list-item twoline value="${identity(smvControl)}"
Expand Down
15 changes: 8 additions & 7 deletions src/zeroline-pane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import './zeroline/ied-editor.js';
import { Settings } from './Setting.js';
import { communicationMappingWizard } from './wizards/commmap-wizards.js';
import { gooseIcon, smvIcon, reportIcon } from './icons.js';
import { isPublic, newSubWizardEvent, newWizardEvent } from './foundation.js';
import { isPublic, newWizardEvent } from './foundation.js';
import { selectGseControlWizard } from './wizards/gsecontrol.js';
import { wizards } from './wizards/wizard-library.js';
import { getAttachedIeds } from './zeroline/foundation.js';
Expand Down Expand Up @@ -66,21 +66,22 @@ export class ZerolinePane extends LitElement {

openReportControlSelection(): void {
this.dispatchEvent(
newSubWizardEvent(() =>
selectReportControlWizard(this.doc.documentElement)
)
newWizardEvent(() => selectReportControlWizard(this.doc.documentElement))
);
}

openGseControlSelection(): void {
this.dispatchEvent(
newSubWizardEvent(() => selectGseControlWizard(this.doc.documentElement))
newWizardEvent(() => selectGseControlWizard(this.doc.documentElement))
);
}

openSampledValueControlSelection(): void {
const wizard = selectSampledValueControlWizard(this.doc.documentElement);
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
this.dispatchEvent(
newWizardEvent(() =>
selectSampledValueControlWizard(this.doc.documentElement)
)
);
}

toggleShowIEDs(): void {
Expand Down
11 changes: 6 additions & 5 deletions src/zeroline/ied-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import '../action-icon.js';
import { createClientLnWizard } from '../wizards/clientln.js';
import { gooseIcon, smvIcon, reportIcon } from '../icons.js';
import { wizards } from '../wizards/wizard-library.js';
import { newSubWizardEvent, newWizardEvent } from '../foundation.js';
import { newWizardEvent } from '../foundation.js';
import { selectGseControlWizard } from '../wizards/gsecontrol.js';
import { selectSampledValueControlWizard } from '../wizards/sampledvaluecontrol.js';
import { selectReportControlWizard } from '../wizards/reportcontrol.js';
Expand All @@ -41,19 +41,20 @@ export class IedEditor extends LitElement {

private openReportControlSelection(): void {
this.dispatchEvent(
newSubWizardEvent(() => selectReportControlWizard(this.element))
newWizardEvent(() => selectReportControlWizard(this.element))
);
}

private openGseControlSelection(): void {
this.dispatchEvent(
newSubWizardEvent(() => selectGseControlWizard(this.element))
newWizardEvent(() => selectGseControlWizard(this.element))
);
}

private openSmvControlSelection(): void {
const wizard = selectSampledValueControlWizard(this.element);
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
this.dispatchEvent(
newWizardEvent(() => selectSampledValueControlWizard(this.element))
);
}

private openCommunicationMapping(): void {
Expand Down
Loading

0 comments on commit fa468b7

Please sign in to comment.