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/substation): add read-only l-node-editor #730

Merged
merged 14 commits into from
May 17, 2022
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
40 changes: 29 additions & 11 deletions src/action-icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export class ActionIcon extends LitElement {
/** highlight pane with dotted outline */
@property({ type: Boolean })
highlighted = false;
/** disables CSS adoption to action buttons */
@property({ type: Boolean })
hideActions = false;

async firstUpdated(): Promise<void> {
this.tabIndex = 0;
Expand Down Expand Up @@ -75,16 +78,6 @@ export class ActionIcon extends LitElement {
--mdc-icon-size: 64px;
}

:host(:focus-within) ::slotted([slot='icon']),
:host(:focus-within) mwc-icon {
outline-style: solid;
outline-width: 4px;
transform: scale(0.8);
transition: all 250ms linear;
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);
}

:host([secondary]) ::slotted([slot='icon']),
:host([secondary]) mwc-icon {
outline-color: var(--mdc-theme-secondary);
Expand All @@ -96,6 +89,20 @@ export class ActionIcon extends LitElement {
outline-width: 2px;
}

:host(:focus-within) ::slotted([slot='icon']),
:host(:focus-within) mwc-icon {
outline-style: solid;
outline-width: 4px;
}

:host(:focus-within:not([hideActions])) ::slotted([slot='icon']),
:host(:focus-within:not([hideActions])) mwc-icon {
transform: scale(0.8);
transition: all 250ms linear;
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);
}

::slotted([slot='icon']:hover),
mwc-icon:hover {
outline-style: dashed;
Expand Down Expand Up @@ -178,6 +185,10 @@ export class ActionIcon extends LitElement {
opacity 200ms linear;
}

:host([secondary]) header {
background-color: var(--mdc-theme-secondary);
}

:host(:hover) header {
position: absolute;
opacity: 1;
Expand All @@ -191,11 +202,18 @@ export class ActionIcon extends LitElement {
:host(:focus-within) header {
position: absolute;
opacity: 1;
transform: translate(0, -80px);
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);
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 250ms linear;
}

:host(:focus-within:not([hideActions])) header {
transform: translate(0, -80px);
}

:host(:focus-within[hideActions]) header {
transform: translate(0, -40px);
}
`;
}
16 changes: 15 additions & 1 deletion src/editors/substation/bay-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ export class BayEditor extends LitElement {
this.addMenu.anchor = <HTMLElement>this.addButton;
}

private renderLNodes(): TemplateResult {
if (!this.showfunctions) return html``;

const lNodes = getChildElementsByTagName(this.element, 'LNode');

return lNodes.length
? html`<div class="container lnode">
${lNodes.map(
lNode => html`<l-node-editor .element=${lNode}></l-node-editor>`
)}
</div>`
: html``;
}

renderFunctions(): TemplateResult {
if (!this.showfunctions) return html``;

Expand Down Expand Up @@ -177,7 +191,7 @@ export class BayEditor extends LitElement {
>${this.renderAddButtons()}</mwc-menu
>
</abbr>
${this.renderIedContainer()} ${this.renderFunctions()}
${this.renderIedContainer()}${this.renderLNodes()}${this.renderFunctions()}
<div
class="${classMap({
content: true,
Expand Down
19 changes: 17 additions & 2 deletions src/editors/substation/conducting-equipment-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import '@material/mwc-icon-button';
import '../../action-icon.js';
import '../../action-pane.js';
import './eq-function-editor.js';
import { startMove, getIcon } from './foundation.js';
import './l-node-editor.js';
import { startMove, getIcon, styles } from './foundation.js';
import {
getChildElementsByTagName,
newActionEvent,
Expand Down Expand Up @@ -62,6 +63,18 @@ export class ConductingEquipmentEditor extends LitElement {
);
}

private renderLNodes(): TemplateResult {
const lNodes = getChildElementsByTagName(this.element, 'LNode');

return lNodes.length
? html`<div class="container lnode">
${lNodes.map(
lNode => html`<l-node-editor .element=${lNode}></l-node-editor>`
)}
</div>`
: html``;
}

renderEqFunctions(): TemplateResult {
if (!this.showfunctions) return html``;

Expand Down Expand Up @@ -143,7 +156,7 @@ export class ConductingEquipmentEditor extends LitElement {
render(): TemplateResult {
if (this.showfunctions)
return html`<action-pane label="${this.name}"
>${this.renderContentPane()}${this.renderEqFunctions()}</action-pane
>${this.renderContentPane()}${this.renderLNodes()}${this.renderEqFunctions()}</action-pane
>`;

return html`<action-icon label="${this.name}"
Expand All @@ -152,6 +165,8 @@ export class ConductingEquipmentEditor extends LitElement {
}

static styles = css`
${styles}

:host(.moving) {
opacity: 0.3;
}
Expand Down
25 changes: 24 additions & 1 deletion src/editors/substation/eq-function-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
property,
customElement,
state,
css,
} from 'lit-element';

import '../../action-pane.js';
Expand All @@ -26,6 +27,18 @@ export class EqFunctionEditor extends LitElement {
return `${name}${desc ? ` - ${desc}` : ''}${type ? ` (${type})` : ''}`;
}

private renderLNodes(): TemplateResult {
const lNodes = getChildElementsByTagName(this.element, 'LNode');

return lNodes.length
? html`<div class="container lnode">
${lNodes.map(
lNode => html`<l-node-editor .element=${lNode}></l-node-editor>`
)}
</div>`
: html``;
}

private renderEqSubFunctions(): TemplateResult {
const eqSubFunctions = getChildElementsByTagName(
this.element,
Expand All @@ -45,7 +58,17 @@ export class EqFunctionEditor extends LitElement {
icon="functions"
secondary
highlighted
>${this.renderEqSubFunctions()}</action-pane
>${this.renderLNodes()}${this.renderEqSubFunctions()}</action-pane
>`;
}

static styles = css`
.container.lnode {
display: grid;
grid-gap: 12px;
padding: 8px 12px 16px;
box-sizing: border-box;
grid-template-columns: repeat(auto-fit, minmax(64px, auto));
}
`;
}
25 changes: 24 additions & 1 deletion src/editors/substation/eq-sub-function-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
property,
customElement,
state,
css,
} from 'lit-element';

