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(editors/ied): add DO elements to IED editor #454

Merged
merged 7 commits into from
Jan 6, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(
Flurb marked this conversation as resolved.
Show resolved Hide resolved
server => html`<server-container
.element=${server}
></server-container>`)}
Expand Down
87 changes: 87 additions & 0 deletions src/editors/ied/do-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
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 DOType of this DO.
* @param doType - The type of this DO.
* @returns The DOType section for this DO.
*/
private getDOType(): Element | null {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you see something speaking against using js getters to access these as properties? It may fit better with the rest of the codebase.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also would suggest that. You can also combine getNestedDOElement and getDOType to something like

private getNestedDOElements(): Element[] {
    const id = this.element.getAttribute('type');

    const doType = this.element
      .closest('DataTypeTemplates')
      ?.querySelector(`DOType[id="${id}"]`);

    return Array.from(doType?.querySelectorAll('SDO') ?? []);
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the removal of getDOType, because it's only usage is in getNestedDOElements :) So I will merge them!

I was wondering how you guys would implement it as a getter (the getNestedDOElements for example).
I think getters and setters should apply to properties, so you can control the access of a certain property. That's why I'm a bit confused about how it's being used right now in open-scd, for example in the voltage-level-editor.ts, I see a get voltage() without a property (the voltage method itself is handled as a property). In my opinion this is a wrong usage, but maybe my Typescript expertise is lacking here :)

Is this how we want to use it and how we want this getNestedDOElements as well? :) If so, maybe we can discuss it!

const doType = this.element.getAttribute('type') ?? undefined;
return this.element.closest('SCL')!.querySelector(`:root > DataTypeTemplates > DOType[id="${doType}"]`);
JakobVogelsang marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Get the nested SDO elements.
* @returns The nested SDO elements of this DO container.
*/
private getNestedDOElements(): Element[] {
const doType = this.getDOType()
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.getNestedDOElements().map(dO =>
html`<do-container
.element=${dO}
.instanceElement=${this.getInstanceElement(dO)}>
</do-container>`)}
</action-pane>
`;
}

static styles = css``;
Flurb marked this conversation as resolved.
Show resolved Hide resolved
}
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
29 changes: 28 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 { compareNames, getInstanceAttribute, getNameAttribute } from '../../foundation.js';

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

/**
* Get the LNodeType of this LN(0) section.
* @returns The LNodeType section, or null if not found.
*/
private getLNodeType(): Element | null {
const lnType = this.element.getAttribute('lnType') ?? undefined;
return this.element.closest('SCL')!.querySelector(`:root > DataTypeTemplates > LNodeType[id="${lnType}"]`);
JakobVogelsang marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* 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()}">
${Array.from(this.getLNodeType() ? this.getLNodeType()!.querySelectorAll(':scope > DO') : [])
Flurb marked this conversation as resolved.
Show resolved Hide resolved
.sort((a,b) => compareNames(a,b))
JakobVogelsang marked this conversation as resolved.
Show resolved Hide resolved
.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
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