Skip to content

Commit

Permalink
Merge pull request #461 from openscd/add-da-container
Browse files Browse the repository at this point in the history
feat(editors/ied): add DA elements to IED editor
  • Loading branch information
Flurb committed Jan 10, 2022
2 parents 21f2ebf + 081eac7 commit 541b347
Show file tree
Hide file tree
Showing 11 changed files with 579 additions and 18 deletions.
116 changes: 116 additions & 0 deletions src/editors/ied/da-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import {
css,
customElement,
html,
LitElement,
property,
query,
TemplateResult,
} from 'lit-element';
import { nothing } from 'lit-html';
import { translate } from 'lit-translate';

import '@material/mwc-icon-button-toggle';
import { IconButtonToggle } from '@material/mwc-icon-button-toggle';

import '../../action-pane.js';
import { getNameAttribute } from '../../foundation.js';

/** [[`IED`]] plugin subeditor for editing `(B)DA` element. */
@customElement('da-container')
export class DAContainer extends LitElement {
/**
* The DA itself.
*/
@property({ attribute: false })
element!: Element;

/**
* The optional DAI of this (B)DA.
*/
@property({ attribute: false })
instanceElement!: Element;

@query('#toggleButton') toggleButton: IconButtonToggle | undefined;

private header(): TemplateResult {
const name = getNameAttribute(this.element);
const bType = this.element!.getAttribute('bType') ?? nothing;

if (this.instanceElement) {
return html`<b>${name}</b> &mdash; ${bType}`;
} else {
return html`${name} &mdash; ${bType}`;
}
}

/**
* Rendering an optional value of this (B)DA container.
* If there is a DAI, it get's priority on top of (B)DA values.
* @returns TemplateResult containing the value of the instance, element or nothing.
*/
private renderValue(): TemplateResult {
if (this.instanceElement) {
return html`${this.getValueElement(this.instanceElement)?.textContent}`
}

return html`${this.getValueElement(this.element)?.textContent}`;
}

/**
* Get the 'Val' element of another element.
* @param element - The element to search for an 'Val' element.
* @returns the 'Val' element, or null if not found.
*/
private getValueElement(element: Element): Element | null {
return element.querySelector('Val') ?? null;
}

/**
* Get the nested (B)DA element(s) if available.
* @returns The nested (B)DA element(s) of this (B)DA container.
*/
private getBDAElements(): Element[] {
const type = this.element!.getAttribute('type') ?? undefined;
const doType = this.element!.closest('SCL')!.querySelector(`:root > DataTypeTemplates > DAType[id="${type}"]`);
if (doType != null) {
return Array.from(doType!.querySelectorAll(':scope > BDA'))
}
return [];
}

render(): TemplateResult {
const bType = this.element!.getAttribute('bType');

return html`<action-pane .label="${this.header()}" icon="${this.instanceElement != null ? 'done' : ''}">
${bType == 'Struct' ? html`<abbr slot="action" title="${translate('iededitor.toggleChildElements')}">
<mwc-icon-button-toggle
id="toggleButton"
onIcon="keyboard_arrow_up"
offIcon="keyboard_arrow_down"
@click=${() => this.requestUpdate()}
></mwc-icon-button-toggle>
</abbr>` : nothing}
<h6>${this.renderValue()}</h6>
${this.toggleButton?.on && bType == 'Struct' ? this.getBDAElements().map(element =>
html`<da-container
.element=${element}>
</da-container>`) : nothing}
</action-pane>
`;
}

static styles = css`
h6 {
color: var(--mdc-theme-on-surface);
font-family: 'Roboto', sans-serif;
font-weight: 500;
font-size: 0.8em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 0px;
padding-left: 0.3em;
}
`;
}
66 changes: 58 additions & 8 deletions src/editors/ied/do-container.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import {
css,
customElement,
html,
LitElement,
property,
query,
TemplateResult,
} from 'lit-element';
import { nothing } from 'lit-html';

import '@material/mwc-icon-button-toggle';
import { IconButtonToggle } from '@material/mwc-icon-button-toggle';

import '../../action-pane.js';
import './da-container.js';
import { getDescriptionAttribute, getNameAttribute } from '../../foundation.js';
import { translate } from 'lit-translate';

