Skip to content

Commit 2d98615

Browse files
Dennis LabordusRob Tjalma
andauthored
Merge pull request openscd#834 from openscd/104-plugin
* Added new Communication 104 Editor framework. * Added List of IEDs and 104-related DAI to values screen. * Renamed Communication104 to Protocol104. * Renamed Communication104 to Protocol104. * Renamed Communication104 to Protocol104. * Refactor ied-container and add tests for different components of 104. * Added documentation. * Small changes. * feat(104/values): Added List of IEDs and 104-related DAI to values screen. * Refactor list of 104 Address and add wizard to edit existing Address Elements. * Small fixes. * feat(editors/104): Show/edit subnetworks without redundancy * First support of CDC's adding 104 Addresses. * Added create wizard + extra unit tests * Added unit tests * Added some more CDC supported to configuration. * Added Control versions of CDC and first part of refactoring are 104 discussion. * Added Control versions of CDC and first part of refactoring are 104 discussion. * Small changes regarding creating the Address elements. * Small changes regarding creating the Address elements. * Small changes regarding creating the Address elements. * Small changes regarding creating the Address elements. * Small changes regarding creating the Address elements. * Changed handling inverted, request engineer if needed, react on answer. * Changed handling inverted, request engineer if needed, react on answer. * Added check for redundancy * Added correct redundancy switch functionality * Added logic to handle Check Addresses. * Fixed tests. * Fixed tests. * Implemented check for redundancy group * Fixed snapshot tests. * Fixed Wizard Menu. * Added redundancy group wizard * First version of handling Expected Values. * working write * Refactor some foundation functions for 104 and fixed tests. * Implemented Logic Link wizard * Added Logic Links wizard to Redundancy Group wizard * Small changes.: * Refactoring * Refactored Logic Link translations * Refactoring * Refactoring and added some tests. * Fixing Redundancy Group translations * Fixed connectedAP translations * Added Logic Link remove * Added Redundancy Group remove * Fixed translations for Add Redundancy Group * Added Logic Link unit tests * Added Redundancy Group unit tests * Refactoring and adding test for 104 Address. * Changed DOI Info Wizard to show detailed info about known/found TIs * Refactoring * Implemented Redundancy Group create wizard * Small change and some refactoring. * Small fix * Fixed snapshots. * Fixed snapshots. * Use default close button. * Fixed snapshots. * Fixing Logic Link review * Fixed Redundancy Group tests * Typo * Typo * Review comments * Unit test fix * Changed Create action into Replace in Redundancy wizard * Missing snapshot file. * Merged functions for creating textfields into 1 function * Missing Logic Link fields are also created now during editing * Removed typos * First steps changing code to support uninitialized DO structures. * Review comments. * Formatted language files. * Changed tests. * First working version of initializing DO Structure. * Fixed doi wizard test. * Added test and documentation. * Fixed issue with existing DAI Elements and updated test. * Temporary fix to refresh components. * Fixed input field issue using live directive. * Moved import statement * feat(104-plugin): add some German translations * Fixed build and processed some review comments. * Review comments processed. Signed-off-by: Dennis Labordus <[email protected]> Co-authored-by: Rob Tjalma <[email protected]> Co-authored-by: Christian Dinkel <[email protected]>`
2 parents f082d20 + 72fdfdd commit 2d98615

File tree

79 files changed

+14699
-63
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+14699
-63
lines changed

