diff --git a/src/editors/substation/line-editor.ts b/src/editors/substation/line-editor.ts index bffffd52a4..fc2f2e5f56 100644 --- a/src/editors/substation/line-editor.ts +++ b/src/editors/substation/line-editor.ts @@ -6,12 +6,17 @@ import { TemplateResult, property, state, + query, } from 'lit-element'; import { translate } from 'lit-translate'; import '@material/mwc-icon'; import '@material/mwc-icon-button'; +import '@material/mwc-menu'; +import { IconButton } from '@material/mwc-icon-button'; +import { ListItem } from '@material/mwc-list/mwc-list-item'; +import { Menu } from '@material/mwc-menu'; import './conducting-equipment-editor.js'; import './function-editor.js'; @@ -23,8 +28,19 @@ import { getChildElementsByTagName, newWizardEvent, newActionEvent, + SCLTag, + tags, } from '../../foundation.js'; -import { wizards } from '../../wizards/wizard-library.js'; + +import { emptyWizard, wizards } from '../../wizards/wizard-library.js'; + +function childTags(element: Element | null | undefined): SCLTag[] { + if (!element) return []; + + return tags[element.tagName].children.filter( + child => wizards[child].create !== emptyWizard + ); +} @customElement('line-editor') export class LineEditor extends LitElement { @@ -46,10 +62,19 @@ export class LineEditor extends LitElement { return `${name} ${desc ? `—${desc}` : ''}`; } + @query('mwc-menu') addMenu!: Menu; + @query('mwc-icon-button[icon="playlist_add"]') addButton!: IconButton; + private openEditWizard(): void { const wizard = wizards['Line'].edit(this.element); if (wizard) this.dispatchEvent(newWizardEvent(wizard)); } + + private openCreateWizard(tagName: string): void { + const wizard = wizards[tagName].create(this.element!); + + if (wizard) this.dispatchEvent(newWizardEvent(wizard)); + } private renderConductingEquipments(): TemplateResult { const ConductingEquipments = getChildElementsByTagName( @@ -94,6 +119,12 @@ export class LineEditor extends LitElement { >` )}`; } + + updated(): void { + if (this.addMenu && this.addButton) + this.addMenu.anchor = this.addButton; + } + remove(): void { if (this.element.parentElement) this.dispatchEvent( @@ -123,6 +154,14 @@ export class LineEditor extends LitElement { : html``; } + private renderAddButtons(): TemplateResult[] { + return childTags(this.element).map( + child => + html`${child}` + ); + } render(): TemplateResult { return html` @@ -135,7 +174,26 @@ export class LineEditor extends LitElement { this.remove()} - > + + + (this.addMenu.open = true)} + > { + const tagName = ((e.target).selected).value; + this.openCreateWizard(tagName); + }} + >${this.renderAddButtons()}${this.renderConductingEquipments()}${this.renderGeneralEquipments()}${this.renderFunctions()}${this.renderLNodes()} `; } diff --git a/test/integration/editors/substation/line-editor-wizard-editing.test.ts b/test/integration/editors/substation/line-editor-wizard-editing.test.ts index 5bfce701b6..1571d9f0ad 100644 --- a/test/integration/editors/substation/line-editor-wizard-editing.test.ts +++ b/test/integration/editors/substation/line-editor-wizard-editing.test.ts @@ -7,9 +7,44 @@ import { ListItemBase } from '@material/mwc-list/mwc-list-item-base'; import '../../../../src/editors/substation/line-editor.js'; import { LineEditor } from '../../../../src/editors/substation/line-editor.js'; import { WizardTextField } from '../../../../src/wizard-textfield.js'; -import { WizardCheckbox } from '../../../../src/wizard-checkbox.js'; import { MenuBase } from '@material/mwc-menu/mwc-menu-base.js'; +const openAndCancelMenu: ( + parent: MockWizardEditor, + element: LineEditor +) => Promise = ( + parent: MockWizardEditor, + element: LineEditor +): Promise => + new Promise(async resolve => { + expect(parent.wizardUI.dialog).to.be.undefined; + + element?.shadowRoot + ?.querySelector("mwc-icon-button[icon='playlist_add']")! + .click(); + const lnodMenuItem: ListItemBase = + element?.shadowRoot?.querySelector( + `mwc-list-item[value='LNode']` + )!; + lnodMenuItem.click(); + await new Promise(resolve => setTimeout(resolve, 100)); // await animation + + expect(parent.wizardUI.dialog).to.exist; + + const secondaryAction: HTMLElement = ( + parent.wizardUI.dialog?.querySelector( + 'mwc-button[slot="secondaryAction"][dialogaction="close"]' + ) + ); + + secondaryAction.click(); + await new Promise(resolve => setTimeout(resolve, 100)); // await animation + + expect(parent.wizardUI.dialog).to.be.undefined; + + return resolve(); + }); + describe('line-editor wizarding editing integration', () => { let doc: XMLDocument; let parent: MockWizardEditor; @@ -123,4 +158,33 @@ describe('line-editor wizarding editing integration', () => { }); }); }); + describe('Open add wizard', () => { + let doc: XMLDocument; + let parent: MockWizardEditor; + let element: LineEditor | null; + + beforeEach(async () => { + doc = await fetch('/test/testfiles/editors/substation/Line.scd') + .then(response => response.text()) + .then(str => new DOMParser().parseFromString(str, 'application/xml')); + parent = ( + await fixture( + html`` + ) + ); + + element = parent.querySelector('line-editor'); + + await parent.updateComplete; + }); + + it('Should open the same wizard for the second time', async () => { + await openAndCancelMenu(parent, element!); + await openAndCancelMenu(parent, element!); + }); + }); }); diff --git a/test/unit/editors/substation/__snapshots__/line-editor.test.snap.js b/test/unit/editors/substation/__snapshots__/line-editor.test.snap.js index f42ad941f2..1df347050a 100644 --- a/test/unit/editors/substation/__snapshots__/line-editor.test.snap.js +++ b/test/unit/editors/substation/__snapshots__/line-editor.test.snap.js @@ -20,6 +20,63 @@ snapshots["web component rendering Line element rendering LNode and Function chi + + + + + + + LNode + + + + + GeneralEquipment + + + + + Function + + + + + ConductingEquipment + + + + @@ -51,6 +108,63 @@ snapshots["web component rendering Line element rendering ConductingEquipment lo + + + + + + + LNode + + + + + GeneralEquipment + + + + + Function + + + + + ConductingEquipment + + + + @@ -82,6 +196,63 @@ snapshots["web component rendering Line element rendering GeneralEquipment looks + + + + + + + LNode + + + + + GeneralEquipment + + + + + Function + + + + + ConductingEquipment + + + +