Skip to content

Commit 35637de

Browse files
committed
feat(#77): change section options in visual editor
1 parent afada3f commit 35637de

File tree

4 files changed

+219
-85
lines changed

4 files changed

+219
-85
lines changed

src/editor/entity.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const computeSchema = (entityConf: EntityConfig, icon: string) => [
5555
];
5656

5757
@customElement('sankey-chart-entity-editor')
58-
export class SankeyChartEntityEditor extends LitElement {
58+
class SankeyChartEntityEditor extends LitElement {
5959
@property({ attribute: false }) public hass!: HomeAssistant;
6060
@property({ attribute: false }) public entity!: EntityConfigOrStr;
6161
@property({ attribute: false }) public onClose!: () => void;
@@ -69,7 +69,14 @@ export class SankeyChartEntityEditor extends LitElement {
6969
return localize('editor.fields.' + schema.name);
7070
};
7171

72-
private _editChild(ev) {
72+
private _editChild(
73+
ev: CustomEvent & {
74+
target: {
75+
value: string;
76+
index: number;
77+
};
78+
},
79+
) {
7380
const {
7481
detail: { value },
7582
target,
@@ -104,7 +111,7 @@ export class SankeyChartEntityEditor extends LitElement {
104111
return html`
105112
<div class="header">
106113
<ha-icon-button .label=${this.hass!.localize('ui.common.back')} @click=${this.onClose}>
107-
<ha-icon .icon=${'mdi:arrow-left'} />
114+
<ha-icon .icon=${'mdi:arrow-left'}></ha-icon>
108115
</ha-icon-button>
109116
<h2>${localize('editor.entity_editor')}</h2>
110117
</div>
@@ -164,3 +171,5 @@ export class SankeyChartEntityEditor extends LitElement {
164171
`;
165172
}
166173
}
174+
175+
export default SankeyChartEntityEditor;

src/editor/index.ts

Lines changed: 26 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { customElement, property, state } from 'lit/decorators';
77
import { repeat } from 'lit/directives/repeat';
88
import { SankeyChartConfig, SectionConfig } from '../types';
99
import { localize } from '../localize/localize';
10-
import { getEntityId, normalizeConfig } from '../utils';
10+
import { normalizeConfig } from '../utils';
11+
import './section';
1112
import './entity';
1213
import { EntityConfigOrStr } from '../types';
1314
import { UNIT_PREFIXES } from '../const';
@@ -132,14 +133,22 @@ export class SankeyChartEditor extends LitElement implements LovelaceCardEditor
132133
this._entityConfig = { sectionIndex, entityIndex, entity: sections[sectionIndex].entities[entityIndex] };
133134
}
134135

135-
private _handleEntityConfig = (entityConf: EntityConfigOrStr): void => {
136+
private _handleEntityChange = (entityConf: EntityConfigOrStr): void => {
136137
this._editEntity({
137138
detail: { value: entityConf },
138139
target: { section: this._entityConfig?.sectionIndex, index: this._entityConfig?.entityIndex },
139140
});
140141
this._entityConfig = { ...this._entityConfig!, entity: entityConf };
141142
};
142143

144+
private _handleSectionChange = (index: number, sectionConf: SectionConfig): void => {
145+
this._config = {
146+
...this._config!,
147+
sections: this._config?.sections?.map((section, i) => (i === index ? sectionConf : section)),
148+
};
149+
this._updateConfig();
150+
};
151+
143152
private _updateConfig(): void {
144153
fireEvent(this, 'config-changed', { config: this._config });
145154
}
@@ -209,11 +218,11 @@ export class SankeyChartEditor extends LitElement implements LovelaceCardEditor
209218
<sankey-chart-entity-editor
210219
.hass=${this.hass}
211220
.entity=${this._entityConfig.entity}
212-
.onChange=${this._handleEntityConfig}
221+
.onChange=${this._handleEntityChange}
213222
.onClose=${() => {
214223
this._entityConfig = undefined;
215224
}}
216-
/>
225+
></sankey-chart-entity-editor>
217226
`;
218227
}
219228

@@ -268,46 +277,20 @@ export class SankeyChartEditor extends LitElement implements LovelaceCardEditor
268277
return html`
269278
<div class="sections">
270279
<h3>${localize('editor.sections')}</h3>
271-
${sections.map(
280+
${repeat(
281+
sections,
282+
(s, i) => i,
272283
(section, sectionIndex) =>
273284
html`
274-
<ha-card .header=${localize('editor.section') + ` ${sectionIndex + 1}`} class="section">
275-
<div class="entities">
276-
${repeat(
277-
section.entities,
278-
entityConf => sectionIndex + getEntityId(entityConf),
279-
(entityConf, i) => html`
280-
<div class="entity">
281-
<div class="handle">
282-
<ha-icon .icon=${'mdi:drag'} />
283-
</div>
284-
<ha-entity-picker
285-
allow-custom-entity
286-
.hass=${this.hass}
287-
.value=${getEntityId(entityConf)}
288-
.section=${sectionIndex}
289-
.index=${i}
290-
@value-changed=${this._editEntity}
291-
></ha-entity-picker>
292-
<ha-icon-button
293-
.label=${this.hass!.localize('ui.components.entity.entity-picker.edit')}
294-
class="edit-icon"
295-
@click=${() => this._configEntity(sectionIndex, i)}
296-
>
297-
<ha-icon .icon=${'mdi:pencil'} />
298-
</ha-icon-button>
299-
</div>
300-
`,
301-
)}
302-
</div>
303-
<ha-entity-picker
304-
allow-custom-entity
305-
class="add-entity"
306-
.hass=${this.hass}
307-
.section=${sectionIndex}
308-
@value-changed=${this._addEntity}
309-
></ha-entity-picker>
310-
</ha-card>
285+
<sankey-chart-section-editor
286+
.hass=${this.hass}
287+
.section=${section}
288+
.index=${sectionIndex}
289+
.onConfigEntity=${this._configEntity.bind(this, sectionIndex)}
290+
.onChange=${this._handleSectionChange.bind(this, sectionIndex)}
291+
.onChangeEntity=${this._editEntity.bind(this)}
292+
.onAddEntity=${this._addEntity.bind(this)}
293+
></sankey-chart-section-editor>
311294
`,
312295
)}
313296
<ha-actions>
@@ -342,46 +325,8 @@ export class SankeyChartEditor extends LitElement implements LovelaceCardEditor
342325
flex-direction: column;
343326
margin-bottom: 20px;
344327
}
345-
.section {
346-
margin-bottom: 16px;
347-
padding: 0 10px 10px;
348-
}
349328
ha-formfield {
350-
padding-bottom: 8px;
351-
}
352-
.add-entity {
353-
display: block;
354-
margin-left: 31px;
355-
margin-right: 36px;
356-
margin-inline-start: 31px;
357-
margin-inline-end: 36px;
358-
direction: var(--direction);
359-
}
360-
.entity {
361-
display: flex;
362-
align-items: center;
363-
margin-bottom: 8px;
364-
}
365-
366-
.entity .handle {
367-
visibility: hidden;
368-
padding-right: 8px;
369-
cursor: move;
370-
padding-inline-end: 8px;
371-
padding-inline-start: initial;
372-
direction: var(--direction);
373-
}
374-
.entity .handle > * {
375-
pointer-events: none;
376-
}
377-
378-
.entity ha-entity-picker {
379-
flex-grow: 1;
380-
}
381-
382-
.edit-icon {
383-
--mdc-icon-button-size: 36px;
384-
/* color: var(--secondary-text-color); */
329+
padding-bottom: 8px;
385330
}
386331
`;
387332
}

src/editor/section.ts

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import { HomeAssistant } from 'custom-card-helpers';
2+
import { LitElement, html, TemplateResult, css, CSSResultGroup } from 'lit';
3+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
4+
import { customElement, property } from 'lit/decorators';
5+
import { SectionConfig } from '../types';
6+
import { localize } from '../localize/localize';
7+
import { repeat } from 'lit/directives/repeat';
8+
import { getEntityId } from '../utils';
9+
10+
@customElement('sankey-chart-section-editor')
11+
class SankeyChartSectionEditor extends LitElement {
12+
@property({ attribute: false }) public hass!: HomeAssistant;
13+
@property({ attribute: false }) public section!: SectionConfig;
14+
@property({ attribute: false }) public index!: number;
15+
@property({ attribute: false }) public onChange!: (sectionConf: SectionConfig) => void;
16+
@property({ attribute: false }) public onConfigEntity!: (entityIndex: number) => void;
17+
@property({ attribute: false }) public onChangeEntity!: (ev: CustomEvent) => void;
18+
@property({ attribute: false }) public onAddEntity!: (ev: CustomEvent) => void;
19+
20+
private _valueChanged(ev: CustomEvent): void {
21+
const { value } = ev.detail;
22+
this.onChange({ ...value, sort_by: value.sort_by || undefined, sort_dir: value.sort_dir || undefined });
23+
}
24+
25+
private _computeSchema = () => {
26+
return [
27+
{ name: 'min_width', selector: { text: {} } },
28+
{
29+
type: 'grid',
30+
name: '',
31+
schema: [
32+
{
33+
name: 'sort_by',
34+
selector: {
35+
select: {
36+
mode: 'dropdown',
37+
options: [{ value: '' }, { value: 'state', label: localize('editor.sort_by.state') }],
38+
},
39+
},
40+
},
41+
{
42+
name: 'sort_dir',
43+
selector: {
44+
select: {
45+
mode: 'dropdown',
46+
options: [
47+
{ value: '' },
48+
{ value: 'desc', label: localize('editor.sort_dir.desc') },
49+
{ value: 'asc', label: localize('editor.sort_dir.asc') },
50+
],
51+
},
52+
},
53+
},
54+
{ name: 'sort_group_by_parent', selector: { boolean: {} } },
55+
],
56+
},
57+
];
58+
};
59+
60+
private _computeLabel = (schema: { name: string }) => {
61+
return localize('editor.fields.section.' + schema.name);
62+
};
63+
64+
protected render(): TemplateResult | void {
65+
return html`
66+
<ha-card class="section">
67+
<ha-expansion-panel
68+
.header=${localize('editor.section') + ` ${this.index + 1}`}
69+
.secondary=${localize('editor.section_options')}
70+
.leftChevron=${true}
71+
>
72+
<br />
73+
<ha-form
74+
.hass=${this.hass}
75+
.data=${this.section}
76+
.schema=${this._computeSchema()}
77+
.computeLabel=${this._computeLabel}
78+
@value-changed=${this._valueChanged}
79+
></ha-form>
80+
<br />
81+
</ha-expansion-panel>
82+
83+
<div class="entities">
84+
${repeat(
85+
this.section.entities,
86+
entityConf => this.index + getEntityId(entityConf),
87+
(entityConf, i) => html`
88+
<div class="entity">
89+
<div class="handle">
90+
<ha-icon .icon=${'mdi:drag'}></ha-icon>
91+
</div>
92+
<ha-entity-picker
93+
allow-custom-entity
94+
.hass=${this.hass}
95+
.value=${getEntityId(entityConf)}
96+
.section=${this.index}
97+
.index=${i}
98+
@value-changed=${this.onChangeEntity}
99+
></ha-entity-picker>
100+
<ha-icon-button
101+
.label=${this.hass!.localize('ui.components.entity.entity-picker.edit')}
102+
class="edit-icon"
103+
@click=${() => this.onConfigEntity(i)}
104+
>
105+
<ha-icon .icon=${'mdi:pencil'}></ha-icon>
106+
</ha-icon-button>
107+
</div>
108+
`,
109+
)}
110+
</div>
111+
<ha-entity-picker
112+
allow-custom-entity
113+
class="add-entity"
114+
.hass=${this.hass}
115+
.section=${this.index}
116+
@value-changed=${this.onAddEntity}
117+
></ha-entity-picker>
118+
</ha-card>
119+
`;
120+
}
121+
122+
static get styles(): CSSResultGroup {
123+
return css`
124+
.section {
125+
margin-bottom: 16px;
126+
padding: 0 10px 10px;
127+
}
128+
.add-entity {
129+
display: block;
130+
margin-left: 31px;
131+
margin-right: 36px;
132+
margin-inline-start: 31px;
133+
margin-inline-end: 36px;
134+
direction: var(--direction);
135+
}
136+
.entity {
137+
display: flex;
138+
align-items: center;
139+
margin-bottom: 8px;
140+
}
141+
142+
.entity .handle {
143+
visibility: hidden;
144+
padding-right: 8px;
145+
cursor: move;
146+
padding-inline-end: 8px;
147+
padding-inline-start: initial;
148+
direction: var(--direction);
149+
}
150+
.entity .handle > * {
151+
pointer-events: none;
152+
}
153+
154+
.entity ha-entity-picker {
155+
flex-grow: 1;
156+
}
157+
158+
.edit-icon {
159+
--mdc-icon-button-size: 36px;
160+
/* color: var(--secondary-text-color); */
161+
}
162+
`;
163+
}
164+
}
165+
166+
export default SankeyChartSectionEditor;

src/localize/languages/en.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"add_entity": "+ Add entity",
1717
"entity_editor": "Entity editor",
1818
"decimals": "decimals",
19+
"section_options": "Options",
1920
"fields": {
2021
"autoconfig": "Autoconfig",
2122
"print_yaml": "Print auto generated config yaml",
@@ -43,13 +44,26 @@
4344
"color_on_state": "Change color based on state",
4445
"color_limit": "State limit for color change",
4546
"color_above": "Color above limit",
46-
"color_below": "Color below limit"
47+
"color_below": "Color below limit",
48+
"section": {
49+
"min_width": "Min width",
50+
"sort_by": "Sort by",
51+
"sort_dir": "Sort direction",
52+
"sort_group_by_parent": "Group by parent"
53+
}
4754
},
4855
"entity_types": {
4956
"entity": "Entity",
5057
"remaining_parent_state": "Remaining parent state",
5158
"remaining_child_state": "Remaining child state",
5259
"passthrough": "Passthrough"
60+
},
61+
"sort_by": {
62+
"state": "State"
63+
},
64+
"sort_dir": {
65+
"desc": "Descending",
66+
"asc": "Ascending"
5367
}
5468
}
5569
}

0 commit comments

Comments
 (0)