Skip to content

Commit

Permalink
feat(editor/subscriber): Show counter for Subscriber Plugins (Logical…
Browse files Browse the repository at this point in the history
… Nodes / Later) (GOOSE/SMV) (#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.
  • Loading branch information
Dennis Labordus committed Oct 13, 2022
1 parent 1c55aed commit 02ec714
Show file tree
Hide file tree
Showing 20 changed files with 634 additions and 433 deletions.
3 changes: 2 additions & 1 deletion src/editors/GooseSubscriberDataBinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export default class GooseSubscribeDataBindingPlugin extends LitElement {
<fcda-binding-list
class="column"
controlTag="GSEControl"
.doc=${this.doc}
.includeLaterBinding="${false}"
.doc="${this.doc}"
>
</fcda-binding-list>
<extref-ln-binding-list
Expand Down
5 changes: 3 additions & 2 deletions src/editors/GooseSubscriberLaterBinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ export default class GooseSubscribeLaterBindingPlugin extends LitElement {
<div class="container">
<fcda-binding-list
class="column"
.doc=${this.doc}
controlTag="GSEControl"
.includeLaterBinding="${true}"
.doc="${this.doc}"
>
</fcda-binding-list>
<extref-later-binding-list
class="column"
controlTag="GSEControl"
.doc=${this.doc}
.doc="${this.doc}"
>
</extref-later-binding-list>
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/editors/SMVSubscriberDataBinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export default class SMVSubscribeDataBindingPlugin extends LitElement {
<fcda-binding-list
class="column"
controlTag="SampledValueControl"
.doc=${this.doc}
.includeLaterBinding="${false}"
.doc="${this.doc}"
>
</fcda-binding-list>
<extref-ln-binding-list
Expand Down
5 changes: 3 additions & 2 deletions src/editors/SMVSubscriberLaterBinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ export default class SMVSubscribeLaterBindingPlugin extends LitElement {
<div class="container">
<fcda-binding-list
class="column"
.doc=${this.doc}
controlTag="SampledValueControl"
.includeLaterBinding="${true}"
.doc="${this.doc}"
>
</fcda-binding-list>
<extref-later-binding-list
class="column"
.doc=${this.doc}
controlTag="SampledValueControl"
.doc="${this.doc}"
>
</extref-later-binding-list>
</div>
Expand Down
71 changes: 61 additions & 10 deletions src/editors/subscription/fcda-binding-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import '@material/mwc-list';
import '@material/mwc-list/mwc-list-item';

import {
compareNames,
getDescriptionAttribute,
getNameAttribute,
identity,
Expand All @@ -25,7 +24,13 @@ import {
import { gooseIcon, smvIcon } from '../../icons/icons.js';
import { wizards } from '../../wizards/wizard-library.js';

import { getFcdaTitleValue, newFcdaSelectEvent, styles } from './foundation.js';
import {
getFcdaTitleValue,
newFcdaSelectEvent,
styles,
SubscriptionChangedEvent,
} from './foundation.js';
import { getSubscribedExtRefElements } from './later-binding/foundation.js';

type controlTag = 'SampledValueControl' | 'GSEControl';

Expand All @@ -42,14 +47,18 @@ export class FcdaBindingList extends LitElement {
doc!: XMLDocument;
@property()
controlTag!: controlTag;
@property()
includeLaterBinding!: boolean;

// The selected Elements when a FCDA Line is clicked.
@state()
selectedControlElement: Element | undefined;
private selectedControlElement: Element | undefined;
@state()
selectedFcdaElement: Element | undefined;
private selectedFcdaElement: Element | undefined;
@state()
private extRefCounters = new Map();

iconControlLookup: iconLookup = {
private iconControlLookup: iconLookup = {
SampledValueControl: smvIcon,
GSEControl: gooseIcon,
};
Expand All @@ -59,13 +68,17 @@ export class FcdaBindingList extends LitElement {

this.resetSelection = this.resetSelection.bind(this);
parent.addEventListener('open-doc', this.resetSelection);

const parentDiv = this.closest('.container');
if (parentDiv) {
this.resetExtRefCount = this.resetExtRefCount.bind(this);
parentDiv.addEventListener('subscription-changed', this.resetExtRefCount);
}
}

private getControlElements(): Element[] {
if (this.doc) {
return Array.from(
this.doc.querySelectorAll(`LN0 > ${this.controlTag}`)
).sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
return Array.from(this.doc.querySelectorAll(`LN0 > ${this.controlTag}`));
}
return [];
}
Expand All @@ -79,11 +92,40 @@ export class FcdaBindingList extends LitElement {
'datSet'
)}] > FCDA`
)
).sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
);
}
return [];
}

private resetExtRefCount(event: SubscriptionChangedEvent): void {
if (event.detail.control && event.detail.fcda) {
const controlBlockFcdaId = `${identity(event.detail.control)} ${identity(
event.detail.fcda
)}`;
this.extRefCounters.delete(controlBlockFcdaId);
}
}

private getExtRefCount(
fcdaElement: Element,
controlElement: Element
): number {
const controlBlockFcdaId = `${identity(controlElement)} ${identity(
fcdaElement
)}`;
if (!this.extRefCounters.has(controlBlockFcdaId)) {
const extRefCount = getSubscribedExtRefElements(
<Element>this.doc.getRootNode(),
this.controlTag,
fcdaElement,
controlElement!,
this.includeLaterBinding
).length;
this.extRefCounters.set(controlBlockFcdaId, extRefCount);
}
return this.extRefCounters.get(controlBlockFcdaId);
}

private openEditWizard(controlElement: Element): void {
const wizard = wizards[this.controlTag].edit(controlElement);
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
Expand All @@ -104,7 +146,8 @@ export class FcdaBindingList extends LitElement {
protected updated(_changedProperties: PropertyValues): void {
super.updated(_changedProperties);

// When the document is updated, we will fire the event again.
// When a new document is loaded or the selection is changed
// we will fire the FCDA Select Event.
if (
_changedProperties.has('doc') ||
_changedProperties.has('selectedControlElement') ||
Expand All @@ -117,11 +160,18 @@ export class FcdaBindingList extends LitElement {
)
);
}

// When a new document is loaded we will reset the Map to clear old entries.
if (_changedProperties.has('doc')) {
this.extRefCounters = new Map();
}
}

renderFCDA(controlElement: Element, fcdaElement: Element): TemplateResult {
const fcdaCount = this.getExtRefCount(fcdaElement, controlElement);
return html`<mwc-list-item
graphic="large"
?hasMeta=${fcdaCount !== 0}
twoline
class="subitem"
@click=${() => this.onFcdaSelect(controlElement, fcdaElement)}
Expand All @@ -138,6 +188,7 @@ export class FcdaBindingList extends LitElement {
${fcdaElement.getAttribute('lnInst')}
</span>
<mwc-icon slot="graphic">subdirectory_arrow_right</mwc-icon>
${fcdaCount !== 0 ? html`<span slot="meta">${fcdaCount}</span>` : nothing}
</mwc-list-item>`;
}

Expand Down
25 changes: 22 additions & 3 deletions src/editors/subscription/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,38 @@ export function newIEDSelectEvent(
}

export interface FcdaSelectDetail {
controlElement: Element | undefined;
control: Element | undefined;
fcda: Element | undefined;
}
export type FcdaSelectEvent = CustomEvent<FcdaSelectDetail>;
export function newFcdaSelectEvent(
controlElement: Element | undefined,
control: Element | undefined,
fcda: Element | undefined,
eventInitDict?: CustomEventInit<FcdaSelectDetail>
): FcdaSelectEvent {
return new CustomEvent<FcdaSelectDetail>('fcda-select', {
bubbles: true,
composed: true,
...eventInitDict,
detail: { controlElement, fcda, ...eventInitDict?.detail },
detail: { control, fcda, ...eventInitDict?.detail },
});
}

export interface SubscriptionChangedDetail {
control: Element | undefined;
fcda: Element | undefined;
}
export type SubscriptionChangedEvent = CustomEvent<SubscriptionChangedDetail>;
export function newSubscriptionChangedEvent(
control: Element | undefined,
fcda: Element | undefined,
eventInitDict?: CustomEventInit<SubscriptionChangedDetail>
): SubscriptionChangedEvent {
return new CustomEvent<SubscriptionChangedDetail>('subscription-changed', {
bubbles: true,
composed: true,
...eventInitDict,
detail: { control, fcda, ...eventInitDict?.detail },
});
}

Expand Down Expand Up @@ -408,5 +426,6 @@ declare global {
['view']: ViewEvent;
['ied-select']: IEDSelectEvent;
['fcda-select']: FcdaSelectEvent;
['subscription-changed']: SubscriptionChangedEvent;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { translate } from 'lit-translate';

import {
cloneElement,
compareNames,
getDescriptionAttribute,
identity,
newActionEvent,
Expand All @@ -21,11 +20,15 @@ import {

import {
FcdaSelectEvent,
serviceTypes,
newSubscriptionChangedEvent,
styles,
updateExtRefElement,
} from '../foundation.js';
import { isSubscribedTo } from './foundation.js';
import {
getExtRefElements,
getSubscribedExtRefElements,
isSubscribed,
} from './foundation.js';

/**
* A sub element for showing all Ext Refs from a FCDA Element.
Expand Down Expand Up @@ -55,41 +58,8 @@ export class ExtRefLaterBindingList extends LitElement {
}
}

private getExtRefElements(): Element[] {
if (this.doc) {
return Array.from(this.doc.querySelectorAll('ExtRef'))
.filter(element => element.hasAttribute('intAddr'))
.filter(element => element.closest('IED') !== this.currentIedElement)
.sort((a, b) =>
compareNames(
`${a.getAttribute('intAddr')}`,
`${b.getAttribute('intAddr')}`
)
);
}
return [];
}

private getSubscribedExtRefElements(): Element[] {
return this.getExtRefElements().filter(extRefElement =>
isSubscribedTo(
serviceTypes[this.controlTag],
this.currentIedElement,
this.currentSelectedControlElement,
this.currentSelectedFcdaElement,
extRefElement
)
);
}

private getAvailableExtRefElements(): Element[] {
return this.getExtRefElements().filter(
element => !this.isSubscribed(element)
);
}

private async onFcdaSelectEvent(event: FcdaSelectEvent) {
this.currentSelectedControlElement = event.detail.controlElement;
this.currentSelectedControlElement = event.detail.control;
this.currentSelectedFcdaElement = event.detail.fcda;

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

/**
* Check if the ExtRef is already subscribed to a FCDA Element.
*
* @param extRefElement - The Ext Ref Element to check.
*/
private isSubscribed(extRefElement: Element): boolean {
return (
extRefElement.hasAttribute('iedName') &&
extRefElement.hasAttribute('ldInst') &&
extRefElement.hasAttribute('prefix') &&
extRefElement.hasAttribute('lnClass') &&
extRefElement.hasAttribute('lnInst') &&
extRefElement.hasAttribute('doName') &&
extRefElement.hasAttribute('daName')
);
}

/**
* The data attribute check using attributes pLN, pDO, pDA and pServT is not supported yet by this plugin.
* To make sure the user does not do anything prohibited, this type of ExtRef cannot be manipulated for the time being.
Expand Down Expand Up @@ -194,6 +147,24 @@ export class ExtRefLaterBindingList extends LitElement {
};
}

private getSubscribedExtRefElements(): Element[] {
return getSubscribedExtRefElements(
<Element>this.doc.getRootNode(),
this.controlTag,
this.currentSelectedFcdaElement,
this.currentSelectedControlElement,
true
);
}

private getAvailableExtRefElements(): Element[] {
return getExtRefElements(
<Element>this.doc.getRootNode(),
this.currentSelectedFcdaElement,
true
).filter(extRefElement => !isSubscribed(extRefElement));
}

private renderTitle(): TemplateResult {
return html`<h1>
${translate(`subscription.laterBinding.extRefList.title`)}
Expand Down Expand Up @@ -226,6 +197,12 @@ export class ExtRefLaterBindingList extends LitElement {
const replaceAction = this.unsubscribe(extRefElement);
if (replaceAction) {
this.dispatchEvent(newActionEvent(replaceAction));
this.dispatchEvent(
newSubscriptionChangedEvent(
this.currentSelectedControlElement,
this.currentSelectedFcdaElement
)
);
}
}}
value="${identity(extRefElement)}"
Expand Down Expand Up @@ -277,6 +254,12 @@ export class ExtRefLaterBindingList extends LitElement {
const replaceAction = this.subscribe(extRefElement);
if (replaceAction) {
this.dispatchEvent(newActionEvent(replaceAction));
this.dispatchEvent(
newSubscriptionChangedEvent(
this.currentSelectedControlElement,
this.currentSelectedFcdaElement
)
);
}
}}
value="${identity(extRefElement)}"
Expand Down
Loading

0 comments on commit 02ec714

Please sign in to comment.