Skip to content

Commit 02ec714

Browse files
author
Dennis Labordus
authored
feat(editor/subscriber): Show counter for Subscriber Plugins (Logical Nodes / Later) (GOOSE/SMV) (openscd#1040)
* Added plugin and show FCDA Elements including edit button * Added plugin and show FCDA Elements including edit button * Added plugin and show FCDA Elements including edit button + renaming other subscriber plugins * Fixed plugin test * Show connected and available LN + small fixes * First version of subscribe and unsubscribe * Added test for subscribing and unsubscribing logica node binding * First step for the counter, refactoring list methods to re-use logic. Also removed sorting. * Added counter logic to both subscriber plugins * Processed review comments. * Changed query to retrieve available LN Classes to match only data binding ExtRefs * Fix performance issue. * Fixed snapshot. * Review comments processed * Fixed tests. * Fixed test.
1 parent 1c55aed commit 02ec714

20 files changed

+634
-433
lines changed

src/editors/GooseSubscriberDataBinding.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export default class GooseSubscribeDataBindingPlugin extends LitElement {
1818
<fcda-binding-list
1919
class="column"
2020
controlTag="GSEControl"
21-
.doc=${this.doc}
21+
.includeLaterBinding="${false}"
22+
.doc="${this.doc}"
2223
>
2324
</fcda-binding-list>
2425
<extref-ln-binding-list

src/editors/GooseSubscriberLaterBinding.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ export default class GooseSubscribeLaterBindingPlugin extends LitElement {
1313
<div class="container">
1414
<fcda-binding-list
1515
class="column"
16-
.doc=${this.doc}
1716
controlTag="GSEControl"
17+
.includeLaterBinding="${true}"
18+
.doc="${this.doc}"
1819
>
1920
</fcda-binding-list>
2021
<extref-later-binding-list
2122
class="column"
2223
controlTag="GSEControl"
23-
.doc=${this.doc}
24+
.doc="${this.doc}"
2425
>
2526
</extref-later-binding-list>
2627
</div>

src/editors/SMVSubscriberDataBinding.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export default class SMVSubscribeDataBindingPlugin extends LitElement {
1818
<fcda-binding-list
1919
class="column"
2020
controlTag="SampledValueControl"
21-
.doc=${this.doc}
21+
.includeLaterBinding="${false}"
22+
.doc="${this.doc}"
2223
>
2324
</fcda-binding-list>
2425
<extref-ln-binding-list

src/editors/SMVSubscriberLaterBinding.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ export default class SMVSubscribeLaterBindingPlugin extends LitElement {
1313
<div class="container">
1414
<fcda-binding-list
1515
class="column"
16-
.doc=${this.doc}
1716
controlTag="SampledValueControl"
17+
.includeLaterBinding="${true}"
18+
.doc="${this.doc}"
1819
>
1920
</fcda-binding-list>
2021
<extref-later-binding-list
2122
class="column"
22-
.doc=${this.doc}
2323
controlTag="SampledValueControl"
24+
.doc="${this.doc}"
2425
>
2526
</extref-later-binding-list>
2627
</div>

src/editors/subscription/fcda-binding-list.ts

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import '@material/mwc-list';
1616
import '@material/mwc-list/mwc-list-item';
1717

1818
import {
19-
compareNames,
2019
getDescriptionAttribute,
2120
getNameAttribute,
2221
identity,
@@ -25,7 +24,13 @@ import {
2524
import { gooseIcon, smvIcon } from '../../icons/icons.js';
2625
import { wizards } from '../../wizards/wizard-library.js';
2726

28-
import { getFcdaTitleValue, newFcdaSelectEvent, styles } from './foundation.js';
27+
import {
28+
getFcdaTitleValue,
29+
newFcdaSelectEvent,
30+
styles,
31+
SubscriptionChangedEvent,
32+
} from './foundation.js';
33+
import { getSubscribedExtRefElements } from './later-binding/foundation.js';
2934

3035
type controlTag = 'SampledValueControl' | 'GSEControl';
3136

@@ -42,14 +47,18 @@ export class FcdaBindingList extends LitElement {
4247
doc!: XMLDocument;
4348
@property()
4449
controlTag!: controlTag;
50+
@property()
51+
includeLaterBinding!: boolean;
4552

4653
// The selected Elements when a FCDA Line is clicked.
4754
@state()
48-
selectedControlElement: Element | undefined;
55+
private selectedControlElement: Element | undefined;
4956
@state()
50-
selectedFcdaElement: Element | undefined;
57+
private selectedFcdaElement: Element | undefined;
58+
@state()
59+
private extRefCounters = new Map();
5160

52-
iconControlLookup: iconLookup = {
61+
private iconControlLookup: iconLookup = {
5362
SampledValueControl: smvIcon,
5463
GSEControl: gooseIcon,
5564
};
@@ -59,13 +68,17 @@ export class FcdaBindingList extends LitElement {
5968

6069
this.resetSelection = this.resetSelection.bind(this);
6170
parent.addEventListener('open-doc', this.resetSelection);
71+
72+
const parentDiv = this.closest('.container');
73+
if (parentDiv) {
74+
this.resetExtRefCount = this.resetExtRefCount.bind(this);
75+
parentDiv.addEventListener('subscription-changed', this.resetExtRefCount);
76+
}
6277
}
6378

6479
private getControlElements(): Element[] {
6580
if (this.doc) {
66-
return Array.from(
67-
this.doc.querySelectorAll(`LN0 > ${this.controlTag}`)
68-
).sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
81+
return Array.from(this.doc.querySelectorAll(`LN0 > ${this.controlTag}`));
6982
}
7083
return [];
7184
}
@@ -79,11 +92,40 @@ export class FcdaBindingList extends LitElement {
7992
'datSet'
8093
)}] > FCDA`
8194
)
82-
).sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
95+
);
8396
}
8497
return [];
8598
}
8699

100+
private resetExtRefCount(event: SubscriptionChangedEvent): void {
101+
if (event.detail.control && event.detail.fcda) {
102+
const controlBlockFcdaId = `${identity(event.detail.control)} ${identity(
103+
event.detail.fcda
104+
)}`;
105+
this.extRefCounters.delete(controlBlockFcdaId);
106+
}
107+
}
108+
109+
private getExtRefCount(
110+
fcdaElement: Element,
111+
controlElement: Element
112+
): number {
113+
const controlBlockFcdaId = `${identity(controlElement)} ${identity(
114+
fcdaElement
115+
)}`;
116+
if (!this.extRefCounters.has(controlBlockFcdaId)) {
117+
const extRefCount = getSubscribedExtRefElements(
118+
<Element>this.doc.getRootNode(),
119+
this.controlTag,
120+
fcdaElement,
121+
controlElement!,
122+
this.includeLaterBinding
123+
).length;
124+
this.extRefCounters.set(controlBlockFcdaId, extRefCount);
125+
}
126+
return this.extRefCounters.get(controlBlockFcdaId);
127+
}
128+
87129
private openEditWizard(controlElement: Element): void {
88130
const wizard = wizards[this.controlTag].edit(controlElement);
89131
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
@@ -104,7 +146,8 @@ export class FcdaBindingList extends LitElement {
104146
protected updated(_changedProperties: PropertyValues): void {
105147
super.updated(_changedProperties);
106148

107-
// When the document is updated, we will fire the event again.
149+
// When a new document is loaded or the selection is changed
150+
// we will fire the FCDA Select Event.
108151
if (
109152
_changedProperties.has('doc') ||
110153
_changedProperties.has('selectedControlElement') ||
@@ -117,11 +160,18 @@ export class FcdaBindingList extends LitElement {
117160
)
118161
);
119162
}
163+
164+
// When a new document is loaded we will reset the Map to clear old entries.
165+
if (_changedProperties.has('doc')) {
166+
this.extRefCounters = new Map();
167+
}
120168
}
121169

122170
renderFCDA(controlElement: Element, fcdaElement: Element): TemplateResult {
171+
const fcdaCount = this.getExtRefCount(fcdaElement, controlElement);
123172
return html`<mwc-list-item
124173
graphic="large"
174+
?hasMeta=${fcdaCount !== 0}
125175
twoline
126176
class="subitem"
127177
@click=${() => this.onFcdaSelect(controlElement, fcdaElement)}
@@ -138,6 +188,7 @@ export class FcdaBindingList extends LitElement {
138188
${fcdaElement.getAttribute('lnInst')}
139189
</span>
140190
<mwc-icon slot="graphic">subdirectory_arrow_right</mwc-icon>
191+
${fcdaCount !== 0 ? html`<span slot="meta">${fcdaCount}</span>` : nothing}
141192
</mwc-list-item>`;
142193
}
143194

src/editors/subscription/foundation.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,38 @@ export function newIEDSelectEvent(
5454
}
5555

5656
export interface FcdaSelectDetail {
57-
controlElement: Element | undefined;
57+
control: Element | undefined;
5858
fcda: Element | undefined;
5959
}
6060
export type FcdaSelectEvent = CustomEvent<FcdaSelectDetail>;
6161
export function newFcdaSelectEvent(
62-
controlElement: Element | undefined,
62+
control: Element | undefined,
6363
fcda: Element | undefined,
6464
eventInitDict?: CustomEventInit<FcdaSelectDetail>
6565
): FcdaSelectEvent {
6666
return new CustomEvent<FcdaSelectDetail>('fcda-select', {
6767
bubbles: true,
6868
composed: true,
6969
...eventInitDict,
70-
detail: { controlElement, fcda, ...eventInitDict?.detail },
70+
detail: { control, fcda, ...eventInitDict?.detail },
71+
});
72+
}
73+
74+
export interface SubscriptionChangedDetail {
75+
control: Element | undefined;
76+
fcda: Element | undefined;
77+
}
78+
export type SubscriptionChangedEvent = CustomEvent<SubscriptionChangedDetail>;
79+
export function newSubscriptionChangedEvent(
80+
control: Element | undefined,
81+
fcda: Element | undefined,
82+
eventInitDict?: CustomEventInit<SubscriptionChangedDetail>
83+
): SubscriptionChangedEvent {
84+
return new CustomEvent<SubscriptionChangedDetail>('subscription-changed', {
85+
bubbles: true,
86+
composed: true,
87+
...eventInitDict,
88+
detail: { control, fcda, ...eventInitDict?.detail },
7189
});
7290
}
7391

@@ -408,5 +426,6 @@ declare global {
408426
['view']: ViewEvent;
409427
['ied-select']: IEDSelectEvent;
410428
['fcda-select']: FcdaSelectEvent;
429+
['subscription-changed']: SubscriptionChangedEvent;
411430
}
412431
}

src/editors/subscription/later-binding/ext-ref-later-binding-list.ts

Lines changed: 37 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { translate } from 'lit-translate';
1212

1313
import {
1414
cloneElement,
15-
compareNames,
1615
getDescriptionAttribute,
1716
identity,
1817
newActionEvent,
@@ -21,11 +20,15 @@ import {
2120

2221
import {
2322
FcdaSelectEvent,
24-
serviceTypes,
23+
newSubscriptionChangedEvent,
2524
styles,
2625
updateExtRefElement,
2726
} from '../foundation.js';
28-
import { isSubscribedTo } from './foundation.js';
27+
import {
28+
getExtRefElements,
29+
getSubscribedExtRefElements,
30+
isSubscribed,
31+
} from './foundation.js';
2932

3033
/**
3134
* A sub element for showing all Ext Refs from a FCDA Element.
@@ -55,41 +58,8 @@ export class ExtRefLaterBindingList extends LitElement {
5558
}
5659
}
5760

58-
private getExtRefElements(): Element[] {
59-
if (this.doc) {
60-
return Array.from(this.doc.querySelectorAll('ExtRef'))
61-
.filter(element => element.hasAttribute('intAddr'))
62-
.filter(element => element.closest('IED') !== this.currentIedElement)
63-
.sort((a, b) =>
64-
compareNames(
65-
`${a.getAttribute('intAddr')}`,
66-
`${b.getAttribute('intAddr')}`
67-
)
68-
);
69-
}
70-
return [];
71-
}
72-
73-
private getSubscribedExtRefElements(): Element[] {
74-
return this.getExtRefElements().filter(extRefElement =>
75-
isSubscribedTo(
76-
serviceTypes[this.controlTag],
77-
this.currentIedElement,
78-
this.currentSelectedControlElement,
79-
this.currentSelectedFcdaElement,
80-
extRefElement
81-
)
82-
);
83-
}
84-
85-
private getAvailableExtRefElements(): Element[] {
86-
return this.getExtRefElements().filter(
87-
element => !this.isSubscribed(element)
88-
);
89-
}
90-
9161
private async onFcdaSelectEvent(event: FcdaSelectEvent) {
92-
this.currentSelectedControlElement = event.detail.controlElement;
62+
this.currentSelectedControlElement = event.detail.control;
9363
this.currentSelectedFcdaElement = event.detail.fcda;
9464

9565
// Retrieve the IED Element to which the FCDA belongs.
@@ -99,23 +69,6 @@ export class ExtRefLaterBindingList extends LitElement {
9969
: undefined;
10070
}
10171

102-
/**
103-
* Check if the ExtRef is already subscribed to a FCDA Element.
104-
*
105-
* @param extRefElement - The Ext Ref Element to check.
106-
*/
107-
private isSubscribed(extRefElement: Element): boolean {
108-
return (
109-
extRefElement.hasAttribute('iedName') &&
110-
extRefElement.hasAttribute('ldInst') &&
111-
extRefElement.hasAttribute('prefix') &&
112-
extRefElement.hasAttribute('lnClass') &&
113-
extRefElement.hasAttribute('lnInst') &&
114-
extRefElement.hasAttribute('doName') &&
115-
extRefElement.hasAttribute('daName')
116-
);
117-
}
118-
11972
/**
12073
* The data attribute check using attributes pLN, pDO, pDA and pServT is not supported yet by this plugin.
12174
* To make sure the user does not do anything prohibited, this type of ExtRef cannot be manipulated for the time being.
@@ -194,6 +147,24 @@ export class ExtRefLaterBindingList extends LitElement {
194147
};
195148
}
196149

150+
private getSubscribedExtRefElements(): Element[] {
151+
return getSubscribedExtRefElements(
152+
<Element>this.doc.getRootNode(),
153+
this.controlTag,
154+
this.currentSelectedFcdaElement,
155+
this.currentSelectedControlElement,
156+
true
157+
);
158+
}
159+
160+
private getAvailableExtRefElements(): Element[] {
161+
return getExtRefElements(
162+
<Element>this.doc.getRootNode(),
163+
this.currentSelectedFcdaElement,
164+
true
165+
).filter(extRefElement => !isSubscribed(extRefElement));
166+
}
167+
197168
private renderTitle(): TemplateResult {
198169
return html`<h1>
199170
${translate(`subscription.laterBinding.extRefList.title`)}
@@ -226,6 +197,12 @@ export class ExtRefLaterBindingList extends LitElement {
226197
const replaceAction = this.unsubscribe(extRefElement);
227198
if (replaceAction) {
228199
this.dispatchEvent(newActionEvent(replaceAction));
200+
this.dispatchEvent(
201+
newSubscriptionChangedEvent(
202+
this.currentSelectedControlElement,
203+
this.currentSelectedFcdaElement
204+
)
205+
);
229206
}
230207
}}
231208
value="${identity(extRefElement)}"
@@ -277,6 +254,12 @@ export class ExtRefLaterBindingList extends LitElement {
277254
const replaceAction = this.subscribe(extRefElement);
278255
if (replaceAction) {
279256
this.dispatchEvent(newActionEvent(replaceAction));
257+
this.dispatchEvent(
258+
newSubscriptionChangedEvent(
259+
this.currentSelectedControlElement,
260+
this.currentSelectedFcdaElement
261+
)
262+
);
280263
}
281264
}}
282265
value="${identity(extRefElement)}"

0 commit comments

Comments
 (0)