import '../../action-pane.js';
Expand Down Expand Up @@ -38,9 +39,31 @@ export class EqSubFunctionEditor extends LitElement {
)}`;
}

private renderLNodes(): TemplateResult {
const lNodes = getChildElementsByTagName(this.element, 'LNode');

return lNodes.length
? html`<div class="container lnode">
${lNodes.map(
lNode => html`<l-node-editor .element=${lNode}></l-node-editor>`
)}
</div>`
: html``;
}

render(): TemplateResult {
return html`<action-pane label="${this.header}" icon="functions" secondary
>${this.renderEqSubFunctions()}</action-pane
>${this.renderLNodes()}${this.renderEqSubFunctions()}</action-pane
>`;
}

static styles = css`
.container.lnode {
display: grid;
grid-gap: 12px;
padding: 8px 12px 16px;
box-sizing: border-box;
grid-template-columns: repeat(auto-fit, minmax(64px, auto));
}
`;
}
8 changes: 8 additions & 0 deletions src/editors/substation/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,14 @@ export const styles = css`
grid-template-columns: repeat(auto-fit, minmax(64px, auto));
}

.container.lnode {
display: grid;
grid-gap: 12px;
padding: 8px 12px 16px;
box-sizing: border-box;
grid-template-columns: repeat(auto-fit, minmax(64px, auto));
}

powertransformer-editor[showfunctions] {
margin: 4px 8px 16px;
}
Expand Down
25 changes: 24 additions & 1 deletion src/editors/substation/function-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
property,
customElement,
state,
css,
} from 'lit-element';