/** [[`IED`]] plugin subeditor for editing `DO` element. */
@customElement('do-container')
Expand All @@ -25,6 +30,8 @@ export class DOContainer extends LitElement {
*/
@property({ attribute: false })
instanceElement!: Element;

@query('#toggleButton') toggleButton: IconButtonToggle | undefined;

private header(): TemplateResult {
const name = getNameAttribute(this.element);
Expand All @@ -51,25 +58,68 @@ export class DOContainer extends LitElement {
}

/**
* Get the instance element (SDI) of a SDO element (if available)
* @param sdo - The SDO object to search with.
* Get the nested (B)DA element(s).
* @returns The nested (B)DA element(s) of this DO container.
*/
private getDAElements(): Element[] {
const type = this.element.getAttribute('type') ?? undefined;
const doType = this.element.closest('SCL')!.querySelector(`:root > DataTypeTemplates > DOType[id="${type}"]`);
if (doType != null) {
return Array.from(doType!.querySelectorAll(':scope > DA'))
}
return [];
}

/**
* Get the instance element (SDI) of a (S)DO element (if available)
* @param dO - The (S)DO object to search with.
* @returns The optional SDI element.
*/
private getInstanceElement(sdo: Element): Element | null {
const sdoName = getNameAttribute(sdo);
private getInstanceDOElement(dO: Element): Element | null {
const sdoName = getNameAttribute(dO);
if (this.instanceElement) {
return this.instanceElement.querySelector(`:scope > SDI[name="${sdoName}"]`)
}
return null;
}

/**
* Get the instance element (DAI) of a DA element (if available)
* @param da - The (B)DA object to search with.
* @returns The optional DAI element.
*/
private getInstanceDAElement(da: Element): Element | null {
const daName = getNameAttribute(da);
if (this.instanceElement) {
return this.instanceElement.querySelector(`:scope > DAI[name="${daName}"]`)
}
return null;
}

render(): TemplateResult {
const daElements = this.getDAElements();
const doElements = this.getDOElements();

return html`<action-pane .label="${this.header()}" icon="${this.instanceElement != null ? 'done' : ''}">
${this.getDOElements().map(dO =>
${daElements.length > 0 || doElements.length > 0 ?
html`<abbr slot="action" title="${translate('iededitor.toggleChildElements')}">
<mwc-icon-button-toggle
id="toggleButton"
onIcon="keyboard_arrow_up"
offIcon="keyboard_arrow_down"
@click=${()=>this.requestUpdate()}
></mwc-icon-button-toggle>
</abbr>` : nothing}
${this.toggleButton?.on ? daElements.map(da =>
html`<da-container
.element=${da}
.instanceElement=${this.getInstanceDAElement(da)}>
</da-container>`) : nothing}
${this.toggleButton?.on ? doElements.map(dO =>
html`<do-container
.element=${dO}
.instanceElement=${this.getInstanceElement(dO)}>
</do-container>`)}
.instanceElement=${this.getInstanceDOElement(dO)}>
</do-container>`) : nothing}
</action-pane>
`;
}
Expand Down
21 changes: 18 additions & 3 deletions src/editors/ied/ln-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@ import {
html,
LitElement,
property,
query,
TemplateResult,
} from 'lit-element';
import { nothing } from 'lit-html';

import '../../action-pane.js';
import './do-container.js';
import { getInstanceAttribute, getNameAttribute } from '../../foundation.js';
import { translate } from 'lit-translate';
import { IconButtonToggle } from '@material/mwc-icon-button-toggle';

/** [[`IED`]] plugin subeditor for editing `LN` and `LN0` element. */
@customElement('ln-container')
export class LNContainer extends LitElement {
@property({ attribute: false })
element!: Element;

@query('#toggleButton') toggleButton!: IconButtonToggle | undefined;

private header(): TemplateResult {
const prefix = this.element.getAttribute('prefix');
Expand All @@ -43,7 +48,7 @@ export class LNContainer extends LitElement {

/**
* Get the instance element (DOI) of a DO element (if available)
* @param dO - The DOI object to use.
* @param dO - The DO object to use.
* @returns The optional DOI object.
*/
private getInstanceElement(dO: Element): Element | null {
Expand All @@ -52,12 +57,22 @@ export class LNContainer extends LitElement {
}

render(): TemplateResult {
const doElements = this.getDOElements();

return html`<action-pane .label="${this.header()}">
${this.getDOElements().map(dO => html`<do-container
${doElements.length > 0 ? html`<abbr slot="action" title="${translate('iededitor.toggleChildElements')}">
<mwc-icon-button-toggle
id="toggleButton"
onIcon="keyboard_arrow_up"
offIcon="keyboard_arrow_down"
@click=${() => this.requestUpdate()}
></mwc-icon-button-toggle>
</abbr>` : nothing}
${this.toggleButton?.on ? this.getDOElements().map(dO => html`<do-container
.element=${dO}
.instanceElement=${this.getInstanceElement(dO)}>
</do-container>
`)}
`) : nothing}
</action-pane>`;
}

Expand Down
1 change: 1 addition & 0 deletions src/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export const de: Translations = {
searchHelper: 'IED auswählen',
searchHelperDesc: '({{description}})',
missing: 'Kein IED vorhanden',
toggleChildElements: "???"
},
voltagelevel: {
name: 'Spannungsebene',
Expand Down
3 changes: 2 additions & 1 deletion src/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ export const en = {
iededitor: {
searchHelper: "Select IED",
searchHelperDesc: "({{description}})",
missing: 'No IED'
missing: 'No IED',
toggleChildElements: "Toggle child elements"
},
voltagelevel: {
name: 'Voltage level',
Expand Down
61 changes: 61 additions & 0 deletions test/unit/editors/ied/__snapshots__/da-container.test.snap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["da-container looks like the latest snapshot with a DA element"] =
`<action-pane
icon=""
tabindex="0"
>
<h6>
</h6>
</action-pane>
`;
/* end snapshot da-container looks like the latest snapshot with a DA element */

snapshots["da-container looks like the latest snapshot with a DA element and child elements are toggled."] =
`<action-pane
icon=""
tabindex="0"
>
<abbr
slot="action"
title="[iededitor.toggleChildElements]"
>
<mwc-icon-button-toggle
id="toggleButton"
officon="keyboard_arrow_down"
on=""
onicon="keyboard_arrow_up"
>
</mwc-icon-button-toggle>
</abbr>
<h6>
</h6>
<da-container>
</da-container>
<da-container>
</da-container>
<da-container>
</da-container>
<da-container>
</da-container>
<da-container>
</da-container>
<da-container>
</da-container>
</action-pane>
`;
/* end snapshot da-container looks like the latest snapshot with a DA element and child elements are toggled. */

snapshots["da-container looks like the latest snapshot with a DA element containing and a DAI."] =
`<action-pane
icon="done"
tabindex="0"
>
<h6>
status-only
</h6>
</action-pane>
`;
/* end snapshot da-container looks like the latest snapshot with a DA element containing and a DAI. */

Loading

0 comments on commit 541b347

Please sign in to comment.