Skip to content

Commit

Permalink
refactor(setting/nsdoc): Loading NSDoc Files through Custom Event (#644)
Browse files Browse the repository at this point in the history
Refactor loading NSDoc File through Custom Event. And added some integration tests.
  • Loading branch information
Dennis Labordus committed Mar 29, 2022
1 parent cbde240 commit 3b39d20
Show file tree
Hide file tree
Showing 14 changed files with 1,487 additions and 110 deletions.
2 changes: 1 addition & 1 deletion src/Logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,8 @@ export function Logging<TBase extends LitElementConstructor>(Base: TBase) {

this.undo = this.undo.bind(this);
this.redo = this.redo.bind(this);

this.onLog = this.onLog.bind(this);

this.addEventListener('log', this.onLog);
this.addEventListener('issue', this.onIssue);
this.addEventListener('open-doc', this.onLoadHistoryFromDoc);
Expand Down
94 changes: 63 additions & 31 deletions src/Setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ type NsdVersions = {
'IEC 61850-8-1': NsdVersion;
}

/** Represents a document to be opened. */
export interface LoadNsdocDetail {
nsdoc: string;
filename: string;
}
export type LoadNsdocEvent = CustomEvent<LoadNsdocDetail>;
export function newLoadNsdocEvent(
nsdoc: string,
filename: string
): LoadNsdocEvent {
return new CustomEvent<LoadNsdocDetail>('load-nsdoc', {
bubbles: true,
composed: true,
detail: { nsdoc, filename },
});
}

/** Mixin that saves [[`Settings`]] to `localStorage`, reflecting them in the
* `settings` property, setting them through `setSetting(setting, value)`. */
export type SettingElement = Mixin<typeof Setting>;
Expand Down Expand Up @@ -168,7 +185,7 @@ export function Setting<TBase extends LitElementConstructor>(Base: TBase) {
private renderFileSelect(): TemplateResult {
return html `
<input id="nsdoc-file" accept=".nsdoc" type="file" hidden required multiple
@change=${(evt: Event) => this.loadNsdocFile(evt)}}>
@change=${(evt: Event) => this.uploadNsdocFile(evt)}}>
<mwc-button label="${translate('settings.selectFileButton')}"
id="selectFileButton"
@click=${() => {
Expand All @@ -179,50 +196,63 @@ export function Setting<TBase extends LitElementConstructor>(Base: TBase) {
`;
}

private async loadNsdocFile(evt: Event): Promise<void> {
const nsdVersions = await this.nsdVersions();
private async uploadNsdocFile(evt: Event): Promise<void> {
const files = Array.from(
(<HTMLInputElement | null>evt.target)?.files ?? []
);

if (files.length == 0) return;
files.forEach(async file => {
for (const file of files) {
const text = await file.text();
const nsdocElement = this.parseToXmlObject(text).querySelector('NSDoc');
const id = nsdocElement?.getAttribute('id');
if (!id) {
document
document
.querySelector('open-scd')!
.dispatchEvent(
newLogEvent({ kind: 'error', title: get('settings.invalidFileNoIdFound') })
);
return;
}
const nsdVersion = nsdVersions[id as keyof NsdVersions];
const nsdocVersion = {
version: nsdocElement!.getAttribute('version') ?? '',
revision: nsdocElement!.getAttribute('revision') ?? '',
release: nsdocElement!.getAttribute('release') ?? ''
}
newLoadNsdocEvent(text, file.name)
);
}

this.nsdocFileUI.value = '';
this.requestUpdate();
}

private async onLoadNsdoc(event: LoadNsdocEvent) {
const nsdocElement = this.parseToXmlObject(event.detail.nsdoc).querySelector('NSDoc');

if (!this.isEqual(nsdVersion, nsdocVersion)) {
document
const id = nsdocElement?.getAttribute('id');
if (!id) {
document
.querySelector('open-scd')!
.dispatchEvent(
newLogEvent({ kind: 'error', title: get('settings.invalidNsdocVersion', {
newLogEvent({ kind: 'error', title: get('settings.invalidFileNoIdFound', {
filename: event.detail.filename
}) })
);
return;
}

const nsdVersions = await this.nsdVersions();
const nsdVersion = nsdVersions[id as keyof NsdVersions];
const nsdocVersion = {
version: nsdocElement!.getAttribute('version') ?? '',
revision: nsdocElement!.getAttribute('revision') ?? '',
release: nsdocElement!.getAttribute('release') ?? ''
}

if (!this.isEqual(nsdVersion, nsdocVersion)) {
document
.querySelector('open-scd')!
.dispatchEvent(
newLogEvent({ kind: 'error', title: get('settings.invalidNsdocVersion', {
id: id,
filename: event.detail.filename,
nsdVersion: `${nsdVersion.version}${nsdVersion.revision}${nsdVersion.release}`,
nsdocVersion: `${nsdocVersion.version}${nsdocVersion.revision}${nsdocVersion.release}`
}) })
);
return;
}

this.setSetting(id as keyof Settings, text);
})
);
return;
}

this.nsdocFileUI.value = '';
this.requestUpdate();
this.setSetting(id as keyof Settings, event.detail.nsdoc);
}

/**
Expand All @@ -245,7 +275,7 @@ export function Setting<TBase extends LitElementConstructor>(Base: TBase) {
let nsdVersion: string | undefined | null;
let nsdRevision: string | undefined | null;
let nsdRelease: string | undefined | null;

if (nsdSetting) {
const nsdoc = this.parseToXmlObject(nsdSetting)!.querySelector('NSDoc');
nsdVersion = nsdoc?.getAttribute('version');
Expand Down Expand Up @@ -273,6 +303,8 @@ export function Setting<TBase extends LitElementConstructor>(Base: TBase) {

registerTranslateConfig({ loader, empty: key => key });
use(this.settings.language);

(<any>this).addEventListener('load-nsdoc', this.onLoadNsdoc);
}

render(): TemplateResult {
Expand Down
5 changes: 2 additions & 3 deletions src/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@ export const de: Translations = {
showieds: 'Zeige IEDs im Substation-Editor',
selectFileButton: 'Datei auswählen',
loadNsdTranslations: 'NSDoc-Dateien hochladen',
invalidFileNoIdFound:
"Ungültiges NSDoc; kein 'id'-Attribut in der Datei gefunden",
invalidFileNoIdFound: "Ungültiges NSDoc ({{ filename }}); kein 'id'-Attribut in der Datei gefunden",
invalidNsdocVersion:
'Die Version {{ id }} NSD ({{ nsdVersion }}) passt nicht zu der geladenen NSDoc ({{ nsdocVersion }})',
'Die Version {{ id }} NSD ({{ nsdVersion }}) passt nicht zu der geladenen NSDoc ({{ filename }}, {{ nsdocVersion }})',
},
menu: {
new: 'Neues projekt',
Expand Down
6 changes: 3 additions & 3 deletions src/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ export const en = {
mode: 'Pro mode',
showieds: 'Show IEDs in substation editor',
selectFileButton: 'Select file',
loadNsdTranslations: 'Uploading NSDoc files',
invalidFileNoIdFound: "Invalid NSDoc; no 'id' attribute found in file",
loadNsdTranslations: 'Uploaded NSDoc files',
invalidFileNoIdFound: "Invalid NSDoc ({{ filename }}); no 'id' attribute found in file",
invalidNsdocVersion:
'The version of {{ id }} NSD ({{ nsdVersion }}) does not correlate with the version of the corresponding NSDoc ({{ nsdocVersion }})',
'The version of {{ id }} NSD ({{ nsdVersion }}) does not correlate with the version of the corresponding NSDoc ({{ filename }}, {{ nsdocVersion }})',
},
menu: {
new: 'New project',
Expand Down
84 changes: 84 additions & 0 deletions test/integration/Setting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { html, fixture, expect } from '@open-wc/testing';

import '../../src/open-scd.js';

import { OpenSCD } from '../../src/open-scd.js';
import { newLoadNsdocEvent } from "../../src/Setting.js";

describe('Setting', () => {
let element: OpenSCD;

beforeEach(async () => {
localStorage.clear();

element = await fixture(html`
<open-scd></open-scd>
<link href="public/google/fonts/roboto-v27.css" rel="stylesheet" />
<link href="public/google/fonts/roboto-mono-v13.css" rel="stylesheet" />
<link href="public/google/icons/material-icons-outlined.css" rel="stylesheet" />
`);
});

it('opens the log on log menu entry click', async () => {
await (<HTMLElement>(
element.shadowRoot!.querySelector('mwc-list-item[iconid="history"]')!
)).click();
expect(element.logUI).to.have.property('open', true);
});

it('upload .nsdoc file using event and looks like latest snapshot', async () => {
element.settingsUI.show();
await element.settingsUI.updateComplete;

const nsdocFile = await fetch('/test/testfiles/nsdoc/IEC_61850-7-2.nsdoc')
.then(response => response.text())

element.dispatchEvent(
newLoadNsdocEvent(nsdocFile, 'IEC_61850-7-2.nsdoc')
);

await element.requestUpdate();
await element.updateComplete;

expect(localStorage.getItem('IEC 61850-7-2')).to.eql(nsdocFile);
expect(element).shadowDom.to.equalSnapshot();
});

it('upload invalid .nsdoc file using event and log event fired', async () => {
element.settingsUI.show();
await element.settingsUI.updateComplete;

const nsdocFile = await fetch('/test/testfiles/nsdoc/invalid.nsdoc')
.then(response => response.text())

element.dispatchEvent(
newLoadNsdocEvent(nsdocFile, 'invalid.nsdoc')
);

await element.requestUpdate();
await element.updateComplete;

expect(element.history.length).to.be.equal(1);
expect(element.history[0].title).to.be.equal('Invalid NSDoc (invalid.nsdoc); no \'id\' attribute found in file');
});

it('upload .nsdoc file with wrong version using event and log event fired', async () => {
element.settingsUI.show();
await element.settingsUI.updateComplete;

const nsdocFile = await fetch('/test/testfiles/nsdoc/wrong-version.nsdoc')
.then(response => response.text())

element.dispatchEvent(
newLoadNsdocEvent(nsdocFile, 'wrong-version.nsdoc')
);

await element.requestUpdate();
await element.updateComplete;

expect(element.history.length).to.be.equal(1);
expect(element.history[0].title).to.be.equal('The version of IEC 61850-7-3 NSD (2007B3) does not correlate ' +
'with the version of the corresponding NSDoc (wrong-version.nsdoc, 2007B4)');
});
}).timeout(4000);
Loading

0 comments on commit 3b39d20

Please sign in to comment.