Skip to content

Commit f52cac6

Browse files
author
Dennis Labordus
authored
Merge pull request #195 from com-pas/filter-labels-open-scl
Filter on labels when opening a SCL File from CoMPAS
2 parents d64cf4c + ebe32fc commit f52cac6

20 files changed

+798
-170
lines changed

src/compas/CompasOpen.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import '../WizardDivider.js';
2121
import './CompasSclTypeList.js';
2222
import './CompasSclList.js';
2323

24-
/* Event that will be used when a SCL Document is retrieved. */
24+
/* Event that will be used when an SCL Document is retrieved. */
2525
export interface DocRetrievedDetail {
2626
localFile: boolean;
2727
doc: Document;
@@ -33,7 +33,7 @@ export function newDocRetrievedEvent(
3333
doc: Document,
3434
docName?: string
3535
): DocRetrievedEvent {
36-
return new CustomEvent<DocRetrievedDetail>('docRetrieved', {
36+
return new CustomEvent<DocRetrievedDetail>('doc-retrieved', {
3737
bubbles: true,
3838
composed: true,
3939
detail: { localFile, doc, docName },
@@ -110,7 +110,7 @@ export default class CompasOpenElement extends LitElement {
110110
type: this.selectedType ?? '',
111111
})}</p>
112112
<compas-scl-list .type=${this.selectedType}
113-
@sclSelected=${(evt: SclSelectedEvent) =>
113+
@scl-selected=${(evt: SclSelectedEvent) =>
114114
this.dispatchEvent(
115115
newPendingStateEvent(
116116
this.getSclDocument(evt.detail.docId)

src/compas/CompasSave.ts

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
html,
55
LitElement,
66
property,
7+
PropertyValues,
78
query,
89
TemplateResult,
910
} from 'lit-element';
@@ -42,6 +43,15 @@ import './CompasLabelsField.js';
4243
import './CompasLoading.js';
4344
import './CompasSclTypeSelect.js';
4445

46+
/* Event that will be used when an SCL Document is saved. */
47+
export type DocSavedEvent = CustomEvent<void>;
48+
export function newDocSavedEvent(): DocSavedEvent {
49+
return new CustomEvent<void>('doc-saved', {
50+
bubbles: true,
51+
composed: true,
52+
});
53+
}
54+
4555
@customElement('compas-save')
4656
export default class CompasSaveElement extends CompasExistsIn(LitElement) {
4757
@property()
@@ -62,6 +72,17 @@ export default class CompasSaveElement extends CompasExistsIn(LitElement) {
6272
@query('compas-labels-field')
6373
private labelsField!: CompasLabelsFieldElement;
6474

75+
protected updated(_changedProperties: PropertyValues): void {
76+
super.updated(_changedProperties);
77+
78+
// When the document is updated, we reset the selected IED.
79+
if (_changedProperties.has('doc')) {
80+
if (this.commentField) {
81+
this.commentField.value = null;
82+
}
83+
}
84+
}
85+
6586
valid(): boolean {
6687
if (!this.existInCompas) {
6788
return this.nameField.checkValidity() && this.sclTypeRadioGroup.valid();
@@ -79,16 +100,14 @@ export default class CompasSaveElement extends CompasExistsIn(LitElement) {
79100
this.labelsField.updateLabelsInPrivateElement(privateElement!);
80101
}
81102

82-
private async addSclToCompas(doc: XMLDocument): Promise<boolean> {
103+
private async addSclToCompas(doc: XMLDocument): Promise<void> {
83104
const name = stripExtensionFromName(this.nameField.value);
84105
const comment = this.commentField.value;
85106
const docType = this.sclTypeRadioGroup.getSelectedValue() ?? '';
86-
let success = false;
87107

88108
await CompasSclDataService()
89109
.addSclDocument(docType, { sclName: name, comment: comment, doc: doc })
90110
.then(sclDocument => {
91-
this.commentField.value = null;
92111
updateDocumentInOpenSCD(this, sclDocument);
93112

94113
this.dispatchEvent(
@@ -97,22 +116,20 @@ export default class CompasSaveElement extends CompasExistsIn(LitElement) {
97116
title: get('compas.save.addSuccess'),
98117
})
99118
);
100-
success = true;
119+
120+
this.dispatchEvent(newDocSavedEvent());
101121
})
102122
.catch(reason => createLogEvent(this, reason));
103-
104-
return success;
105123
}
106124

107125
private async updateSclInCompas(
108126
docId: string,
109127
docName: string,
110128
doc: XMLDocument
111-
): Promise<boolean> {
129+
): Promise<void> {
112130
const changeSet = this.changeSetRadiogroup.getSelectedValue();
113131
const comment = this.commentField.value;
114132
const docType = getTypeFromDocName(docName);
115-
let success = false;
116133

117134
await CompasSclDataService()
118135
.updateSclDocument(docType, docId, {
@@ -121,7 +138,6 @@ export default class CompasSaveElement extends CompasExistsIn(LitElement) {
121138
doc: doc,
122139
})
123140
.then(sclDocument => {
124-
this.commentField.value = null;
125141
updateDocumentInOpenSCD(this, sclDocument);
126142

127143
this.dispatchEvent(
@@ -130,19 +146,18 @@ export default class CompasSaveElement extends CompasExistsIn(LitElement) {
130146
title: get('compas.save.updateSuccess'),
131147
})
132148
);
133-
success = true;
149+
150+
this.dispatchEvent(newDocSavedEvent());
134151
})
135152
.catch(reason => createLogEvent(this, reason));
136-
137-
return success;
138153
}
139154

140-
async saveToCompas(): Promise<boolean> {
155+
async saveToCompas(): Promise<void> {
141156
this.updateLabels();
142157
if (!this.docId || !this.existInCompas) {
143-
return this.addSclToCompas(this.doc);
158+
await this.addSclToCompas(this.doc);
144159
} else {
145-
return this.updateSclInCompas(this.docId, this.docName, this.doc);
160+
await this.updateSclInCompas(this.docId, this.docName, this.doc);
146161
}
147162
}
148163

@@ -153,6 +168,8 @@ export default class CompasSaveElement extends CompasExistsIn(LitElement) {
153168
@click=${() => {
154169
this.updateLabels();
155170
saveDocumentToFile(this.doc, this.docName);
171+
172+
this.dispatchEvent(newDocSavedEvent());
156173
}}
157174
>
158175
</mwc-button>

src/compas/CompasSclList.ts

Lines changed: 144 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
import {
2+
css,
23
customElement,
34
html,
45
LitElement,
56
property,
7+
PropertyValues,
8+
state,
69
TemplateResult,
710
} from 'lit-element';
811
import { translate } from 'lit-translate';
912

13+
import '@material/mwc-icon';
1014
import '@material/mwc-list';
1115
import '@material/mwc-list/mwc-list-item';
1216

17+
import { SelectedItemsChangedEvent } from '../oscd-filter-button.js';
18+
19+
import '../filtered-list.js';
20+
import '../oscd-filter-button.js';
21+
1322
import {
1423
CompasSclDataService,
1524
SDS_NAMESPACE,
@@ -21,7 +30,7 @@ export interface SclSelectedDetail {
2130
}
2231
export type SclSelectedEvent = CustomEvent<SclSelectedDetail>;
2332
export function newSclSelectedEvent(docId: string): SclSelectedEvent {
24-
return new CustomEvent<SclSelectedDetail>('sclSelected', {
33+
return new CustomEvent<SclSelectedDetail>('scl-selected', {
2534
bubbles: true,
2635
composed: true,
2736
detail: { docId },
@@ -30,54 +39,156 @@ export function newSclSelectedEvent(docId: string): SclSelectedEvent {
3039

3140
@customElement('compas-scl-list')
3241
export class CompasSclList extends LitElement {
33-
@property({ type: String })
34-
type = '';
35-
3642
@property()
37-
scls!: Element[];
43+
type?: string;
44+
45+
@state()
46+
private items?: Element[];
47+
48+
@state()
49+
private labels: string[] = [];
50+
51+
@state()
52+
private selectedLabels: string[] = [];
53+
54+
@state()
55+
private get filteredItems(): Element[] | undefined {
56+
// If items are still being retrieved, return undefined.
57+
if (!this.items) {
58+
return undefined;
59+
}
60+
61+
// If all labels are selected, show all items, including the ones not having a Label.
62+
if (this.labels.length === this.selectedLabels.length) {
63+
return this.items;
64+
}
65+
66+
return this.items.filter(item => {
67+
const labels = Array.from(item.querySelectorAll('Label') ?? [])
68+
.map(element => element.textContent)
69+
.filter(value => !!value) as string[];
70+
return (
71+
labels.filter(label => this.selectedLabels.includes(label)).length > 0
72+
);
73+
});
74+
}
3875

3976
firstUpdated(): void {
4077
this.fetchData();
4178
}
4279

80+
protected updated(_changedProperties: PropertyValues): void {
81+
super.updated(_changedProperties);
82+
83+
// When the document is updated, we reset the selected IED.
84+
if (_changedProperties.has('type')) {
85+
this.items = undefined;
86+
this.labels = [];
87+
this.selectedLabels = [];
88+
this.fetchData();
89+
}
90+
}
91+
4392
fetchData(): void {
44-
CompasSclDataService()
45-
.listScls(this.type)
46-
.then(xmlResponse => {
47-
this.scls = Array.from(xmlResponse.querySelectorAll('Item') ?? []);
48-
});
93+
if (this.type) {
94+
CompasSclDataService()
95+
.listScls(this.type)
96+
.then(xmlResponse => {
97+
this.items = Array.from(xmlResponse.querySelectorAll('Item') ?? []);
98+
this.labels = Array.from(
99+
new Set(
100+
Array.from(xmlResponse.querySelectorAll('Label') ?? [])
101+
.map(element => element.textContent)
102+
.filter(label => !!label)
103+
.sort((label1, label2) => label1!.localeCompare(label2!))
104+
)
105+
) as string[];
106+
this.selectedLabels = this.labels;
107+
});
108+
}
49109
}
50110

51111
render(): TemplateResult {
52-
if (!this.scls) {
112+
if (!this.items) {
53113
return html` <compas-loading></compas-loading> `;
54114
}
55-
if (this.scls?.length <= 0) {
115+
if (this.items?.length <= 0) {
56116
return html` <mwc-list>
57117
<mwc-list-item><i>${translate('compas.noScls')}</i></mwc-list-item>
58118
</mwc-list>`;
59119
}
60-
return html` <mwc-list>
61-
${this.scls.map(item => {
62-
const id =
63-
item.getElementsByTagNameNS(SDS_NAMESPACE, 'Id').item(0)!
64-
.textContent ?? '';
65-
let name =
66-
item.getElementsByTagNameNS(SDS_NAMESPACE, 'Name').item(0)!
67-
.textContent ?? '';
68-
if (name === '') {
69-
name = id;
70-
}
71-
const version =
72-
item.getElementsByTagNameNS(SDS_NAMESPACE, 'Version').item(0)!
73-
.textContent ?? '';
74-
return html`<mwc-list-item
75-
tabindex="0"
76-
@click=${() => this.dispatchEvent(newSclSelectedEvent(id))}
120+
const filteredItems = this.filteredItems;
121+
return html`
122+
<div class="filters">
123+
<span>${translate('compas.sclFilter')}</span>
124+
<oscd-filter-button
125+
id="labelsFilter"
126+
multi="true"
127+
?disabled="${this.labels.length <= 0}"
128+
.header=${translate('compas.label.selectLabels')}
129+
@selected-items-changed="${(e: SelectedItemsChangedEvent) => {
130+
this.selectedLabels = e.detail.selectedItems;
131+
this.requestUpdate('items');
132+
this.requestUpdate('filteredItems');
133+
this.requestUpdate('selectedLabels');
134+
}}"
77135
>
78-
${name} (${version})
79-
</mwc-list-item>`;
80-
})}
81-
</mwc-list>`;
136+
<span slot="icon">
137+
<mwc-icon>
138+
${this.labels.length != this.selectedLabels.length
139+
? 'label'
140+
: 'label_off'}
141+
</mwc-icon>
142+
</span>
143+
${this.labels.map(label => {
144+
return html` <mwc-check-list-item
145+
value="${label}"
146+
?selected="${this.selectedLabels.includes(label)}"
147+
>
148+
${label}
149+
</mwc-check-list-item>`;
150+
})}
151+
</oscd-filter-button>
152+
</div>
153+
${filteredItems && filteredItems.length > 0
154+
? html` <filtered-list>
155+
${filteredItems.map(item => {
156+
const id =
157+
item.getElementsByTagNameNS(SDS_NAMESPACE, 'Id').item(0)!
158+
.textContent ?? '';
159+
let name =
160+
item.getElementsByTagNameNS(SDS_NAMESPACE, 'Name').item(0)!
161+
.textContent ?? '';
162+
if (name === '') {
163+
name = id;
164+
}
165+
const version =
166+
item.getElementsByTagNameNS(SDS_NAMESPACE, 'Version').item(0)!
167+
.textContent ?? '';
168+
return html` <mwc-list-item
169+
tabindex="0"
170+
@click=${() => this.dispatchEvent(newSclSelectedEvent(id))}
171+
>
172+
${name} (${version})
173+
</mwc-list-item>`;
174+
})}
175+
</filtered-list>`
176+
: html` <mwc-list>
177+
<mwc-list-item>
178+
<i>${translate('compas.noFilteredScls')}</i>
179+
</mwc-list-item>
180+
</mwc-list>`}
181+
`;
82182
}
183+
184+
static styles = css`
185+
.filters {
186+
padding-left: var(--mdc-list-side-padding, 16px);
187+
display: flex;
188+
}
189+
190+
.filters > span {
191+
line-height: 48px;
192+
}
193+
`;
83194
}

src/menu/CompasCompareIED.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default class CompasCompareIEDPlugin extends CompareIEDPlugin {
1515
*/
1616
protected renderSelectTemplateFile(): TemplateResult {
1717
return html`<compas-open
18-
@docRetrieved=${(evt: DocRetrievedEvent) => {
18+
@doc-retrieved=${(evt: DocRetrievedEvent) => {
1919
this.templateDoc = evt.detail.doc;
2020
}}
2121
></compas-open>

0 commit comments

Comments
 (0)