diff --git a/src/foundation.ts b/src/foundation.ts index ed639b97a4..e2de6e75bc 100644 --- a/src/foundation.ts +++ b/src/foundation.ts @@ -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 = diff --git a/src/wizards/reportcontrol.ts b/src/wizards/reportcontrol.ts index 1d9f330ce2..651c1fa8b0 100644 --- a/src/wizards/reportcontrol.ts +++ b/src/wizards/reportcontrol.ts @@ -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'; @@ -15,6 +18,8 @@ import { getValue, identity, isPublic, + newSubWizardEvent, + selector, SimpleAction, Wizard, WizardActor, @@ -230,6 +235,17 @@ export function selectReportControlWizard(element: Element): Wizard { title: get('wizard.title.select', { tagName: 'ReportControl' }), content: [ html` { + const identity = ((e.target).selected).value; + const reportControl = element.querySelector( + selector('ReportControl', identity) + ); + if (!reportControl) return; + + e.target?.dispatchEvent( + newSubWizardEvent(() => editReportControlWizard(reportControl)) + ); + }} >${reportControls.map( reportControl => html` + selectReportControlWizard(this.doc.documentElement) + ) + ); } openGseControlSelection(): void { diff --git a/src/zeroline/ied-editor.ts b/src/zeroline/ied-editor.ts index a358519fea..40e7589521 100644 --- a/src/zeroline/ied-editor.ts +++ b/src/zeroline/ied-editor.ts @@ -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'; @@ -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 { diff --git a/test/integration/wizards/reportcontrol-wizarding-editing.test.ts b/test/integration/wizards/reportcontrol-wizarding-editing.test.ts new file mode 100644 index 0000000000..32dd3a8faf --- /dev/null +++ b/test/integration/wizards/reportcontrol-wizarding-editing.test.ts @@ -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``); + 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 = ( + 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 = ( + element.wizardUI.dialog?.querySelector('filtered-list') + ); + await reportControlList.updateComplete; + + expect(reportControlList.items.length).to.equal( + doc.querySelector('IED')!.querySelectorAll('ReportControl').length + ); + }); + + it('opens edit wizard for selected ReportControl element on click', async () => { + const reportItem = reportControlList.items[1]; + reportItem.click(); + await new Promise(resolve => setTimeout(resolve, 20)); // await animation + + const nameField = ( + 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 = ( + (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 = ( + element.wizardUI.dialog?.querySelector( + 'mwc-button[slot="primaryAction"]' + ) + ); + secondaryAction = ( + 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 = ( + (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 = ( + (element.wizardUI.dialog?.querySelector('filtered-list')) + .items[0] + ); + + expect(report.innerHTML).to.contain('ReportCb'); + }); + }); +}); diff --git a/test/testfiles/wizards/reportcontrol.scd b/test/testfiles/wizards/reportcontrol.scd index f34ab84548..1d2874926e 100644 --- a/test/testfiles/wizards/reportcontrol.scd +++ b/test/testfiles/wizards/reportcontrol.scd @@ -126,4 +126,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + status-only + + + + + + + + + + + + + + + status-only + + + + + + + + + + + status-only + + + + + + + + diff --git a/test/unit/wizards/__snapshots__/reportcontrol.test.snap.js b/test/unit/wizards/__snapshots__/reportcontrol.test.snap.js index c8eb4f4e33..6c29bd7141 100644 --- a/test/unit/wizards/__snapshots__/reportcontrol.test.snap.js +++ b/test/unit/wizards/__snapshots__/reportcontrol.test.snap.js @@ -180,6 +180,34 @@ snapshots["Wizards for SCL ReportControl element define a select wizard that loo IED2>>CBSW> XSWI 2>ReportCb3 + + + ReportCb + + + IED3>>CBSW>ReportCb + + + + + ReportCb2 + + + IED3>>CBSW> XSWI 1>ReportCb2 + +