Skip to content

Commit 1c55aed

Browse files
author
Dennis Labordus
authored
feat(editor/subscriber): Subscribe and unsubscribe for Subscriber Logical Nodes (GOOSE/SMV) (openscd#1039)
* 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 * Processed review comments. * Review comments processed * Fixed tests.
1 parent 971f0c1 commit 1c55aed

File tree

12 files changed

+492
-30
lines changed

12 files changed

+492
-30
lines changed

src/editors/subscription/goose/subscriber-list.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
property,
66
TemplateResult,
77
} from 'lit-element';
8-
import { translate } from 'lit-translate';
8+
import { get, translate } from 'lit-translate';
99

1010
import '@material/mwc-icon';
1111
import '@material/mwc-list';
@@ -20,9 +20,9 @@ import {
2020
newActionEvent,
2121
} from '../../../foundation.js';
2222
import {
23-
newGooseSubscriptionEvent,
2423
GOOSESelectEvent,
2524
GooseSubscriptionEvent,
25+
newGooseSubscriptionEvent,
2626
} from './foundation.js';
2727
import {
2828
emptyInputsDeleteActions,
@@ -266,7 +266,7 @@ export class SubscriberList extends SubscriberListContainer {
266266
});
267267

268268
/** If the IED doesn't have a Inputs element, just append it to the first LN0 element. */
269-
const title = 'Connect';
269+
const title = get('subscription.connect');
270270
if (inputsElement.parentElement) {
271271
this.dispatchEvent(newActionEvent({ title, actions }));
272272
} else {
@@ -295,7 +295,7 @@ export class SubscriberList extends SubscriberListContainer {
295295

296296
this.dispatchEvent(
297297
newActionEvent({
298-
title: 'Disconnect',
298+
title: get('subscription.disconnect'),
299299
actions: actions,
300300
})
301301
);
@@ -413,7 +413,7 @@ export class SubscriberList extends SubscriberListContainer {
413413
}
414414

415415
protected firstUpdated(): void {
416-
this.currentSelectedIed = undefined
416+
this.currentSelectedIed = undefined;
417417
}
418418

419419
render(): TemplateResult {

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,15 @@ export class ExtRefLaterBindingList extends LitElement {
137137
*
138138
* @param extRefElement - The Ext Ref Element to clean from attributes.
139139
*/
140-
private unsubscribe(extRefElement: Element): Replace {
140+
private unsubscribe(extRefElement: Element): Replace | null {
141+
if (
142+
!this.currentIedElement ||
143+
!this.currentSelectedFcdaElement ||
144+
!this.currentSelectedControlElement!
145+
) {
146+
return null;
147+
}
148+
141149
const clonedExtRefElement = cloneElement(extRefElement, {
142150
iedName: null,
143151
ldInst: null,
@@ -215,9 +223,10 @@ export class ExtRefLaterBindingList extends LitElement {
215223
graphic="large"
216224
twoline
217225
@click=${() => {
218-
this.dispatchEvent(
219-
newActionEvent(this.unsubscribe(extRefElement))
220-
);
226+
const replaceAction = this.unsubscribe(extRefElement);
227+
if (replaceAction) {
228+
this.dispatchEvent(newActionEvent(replaceAction));
229+
}
221230
}}
222231
value="${identity(extRefElement)}"
223232
>

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

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,31 @@ import {
77
state,
88
TemplateResult,
99
} from 'lit-element';
10-
import { translate } from 'lit-translate';
10+
import { get, translate } from 'lit-translate';
1111

12-
import { identity } from '../../../foundation.js';
12+
import {
13+
ComplexAction,
14+
Create,
15+
createElement,
16+
Delete,
17+
identity,
18+
newActionEvent,
19+
} from '../../../foundation.js';
1320
import { Nsdoc } from '../../../foundation/nsdoc.js';
1421

15-
import { FcdaSelectEvent, serviceTypes, styles } from '../foundation.js';
22+
import {
23+
canCreateValidExtRef,
24+
createExtRefElement,
25+
existExtRef,
26+
FcdaSelectEvent,
27+
serviceTypes,
28+
styles,
29+
} from '../foundation.js';
1630
import { isSubscribedTo } from './foundation.js';
31+
import {
32+
emptyInputsDeleteActions,
33+
getFcdaReferences,
34+
} from '../../../foundation/ied.js';
1735

1836
/**
1937
* A sub element for showing all Ext Refs from a FCDA Element.
@@ -106,6 +124,68 @@ export class ExtRefLnBindingList extends LitElement {
106124
: undefined;
107125
}
108126

127+
private subscribe(lnElement: Element): ComplexAction | null {
128+
if (
129+
!this.currentIedElement ||
130+
!this.currentSelectedFcdaElement ||
131+
!this.currentSelectedControlElement!
132+
) {
133+
return null;
134+
}
135+
136+
const actions: Create[] = [];
137+
let inputsElement = lnElement.querySelector(':scope > Inputs');
138+
if (!inputsElement) {
139+
inputsElement = createElement(lnElement.ownerDocument, 'Inputs', {});
140+
actions.push({ new: { parent: lnElement, element: inputsElement } });
141+
}
142+
143+
if (
144+
!existExtRef(inputsElement!, this.currentSelectedFcdaElement) &&
145+
canCreateValidExtRef(
146+
this.currentSelectedFcdaElement,
147+
this.currentSelectedControlElement
148+
)
149+
) {
150+
const extRef = createExtRefElement(
151+
this.currentSelectedControlElement,
152+
this.currentSelectedFcdaElement
153+
);
154+
actions.push({ new: { parent: inputsElement, element: extRef } });
155+
}
156+
157+
const title = get('subscription.connect');
158+
return { title, actions };
159+
}
160+
161+
private unsubscribe(lnElement: Element): ComplexAction | null {
162+
if (
163+
!this.currentIedElement ||
164+
!this.currentSelectedFcdaElement ||
165+
!this.currentSelectedControlElement!
166+
) {
167+
return null;
168+
}
169+
170+
const actions: Delete[] = [];
171+
const inputElement = lnElement.querySelector(':scope > Inputs')!;
172+
const extRefElement = inputElement.querySelector(
173+
`ExtRef[iedName=${this.currentIedElement.getAttribute('name')}]` +
174+
`${getFcdaReferences(this.currentSelectedFcdaElement)}`
175+
);
176+
if (extRefElement) {
177+
actions.push({ old: { parent: inputElement, element: extRefElement } });
178+
}
179+
180+
// Check if empty Input Element should also be removed.
181+
actions.push(...emptyInputsDeleteActions(actions));
182+
183+
return {
184+
title: get('subscription.disconnect'),
185+
actions: actions,
186+
};
187+
}
188+
109189
private bindingNotSupported(lnElement: Element): boolean {
110190
const iedElement = lnElement.closest('IED')!;
111191
return (
@@ -156,6 +236,12 @@ export class ExtRefLnBindingList extends LitElement {
156236
?disabled=${this.bindingNotSupported(lnElement)}
157237
twoline
158238
value="${identity(lnElement)}"
239+
@click=${() => {
240+
const replaceAction = this.unsubscribe(lnElement);
241+
if (replaceAction) {
242+
this.dispatchEvent(newActionEvent(replaceAction));
243+
}
244+
}}
159245
>
160246
<span>${this.buildLNTitle(lnElement)}</span>
161247
<span slot="secondary">
@@ -196,6 +282,12 @@ export class ExtRefLnBindingList extends LitElement {
196282
?disabled=${this.bindingNotSupported(lnElement)}
197283
twoline
198284
value="${identity(lnElement)}"
285+
@click=${() => {
286+
const replaceAction = this.subscribe(lnElement);
287+
if (replaceAction) {
288+
this.dispatchEvent(newActionEvent(replaceAction));
289+
}
290+
}}
199291
>
200292
<span>${this.buildLNTitle(lnElement)}</span>
201293
<span slot="secondary">

src/editors/subscription/sampledvalues/subscriber-list.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
property,
66
TemplateResult,
77
} from 'lit-element';
8-
import { translate } from 'lit-translate';
8+
import { get, translate } from 'lit-translate';
99

1010
import '@material/mwc-icon';
1111
import '@material/mwc-list';
@@ -268,7 +268,7 @@ export class SubscriberList extends SubscriberListContainer {
268268
});
269269

270270
/** If the IED doesn't have a Inputs element, just append it to the first LN0 element. */
271-
const title = 'Connect';
271+
const title = get('subscription.connect');
272272
if (inputsElement.parentElement)
273273
this.dispatchEvent(newActionEvent({ title, actions }));
274274
else {
@@ -297,7 +297,7 @@ export class SubscriberList extends SubscriberListContainer {
297297

298298
this.dispatchEvent(
299299
newActionEvent({
300-
title: 'Disconnect',
300+
title: get('subscription.disconnect'),
301301
actions: actions,
302302
})
303303
);
@@ -415,7 +415,7 @@ export class SubscriberList extends SubscriberListContainer {
415415
}
416416

417417
protected firstUpdated(): void {
418-
this.currentSelectedIed = undefined
418+
this.currentSelectedIed = undefined;
419419
}
420420

421421
render(): TemplateResult {

src/translations/de.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ export const de: Translations = {
337337
},
338338
subscription: {
339339
none: 'Keine Verbindung vorhanden',
340+
connect: 'Daten-Attribut verbunden',
341+
disconnect: 'Daten-Attribute Verbindung gelöst',
340342
subscriber: {
341343
subscribed: 'Verbunden',
342344
availableToSubscribe: 'Kann verbunden werden',

src/translations/en.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ export const en = {
334334
},
335335
subscription: {
336336
none: 'None',
337+
connect: 'Connect data attribute',
338+
disconnect: 'Disconnect data attribute',
337339
subscriber: {
338340
subscribed: 'Subscribed',
339341
availableToSubscribe: 'Available to subscribe',

0 commit comments

Comments
 (0)