Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 13 commits into from
Sep 25, 2023
Merged
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
Loading