Skip to content

Commit 87788d0

Browse files
committed
feat: implement delete dialog and functionality for LNodeType management
1 parent 4222b44 commit 87788d0

7 files changed

Lines changed: 589 additions & 29 deletions

File tree

components/delete-dialog.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/* eslint-disable @typescript-eslint/no-unused-vars */
2+
import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
3+
import { LitElement, html, css } from 'lit';
4+
import { query, state } from 'lit/decorators.js';
5+
import { MdDialog } from '@scopedelement/material-web/dialog/dialog.js';
6+
import { MdOutlinedButton } from '@scopedelement/material-web/button/MdOutlinedButton.js';
7+
8+
export class DeleteDialog extends ScopedElementsMixin(LitElement) {
9+
static scopedElements = {
10+
'md-dialog': MdDialog,
11+
'md-outlined-button': MdOutlinedButton,
12+
};
13+
14+
@query('md-dialog')
15+
dialog!: MdDialog;
16+
17+
@state()
18+
lnodeTypeId: string = '';
19+
20+
@state()
21+
message: string = '';
22+
23+
onConfirm?: () => void;
24+
25+
get open() {
26+
return this.dialog?.open ?? false;
27+
}
28+
29+
show() {
30+
this.dialog?.show();
31+
}
32+
33+
close() {
34+
this.dialog?.close();
35+
}
36+
37+
private handleCancel() {
38+
this.close();
39+
}
40+
41+
private handleConfirm() {
42+
if (this.onConfirm) {
43+
this.onConfirm();
44+
}
45+
this.close();
46+
}
47+
48+
render() {
49+
return html`
50+
<md-dialog>
51+
<div slot="headline">Confirm Delete</div>
52+
<form slot="content" id="form-delete" method="dialog">
53+
<div class="delete-content">
54+
<div class="message">${this.message}</div>
55+
</div>
56+
</form>
57+
<div slot="actions">
58+
<md-outlined-button
59+
class="button close"
60+
form="form-delete"
61+
@click="${this.handleCancel}"
62+
>Cancel</md-outlined-button
63+
>
64+
<md-outlined-button
65+
class="button delete"
66+
form="form-delete"
67+
@click="${this.handleConfirm}"
68+
>Delete</md-outlined-button
69+
>
70+
</div>
71+
</md-dialog>
72+
`;
73+
}
74+
75+
static styles = css`
76+
* {
77+
--md-sys-color-primary: var(--oscd-primary);
78+
--md-sys-color-secondary: var(--oscd-secondary);
79+
--md-sys-typescale-body-large-font: var(--oscd-theme-text-font);
80+
--md-outlined-text-field-input-text-color: var(--oscd-base01);
81+
82+
--md-sys-color-surface: var(--oscd-base3);
83+
--md-sys-color-on-surface: var(--oscd-base00);
84+
--md-sys-color-on-primary: var(--oscd-base2);
85+
--md-sys-color-on-surface-variant: var(--oscd-base00);
86+
--md-menu-container-color: var(--oscd-base3);
87+
font-family: var(--oscd-theme-text-font);
88+
--md-sys-color-surface-container-highest: var(--oscd-base2);
89+
--md-dialog-container-color: var(--oscd-base3);
90+
font-family: var(--oscd-theme-text-font, 'Roboto');
91+
}
92+
93+
md-outlined-button {
94+
text-transform: uppercase;
95+
}
96+
97+
.delete-content {
98+
display: flex;
99+
flex-direction: column;
100+
gap: 12px;
101+
}
102+
103+
.message {
104+
color: var(--oscd-base00);
105+
}
106+
107+
.button.close {
108+
--md-outlined-button-label-text-color: var(--oscd-accent-red);
109+
--md-outlined-button-hover-label-text-color: var(--oscd-accent-red);
110+
}
111+
112+
.button.delete {
113+
--md-outlined-button-label-text-color: var(--oscd-accent-red);
114+
--md-outlined-button-hover-label-text-color: var(--oscd-accent-red);
115+
}
116+
`;
117+
}

