Skip to content

Commit 1373b12

Browse files
committed
add dialog component for editing (sub)functions
1 parent a52118a commit 1373b12

File tree

4 files changed

+302
-154
lines changed

4 files changed

+302
-154
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable no-unused-expressions */
22
import { html, fixture, expect } from '@open-wc/testing';
33
import './function-editor.js';
4-
import { testScl } from './scl-bay-template.testfiles.js';
4+
import { testScl } from '../scl-bay-template.testfiles.js';
55

66
describe('FunctionEditor', () => {
77
let element: any;
Lines changed: 109 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/* eslint-disable import/no-extraneous-dependencies */
22
/* eslint-disable no-return-assign */
33
/* eslint-disable lit-a11y/click-events-have-key-events */
4-
import { css, html, LitElement, nothing, TemplateResult } from 'lit';
5-
import { customElement, property, query, state } from 'lit/decorators.js';
4+
import { LitElement, html, css, nothing, TemplateResult } from 'lit';
5+
import { customElement, property, state, query } from 'lit/decorators.js';
66

77
import { classMap } from 'lit/directives/class-map.js';
88

@@ -17,7 +17,7 @@ import '@material/mwc-textfield';
1717
import type { Dialog } from '@material/mwc-dialog';
1818
import type { TextField } from '@material/mwc-textfield';
1919

20-
import { Edit, Insert, newEditEvent, Remove } from '@openscd/open-scd-core';
20+
import { Edit, Insert, Remove, newEditEvent } from '@openscd/open-scd-core';
2121

2222
import '@openscd/oscd-tree-grid';
2323
import type { Path, TreeGrid } from '@openscd/oscd-tree-grid';
@@ -44,12 +44,12 @@ import {
4444
listAddPath,
4545
outputCirclePath,
4646
switchAddPath,
47-
} from './foundation/sldIcons.js';
47+
} from '../foundation/sldIcons.js';
4848
import {
4949
dataAttributeTree,
5050
getSourceDef,
51-
} from './foundation/dataAttributePicker.js';
52-
import { newCreateWizardEvent, newEditWizardEvent } from './foundation.js';
51+
} from '../foundation/dataAttributePicker.js';
52+
import './function-element-dialog.js';
5353

