Skip to content

Commit

Permalink
fix(editors): Changed selectors in Substation and IED Editors and upd…
Browse files Browse the repository at this point in the history
…ated IED and Substation Wizards. (#671)
  • Loading branch information
Dennis Labordus authored Apr 11, 2022
1 parent e63f11f commit 33b590a
Show file tree
Hide file tree
Showing 17 changed files with 752 additions and 159 deletions.
46 changes: 24 additions & 22 deletions src/Editing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,30 +319,32 @@ export function Editing<TBase extends LitElementConstructor>(Base: TBase) {
private checkUpdateValidity(update: Update): boolean {
if (update.checkValidity !== undefined) return update.checkValidity();

const invalidNaming = Array.from(
update.element.parentElement?.children ?? []
).some(
elm =>
elm.tagName === update.element.tagName &&
elm.getAttribute('name') === update.newAttributes['name']
);

if (invalidNaming) {
this.dispatchEvent(
newLogEvent({
kind: 'error',
title: get('editing.error.update', {
name: update.element.tagName,
}),
message: get('editing.error.nameClash', {
parent: update.element.parentElement!.tagName,
child: update.element.tagName,
name: update.newAttributes['name']!,
}),
})
if (update.oldAttributes['name'] !== update.newAttributes['name']) {
const invalidNaming = Array.from(
update.element.parentElement?.children ?? []
).some(
elm =>
elm.tagName === update.element.tagName &&
elm.getAttribute('name') === update.newAttributes['name']
);

return false;
if (invalidNaming) {
this.dispatchEvent(
newLogEvent({
kind: 'error',
title: get('editing.error.update', {
name: update.element.tagName,
}),
message: get('editing.error.nameClash', {
parent: update.element.parentElement!.tagName,
child: update.element.tagName,
name: update.newAttributes['name']!,
}),
})
);

return false;
}
}

const invalidId =
Expand Down
26 changes: 12 additions & 14 deletions src/editors/IED.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import { Nsdoc } from '../foundation/nsdoc.js';
* We need a variable outside the plugin to save the selected IED, because the Plugin is created
* more than once during working with the IED Editor, for instance when opening a Wizard to edit the IED.
*/
let iedEditorSelectedIedName: string | undefined;
let iedEditorSelectedIed: Element | undefined;
/*
* We will also add an Event Listener when a new document is opened. We then want to reset the selection
* so setting it to undefined will set the selected IED again on the first in the list.
*/
function onOpenDocResetSelectedIed() {
iedEditorSelectedIedName = undefined;
iedEditorSelectedIed = undefined;
}
addEventListener('open-doc', onOpenDocResetSelectedIed);

Expand All @@ -45,14 +45,17 @@ export default class IedPlugin extends LitElement {

@state()
private set selectedIed(element: Element | undefined) {
iedEditorSelectedIedName = (element) ? getNameAttribute(element) : undefined;
iedEditorSelectedIed = element;
}

private get selectedIed(): Element {
if (iedEditorSelectedIedName === undefined) {
iedEditorSelectedIedName = getNameAttribute(this.alphabeticOrderedIeds[0]);
private get selectedIed(): Element | undefined {
if (iedEditorSelectedIed === undefined) {
const iedList = this.alphabeticOrderedIeds;
if (iedList.length > 0) {
iedEditorSelectedIed = iedList[0];
}
}
return this.doc.querySelector(`:root > IED[name="${iedEditorSelectedIedName}"]`)!;
return iedEditorSelectedIed;
}

private onSelect(event: SingleSelectedEvent): void {
Expand All @@ -63,11 +66,6 @@ export default class IedPlugin extends LitElement {
render(): TemplateResult {
const iedList = this.alphabeticOrderedIeds;
if (iedList.length > 0) {
let selectedIedElement = this.selectedIed;
if (!selectedIedElement) {
// Fix: If the selected IED can't be found, because the name is changed, will select the first one again.
selectedIedElement = iedList[0];
}
return html `
<section>
<mwc-select
Expand All @@ -78,7 +76,7 @@ export default class IedPlugin extends LitElement {
ied =>
html`
<mwc-list-item
?selected=${ied == selectedIedElement}
?selected=${ied == this.selectedIed}
value="${getNameAttribute(ied)}"
>${getNameAttribute(ied)} ${ied.hasAttribute('desc') ? translate('iededitor.searchHelperDesc', {
description: getDescriptionAttribute(ied)!,
Expand All @@ -87,7 +85,7 @@ export default class IedPlugin extends LitElement {
)}
</mwc-select>
<ied-container
.element=${selectedIedElement}
.element=${this.selectedIed}
.nsdoc=${this.nsdoc}
></ied-container>
</section>`;
Expand Down
14 changes: 6 additions & 8 deletions src/editors/SingleLineDiagram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ import '@material/mwc-textfield';
* We need a variable outside the plugin to save the selected substation, because the Plugin is created
* more than once during working with the SLD, for instance when opening a Wizard to edit equipment.
*/
let sldEditorSelectedSubstationName: string | undefined;
let sldEditorSelectedSubstation: Element | undefined;
/*
* We will also add an Event Listener when a new document is opened. We then want to reset the selection
* so setting it to undefined will set the selected Substation again on the first in the list.
*/
function onOpenDocResetSelectedSubstation() {
sldEditorSelectedSubstationName = undefined;
sldEditorSelectedSubstation = undefined;
}
addEventListener('open-doc', onOpenDocResetSelectedSubstation);

Expand All @@ -90,19 +90,17 @@ export default class SingleLineDiagramPlugin extends LitElement {

@state()
private set selectedSubstation(element: Element | undefined) {
sldEditorSelectedSubstationName = (element) ? getNameAttribute(element) : undefined;
sldEditorSelectedSubstation = element;
}

private get selectedSubstation(): Element | undefined {
if (sldEditorSelectedSubstationName === undefined) {
if (sldEditorSelectedSubstation === undefined) {
const substationList = this.substations;
if (substationList.length > 0) {
sldEditorSelectedSubstationName = getNameAttribute(substationList[0]);
sldEditorSelectedSubstation = substationList[0];
}
}
return (sldEditorSelectedSubstationName)
? this.doc.querySelector(`:root > Substation[name="${sldEditorSelectedSubstationName}"]`) ?? undefined
: undefined;
return sldEditorSelectedSubstation;
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export const de: Translations = {
},
action: {
addvoltagelevel: 'Spannungsebene hinzufügen',
updatesubstation: 'Schaltanlage "{{name}}" bearbeitet',
},
},
iededitor: {
Expand All @@ -209,7 +210,7 @@ export const de: Translations = {
},
},
action: {
updateied: 'IED "{{iedName}}" bearbeitet',
updateied: 'IED "{{name}}" bearbeitet',
},
},
powertransformer: {
Expand Down
3 changes: 2 additions & 1 deletion src/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export const en = {
},
action: {
addvoltagelevel: 'Add voltage level',
updatesubstation: 'Edited substation "{{name}}"',
},
},
iededitor: {
Expand All @@ -206,7 +207,7 @@ export const en = {
},
},
action: {
updateied: 'Edited IED "{{iedName}}"',
updateied: 'Edited IED "{{name}}"',
},
},
powertransformer: {
Expand Down
65 changes: 64 additions & 1 deletion src/wizards/foundation/actions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import {
cloneElement,
ComplexAction,
createUpdateAction,
EditorAction,
getValue,
WizardActor,
WizardInputElement,
} from '../../foundation.js';
import { get } from "lit-translate";
import { updateReferences } from "./references.js";

export function updateNamingAction(element: Element): WizardActor {
return (inputs: WizardInputElement[]): EditorAction[] => {
Expand All @@ -14,11 +18,70 @@ export function updateNamingAction(element: Element): WizardActor {
if (
name === element.getAttribute('name') &&
desc === element.getAttribute('desc')
)
) {
return [];
}

const newElement = cloneElement(element, { name, desc });

return [{ old: { element }, new: { element: newElement } }];
};
}

export function updateNamingAttributeWithReferencesAction(
element: Element,
messageTitleKey: string
): WizardActor {
return (inputs: WizardInputElement[]): EditorAction[] => {
const newAttributes: Record<string, string | null> = {};
processNamingAttributes(newAttributes, element, inputs);
if (Object.keys(newAttributes).length == 0) {
return [];
}
addMissingAttributes(element, newAttributes)

const name = getValue(inputs.find(i => i.label === 'name')!)!;
const complexAction: ComplexAction = {
actions: [],
title: get(messageTitleKey, {name}),
};
complexAction.actions.push(createUpdateAction(
element,
newAttributes));
complexAction.actions.push(...updateReferences(
element,
element.getAttribute('name'),
name));
return complexAction.actions.length ? [complexAction] : [];
};
}

export function processNamingAttributes(
newAttributes: Record<string, string | null>,
element: Element,
inputs: WizardInputElement[]
): void {
const name = getValue(inputs.find(i => i.label === 'name')!)!;
const desc = getValue(inputs.find(i => i.label === 'desc')!);

if (name !== element.getAttribute('name')) {
newAttributes['name'] = name;
}
if (desc !== element.getAttribute('desc')) {
newAttributes['desc'] = desc;
}
}

export function addMissingAttributes(
element: Element,
newAttributes: Record<string, string | null>
): Record<string, string | null> {
const newAttributeKeys = Object.keys(newAttributes);
Array.from(element.attributes)
.filter(attr => !newAttributeKeys.includes(attr.name))
.forEach(attr => {
newAttributes[attr.name] = attr.value;
});

return newAttributes;
}
7 changes: 6 additions & 1 deletion src/wizards/foundation/references.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {isPublic, SimpleAction} from "../../foundation.js";

const referenceInfoTags = ['IED'] as const;
const referenceInfoTags = ['IED', 'Substation'] as const;
type ReferencesInfoTag = typeof referenceInfoTags[number];

/*
Expand Down Expand Up @@ -41,6 +41,11 @@ const referenceInfos: Record<
}, {
elementQuery: `SampledValueControl > IEDName`,
attribute: null
}],
Substation:
[{
elementQuery: `Terminal`,
attribute: 'substationName'
}]
}

Expand Down
45 changes: 7 additions & 38 deletions src/wizards/ied.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import {html, TemplateResult} from 'lit-element';
import {get, translate} from 'lit-translate';
import { html, TemplateResult } from 'lit-element';
import { get, translate } from 'lit-translate';

import {
cloneElement,
ComplexAction,
EditorAction,
getValue,
isPublic,
Wizard,
WizardActor,
WizardInputElement,
} from '../foundation.js';
import {patterns} from "./foundation/limits.js";
import {updateReferences} from "./foundation/references.js";
import '../wizard-textfield.js';
import { isPublic, Wizard } from '../foundation.js';
import { patterns } from "./foundation/limits.js";
import { updateNamingAttributeWithReferencesAction } from "./foundation/actions.js";

const iedNamePattern = "[A-Za-z][0-9A-Za-z_]{0,2}|" +
"[A-Za-z][0-9A-Za-z_]{4,63}|" +
Expand All @@ -21,29 +13,6 @@ const iedNamePattern = "[A-Za-z][0-9A-Za-z_]{0,2}|" +
"No[0-9A-Za-mo-z_][0-9A-Za-z_]|" +
"Non[0-9A-Za-df-z_]";

export function updateIED(element: Element): WizardActor {
return (inputs: WizardInputElement[]): EditorAction[] => {
const name = getValue(inputs.find(i => i.label === 'name')!)!;
const oldName = element.getAttribute('name');
const desc = getValue(inputs.find(i => i.label === 'desc')!);

if ( name === oldName &&
desc === element.getAttribute('desc')) {
return [];
}

const complexAction: ComplexAction = {
actions: [],
title: get('ied.action.updateied', {iedName: name}),
};

const newElement = cloneElement(element, { name, desc });
complexAction.actions.push({ old: { element }, new: { element: newElement } });
complexAction.actions.push(...updateReferences(element, oldName, name));
return complexAction.actions.length ? [complexAction] : [];
};
}

export function renderIEDWizard(
name: string | null,
desc: string | null,
Expand Down Expand Up @@ -87,7 +56,7 @@ export function editIEDWizard(element: Element): Wizard {
primary: {
icon: 'edit',
label: get('save'),
action: updateIED(element),
action: updateNamingAttributeWithReferencesAction(element, 'ied.action.updateied'),
},
content: renderIEDWizard(
element.getAttribute('name'),
Expand Down
4 changes: 2 additions & 2 deletions src/wizards/substation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
WizardActor,
WizardInputElement,
} from '../foundation.js';
import { updateNamingAction } from './foundation/actions.js';
import { guessVoltageLevel } from '../editors/substation/guess-wizard.js';
import { updateNamingAttributeWithReferencesAction } from "./foundation/actions.js";

function render(
name: string,
Expand Down Expand Up @@ -97,7 +97,7 @@ export function substationEditWizard(element: Element): Wizard {
primary: {
icon: 'edit',
label: get('save'),
action: updateNamingAction(element),
action: updateNamingAttributeWithReferencesAction(element, 'substation.action.updatesubstation'),
},
content: render(
element.getAttribute('name') ?? '',
Expand Down
Loading

0 comments on commit 33b590a

Please sign in to comment.