Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(substation): read only Function and SubFunction container #700

Merged
12 changes: 8 additions & 4 deletions src/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ export const de: Translations = {
showieds: 'Zeige IEDs im Substation-Editor',
selectFileButton: 'Datei auswählen',
loadNsdTranslations: 'NSDoc-Dateien hochladen',
invalidFileNoIdFound: "Ungültiges NSDoc ({{ filename }}); kein 'id'-Attribut in der Datei gefunden",
invalidFileNoIdFound:
"Ungültiges NSDoc ({{ filename }}); kein 'id'-Attribut in der Datei gefunden",
invalidNsdocVersion:
'Die Version {{ id }} NSD ({{ nsdVersion }}) passt nicht zu der geladenen NSDoc ({{ filename }}, {{ nsdocVersion }})',
},
Expand All @@ -96,6 +97,7 @@ export const de: Translations = {
zeroline: {
iedsloading: 'IEDs werden geladen...',
showieds: 'IEDs im Substation-Editor anzeigen/ausblenden',
showfunctions: 'Funktionselemente in der Ansicht filtern',
commmap: 'Kommunikationszuordnung',
reportcontrol: 'Reports anzeigen',
gsecontrol: 'GOOSEs anzeigen',
Expand Down Expand Up @@ -390,7 +392,7 @@ export const de: Translations = {
},
action: {
updatedai: 'DAI "{{daiName}} bearbeitet"',
}
},
},
sdo: {
wizard: {
Expand Down Expand Up @@ -552,8 +554,10 @@ export const de: Translations = {
unreferencedControls: {
title: 'Steuerblöcke mit einem fehlenden oder ungültigen Kontrollblock',
deleteButton: 'Ausgewählte Kontrollblöcke entfernen',
tooltip: 'Steuerblöcke ohne Verweis auf ein vorhandenes Datensatz. Das ist kein Fehler und eher üblich for allem für Reports',
addressDefinitionTooltip: 'Für diesen Kontrollblock existiert eine Adressdefinition im Abschnitt Kommunikation',
tooltip:
'Steuerblöcke ohne Verweis auf ein vorhandenes Datensatz. Das ist kein Fehler und eher üblich for allem für Reports',
addressDefinitionTooltip:
'Für diesen Kontrollblock existiert eine Adressdefinition im Abschnitt Kommunikation',
alsoRemoveFromCommunication: 'Kommunikation SMV/GSE mit entfernen',
},
},
Expand Down
12 changes: 8 additions & 4 deletions src/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export const en = {
showieds: 'Show IEDs in substation editor',
selectFileButton: 'Select file',
loadNsdTranslations: 'Uploaded NSDoc files',
invalidFileNoIdFound: "Invalid NSDoc ({{ filename }}); no 'id' attribute found in file",
invalidFileNoIdFound:
"Invalid NSDoc ({{ filename }}); no 'id' attribute found in file",
invalidNsdocVersion:
'The version of {{ id }} NSD ({{ nsdVersion }}) does not correlate with the version of the corresponding NSDoc ({{ filename }}, {{ nsdocVersion }})',
},
Expand All @@ -94,6 +95,7 @@ export const en = {
zeroline: {
iedsloading: 'Loading IEDs...',
showieds: 'Show/hide IEDs in substation editor',
showfunctions: 'Filter function type elements',
commmap: 'Communication mapping',
reportcontrol: 'Show all Reports',
gsecontrol: 'Show all GOOSEs',
Expand Down Expand Up @@ -387,7 +389,7 @@ export const en = {
},
action: {
updatedai: 'Edited DAI "{{daiName}}"',
}
},
},
sdo: {
wizard: {
Expand Down Expand Up @@ -549,8 +551,10 @@ export const en = {
unreferencedControls: {
title: 'Control Blocks with a Missing or Invalid Dataset',
deleteButton: 'Remove Selected Control Blocks',
tooltip: 'Control Blocks without a reference to an existing DataSet. Note that this is normal in an ICD file or for an MMS ReportControl with a dynamically allocated DataSet',
addressDefinitionTooltip: 'An address definition exists for this control block in the Communication section',
tooltip:
'Control Blocks without a reference to an existing DataSet. Note that this is normal in an ICD file or for an MMS ReportControl with a dynamically allocated DataSet',
addressDefinitionTooltip:
'An address definition exists for this control block in the Communication section',
alsoRemoveFromCommunication: 'Also remove SMV/GSE Address',
},
},
Expand Down
25 changes: 25 additions & 0 deletions src/zeroline-pane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ function setShowIEDs(value: Settings['showieds']) {
localStorage.setItem('showieds', value);
}

function shouldShowFunctions(): boolean {
return localStorage.getItem('showfunctions') === 'on';
}

function setShowFunctions(value: 'on' | 'off') {
localStorage.setItem('showfunctions', value);
}

/** [[`Zeroline`]] pane for displaying `Substation` and/or `IED` sections. */
@customElement('zeroline-pane')
export class ZerolinePane extends LitElement {
Expand All @@ -48,6 +56,7 @@ export class ZerolinePane extends LitElement {

@query('#commmap') commmap!: IconButton;
@query('#showieds') showieds!: IconButtonToggle;
@query('#showfunctions') showfunctions!: IconButtonToggle;
@query('#gsecontrol') gsecontrol!: IconButton;
@query('#smvcontrol') smvcontrol!: IconButton;
@query('#reportcontrol') reportcontrol!: IconButton;
Expand Down Expand Up @@ -90,6 +99,12 @@ export class ZerolinePane extends LitElement {
this.requestUpdate();
}

toggleShowFunctions(): void {
if (shouldShowFunctions()) setShowFunctions('off');
else setShowFunctions('on');
this.requestUpdate();
}

renderIedContainer(): TemplateResult {
this.getAttachedIeds = shouldShowIEDs()
? getAttachedIeds(this.doc)
Expand Down Expand Up @@ -124,6 +139,15 @@ export class ZerolinePane extends LitElement {
offIcon="developer_board_off"
></mwc-icon-button-toggle>
</abbr>
<abbr title="${translate('zeroline.showfunctions')}">
<mwc-icon-button-toggle
?on=${shouldShowFunctions()}
@click=${() => this.toggleShowFunctions()}
id="showfunctions"
onIcon="layers"
offIcon="layers_clear"
></mwc-icon-button-toggle>
</abbr>
<abbr title="${translate('zeroline.commmap')}">
<mwc-icon-button
id="commmap"
Expand Down Expand Up @@ -165,6 +189,7 @@ export class ZerolinePane extends LitElement {
.element=${substation}
.getAttachedIeds=${this.getAttachedIeds}
?readonly=${this.readonly}
?showfunctions=${shouldShowFunctions()}
></substation-editor>`
)}
</section>`
Expand Down
24 changes: 17 additions & 7 deletions src/zeroline/bay-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ import {
tags,
} from '../foundation.js';
import { emptyWizard, wizards } from '../wizards/wizard-library.js';
import {
cloneSubstationElement,
startMove,
styles,
} from './foundation.js';
import { cloneSubstationElement, startMove, styles } from './foundation.js';

function childTags(element: Element | null | undefined): SCLTag[] {
if (!element) return [];
Expand All @@ -48,6 +44,9 @@ export class BayEditor extends LitElement {
element!: Element;
@property({ type: Boolean })
readonly = false;
/** Wheter `Function` and `SubFunction` are rendered */
@property({ type: Boolean })
showfunctions = false;

@property({ type: String })
get header(): string {
Expand Down Expand Up @@ -99,6 +98,15 @@ export class BayEditor extends LitElement {
this.addMenu.anchor = <HTMLElement>this.addButton;
}

renderFunctions(): TemplateResult {
if (!this.showfunctions) return html``;

const functions = getChildElementsByTagName(this.element, 'Function');
return html` ${functions.map(
fUnction => html`<function-editor .element=${fUnction}></function-editor>`
)}`;
}

renderIedContainer(): TemplateResult {
const ieds = this.getAttachedIeds?.(this.element) ?? [];
return ieds?.length
Expand Down Expand Up @@ -168,13 +176,15 @@ export class BayEditor extends LitElement {
>${this.renderAddButtons()}</mwc-menu
>
</abbr>
${this.renderIedContainer()}
${this.renderIedContainer()} ${this.renderFunctions()}
<div id="ceContainer">
${Array.from(
getChildElementsByTagName(this.element, 'PowerTransformer')
).map(
pwt =>
html`<powertransformer-editor .element=${pwt}></powertransformer-editor>`
html`<powertransformer-editor
.element=${pwt}
></powertransformer-editor>`
)}
${Array.from(
getChildElementsByTagName(this.element, 'ConductingEquipment')
Expand Down
21 changes: 12 additions & 9 deletions src/zeroline/foundation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { css, TemplateResult } from 'lit-element';

import './function-editor.js';
import { newActionEvent, isPublic } from '../foundation.js';
import {
circuitBreakerIcon,
Expand Down Expand Up @@ -156,12 +157,8 @@ export type ElementEditorClass<T extends ElementEditor> = new () => T;
export function startMove<
E extends ElementEditor,
C extends ElementEditorClass<ElementEditor>,
P extends ElementEditorClass<ElementEditor>>
(
editor: E,
childClass: C,
parentClasses: P[]
): void {
P extends ElementEditorClass<ElementEditor>
>(editor: E, childClass: C, parentClasses: P[]): void {
if (!editor.element) return;

editor.classList.add('moving');
Expand All @@ -184,8 +181,13 @@ export function startMove<

if (e instanceof KeyboardEvent && e.key === 'Escape') return;

const targetEditor = e.composedPath()
.find(et => et instanceof childClass || checkInstanceOfParentClass(et, parentClasses));
const targetEditor = e
.composedPath()
.find(
et =>
et instanceof childClass ||
checkInstanceOfParentClass(et, parentClasses)
);
if (targetEditor === undefined || targetEditor === editor) return;

const destination =
Expand Down Expand Up @@ -227,7 +229,8 @@ export function startMove<
*/
function checkInstanceOfParentClass<E extends ElementEditor>(
et: EventTarget,
classes: ElementEditorClass<E>[]): boolean {
classes: ElementEditorClass<E>[]
): boolean {
const targetEditor = classes.find(clazz => et instanceof clazz);
return targetEditor !== undefined;
}
Expand Down
46 changes: 46 additions & 0 deletions src/zeroline/function-editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
html,
LitElement,
TemplateResult,
property,
customElement,
state,
} from 'lit-element';

import '../action-pane.js';
import './subfunction-editor.js';
import { getChildElementsByTagName } from '../foundation.js';

/** Pane rendering `Function` element with its children */
@customElement('function-editor')
export class FunctionEditor extends LitElement {
/** The edited `Function` element */
@property({ attribute: false })
element!: Element;
@state()
get header(): string {
const name = this.element.getAttribute('name');
const desc = this.element.getAttribute('desc');
const type = this.element.getAttribute('type');

return `${name}${desc ? ` - ${desc}` : ''}${type ? ` (${type})` : ''}`;
}

renderSubFunctions(): TemplateResult {
const subfunctions = getChildElementsByTagName(this.element, 'SubFunction');
return html` ${subfunctions.map(
subFunction =>
html`<subfunction-editor .element=${subFunction}></subfunction-editor>`
)}`;
}

render(): TemplateResult {
return html`<action-pane
label="${this.header}"
icon="functions"
secondary
highlighted
>${this.renderSubFunctions()}</action-pane
>`;
}
}
42 changes: 42 additions & 0 deletions src/zeroline/subfunction-editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
html,
LitElement,
TemplateResult,
property,
customElement,
state,
} from 'lit-element';

import '../action-pane.js';
import './subfunction-editor.js';
import { getChildElementsByTagName } from '../foundation.js';

/** Pane rendering `SubFunction` element with its children */
@customElement('subfunction-editor')
export class SubFunctionEditor extends LitElement {
/** The edited `SubFunction` element */
@property({ attribute: false })
element!: Element;
@state()
get header(): string {
const name = this.element.getAttribute('name');
const desc = this.element.getAttribute('desc');
const type = this.element.getAttribute('type');

return `${name}${desc ? ` - ${desc}` : ''}${type ? ` (${type})` : ''}`;
}

renderSubFunctions(): TemplateResult {
const subfunctions = getChildElementsByTagName(this.element, 'SubFunction');
return html` ${subfunctions.map(
subFunction =>
html`<subfunction-editor .element=${subFunction}></subfunction-editor>`
)}`;
}

render(): TemplateResult {
return html`<action-pane label="${this.header}" icon="functions" secondary
>${this.renderSubFunctions()}</action-pane
>`;
}
}
Loading