Skip to content

Commit

Permalink
feat(editors/substation): add read-only l-node-editor (#730)
Browse files Browse the repository at this point in the history
* feat(editors/substation): add read-only l-node-editor

* feat(editors/subtation): add l-node-editor to ConductingEquipment

* feat(editors/subtation): add l-node-editor to PowerTransformer

* feat(editors/subtation): add l-node-editor to EqSubFunction

* feat(editors/subtation): add l-node-editor to EqFunction

* feat(editors/subtation): add l-node-editor to SubFunction

* feat(editors/subtation): add l-node-editor to Function

* feat(editors/subtation): add l-node-editor to Bay

* feat(editors/subtation): add l-node-editor to VoltageLevel

* feat(editors/subtation): add l-node-editor to Substation

* merge with first

* style(action-icon): propper highlight of focused secondary items

* fix(editors/substation): unify rendering of LNode container

* feat(action-icon): add hideActions property (#752)

* feat(action-icon): add noaction property

* test(editors/substation/l-node-editor): update snapshot

* refactor(action-icon): resolve review comments
  • Loading branch information
JakobVogelsang committed May 17, 2022
1 parent 8f89f27 commit ecfeb5d
Show file tree
Hide file tree
Showing 33 changed files with 1,663 additions and 42 deletions.
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

0 comments on commit ecfeb5d

Please sign in to comment.