Skip to content

Commit 5bfc3aa

Browse files
author
Dennis Labordus
authored
feat(editor/laterbinding): Added first part for SMV Later Binding Editor (openscd#927)
* First version of Later Binding (SMV) * Small changes and added tests * Updated Package lock file. * Processed review comments. * Processed review comments.
1 parent 271c397 commit 5bfc3aa

File tree

12 files changed

+1733
-98
lines changed

12 files changed

+1733
-98
lines changed

package-lock.json

Lines changed: 279 additions & 98 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/plugins.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ export const officialPlugins = [
3434
default: true,
3535
kind: 'editor',
3636
},
37+
{
38+
name: 'Subscriber Later Binding (SMV)',
39+
src: '/src/editors/SMVSubscriberLaterBinding.js',
40+
icon: 'link',
41+
default: false,
42+
kind: 'editor',
43+
},
3744
{
3845
name: 'Communication',
3946
src: '/src/editors/Communication.js',
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { css, html, LitElement, property, TemplateResult } from 'lit-element';
2+
3+
import './subscription/smv-laterbinding/svc-laterbinding-list.js';
4+
5+
/** An editor [[`plugin`]] for Subscribe Later Binding (SMV). */
6+
export default class SMVSubscribeLaterBindingPlugin extends LitElement {
7+
@property({ attribute: false })
8+
doc!: XMLDocument;
9+
10+
render(): TemplateResult {
11+
return html`<div>
12+
<div class="container">
13+
<svc-later-binding-list
14+
class="column"
15+
.doc=${this.doc}
16+
></svc-later-binding-list>
17+
</div>
18+
</div>`;
19+
}
20+
21+
static styles = css`
22+
:host {
23+
width: 100vw;
24+
}
25+
26+
.container {
27+
padding: 8px 6px 16px;
28+
}
29+
30+
.column {
31+
flex: 50%;
32+
margin: 0px 6px 0px;
33+
min-width: 300px;
34+
height: 100%;
35+
overflow-y: scroll;
36+
}
37+
`;
38+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import {
2+
css,
3+
customElement,
4+
html,
5+
LitElement,
6+
property,
7+
TemplateResult,
8+
} from 'lit-element';
9+
import { nothing } from 'lit-html';
10+
import { translate } from 'lit-translate';
11+
12+
import '@material/mwc-icon';
13+
import '@material/mwc-list';
14+
import '@material/mwc-list/mwc-list-item';
15+
16+
import {
17+
compareNames,
18+
getNameAttribute,
19+
identity,
20+
newWizardEvent,
21+
} from '../../../foundation.js';
22+
import { smvIcon } from '../../../icons/icons.js';
23+
import { wizards } from '../../../wizards/wizard-library.js';
24+
25+
import { styles } from '../foundation.js';
26+
27+
/** A sub element for showing all Sampled Value Controls. */
28+
@customElement('svc-later-binding-list')
29+
export class SVCLaterBindingList extends LitElement {
30+
@property({ attribute: false })
31+
doc!: XMLDocument;
32+
33+
private getSvcElements(): Element[] {
34+
if (this.doc) {
35+
return Array.from(
36+
this.doc.querySelectorAll('LN0 > SampledValueControl')
37+
).sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
38+
}
39+
return [];
40+
}
41+
42+
private getFcdaElements(svcElement: Element): Element[] {
43+
const lnElement = svcElement.parentElement;
44+
if (lnElement) {
45+
return Array.from(
46+
lnElement.querySelectorAll(
47+
`:scope > DataSet[name=${svcElement.getAttribute('datSet')}] > FCDA`
48+
)
49+
).sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
50+
}
51+
return [];
52+
}
53+
54+
private openEditWizard(svcElement: Element): void {
55+
const wizard = wizards['SampledValueControl'].edit(svcElement);
56+
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
57+
}
58+
59+
renderFCDA(svcElement: Element, fcdaElement: Element): TemplateResult {
60+
return html`<mwc-list-item
61+
graphic="large"
62+
twoline
63+
class="subitem"
64+
value="${identity(svcElement)} ${identity(fcdaElement)}"
65+
>
66+
<span>
67+
${fcdaElement.getAttribute('doName')}${fcdaElement.hasAttribute(
68+
'doName'
69+
) && fcdaElement.hasAttribute('daName')
70+
? html`.`
71+
: nothing}${fcdaElement.getAttribute('daName')}
72+
</span>
73+
<span slot="secondary">
74+
${fcdaElement.getAttribute('ldInst')}${fcdaElement.hasAttribute(
75+
'ldInst'
76+
) && fcdaElement.hasAttribute('prefix')
77+
? html`/`
78+
: nothing}${fcdaElement.getAttribute('prefix')}
79+
${fcdaElement.getAttribute('lnClass')}
80+
${fcdaElement.getAttribute('lnInst')}
81+
</span>
82+
<mwc-icon slot="graphic">subdirectory_arrow_right</mwc-icon>
83+
</mwc-list-item>`;
84+
}
85+
86+
render(): TemplateResult {
87+
const svcElements = this.getSvcElements();
88+
return html` <section tabindex="0">
89+
${svcElements.length > 0
90+
? html` <filtered-list>
91+
${svcElements.map(svcElement => {
92+
const fcdaElements = this.getFcdaElements(svcElement);
93+
return html`
94+
<mwc-list-item
95+
noninteractive
96+
graphic="icon"
97+
twoline
98+
hasMeta
99+
value="${identity(svcElement)} ${fcdaElements
100+
.map(fcdaElement => identity(fcdaElement) as string)
101+
.join(' ')}"
102+
>
103+
<mwc-icon-button
104+
slot="meta"
105+
icon="edit"
106+
class="interactive"
107+
@click=${() => this.openEditWizard(svcElement)}
108+
></mwc-icon-button>
109+
<span>${getNameAttribute(svcElement)}</span>
110+
<span slot="secondary">${identity(svcElement)}</span>
111+
<mwc-icon slot="graphic">${smvIcon}</mwc-icon>
112+
</mwc-list-item>
113+
<li divider role="separator"></li>
114+
${fcdaElements.map(fcdaElement =>
115+
this.renderFCDA(svcElement, fcdaElement)
116+
)}
117+
`;
118+
})}
119+
</filtered-list>`
120+
: html`<h1>
121+
${translate('subscription.smvLaterBinding.svcList.noSvcFound')}
122+
</h1>`}
123+
</section>`;
124+
}
125+
126+
static styles = css`
127+
${styles}
128+
129+
mwc-list-item {
130+
--mdc-list-item-meta-size: 48px;
131+
}
132+
133+
mwc-icon-button.hidden {
134+
display: none;
135+
}
136+
137+
mwc-list-item.hidden[noninteractive] + li[divider] {
138+
display: none;
139+
}
140+
141+
.interactive {
142+
pointer-events: all;
143+
}
144+
145+
.subitem {
146+
padding-left: var(--mdc-list-side-padding, 16px);
147+
}
148+
`;
149+
}

src/translations/de.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,11 @@ export const de: Translations = {
366366
'Zeigt verbundene Sampled Value(s) des ausgewählten IED',
367367
},
368368
},
369+
smvLaterBinding: {
370+
svcList: {
371+
noSvcFound: 'Kein Sampled-Value-Kontrolblock im Projekt',
372+
},
373+
},
369374
iedList: {
370375
title: 'IEDs',
371376
},

src/translations/en.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,11 @@ export const en = {
363363
'Show subscribed Sampled Value(s) publisher for selected IED',
364364
},
365365
},
366+
smvLaterBinding: {
367+
svcList: {
368+
noSvcFound: 'No Sampled Value Controls found',
369+
},
370+
},
366371
iedList: {
367372
title: 'IEDs',
368373
},

test/integration/__snapshots__/open-scd.test.snap.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,21 @@ snapshots["open-scd looks like its snapshot"] =
636636
</mwc-icon>
637637
Subscriber (SMV)
638638
</mwc-check-list-item>
639+
<mwc-check-list-item
640+
aria-disabled="false"
641+
class="official"
642+
graphic="control"
643+
hasmeta=""
644+
left=""
645+
mwc-list-item=""
646+
tabindex="-1"
647+
value="/src/editors/SMVSubscriberLaterBinding.js"
648+
>
649+
<mwc-icon slot="meta">
650+
link
651+
</mwc-icon>
652+
Subscriber Later Binding (SMV)
653+
</mwc-check-list-item>
639654
<mwc-check-list-item
640655
aria-disabled="false"
641656
class="official"

0 commit comments

Comments
 (0)