Skip to content

Commit 34db746

Browse files
author
Dennis Labordus
authored
Merge pull request #205 from com-pas/updating-v0.26.0
Merging v0.26.0 from OpenSCD into CoMPAS
2 parents d714f45 + f0abb3f commit 34db746

File tree

51 files changed

+1874
-442
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1874
-442
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
44

5+
## [0.26.0](https://github.com/openscd/open-scd/compare/v0.25.0...v0.26.0) (2022-11-03)
6+
7+
8+
### Features
9+
10+
* **editor/substation:** read-only editor for SubEquipment element ([#1030](https://github.com/openscd/open-scd/issues/1030)) ([f6e96b5](https://github.com/openscd/open-scd/commits/f6e96b5d2bbb5014b4951299e55ae1462b9b1c33))
11+
* **editors/subscriber/later-binding:** add input requirement check ([#1049](https://github.com/openscd/open-scd/issues/1049)) ([26f7fe5](https://github.com/openscd/open-scd/commits/26f7fe56ecbc216495ddb747e75fb28d002f9447))
12+
13+
14+
### Bug Fixes
15+
16+
* **Editing:** set false attribute values on update ([#899](https://github.com/openscd/open-scd/issues/899)) ([0b414e1](https://github.com/openscd/open-scd/commits/0b414e1687f9a796e7ec161237ad1ab78f04e87e))
17+
* **editor/subscriber:** filtering on FCDAs retains the parent ([#1048](https://github.com/openscd/open-scd/issues/1048)) ([d5f8bb7](https://github.com/openscd/open-scd/commits/d5f8bb7ed8ceeb9c2ca14a91d3624afda7a43513))
18+
* **Logging:** broken toggle button styling ([81da900](https://github.com/openscd/open-scd/commits/81da900c5d3850143961c23e197e19fb2cb02ad1))
19+
* **validate-schema:** cache validator workers ([#901](https://github.com/openscd/open-scd/issues/901)) ([2de7d26](https://github.com/openscd/open-scd/commits/2de7d269b15012af84927de90689e95ca901d05a))
20+
521
## [0.25.0](https://github.com/openscd/open-scd/compare/v0.24.0...v0.25.0) (2022-10-17)
622

723

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,5 @@
4040
"purpose": "maskable"
4141
}
4242
],
43-
"version": "0.25.0"
43+
"version": "0.26.0"
4444
}

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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "open-scd",
3-
"version": "0.25.0",
3+
"version": "0.26.0",
44
"repository": "https://github.com/openscd/open-scd.git",
55
"description": "A bottom-up substation configuration designer for projects described using SCL `IEC 61850-6` Edition 2 or greater.",
66
"keywords": [

src/Editing.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ export function Editing<TBase extends LitElementConstructor>(Base: TBase) {
382382
);
383383

384384
Object.entries(action.newAttributes).forEach(([key, value]) => {
385-
if (value) action.element.setAttribute(key, value);
385+
if (value !== null && value !== undefined)
386+
action.element.setAttribute(key, value);
386387
});
387388

388389
return true;

src/Logging.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,22 @@ export function Logging<TBase extends LitElementConstructor>(Base: TBase) {
349349
display: flex;
350350
}
351351
352+
#infofilter[on] {
353+
color: var(--cyan);
354+
}
355+
356+
#warningfilter[on] {
357+
color: var(--yellow);
358+
}
359+
360+
#errorfilter[on] {
361+
color: var(--red);
362+
}
363+
364+
#actionfilter[on] {
365+
color: var(--blue);
366+
}
367+
352368
#log {
353369
--mdc-dialog-min-width: 92vw;
354370
}

src/editors/cleanup/control-blocks-container.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import '@material/mwc-checkbox';
2222
import { Button } from '@material/mwc-button';
2323
import { Checkbox } from '@material/mwc-checkbox';
2424
import { List, MWCListIndex } from '@material/mwc-list';
25+
import { ListItem } from '@material/mwc-list/mwc-list-item.js';
2526

2627
import '../../filtered-list.js';
2728

@@ -96,7 +97,7 @@ export class CleanupControlBlocks extends LitElement {
9697
cleanupList: List | undefined;
9798

9899
@queryAll('mwc-check-list-item.cleanupListItem')
99-
cleanupListItems: NodeList | undefined;
100+
cleanupListItems: ListItem[] | undefined;
100101

101102
@query('.cleanupAddressCheckbox')
102103
cleanupAddressCheckbox: Checkbox | undefined;
@@ -266,6 +267,9 @@ export class CleanupControlBlocks extends LitElement {
266267
gseSmvLogReportDeleteActions.forEach(deleteAction =>
267268
e.target?.dispatchEvent(newActionEvent(deleteAction))
268269
);
270+
this.cleanupListItems!.forEach((item) => {
271+
item.selected = false;
272+
});
269273
}}
270274
></mwc-button>`;
271275
}

src/editors/cleanup/datasets-container.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ export class CleanupDatasets extends LitElement {
127127
deleteActions.forEach(deleteAction =>
128128
e.target?.dispatchEvent(newActionEvent(deleteAction))
129129
);
130+
this.dataSetItems!.forEach((item) => {
131+
item.selected = false;
132+
});
130133
}}
131134
></mwc-button>`;
132135
}

src/editors/cleanup/datatypes-container.ts

Lines changed: 95 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
queryAll,
1212
} from 'lit-element';
1313
import { classMap } from 'lit-html/directives/class-map';
14-
import { translate } from 'lit-translate';
14+
import { get, translate } from 'lit-translate';
1515

1616
import '@material/mwc-button';
1717
import '@material/mwc-icon';
@@ -22,12 +22,14 @@ import '@material/mwc-checkbox';
2222
import { Button } from '@material/mwc-button';
2323
import { Checkbox } from '@material/mwc-checkbox';
2424
import { List, MWCListIndex } from '@material/mwc-list';
25+
import { ListItem } from '@material/mwc-list/mwc-list-item.js';
2526

2627
import '../../filtered-list.js';
2728

2829
import {
2930
identity,
3031
isPublic,
32+
newLogEvent,
3133
newSubWizardEvent,
3234
newActionEvent,
3335
} from '../../foundation.js';
@@ -84,7 +86,7 @@ export class CleanupDataTypes extends LitElement {
8486
cleanupList: List | undefined;
8587

8688
@queryAll('mwc-check-list-item.cleanup-list-item')
87-
cleanupListItems: NodeList | undefined;
89+
cleanupListItems: ListItem[] | undefined;
8890

8991
@query('.clean-sub-types-checkbox')
9092
cleanSubTypesCheckbox: Checkbox | undefined;
@@ -222,23 +224,20 @@ export class CleanupDataTypes extends LitElement {
222224

223225
/**
224226
* Recurses through all datatype templates and indexes their usage.
225-
* @returns a map of data type templates usage.
227+
* @returns a map of data type templates usage by id.
226228
*/
227-
private indexDataTypeTemplates() {
228-
const dataTypeTemplates = this.doc.querySelector(
229-
':root > DataTypeTemplates'
230-
)!;
231-
const allUsages = this.fetchTree(dataTypeTemplates);
229+
private indexDataTypeTemplates(dttStart: Element[]) {
232230
const dataTypeFrequencyUsage = new Map<string, number>();
231+
232+
// recursively fetch all usages
233+
const allUsages = this.fetchTree(dttStart);
234+
233235
// make frequency count of datatype ids
234236
allUsages.forEach(item => {
235-
const itemType = item!.getAttribute('id');
236-
if (itemType !== null) {
237-
dataTypeFrequencyUsage.set(
238-
itemType!,
239-
(dataTypeFrequencyUsage.get(itemType!) || 0) + 1
240-
);
241-
}
237+
dataTypeFrequencyUsage.set(
238+
item,
239+
(dataTypeFrequencyUsage.get(item) || 0) + 1
240+
);
242241
});
243242
return dataTypeFrequencyUsage;
244243
}
@@ -248,16 +247,22 @@ export class CleanupDataTypes extends LitElement {
248247
* @param element - the SCL Element for which a datatype is required.
249248
* @returns either the datatype or null.
250249
*/
251-
private getSubTypes(element: Element): Element | null {
250+
private getSubType(element: Element): Element | null {
252251
const dataTypeTemplates = this.doc.querySelector(
253252
':root > DataTypeTemplates'
254253
);
255254
const type = element.getAttribute('type');
256255
if (element.tagName === 'DO' || element.tagName === 'SDO') {
257256
return dataTypeTemplates!.querySelector(`DOType[id="${type}"]`);
258-
} else if ((element.tagName === 'DA' || element.tagName === 'BDA') && element.getAttribute('bType') === 'Struct') {
257+
} else if (
258+
(element.tagName === 'DA' || element.tagName === 'BDA') &&
259+
element.getAttribute('bType') === 'Struct'
260+
) {
259261
return dataTypeTemplates!.querySelector(`DAType[id="${type}"]`);
260-
} else if ((element.tagName === 'DA' || element.tagName === 'BDA') && element.getAttribute('bType') === 'Enum') {
262+
} else if (
263+
(element.tagName === 'DA' || element.tagName === 'BDA') &&
264+
element.getAttribute('bType') === 'Enum'
265+
) {
261266
return dataTypeTemplates!.querySelector(`EnumType[id="${type}"]`);
262267
}
263268
return null;
@@ -266,29 +271,43 @@ export class CleanupDataTypes extends LitElement {
266271
/**
267272
* Recurses from an initial element to find all child references (with duplicates).
268273
* @param rootElement - root SCL Element for which all child datatype references are required.
269-
* @returns all SCL element datatypes traversed.
274+
* @returns the id value for all SCL element datatypes traversed.
270275
*/
271-
private fetchTree(rootElement: Element): (Element | undefined)[] {
272-
const elementStack = [rootElement];
273-
const traversedElements: (Element | undefined)[] = [];
276+
private fetchTree(rootElements: Element[]): string[] {
277+
const elementStack = [...rootElements];
278+
const traversedElements: string[] = [];
274279

275280
// A max stack depth is defined to avoid recursive references.
276-
const MAX_STACK_DEPTH = 10000;
277-
while (elementStack.length > 0 && elementStack.length < MAX_STACK_DEPTH) {
281+
const MAX_STACK_DEPTH = 300000;
282+
283+
while (elementStack.length > 0 && elementStack.length <= MAX_STACK_DEPTH) {
278284
const currentElement = elementStack.pop();
279-
traversedElements.push(currentElement);
285+
traversedElements.push(currentElement!.getAttribute('id')!);
286+
287+
const selector = 'DO, SDO, DA, BDA';
280288

281-
Array.from(currentElement!.querySelectorAll('DO, SDO, DA, BDA'))
289+
Array.from(currentElement!.querySelectorAll(selector))
282290
.filter(isPublic)
283291
.forEach(element => {
284-
const newElements = this.getSubTypes(element);
285-
if (newElements !== null) {
286-
elementStack.unshift(newElements);
292+
const newElement = this.getSubType(element);
293+
if (newElement !== null) {
294+
elementStack.unshift(newElement);
287295
}
288296
});
297+
298+
if (elementStack.length >= MAX_STACK_DEPTH) {
299+
this.dispatchEvent(
300+
newLogEvent({
301+
kind: 'error',
302+
title: get('cleanup.unreferencedDataTypes.title'),
303+
message: get('cleanup.unreferencedDataTypes.stackExceeded', {
304+
maxStackDepth: MAX_STACK_DEPTH.toString(),
305+
}),
306+
})
307+
);
308+
}
289309
}
290-
// remove root element - it is not a datatype itself
291-
traversedElements.shift();
310+
292311
return traversedElements;
293312
}
294313

@@ -305,26 +324,47 @@ export class CleanupDataTypes extends LitElement {
305324
const dataTypeTemplates = this.doc.querySelector(
306325
':root > DataTypeTemplates'
307326
)!;
308-
const dataTypeUsageCounter = this.indexDataTypeTemplates();
309327

310-
// update index to allow checking for no longer used DataTypeTemplates
328+
const startingLNodeTypes = Array.from(
329+
dataTypeTemplates.querySelectorAll('LNodeType')
330+
);
331+
const dataTypeUsageCounter =
332+
this.indexDataTypeTemplates(startingLNodeTypes);
333+
334+
/* Create usage counter for children of LNodeTypes that are used.
335+
We remember that _all_ valid template usages within a project
336+
stem from LNodeTypes. */
311337
cleanItems.forEach(item => {
312-
const childDataTypeTemplates = this.fetchTree(item);
313-
childDataTypeTemplates.forEach(element => {
314-
const type = element!.getAttribute('id')!;
315-
if (dataTypeUsageCounter!.has(type)) {
316-
dataTypeUsageCounter?.set(
317-
type,
318-
dataTypeUsageCounter.get(type)! - 1
319-
);
320-
}
321-
});
338+
if (item.tagName === 'LNodeType') {
339+
const childDataTypeTemplateIds = this.fetchTree([item]);
340+
childDataTypeTemplateIds.forEach(id => {
341+
dataTypeUsageCounter?.set(id, dataTypeUsageCounter.get(id)! - 1);
342+
});
343+
}
322344
});
323345

324-
// locate from index consequentially unused DataTypeTemplates
325-
// and add to items to be removed
346+
/* Check to see if children of unused DOType, DAType are present
347+
If so then unless they are from a data type which is part of
348+
the main usage counter they can be safely removed.
349+
If they are part of the main usage counter, then this does not
350+
need to be considered as these DOType and DAType elements are
351+
dangling, they're usage is not relevant. */
352+
cleanItems.forEach(item => {
353+
if (['DOType', 'DAType'].includes(item.tagName)) {
354+
const unusedDataTypeTemplateChildrenIds = uniq(
355+
this.fetchTree([item])
356+
);
357+
unusedDataTypeTemplateChildrenIds.forEach(id => {
358+
if (dataTypeUsageCounter.get(<string>id) === undefined)
359+
cleanItems.push(dataTypeTemplates.querySelector(`[id="${id}"]`)!);
360+
});
361+
}
362+
});
363+
364+
/* Now go through our usage index. If usage is zero then we can
365+
remove the data type template safely. */
326366
dataTypeUsageCounter?.forEach((count, dataTypeId) => {
327-
if (count === 0) {
367+
if (count <= 0) {
328368
cleanItems.push(
329369
dataTypeTemplates.querySelector(`[id="${dataTypeId}"]`)!
330370
);
@@ -354,6 +394,9 @@ export class CleanupDataTypes extends LitElement {
354394
dataTypeItemsDeleteActions.forEach(deleteAction =>
355395
this.dispatchEvent(newActionEvent(deleteAction))
356396
);
397+
this.cleanupListItems!.forEach((item) => {
398+
item.selected = false;
399+
});
357400
}}
358401
></mwc-button>`;
359402
}
@@ -532,18 +575,18 @@ export class CleanupDataTypes extends LitElement {
532575
opacity: 1;
533576
}
534577
578+
/* Make sure to type filter here
579+
.hidden is set on string filter in filtered-list and must always filter*/
580+
.cleanup-list-item.hiddenontypefilter:not(.hidden) {
581+
display: none;
582+
}
583+
535584
/* filter disabled, Material Design guidelines for opacity */
536585
.t-da-type-filter,
537586
.t-enum-type-filter,
538587
.t-lnode-type-filter,
539588
.t-do-type-filter {
540589
opacity: 0.38;
541590
}
542-
543-
/* Make sure to type filter here
544-
.hidden is set on string filter in filtered-list and must always filter*/
545-
.cleanupListItem.hiddenontypefilter:not(.hidden) {
546-
display: none;
547-
}
548591
`;
549592
}

0 commit comments

Comments
 (0)