public/js/plugins.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ export const officialPlugins = [
4141
default: true,
4242
kind: 'editor',
4343
},
44+
{
45+
name: '104',
46+
src: '/src/editors/Protocol104.js',
47+
icon: 'settings_ethernet',
48+
default: false,
49+
kind: 'editor',
50+
},
4451
{
4552
name: 'Templates',
4653
src: '/src/editors/Templates.js',

src/editors/Protocol104.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import {
2+
css,
3+
html,
4+
LitElement,
5+
property,
6+
query,
7+
TemplateResult
8+
} from "lit-element";
9+
import {translate} from "lit-translate";
10+
11+
import '@material/mwc-fab';
12+
import '@material/mwc-radio';
13+
import '@material/mwc-formfield';
14+
15+
import {RadioListItem} from "@material/mwc-list/mwc-radio-list-item";
16+
17+
import './protocol104/network-container.js'
18+
import './protocol104/values-container.js'
19+
20+
import {
21+
newViewEvent,
22+
View,
23+
VIEW_EVENT_NAME,
24+
ViewEvent
25+
} from "./protocol104/foundation/foundation.js";
26+
27+
/** Defining view outside the class, which makes it persistent. */
28+
let selectedViewProtocol104Plugin: View = View.VALUES;
29+
30+
export default class Communication104Plugin extends LitElement {
31+
@property()
32+
doc!: XMLDocument;
33+
34+
@query('#byValuesRadio')
35+
byValuesRadio!: RadioListItem;
36+
37+
@query('#byNetworkRadio')
38+
byNetworkRadio!: RadioListItem;
39+
40+
@query('div#containers')
41+
listDiv!: Element;
42+
43+
constructor() {
44+
super();
45+
46+
this.addEventListener(VIEW_EVENT_NAME, (evt: ViewEvent) => {
47+
selectedViewProtocol104Plugin = evt.detail.view;
48+
this.requestUpdate();
49+
});
50+
}
51+
52+
firstUpdated(): void {
53+
selectedViewProtocol104Plugin == View.VALUES
54+
? this.byValuesRadio.setAttribute('checked', '')
55+
: this.byNetworkRadio.setAttribute('checked', '')
56+
}
57+
58+
render(): TemplateResult {
59+
return html `
60+
<section>
61+
<div>
62+
<mwc-formfield label="${translate('protocol104.view.valuesView')}">
63+
<mwc-radio
64+
id="byValuesRadio"
65+
name="view"
66+
value="values"
67+
@checked=${() => this.listDiv.dispatchEvent(newViewEvent(View.VALUES))}
68+
></mwc-radio>
69+
</mwc-formfield>
70+
<mwc-formfield label="${translate('protocol104.view.networkView')}">
71+
<mwc-radio
72+
id="byNetworkRadio"
73+
name="view"
74+
value="network"
75+
@checked=${() => this.listDiv.dispatchEvent(newViewEvent(View.NETWORK))}
76+
></mwc-radio>
77+
</mwc-formfield>
78+
<div id="containers">
79+
${selectedViewProtocol104Plugin == View.VALUES
80+
? html `<values-104-container .doc=${this.doc}></values-104-container>`
81+
: html `<network-104-container .doc=${this.doc}></network-104-container>`
82+
}
83+
</div>
84+
</div>
85+
</section>`;
86+
}
87+
88+
static styles = css`
89+
:host {
90+
width: 100vw;
91+
}
92+
93+
section {
94+
padding: 8px 12px 16px;
95+
}
96+
`;
97+
}

src/editors/ied/da-container.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export class DAContainer extends Container {
114114
// Next create all missing elements (DOI/SDI/DOI)
115115
const newElement = initializeElements(uninitializedTemplateStructure);
116116

117-
if (parentElement && newElement) {
117+
if (newElement) {
118118
const wizard = createDAIWizard(parentElement, newElement, this.element);
119119
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
120120
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { LitElement, property } from 'lit-element';
2+
3+
export class Base104Container extends LitElement {
4+
@property()
5+
doc!: XMLDocument;
6+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { customElement, html, property, TemplateResult } from 'lit-element';
2+
3+
import '@material/mwc-fab';
4+
5+
import '../../action-icon.js';
6+
import { newActionEvent, newWizardEvent } from '../../foundation.js';
7+
import { editConnectedApWizard } from './wizards/connectedap.js';
8+
import { Base104Container } from './base-container.js';
9+
10+
/** [[`104`]] subeditor for a `ConnectedAP` element. */
11+
@customElement('connectedap-104-editor')
12+
export class ConnectedAP104Editor extends Base104Container {
13+
/** SCL element ConnectedAP */
14+
@property({ attribute: false })
15+
element!: Element;
16+
17+
private openEditWizard(): void {
18+
this.dispatchEvent(
19+
newWizardEvent(() =>
20+
editConnectedApWizard(
21+
this.element,
22+
this.element.querySelectorAll('Address > P[type^="RG"]').length > 0
23+
)
24+
)
25+
);
26+
}
27+
28+
remove(): void {
29+
if (this.element)
30+
this.dispatchEvent(
31+
newActionEvent({
32+
old: {
33+
parent: this.element.parentElement!,
34+
element: this.element,
35+
reference: this.element.nextSibling,
36+
},
37+
})
38+
);
39+
}
40+
41+
render(): TemplateResult {
42+
return html`
43+
<action-icon
44+
label="${this.element.getAttribute('apName') ?? 'UNDEFINED'}"
45+
icon="settings_input_hdmi"
46+
><mwc-fab
47+
slot="action"
48+
mini
49+
icon="edit"
50+
@click="${() => this.openEditWizard()}"
51+
></mwc-fab>
52+
<mwc-fab
53+
slot="action"
54+
mini
55+
icon="delete"
56+
@click="${() => this.remove()}}"
57+
></mwc-fab
58+
></action-icon>
59+
`;
60+
}
61+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import {
2+
css,
3+
customElement,
4+
html,
5+
property,
6+
query,
7+
TemplateResult,
8+
} from 'lit-element';
9+
import { translate } from 'lit-translate';
10+
import { nothing } from 'lit-html';
11+
12+
import { IconButtonToggle } from '@material/mwc-icon-button-toggle';
13+
14+
import '@material/mwc-icon';
15+
import '@material/mwc-icon-button';
16+
import '@material/mwc-icon-button-toggle';
17+
import '@material/mwc-list';
18+
import '@material/mwc-list/mwc-list-item';
19+
20+
import { newWizardEvent } from '../../foundation.js';
21+
22+
import '../../action-pane.js';
23+
24+
import {
25+
get104DetailsLine,
26+
getCdcValueFromDOIElement,
27+
getFullPath,
28+
} from './foundation/foundation.js';
29+
import { editAddressWizard } from './wizards/address.js';
30+
import { showDOIInfoWizard } from './wizards/doi.js';
31+
import { PROTOCOL_104_PRIVATE } from './foundation/private.js';
32+
import { Base104Container } from './base-container.js';
33+
34+
/**
35+
* Container showing all the DAI Elements, related to the 104 Protocol, of the passed DOI Element in a list.
36+
* The DAI Element can be edited by pressing the Edit button at the end of the line.
37+
*/
38+
@customElement('doi-104-container')
39+
export class Doi104Container extends Base104Container {
40+
@property()
41+
element!: Element;
42+
43+
@query('#toggleButton')
44+
toggleButton!: IconButtonToggle | undefined;
45+
46+
@property()
47+
get daiElements(): Element[] {
48+
return Array.from(this.element.querySelectorAll(`DAI`))
49+
.filter(
50+
daiElement =>
51+
daiElement.querySelector(
52+
`Private[type="${PROTOCOL_104_PRIVATE}"] > Address`
53+
) !== null
54+
)
55+
.sort((dai1, dai2) =>
56+
getFullPath(dai1, 'DOI').localeCompare(getFullPath(dai2, 'DOI'))
57+
);
58+
}
59+
60+
private getAddressElements(daiElement: Element): Element[] {
61+
return Array.from(
62+
daiElement.querySelectorAll(
63+
`Private[type="${PROTOCOL_104_PRIVATE}"] > Address`
64+
)
65+
).sort(
66+
(addr1, addr2) =>
67+
(addr1.getAttribute('casdu') ?? '').localeCompare(
68+
addr2.getAttribute('casdu') ?? ''
69+
) &&
70+
(addr1.getAttribute('ioa') ?? '').localeCompare(
71+
addr2.getAttribute('ioa') ?? ''
72+
)
73+
);
74+
}
75+
76+
protected firstUpdated(): void {
77+
this.requestUpdate();
78+
}
79+
80+
private openEditAddressWizard(
81+
daiElement: Element,
82+
addressElement: Element
83+
): void {
84+
const doiElement = daiElement.closest('DOI')!;
85+
const iedElement = doiElement.closest('IED')!;
86+
this.dispatchEvent(
87+
newWizardEvent(
88+
editAddressWizard(iedElement, doiElement, daiElement, addressElement)
89+
)
90+
);
91+
}
92+
93+
private openEditTiWizard(): void {
94+
this.dispatchEvent(newWizardEvent(showDOIInfoWizard(this.element)));
95+
}
96+
97+
@property()
98+
get header(): TemplateResult {
99+
const fullPath = getFullPath(this.element, 'IED');
100+
const cdc = getCdcValueFromDOIElement(this.element);
101+
102+
return html`${fullPath}${cdc ? html` (${cdc})` : nothing}`;
103+
}
104+
105+
private renderAddressList(daiElement: Element): TemplateResult {
106+
const addresses = this.getAddressElements(daiElement);
107+
return html`${addresses.map(addressElement => {
108+
return html`
109+
<mwc-list-item graphic="icon" hasMeta>
110+
<span slot="graphic">&nbsp;</span>
111+
<span>${get104DetailsLine(daiElement, addressElement)}</span>
112+
<span slot="meta">
113+
<mwc-icon-button
114+
icon="edit"
115+
@click=${() =>
116+
this.openEditAddressWizard(daiElement, addressElement)}
117+
>
118+
</mwc-icon-button>
119+
</span>
120+
</mwc-list-item>
121+
`;
122+
})}`;
123+
}
124+
125+
private renderDaiList(): TemplateResult {
126+
const daiElements = this.daiElements;
127+
return html`${daiElements.map(daiElement => {
128+
return html`
129+
<mwc-list-item noninteractive>
130+
<span>${getFullPath(daiElement, 'DOI')}</span>
131+
</mwc-list-item>
132+
${this.renderAddressList(daiElement)}
133+
`;
134+
})}`;
135+
}
136+
137+
render(): TemplateResult {
138+
return html`
139+
<action-pane .label="${this.header}">
140+
<abbr slot="action" title="${translate('edit')}">
141+
<mwc-icon-button
142+
icon="info"
143+
@click=${() => this.openEditTiWizard()}
144+
></mwc-icon-button>
145+
</abbr>
146+
<abbr
147+
slot="action"
148+
title="${translate('protocol104.toggleChildElements')}"
149+
>
150+
<mwc-icon-button-toggle
151+
id="toggleButton"
152+
on
153+
onIcon="keyboard_arrow_up"
154+
offIcon="keyboard_arrow_down"
155+
@click=${() => this.requestUpdate()}
156+
>
157+
</mwc-icon-button-toggle>
158+
</abbr>
159+
${this.toggleButton?.on
160+
? html` <mwc-list id="dailist"> ${this.renderDaiList()} </mwc-list>`
161+
: nothing}
162+
</action-pane>
163+
`;
164+
}
165+
166+
static styles = css`
167+
abbr {
168+
text-decoration: none;
169+
border-bottom: none;
170+
}
171+
172+
mwc-list-item {
173+
--mdc-list-item-meta-size: 48px;
174+
}
175+
`;
176+
}

0 commit comments

Comments
 (0)