Skip to content

Commit b1f2d12

Browse files
author
Rob Tjalma
authored
feat(Subscription): Select by Subscriber in Subscriptions Editor
1 parent 5a18318 commit b1f2d12

File tree

15 files changed

+1388
-224
lines changed

15 files changed

+1388
-224
lines changed

src/editors/Subscription.ts

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,76 @@
1-
import { LitElement, html, TemplateResult, property, css } from 'lit-element';
1+
import { LitElement, html, TemplateResult, property, css, query } from 'lit-element';
22

33
import '@material/mwc-fab';
4+
import '@material/mwc-radio';
5+
import '@material/mwc-formfield';
46

5-
import './subscription/subscriber-ied-list-goose.js';
6-
import './subscription/publisher-goose-list.js';
7+
import './subscription/subscriber-list.js';
8+
import './subscription/goose-publisher-list.js';
9+
import './subscription/goose-subscriber-list.js';
10+
import { translate } from 'lit-translate';
11+
import { newViewEvent, View, ViewEvent } from './subscription/foundation.js';
12+
import { RadioListItem } from '@material/mwc-list/mwc-radio-list-item';
13+
14+
/** Defining view outside the class, which makes it persistent. */
15+
let view: View = View.GOOSE_PUBLISHER;
716

817
/** An editor [[`plugin`]] for subscribing IEDs to GOOSE messages using the ABB subscription method. */
918
export default class SubscriptionABBPlugin extends LitElement {
1019
/** The document being edited as provided to plugins by [[`OpenSCD`]]. */
1120
@property()
1221
doc!: XMLDocument;
1322

23+
@query('#byGooseRadio')
24+
byGooseRadio!: RadioListItem;
25+
26+
@query('#byIedRadio')
27+
byIedRadio!: RadioListItem;
28+
29+
@query('div[class="container"]')
30+
listDiv!: Element;
31+
32+
constructor() {
33+
super();
34+
this.addEventListener('view', (evt: ViewEvent) => {
35+
view = evt.detail.view;
36+
this.requestUpdate();
37+
});
38+
}
39+
40+
firstUpdated(): void {
41+
view == View.GOOSE_PUBLISHER
42+
? this.byGooseRadio.setAttribute('checked', '')
43+
: this.byIedRadio.setAttribute('checked', '')
44+
}
45+
1446
render(): TemplateResult {
15-
return html` <div class="container">
16-
<publisher-goose-list class="row" .doc=${this.doc}></publisher-goose-list>
17-
<subscriber-ied-list-goose
18-
class="row"
19-
.doc=${this.doc}
20-
></subscriber-ied-list-goose>
47+
return html`<div>
48+
<mwc-formfield label="${translate('subscription.view.publisherView')}">
49+
<mwc-radio
50+
id="byGooseRadio"
51+
name="view"
52+
value="goose"
53+
@checked=${() => this.listDiv.dispatchEvent(newViewEvent(View.GOOSE_PUBLISHER))}
54+
></mwc-radio>
55+
</mwc-formfield>
56+
<mwc-formfield label="${translate('subscription.view.subscriberView')}">
57+
<mwc-radio
58+
id="byIedRadio"
59+
name="view"
60+
value="ied"
61+
@checked=${() => this.listDiv.dispatchEvent(newViewEvent(View.GOOSE_SUBSCRIBER))}
62+
></mwc-radio>
63+
</mwc-formfield>
64+
<div class="container">
65+
${view == View.GOOSE_PUBLISHER
66+
? html`<goose-publisher-list class="row" .doc=${this.doc}></goose-publisher-list>`
67+
: html`<goose-subscriber-list class="row" .doc=${this.doc}></goose-subscriber-list>`
68+
}
69+
<subscriber-list
70+
class="row"
71+
.doc=${this.doc}
72+
></subscriber-list>
73+
</div>
2174
</div>`;
2275
}
2376

src/editors/subscription/foundation.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ export enum SubscribeStatus {
99
None,
1010
}
1111

12+
/**
13+
* Enumeration stating the current view of the Subscription plugin.
14+
*/
15+
export enum View {
16+
GOOSE_PUBLISHER,
17+
GOOSE_SUBSCRIBER
18+
}
19+
1220
export interface GOOSESelectDetail {
1321
gseControl: Element | undefined;
1422
dataset: Element | undefined;
@@ -27,16 +35,48 @@ export function newGOOSESelectEvent(
2735
});
2836
}
2937

30-
export interface IEDSubscriptionDetail {
38+
export interface IEDSelectDetail {
39+
ied: Element | undefined;
40+
}
41+
export type IEDSelectEvent = CustomEvent<IEDSelectDetail>;
42+
export function newIEDSelectEvent(
43+
ied: Element | undefined,
44+
eventInitDict?: CustomEventInit<IEDSelectDetail>
45+
): IEDSelectEvent {
46+
return new CustomEvent<IEDSelectDetail>('ied-select', {
47+
bubbles: true,
48+
composed: true,
49+
...eventInitDict,
50+
detail: { ied, ...eventInitDict?.detail },
51+
});
52+
}
53+
54+
export interface ViewDetail {
55+
view: View;
56+
}
57+
export type ViewEvent = CustomEvent<ViewDetail>;
58+
export function newViewEvent(
59+
view: View,
60+
eventInitDict?: CustomEventInit<ViewDetail>
61+
): ViewEvent {
62+
return new CustomEvent<ViewDetail>('view', {
63+
bubbles: true,
64+
composed: true,
65+
...eventInitDict,
66+
detail: { view, ...eventInitDict?.detail },
67+
});
68+
}
69+
70+
export interface SubscriptionDetail {
3171
element: Element;
3272
subscribeStatus: SubscribeStatus;
3373
}
34-
export type IEDSubscriptionEvent = CustomEvent<IEDSubscriptionDetail>;
35-
export function newIEDSubscriptionEvent(
74+
export type SubscriptionEvent = CustomEvent<SubscriptionDetail>;
75+
export function newSubscriptionEvent(
3676
element: Element,
3777
subscribeStatus: SubscribeStatus
38-
): IEDSubscriptionEvent {
39-
return new CustomEvent<IEDSubscriptionDetail>('ied-subscription', {
78+
): SubscriptionEvent {
79+
return new CustomEvent<SubscriptionDetail>('subscription', {
4080
bubbles: true,
4181
composed: true,
4282
detail: { element, subscribeStatus },
@@ -114,6 +154,8 @@ export const styles = css`
114154
declare global {
115155
interface ElementEventMap {
116156
['goose-dataset']: GOOSESelectEvent;
117-
['ied-subscription']: IEDSubscriptionEvent;
157+
['subscription']: SubscriptionEvent;
158+
['ied-select']: IEDSelectEvent;
159+
['view']: ViewEvent;
118160
}
119161
}

src/editors/subscription/publisher-goose-list.ts renamed to src/editors/subscription/goose-publisher-list.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ function onOpenDocResetSelectedGooseMsg() {
2626
addEventListener('open-doc', onOpenDocResetSelectedGooseMsg);
2727

2828
/** An sub element for showing all published GOOSE messages per IED. */
29-
@customElement('publisher-goose-list')
30-
export class PublisherGOOSEList extends LitElement {
29+
@customElement('goose-publisher-list')
30+
export class GoosePublisherList extends LitElement {
3131
@property({ attribute: false })
3232
doc!: XMLDocument;
3333

@@ -52,13 +52,13 @@ export class PublisherGOOSEList extends LitElement {
5252
);
5353
}
5454

55-
private onGooseSelect(element: Element): void {
56-
const ln = element.parentElement;
55+
private onGooseSelect(gseControl: Element): void {
56+
const ln = gseControl.parentElement;
5757
const dataset = ln?.querySelector(
58-
`DataSet[name=${element.getAttribute('datSet')}]`
58+
`DataSet[name=${gseControl.getAttribute('datSet')}]`
5959
);
6060

61-
selectedGooseMsg = element;
61+
selectedGooseMsg = gseControl;
6262
selectedDataSet = dataset;
6363

6464
this.dispatchEvent(
@@ -69,12 +69,12 @@ export class PublisherGOOSEList extends LitElement {
6969
);
7070
}
7171

72-
renderGoose(element: Element): TemplateResult {
72+
renderGoose(gseControl: Element): TemplateResult {
7373
return html`<mwc-list-item
74-
@click=${() => this.onGooseSelect(element)}
74+
@click=${() => this.onGooseSelect(gseControl)}
7575
graphic="large"
7676
>
77-
<span>${element.getAttribute('name')}</span>
77+
<span>${gseControl.getAttribute('name')}</span>
7878
<mwc-icon slot="graphic">${gooseIcon}</mwc-icon>
7979
</mwc-list-item>`;
8080
}
@@ -100,8 +100,8 @@ export class PublisherGOOSEList extends LitElement {
100100
<mwc-icon slot="graphic">developer_board</mwc-icon>
101101
</mwc-list-item>
102102
<li divider role="separator"></li>
103-
${this.getGSEControls(ied).map(control =>
104-
this.renderGoose(control)
103+
${this.getGSEControls(ied).map(gseControl =>
104+
this.renderGoose(gseControl)
105105
)}
106106
`
107107
)}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {
2+
css,
3+
customElement,
4+
html,
5+
LitElement,
6+
property,
7+
TemplateResult,
8+
} from 'lit-element';
9+
import { translate } from 'lit-translate';
10+
11+
import '@material/mwc-icon';
12+
import '@material/mwc-list/mwc-list-item';
13+
14+
import '../../filtered-list.js';
15+
import { compareNames, getNameAttribute } from '../../foundation.js';
16+
import { newIEDSelectEvent, styles } from './foundation.js';
17+
18+
let selectedIed: Element | undefined;
19+
20+
function onOpenDocResetSelectedGooseMsg() {
21+
selectedIed = undefined;
22+
}
23+
addEventListener('open-doc', onOpenDocResetSelectedGooseMsg);
24+
25+
@customElement('goose-subscriber-list')
26+
export class GooseSubscriberList extends LitElement {
27+
@property({ attribute: false })
28+
doc!: XMLDocument;
29+
30+
private get ieds(): Element[] {
31+
return this.doc
32+
? Array.from(this.doc.querySelectorAll(':root > IED')).sort((a, b) =>
33+
compareNames(a, b)
34+
)
35+
: [];
36+
}
37+
38+
private onIedSelect(element: Element): void {
39+
selectedIed = element;
40+
41+
this.dispatchEvent(
42+
newIEDSelectEvent(
43+
selectedIed
44+
)
45+
);
46+
}
47+
48+
protected firstUpdated(): void {
49+
this.dispatchEvent(
50+
newIEDSelectEvent(
51+
selectedIed
52+
)
53+
);
54+
}
55+
56+
render(): TemplateResult {
57+
return html` <section tabindex="0">
58+
<h1>${translate('subscription.subscriberGoose.title')}</h1>
59+
<filtered-list>
60+
${this.ieds.map(
61+
ied =>
62+
html`
63+
<mwc-list-item
64+
@click=${() => this.onIedSelect(ied)}
65+
graphic="icon"
66+
>
67+
<span>${getNameAttribute(ied)}</span>
68+
<mwc-icon slot="graphic">developer_board</mwc-icon>
69+
</mwc-list-item>
70+
`
71+
)}
72+
</filtered-list>
73+
</section>`;
74+
}
75+
76+
static styles = css`
77+
${styles}
78+
`;
79+
}

0 commit comments

Comments
 (0)