Skip to content

Commit cf65a50

Browse files
feat(wizards/transformerwinding): add edit wizard (openscd#1137)
* feat(../substation/transformer-winding-editor.ts):edit_wizard_added * feat(../wizards/tarnsformerWinding.ts):included * add_editor_wizard * fix(transformerWinding.ts):import_ordering_issues * fix(../TransformwerWinding.scd):one_scd_test_file * fix(wizards/transformerwinding): required removed
1 parent ae26764 commit cf65a50

File tree

10 files changed

+693
-48
lines changed

10 files changed

+693
-48
lines changed

src/editors/substation/transformer-winding-editor.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
TemplateResult,
88
} from 'lit-element';
99

10+
import { translate } from 'lit-translate';
11+
1012
import '@material/mwc-fab';
1113
import '@material/mwc-icon';
1214
import '@material/mwc-icon-button';
@@ -16,7 +18,8 @@ import '../../action-icon.js';
1618
import '../../action-pane.js';
1719

1820
import { styles } from './foundation.js';
19-
import { getChildElementsByTagName } from '../../foundation.js';
21+
import { getChildElementsByTagName, newWizardEvent } from '../../foundation.js';
22+
import { wizards } from '../../wizards/wizard-library.js';
2023

2124
@customElement('transformer-winding-editor')
2225
export class TransformerWindingEditor extends LitElement {
@@ -48,6 +51,11 @@ export class TransformerWindingEditor extends LitElement {
4851
return `${name}${description}`;
4952
}
5053

54+
openEditWizard(): void {
55+
const wizard = wizards['TransformerWinding'].edit(this.element);
56+
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
57+
}
58+
5159
private renderLNodes(): TemplateResult {
5260
const lNodes = getChildElementsByTagName(this.element, 'LNode');
5361

@@ -81,6 +89,12 @@ export class TransformerWindingEditor extends LitElement {
8189

8290
render(): TemplateResult {
8391
return html`<action-pane label="${this.label}">
92+
<abbr slot="action" title="${translate('edit')}">
93+
<mwc-icon-button
94+
icon="edit"
95+
@click=${() => this.openEditWizard()}
96+
></mwc-icon-button>
97+
</abbr>
8498
${this.renderLNodes()} ${this.renderEqFunctions()}
8599
</action-pane> `;
86100
}

src/wizards/transformerWinding.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { html, TemplateResult } from 'lit-element';
2+
import { get, translate } from 'lit-translate';
3+
4+
import {
5+
cloneElement,
6+
getChildElementsByTagName,
7+
getValue,
8+
SimpleAction,
9+
Wizard,
10+
WizardActor,
11+
WizardInputElement,
12+
} from '../foundation.js';
13+
14+
function updateTransformerWindingAction(element: Element): WizardActor {
15+
return (inputs: WizardInputElement[]): SimpleAction[] => {
16+
const transformerWindingAttrs: Record<string, string | null> = {};
17+
const transformerWindingKeys = ['name', 'desc', 'type', 'virtual'];
18+
transformerWindingKeys.forEach(key => {
19+
transformerWindingAttrs[key] = getValue(
20+
inputs.find(i => i.label === key)!
21+
);
22+
});
23+
24+
if (
25+
transformerWindingKeys.some(
26+
key => transformerWindingAttrs[key] !== element.getAttribute(key)
27+
)
28+
) {
29+
const newElement = cloneElement(element, transformerWindingAttrs);
30+
return [
31+
{
32+
old: { element },
33+
new: { element: newElement },
34+
},
35+
];
36+
}
37+
return [];
38+
};
39+
}
40+
41+
interface ContentOptions {
42+
name: string | null;
43+
desc: string | null;
44+
type: string | null;
45+
virtual: string | null;
46+
reservedNames: string[];
47+
}
48+
49+
export function contentTransformerWindingWizard(
50+
content: ContentOptions
51+
): TemplateResult[] {
52+
return [
53+
html`<wizard-textfield
54+
label="name"
55+
.maybeValue=${content.name}
56+
helper="${translate('scl.name')}"
57+
required
58+
validationMessage="${translate('textfield.required')}"
59+
.reservedValues=${content.reservedNames}
60+
dialogInitialFocus
61+
></wizard-textfield>`,
62+
html`<wizard-textfield
63+
label="desc"
64+
.maybeValue=${content.desc}
65+
nullable
66+
helper="${translate('scl.desc')}"
67+
></wizard-textfield>`,
68+
html`<wizard-textfield
69+
label="type"
70+
.maybeValue=${content.type}
71+
disabled
72+
helper="${translate('scl.type')}"
73+
></wizard-textfield>`,
74+
html`<wizard-checkbox
75+
label="virtual"
76+
.maybeValue=${content.virtual}
77+
helper="${translate('scl.virtual')}"
78+
nullable
79+
></wizard-checkbox>`,
80+
];
81+
}
82+
83+
export function editTransformerWindingWizard(element: Element): Wizard {
84+
const name = element.getAttribute('name');
85+
const desc = element.getAttribute('desc');
86+
const type = element.getAttribute('type');
87+
const virtual = element.getAttribute('virtual');
88+
const reservedNames: string[] = getChildElementsByTagName(
89+
element.parentElement!,
90+
'TransformerWinding'
91+
)
92+
.filter(sibling => sibling !== element)
93+
.map(sibling => sibling.getAttribute('name')!);
94+
95+
return [
96+
{
97+
title: get('wizard.title.edit', { tagName: 'TransformerWinding' }),
98+
primary: {
99+
icon: 'save',
100+
label: get('save'),
101+
action: updateTransformerWindingAction(element),
102+
},
103+
content: [
104+
...contentTransformerWindingWizard({
105+
name,
106+
desc,
107+
type,
108+
virtual,
109+
reservedNames,
110+
}),
111+
],
112+
},
113+
];
114+
}

src/wizards/wizard-library.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
createGeneralEquipmentWizard,
4545
editGeneralEquipmentWizard,
4646
} from './generalEquipment.js';
47+
import { editTransformerWindingWizard } from './transformerWinding.js';
4748

4849
type SclElementWizard = (
4950
element: Element,
@@ -534,7 +535,7 @@ export const wizards: Record<
534535
create: emptyWizard,
535536
},
536537
TransformerWinding: {
537-
edit: emptyWizard,
538+
edit: editTransformerWindingWizard,
538539
create: emptyWizard,
539540
},
540541
TrgOps: {
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { expect, fixture, html } from '@open-wc/testing';
2+
3+
import '../../../mock-wizard-editor.js';
4+
import { MockWizardEditor } from '../../../mock-wizard-editor.js';
5+
6+
import '../../../../src/editors/substation/transformer-winding-editor.js';
7+
import { TransformerWindingEditor } from '../../../../src/editors/substation/transformer-winding-editor.js';
8+
import { WizardTextField } from '../../../../src/wizard-textfield.js';
9+
import { WizardCheckbox } from '../../../../src/wizard-checkbox.js';
10+
11+
describe('transformer-winding-editor wizarding editing integration', () => {
12+
let doc: XMLDocument;
13+
let parent: MockWizardEditor;
14+
let element: TransformerWindingEditor | null;
15+
16+
describe('edit wizard', () => {
17+
let nameField: WizardTextField;
18+
let descField: WizardTextField;
19+
let primaryAction: HTMLElement;
20+
let secondaryAction: HTMLElement;
21+
22+
beforeEach(async () => {
23+
doc = await fetch(
24+
'test/testfiles/editors/substation/TransformerWinding.scd'
25+
)
26+
.then(response => response.text())
27+
.then(str => new DOMParser().parseFromString(str, 'application/xml'));
28+
parent = <MockWizardEditor>(
29+
await fixture(
30+
html`<mock-wizard-editor
31+
><transformer-winding-editor
32+
.element=${doc.querySelector('TransformerWinding')}
33+
></transformer-winding-editor
34+
></mock-wizard-editor>`
35+
)
36+
);
37+
element = parent.querySelector('transformer-winding-editor');
38+
await (<HTMLElement>(
39+
element?.shadowRoot?.querySelector('mwc-icon-button[icon="edit"]')
40+
)).click();
41+
await parent.updateComplete;
42+
43+
nameField = <WizardTextField>(
44+
parent.wizardUI.dialog?.querySelector('wizard-textfield[label="name"]')
45+
);
46+
descField = <WizardTextField>(
47+
parent.wizardUI.dialog?.querySelector('wizard-textfield[label="desc"]')
48+
);
49+
50+
secondaryAction = <HTMLElement>(
51+
parent.wizardUI.dialog?.querySelector(
52+
'mwc-button[slot="secondaryAction"]'
53+
)
54+
);
55+
primaryAction = <HTMLElement>(
56+
parent.wizardUI.dialog?.querySelector(
57+
'mwc-button[slot="primaryAction"]'
58+
)
59+
);
60+
});
61+
it('closes on secondary action', async () => {
62+
secondaryAction.click();
63+
await new Promise(resolve => setTimeout(resolve, 100)); // await animation
64+
expect(parent.wizardUI.dialog).to.not.exist;
65+
});
66+
it('does not change name attribute if not unique within parent element', async () => {
67+
const oldName = nameField.value;
68+
nameField.value = 'some1';
69+
primaryAction.click();
70+
await parent.updateComplete;
71+
expect(
72+
doc.querySelector('TransformerWinding')?.getAttribute('name')
73+
).to.equal(oldName);
74+
});
75+
it('changes desc attribute on primary action', async () => {
76+
await new Promise(resolve => setTimeout(resolve, 100)); // await animation
77+
descField.nullSwitch!.click();
78+
await parent.updateComplete;
79+
descField.value = 'newDesc';
80+
primaryAction.click();
81+
await parent.updateComplete;
82+
expect(
83+
doc.querySelector('TransformerWinding')?.getAttribute('desc')
84+
).to.equal('newDesc');
85+
});
86+
it('changes virtual attribute on primary action', async () => {
87+
const virtualCheckbox = <WizardCheckbox>(
88+
parent.wizardUI.dialog?.querySelector(
89+
'wizard-checkbox[label="virtual"]'
90+
)
91+
);
92+
virtualCheckbox.nullSwitch!.click();
93+
virtualCheckbox.maybeValue = 'true';
94+
primaryAction.click();
95+
await parent.updateComplete;
96+
expect(
97+
doc.querySelector('TransformerWinding')?.getAttribute('virtual')
98+
).to.equal('true');
99+
});
100+
});
101+
});

test/testfiles/TransformerWinding.scd

Lines changed: 0 additions & 45 deletions
This file was deleted.

0 commit comments

Comments
 (0)