Skip to content

Commit 15c4f7b

Browse files
author
Rob Tjalma
authored
feat(editor/ied): Show the technical path to a DO/DA
1 parent bba9b3c commit 15c4f7b

File tree

14 files changed

+293
-161
lines changed

14 files changed

+293
-161
lines changed

src/editors/IED.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import '@material/mwc-select';
55
import '@material/mwc-list/mwc-list-item';
66

77
import './ied/ied-container.js'
8+
import './ied/element-path.js'
89
import './substation/zeroline-pane.js';
910

1011
import { translate } from 'lit-translate';
@@ -70,22 +71,25 @@ export default class IedPlugin extends LitElement {
7071
if (iedList.length > 0) {
7172
return html `
7273
<section>
73-
<mwc-select
74-
id="iedSelect"
75-
label="${translate("iededitor.searchHelper")}"
76-
@selected=${this.onSelect}>
77-
${iedList.map(
78-
ied =>
79-
html`
80-
<mwc-list-item
81-
?selected=${ied == this.selectedIed}
82-
value="${getNameAttribute(ied)}"
83-
>${getNameAttribute(ied)} ${ied.hasAttribute('desc') ? translate('iededitor.searchHelperDesc', {
84-
description: getDescriptionAttribute(ied)!,
85-
}) : ''}
86-
</mwc-list-item>`
87-
)}
88-
</mwc-select>
74+
<div class="header">
75+
<mwc-select
76+
class="iedSelect"
77+
label="${translate("iededitor.searchHelper")}"
78+
@selected=${this.onSelect}>
79+
${iedList.map(
80+
ied =>
81+
html`
82+
<mwc-list-item
83+
?selected=${ied == this.selectedIed}
84+
value="${getNameAttribute(ied)}"
85+
>${getNameAttribute(ied)} ${ied.hasAttribute('desc') ? translate('iededitor.searchHelperDesc', {
86+
description: getDescriptionAttribute(ied)!,
87+
}) : ''}
88+
</mwc-list-item>`
89+
)}
90+
</mwc-select>
91+
<element-path class="elementPath"></element-path>
92+
</div>
8993
<ied-container
9094
.element=${this.selectedIed}
9195
.nsdoc=${this.nsdoc}
@@ -107,11 +111,20 @@ export default class IedPlugin extends LitElement {
107111
padding: 8px 12px 16px;
108112
}
109113
110-
#iedSelect {
114+
.iedSelect {
111115
width: 35vw;
112116
padding-bottom: 20px;
113117
}
114118
119+
.header {
120+
display: flex;
121+
}
122+
123+
.elementPath {
124+
margin-left: auto;
125+
padding-right: 12px;
126+
}
127+
115128
h1 {
116129
color: var(--mdc-theme-on-surface);
117130
font-family: 'Roboto', sans-serif;

src/editors/ied/access-point-container.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {
22
css,
33
customElement,
44
html,
5-
LitElement,
65
property,
76
TemplateResult,
87
} from 'lit-element';
@@ -13,16 +12,11 @@ import { nothing } from 'lit-html';
1312
import { getDescriptionAttribute, getNameAttribute } from '../../foundation.js';
1413
import { Nsdoc } from '../../foundation/nsdoc.js';
1514
import { accessPointIcon } from '../../icons/ied-icons.js';
15+
import { Container } from './foundation.js';
1616

1717
/** [[`IED`]] plugin subeditor for editing `AccessPoint` element. */
1818
@customElement('access-point-container')
19-
export class AccessPointContainer extends LitElement {
20-
@property({ attribute: false })
21-
element!: Element;
22-
23-
@property()
24-
ancestors: Element[] = [];
25-
19+
export class AccessPointContainer extends Container {
2620
@property()
2721
nsdoc!: Nsdoc;
2822

@@ -40,7 +34,7 @@ export class AccessPointContainer extends LitElement {
4034
html`<server-container
4135
.element=${server}
4236
.nsdoc=${this.nsdoc}
43-
.ancestors=${[this.element, ...this.ancestors]}
37+
.ancestors=${[...this.ancestors, this.element]}
4438
></server-container>`)}
4539
</action-pane>`;
4640
}

src/editors/ied/da-container.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {
22
css,
33
customElement,
44
html,
5-
LitElement,
65
property,
76
query,
87
TemplateResult,
@@ -19,26 +18,17 @@ import { Nsdoc } from '../../foundation/nsdoc.js';
1918
import { wizards } from '../../wizards/wizard-library.js';
2019
import { DaiValidationTypes, getCustomField } from './foundation/foundation.js';
2120
import { createDaInfoWizard } from "./da-wizard.js";
22-
import { getInstanceDAElement, getValueElement } from './foundation.js';
21+
import { Container, getInstanceDAElement, getValueElement } from './foundation.js';
2322

2423
/** [[`IED`]] plugin subeditor for editing `(B)DA` element. */
2524
@customElement('da-container')
26-
export class DAContainer extends LitElement {
27-
/**
28-
* The (B)DA itself.
29-
*/
30-
@property({ attribute: false })
31-
element!: Element;
32-
25+
export class DAContainer extends Container {
3326
/**
3427
* The optional DAI of this (B)DA.
3528
*/
3629
@property({ attribute: false })
3730
instanceElement!: Element;
3831

39-
@property()
40-
ancestors: Element[] = [];
41-
4232
@property()
4333
nsdoc!: Nsdoc;
4434

@@ -127,7 +117,7 @@ export class DAContainer extends LitElement {
127117
.element=${bdaElement}
128118
.instanceElement=${getInstanceDAElement(this.instanceElement, bdaElement)}
129119
.nsdoc=${this.nsdoc}
130-
.ancestors=${[this.element, ...this.ancestors]}
120+
.ancestors=${[...this.ancestors, this.element]}
131121
></da-container>`) : nothing}
132122
</action-pane>
133123
`;

src/editors/ied/do-container.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
customElement,
33
html,
4-
LitElement,
54
property,
65
query,
76
TemplateResult,
@@ -17,26 +16,17 @@ import { getDescriptionAttribute, getNameAttribute, newWizardEvent } from '../..
1716
import { translate } from 'lit-translate';
1817
import { Nsdoc } from '../../foundation/nsdoc.js';
1918
import { createDoInfoWizard } from "./do-wizard.js";
20-
import { findDOTypeElement, getInstanceDAElement } from "./foundation.js";
19+
import { Container, findDOTypeElement, getInstanceDAElement } from "./foundation.js";
2120

2221
/** [[`IED`]] plugin subeditor for editing `DO` element. */
2322
@customElement('do-container')
24-
export class DOContainer extends LitElement {
25-
/**
26-
* The DO itself.
27-
*/
28-
@property({ attribute: false })
29-
element!: Element;
30-
23+
export class DOContainer extends Container {
3124
/**
3225
* The optional DOI of this DO.
3326
*/
3427
@property({ attribute: false })
3528
instanceElement!: Element;
3629

37-
@property()
38-
ancestors: Element[] = [];
39-
4030
@property()
4131
nsdoc!: Nsdoc;
4232

@@ -118,14 +108,14 @@ export class DOContainer extends LitElement {
118108
.element=${daElement}
119109
.instanceElement=${getInstanceDAElement(this.instanceElement, daElement)}
120110
.nsdoc=${this.nsdoc}
121-
.ancestors=${[this.element, ...this.ancestors]}
111+
.ancestors=${[...this.ancestors, this.element]}
122112
></da-container>`) : nothing}
123113
${this.toggleButton?.on ? doElements.map(doElement =>
124114
html`<do-container
125115
.element=${doElement}
126116
.instanceElement=${this.getInstanceDOElement(doElement)}
127117
.nsdoc=${this.nsdoc}
128-
.ancestors=${[this.element, ...this.ancestors]}
118+
.ancestors=${[...this.ancestors, this.element]}
129119
></do-container>`) : nothing}
130120
</action-pane>
131121
`;

src/editors/ied/element-path.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {
2+
css,
3+
customElement,
4+
html,
5+
LitElement,
6+
state,
7+
TemplateResult,
8+
} from 'lit-element';
9+
import { FullElementPathEvent } from './foundation.js';
10+
11+
@customElement('element-path')
12+
export class ElementPath extends LitElement {
13+
14+
@state()
15+
elementNames: string[] = [];
16+
17+
constructor() {
18+
super();
19+
20+
const parentSection = this.closest('section');
21+
if (parentSection) {
22+
parentSection.addEventListener('full-element-path', (event: FullElementPathEvent) => {
23+
this.elementNames = event.detail.elementNames;
24+
});
25+
}
26+
}
27+
28+
render(): TemplateResult {
29+
return html`
30+
<h3>${this.elementNames.join(' / ')}</h3>
31+
`;
32+
}
33+
34+
static styles = css`
35+
h3 {
36+
color: var(--mdc-theme-on-surface);
37+
font-family: 'Roboto', sans-serif;
38+
font-weight: 300;
39+
overflow: hidden;
40+
white-space: nowrap;
41+
text-overflow: ellipsis;
42+
margin: 0px;
43+
line-height: 48px;
44+
padding-left: 0.3em;
45+
transition: background-color 150ms linear;
46+
}`;
47+
}

src/editors/ied/foundation.ts

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,38 @@
1-
import { getNameAttribute } from "../../foundation.js";
1+
import { LitElement, property } from "lit-element";
2+
import { getInstanceAttribute, getNameAttribute } from "../../foundation.js";
3+
4+
/** Base class for all containers inside the IED Editor. */
5+
export class Container extends LitElement {
6+
@property({ attribute: false })
7+
element!: Element;
8+
9+
@property()
10+
ancestors: Element[] = [];
11+
12+
constructor() {
13+
super();
14+
15+
this.addEventListener('focus', (event) => {
16+
event.stopPropagation();
17+
const pathOfAncestorNames = this.ancestors.map(ancestor => getTitleForElementPath(ancestor)!);
18+
pathOfAncestorNames.push(getTitleForElementPath(this.element)!);
19+
20+
this.dispatchEvent(
21+
newFullElementPathEvent(
22+
pathOfAncestorNames
23+
)
24+
);
25+
});
26+
27+
this.addEventListener('blur', () => {
28+
this.dispatchEvent(
29+
newFullElementPathEvent(
30+
this.ancestors.map(ancestor => getTitleForElementPath(ancestor)!)
31+
)
32+
);
33+
});
34+
}
35+
}
236

337
/**
438
* Search for an element with a passed tag-name in the list of ancestors passed.
@@ -55,6 +89,24 @@ export function getInstanceDAElement(parentInstance: Element | null, da: Element
5589
return null;
5690
}
5791

92+
export function getTitleForElementPath(element: Element): string {
93+
switch (element.tagName) {
94+
case 'LN':
95+
case 'LN0': {
96+
return element.getAttribute('lnClass')!;
97+
}
98+
case 'LDevice': {
99+
return (getNameAttribute(element) ?? getInstanceAttribute(element))!
100+
}
101+
case 'Server': {
102+
return 'Server';
103+
}
104+
default: {
105+
return element.getAttribute('name')!;
106+
}
107+
}
108+
}
109+
58110
/**
59111
* Get the 'Val' element of another element.
60112
* @param element - The element to search for an 'Val' element.
@@ -63,3 +115,25 @@ export function getInstanceDAElement(parentInstance: Element | null, da: Element
63115
export function getValueElement(element: Element): Element | null {
64116
return element.querySelector('Val');
65117
}
118+
119+
export interface FullElementPathDetail {
120+
elementNames: string[];
121+
}
122+
export type FullElementPathEvent = CustomEvent<FullElementPathDetail>;
123+
export function newFullElementPathEvent(
124+
elementNames: string[],
125+
eventInitDict?: CustomEventInit<FullElementPathDetail>
126+
): FullElementPathEvent {
127+
return new CustomEvent<FullElementPathDetail>('full-element-path', {
128+
bubbles: true,
129+
composed: true,
130+
...eventInitDict,
131+
detail: { elementNames, ...eventInitDict?.detail },
132+
});
133+
}
134+
135+
declare global {
136+
interface ElementEventMap {
137+
['full-element-path']: FullElementPathEvent;
138+
}
139+
}

src/editors/ied/ied-container.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {
22
css,
33
customElement,
44
html,
5-
LitElement,
65
property,
76
TemplateResult,
87
} from 'lit-element';
@@ -14,6 +13,7 @@ import './access-point-container.js';
1413

1514
import { wizards } from "../../wizards/wizard-library.js";
1615
import { Nsdoc } from '../../foundation/nsdoc.js';
16+
import { Container } from './foundation.js';
1717
import {
1818
getDescriptionAttribute,
1919
getNameAttribute,
@@ -23,11 +23,7 @@ import { removeIEDWizard } from "../../wizards/ied.js";
2323

2424
/** [[`IED`]] plugin subeditor for editing `IED` element. */
2525
@customElement('ied-container')
26-
export class IedContainer extends LitElement {
27-
/** The edited `Element`, a common property of all IED subcontainers. */
28-
@property({ attribute: false })
29-
element!: Element;
30-
26+
export class IedContainer extends Container {
3127
@property()
3228
nsdoc!: Nsdoc;
3329

0 commit comments

Comments
 (0)