import '../../action-pane.js';
Expand All @@ -26,6 +27,18 @@ export class FunctionEditor extends LitElement {
return `${name}${desc ? ` - ${desc}` : ''}${type ? ` (${type})` : ''}`;
}

private renderLNodes(): TemplateResult {
const lNodes = getChildElementsByTagName(this.element, 'LNode');

return lNodes.length
? html`<div class="container lnode">
${lNodes.map(
lNode => html`<l-node-editor .element=${lNode}></l-node-editor>`
)}
</div>`
: html``;
}

private renderSubFunctions(): TemplateResult {
const subfunctions = getChildElementsByTagName(this.element, 'SubFunction');
return html` ${subfunctions.map(
Expand All @@ -42,7 +55,17 @@ export class FunctionEditor extends LitElement {
icon="functions"
secondary
highlighted
>${this.renderSubFunctions()}</action-pane
>${this.renderLNodes()}${this.renderSubFunctions()}</action-pane
>`;
}

static styles = css`
.container.lnode {
display: grid;
grid-gap: 12px;
padding: 8px 12px 16px;
box-sizing: border-box;
grid-template-columns: repeat(auto-fit, minmax(64px, auto));
}
`;
}
89 changes: 89 additions & 0 deletions src/editors/substation/l-node-editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {
html,
LitElement,
TemplateResult,
property,
customElement,
state,
} from 'lit-element';

import '../../action-icon.js';
import { identity } from '../../foundation.js';
import {
automationLogicalNode,
controlLogicalNode,
functionalLogicalNode,
furtherPowerSystemEquipmentLogicalNode,
generalLogicalNode,
interfacingLogicalNode,
measurementLogicalNode,
nonElectricalLogicalNode,
powerTransformerLogicalNode,
protectionLogicalNode,
protectionRelatedLogicalNode,
qualityLogicalNode,
supervisionLogicalNode,
switchgearLogicalNode,
systemLogicalNode,
transformerLogicalNode,
} from '../../icons/lnode.js';

export function getLNodeIcon(lNode: Element): TemplateResult {
const lnClassGroup = lNode.getAttribute('lnClass')?.charAt(0) ?? '';
return lnClassIcons[lnClassGroup] ?? systemLogicalNode;
}

const lnClassIcons: Partial<Record<string, TemplateResult>> = {
L: systemLogicalNode,
A: automationLogicalNode,
C: controlLogicalNode,
F: functionalLogicalNode,
G: generalLogicalNode,
I: interfacingLogicalNode,
K: nonElectricalLogicalNode,
M: measurementLogicalNode,
P: protectionLogicalNode,
Q: qualityLogicalNode,
R: protectionRelatedLogicalNode,
S: supervisionLogicalNode,
T: transformerLogicalNode,
X: switchgearLogicalNode,
Y: powerTransformerLogicalNode,
Z: furtherPowerSystemEquipmentLogicalNode,
};

/** Pane rendering `LNode` element with its children */
@customElement('l-node-editor')
export class LNodeEditor extends LitElement {
/** The edited `LNode` element */
@property({ attribute: false })
element!: Element;
@state()
private get header(): string {
const prefix = this.element.getAttribute('prefix') ?? '';
const lnClass = this.element.getAttribute('lnClass');
const lnInst = this.element.getAttribute('lnInst');

const header = this.missingIedReference
? `${prefix} ${lnClass} ${lnInst}`
: identity(this.element);

return typeof header === 'string' ? header : '';
}
@state()
private get missingIedReference(): boolean {
return this.element.getAttribute('iedName') === 'None' ?? false;
}

render(): TemplateResult {
return html`<action-icon
label="${this.header}"
?secondary=${this.missingIedReference}
?highlighted=${this.missingIedReference}
hideActions
><mwc-icon slot="icon"
>${getLNodeIcon(this.element)}</mwc-icon
></action-icon
>`;
}
}
Loading