foundation/utils.spec.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/* eslint-disable no-unused-expressions */
2+
import { expect } from '@open-wc/testing';
3+
import { removeDOsNotInSelection } from './utils.js';
4+
5+
describe('foundation/utils', () => {
6+
describe('removeDOsNotInSelection', () => {
7+
let lNodeType: Element;
8+
9+
beforeEach(() => {
10+
const doc = new DOMParser().parseFromString(
11+
`<LNodeType id="TestLNodeType" lnClass="MMXU">
12+
<DO name="Beh" type="ENS_1"/>
13+
<DO name="A" type="WYE_1"/>
14+
<DO name="PhV" type="WYE_2"/>
15+
</LNodeType>`,
16+
'application/xml'
17+
);
18+
lNodeType = doc.documentElement;
19+
});
20+
21+
it('removes DOs not in selection', () => {
22+
const selection = {
23+
Beh: {},
24+
PhV: {},
25+
};
26+
27+
const result = removeDOsNotInSelection(lNodeType, selection);
28+
29+
const remainingDOs = Array.from(result.querySelectorAll('DO')).map(
30+
doElement => doElement.getAttribute('name')
31+
);
32+
33+
expect(remainingDOs).to.have.lengthOf(2);
34+
expect(remainingDOs).to.include('Beh');
35+
expect(remainingDOs).to.include('PhV');
36+
expect(remainingDOs).to.not.include('A');
37+
});
38+
39+
it('returns a clone without modifying the original', () => {
40+
const selection = {
41+
Beh: {},
42+
};
43+
44+
const originalDOCount = lNodeType.querySelectorAll('DO').length;
45+
const result = removeDOsNotInSelection(lNodeType, selection);
46+
47+
// Original should be unchanged
48+
expect(lNodeType.querySelectorAll('DO')).to.have.lengthOf(
49+
originalDOCount
50+
);
51+
52+
// Result should have fewer DOs
53+
expect(result.querySelectorAll('DO')).to.have.lengthOf(1);
54+
});
55+
56+
it('removes all DOs when selection is empty', () => {
57+
const selection = {};
58+
59+
const result = removeDOsNotInSelection(lNodeType, selection);
60+
61+
expect(result.querySelectorAll('DO')).to.have.lengthOf(0);
62+
});
63+
64+
it('keeps all DOs when all are in selection', () => {
65+
const selection = {
66+
Beh: {},
67+
A: {},
68+
PhV: {},
69+
};
70+
71+
const result = removeDOsNotInSelection(lNodeType, selection);
72+
73+
expect(result.querySelectorAll('DO')).to.have.lengthOf(3);
74+
});
75+
76+
it('preserves LNodeType attributes', () => {
77+
const selection = {
78+
Beh: {},
79+
};
80+
81+
const result = removeDOsNotInSelection(lNodeType, selection);
82+
83+
expect(result.getAttribute('id')).to.equal('TestLNodeType');
84+
expect(result.getAttribute('lnClass')).to.equal('MMXU');
85+
expect(result.tagName).to.equal('LNodeType');
86+
});
87+
});
88+
});

foundation/utils.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,27 @@ export function filterSelection(
3939

4040
return filteredTree;
4141
}
42+
43+
export function removeDOsNotInSelection(
44+
lNodeType: Element,
45+
selection: TreeSelection
46+
): Element {
47+
const clonedLNodeType = lNodeType.cloneNode(true) as Element;
48+
49+
// Remove DOs that are not in selection
50+
const dosToRemove: Element[] = [];
51+
Array.from(clonedLNodeType.querySelectorAll(':scope > DO')).forEach(
52+
doElement => {
53+
const doName = doElement.getAttribute('name');
54+
if (doName && !selection[doName]) {
55+
dosToRemove.push(doElement);
56+
}
57+
}
58+
);
59+
60+
dosToRemove.forEach(doElement => {
61+
clonedLNodeType.removeChild(doElement);
62+
});
63+
64+
return clonedLNodeType;
65+
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
2-
"name": "@openscd/oscd-template-generator",
3-
"description": "OpenSCD plugin for creating new DataTypeTemplates",
2+
"name": "@com-pas/scl-template-update",
3+
"description": "OpenSCD plugin for updating DataTypeTemplates",
44
"license": "Apache-2.0",
5-
"author": "oscd-template-generator",
5+
"author": "CoMPAS",
66
"version": "0.0.0",
77
"scripts": {
88
"prepare": "npm run build",

0 commit comments

Comments
 (0)