Skip to content

Commit f262cae

Browse files
marcvanraalteStef3stpascalwilbrink
authored
feat(../substation/sub-equipment-editor.ts):add_button_to_the_SubEqui… (openscd#1113)
* feat(../substation/sub-equipment-editor.ts):add_button_to_the_SubEquipment_editor * Fixed merge conflicts (Delete button / Add button) Signed-off-by: Pascal Wilbrink <[email protected]> Signed-off-by: Pascal Wilbrink <[email protected]> Signed-off-by: Pascal Wilbrink <[email protected]> Co-authored-by: Stef3st <[email protected]> Co-authored-by: Pascal Wilbrink <[email protected]>
1 parent 0c3bd0c commit f262cae

File tree

3 files changed

+233
-2
lines changed

3 files changed

+233
-2
lines changed

src/editors/substation/sub-equipment-editor.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,38 @@ import {
55
LitElement,
66
property,
77
TemplateResult,
8+
query,
89
} from 'lit-element';
910
import { translate } from 'lit-translate';
1011

1112
import '@material/mwc-fab';
1213
import '@material/mwc-icon';
1314
import '@material/mwc-icon-button';
1415
import '@material/mwc-menu';
16+
import { IconButton } from '@material/mwc-icon-button';
17+
import { ListItem } from '@material/mwc-list/mwc-list-item';
18+
import { Menu } from '@material/mwc-menu';
1519

1620
import '../../action-icon.js';
1721
import '../../action-pane.js';
1822

1923
import { styles } from './foundation.js';
2024
import {
2125
getChildElementsByTagName,
22-
newActionEvent,
2326
newWizardEvent,
27+
newActionEvent,
28+
SCLTag,
29+
tags,
2430
} from '../../foundation.js';
25-
import { wizards } from '../../wizards/wizard-library.js';
31+
import { emptyWizard, wizards } from '../../wizards/wizard-library.js';
32+
33+
function childTags(element: Element | null | undefined): SCLTag[] {
34+
if (!element) return [];
35+
36+
return tags[<SCLTag>element.tagName].children.filter(
37+
child => wizards[child].create !== emptyWizard
38+
);
39+
}
2640

2741
/** [[`SubstationEditor`]] subeditor for a child-less `SubEquipment` element. */
2842
@customElement('sub-equipment-editor')
@@ -58,6 +72,9 @@ export class SubEquipmentEditor extends LitElement {
5872
return `${name}${description}${phase}`;
5973
}
6074

75+
@query('mwc-menu') addMenu!: Menu;
76+
@query('mwc-icon-button[icon="playlist_add"]') addButton!: IconButton;
77+
6178
remove(): void {
6279
if (this.element.parentElement)
6380
this.dispatchEvent(
@@ -70,6 +87,26 @@ export class SubEquipmentEditor extends LitElement {
7087
);
7188
}
7289

90+
private openCreateWizard(tagName: string): void {
91+
const wizard = wizards[<SCLTag>tagName].create(this.element!);
92+
93+
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
94+
}
95+
96+
updated(): void {
97+
if (this.addMenu && this.addButton)
98+
this.addMenu.anchor = <HTMLElement>this.addButton;
99+
}
100+
101+
private renderAddButtons(): TemplateResult[] {
102+
return childTags(this.element).map(
103+
child =>
104+
html`<mwc-list-item value="${child}"
105+
><span>${child}</span></mwc-list-item
106+
>`
107+
);
108+
}
109+
73110
private renderLNodes(): TemplateResult {
74111
const lNodes = getChildElementsByTagName(this.element, 'LNode');
75112

@@ -116,6 +153,26 @@ export class SubEquipmentEditor extends LitElement {
116153
@click=${() => this.remove()}
117154
></mwc-icon-button>
118155
</abbr>
156+
<abbr
157+
slot="action"
158+
style="position:relative;"
159+
title="${translate('add')}"
160+
>
161+
<mwc-icon-button
162+
icon="playlist_add"
163+
@click=${() => (this.addMenu.open = true)}
164+
></mwc-icon-button
165+
><mwc-menu
166+
corner="BOTTOM_RIGHT"
167+
menuCorner="END"
168+
@action=${(e: Event) => {
169+
const tagName = (<ListItem>(<Menu>e.target).selected).value;
170+
this.openCreateWizard(tagName);
171+
}}
172+
>${this.renderAddButtons()}</mwc-menu
173+
>
174+
</abbr>
175+
119176
${this.renderLNodes()} ${this.renderEqFunctions()}
120177
</action-pane> `;
121178
}

test/integration/editors/substation/sub-equipment-wizarding-editing.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,44 @@ import '../../../../src/editors/substation/sub-equipment-editor.js';
77
import { WizardTextField } from '../../../../src/wizard-textfield.js';
88
import { SubEquipmentEditor } from '../../../../src/editors/substation/sub-equipment-editor.js';
99
import { WizardCheckbox } from '../../../../src/wizard-checkbox.js';
10+
import { ListItemBase } from '@material/mwc-list/mwc-list-item-base';
11+
import { MenuBase } from '@material/mwc-menu/mwc-menu-base.js';
12+
13+
const openAndCancelMenu: (
14+
parent: MockWizardEditor,
15+
element: SubEquipmentEditor
16+
) => Promise<void> = (
17+
parent: MockWizardEditor,
18+
element: SubEquipmentEditor
19+
): Promise<void> =>
20+
new Promise(async resolve => {
21+
expect(parent.wizardUI.dialog).to.be.undefined;
22+
23+
element?.shadowRoot
24+
?.querySelector<MenuBase>("mwc-icon-button[icon='playlist_add']")!
25+
.click();
26+
const lnodMenuItem: ListItemBase =
27+
element?.shadowRoot?.querySelector<ListItemBase>(
28+
`mwc-list-item[value='LNode']`
29+
)!;
30+
lnodMenuItem.click();
31+
await new Promise(resolve => setTimeout(resolve, 100)); // await animation
32+
33+
expect(parent.wizardUI.dialog).to.exist;
34+
35+
const secondaryAction: HTMLElement = <HTMLElement>(
36+
parent.wizardUI.dialog?.querySelector(
37+
'mwc-button[slot="secondaryAction"]'
38+
)
39+
);
40+
41+
secondaryAction.click();
42+
await new Promise(resolve => setTimeout(resolve, 100)); // await animation
43+
44+
expect(parent.wizardUI.dialog).to.be.undefined;
45+
46+
return resolve();
47+
});
1048

1149
describe('sub-equipment-editor wizarding editing integration', () => {
1250
let doc: XMLDocument;
@@ -118,4 +156,35 @@ describe('sub-equipment-editor wizarding editing integration', () => {
118156
});
119157
});
120158
});
159+
160+
describe('Open add wizard', () => {
161+
let doc: XMLDocument;
162+
let parent: MockWizardEditor;
163+
let element: SubEquipmentEditor | null;
164+
165+
beforeEach(async () => {
166+
doc = await fetch('/test/testfiles/SubEquipment.scd')
167+
.then(response => response.text())
168+
.then(str => new DOMParser().parseFromString(str, 'application/xml'));
169+
parent = <MockWizardEditor>(
170+
await fixture(
171+
html`<mock-wizard-editor
172+
><sub-equipment-editor
173+
.element=${doc.querySelector('SubEquipment[name="subque"]')}
174+
?showfunctions=${true}
175+
></sub-equipment-editor
176+
></mock-wizard-editor>`
177+
)
178+
);
179+
180+
element = parent.querySelector('sub-equipment-editor');
181+
182+
await parent.updateComplete;
183+
});
184+
185+
it('Should open the same wizard for the second time', async () => {
186+
await openAndCancelMenu(parent, element!);
187+
await openAndCancelMenu(parent, element!);
188+
});
189+
});
121190
});

test/unit/editors/substation/__snapshots__/sub-equipment-editor.test.snap.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,41 @@ snapshots["sub-equipment-editor looks like the latest snapshot"] =
2020
<mwc-icon-button icon="delete">
2121
</mwc-icon-button>
2222
</abbr>
23+
<abbr
24+
slot="action"
25+
style="position:relative;"
26+
title="[add]"
27+
>
28+
<mwc-icon-button icon="playlist_add">
29+
</mwc-icon-button>
30+
<mwc-menu
31+
corner="BOTTOM_RIGHT"
32+
menucorner="END"
33+
>
34+
<mwc-list-item
35+
aria-disabled="false"
36+
mwc-list-item=""
37+
role="menuitem"
38+
tabindex="0"
39+
value="LNode"
40+
>
41+
<span>
42+
LNode
43+
</span>
44+
</mwc-list-item>
45+
<mwc-list-item
46+
aria-disabled="false"
47+
mwc-list-item=""
48+
role="menuitem"
49+
tabindex="-1"
50+
value="EqFunction"
51+
>
52+
<span>
53+
EqFunction
54+
</span>
55+
</mwc-list-item>
56+
</mwc-menu>
57+
</abbr>
2358
</action-pane>
2459
`;
2560
/* end snapshot sub-equipment-editor looks like the latest snapshot */
@@ -43,6 +78,41 @@ snapshots["sub-equipment-editor With children looks like the latest snapshot"] =
4378
<mwc-icon-button icon="delete">
4479
</mwc-icon-button>
4580
</abbr>
81+
<abbr
82+
slot="action"
83+
style="position:relative;"
84+
title="[add]"
85+
>
86+
<mwc-icon-button icon="playlist_add">
87+
</mwc-icon-button>
88+
<mwc-menu
89+
corner="BOTTOM_RIGHT"
90+
menucorner="END"
91+
>
92+
<mwc-list-item
93+
aria-disabled="false"
94+
mwc-list-item=""
95+
role="menuitem"
96+
tabindex="0"
97+
value="LNode"
98+
>
99+
<span>
100+
LNode
101+
</span>
102+
</mwc-list-item>
103+
<mwc-list-item
104+
aria-disabled="false"
105+
mwc-list-item=""
106+
role="menuitem"
107+
tabindex="-1"
108+
value="EqFunction"
109+
>
110+
<span>
111+
EqFunction
112+
</span>
113+
</mwc-list-item>
114+
</mwc-menu>
115+
</abbr>
46116
<div class="container lnode">
47117
<l-node-editor>
48118
</l-node-editor>
@@ -72,6 +142,41 @@ snapshots["sub-equipment-editor without description and state looks like the lat
72142
<mwc-icon-button icon="delete">
73143
</mwc-icon-button>
74144
</abbr>
145+
<abbr
146+
slot="action"
147+
style="position:relative;"
148+
title="[add]"
149+
>
150+
<mwc-icon-button icon="playlist_add">
151+
</mwc-icon-button>
152+
<mwc-menu
153+
corner="BOTTOM_RIGHT"
154+
menucorner="END"
155+
>
156+
<mwc-list-item
157+
aria-disabled="false"
158+
mwc-list-item=""
159+
role="menuitem"
160+
tabindex="0"
161+
value="LNode"
162+
>
163+
<span>
164+
LNode
165+
</span>
166+
</mwc-list-item>
167+
<mwc-list-item
168+
aria-disabled="false"
169+
mwc-list-item=""
170+
role="menuitem"
171+
tabindex="-1"
172+
value="EqFunction"
173+
>
174+
<span>
175+
EqFunction
176+
</span>
177+
</mwc-list-item>
178+
</mwc-menu>
179+
</abbr>
75180
<div class="container lnode">
76181
<l-node-editor>
77182
</l-node-editor>

0 commit comments

Comments
 (0)