-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## `with readonly property`
+
+#### `looks like the latest snapshot`
+
+```html
+
+
+ COUPLING_BAY — Bay
+
+
diff --git a/__snapshots__/conducting-equipment-editor wizarding integration.md b/__snapshots__/conducting-equipment-editor wizarding integration.md
index ad7e1f76d..afa295bc5 100644
--- a/__snapshots__/conducting-equipment-editor wizarding integration.md
+++ b/__snapshots__/conducting-equipment-editor wizarding integration.md
@@ -5,15 +5,15 @@
```html
@@ -42,7 +42,7 @@
@@ -50,7 +50,7 @@
diff --git a/__snapshots__/conducting-equipment-editor.md b/__snapshots__/conducting-equipment-editor.md
index e959738dc..0b75dd8c7 100644
--- a/__snapshots__/conducting-equipment-editor.md
+++ b/__snapshots__/conducting-equipment-editor.md
@@ -38,3 +38,19 @@
```
+## `with readonly property`
+
+#### `looks like the latest snapshot`
+
+```html
+
+
+
+ QA1
+
+
+```
+
diff --git a/__snapshots__/open-scd.md b/__snapshots__/open-scd.md
index 9cd35d1a2..e8ad2c20d 100644
--- a/__snapshots__/open-scd.md
+++ b/__snapshots__/open-scd.md
@@ -982,6 +982,10 @@
+
+
+
+
@@ -26,7 +26,7 @@
@@ -34,7 +34,7 @@
diff --git a/__snapshots__/substation-editor.md b/__snapshots__/substation-editor.md
index 915b44c92..193e27afa 100644
--- a/__snapshots__/substation-editor.md
+++ b/__snapshots__/substation-editor.md
@@ -33,3 +33,20 @@
```
+## `with readonly property`
+
+#### `looks like the latest snapshot`
+
+```html
+
+
+ AA1 — Substation
+
+
+
+
+
+
+
+```
+
diff --git a/__snapshots__/voltage-level-editor wizarding integration.md b/__snapshots__/voltage-level-editor wizarding integration.md
index 9aea6ff40..1aea3e20b 100644
--- a/__snapshots__/voltage-level-editor wizarding integration.md
+++ b/__snapshots__/voltage-level-editor wizarding integration.md
@@ -5,36 +5,36 @@
```html
@@ -66,7 +66,7 @@
diff --git a/__snapshots__/voltage-level-editor.md b/__snapshots__/voltage-level-editor.md
index 4c6ea782b..991571476 100644
--- a/__snapshots__/voltage-level-editor.md
+++ b/__snapshots__/voltage-level-editor.md
@@ -44,3 +44,23 @@
```
+## `with readonly property`
+
+#### `looks like the latest snapshot`
+
+```html
+
+
+ E1 — Voltage Level
+ (110.0 kV)
+
+
+
+
+
+
+
+
+
+```
+
diff --git a/__snapshots__/zeroline-pane.md b/__snapshots__/zeroline-pane.md
new file mode 100644
index 000000000..8badf995d
--- /dev/null
+++ b/__snapshots__/zeroline-pane.md
@@ -0,0 +1,86 @@
+# `zeroline-pane`
+
+#### `per default looks like the latest snapshot`
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+#### `readonly looks like the latest snapshot`
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+#### `showieds looks like the latest snapshot`
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
diff --git a/src/Setting.ts b/src/Setting.ts
index 74c3de4fe..cb48ac5ca 100644
--- a/src/Setting.ts
+++ b/src/Setting.ts
@@ -13,11 +13,13 @@ export type Settings = {
language: Language;
theme: 'light' | 'dark';
mode: 'safe' | 'pro';
+ showieds: 'on' | 'off';
};
export const defaults: Settings = {
language: 'en',
theme: 'light',
mode: 'safe',
+ showieds: 'off',
};
/** Mixin that saves [[`Settings`]] to `localStorage`, reflecting them in the
@@ -33,6 +35,7 @@ export function Setting(Base: TBase) {
language: this.getSetting('language'),
theme: this.getSetting('theme'),
mode: this.getSetting('mode'),
+ showieds: this.getSetting('showieds'),
};
}
@@ -44,6 +47,8 @@ export function Setting(Base: TBase) {
darkThemeUI!: Switch;
@query('#mode')
modeUI!: Switch;
+ @query('#showieds')
+ showiedsUI!: Switch;
private getSetting(setting: T): Settings[T] {
return (
@@ -69,6 +74,7 @@ export function Setting(Base: TBase) {
this.setSetting('language', this.languageUI.value);
this.setSetting('theme', this.darkThemeUI.checked ? 'dark' : 'light');
this.setSetting('mode', this.modeUI.checked ? 'pro' : 'safe');
+ this.setSetting('showieds', this.showiedsUI.checked ? 'on' : 'off');
this.requestUpdate('settings');
}
}
@@ -121,6 +127,12 @@ export function Setting(Base: TBase) {
?checked=${this.settings.mode === 'pro'}
>
+
+
+
${translate('cancel')}
diff --git a/src/editors/Substation.ts b/src/editors/Substation.ts
index 09d58916c..2d0d71b70 100644
--- a/src/editors/Substation.ts
+++ b/src/editors/Substation.ts
@@ -1,13 +1,10 @@
import { LitElement, html, TemplateResult, property, css } from 'lit-element';
-import { translate, get } from 'lit-translate';
+import { get } from 'lit-translate';
import { newWizardEvent } from '../foundation.js';
import { wizards } from '../wizards/wizard-library.js';
-import { selectors, styles } from './substation/foundation.js';
-
-import './substation/substation-editor.js';
-import { SubstationEditor } from './substation/substation-editor.js';
+import '../zeroline-pane.js';
/** An editor [[`plugin`]] for editing the `Substation` section. */
export default class SubstationPlugin extends LitElement {
@@ -22,29 +19,20 @@ export default class SubstationPlugin extends LitElement {
}
render(): TemplateResult {
- if (!this.doc?.querySelector(selectors.Substation))
- return html`
- ${translate('substation.missing')}
- this.openCreateSubstationWizard()}
- >
-
`;
- return html`
- ${Array.from(this.doc.querySelectorAll(selectors.Substation) ?? []).map(
- substation =>
- html``
- )}
- `;
+ return html`
+ ${!this.doc?.querySelector(':root > Substation')
+ ? html`
+ this.openCreateSubstationWizard()}
+ >
+
`
+ : html``}`;
}
static styles = css`
- ${styles}
-
mwc-fab {
position: fixed;
bottom: 32px;
diff --git a/src/editors/substation/bay-editor.ts b/src/editors/substation/bay-editor.ts
deleted file mode 100644
index fd61562b6..000000000
--- a/src/editors/substation/bay-editor.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import {
- css,
- customElement,
- html,
- LitElement,
- property,
- TemplateResult,
-} from 'lit-element';
-import { translate } from 'lit-translate';
-
-import { newActionEvent, newWizardEvent } from '../../foundation.js';
-
-import { startMove, styles, cloneElement } from './foundation.js';
-import './conducting-equipment-editor.js';
-import { VoltageLevelEditor } from './voltage-level-editor.js';
-import { wizards } from '../../wizards/wizard-library.js';
-
-/** [[`SubstationEditor`]] subeditor for a `Bay` element. */
-@customElement('bay-editor')
-export class BayEditor extends LitElement {
- @property({ attribute: false })
- element!: Element;
-
- @property({ type: String })
- get name(): string {
- return this.element.getAttribute('name') ?? '';
- }
- @property({ type: String })
- get desc(): string | null {
- return this.element.getAttribute('desc') ?? null;
- }
-
- openEditWizard(): void {
- const wizard = wizards['Bay'].edit(this.element);
- if (wizard) this.dispatchEvent(newWizardEvent(wizard));
- }
-
- openConductingEquipmentWizard(): void {
- const wizard = wizards['ConductingEquipment'].create(this.element);
- if (wizard) this.dispatchEvent(newWizardEvent(wizard));
- }
-
- /** Opens a [[`WizardDialog`]] for editing `LNode` connections. */
- openLNodeWizard(): void {
- const wizard = wizards['LNode'].edit(this.element);
- if (wizard) this.dispatchEvent(newWizardEvent(wizard));
- }
-
- remove(): void {
- if (this.element)
- this.dispatchEvent(
- newActionEvent({
- old: {
- parent: this.element.parentElement!,
- element: this.element,
- reference: this.element.nextSibling,
- },
- })
- );
- }
-
- renderHeader(): TemplateResult {
- return html`
- ${this.name} ${this.desc === null ? '' : html`—`} ${this.desc}
-
- this.openConductingEquipmentWizard()}
- >
-
-
-
`;
- }
-
- render(): TemplateResult {
- return html`
- ${this.renderHeader()}
-
- ${Array.from(
- this.element?.querySelectorAll(
- ':root > Substation > VoltageLevel > Bay > ConductingEquipment'
- ) ?? []
- ).map(
- voltageLevel =>
- html``
- )}
-
- `;
- }
-
- static styles = css`
- ${styles}
-
- section {
- margin: 0px;
- }
-
- #ceContainer {
- display: grid;
- grid-gap: 12px;
- padding: 12px;
- box-sizing: border-box;
- grid-template-columns: repeat(auto-fit, minmax(64px, auto));
- }
- `;
-}
diff --git a/src/editors/substation/conducting-equipment-types.ts b/src/editors/substation/conducting-equipment-types.ts
deleted file mode 100644
index 0a3c3670a..000000000
--- a/src/editors/substation/conducting-equipment-types.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { TemplateResult } from 'lit-html';
-
-import {
- disconnectorIcon,
- circuitBreakerIcon,
- currentTransformerIcon,
- earthSwitchIcon,
- generalConductingEquipmentIcon,
- voltageTransformerIcon,
-} from '../../icons.js';
-
-function typeStr(condEq: Element): string {
- return condEq.getAttribute('type') === 'DIS' &&
- condEq.querySelector('Terminal')?.getAttribute('cNodeName') === 'grounded'
- ? 'ERS'
- : condEq.getAttribute('type') ?? '';
-}
-
-const typeIcons: Partial> = {
- CBR: circuitBreakerIcon,
- DIS: disconnectorIcon,
- CTR: currentTransformerIcon,
- VTR: voltageTransformerIcon,
- ERS: earthSwitchIcon,
-};
-
-export function typeIcon(condEq: Element): TemplateResult {
- return typeIcons[typeStr(condEq)] ?? generalConductingEquipmentIcon;
-}
diff --git a/src/translations/de.ts b/src/translations/de.ts
index 399a93f60..a33e9bf94 100644
--- a/src/translations/de.ts
+++ b/src/translations/de.ts
@@ -33,6 +33,7 @@ export const de: Translations = {
languages: { de: 'Deutsch', en: 'Englisch (English)' },
dark: 'Dunkles Design',
mode: 'Profimodus',
+ showieds: 'Zeige IEDs im Substation-Editor',
},
menu: {
title: 'Menü',
@@ -44,6 +45,10 @@ export const de: Translations = {
readError: '{{ name }} Lesefehler',
readAbort: '{{ name }} Leseabbruch',
},
+ zeroline: {
+ iedsloading: 'IEDs werden geladen...',
+ showieds: 'IEDs anzeigen/ausblenden',
+ },
editing: {
created: '{{ name }} hinzugefügt',
deleted: '{{ name }} entfernt',
diff --git a/src/translations/en.ts b/src/translations/en.ts
index 4505dcd8a..ce03e3367 100644
--- a/src/translations/en.ts
+++ b/src/translations/en.ts
@@ -31,6 +31,7 @@ export const en = {
languages: { de: 'German (Deutsch)', en: 'English' },
dark: 'Dark theme',
mode: 'Pro mode',
+ showieds: 'Show IEDs in substation editor',
},
menu: {
title: 'Menu',
@@ -42,6 +43,10 @@ export const en = {
readError: 'Error reading {{ name }}',
readAbort: 'Aborted reading {{ name }}',
},
+ zeroline: {
+ iedsloading: 'Loading IEDs...',
+ showieds: 'Display/hide IEDs',
+ },
editing: {
created: 'Added {{ name }}',
deleted: 'Removed {{ name }}',
diff --git a/src/wizards/bay.ts b/src/wizards/bay.ts
index 94a0628c9..19cbe8a2c 100644
--- a/src/wizards/bay.ts
+++ b/src/wizards/bay.ts
@@ -1,6 +1,5 @@
import { html, TemplateResult } from 'lit-html';
import { get, translate } from 'lit-translate';
-import { updateNamingAction } from '../editors/substation/foundation.js';
import {
createElement,
@@ -12,6 +11,8 @@ import {
WizardInput,
} from '../foundation.js';
+import { updateNamingAction } from '../zeroline/foundation.js';
+
function render(name: string | null, desc: string | null): TemplateResult[] {
return [
html` {
const name = getValue(inputs.find(i => i.label === 'name')!);
const desc = getValue(inputs.find(i => i.label === 'desc')!);
diff --git a/src/wizards/substation.ts b/src/wizards/substation.ts
index 69108616d..a5055dcce 100644
--- a/src/wizards/substation.ts
+++ b/src/wizards/substation.ts
@@ -40,7 +40,7 @@ function render(
];
}
-function createAction(parent: Element): WizardActor {
+export function createAction(parent: Element): WizardActor {
return (inputs: WizardInput[], wizard: Element): EditorAction[] => {
const name = getValue(inputs.find(i => i.label === 'name')!);
const desc = getValue(inputs.find(i => i.label === 'desc')!);
@@ -69,6 +69,8 @@ function createAction(parent: Element): WizardActor {
}
export function substationCreateWizard(parent: Element): Wizard {
+ const guessable = parent.querySelector('Substation') === null;
+
return [
{
title: get('substation.wizard.title.add'),
@@ -78,7 +80,7 @@ export function substationCreateWizard(parent: Element): Wizard {
label: get('add'),
action: createAction(parent),
},
- content: render('', '', true),
+ content: render('', '', guessable),
},
];
}
diff --git a/src/zeroline-pane.ts b/src/zeroline-pane.ts
new file mode 100644
index 000000000..a2be0e3a0
--- /dev/null
+++ b/src/zeroline-pane.ts
@@ -0,0 +1,116 @@
+import {
+ LitElement,
+ html,
+ TemplateResult,
+ property,
+ customElement,
+ css,
+} from 'lit-element';
+import { until } from 'lit-html/directives/until';
+import { translate } from 'lit-translate';
+
+import { isPublic, newWizardEvent } from './foundation.js';
+import { getAttachedIeds, styles } from './zeroline/foundation.js';
+
+import './zeroline/substation-editor.js';
+import './zeroline/ied-editor.js';
+import { Settings } from './Setting.js';
+import { wizards } from './wizards/wizard-library.js';
+
+function shouldShowIEDs(): boolean {
+ return localStorage.getItem('showieds') === 'on';
+}
+
+function setShowIEDs(value: Settings['showieds']) {
+ localStorage.setItem('showieds', value);
+}
+
+/** [[`Zeroline`]] pane for displaying `Substation` and/or `IED` sections. */
+@customElement('zeroline-pane')
+export class ZerolinePane extends LitElement {
+ /** The document being edited as provided to editor by [[`Zeroline`]]. */
+ @property({ attribute: false })
+ doc!: XMLDocument;
+ @property({ type: Boolean })
+ readonly = false;
+
+ @property({ attribute: false })
+ getAttachedIeds?: (element: Element) => Promise = async () => [];
+
+ /** Opens a [[`WizardDialog`]] for creating a new `Substation` element. */
+ openCreateSubstationWizard(): void {
+ const wizard = wizards['Substation'].create(this.doc.documentElement);
+ if (wizard) this.dispatchEvent(newWizardEvent(wizard));
+ }
+
+ toggleShowIEDs(): void {
+ console.warn(shouldShowIEDs());
+ if (shouldShowIEDs()) setShowIEDs('off');
+ else setShowIEDs('on');
+ console.log(shouldShowIEDs());
+ this.requestUpdate();
+ }
+
+ async renderIedContainer(): Promise {
+ this.getAttachedIeds = shouldShowIEDs()
+ ? getAttachedIeds(this.doc)
+ : async () => [];
+ const ieds = await this.getAttachedIeds?.(this.doc.documentElement);
+
+ await new Promise(requestAnimationFrame);
+ return ieds.length
+ ? html`
+ ${ieds.map(ied => html``)}
+
`
+ : html``;
+ }
+
+ render(): TemplateResult {
+ return html`
+
+ ${html`
+ this.openCreateSubstationWizard()}
+ >
+ `}
+
+
+
+ ${until(this.renderIedContainer(), html`loading ieds...`)}
+ ${
+ this.doc?.querySelector(':root > Substation')
+ ? html`
+ ${Array.from(this.doc.querySelectorAll('Substation') ?? [])
+ .filter(isPublic)
+ .map(
+ substation =>
+ html``
+ )}
+ `
+ : html`
+ ${translate('substation.missing')}
+
`
+ }`;
+ }
+
+ static styles = css`
+ ${styles}
+ `;
+}
diff --git a/src/zeroline/bay-editor.ts b/src/zeroline/bay-editor.ts
new file mode 100644
index 000000000..01b358662
--- /dev/null
+++ b/src/zeroline/bay-editor.ts
@@ -0,0 +1,166 @@
+import {
+ css,
+ customElement,
+ html,
+ LitElement,
+ property,
+ TemplateResult,
+} from 'lit-element';
+import { until } from 'lit-html/directives/until';
+import { translate } from 'lit-translate';
+
+import { startMove, styles, cloneElement } from './foundation.js';
+import { newActionEvent, newWizardEvent } from '../foundation.js';
+
+import { wizards } from '../wizards/wizard-library.js';
+
+import { VoltageLevelEditor } from './voltage-level-editor.js';
+import './conducting-equipment-editor.js';
+
+/** [[`SubstationEditor`]] subeditor for a `Bay` element. */
+@customElement('bay-editor')
+export class BayEditor extends LitElement {
+ @property({ attribute: false })
+ element!: Element;
+ @property({ type: Boolean })
+ readonly = false;
+
+ @property({ type: String })
+ get name(): string {
+ return this.element.getAttribute('name') ?? '';
+ }
+ @property({ type: String })
+ get desc(): string | null {
+ return this.element.getAttribute('desc') ?? null;
+ }
+
+ @property({ attribute: false })
+ getAttachedIeds?: (element: Element) => Promise = async () => {
+ return [];
+ };
+
+ openEditWizard(): void {
+ const wizard = wizards['Bay'].edit(this.element);
+ if (wizard) this.dispatchEvent(newWizardEvent(wizard));
+ }
+
+ openConductingEquipmentWizard(): void {
+ const wizard = wizards['ConductingEquipment'].create(this.element);
+ if (wizard) this.dispatchEvent(newWizardEvent(wizard));
+ }
+
+ /** Opens a [[`WizardDialog`]] for editing `LNode` connections. */
+ openLNodeWizard(): void {
+ const wizard = wizards['LNode'].edit(this.element);
+ if (wizard) this.dispatchEvent(newWizardEvent(wizard));
+ }
+
+ remove(): void {
+ if (this.element)
+ this.dispatchEvent(
+ newActionEvent({
+ old: {
+ parent: this.element.parentElement!,
+ element: this.element,
+ reference: this.element.nextSibling,
+ },
+ })
+ );
+ }
+
+ async renderIedContainer(): Promise {
+ const ieds = await this.getAttachedIeds?.(this.element);
+ return ieds?.length
+ ? html`
+ ${ieds.map(ied => html``)}
+
`
+ : html``;
+ }
+
+ renderHeader(): TemplateResult {
+ return html`
+ ${this.name} ${this.desc === null ? '' : html`—`} ${this.desc}
+ ${this.readonly
+ ? html``
+ : html`
+ this.openConductingEquipmentWizard()}
+ >
+
+ `}
+
`;
+ }
+
+ render(): TemplateResult {
+ return html`
+ ${this.renderHeader()}
+
+ ${until(
+ this.renderIedContainer(),
+ html`
${translate('zeroline.iedsloading')}`
+ )}
+
+ ${Array.from(
+ this.element?.querySelectorAll(
+ ':root > Substation > VoltageLevel > Bay > ConductingEquipment'
+ ) ?? []
+ ).map(
+ voltageLevel =>
+ html``
+ )}
+
+
+ `;
+ }
+
+ static styles = css`
+ ${styles}
+
+ section {
+ margin: 0px;
+ }
+
+ #ceContainer {
+ display: grid;
+ grid-gap: 12px;
+ padding: 12px;
+ box-sizing: border-box;
+ grid-template-columns: repeat(auto-fit, minmax(64px, auto));
+ }
+ `;
+}
diff --git a/src/editors/substation/conducting-equipment-editor.ts b/src/zeroline/conducting-equipment-editor.ts
similarity index 67%
rename from src/editors/substation/conducting-equipment-editor.ts
rename to src/zeroline/conducting-equipment-editor.ts
index 7a218e52a..2f51d3100 100644
--- a/src/editors/substation/conducting-equipment-editor.ts
+++ b/src/zeroline/conducting-equipment-editor.ts
@@ -7,14 +7,39 @@ import {
TemplateResult,
} from 'lit-element';
-import { newActionEvent, newWizardEvent } from '../../foundation.js';
-
import { startMove } from './foundation.js';
+import { newActionEvent, newWizardEvent } from '../foundation.js';
+
+import {
+ circuitBreakerIcon,
+ currentTransformerIcon,
+ disconnectorIcon,
+ earthSwitchIcon,
+ generalConductingEquipmentIcon,
+ voltageTransformerIcon,
+} from '../icons.js';
+
import { BayEditor } from './bay-editor.js';
+import { wizards } from '../wizards/wizard-library.js';
+
+function typeStr(condEq: Element): string {
+ return condEq.getAttribute('type') === 'DIS' &&
+ condEq.querySelector('Terminal')?.getAttribute('cNodeName') === 'grounded'
+ ? 'ERS'
+ : condEq.getAttribute('type') ?? '';
+}
-import { typeIcon } from './conducting-equipment-types.js';
+const typeIcons: Partial> = {
+ CBR: circuitBreakerIcon,
+ DIS: disconnectorIcon,
+ CTR: currentTransformerIcon,
+ VTR: voltageTransformerIcon,
+ ERS: earthSwitchIcon,
+};
-import { wizards } from '../../wizards/wizard-library.js';
+export function typeIcon(condEq: Element): TemplateResult {
+ return typeIcons[typeStr(condEq)] ?? generalConductingEquipmentIcon;
+}
/** [[`SubstationEditor`]] subeditor for a `ConductingEquipment` element. */
@customElement('conducting-equipment-editor')
@@ -22,14 +47,13 @@ export class ConductingEquipmentEditor extends LitElement {
@property({ type: Element })
element!: Element;
+ @property({ type: Boolean })
+ readonly = false;
+
@property({ type: String })
get name(): string {
return this.element.getAttribute('name') ?? '';
}
- @property({ type: String })
- get desc(): string {
- return this.element.getAttribute('desc') ?? '';
- }
openEditWizard(): void {
const wizard = wizards['ConductingEquipment'].edit(this.element);
@@ -59,31 +83,33 @@ export class ConductingEquipmentEditor extends LitElement {
return html`
${typeIcon(this.element)}
-
-
-
-
+ ${this.readonly
+ ? html``
+ : html`
+
+
+ `}
${this.name}
`;
diff --git a/src/editors/substation/foundation.ts b/src/zeroline/foundation.ts
similarity index 69%
rename from src/editors/substation/foundation.ts
rename to src/zeroline/foundation.ts
index bcc697e06..39918bc1e 100644
--- a/src/editors/substation/foundation.ts
+++ b/src/zeroline/foundation.ts
@@ -6,28 +6,105 @@ import {
newActionEvent,
WizardActor,
WizardInput,
-} from '../../foundation.js';
-import { VoltageLevelEditor } from './voltage-level-editor.js';
+ isPublic,
+} from '../foundation.js';
+
import { BayEditor } from './bay-editor.js';
+import { VoltageLevelEditor } from './voltage-level-editor.js';
-export type ElementEditor = Element & {
- element: Element;
-};
+function containsReference(element: Element, iedName: string): boolean {
+ return Array.from(element.getElementsByTagName('LNode'))
+ .filter(isPublic)
+ .some(lnode => lnode.getAttribute('iedName') === iedName);
+}
-interface UpdateOptions {
- element: Element;
+function isReferencedItself(element: Element, iedName: string): boolean {
+ return (Array.from(element.children)).some(
+ child =>
+ child.tagName === 'LNode' && child.getAttribute('iedName') === iedName
+ );
+}
+
+function hasReferencedChildren(element: Element, iedName: string): boolean {
+ const threshold = element.tagName === 'Bay' ? 0 : 1;
+ return (
+ (Array.from(element.children)).filter(child =>
+ containsReference(child, iedName)
+ ).length > threshold
+ );
+}
+
+function hasOurs(element: Element, iedName: string): boolean {
+ return Array.from(element.getElementsByTagName('LNode'))
+ .filter(isPublic)
+ .some(lnode => lnode.getAttribute('iedName') === iedName);
+}
+
+function getOurs(element: Element, iedName: string): Element[] {
+ return Array.from(element.getElementsByTagName('LNode'))
+ .filter(isPublic)
+ .filter(lnode => lnode.getAttribute('iedName') === iedName);
+}
+
+function hasTheirs(element: Element, iedName: string): boolean {
+ const ours = getOurs(element, iedName);
+ const scl = element.closest('SCL')!;
+
+ return Array.from(scl.getElementsByTagName('LNode'))
+ .filter(isPublic)
+ .filter(lnode => lnode.getAttribute('iedName') === iedName)
+ .some(lnode => !ours.includes(lnode));
}
-interface CreateOptions {
- parent: Element;
+
+export async function attachedIeds(
+ element: Element,
+ remainingIeds: Set
+): Promise {
+ await new Promise(requestAnimationFrame);
+
+ const attachedIeds: Element[] = [];
+ for (const ied of remainingIeds) {
+ const iedName = ied.getAttribute('name')!;
+
+ if (element.tagName === 'SCL') {
+ if (!hasOurs(element, iedName) || hasReferencedChildren(element, iedName))
+ attachedIeds.push(ied);
+
+ continue;
+ }
+
+ if (hasTheirs(element, iedName)) continue;
+ if (
+ hasReferencedChildren(element, iedName) ||
+ isReferencedItself(element, iedName)
+ )
+ attachedIeds.push(ied);
+ }
+
+ for (const ied of attachedIeds) {
+ remainingIeds.delete(ied);
+ }
+
+ return attachedIeds;
}
-export type WizardOptions = UpdateOptions | CreateOptions;
-export function isCreateOptions(
- options: WizardOptions
-): options is CreateOptions {
- return (options).parent !== undefined;
+export function getAttachedIeds(
+ doc: XMLDocument
+): (element: Element) => Promise {
+ return async (element: Element) => {
+ const ieds = new Set(
+ Array.from(doc.querySelectorAll('IED')).filter(isPublic)
+ );
+ await new Promise(requestAnimationFrame);
+
+ return await attachedIeds(element, ieds);
+ };
}
+export type ElementEditor = Element & {
+ element: Element;
+};
+
export function updateNamingAction(element: Element): WizardActor {
return (inputs: WizardInput[]): EditorAction[] => {
const name = getValue(inputs.find(i => i.label === 'name')!)!;
@@ -241,4 +318,12 @@ export const styles = css`
text-decoration: none;
border-bottom: none;
}
+
+ #iedcontainer {
+ display: grid;
+ grid-gap: 12px;
+ padding: 8px 12px 16px;
+ box-sizing: border-box;
+ grid-template-columns: repeat(auto-fit, minmax(64px, auto));
+ }
`;
diff --git a/src/zeroline/ied-editor.ts b/src/zeroline/ied-editor.ts
new file mode 100644
index 000000000..cb51cf791
--- /dev/null
+++ b/src/zeroline/ied-editor.ts
@@ -0,0 +1,135 @@
+import {
+ css,
+ customElement,
+ html,
+ LitElement,
+ property,
+ TemplateResult,
+} from 'lit-element';
+import { newActionEvent } from '../foundation.js';
+
+/** [[`SubstationEditor`]] subeditor for a `ConductingEquipment` element. */
+@customElement('ied-editor')
+export class IedEditor extends LitElement {
+ @property({ type: Element })
+ element!: Element;
+
+ @property({ type: String })
+ get name(): string {
+ return this.element.getAttribute('name') ?? '';
+ }
+
+ render(): TemplateResult {
+ return html`
+
+ developer_board
+
+ ${this.name}
+ `;
+ }
+
+ static styles = css`
+ #container {
+ color: var(--mdc-theme-on-surface);
+ width: 50px;
+ height: 50px;
+ margin: auto;
+ position: relative;
+ transition: all 200ms linear;
+ }
+
+ #container:focus {
+ outline: none;
+ }
+
+ .icon {
+ color: var(--mdc-theme-on-surface);
+ --mdc-icon-size: 50px;
+ transition: transform 150ms linear, box-shadow 200ms linear;
+ outline-color: var(--mdc-theme-primary);
+ outline-style: solid;
+ outline-width: 0px;
+ }
+
+ #container > .icon {
+ color: var(--mdc-theme-on-surface);
+ width: 50px;
+ height: 50px;
+ transition: transform 150ms linear, box-shadow 200ms linear;
+ outline-color: var(--mdc-theme-primary);
+ outline-style: solid;
+ outline-width: 0px;
+ }
+
+ #container:focus > .icon {
+ box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
+ 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);
+ }
+
+ #container:hover > .icom {
+ outline: 2px dashed var(--mdc-theme-primary);
+ transition: transform 200ms linear, box-shadow 250ms linear;
+ }
+
+ #container:focus-within > .icon {
+ outline: 2px solid var(--mdc-theme-primary);
+ background: var(--mdc-theme-on-primary);
+ transform: scale(0.8);
+ transition: transform 200ms linear, box-shadow 250ms linear;
+ }
+
+ .menu-item {
+ color: var(--mdc-theme-on-surface);
+ transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1),
+ opacity 200ms linear;
+ position: absolute;
+ top: 8px;
+ left: 8px;
+ pointer-events: none;
+ z-index: 1;
+ opacity: 0;
+ }
+
+ #container:focus-within > .menu-item {
+ transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
+ opacity 250ms linear;
+ pointer-events: auto;
+ opacity: 1;
+ }
+
+ #container:focus-within > .menu-item.up {
+ transform: translate(0px, -52px);
+ }
+
+ #container:focus-within > .menu-item.down {
+ transform: translate(0px, 52px);
+ }
+
+ #container:focus-within > .menu-item.right {
+ transform: translate(52px, 0px);
+ }
+
+ #container:focus-within > .menu-item.left {
+ transform: translate(-52px, 0px);
+ }
+
+ h4 {
+ color: var(--mdc-theme-on-surface);
+ font-family: 'Roboto', sans-serif;
+ font-weight: 300;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ margin: 0px;
+ opacity: 1;
+ transition: opacity 200ms linear;
+ text-align: center;
+ direction: rtl;
+ }
+
+ :host(.moving) #container,
+ :host(.moving) h4 {
+ opacity: 0.3;
+ }
+ `;
+}
diff --git a/src/editors/substation/substation-editor.ts b/src/zeroline/substation-editor.ts
similarity index 51%
rename from src/editors/substation/substation-editor.ts
rename to src/zeroline/substation-editor.ts
index 012347a7c..eb8ffbe62 100644
--- a/src/editors/substation/substation-editor.ts
+++ b/src/zeroline/substation-editor.ts
@@ -6,20 +6,23 @@ import {
property,
TemplateResult,
} from 'lit-element';
+import { until } from 'lit-html/directives/until';
import { translate } from 'lit-translate';
-
-import { newActionEvent, newWizardEvent } from '../../foundation.js';
+import { newActionEvent, newWizardEvent } from '../foundation.js';
+import { wizards } from '../wizards/wizard-library.js';
import { selectors, styles } from './foundation.js';
import './voltage-level-editor.js';
-import { wizards } from '../../wizards/wizard-library.js';
+
/** [[`Substation`]] plugin subeditor for editing `Substation` sections. */
@customElement('substation-editor')
export class SubstationEditor extends LitElement {
/** The edited `Element`, a common property of all Substation subeditors. */
@property({ attribute: false })
element!: Element;
+ @property({ type: Boolean })
+ readonly = false;
/** [[element | `element.name`]] */
@property({ type: String })
@@ -32,6 +35,11 @@ export class SubstationEditor extends LitElement {
return this.element.getAttribute('desc');
}
+ @property({ attribute: false })
+ getAttachedIeds?: (element: Element) => Promise = async () => {
+ return [];
+ };
+
/** Opens a [[`WizardDialog`]] for editing [[`element`]]. */
openEditWizard(): void {
const wizard = wizards['Substation'].edit(this.element);
@@ -63,48 +71,68 @@ export class SubstationEditor extends LitElement {
);
}
+ async renderIedContainer(): Promise {
+ const ieds = await this.getAttachedIeds?.(this.element);
+ return ieds?.length
+ ? html`
+ ${ieds.map(ied => html``)}
+
`
+ : html``;
+ }
+
renderHeader(): TemplateResult {
return html`
-
- ${this.name} ${this.desc === null ? '' : html`—`} ${this.desc}
-
- this.openVoltageLevelWizard()}
- >
-
-
-
- `;
+
+ ${this.name} ${this.desc === null ? '' : html`—`} ${this.desc}
+ ${
+ this.readonly
+ ? html``
+ : html`
+ this.openVoltageLevelWizard()}
+ >
+
+ `
+ }
+
+
+ `;
}
render(): TemplateResult {
return html`
${this.renderHeader()}
+ ${until(
+ this.renderIedContainer(),
+ html`${translate('zeroline.iedsloading')}`
+ )}
${Array.from(this.element.querySelectorAll(selectors.VoltageLevel)).map(
voltageLevel =>
html``
)}
diff --git a/src/editors/substation/voltage-level-editor.ts b/src/zeroline/voltage-level-editor.ts
similarity index 52%
rename from src/editors/substation/voltage-level-editor.ts
rename to src/zeroline/voltage-level-editor.ts
index c67f106d7..a7b7a6637 100644
--- a/src/editors/substation/voltage-level-editor.ts
+++ b/src/zeroline/voltage-level-editor.ts
@@ -8,18 +8,20 @@ import {
} from 'lit-element';
import { translate } from 'lit-translate';
-import { newActionEvent, newWizardEvent } from '../../foundation.js';
-
import { selectors, startMove, styles, cloneElement } from './foundation.js';
import './bay-editor.js';
import { SubstationEditor } from './substation-editor.js';
-import { wizards } from '../../wizards/wizard-library.js';
+import { wizards } from '../wizards/wizard-library.js';
+import { newActionEvent, newWizardEvent } from '../foundation.js';
+import { until } from 'lit-html/directives/until';
/** [[`Substation`]] subeditor for a `VoltageLevel` element. */
@customElement('voltage-level-editor')
export class VoltageLevelEditor extends LitElement {
@property()
element!: Element;
+ @property({ type: Boolean })
+ readonly = false;
@property()
get name(): string {
@@ -39,6 +41,11 @@ export class VoltageLevelEditor extends LitElement {
return v ? v + u : null;
}
+ @property({ attribute: false })
+ getAttachedIeds?: (element: Element) => Promise = async () => {
+ return [];
+ };
+
openEditWizard(): void {
const wizard = wizards['VoltageLevel'].edit(this.element);
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
@@ -68,58 +75,77 @@ export class VoltageLevelEditor extends LitElement {
);
}
+ async renderIedContainer(): Promise {
+ const ieds = await this.getAttachedIeds?.(this.element);
+ return ieds?.length
+ ? html`
+ ${ieds.map(ied => html``)}
+
`
+ : html``;
+ }
+
renderHeader(): TemplateResult {
return html`
${this.name} ${this.desc === null ? '' : html`—`} ${this.desc}
${this.voltage === null ? '' : html`(${this.voltage})`}
-
- this.openBayWizard()}
- >
-
-
+ ${this.readonly
+ ? html``
+ : html`
+ this.openBayWizard()}
+ >
+
+ `}
`;
}
render(): TemplateResult {
return html`
${this.renderHeader()}
+ ${until(
+ this.renderIedContainer(),
+ html`${translate('zeroline.iedsloading')}`
+ )}
${Array.from(this.element?.querySelectorAll(selectors.Bay) ?? []).map(
- bay => html``
+ bay => html``
)}
`;
diff --git a/test/integration/editors/substation/Substation.test.ts b/test/integration/editors/Substation.test.ts
similarity index 84%
rename from test/integration/editors/substation/Substation.test.ts
rename to test/integration/editors/Substation.test.ts
index f969c4e1f..0324a7a9b 100644
--- a/test/integration/editors/substation/Substation.test.ts
+++ b/test/integration/editors/Substation.test.ts
@@ -1,9 +1,9 @@
import { html, fixture, expect } from '@open-wc/testing';
-import '../../../mock-wizard.js';
-import { Editing } from '../../../../src/Editing.js';
-import Substation from '../../../../src/editors/Substation.js';
-import { Wizarding, WizardingElement } from '../../../../src/Wizarding.js';
+import '../../mock-wizard.js';
+import { Editing } from '../../../src/Editing.js';
+import Substation from '../../../src/editors/Substation.js';
+import { Wizarding, WizardingElement } from '../../../src/Wizarding.js';
describe('Substation Plugin', () => {
customElements.define('substation-plugin', Wizarding(Editing(Substation)));
@@ -29,8 +29,8 @@ describe('Substation Plugin', () => {
html``
);
});
- it('constains a substation-editor rendering the substation section', () => {
- expect(element.shadowRoot?.querySelector('substation-editor')).to.exist;
+ it('constains a zeroline-pane rendering the substation sections', () => {
+ expect(element.shadowRoot?.querySelector('zeroline-pane')).to.exist;
});
});
diff --git a/test/integration/editors/substation/guess-wizarding-editing.test.ts b/test/integration/editors/substation/guess-wizarding-editing.test.ts
index 201a1f1f7..b893c0e88 100644
--- a/test/integration/editors/substation/guess-wizarding-editing.test.ts
+++ b/test/integration/editors/substation/guess-wizarding-editing.test.ts
@@ -1,13 +1,14 @@
import { expect, fixture, html } from '@open-wc/testing';
import '../../../mock-wizard-editor.js';
+import '../../../mock-wizard.js';
import '@material/mwc-list/mwc-check-list-item';
import '@material/mwc-list/mwc-list';
-import '../../../mock-wizard.js';
+
+import { EditingElement } from '../../../../src/Editing.js';
import { MockWizard } from '../../../mock-wizard.js';
import { guessVoltageLevel } from '../../../../src/editors/substation/guess-wizard.js';
-import { EditingElement } from '../../../../src/Editing.js';
import { WizardingElement } from '../../../../src/Wizarding.js';
describe('guess-wizard-integration', () => {
diff --git a/test/integration/editors/substation/bay-editor-wizarding-editing.test.ts b/test/integration/zeroline/bay-editor-wizarding-editing.test.ts
similarity index 97%
rename from test/integration/editors/substation/bay-editor-wizarding-editing.test.ts
rename to test/integration/zeroline/bay-editor-wizarding-editing.test.ts
index 312b81ca9..96b84d16c 100644
--- a/test/integration/editors/substation/bay-editor-wizarding-editing.test.ts
+++ b/test/integration/zeroline/bay-editor-wizarding-editing.test.ts
@@ -1,12 +1,12 @@
import { fixture, html, expect } from '@open-wc/testing';
-import '../../../mock-wizard-editor.js';
-import { BayEditor } from '../../../../src/editors/substation/bay-editor.js';
-import { EditingElement } from '../../../../src/Editing.js';
-import { WizardingElement } from '../../../../src/Wizarding.js';
+import '../../mock-wizard-editor.js';
-import { WizardTextField } from '../../../../src/wizard-textfield.js';
+import { BayEditor } from '../../../src/zeroline/bay-editor.js';
+import { EditingElement } from '../../../src/Editing.js';
import { Select } from '@material/mwc-select';
+import { WizardingElement } from '../../../src/Wizarding.js';
+import { WizardTextField } from '../../../src/wizard-textfield.js';
describe('bay-editor wizarding editing integration', () => {
describe('edit wizard', () => {
diff --git a/test/integration/editors/substation/bay-editor-wizarding.test.ts b/test/integration/zeroline/bay-editor-wizarding.test.ts
similarity index 92%
rename from test/integration/editors/substation/bay-editor-wizarding.test.ts
rename to test/integration/zeroline/bay-editor-wizarding.test.ts
index ddf3c8d64..cd8279f10 100644
--- a/test/integration/editors/substation/bay-editor-wizarding.test.ts
+++ b/test/integration/zeroline/bay-editor-wizarding.test.ts
@@ -1,10 +1,10 @@
import { fixture, html, expect } from '@open-wc/testing';
import fc from 'fast-check';
-import '../../../mock-wizard.js';
-import { WizardingElement } from '../../../../src/Wizarding.js';
+import { regExp, regexString } from '../../foundation.js';
+import '../../mock-wizard.js';
-import { regexString, regExp } from '../../../foundation.js';
+import { WizardingElement } from '../../../src/Wizarding.js';
describe('bay-editor wizarding integration', () => {
let doc: XMLDocument;
diff --git a/test/integration/editors/substation/conducting-equipment-editor-wizarding-editing.test.ts b/test/integration/zeroline/conducting-equipment-editor-wizarding-editing.test.ts
similarity index 95%
rename from test/integration/editors/substation/conducting-equipment-editor-wizarding-editing.test.ts
rename to test/integration/zeroline/conducting-equipment-editor-wizarding-editing.test.ts
index cc776f3c6..930181cfa 100644
--- a/test/integration/editors/substation/conducting-equipment-editor-wizarding-editing.test.ts
+++ b/test/integration/zeroline/conducting-equipment-editor-wizarding-editing.test.ts
@@ -1,10 +1,10 @@
import { fixture, html, expect } from '@open-wc/testing';
-import '../../../mock-wizard-editor.js';
-import { ConductingEquipmentEditor } from '../../../../src/editors/substation/conducting-equipment-editor.js';
-import { EditingElement } from '../../../../src/Editing.js';
-import { WizardingElement } from '../../../../src/Wizarding.js';
-import { WizardTextField } from '../../../../src/wizard-textfield.js';
+import '../../mock-wizard-editor.js';
+import { EditingElement } from '../../../src/Editing.js';
+import { WizardingElement } from '../../../src/Wizarding.js';
+import { WizardTextField } from '../../../src/wizard-textfield.js';
+import { ConductingEquipmentEditor } from '../../../src/zeroline/conducting-equipment-editor.js';
describe('conducting-equipment-editor wizarding editing integration', () => {
describe('edit wizard', () => {
diff --git a/test/integration/editors/substation/conducting-equipment-editor-wizarding.test.ts b/test/integration/zeroline/conducting-equipment-editor-wizarding.test.ts
similarity index 93%
rename from test/integration/editors/substation/conducting-equipment-editor-wizarding.test.ts
rename to test/integration/zeroline/conducting-equipment-editor-wizarding.test.ts
index 464a4d0e9..69b052be1 100644
--- a/test/integration/editors/substation/conducting-equipment-editor-wizarding.test.ts
+++ b/test/integration/zeroline/conducting-equipment-editor-wizarding.test.ts
@@ -1,10 +1,10 @@
import { fixture, html, expect } from '@open-wc/testing';
import fc from 'fast-check';
-import '../../../mock-wizard.js';
-import { WizardingElement } from '../../../../src/Wizarding.js';
+import { regexString, regExp } from '../../foundation.js';
+import '../../mock-wizard.js';
-import { regexString, regExp } from '../../../foundation.js';
+import { WizardingElement } from '../../../src/Wizarding.js';
describe('conducting-equipment-editor wizarding integration', () => {
let doc: XMLDocument;
diff --git a/test/integration/editors/substation/substation-editor-wizarding-editing.test.ts b/test/integration/zeroline/substation-editor-wizarding-editing.test.ts
similarity index 95%
rename from test/integration/editors/substation/substation-editor-wizarding-editing.test.ts
rename to test/integration/zeroline/substation-editor-wizarding-editing.test.ts
index 95daeceb5..fded7ce2e 100644
--- a/test/integration/editors/substation/substation-editor-wizarding-editing.test.ts
+++ b/test/integration/zeroline/substation-editor-wizarding-editing.test.ts
@@ -1,11 +1,10 @@
import { fixture, html, expect } from '@open-wc/testing';
-import '../../../mock-wizard-editor.js';
-import { EditingElement } from '../../../../src/Editing.js';
-import { WizardingElement } from '../../../../src/Wizarding.js';
-
-import { SubstationEditor } from '../../../../src/editors/substation/substation-editor.js';
-import { WizardTextField } from '../../../../src/wizard-textfield.js';
+import '../../mock-wizard-editor.js';
+import { EditingElement } from '../../../src/Editing.js';
+import { SubstationEditor } from '../../../src/zeroline/substation-editor.js';
+import { WizardingElement } from '../../../src/Wizarding.js';
+import { WizardTextField } from '../../../src/wizard-textfield.js';
describe('substation-editor wizarding editing integration', () => {
describe('edit wizard', () => {
diff --git a/test/integration/editors/substation/substation-editor-wizarding.test.ts b/test/integration/zeroline/substation-editor-wizarding.test.ts
similarity index 92%
rename from test/integration/editors/substation/substation-editor-wizarding.test.ts
rename to test/integration/zeroline/substation-editor-wizarding.test.ts
index ebce0a955..2a0d2541e 100644
--- a/test/integration/editors/substation/substation-editor-wizarding.test.ts
+++ b/test/integration/zeroline/substation-editor-wizarding.test.ts
@@ -1,10 +1,9 @@
import { fixture, html, expect } from '@open-wc/testing';
import fc from 'fast-check';
+import { regExp, regexString } from '../../foundation.js';
-import '../../../mock-wizard.js';
-import { WizardingElement } from '../../../../src/Wizarding.js';
-
-import { regexString, regExp } from '../../../foundation.js';
+import '../../mock-wizard.js';
+import { WizardingElement } from '../../../src/Wizarding.js';
describe('substation-editor wizarding integration', () => {
let doc: XMLDocument;
diff --git a/test/integration/editors/substation/voltage-level-editor-wizarding-editing.test.ts b/test/integration/zeroline/voltage-level-editor-wizarding-editing.test.ts
similarity index 97%
rename from test/integration/editors/substation/voltage-level-editor-wizarding-editing.test.ts
rename to test/integration/zeroline/voltage-level-editor-wizarding-editing.test.ts
index 7435ad3e6..7730ad402 100644
--- a/test/integration/editors/substation/voltage-level-editor-wizarding-editing.test.ts
+++ b/test/integration/zeroline/voltage-level-editor-wizarding-editing.test.ts
@@ -1,11 +1,11 @@
import { fixture, html, expect } from '@open-wc/testing';
-import '../../../mock-wizard-editor.js';
-import { EditingElement } from '../../../../src/Editing.js';
-import { WizardingElement } from '../../../../src/Wizarding.js';
-import { VoltageLevelEditor } from '../../../../src/editors/substation/voltage-level-editor.js';
+import '../../mock-wizard-editor.js';
-import { WizardTextField } from '../../../../src/wizard-textfield.js';
+import { EditingElement } from '../../../src/Editing.js';
+import { VoltageLevelEditor } from '../../../src/zeroline/voltage-level-editor.js';
+import { WizardingElement } from '../../../src/Wizarding.js';
+import { WizardTextField } from '../../../src/wizard-textfield.js';
describe('voltage-level-editor wizarding editing integration', () => {
describe('edit wizard', () => {
diff --git a/test/integration/editors/substation/voltage-level-editor-wizarding.test.ts b/test/integration/zeroline/voltage-level-editor-wizarding.test.ts
similarity index 97%
rename from test/integration/editors/substation/voltage-level-editor-wizarding.test.ts
rename to test/integration/zeroline/voltage-level-editor-wizarding.test.ts
index ae62ace2d..1e0857c74 100644
--- a/test/integration/editors/substation/voltage-level-editor-wizarding.test.ts
+++ b/test/integration/zeroline/voltage-level-editor-wizarding.test.ts
@@ -1,10 +1,10 @@
import { fixture, html, expect } from '@open-wc/testing';
import fc from 'fast-check';
-import '../../../mock-wizard.js';
-import { WizardingElement } from '../../../../src/Wizarding.js';
+import '../../mock-wizard.js';
+import { WizardingElement } from '../../../src/Wizarding.js';
-import { regexString, regExp, inverseRegExp } from '../../../foundation.js';
+import { regexString, regExp, inverseRegExp } from '../../foundation.js';
describe('voltage-level-editor wizarding integration', () => {
let doc: XMLDocument;
diff --git a/test/testfiles/zeroline/iedalloctest.scd b/test/testfiles/zeroline/iedalloctest.scd
new file mode 100644
index 000000000..c6de2e96d
--- /dev/null
+++ b/test/testfiles/zeroline/iedalloctest.scd
@@ -0,0 +1,64 @@
+
+
+
+ TrainingIEC61850
+
+
+
+
+
+
+
+ 110.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/testfiles/zeroline/substationonly.scd b/test/testfiles/zeroline/substationonly.scd
new file mode 100644
index 000000000..b5d2a9a90
--- /dev/null
+++ b/test/testfiles/zeroline/substationonly.scd
@@ -0,0 +1,41 @@
+
+
+
+ TrainingIEC61850
+
+
+
+
+
+
+ 110.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
diff --git a/test/unit/zeroline-pane.test.ts b/test/unit/zeroline-pane.test.ts
new file mode 100644
index 000000000..53f67d621
--- /dev/null
+++ b/test/unit/zeroline-pane.test.ts
@@ -0,0 +1,145 @@
+import { expect, fixture, html } from '@open-wc/testing';
+import {
+ attachedIeds,
+ getAttachedIeds,
+} from '../../src/zeroline/foundation.js';
+
+describe('zeroline-pane', () => {
+ let doc: XMLDocument;
+
+ let substation1: Element;
+ let substation2: Element;
+
+ let voltageLevel1: Element;
+ let voltageLevel2: Element;
+
+ let bay1: Element;
+ let bay2: Element;
+
+ let remainingIeds: Set;
+
+ beforeEach(async () => {
+ doc = await fetch('/base/test/testfiles/zeroline/iedalloctest.scd')
+ .then(response => response.text())
+ .then(str => new DOMParser().parseFromString(str, 'application/xml'));
+
+ substation1 = doc.querySelector('Substation[name="AA1"]')!;
+ substation2 = doc.querySelector('Substation[name="AA2"]')!;
+
+ voltageLevel1 = doc.querySelector('VoltageLevel[name="E1"]')!;
+ voltageLevel2 = doc.querySelector('VoltageLevel[name="J1"]')!;
+
+ bay1 = doc.querySelector('Bay[name="Bay1"]')!;
+ bay2 = doc.querySelector('Bay[name="Bay2"]')!;
+
+ remainingIeds = new Set(Array.from(doc.querySelectorAll('IED')));
+ });
+
+ it('per default looks like the latest snapshot', async () => {
+ const element = await fixture(
+ html``
+ );
+
+ await new Promise(resolve => setTimeout(resolve, 2000)); // await animation
+
+ expect(element).shadowDom.to.equalSnapshot();
+ }).timeout(5000);
+
+ it('readonly looks like the latest snapshot', async () => {
+ const element = await fixture(
+ html``
+ );
+
+ await new Promise(resolve => setTimeout(resolve, 2000)); // await animation
+
+ expect(element).shadowDom.to.equalSnapshot();
+ }).timeout(5000);
+
+ it('showieds looks like the latest snapshot', async () => {
+ const element = await fixture(
+ html``
+ );
+
+ await new Promise(resolve => setTimeout(resolve, 2000)); // await animation
+
+ expect(element).shadowDom.to.equalSnapshot();
+ }).timeout(5000);
+
+ describe('attachedIeds', () => {
+ it('returns IEDs that cannot be allocated to any element', async () => {
+ const ieds = await attachedIeds(doc.documentElement!, remainingIeds);
+
+ expect(ieds.length).to.equal(2);
+ expect(ieds[0].getAttribute('name')).to.equal('IED6');
+ expect(ieds[1].getAttribute('name')).to.equal('IED8');
+ });
+ describe('return IEDs for Bay elements that', () => {
+ it('are connected itself or underlaying conduncting equipment', async () => {
+ const ieds = await attachedIeds(bay1, remainingIeds);
+
+ expect(ieds.length).to.equal(2);
+ expect(ieds[0].getAttribute('name')).to.equal('IED1');
+ expect(ieds[1].getAttribute('name')).to.equal('IED4');
+ });
+
+ it('are not connected to another Bay as well', async () => {
+ expect((await attachedIeds(bay2, remainingIeds)).length).to.equal(0);
+ });
+ });
+ describe('return IEDs for VoltageLevel elements that', () => {
+ it('are connected itself or underlaying elements', async () => {
+ const ieds = await attachedIeds(voltageLevel1, remainingIeds);
+
+ expect(ieds.length).to.equal(2);
+ expect(ieds[0].getAttribute('name')).to.equal('IED2');
+ expect(ieds[1].getAttribute('name')).to.equal('IED5');
+ });
+
+ it('are not connected to another Bay ass well', async () => {
+ expect(
+ (await attachedIeds(voltageLevel2, remainingIeds)).length
+ ).to.equal(0);
+ });
+ });
+ describe('return IEDs for Substation elements that', () => {
+ it('are connected itself or underlaying elements', async () => {
+ const ieds = await attachedIeds(substation1, remainingIeds);
+
+ expect(ieds.length).to.equal(2);
+ expect(ieds[0].getAttribute('name')).to.equal('IED3');
+ expect(ieds[1].getAttribute('name')).to.equal('IED7');
+ });
+ it('are not connected to another Substation ass well', async () => {
+ expect(
+ (await attachedIeds(substation2, remainingIeds)).length
+ ).to.equal(0);
+ });
+ });
+ });
+ it('both the functions return every IED only once', async () => {
+ const numSub1 = (await attachedIeds(substation1, remainingIeds)).length;
+ const numSub2 = (await attachedIeds(substation2, remainingIeds)).length;
+ const numVolt1 = (await attachedIeds(voltageLevel1, remainingIeds)).length;
+ const numVolt2 = (await attachedIeds(voltageLevel2, remainingIeds)).length;
+ const numBay1 = (await attachedIeds(bay1, remainingIeds)).length;
+ const numBay2 = (await attachedIeds(bay2, remainingIeds)).length;
+
+ const numUnRef = (await attachedIeds(doc.documentElement, remainingIeds))
+ .length;
+
+ const sumIeds =
+ numBay1 + numBay2 + numVolt1 + numVolt2 + numSub1 + numSub2 + numUnRef;
+
+ expect(sumIeds).to.equal(doc.querySelectorAll('IED').length);
+ });
+}).timeout(10000);
diff --git a/test/unit/editors/substation/BayEditor.test.ts b/test/unit/zeroline/BayEditor.test.ts
similarity index 83%
rename from test/unit/editors/substation/BayEditor.test.ts
rename to test/unit/zeroline/BayEditor.test.ts
index cd8da65dc..305a46c39 100644
--- a/test/unit/editors/substation/BayEditor.test.ts
+++ b/test/unit/zeroline/BayEditor.test.ts
@@ -1,11 +1,10 @@
-import { WizardInput, isCreate, isUpdate } from '../../../../src/foundation.js';
import { fixture, html, expect } from '@open-wc/testing';
-import '../../../../src/wizard-textfield.js';
-import { BayEditor } from '../../../../src/editors/substation/bay-editor.js';
-import { updateNamingAction } from '../../../../src/editors/substation/foundation.js';
-import { wizards } from '../../../../src/wizards/wizard-library.js';
-import { createAction } from '../../../../src/wizards/bay.js';
+import { WizardInput, isCreate, isUpdate } from '../../../src/foundation.js';
+
+import '../../../src/wizard-textfield.js';
+import { updateNamingAction } from '../../../src/zeroline/foundation.js';
+import { createAction } from '../../../src/wizards/bay.js';
describe('BayEditor', () => {
const noOp = () => {
diff --git a/test/unit/editors/substation/ConductingEquipmentEditor.test.ts b/test/unit/zeroline/ConductingEquipmentEditor.test.ts
similarity index 83%
rename from test/unit/editors/substation/ConductingEquipmentEditor.test.ts
rename to test/unit/zeroline/ConductingEquipmentEditor.test.ts
index adca90819..5ca0e5620 100644
--- a/test/unit/editors/substation/ConductingEquipmentEditor.test.ts
+++ b/test/unit/zeroline/ConductingEquipmentEditor.test.ts
@@ -1,7 +1,9 @@
import { fixture, html, expect } from '@open-wc/testing';
-import { WizardInput, isCreate, isUpdate } from '../../../../src/foundation.js';
-import { ConductingEquipmentEditor } from '../../../../src/editors/substation/conducting-equipment-editor.js';
-import { updateNamingAction } from '../../../../src/editors/substation/foundation.js';
+
+import { WizardInput, isCreate, isUpdate } from '../../../src/foundation.js';
+import { updateNamingAction } from '../../../src/zeroline/foundation.js';
+import { createAction } from '../../../src/wizards/conductingequipment.js';
+
describe('ConductingEquipmentEditor', () => {
const noOp = () => {
return;
@@ -36,10 +38,10 @@ describe('ConductingEquipmentEditor', () => {
).documentElement;
});
- /* it('returns a WizardAction which returns a Create EditorAction', () => {
- const wizardAction = ConductingEquipmentEditor.createAction(parent);
+ it('returns a WizardAction which returns a Create EditorAction', () => {
+ const wizardAction = createAction(parent);
expect(wizardAction(inputs, newWizard())[0]).to.satisfy(isCreate);
- }); */
+ });
});
describe('updateAction', () => {
diff --git a/test/unit/editors/substation/SubstationEditor.test.ts b/test/unit/zeroline/SubstationEditor.test.ts
similarity index 83%
rename from test/unit/editors/substation/SubstationEditor.test.ts
rename to test/unit/zeroline/SubstationEditor.test.ts
index e71dd76e4..9f11919e0 100644
--- a/test/unit/editors/substation/SubstationEditor.test.ts
+++ b/test/unit/zeroline/SubstationEditor.test.ts
@@ -1,8 +1,9 @@
import { fixture, html, expect } from '@open-wc/testing';
-import { WizardInput, isCreate, isUpdate } from '../../../../src/foundation.js';
-import { SubstationEditor } from '../../../../src/editors/substation/substation-editor.js';
-import { updateNamingAction } from '../../../../src/editors/substation/foundation.js';
+import { WizardInput, isCreate, isUpdate } from '../../../src/foundation.js';
+import { createAction } from '../../../src/wizards/substation.js';
+import { updateNamingAction } from '../../../src/zeroline/foundation.js';
+
describe('SubstationEditor', () => {
const noOp = () => {
return;
@@ -34,10 +35,10 @@ describe('SubstationEditor', () => {
).documentElement;
});
- /* it('returns a WizardAction which returns a Create EditorAction', () => {
- const wizardAction = SubstationEditor.createAction(parent);
+ it('returns a WizardAction which returns a Create EditorAction', () => {
+ const wizardAction = createAction(parent);
expect(wizardAction(inputs, newWizard())[0]).to.satisfy(isCreate);
- }); */
+ });
});
describe('updateAction', () => {
diff --git a/test/unit/editors/substation/VoltageLevelEditor.test.ts b/test/unit/zeroline/VoltageLevelEditor.test.ts
similarity index 97%
rename from test/unit/editors/substation/VoltageLevelEditor.test.ts
rename to test/unit/zeroline/VoltageLevelEditor.test.ts
index 7dd5e9352..11263e15a 100644
--- a/test/unit/editors/substation/VoltageLevelEditor.test.ts
+++ b/test/unit/zeroline/VoltageLevelEditor.test.ts
@@ -4,12 +4,12 @@ import {
isCreate,
isUpdate,
isDelete,
-} from '../../../../src/foundation.js';
-import { VoltageLevelEditor } from '../../../../src/editors/substation/voltage-level-editor.js';
+} from '../../../src/foundation.js';
+
import {
createAction,
updateAction,
-} from '../../../../src/wizards/voltagelevel.js';
+} from '../../../src/wizards/voltagelevel.js';
describe('VoltageLevelEditor', () => {
describe('with no nulled properties', () => {
diff --git a/test/unit/editors/substation/bay-editor.test.ts b/test/unit/zeroline/bay-editor.test.ts
similarity index 63%
rename from test/unit/editors/substation/bay-editor.test.ts
rename to test/unit/zeroline/bay-editor.test.ts
index a80d62e61..b449e6f99 100644
--- a/test/unit/editors/substation/bay-editor.test.ts
+++ b/test/unit/zeroline/bay-editor.test.ts
@@ -1,7 +1,7 @@
import { fixture, html, expect } from '@open-wc/testing';
-import '../../../../src/editors/substation/bay-editor.js';
-import { BayEditor } from '../../../../src/editors/substation/bay-editor.js';
+import '../../../src/zeroline/bay-editor.js';
+import { BayEditor } from '../../../src/zeroline/bay-editor.js';
describe('bay-editor', () => {
let element: BayEditor;
@@ -20,13 +20,17 @@ describe('bay-editor', () => {
);
});
- it('has a name property', () =>
- expect(element).to.have.property('name', 'COUPLING_BAY'));
-
- it('has a desc property', () =>
- expect(element).to.have.property('desc', 'Bay'));
-
it('looks like the latest snapshot', () => {
expect(element).shadowDom.to.equalSnapshot();
});
+
+ describe('with readonly property', () => {
+ beforeEach(async () => {
+ element.readonly = true;
+ await element.requestUpdate();
+ });
+ it('looks like the latest snapshot', () => {
+ expect(element).shadowDom.to.equalSnapshot();
+ });
+ });
});
diff --git a/test/unit/editors/substation/conducting-equipment-editor.test.ts b/test/unit/zeroline/conducting-equipment-editor.test.ts
similarity index 63%
rename from test/unit/editors/substation/conducting-equipment-editor.test.ts
rename to test/unit/zeroline/conducting-equipment-editor.test.ts
index 595807473..a0551b9f1 100644
--- a/test/unit/editors/substation/conducting-equipment-editor.test.ts
+++ b/test/unit/zeroline/conducting-equipment-editor.test.ts
@@ -1,7 +1,7 @@
import { fixture, html, expect } from '@open-wc/testing';
-import '../../../../src/editors/substation/conducting-equipment-editor.js';
-import { ConductingEquipmentEditor } from '../../../../src/editors/substation/conducting-equipment-editor.js';
+import '../../../src/zeroline/conducting-equipment-editor.js';
+import { ConductingEquipmentEditor } from '../../../src/zeroline/conducting-equipment-editor.js';
describe('conducting-equipment-editor', () => {
let element: ConductingEquipmentEditor;
@@ -20,13 +20,17 @@ describe('conducting-equipment-editor', () => {
);
});
- it('has a name property', () =>
- expect(element).to.have.property('name', 'QA1'));
-
- it('has a desc property', () =>
- expect(element).to.have.property('desc', 'coupling field ciscuit breaker'));
-
it('looks like the latest snapshot', () => {
expect(element).shadowDom.to.equalSnapshot();
});
+
+ describe('with readonly property', () => {
+ beforeEach(async () => {
+ element.readonly = true;
+ await element.requestUpdate();
+ });
+ it('looks like the latest snapshot', () => {
+ expect(element).shadowDom.to.equalSnapshot();
+ });
+ });
});
diff --git a/test/unit/editors/substation/substation-editor.test.ts b/test/unit/zeroline/substation-editor.test.ts
similarity index 61%
rename from test/unit/editors/substation/substation-editor.test.ts
rename to test/unit/zeroline/substation-editor.test.ts
index b1eb74683..e728e7631 100644
--- a/test/unit/editors/substation/substation-editor.test.ts
+++ b/test/unit/zeroline/substation-editor.test.ts
@@ -1,7 +1,7 @@
import { html, fixture, expect } from '@open-wc/testing';
-import '../../../../src/editors/substation/substation-editor.js';
-import { SubstationEditor } from '../../../../src/editors/substation/substation-editor.js';
+import '../../../src/zeroline/substation-editor.js';
+import { SubstationEditor } from '../../../src/zeroline/substation-editor.js';
describe('substation-editor', () => {
let element: SubstationEditor;
@@ -16,13 +16,17 @@ describe('substation-editor', () => {
>`);
});
- it('has a name property', () =>
- expect(element).to.have.property('name', 'AA1'));
-
- it('has a desc property', () =>
- expect(element).to.have.property('desc', 'Substation'));
-
it('looks like the latest snapshot', () => {
expect(element).shadowDom.to.equalSnapshot();
});
+
+ describe('with readonly property', () => {
+ beforeEach(async () => {
+ element.readonly = true;
+ await element.requestUpdate();
+ });
+ it('looks like the latest snapshot', () => {
+ expect(element).shadowDom.to.equalSnapshot();
+ });
+ });
});
diff --git a/test/unit/editors/substation/voltage-level-editor.test.ts b/test/unit/zeroline/voltage-level-editor.test.ts
similarity index 63%
rename from test/unit/editors/substation/voltage-level-editor.test.ts
rename to test/unit/zeroline/voltage-level-editor.test.ts
index e30ccff57..148cf44d4 100644
--- a/test/unit/editors/substation/voltage-level-editor.test.ts
+++ b/test/unit/zeroline/voltage-level-editor.test.ts
@@ -1,7 +1,7 @@
import { fixture, html, expect } from '@open-wc/testing';
-import '../../../../src/editors/substation/voltage-level-editor.js';
-import { VoltageLevelEditor } from '../../../../src/editors/substation/voltage-level-editor.js';
+import '../../../src/zeroline/voltage-level-editor.js';
+import { VoltageLevelEditor } from '../../../src/zeroline/voltage-level-editor.js';
describe('voltage-level-editor', () => {
let element: VoltageLevelEditor;
@@ -20,13 +20,17 @@ describe('voltage-level-editor', () => {
);
});
- it('has a name property', () =>
- expect(element).to.have.property('name', 'E1'));
-
- it('has a desc property', () =>
- expect(element).to.have.property('desc', 'Voltage Level'));
-
it('looks like the latest snapshot', () => {
expect(element).shadowDom.to.equalSnapshot();
});
+
+ describe('with readonly property', () => {
+ beforeEach(async () => {
+ element.readonly = true;
+ await element.requestUpdate();
+ });
+ it('looks like the latest snapshot', () => {
+ expect(element).shadowDom.to.equalSnapshot();
+ });
+ });
});