diff --git a/public/js/plugins.js b/public/js/plugins.js
index a1e4e11c67..9e0836c03e 100644
--- a/public/js/plugins.js
+++ b/public/js/plugins.js
@@ -41,6 +41,13 @@ export const officialPlugins = [
default: true,
kind: 'editor',
},
+ {
+ name: '104',
+ src: '/src/editors/Communication104.js',
+ icon: 'settings_ethernet',
+ default: false,
+ kind: 'editor',
+ },
{
name: 'Templates',
src: '/src/editors/Templates.js',
diff --git a/src/editors/Communication104.ts b/src/editors/Communication104.ts
new file mode 100644
index 0000000000..488800d939
--- /dev/null
+++ b/src/editors/Communication104.ts
@@ -0,0 +1,106 @@
+import {
+ css,
+ html,
+ LitElement,
+ property,
+ query,
+ TemplateResult
+} from "lit-element";
+import {translate} from "lit-translate";
+
+import '@material/mwc-fab';
+import '@material/mwc-radio';
+import '@material/mwc-formfield';
+
+import {RadioListItem} from "@material/mwc-list/mwc-radio-list-item";
+
+import './communication104/network-container.js'
+import './communication104/values-container.js'
+
+import {
+ newViewEvent,
+ View,
+ VIEW_EVENT_NAME,
+ ViewEvent
+} from "./communication104/foundation/foundation.js";
+
+/** Defining view outside the class, which makes it persistent. */
+let selectedViewCommunication104Plugin: View = View.VALUES;
+
+/** An editor [[`plugin`]] for editing the `IED` section. */
+export default class Communication104Plugin extends LitElement {
+ /** The document being edited as provided to plugins by [[`OpenSCD`]]. */
+ @property()
+ doc!: XMLDocument;
+
+ @query('#byValuesRadio')
+ byValuesRadio!: RadioListItem;
+
+ @query('#byNetworkRadio')
+ byNetworkRadio!: RadioListItem;
+
+ @query('div[class="container"]')
+ listDiv!: Element;
+
+ constructor() {
+ super();
+
+ this.addEventListener(VIEW_EVENT_NAME, (evt: ViewEvent) => {
+ selectedViewCommunication104Plugin = evt.detail.view;
+ this.requestUpdate();
+ });
+ }
+
+ firstUpdated(): void {
+ selectedViewCommunication104Plugin == View.VALUES
+ ? this.byValuesRadio.setAttribute('checked', '')
+ : this.byNetworkRadio.setAttribute('checked', '')
+ }
+
+ render(): TemplateResult {
+ return html`
+
+ this.listDiv.dispatchEvent(newViewEvent(View.VALUES))}
+ >
+
+
+ this.listDiv.dispatchEvent(newViewEvent(View.NETWORK))}
+ >
+
+
+ ${selectedViewCommunication104Plugin == View.VALUES
+ ? html``
+ : html``
+ }
+
+
`;
+ }
+
+ static styles = css`
+ :host {
+ width: 100vw;
+ }
+
+ .container {
+ display: flex;
+ padding: 8px 6px 16px;
+ height: 86vh;
+ }
+
+ .row {
+ flex: 50%;
+ margin: 0px 6px 0px;
+ min-width: 300px;
+ height: 100%;
+ overflow-y: scroll;
+ }
+ `;
+}
diff --git a/src/editors/communication104/foundation/foundation.ts b/src/editors/communication104/foundation/foundation.ts
new file mode 100644
index 0000000000..ef16f000ec
--- /dev/null
+++ b/src/editors/communication104/foundation/foundation.ts
@@ -0,0 +1,32 @@
+/**
+ * Enumeration stating the current view of the 104 plugin.
+ */
+export enum View {
+ VALUES,
+ NETWORK
+}
+
+export const VIEW_EVENT_NAME = 'view-change-104-plugin';
+
+// Objects needed to register and fire the change of a view within the Communication 104 Plugin
+export interface ViewDetail {
+ view: View;
+}
+export type ViewEvent = CustomEvent;
+export function newViewEvent(
+ view: View,
+ eventInitDict?: CustomEventInit
+): ViewEvent {
+ return new CustomEvent(VIEW_EVENT_NAME, {
+ bubbles: true,
+ composed: true,
+ ...eventInitDict,
+ detail: { view, ...eventInitDict?.detail },
+ });
+}
+
+declare global {
+ interface ElementEventMap {
+ [VIEW_EVENT_NAME]: ViewEvent;
+ }
+}
diff --git a/src/editors/communication104/network-container.ts b/src/editors/communication104/network-container.ts
new file mode 100644
index 0000000000..1ec3abfce2
--- /dev/null
+++ b/src/editors/communication104/network-container.ts
@@ -0,0 +1,13 @@
+import {css, customElement, html, LitElement, TemplateResult} from "lit-element";
+
+@customElement('network-104-container')
+export class NetworkContainer extends LitElement {
+ render(): TemplateResult {
+ return html`
+ Network Container
+ `;
+ }
+
+ static styles = css`
+ `;
+}
diff --git a/src/editors/communication104/values-container.ts b/src/editors/communication104/values-container.ts
new file mode 100644
index 0000000000..d108807897
--- /dev/null
+++ b/src/editors/communication104/values-container.ts
@@ -0,0 +1,13 @@
+import {css, customElement, html, LitElement, TemplateResult} from "lit-element";
+
+@customElement('values-104-container')
+export class ValuesContainer extends LitElement {
+ render(): TemplateResult {
+ return html`
+ Values Container
+ `;
+ }
+
+ static styles = css`
+ `;
+}
diff --git a/src/translations/de.ts b/src/translations/de.ts
index ce8fe8653b..a4c6da15f4 100644
--- a/src/translations/de.ts
+++ b/src/translations/de.ts
@@ -355,6 +355,12 @@ export const de: Translations = {
noSampledValuesSelected: 'Keinen Kontrollblock ausgewählt',
},
},
+ communication104: {
+ view: {
+ valuesView: 'Values',
+ networkView: 'Network',
+ }
+ },
'enum-val': {
wizard: {
title: {
diff --git a/src/translations/en.ts b/src/translations/en.ts
index 02a695c372..e3b107d270 100644
--- a/src/translations/en.ts
+++ b/src/translations/en.ts
@@ -352,6 +352,12 @@ export const en = {
noSampledValuesSelected: 'No control block selected',
},
},
+ communication104: {
+ view: {
+ valuesView: 'Values',
+ networkView: 'Network',
+ }
+ },
'enum-val': {
wizard: {
title: {
diff --git a/test/integration/__snapshots__/open-scd.test.snap.js b/test/integration/__snapshots__/open-scd.test.snap.js
index 53922f1ac2..73ee5789ae 100644
--- a/test/integration/__snapshots__/open-scd.test.snap.js
+++ b/test/integration/__snapshots__/open-scd.test.snap.js
@@ -652,6 +652,21 @@ snapshots["open-scd looks like its snapshot"] =
Communication
+
+
+ settings_ethernet
+
+ 104
+
{
+ customElements.define(
+ 'communication104-plugin',
+ Wizarding(Editing(Communication104))
+ );
+ let element: Communication104;
+ let doc: XMLDocument;
+
+ beforeEach(async () => {
+ doc = await fetch('/test/testfiles/communication.scd')
+ .then(response => response.text())
+ .then(str => new DOMParser().parseFromString(str, 'application/xml'));
+
+ element = await fixture(
+ html``
+ );
+ });
+
+ describe('in Values view', () => {
+ it('the plugin looks like the latest snapshot', async () => {
+ await expect(element).shadowDom.to.equalSnapshot();
+ });
+ });
+
+ describe('in Network view', () => {
+ beforeEach(async () => {
+ const radioButton = element.shadowRoot?.querySelector('#byNetworkRadio');
+ (radioButton).click();
+ await element.updateComplete;
+ });
+
+ it('the plugin looks like the latest snapshot', async () => {
+ await expect(element).shadowDom.to.equalSnapshot();
+ });
+ });
+});
diff --git a/test/integration/editors/sampledvalues/SampledValues.test.ts b/test/integration/editors/SampledValues.test.ts
similarity index 93%
rename from test/integration/editors/sampledvalues/SampledValues.test.ts
rename to test/integration/editors/SampledValues.test.ts
index a794d726f7..fc74ad1b0f 100644
--- a/test/integration/editors/sampledvalues/SampledValues.test.ts
+++ b/test/integration/editors/SampledValues.test.ts
@@ -1,10 +1,10 @@
import { html, fixture, expect } from '@open-wc/testing';
-import '../../../mock-wizard.js';
+import '../../mock-wizard.js';
-import SampledValues from '../../../../src/editors/SampledValues.js';
-import { Editing } from '../../../../src/Editing.js';
-import { Wizarding } from '../../../../src/Wizarding.js';
+import SampledValues from '../../../src/editors/SampledValues.js';
+import { Editing } from '../../../src/Editing.js';
+import { Wizarding } from '../../../src/Wizarding.js';
describe('Sampled Values Plugin', () => {
customElements.define('smv-plugin', Wizarding(Editing(SampledValues)));
diff --git a/test/integration/editors/subscription/Subscription.test.ts b/test/integration/editors/Subscription.test.ts
similarity index 98%
rename from test/integration/editors/subscription/Subscription.test.ts
rename to test/integration/editors/Subscription.test.ts
index b5d01c0387..b2522b45c1 100644
--- a/test/integration/editors/subscription/Subscription.test.ts
+++ b/test/integration/editors/Subscription.test.ts
@@ -1,10 +1,10 @@
import { html, fixture, expect } from '@open-wc/testing';
-import '../../../mock-wizard.js';
+import '../../mock-wizard.js';
-import Subscription from '../../../../src/editors/Subscription.js';
-import { Editing } from '../../../../src/Editing.js';
-import { Wizarding } from '../../../../src/Wizarding.js';
+import Subscription from '../../../src/editors/Subscription.js';
+import { Editing } from '../../../src/Editing.js';
+import { Wizarding } from '../../../src/Wizarding.js';
describe('Subscription Plugin', () => {
customElements.define(
@@ -197,7 +197,7 @@ describe('Subscription Plugin', () => {
(radioButton).click();
await element.updateComplete;
});
-
+
describe('initially', () => {
it('the plugin looks like the latest snapshot', async () => {
await expect(element).shadowDom.to.equalSnapshot();
diff --git a/test/integration/editors/__snapshots__/Communication104.test.snap.js b/test/integration/editors/__snapshots__/Communication104.test.snap.js
new file mode 100644
index 0000000000..841dd8a705
--- /dev/null
+++ b/test/integration/editors/__snapshots__/Communication104.test.snap.js
@@ -0,0 +1,61 @@
+/* @web/test-runner snapshot v1 */
+export const snapshots = {};
+
+snapshots["Communication 104 Plugin in Values view the plugin looks like the latest snapshot"] =
+`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+/* end snapshot Communication 104 Plugin in Values view the plugin looks like the latest snapshot */
+
+snapshots["Communication 104 Plugin in Network view the plugin looks like the latest snapshot"] =
+`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+/* end snapshot Communication 104 Plugin in Network view the plugin looks like the latest snapshot */
+
diff --git a/test/integration/editors/sampledvalues/__snapshots__/SampledValues.test.snap.js b/test/integration/editors/__snapshots__/SampledValues.test.snap.js
similarity index 100%
rename from test/integration/editors/sampledvalues/__snapshots__/SampledValues.test.snap.js
rename to test/integration/editors/__snapshots__/SampledValues.test.snap.js
diff --git a/test/integration/editors/subscription/__snapshots__/Subscription.test.snap.js b/test/integration/editors/__snapshots__/Subscription.test.snap.js
similarity index 100%
rename from test/integration/editors/subscription/__snapshots__/Subscription.test.snap.js
rename to test/integration/editors/__snapshots__/Subscription.test.snap.js
diff --git a/test/unit/editors/importieds.test.ts b/test/unit/editors/importieds.test.ts
deleted file mode 100644
index f0fe4d7aa8..0000000000
--- a/test/unit/editors/importieds.test.ts
+++ /dev/null
@@ -1 +0,0 @@
-describe('ImportIedsPlugin', () => {});
diff --git a/test/unit/editors/subscriberinfo.test.ts b/test/unit/menu/subscriberinfo.test.ts
similarity index 100%
rename from test/unit/editors/subscriberinfo.test.ts
rename to test/unit/menu/subscriberinfo.test.ts
diff --git a/test/unit/editors/updatesubstation.test.ts b/test/unit/menu/updatesubstation.test.ts
similarity index 100%
rename from test/unit/editors/updatesubstation.test.ts
rename to test/unit/menu/updatesubstation.test.ts