Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wizards/reportcontrol): access edit wizard from select wizard #492

Merged
merged 2 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,12 @@ export function newWizardEvent(
});
}

export function newSubWizardEvent(
wizardOrFactory?: Wizard | WizardFactory
): WizardEvent {
return newWizardEvent(wizardOrFactory, { detail: { subwizard: true } });
}

type InfoEntryKind = 'info' | 'warning' | 'error';

export type LogEntryType =
Expand Down
16 changes: 16 additions & 0 deletions src/wizards/reportcontrol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { get, translate } from 'lit-translate';

import '@material/mwc-button';
import '@material/mwc-list/mwc-list-item';
import { List } from '@material/mwc-list';
import { ListItemBase } from '@material/mwc-list/mwc-list-item-base';
import { SingleSelectedEvent } from '@material/mwc-list/mwc-list-foundation';

import '../wizard-textfield.js';
import '../wizard-select.js';
Expand All @@ -15,6 +18,8 @@ import {
getValue,
identity,
isPublic,
newSubWizardEvent,
selector,
SimpleAction,
Wizard,
WizardActor,
Expand Down Expand Up @@ -230,6 +235,17 @@ export function selectReportControlWizard(element: Element): Wizard {
title: get('wizard.title.select', { tagName: 'ReportControl' }),
content: [
html`<filtered-list
@selected=${(e: SingleSelectedEvent) => {
const identity = (<ListItemBase>(<List>e.target).selected).value;
const reportControl = element.querySelector(
selector('ReportControl', identity)
);
if (!reportControl) return;

e.target?.dispatchEvent(
newSubWizardEvent(() => editReportControlWizard(reportControl))
);
}}
>${reportControls.map(
reportControl =>
html`<mwc-list-item twoline value="${identity(reportControl)}"
Expand Down
9 changes: 6 additions & 3 deletions src/zeroline-pane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import './zeroline/ied-editor.js';
import { Settings } from './Setting.js';
import { communicationMappingWizard } from './wizards/commmap-wizards.js';
import { gooseIcon, smvIcon, reportIcon } from './icons.js';
import { isPublic, newWizardEvent } from './foundation.js';
import { isPublic, newSubWizardEvent, newWizardEvent } from './foundation.js';
import { selectGseControlWizard } from './wizards/gsecontrol.js';
import { wizards } from './wizards/wizard-library.js';
import { getAttachedIeds } from './zeroline/foundation.js';
Expand Down Expand Up @@ -65,8 +65,11 @@ export class ZerolinePane extends LitElement {
}

openReportControlSelection(): void {
const wizard = selectReportControlWizard(this.doc.documentElement);
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
this.dispatchEvent(
newSubWizardEvent(() =>
selectReportControlWizard(this.doc.documentElement)
)
);
}

openGseControlSelection(): void {
Expand Down
7 changes: 4 additions & 3 deletions src/zeroline/ied-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Fab } from '@material/mwc-fab';
import '../action-icon.js';
import { createClientLnWizard } from '../wizards/clientln.js';
import { gooseIcon, smvIcon, reportIcon } from '../icons.js';
import { newWizardEvent } from '../foundation.js';
import { newSubWizardEvent, newWizardEvent } from '../foundation.js';
import { selectGseControlWizard } from '../wizards/gsecontrol.js';
import { selectSampledValueControlWizard } from '../wizards/sampledvaluecontrol.js';
import { selectReportControlWizard } from '../wizards/reportcontrol.js';
Expand All @@ -34,8 +34,9 @@ export class IedEditor extends LitElement {
@query('.connectreport') connectReport!: Fab;

private openReportControlSelection(): void {
const wizard = selectReportControlWizard(this.element);
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
this.dispatchEvent(
newSubWizardEvent(() => selectReportControlWizard(this.element))
);
}

private openGseControlSelection(): void {
Expand Down
164 changes: 164 additions & 0 deletions test/integration/wizards/reportcontrol-wizarding-editing.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { expect, fixture, html } from '@open-wc/testing';

import '../../mock-wizard-editor.js';
import { MockWizardEditor } from '../../mock-wizard-editor.js';

import { ListItemBase } from '@material/mwc-list/mwc-list-item-base';

import { FilteredList } from '../../../src/filtered-list.js';
import { WizardTextField } from '../../../src/wizard-textfield.js';
import { selectReportControlWizard } from '../../../src/wizards/reportcontrol.js';

describe('Wizards for SCL element ReportControl', () => {
let doc: XMLDocument;
let element: MockWizardEditor;

beforeEach(async () => {
element = await fixture(html`<mock-wizard-editor></mock-wizard-editor>`);
doc = await fetch('/test/testfiles/wizards/reportcontrol.scd')
.then(response => response.text())
.then(str => new DOMParser().parseFromString(str, 'application/xml'));
});

describe('define a select wizards that ', () => {
let reportControlList: FilteredList;

beforeEach(async () => {
const wizard = selectReportControlWizard(doc.documentElement);
element.workflow.push(() => wizard);
await element.requestUpdate();

reportControlList = <FilteredList>(
element.wizardUI.dialog?.querySelector('filtered-list')
);
await reportControlList.updateComplete;
});

it('shows all ReportControl elements within a project', () =>
expect(reportControlList.items.length).to.equal(
doc.querySelectorAll('ReportControl').length
));

it('allows to filter ReportControl elements per IED', async () => {
const wizard = selectReportControlWizard(doc.querySelector('IED')!);
element.workflow.pop();
element.workflow.push(() => wizard);
await element.requestUpdate();

reportControlList = <FilteredList>(
element.wizardUI.dialog?.querySelector('filtered-list')
);
await reportControlList.updateComplete;

expect(reportControlList.items.length).to.equal(
JakobVogelsang marked this conversation as resolved.
Show resolved Hide resolved
doc.querySelector('IED')!.querySelectorAll('ReportControl').length
);
});

it('opens edit wizard for selected ReportControl element on click', async () => {
const reportItem = <ListItemBase>reportControlList.items[1];
reportItem.click();
await new Promise(resolve => setTimeout(resolve, 20)); // await animation

const nameField = <WizardTextField>(
element.wizardUI.dialog?.querySelector('wizard-textfield[label="name"]')
);
await nameField.requestUpdate();

expect(nameField.value).to.equal(
doc.querySelectorAll('ReportControl')[1].getAttribute('name')
);
});
});

describe('defines an edit wizard that', () => {
let nameField: WizardTextField;
let secondaryAction: HTMLElement;
let primaryAction: HTMLElement;
let parentIED: Element;

beforeEach(async () => {
parentIED = doc.querySelector('IED')!;
element.workflow.push(() => selectReportControlWizard(parentIED));
await element.requestUpdate();
await new Promise(resolve => setTimeout(resolve, 20)); // await animation

const report = <ListItemBase>(
(<FilteredList>element.wizardUI.dialog?.querySelector('filtered-list'))
.items[0]
);
report.click();
await new Promise(resolve => setTimeout(resolve, 20)); // await animation

nameField = element.wizardUI.dialog!.querySelector(
'wizard-textfield[label="name"]'
)!;
primaryAction = <HTMLElement>(
element.wizardUI.dialog?.querySelector(
'mwc-button[slot="primaryAction"]'
)
);
secondaryAction = <HTMLElement>(
element.wizardUI.dialog?.querySelector(
'mwc-button[slot="secondaryAction"]'
)
);
await nameField.updateComplete;
});

it('rejects name attribute starting with decimals', async () => {
expect(
parentIED.querySelector('ReportControl')?.getAttribute('name')
).to.not.equal('4adsasd');

nameField.value = '4adsasd';
await element.requestUpdate();
primaryAction.click();

expect(
parentIED.querySelector('ReportControl')?.getAttribute('name')
).to.not.equal('4adsasd');
});

it('edits name attribute on primary action', async () => {
expect(
parentIED.querySelector('ReportControl')?.getAttribute('name')
).to.not.equal('myNewName');

nameField.value = 'myNewName';
await element.requestUpdate();
primaryAction.click();

expect(
parentIED.querySelector('ReportControl')?.getAttribute('name')
).to.equal('myNewName');
});

it('dynamically updates wizards after attribute change', async () => {
nameField.value = 'myNewName';
primaryAction.click();

await new Promise(resolve => setTimeout(resolve, 100)); // await animation

const report = <ListItemBase>(
(<FilteredList>element.wizardUI.dialog?.querySelector('filtered-list'))
.items[0]
);

expect(report.innerHTML).to.contain('myNewName');
});

it('returns back to its starting wizard on secondary action', async () => {
secondaryAction.click();

await new Promise(resolve => setTimeout(resolve, 100)); // await animation

const report = <ListItemBase>(
(<FilteredList>element.wizardUI.dialog?.querySelector('filtered-list'))
.items[0]
);

expect(report.innerHTML).to.contain('ReportCb');
});
});
});
84 changes: 84 additions & 0 deletions test/testfiles/wizards/reportcontrol.scd
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,88 @@
</Server>
</AccessPoint>
</IED>
<IED name="IED3" type="DummyIED" manufacturer="DummyManufactorer" configVersion="1" originalSclVersion="2007" originalSclRevision="B" owner="DummyOwner">
<Services>
<DynAssociation />
<GetDirectory />
<GetDataObjectDefinition />
<DataObjectDirectory />
<GetDataSetValue />
<SetDataSetValue />
<DataSetDirectory />
<ConfDataSet modify="false" max="3" />
<DynDataSet max="42" />
<ReadWrite />
<ConfReportControl max="10" />
<GetCBValues />
<ReportSettings rptID="Dyn" optFields="Dyn" bufTime="Dyn" trgOps="Dyn" intgPd="Dyn" resvTms="true" owner="true" />
<GOOSE max="1" />
<GSSE max="0" />
<ConfLNs fixPrefix="true" fixLnInst="true" />
</Services>
<AccessPoint name="P1">
<Server>
<Authentication />
<LDevice inst="CBSW">
<LN0 lnClass="LLN0" inst="" lnType="Dummy.LLN0">
<Private type="dummyType">
<esld:FCDA xmlns:esld="http://www.dummyURL.com/dummyNS" ldInst="CBSW" prefix="" lnClass="XSWI" lnInst="2" doName="Pos" daName="stVal" fc="ST"/>
</Private>
<DataSet name="GooseDataSet1">
<FCDA ldInst="CBSW" prefix="" lnClass="XSWI" lnInst="2" doName="Pos" daName="stVal" fc="ST"/>
<FCDA ldInst="CBSW" prefix="" lnClass="XSWI" lnInst="2" doName="Pos" daName="q" fc="ST"/>
<FCDA ldInst="CBSW" prefix="" lnClass="XSWI" lnInst="2" doName="OpSlc.dsd" daName="sasd.ads.asd" fc="ST"/>
</DataSet>
<GSEControl type="GOOSE" appID="0002" fixedOffs="false" confRev="1" name="GCB" datSet="GooseDataSet1">
</GSEControl>
<ReportControl rptID="reportCb1" confRev="9" buffered="true" bufTime="100" indexed="true" name="ReportCb" datSet="GooseDataSet1">
<TrgOps dchg="true" qchg="true" dupd="false" period="false" gi="true"/>
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" dataRef="false" entryID="false" configRef="true" bufOvfl="false"/>
<RptEnabled max="5">
<ClientLN apRef="P1" ldInst="CircuitBreaker_CB1" lnClass="XCBR" lnInst="1" iedName="IED1"/>
</RptEnabled>
</ReportControl>
<SampledValueControl smvID="asdfads" multicast="true" smpRate="80" nofASDU="1" confRev="1" name="MSVCB01" datSet="GooseDataSet1">
<SmvOpts/>
</SampledValueControl>
</LN0>
<LN lnClass="LPHD" inst="1" lnType="Dummy.LPHD1"/>
<LN lnClass="XCBR" inst="1" lnType="Dummy.XCBR1">
<DOI name="Pos">
<DAI name="ctlModel">
<Val>status-only</Val>
</DAI>
</DOI>
</LN>
<LN lnClass="XSWI" inst="1" lnType="Dummy.XSWI1">
<DataSet name="dataSet">
<FCDA ldInst="CBSW" lnClass="XSWI" lnInst="1" doName="Pos" daName="stVal" fc="ST"/>
<FCDA ldInst="CBSW" lnClass="XSWI" lnInst="1" doName="Pos" daName="q" fc="ST"/>
</DataSet>
<ReportControl rptID="IED2/CBSW/XSWI/SwitchGearBRCB" confRev="9" buffered="true" bufTime="100" indexed="true" intgPd="0" name="ReportCb2" datSet="dataSet">
<TrgOps dchg="true" qchg="true" dupd="false" period="false" gi="true"/>
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" dataRef="false" entryID="false" configRef="true" bufOvfl="false"/>
</ReportControl>
<DOI name="Pos">
<DAI name="ctlModel">
<Val>status-only</Val>
</DAI>
</DOI>
<Inputs>
<ExtRef iedName="IED1" ldInst="Disconnectors" prefix="DC" lnClass="XSWI" lnInst="1" doName="Pos" daName="stVal"/>
<ExtRef iedName="IED1" ldInst="Disconnectors" prefix="DC" lnClass="XSWI" lnInst="1" doName="Pos" daName="q"/>
</Inputs>
</LN>
<LN lnClass="XSWI" inst="3" lnType="Dummy.XSWI1">
<DOI name="Pos">
<DAI name="ctlModel">
<Val>status-only</Val>
</DAI>
</DOI>
</LN>
<LN lnClass="GGIO" inst="1" lnType="Dummy.GGIO1"/>
</LDevice>
</Server>
</AccessPoint>
</IED>
</SCL>
28 changes: 28 additions & 0 deletions test/unit/wizards/__snapshots__/reportcontrol.test.snap.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,34 @@ snapshots["Wizards for SCL ReportControl element define a select wizard that loo
IED2>>CBSW> XSWI 2>ReportCb3
</span>
</mwc-list-item>
<mwc-list-item
aria-disabled="false"
mwc-list-item=""
tabindex="-1"
twoline=""
value="IED3>>CBSW>ReportCb"
>
<span>
ReportCb
</span>
<span slot="secondary">
IED3>>CBSW>ReportCb
</span>
</mwc-list-item>
<mwc-list-item
aria-disabled="false"
mwc-list-item=""
tabindex="-1"
twoline=""
value="IED3>>CBSW> XSWI 1>ReportCb2"
>
<span>
ReportCb2
</span>
<span slot="secondary">
IED3>>CBSW> XSWI 1>ReportCb2
</span>
</mwc-list-item>
</filtered-list>
</div>
<mwc-button
Expand Down