5454
const uri6100 = 'http://www.iec.ch/61850/2019/SCL/6-100';
5555
const xmlnsNs = 'http://www.w3.org/2000/xmlns/';
@@ -818,137 +818,37 @@ export default class FunctionEditor9030 extends LitElement {
818818

819819
@query('#lnlist') lnList!: SelectionList;
820820

821-
@query('#addSubFunctionDialog') addSubFunctionDialog!: Dialog;
822-
823-
@query('#subfunc-name') subFunctionNameField!: TextField;
824-
825-
@query('#subfunc-desc') subFunctionDescField!: TextField;
826-
827-
@query('#subfunc-type') subFunctionTypeField!: TextField;
828-
829821
@state()
830-
subFunctionDialogParent?: Element;
831-
832-
private openAddSubFunctionDialog(parent: Element): void {
833-
this.subFunctionDialogParent = parent;
834-
this.addSubFunctionDialog.show();
835-
}
836-
837-
private onClosing(): void {
838-
this.subFunctionNameField.value = '';
839-
this.subFunctionNameField.setCustomValidity('');
840-
this.subFunctionDescField.value = '';
841-
this.subFunctionTypeField.value = '';
842-
}
843-
844-
private isSubFunctionNameUnique(name: string): boolean {
845-
if (!this.subFunctionDialogParent) return false;
846-
return !Array.from(this.subFunctionDialogParent.children).some(
847-
el =>
848-
(el.tagName === 'SubFunction' || el.tagName === 'EqSubFunction') &&
849-
el.getAttribute('name')?.trim().toLowerCase() === name.toLowerCase()
850-
);
851-
}
852-
853-
// eslint-disable-next-line class-methods-use-this
854-
private getSubFunctionTagName(
855-
parent: Element
856-
): 'SubFunction' | 'EqSubFunction' {
857-
return parent.tagName === 'Function' || parent.tagName === 'SubFunction'
858-
? 'SubFunction'
859-
: 'EqSubFunction';
860-
}
822+
showElementDialog = false;
861823

862-
private createSubFunctionElement(
863-
parent: Element,
864-
name: string,
865-
desc: string,
866-
type: string
867-
): Element {
868-
const tagName = this.getSubFunctionTagName(parent);
869-
const doc = parent.ownerDocument;
870-
const subFunc = doc.createElement(tagName);
871-
subFunc.setAttribute('name', name);
872-
if (desc) subFunc.setAttribute('desc', desc);
873-
if (type) subFunc.setAttribute('type', type);
874-
return subFunc;
875-
}
876-
877-
private saveSubFunction(): void {
878-
const name = this.subFunctionNameField.value.trim();
879-
const desc = this.subFunctionDescField.value.trim();
880-
const type = this.subFunctionTypeField.value.trim();
881-
882-
if (!this.subFunctionDialogParent) return;
883-
884-
if (!this.isSubFunctionNameUnique(name)) {
885-
this.subFunctionNameField.setCustomValidity('Name must be unique.');
886-
this.subFunctionNameField.reportValidity();
887-
return;
888-
}
889-
this.subFunctionNameField.setCustomValidity('');
890-
891-
if (!this.subFunctionNameField.reportValidity()) return;
824+
@state()
825+
dialogRequireUniqueName = false;
892826

893-
const subFunc = this.createSubFunctionElement(
894-
this.subFunctionDialogParent,
895-
name,
896-
desc,
897-
type
898-
);
827+
@state()
828+
dialogSiblings: Element[] = [];
899829

900-
const insertEdit = {
901-
parent: this.subFunctionDialogParent,
902-
node: subFunc,
903-
reference: null,
904-
};
905-
this.dispatchEvent(newEditEvent(insertEdit as Insert));
906-
this.addSubFunctionDialog.close();
907-
}
830+
@state()
831+
dialogElement?: Element;
908832

909-
private renderAddSubFunctionDialog(): TemplateResult {
910-
return html`
911-
<mwc-dialog
912-
id="addSubFunctionDialog"
913-
heading=${`Add ${
914-
this.subFunctionDialogParent?.tagName === 'Function' ||
915-
this.subFunctionDialogParent?.tagName === 'SubFunction'
916-
? 'SubFunction'
917-
: 'EqSubFunction'
918-
}`}
919-
@closing=${this.onClosing}
920-
>
921-
<div class="subfunc-dialog-content">
922-
<mwc-textfield
923-
id="subfunc-name"
924-
label="Name"
925-
required
926-
></mwc-textfield>
927-
<mwc-textfield id="subfunc-desc" label="Description"></mwc-textfield>
928-
<mwc-textfield id="subfunc-type" label="Type"></mwc-textfield>
929-
</div>
930-
<mwc-button slot="secondaryAction" dialogAction="close">
931-
Close
932-
</mwc-button>
933-
<mwc-button
934-
slot="primaryAction"
935-
icon="save"
936-
@click=${this.saveSubFunction}
937-
>
938-
Save
939-
</mwc-button>
940-
</mwc-dialog>
941-
`;
942-
}
833+
@state()
834+
dialogParent?: Element;
943835

944-
private openCreateWizard(tagName: string): void {
945-
if (this.parent)
946-
this.dispatchEvent(newCreateWizardEvent(this.parent, tagName));
947-
}
836+
@state()
837+
dialogTagName?: string;
838+
839+
private closeElementDialog = () => {
840+
this.showElementDialog = false;
841+
this.dialogElement = undefined;
842+
this.dialogParent = undefined;
843+
this.dialogTagName = undefined;
844+
this.dialogRequireUniqueName = false;
845+
this.dialogSiblings = [];
846+
};
948847

949-
private openEditWizard(element: Element): void {
950-
this.dispatchEvent(newEditWizardEvent(element));
951-
}
848+
private handleElementDialogSave = (e: CustomEvent) => {
849+
this.dispatchEvent(newEditEvent(e.detail));
850+
this.closeElementDialog();
851+
};
952852

953853
private removeFunction(func: Element): void {
954854
this.dispatchEvent(newEditEvent({ node: func }));
@@ -958,18 +858,6 @@ export default class FunctionEditor9030 extends LitElement {
958858
this.dispatchEvent(newEditEvent({ node: srcRef }));
959859
}
960860

961-
addFunction(): void {
962-
if (
963-
(this.parent && this.parent?.tagName === 'Bay') ||
964-
this.parent?.tagName === 'VoltageLevel'
965-
) {
966-
this.openCreateWizard('Function');
967-
return;
968-
}
969-
970-
this.openCreateWizard('EqFunction');
971-
}
972-
973861
createNewLNodeElements(): void {
974862
if (!this.lnodeparent) return;
975863

@@ -1131,6 +1019,22 @@ export default class FunctionEditor9030 extends LitElement {
11311019
this.lnList.items = deselectedItems;
11321020
}
11331021

1022+
openElementDialog(options: {
1023+
element?: Element;
1024+
parent?: Element;
1025+
tagName?: string;
1026+
heading?: string;
1027+
requireUniqueName?: boolean;
1028+
siblings?: Element[];
1029+
}) {
1030+
this.dialogElement = options.element;
1031+
this.dialogParent = options.parent;
1032+
this.dialogTagName = options.tagName;
1033+
this.dialogRequireUniqueName = !!options.requireUniqueName;
1034+
this.dialogSiblings = options.siblings ?? [];
1035+
this.showElementDialog = true;
1036+
}
1037+
11341038
updated(changedProperties: Map<string, any>) {
11351039
// make sure to put the 6-100 on the SCL element as defined by the IEC 61850-6
11361040
if (!changedProperties.has('doc')) return;
@@ -1800,9 +1704,37 @@ export default class FunctionEditor9030 extends LitElement {
18001704
})}"
18011705
>
18021706
<nav>
1707+
<mwc-icon-button
1708+
icon="edit"
1709+
@click="${() => {
1710+
this.openElementDialog({
1711+
element: subFunc!,
1712+
parent: this.parent!,
1713+
tagName: subFunc!.tagName,
1714+
requireUniqueName: true,
1715+
siblings: this.parent?.children
1716+
? Array.from(this.parent?.children).filter(
1717+
el => el.tagName === subFunc!.tagName
1718+
)
1719+
: [],
1720+
});
1721+
}}"
1722+
>
1723+
</mwc-icon-button>
18031724
<mwc-icon-button
18041725
icon="account_tree"
1805-
@click="${() => this.openAddSubFunctionDialog(subFunc)}"
1726+
@click="${() => {
1727+
this.openElementDialog({
1728+
element: undefined,
1729+
parent: subFunc,
1730+
tagName: 'SubFunction',
1731+
heading: 'Add SubFunction',
1732+
requireUniqueName: true,
1733+
siblings: Array.from(subFunc.children).filter(
1734+
el => el.tagName === 'SubFunction'
1735+
),
1736+
});
1737+
}}"
18061738
></mwc-icon-button>
18071739
<mwc-icon-button
18081740
icon="delete"
@@ -1841,12 +1773,34 @@ export default class FunctionEditor9030 extends LitElement {
18411773
<nav>
18421774
<mwc-icon-button
18431775
icon="edit"
1844-
@click="${() => this.openEditWizard(this.function!)}"
1776+
@click="${() => {
1777+
this.openElementDialog({
1778+
element: this.function!,
1779+
parent: this.parent!,
1780+
tagName: this.function!.tagName,
1781+
requireUniqueName: true,
1782+
siblings: this.parent?.children
1783+
? Array.from(this.parent?.children).filter(
1784+
el => el.tagName === this.function!.tagName
1785+
)
1786+
: [],
1787+
});
1788+
}}"
18451789
>
18461790
</mwc-icon-button>
18471791
<mwc-icon-button
18481792
icon="account_tree"
1849-
@click="${() => this.openAddSubFunctionDialog(this.function!)}"
1793+
@click="${() => {
1794+
this.openElementDialog({
1795+
element: undefined,
1796+
parent: this.function!,
1797+
tagName: 'SubFunction',
1798+
requireUniqueName: true,
1799+
siblings: Array.from(this.function!.children).filter(
1800+
el => el.tagName === 'SubFunction'
1801+
),
1802+
});
1803+
}}"
18501804
>
18511805
</mwc-icon-button>
18521806
<mwc-icon-button
@@ -1891,7 +1845,16 @@ export default class FunctionEditor9030 extends LitElement {
18911845
${this.renderLNodeTypePicker()} ${this.renderLNodeDetail()}
18921846
${this.renderExtRefPicker()}
18931847
</div>
1894-
${this.renderAddSubFunctionDialog()}
1848+
<function-element-dialog
1849+
.element=${this.dialogElement}
1850+
.parent=${this.dialogParent}
1851+
.elTagName=${this.dialogTagName}
1852+
.open=${this.showElementDialog}
1853+
.requireUniqueName=${this.dialogRequireUniqueName}
1854+
.siblings=${this.dialogSiblings}
1855+
@save=${this.handleElementDialogSave}
1856+
@close=${this.closeElementDialog}
1857+
></function-element-dialog>
18951858
</main>`;
18961859
}
18971860

@@ -2025,12 +1988,6 @@ export default class FunctionEditor9030 extends LitElement {
20251988
margin: 8px 10px 16px;
20261989
}
20271990
2028-
.subfunc-dialog-content {
2029-
display: flex;
2030-
flex-direction: column;
2031-
gap: 12px;
2032-
}
2033-
20341991
* {
20351992
--mdc-theme-primary: var(--fedit-primary);
20361993
--mdc-theme-secondary: var(--fedit-secondary);

0 commit comments

Comments
 (0)