Skip to content

Commit

Permalink
feat(editors/ied): Improve IED editor UI for IED and LN selection (#1288
Browse files Browse the repository at this point in the history
)

feat(editors/ied): Improve IED editor UI for IED and LN selection, closes #1287

---------

Co-authored-by: Tamás Russ <[email protected]>
  • Loading branch information
danyill and Tamás Russ authored Sep 25, 2023
1 parent 2ae1cd3 commit e5bc0b8
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 29 deletions.
66 changes: 55 additions & 11 deletions packages/open-scd/src/editors/IED.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default class IedPlugin extends LitElement {
/** The document being edited as provided to plugins by [[`OpenSCD`]]. */
@property()
doc!: XMLDocument;

@property({ type: Number })
editCount = -1;

Expand Down Expand Up @@ -69,6 +70,12 @@ export default class IedPlugin extends LitElement {
uniqueLNClassList.push(lnClass);
return true;
})
.sort((a, b) => {
const aLnClass = a.getAttribute('lnClass') ?? '';
const bLnClass = b.getAttribute('lnClass') ?? '';

return aLnClass.localeCompare(bLnClass);
})
.map(element => {
const lnClass = element.getAttribute('lnClass');
const label = this.nsdoc.getDataDescription(element).label;
Expand All @@ -92,17 +99,28 @@ export default class IedPlugin extends LitElement {
return undefined;
}

lNClassListOpenedOnce = false;

protected updated(_changedProperties: PropertyValues): void {
super.updated(_changedProperties);

// When the document is updated, we reset the selected IED.
if (
// When the document is updated, we reset the selected IED if it no longer exists
const isDocumentUpdated =
_changedProperties.has('doc') ||
_changedProperties.has('editCount') ||
_changedProperties.has('nsdoc')
) {
_changedProperties.has('nsdoc');

if (isDocumentUpdated) {
// if the IED exists, retain selection
const iedExists = this.doc?.querySelector(
`IED[name="${this.selectedIEDs[0]}"]`
);

if (iedExists) return;

this.selectedIEDs = [];
this.selectedLNClasses = [];
this.lNClassListOpenedOnce = false;

const iedList = this.iedList;
if (iedList.length > 0) {
Expand All @@ -111,12 +129,22 @@ export default class IedPlugin extends LitElement {
this.selectedIEDs = [iedName];
}
}
this.selectedLNClasses = this.lnClassList.map(
lnClassInfo => lnClassInfo[0]
);
}
}

private calcSelectedLNClasses(): string[] {
const somethingSelected = this.selectedLNClasses.length > 0;
const lnClasses = this.lnClassList.map( lnClassInfo => lnClassInfo[0] );

let selectedLNClasses = lnClasses;

if(somethingSelected){
selectedLNClasses = lnClasses.filter( lnClass => this.selectedLNClasses.includes(lnClass));
}

return selectedLNClasses;
}

render(): TemplateResult {
const iedList = this.iedList;
if (iedList.length > 0) {
Expand All @@ -129,10 +157,25 @@ export default class IedPlugin extends LitElement {
icon="developer_board"
.header=${translate('iededitor.iedSelector')}
@selected-items-changed="${(e: SelectedItemsChangedEvent) => {
this.selectedIEDs = e.detail.selectedItems;
this.selectedLNClasses = this.lnClassList.map(
lnClassInfo => lnClassInfo[0]
const equalArrays = <T>(first: T[], second: T[]): boolean => {
return (
first.length === second.length &&
first.every((val, index) => val === second[index])
);
};
const selectionChanged = !equalArrays(
this.selectedIEDs,
e.detail.selectedItems
);
if (!selectionChanged) {
return;
}
this.lNClassListOpenedOnce = false;
this.selectedIEDs = e.detail.selectedItems;
this.selectedLNClasses = [];
this.requestUpdate('selectedIed');
}}"
>
Expand Down Expand Up @@ -160,6 +203,7 @@ export default class IedPlugin extends LitElement {
multi="true"
.header="${translate('iededitor.lnFilter')}"
@selected-items-changed="${(e: SelectedItemsChangedEvent) => {
this.selectedLNClasses = e.detail.selectedItems;
this.requestUpdate('selectedIed');
}}"
Expand All @@ -184,7 +228,7 @@ export default class IedPlugin extends LitElement {
.editCount=${this.editCount}
.doc=${this.doc}
.element=${this.selectedIed}
.selectedLNClasses=${this.selectedLNClasses}
.selectedLNClasses=${this.calcSelectedLNClasses()}
.nsdoc=${this.nsdoc}
></ied-container>
</section>`;
Expand Down
58 changes: 55 additions & 3 deletions packages/open-scd/test/integration/editors/IED.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,66 @@ describe('IED Plugin', () => {
).length
).to.eql(5);

await deselectLNClasses('CSWI');
await selectLNClasses('CSWI');
await new Promise(resolve => setTimeout(resolve, 100)); // await animation

expect(
getLDeviceContainer(getIedContainer()).shadowRoot!.querySelectorAll(
'ln-container'
).length
).to.eql(3);
).to.eql(2);
});

it('when other IED selected, all LNs are selected by default', async () => {
await selectLNClasses('XCBR');

await selectIed('IED3');
await new Promise(resolve => setTimeout(resolve, 100)); // await animation

expect(
element.shadowRoot?.querySelectorAll('ied-container').length
).to.eql(1);
expect(
getIedContainer().shadowRoot?.querySelector('action-pane')!.shadowRoot
?.innerHTML
).to.include('IED3');

expect(
getLDeviceContainer(getIedContainer()).shadowRoot!.querySelectorAll(
'ln-container'
).length
).to.eql(9);
});

it('when filtering LNs, if none are selected, all are selected', async () => {
await selectIed('IED3');

const oscdFilterButton = <FilterButton>(
element.shadowRoot!.querySelector(
'oscd-filter-button[id="lnClassesFilter"]'
)
);
const filterButton = <LitElement>(
oscdFilterButton!.shadowRoot!.querySelector('mwc-icon-button')
);
filterButton.click();
await element.updateComplete;

const primaryButton = <HTMLElement>(
oscdFilterButton!.shadowRoot!.querySelector(
'mwc-button[slot="primaryAction"]'
)
);
primaryButton.click();
await element.updateComplete;

await new Promise(resolve => setTimeout(resolve, 100)); // await animation

expect(
getLDeviceContainer(getIedContainer()).shadowRoot!.querySelectorAll(
'ln-container'
).length
).to.eql(9);
});

it('then renders the path of elements correctly', async () => {
Expand Down Expand Up @@ -277,7 +329,7 @@ describe('IED Plugin', () => {
);
}

async function deselectLNClasses(lnClass: string): Promise<void> {
async function selectLNClasses(lnClass: string): Promise<void> {
const oscdFilterButton = <FilterButton>(
element.shadowRoot!.querySelector(
'oscd-filter-button[id="lnClassesFilter"]'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,51 +116,46 @@ snapshots["IED Plugin with a doc loaded containing IEDs looks like the latest sn
aria-disabled="false"
graphic="control"
mwc-list-item=""
selected=""
tabindex="0"
value="LLN0"
value="CILO"
>
LLN0
CILO
</mwc-check-list-item>
<mwc-check-list-item
aria-disabled="false"
graphic="control"
mwc-list-item=""
selected=""
tabindex="-1"
value="XCBR"
value="CSWI"
>
XCBR
CSWI
</mwc-check-list-item>
<mwc-check-list-item
aria-disabled="false"
graphic="control"
mwc-list-item=""
selected=""
tabindex="-1"
value="CSWI"
value="LLN0"
>
CSWI
LLN0
</mwc-check-list-item>
<mwc-check-list-item
aria-disabled="false"
graphic="control"
mwc-list-item=""
selected=""
tabindex="-1"
value="XSWI"
value="XCBR"
>
XSWI
XCBR
</mwc-check-list-item>
<mwc-check-list-item
aria-disabled="false"
graphic="control"
mwc-list-item=""
selected=""
tabindex="-1"
value="CILO"
value="XSWI"
>
CILO
XSWI
</mwc-check-list-item>
</oscd-filter-button>
<element-path class="elementPath">
Expand Down

0 comments on commit e5bc0b8

Please sign in to comment.