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

refactor(ied-editor): use action-icon #418

Merged
merged 1 commit into from
Dec 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 25 additions & 136 deletions src/zeroline/ied-editor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
css,
customElement,
html,
LitElement,
Expand All @@ -12,165 +11,55 @@ import '@material/mwc-fab';
import '@material/mwc-icon';
import { Fab } from '@material/mwc-fab';

import '../action-icon.js';
import { createClientLnWizard } from '../wizards/clientln.js';
import { gooseIcon } from '../icons.js';
import { newWizardEvent } from '../foundation.js';
import { selectGseControlWizard } from '../wizards/gsecontrol.js';

/** [[`SubstationEditor`]] subeditor for a `ConductingEquipment` element. */
/** [[`SubstationEditor`]] subeditor for a child-less `IED` element. */
@customElement('ied-editor')
export class IedEditor extends LitElement {
@property({ type: Element })
/** SCL element IED */
@property({ attribute: false })
element!: Element;

/** IED name attribute */
@property({ type: String })
get name(): string {
return this.element.getAttribute('name') ?? '';
return this.element.getAttribute('name') ?? 'UNDEFINED';
}

@query('#connectreport') connectReport!: Fab;
@query('.connectreport') connectReport!: Fab;

openCommunicationMapping(): void {
private openCommunicationMapping(): void {
const sendingIeds = Array.from(
this.element.closest('SCL')?.querySelectorAll('IED') ?? []
);
const wizard = createClientLnWizard(sendingIeds, this.element);
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
}

openGseControlSelection(): void {
private openGseControlSelection(): void {
const wizard = selectGseControlWizard(this.element);
if (wizard) this.dispatchEvent(newWizardEvent(wizard));
}

render(): TemplateResult {
return html`
<div id="container" tabindex="0">
<abbr title="${this.name}">
<mwc-icon class="icon">developer_board</mwc-icon></abbr
>
<mwc-fab
id="connectreport"
mini
class="menu-item right"
@click="${() => this.openCommunicationMapping()}"
icon="add_link"
></mwc-fab>
<mwc-fab
id="connectreport"
mini
class="menu-item left"
@click="${() => this.openGseControlSelection()}"
><mwc-icon slot="icon">${gooseIcon}</mwc-icon></mwc-fab
>
</div>
<h4>${this.name}</h4>
`;
return html`<action-icon label="${this.name}" icon="developer_board"
><mwc-fab
slot="action"
class="connectreport"
mini
@click="${() => this.openCommunicationMapping()}"
icon="add_link"
></mwc-fab>
<mwc-fab
slot="action"
class="selectgse"
mini
@click="${() => this.openGseControlSelection()}"
><mwc-icon slot="icon">${gooseIcon}</mwc-icon></mwc-fab
></action-icon
> `;
}

static styles = css`
#container {
color: var(--mdc-theme-on-surface);
width: 50px;
height: 50px;
margin: auto;
position: relative;
transition: all 200ms linear;
user-select: none;
}

#container:focus {
outline: none;
}

.icon {
color: var(--mdc-theme-on-surface);
--mdc-icon-size: 50px;
transition: transform 150ms linear, box-shadow 200ms linear;
outline-color: var(--mdc-theme-primary);
outline-style: solid;
outline-width: 0px;
}

#container > .icon {
color: var(--mdc-theme-on-surface);
width: 50px;
height: 50px;
transition: transform 150ms linear, box-shadow 200ms linear;
outline-color: var(--mdc-theme-primary);
outline-style: solid;
outline-width: 0px;
}

#container:focus > .icon {
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);
}

#container:hover > .icon {
outline: 2px dashed var(--mdc-theme-primary);
transition: transform 200ms linear, box-shadow 250ms linear;
}

#container:focus-within > .icon {
outline: 2px solid var(--mdc-theme-primary);
background: var(--mdc-theme-on-primary);
transform: scale(0.8);
transition: transform 200ms linear, box-shadow 250ms linear;
}

.menu-item {
color: var(--mdc-theme-on-surface);
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 200ms linear;
position: absolute;
top: 2px;
left: 2px;
pointer-events: none;
z-index: 1;
opacity: 0;
}

#container:focus-within > .menu-item {
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 250ms linear;
pointer-events: auto;
opacity: 1;
}

#container:focus-within > .menu-item.up {
transform: translate(0px, -60px);
}

#container:focus-within > .menu-item.down {
transform: translate(0px, 60px);
}

#container:focus-within > .menu-item.right {
transform: translate(60px, 0px);
}

#container:focus-within > .menu-item.left {
transform: translate(-60px, 0px);
}

h4 {
color: var(--mdc-theme-on-surface);
font-family: 'Roboto', sans-serif;
font-weight: 300;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 0px;
opacity: 1;
transition: opacity 200ms linear;
text-align: center;
direction: rtl;
}

:host(.moving) #container,
:host(.moving) h4 {
opacity: 0.3;
}
`;
}
28 changes: 28 additions & 0 deletions test/unit/zeroline/__snapshots__/ied-editor.test.snap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["A component to visualize SCL element IED looks like the latest snapshot"] =
`<action-icon
icon="developer_board"
label="IED1"
tabindex="0"
>
<mwc-fab
class="connectreport"
icon="add_link"
mini=""
slot="action"
>
</mwc-fab>
<mwc-fab
class="selectgse"
mini=""
slot="action"
>
<mwc-icon slot="icon">
</mwc-icon>
</mwc-fab>
</action-icon>
`;
/* end snapshot A component to visualize SCL element IED looks like the latest snapshot */

82 changes: 82 additions & 0 deletions test/unit/zeroline/ied-editor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { fixture, html, expect } from '@open-wc/testing';
import { SinonSpy, spy } from 'sinon';

import '../../../src/zeroline/ied-editor.js';
import { IedEditor } from '../../../src/zeroline/ied-editor.js';

describe('A component to visualize SCL element IED', () => {
let element: IedEditor;
let validSCL: XMLDocument;

let wizardEvent: SinonSpy;

beforeEach(async () => {
validSCL = await fetch('/test/testfiles/valid2007B4.scd')
.then(response => response.text())
.then(str => new DOMParser().parseFromString(str, 'application/xml'));

element = <IedEditor>(
await fixture(
html`<ied-editor
.element=${validSCL.querySelector('IED')}
></ied-editor>`
)
);

wizardEvent = spy();
window.addEventListener('wizard', wizardEvent);
});

it('looks like the latest snapshot', async () => {
await expect(element).shadowDom.to.equalSnapshot();
});

it('renders label UNDEFINED in case IED name attribute is missing', async () => {
const condEq = validSCL.querySelector('IED');
condEq?.removeAttribute('name');
await element.requestUpdate();

expect(element).to.have.property('name', 'UNDEFINED');
});

it('triggers select wizard for GSEControl element on action button click', async () => {
(<HTMLElement>(
element.shadowRoot?.querySelector('mwc-fab[class="selectgse"]')
)).click();

await element.requestUpdate();

expect(wizardEvent).to.have.be.calledOnce;
expect(wizardEvent.args[0][0].detail.wizard[0].title).to.contain('select');
});

it('triggers create wizard for ClientLN element on action button click', async () => {
(<HTMLElement>(
element.shadowRoot?.querySelector('mwc-fab[class="connectreport"]')
)).click();

await element.requestUpdate();

expect(wizardEvent).to.have.be.calledOnce;
expect(wizardEvent.args[0][0].detail.wizard[0].title).to.contain(
'connectToIED'
);
});

it('still triggers create wizard for ClientLN element with missing parent', async () => {
const copyElement: Element = <Element>element.cloneNode(true);
element.element = copyElement;
await element.requestUpdate();

(<HTMLElement>(
element.shadowRoot?.querySelector('mwc-fab[class="connectreport"]')
)).click();

await element.requestUpdate();

expect(wizardEvent).to.have.been.calledOnce;
expect(wizardEvent.args[0][0].detail.wizard[0].title).to.contain(
'connectToIED'
);
});
});