Skip to content

Commit

Permalink
refactor(wizards/reportcontrol): change iedsPicker use filtered-list
Browse files Browse the repository at this point in the history
  • Loading branch information
JakobVogelsang committed Mar 30, 2022
1 parent 4009cd7 commit fd6b42d
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 63 deletions.
82 changes: 65 additions & 17 deletions src/wizards/reportcontrol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { get, translate } from 'lit-translate';

import '@material/mwc-button';
import '@material/mwc-list/mwc-list-item';
import '@material/mwc-list/mwc-check-list-item';
import { List } from '@material/mwc-list';
import { ListItemBase } from '@material/mwc-list/mwc-list-item-base';
import { SingleSelectedEvent } from '@material/mwc-list/mwc-list-foundation';
Expand Down Expand Up @@ -32,12 +33,9 @@ import {
WizardAction,
MenuAction,
} from '../foundation.js';
import { FilteredList } from '../filtered-list.js';
import { FinderList } from '../finder-list.js';
import {
dataAttributePicker,
iEDPicker,
iEDsPicker,
} from './foundation/finder.js';
import { dataAttributePicker, iEDPicker } from './foundation/finder.js';
import { maxLength, patterns } from './foundation/limits.js';
import { editDataSetWizard } from './dataset.js';
import { newFCDA } from './fcda.js';
Expand Down Expand Up @@ -409,17 +407,13 @@ function copyReportControlActions(element: Element): WizardActor {
return (_: WizardInputElement[], wizard: Element) => {
const doc = element.ownerDocument;

const finder = wizard.shadowRoot?.querySelector<FinderList>('finder-list');
const paths = finder?.paths ?? [];

if (paths.length === 0) return [];
const iedItems = <ListItemBase[]>(
wizard.shadowRoot?.querySelector<FilteredList>('filtered-list')?.selected
);

const complexActions: ComplexAction[] = [];
paths.forEach(path => {
const [tagName, id] = path.pop()!.split(': ');
if (tagName !== 'IED') return;

const ied = doc.querySelector(selector(tagName, id));
iedItems.forEach(iedItem => {
const ied = doc.querySelector(selector('IED', iedItem.value));
if (!ied) return;

const sinkLn0 = ied.querySelector('LN0');
Expand Down Expand Up @@ -468,9 +462,57 @@ function copyReportControlActions(element: Element): WizardActor {
};
}

export function reportControlCopyToIedSelector(element: Element): Wizard {
const doc = element.ownerDocument;
function renderIedListItem(sourceCb: Element, ied: Element): TemplateResult {
const sourceDataSet = sourceCb.parentElement?.querySelector(
`DataSet[name="${sourceCb.getAttribute('datSet')}"]`
);

const isSourceIed =
sourceCb.closest('IED')?.getAttribute('name') === ied.getAttribute('name');
const ln0 = ied.querySelector('AccessPoint > Server > LDevice > LN0');
const hasCbNameConflict = ln0?.querySelector(
`ReportControl[name="${sourceCb.getAttribute('name')}"]`
)
? true
: false;
const hasDataSetConflict = ln0?.querySelector(
`DataSet[name="${sourceDataSet?.getAttribute('name')}"]`
)
? true
: false;

// clone DataSet and make sure that FCDA is valid in ied
const sinkDataSet = <Element>sourceDataSet?.cloneNode(true);
Array.from(sinkDataSet.querySelectorAll('FCDA')).forEach(fcda => {
if (!existFcdaReference(fcda, ied)) sinkDataSet.removeChild(fcda);
});
const hasDataMatch = sinkDataSet.children.length > 0;

const primSpan = ied.getAttribute('name');
let secondSpan = '';
if (isSourceIed) secondSpan = 'Source IED';
else if (!ln0) secondSpan = 'Not a Server';
else if (hasDataSetConflict && !isSourceIed)
secondSpan = 'ReportControl already exist';
else if (hasCbNameConflict && !isSourceIed)
secondSpan = 'ReportControl already exist';
else if (!hasDataMatch) secondSpan = 'No matching data';
else secondSpan = 'Can be copied';

return html`<mwc-check-list-item
twoline
value="${identity(ied)}"
?disabled=${isSourceIed ||
!ln0 ||
hasCbNameConflict ||
hasDataSetConflict ||
!hasDataMatch}
><span>${primSpan}</span
><span slot="secondary">${secondSpan}</span></mwc-check-list-item
>`;
}

export function reportControlCopyToIedSelector(element: Element): Wizard {
return [
{
title: get('report.wizard.location'),
Expand All @@ -479,7 +521,13 @@ export function reportControlCopyToIedSelector(element: Element): Wizard {
label: get('save'),
action: copyReportControlActions(element),
},
content: [iEDsPicker(doc)],
content: [
html`<filtered-list multi
>${Array.from(element.ownerDocument.querySelectorAll('IED')).map(
ied => renderIedListItem(element, ied)
)}</filtered-list
>`,
],
},
];
}
Expand Down
83 changes: 55 additions & 28 deletions test/integration/wizards/reportcontrol-wizarding-editing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
selectReportControlWizard,
} from '../../../src/wizards/reportcontrol.js';
import { FinderList } from '../../../src/finder-list.js';
import { execPath } from 'process';
import { CheckListItem } from '@material/mwc-list/mwc-check-list-item';

describe('Wizards for SCL element ReportControl', () => {
let doc: XMLDocument;
Expand Down Expand Up @@ -349,7 +349,7 @@ describe('Wizards for SCL element ReportControl', () => {
await new Promise(resolve => setTimeout(resolve, 100)); // await animation

const iedsPicker =
element.wizardUI.dialog?.querySelector<FinderList>('finder-list');
element.wizardUI.dialog?.querySelector<FilteredList>('filtered-list');

expect(iedsPicker).to.exist;
expect(iedsPicker!.multi).to.be.true;
Expand Down Expand Up @@ -412,7 +412,8 @@ describe('Wizards for SCL element ReportControl', () => {
});

describe('defines a selector wizard to select ReportControl copy to sink', () => {
let iedsPicker: FinderList;
let iedsPicker: FilteredList;
let listItem: CheckListItem;

beforeEach(async () => {
const sourceReportControl = doc.querySelector(
Expand All @@ -422,8 +423,8 @@ describe('Wizards for SCL element ReportControl', () => {
element.workflow.push(() => wizard);
await element.requestUpdate();

iedsPicker = <FinderList>(
element.wizardUI.dialog?.querySelector('finder-list')
iedsPicker = <FilteredList>(
element.wizardUI.dialog?.querySelector('filtered-list')
);

primaryAction = <HTMLElement>(
Expand All @@ -438,53 +439,74 @@ describe('Wizards for SCL element ReportControl', () => {

describe('with a sink IED not meeting any of the data references', () => {
beforeEach(async () => {
iedsPicker.paths = [['IED: IED4']];
primaryAction.click();

listItem = <CheckListItem>(
iedsPicker.items.find(item => item.value.includes('IED4'))!
);
await element.requestUpdate();
});

it('does not copy the control block ', () =>
expect(doc.querySelector('IED[name="IED4"] ReportControl')).to.not
.exist);
it('disables the list item', () => expect(listItem.disabled).to.be.true);

it('does not close the wizard', async () =>
expect(element.wizardUI.dialog).to.exist);
it('does not copy the control block ', async () => {
listItem.selected = true;
await listItem.requestUpdate();
primaryAction.click();
expect(doc.querySelector('IED[name="IED4"] ReportControl')).to.not
.exist;
});
});

describe('with a sink IED not meeting partially the data references', () => {
describe('with a sink IED meeting partially the data references', () => {
beforeEach(async () => {
iedsPicker.paths = [['IED: IED5']];
primaryAction.click();
listItem = <CheckListItem>(
iedsPicker.items.find(item => item.value.includes('IED5'))!
);

await element.requestUpdate();
await listItem.requestUpdate();
});

it('list item is selectable', () =>
expect(listItem.disabled).to.be.false);

it('does copy the control block ', async () => {
listItem.selected = true;
await listItem.requestUpdate();
primaryAction.click();

expect(doc.querySelector('IED[name="IED5"] ReportControl')).to.exist;
});

it('does copy the control block ', () =>
expect(doc.querySelector('IED[name="IED5"] ReportControl')).to.exist);
it('removes non referenced data from the DataSet the control block ', async () => {
listItem.selected = true;
await listItem.requestUpdate();
primaryAction.click();

it('removes non referenced data from the DataSet the control block ', () => {
const rpControl = doc.querySelector('IED[name="IED5"] ReportControl')!;
const dataSet = doc.querySelector(
`IED[name="IED5"] DataSet[name="${rpControl.getAttribute('datSet')}"]`
);
expect(dataSet).to.exist;
expect(dataSet!.children).to.have.lengthOf(2);
});

it('does close the wizard', () =>
expect(element.wizardUI.dialog).to.not.exist);
});

describe('with a sink IED already containing ReportControl', () => {
beforeEach(async () => {
iedsPicker.paths = [['IED: IED6']];
primaryAction.click();
listItem = <CheckListItem>(
iedsPicker.items.find(item => item.value.includes('IED4'))!
);

await element.requestUpdate();
});

it('does not copy report control block nor DataSet ', () => {
it('list item is disabled', () => expect(listItem.disabled).to.be.true);

it('does not copy report control block nor DataSet ', async () => {
listItem.selected = true;
await listItem.requestUpdate();
primaryAction.click();

const rpControl = doc.querySelector('IED[name="IED6"] ReportControl')!;
expect(rpControl.getAttribute('datSet')).to.not.exist;

Expand All @@ -495,13 +517,18 @@ describe('Wizards for SCL element ReportControl', () => {

describe('with a sink IED already containing DataSet', () => {
beforeEach(async () => {
iedsPicker.paths = [['IED: IED7']];
primaryAction.click();
listItem = <CheckListItem>(
iedsPicker.items.find(item => item.value.includes('IED7'))!
);

await element.requestUpdate();
});

it('does not copy report control block nor DataSet ', () => {
it('does not copy report control block nor DataSet ', async () => {
listItem.selected = true;
await listItem.requestUpdate();
primaryAction.click();

const rpControl = doc.querySelector('IED[name="IED7"] ReportControl')!;
expect(rpControl).to.not.exist;

Expand Down
Loading

0 comments on commit fd6b42d

Please sign in to comment.