Skip to content

Commit

Permalink
feat(editors/ied): add DO elements to IED editor (#454)
Browse files Browse the repository at this point in the history
* Added DO/SDO elements

* Added DO/SDO/DOI/SDI

* Added unit tests ln-container

* Made methods private in ln-container

* Added do-container snapshot tests

* Added batch of do-container unit tests

* Review comments

Co-authored-by: Rob Tjalma <rob@tjalma.com>
  • Loading branch information
Flurb and Flurb committed Jan 6, 2022
1 parent f4904f6 commit 21f2ebf
Show file tree
Hide file tree
Showing 20 changed files with 1,006 additions and 48 deletions.
2 changes: 1 addition & 1 deletion public/js/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const officialPlugins = [
name: 'IED',
src: '/src/editors/IED.js',
icon: 'edit',
default: true,
default: false,
kind: 'editor',
},
{
Expand Down
3 changes: 1 addition & 2 deletions src/editors/IED.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import '../zeroline-pane.js';
import './ied/ied-container.js'

import { translate } from 'lit-translate';
import { IEDSelector } from './ied/foundation.js';
import { Select } from '@material/mwc-select';
import { SingleSelectedEvent } from '@material/mwc-list/mwc-list-foundation';
import { compareNames, getDescriptionAttribute, getNameAttribute } from '../foundation.js';
Expand All @@ -21,7 +20,7 @@ export default class IedPlugin extends LitElement {

/** Query holding the current selected IEDs. */
@state()
currentSelectedIEDs: string = IEDSelector.IED;
currentSelectedIEDs = ':root > IED';

@query('#iedSelect') iedSelector?: Select;

Expand Down
3 changes: 1 addition & 2 deletions src/editors/ied/access-point-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {

import '../../action-pane.js';
import './server-container.js'
import { IEDSelector } from './foundation.js';
import { nothing } from 'lit-html';
import { getDescriptionAttribute, getNameAttribute } from '../../foundation.js';

Expand All @@ -28,7 +27,7 @@ export class AccessPointContainer extends LitElement {

render(): TemplateResult {
return html`<action-pane .label="${this.header()}">
${Array.from(this.element.querySelectorAll(IEDSelector.Server)).map(
${Array.from(this.element.querySelectorAll(':scope > Server')).map(
server => html`<server-container
.element=${server}
></server-container>`)}
Expand Down
76 changes: 76 additions & 0 deletions src/editors/ied/do-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
css,
customElement,
html,
LitElement,
property,
TemplateResult,
} from 'lit-element';
import { nothing } from 'lit-html';

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

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

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

private header(): TemplateResult {
const name = getNameAttribute(this.element);
const desc = getDescriptionAttribute(this.element);

if (this.instanceElement != null) {
return html`<b>${name}${desc ? html` &mdash; ${desc}` : nothing}</b>`;
} else {
return html`${name}${desc ? html` &mdash; ${desc}` : nothing}`;
}
}

/**
* Get the nested SDO element(s).
* @returns The nested SDO element(s) of this DO container.
*/
private getDOElements(): 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 > SDO'))
}
return [];
}

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

render(): TemplateResult {
return html`<action-pane .label="${this.header()}" icon="${this.instanceElement != null ? 'done' : ''}">
${this.getDOElements().map(dO =>
html`<do-container
.element=${dO}
.instanceElement=${this.getInstanceElement(dO)}>
</do-container>`)}
</action-pane>
`;
}
}
10 changes: 0 additions & 10 deletions src/editors/ied/foundation.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/editors/ied/ied-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { nothing } from 'lit-html';
import '../../action-pane.js';
import { getDescriptionAttribute, getNameAttribute } from '../../foundation.js';
import './access-point-container.js';
import { IEDSelector } from './foundation.js';

/** [[`IED`]] plugin subeditor for editing `IED` element. */
@customElement('ied-container')
Expand All @@ -29,7 +28,7 @@ export class IedContainer extends LitElement {

render(): TemplateResult {
return html`<action-pane .label="${this.header()}">
${Array.from(this.element.querySelectorAll(IEDSelector.AccessPoint)).map(
${Array.from(this.element.querySelectorAll(':scope > AccessPoint')).map(
ap => html`<access-point-container
.element=${ap}
></access-point-container>`)}
Expand Down
9 changes: 4 additions & 5 deletions src/editors/ied/ldevice-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {

import '../../action-pane.js';
import './ln-container.js'
import { IEDSelector } from './foundation.js';
import { nothing } from 'lit-html';
import { getDescriptionAttribute, getInstanceAttribute, getNameAttribute } from '../../foundation.js';

Expand All @@ -28,8 +27,8 @@ export class LDeviceContainer extends LitElement {

render(): TemplateResult {
return html`<action-pane .label="${this.header()}">
<div id="bayContainer">
${Array.from(this.element.querySelectorAll(IEDSelector.AnyLN)).map(
<div id="lnContainer">
${Array.from(this.element.querySelectorAll(':scope > LN,LN0')).map(
server => html`<ln-container
.element=${server}
></ln-container>`)}
Expand All @@ -38,15 +37,15 @@ export class LDeviceContainer extends LitElement {
}

static styles = css`
#bayContainer {
#lnContainer {
display: grid;
grid-gap: 12px;
box-sizing: border-box;
grid-template-columns: repeat(auto-fit, minmax(316px, auto));
}
@media (max-width: 387px) {
#bayContainer {
#lnContainer {
grid-template-columns: repeat(auto-fit, minmax(196px, auto));
}
}`;
Expand Down
31 changes: 30 additions & 1 deletion src/editors/ied/ln-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
import { nothing } from 'lit-html';

import '../../action-pane.js';
import { getInstanceAttribute } from '../../foundation.js';
import './do-container.js';
import { getInstanceAttribute, getNameAttribute } from '../../foundation.js';

/** [[`IED`]] plugin subeditor for editing `LN` and `LN0` element. */
@customElement('ln-container')
Expand All @@ -27,8 +28,36 @@ export class LNContainer extends LitElement {
${inst ? html` &mdash; ${inst}` : nothing}`;
}

/**
* Get the DO child elements of this LN(0) section.
* @returns The DO child elements, or an empty array if none are found.
*/
private getDOElements(): Element[] {
const lnType = this.element.getAttribute('lnType') ?? undefined;
const lNodeType = this.element.closest('SCL')!.querySelector(`:root > DataTypeTemplates > LNodeType[id="${lnType}"]`);
if (lNodeType != null) {
return Array.from(lNodeType.querySelectorAll(':scope > DO'));
}
return [];
}

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

render(): TemplateResult {
return html`<action-pane .label="${this.header()}">
${this.getDOElements().map(dO => html`<do-container
.element=${dO}
.instanceElement=${this.getInstanceElement(dO)}>
</do-container>
`)}
</action-pane>`;
}

Expand Down
3 changes: 1 addition & 2 deletions src/editors/ied/server-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {

import '../../action-pane.js';
import './ldevice-container.js';
import { IEDSelector } from './foundation.js';

/** [[`IED`]] plugin subeditor for editing `Server` element. */
@customElement('server-container')
Expand All @@ -23,7 +22,7 @@ export class ServerContainer extends LitElement {

render(): TemplateResult {
return html`<action-pane label="${this.header()}">
${Array.from(this.element.querySelectorAll(IEDSelector.LDevice)).map(
${Array.from(this.element.querySelectorAll(':scope > LDevice')).map(
server => html`<ldevice-container
.element=${server}
></ldevice-container>`)}
Expand Down
1 change: 0 additions & 1 deletion test/integration/__snapshots__/open-scd.test.snap.js
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,6 @@ snapshots["open-scd looks like its snapshot"] =
hasmeta=""
left=""
mwc-list-item=""
selected=""
tabindex="-1"
value="/src/editors/IED.js"
>
Expand Down
11 changes: 0 additions & 11 deletions test/integration/editors/ied/__snapshots__/IED.test.snap.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["IED Editor Plugin without a doc loaded looks like the latest snapshot"] =
`<h1>
<span style="color: var(--base1)">
[iededitor.missing]
</span>
</h1>
<wizard-dialog>
</wizard-dialog>
`;
/* end snapshot IED Editor Plugin without a doc loaded looks like the latest snapshot */

snapshots["IED Plugin without a doc loaded looks like the latest snapshot"] =
`<h1>
<span style="color: var(--base1)">
Expand Down
4 changes: 2 additions & 2 deletions test/integration/editors/triggered/ImportIedsPlugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ describe('ImportIedsPlugin', () => {
expect(
element.doc?.querySelectorAll(':root > DataTypeTemplates > DOType')
.length
).to.equal(14);
).to.equal(16);
element.prepareImport(importDoc, doc);
expect(
element.doc?.querySelectorAll(':root > DataTypeTemplates > DOType')
.length
).to.equal(24);
).to.equal(26);
});

it('loads unique datypes to the project', () => {
Expand Down
23 changes: 23 additions & 0 deletions test/testfiles/valid2007B4.scd
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
</GSEControl>
</LN0>
<LN lnClass="LPHD" inst="1" lnType="Dummy.LPHD1"/>
<LN lnClass="THARDE" inst="1" lnType="Dummy.THARDE"/>
<LN lnClass="XCBR" inst="1" lnType="Dummy.XCBR1">
<DOI name="Pos">
<DAI name="ctlModel">
Expand Down Expand Up @@ -393,6 +394,7 @@
<DataTypeTemplates>
<LNodeType lnClass="LLN0" id="Dummy.LLN0">
<DO name="Mod" type="Dummy.LLN0.Mod" />
<DO name="ExtendedMod" type="Dummy.LLN0.ExtendedMod" />
<DO name="Beh" type="Dummy.LLN0.Beh" />
<DO name="Health" type="Dummy.LLN0.Health" />
<DO name="NamPlt" type="Dummy.LLN0.NamPlt" />
Expand Down Expand Up @@ -486,6 +488,27 @@
<DA fc="CO" name="Oper" bType="Struct" type="Dummy.LLN0.Mod.SBOw" />
<DA fc="CO" name="Cancel" bType="Struct" type="Dummy.LLN0.Mod.Cancel" />
</DOType>
<DOType cdc="ENC" id="Dummy.LLN0.ExtendedMod">
<SDO fc="ST" name="someSdo" type="someSdoType"/>
<DA fc="ST" name="stVal" bType="Enum" type="Dummy_Beh" />
<DA fc="ST" name="q" bType="Quality" />
<DA fc="ST" name="t" bType="Timestamp" />
<DA fc="ST" name="stSeld" bType="BOOLEAN" />
<DA fc="OR" name="opRcvd" bType="BOOLEAN" />
<DA fc="OR" name="opOk" bType="BOOLEAN" />
<DA fc="OR" name="tOpOk" bType="Timestamp" />
<DA fc="CF" name="ctlModel" bType="Enum" type="Dummy_ctlModel" />
<DA fc="CF" name="sboTimeout" bType="INT32U" />
<DA fc="CF" name="operTimeout" bType="INT32U" />
<DA fc="CO" name="SBO" bType="ObjRef" />
<DA fc="CO" name="SBOw" bType="Struct" type="Dummy.LLN0.Mod.SBOw" />
<DA fc="CO" name="Oper" bType="Struct" type="Dummy.LLN0.Mod.SBOw" />
<DA fc="CO" name="Cancel" bType="Struct" type="Dummy.LLN0.Mod.Cancel" />
</DOType>
<DOType cdc="CMV" id="someSdoType">
<DA fc="MX" qchg="true" name="q" bType="Quality"/>
<DA fc="MX" name="t" bType="Timestamp"/>
</DOType>
<DOType cdc="ENS" id="Dummy.LLN0.Beh">
<DA fc="ST" name="stVal" bType="Enum" type="Dummy_Beh" />
<DA fc="ST" name="q" bType="Quality" />
Expand Down
Loading

0 comments on commit 21f2ebf

Please sign in to comment.