From 4645fd7d8332e94fe1105ac632c60da6e98b09f1 Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Sat, 23 May 2026 22:19:50 +0300 Subject: [PATCH 01/12] add canEdit --- src/components/entity/ha-statistic-picker.ts | 34 +++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index 39ef6a8768d4..a63b0f52b36f 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -1,5 +1,10 @@ import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize"; -import { mdiChartLine, mdiHelpCircleOutline, mdiShape } from "@mdi/js"; +import { + mdiChartLine, + mdiHelpCircleOutline, + mdiPencil, + mdiShape, +} from "@mdi/js"; import type { HassEntity } from "home-assistant-js-websocket"; import { html, LitElement, nothing, type PropertyValues } from "lit"; import { customElement, property, query } from "lit/decorators"; @@ -53,6 +58,16 @@ const SEARCH_KEYS = [ { name: "id", weight: 2 }, ]; +export interface StatisticElementChangedEvent { + statisticId: string; +} + +declare global { + interface HASSDomEvents { + "edit-statistics-element": StatisticElementChangedEvent; + } +} + @customElement("ha-statistic-picker") export class HaStatisticPicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -130,6 +145,8 @@ export class HaStatisticPicker extends LitElement { @query("ha-generic-picker") private _picker?: HaGenericPicker; + @property({ attribute: "can-edit", type: Boolean }) public canEdit?; + public willUpdate(changedProps: PropertyValues) { if ( (!this.hasUpdated && !this.statisticIds) || @@ -341,6 +358,15 @@ export class HaStatisticPicker extends LitElement { ${item.secondary ? html`${item.secondary}` : nothing} + ${this.canEdit + ? html`` + : nothing} `; } @@ -350,6 +376,12 @@ export class HaStatisticPicker extends LitElement { private _valueRenderer: PickerValueRenderer = this._makeValueRenderer(); + private _editItem(ev) { + ev.stopPropagation(); + const statisticId = (ev.currentTarget as any).value; + fireEvent(this, "edit-statistics-element", { statisticId }); + } + private _computeItem(statisticId: string): StatisticComboBoxItem { const stateObj = this.hass.states[statisticId]; From 6dc4671c66c0d91ae9828b5aa7cd086ed2a677ff Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Sat, 23 May 2026 22:20:26 +0300 Subject: [PATCH 02/12] add canEdit --- src/components/entity/ha-statistics-picker.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/components/entity/ha-statistics-picker.ts b/src/components/entity/ha-statistics-picker.ts index d8dedfa9e77a..0abd07d220a4 100644 --- a/src/components/entity/ha-statistics-picker.ts +++ b/src/components/entity/ha-statistics-picker.ts @@ -1,9 +1,10 @@ import { css, html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators"; import { repeat } from "lit/directives/repeat"; -import { fireEvent } from "../../common/dom/fire_event"; +import { type HASSDomEvent, fireEvent } from "../../common/dom/fire_event"; import type { ValueChangedEvent, HomeAssistant } from "../../types"; import "./ha-statistic-picker"; +import { type StatisticElementChangedEvent } from "./ha-statistic-picker"; @customElement("ha-statistics-picker") class HaStatisticsPicker extends LitElement { @@ -59,6 +60,8 @@ class HaStatisticsPicker extends LitElement { }) public ignoreRestrictionsOnFirstStatistic = false; + @property({ attribute: "can-edit", type: Boolean }) public canEdit?; + protected render() { if (!this.hass) { return nothing; @@ -99,7 +102,9 @@ class HaStatisticsPicker extends LitElement { .statisticIds=${this.statisticIds} .excludeStatistics=${this.value} .allowCustomEntity=${this.allowCustomEntity} + .canEdit=${this.canEdit} @value-changed=${this._statisticChanged} + @edit-statistics-element=${this._editItem} > ` @@ -122,6 +127,17 @@ class HaStatisticsPicker extends LitElement { `; } + private _editItem(ev: HASSDomEvent) { + const statisticId = ev.detail.statisticId; + const index = this._currentStatistics!.findIndex((e) => e === statisticId); + fireEvent(this, "edit-detail-element", { + subElementConfig: { + index, + type: "row", + }, + }); + } + private get _currentStatistics() { return this.value || []; } From 354082f667f8a6c7218eda43571d35874f1102f6 Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Sat, 23 May 2026 22:20:53 +0300 Subject: [PATCH 03/12] add subEditor --- .../hui-statistics-graph-card-editor.ts | 168 +++++++++++++++--- 1 file changed, 145 insertions(+), 23 deletions(-) diff --git a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts index 7739890a2f1f..2cd737d4d50f 100644 --- a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts @@ -15,7 +15,10 @@ import { union, } from "superstruct"; import { ensureArray } from "../../../../common/array/ensure-array"; -import { fireEvent } from "../../../../common/dom/fire_event"; +import { + type HASSDomEvent, + fireEvent, +} from "../../../../common/dom/fire_event"; import type { LocalizeFunc } from "../../../../common/translations/localize"; import { deepEqual } from "../../../../common/util/deep-equal"; import { supportedStatTypeMap } from "../../../../components/chart/statistics-chart"; @@ -32,13 +35,19 @@ import { isExternalStatistic, statisticsMetaHasType, } from "../../../../data/recorder"; +import type { EntityConfig } from "../../../../panels/lovelace/entity-rows/types"; import type { HomeAssistant } from "../../../../types"; import { DEFAULT_DAYS_TO_SHOW } from "../../cards/hui-statistics-graph-card"; -import type { StatisticsGraphCardConfig } from "../../cards/types"; +import type { + GraphEntityConfig, + StatisticsGraphCardConfig, +} from "../../cards/types"; import { processConfigEntities } from "../../common/process-config-entities"; import type { LovelaceCardEditor } from "../../types"; +import "../hui-sub-element-editor"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; import { graphEntitiesConfigStruct } from "../structs/entities-struct"; +import type { EditDetailElementEvent, SubElementEditorConfig } from "../types"; import { orderPropertiesGraphCard } from "./order-properties/order-properties-graph"; const statTypeStruct = union([ @@ -114,6 +123,8 @@ export class HuiStatisticsGraphCardEditor @state() private _metaDatas?: StatisticsMetaData[]; + @state() private _subElementEditorConfig?: SubElementEditorConfig; + public setConfig(config: StatisticsGraphCardConfig): void { assert(config, cardConfigStruct); this._config = config; @@ -334,11 +345,54 @@ export class HuiStatisticsGraphCardEditor } ); + private _subForm = memoizeOne((localize: LocalizeFunc) => ({ + schema: [ + { name: "entity", required: true, selector: { statistic: {} } }, + { + name: "name", + selector: { entity_name: {} }, + context: { + entity: "entity", + }, + }, + { + name: "color", + selector: { ui_color: {} }, + }, + ] as const, + computeLabel: (item: HaFormSchema) => { + switch (item.name) { + case "entity": + return localize( + "ui.panel.lovelace.editor.card.statistics-graph.picked_statistic" + ); + case "name": + case "color": + return localize(`ui.panel.lovelace.editor.card.generic.${item.name}`); + default: + return undefined; + } + }, + })); + protected render() { if (!this.hass || !this._config) { return nothing; } + if (this._subElementEditorConfig) { + return html` + + + `; + } + const schema = this._schema( this.hass.localize, this._configEntities, @@ -375,24 +429,43 @@ export class HuiStatisticsGraphCardEditor .computeHelper=${this._computeHelperCallback} @value-changed=${this._valueChanged} > - + + `; } + private _goBack(): void { + this._subElementEditorConfig = undefined; + } + + private _editDetailElement(ev: HASSDomEvent): void { + const index = ev.detail.subElementConfig.index!; + let elementConfig = this._config!.entities[index]; + if (typeof elementConfig === "string") { + elementConfig = { entity: elementConfig }; + } + this._subElementEditorConfig = { + ...ev.detail.subElementConfig, + ...{ elementConfig: elementConfig as EntityConfig }, + }; + } + private _valueChanged(ev: CustomEvent): void { const config = this._orderProperties(ev.detail.value); fireEvent(this, "config-changed", { config }); @@ -410,15 +483,66 @@ export class HuiStatisticsGraphCardEditor }); let config = { ...this._config!, entities: newEntities }; + + // remove inappropriate stat options dependently on entities + config = await this._cleanConfig(config); + // normalize a generated yaml code + config = this._orderProperties(config); + + fireEvent(this, "config-changed", { + config, + }); + } + + private async _handleSubEntityChanged(ev: CustomEvent): Promise { + ev.stopPropagation(); + + // get updated entity config + let newEntityConfig = ev.detail.config as GraphEntityConfig; + + // update card config with updated entity config + const index = this._subElementEditorConfig!.index!; + const newEntities = [...this._config!.entities]; + newEntities[index] = newEntityConfig; + let config = this._config!; + config = { ...config, entities: newEntities }; + + // remove inappropriate stat options dependently on entities + config = await this._cleanConfig(config); + // normalize a generated yaml code + config = this._orderProperties(config); + this._config = config; + + // update sub-element editor config + this._subElementEditorConfig = { + ...this._subElementEditorConfig!, + elementConfig: { + ...(this._config!.entities[index] as GraphEntityConfig), + }, + }; + + fireEvent(this, "config-changed", { config }); + } + + // remove inappropriate stat options dependently on entities + private async _cleanConfig( + config: StatisticsGraphCardConfig + ): Promise { + const entityIds = config.entities.map((entityConf) => { + if (typeof entityConf === "string") { + return entityConf; + } + return entityConf.entity ?? undefined; + }); if ( - newEntityIds?.some((statistic_id) => isExternalStatistic(statistic_id)) && + entityIds.some((statistic_id) => isExternalStatistic(statistic_id)) && config.period === "5minute" ) { delete config.period; } const metadata = config.stat_types || config.unit - ? await getStatisticMetadata(this.hass!, newEntityIds) + ? await getStatisticMetadata(this.hass!, entityIds) : undefined; if (config.stat_types && config.entities.length) { config.stat_types = ensureArray(config.stat_types).filter((stat_type) => @@ -438,10 +562,8 @@ export class HuiStatisticsGraphCardEditor ) { delete config.unit; } - config = this._orderProperties(config); - fireEvent(this, "config-changed", { - config, - }); + + return config; } // normalize a generated yaml code by placing lines in a consistent order From b2c10c9d4e0d34e19b9407f6291b86f0b5ff96a3 Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Sat, 23 May 2026 22:31:58 +0300 Subject: [PATCH 04/12] linter --- src/components/entity/ha-statistics-picker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/entity/ha-statistics-picker.ts b/src/components/entity/ha-statistics-picker.ts index 0abd07d220a4..b919d191cff6 100644 --- a/src/components/entity/ha-statistics-picker.ts +++ b/src/components/entity/ha-statistics-picker.ts @@ -4,7 +4,7 @@ import { repeat } from "lit/directives/repeat"; import { type HASSDomEvent, fireEvent } from "../../common/dom/fire_event"; import type { ValueChangedEvent, HomeAssistant } from "../../types"; import "./ha-statistic-picker"; -import { type StatisticElementChangedEvent } from "./ha-statistic-picker"; +import type { StatisticElementChangedEvent } from "./ha-statistic-picker"; @customElement("ha-statistics-picker") class HaStatisticsPicker extends LitElement { From b8a21a3797d5e8e3565f13f1d84effdc730ecc92 Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Sat, 23 May 2026 22:33:12 +0300 Subject: [PATCH 05/12] linter --- .../editor/config-elements/hui-statistics-graph-card-editor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts index 2cd737d4d50f..7882af6b5d66 100644 --- a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts @@ -35,7 +35,7 @@ import { isExternalStatistic, statisticsMetaHasType, } from "../../../../data/recorder"; -import type { EntityConfig } from "../../../../panels/lovelace/entity-rows/types"; +import type { EntityConfig } from "../entity-rows/types"; import type { HomeAssistant } from "../../../../types"; import { DEFAULT_DAYS_TO_SHOW } from "../../cards/hui-statistics-graph-card"; import type { From 794cc7535c027bcaa3696e90625f7096632c6b2a Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Sat, 23 May 2026 22:37:58 +0300 Subject: [PATCH 06/12] linter --- .../editor/config-elements/hui-statistics-graph-card-editor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts index 7882af6b5d66..673096c792eb 100644 --- a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts @@ -498,7 +498,7 @@ export class HuiStatisticsGraphCardEditor ev.stopPropagation(); // get updated entity config - let newEntityConfig = ev.detail.config as GraphEntityConfig; + const newEntityConfig = ev.detail.config as GraphEntityConfig; // update card config with updated entity config const index = this._subElementEditorConfig!.index!; From 1392487242b345272055034f3dc517b855502a3e Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Sat, 23 May 2026 22:42:15 +0300 Subject: [PATCH 07/12] linter --- .../editor/config-elements/hui-statistics-graph-card-editor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts index 673096c792eb..b8b4563bda54 100644 --- a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts @@ -35,7 +35,7 @@ import { isExternalStatistic, statisticsMetaHasType, } from "../../../../data/recorder"; -import type { EntityConfig } from "../entity-rows/types"; +import type { EntityConfig } from "../../entity-rows/types"; import type { HomeAssistant } from "../../../../types"; import { DEFAULT_DAYS_TO_SHOW } from "../../cards/hui-statistics-graph-card"; import type { From ca0cef636c9d2a10dbb1b1407d86ec249f282d42 Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Sun, 24 May 2026 12:26:09 +0300 Subject: [PATCH 08/12] Remove div --- .../hui-statistics-graph-card-editor.ts | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts index b8b4563bda54..adb0733842aa 100644 --- a/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-statistics-graph-card-editor.ts @@ -429,24 +429,23 @@ export class HuiStatisticsGraphCardEditor .computeHelper=${this._computeHelperCallback} @value-changed=${this._valueChanged} > - - + `; } From 575cd5bb97f8f06f4bb43eff8f283ec2b19be1d1 Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Thu, 28 May 2026 10:08:34 +0300 Subject: [PATCH 09/12] Update src/components/entity/ha-statistic-picker.ts Co-authored-by: Petar Petrov --- src/components/entity/ha-statistic-picker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index a63b0f52b36f..629bd8d1b98f 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -376,7 +376,7 @@ export class HaStatisticPicker extends LitElement { private _valueRenderer: PickerValueRenderer = this._makeValueRenderer(); - private _editItem(ev) { + private _editItem(ev: HASSDomEvent) { ev.stopPropagation(); const statisticId = (ev.currentTarget as any).value; fireEvent(this, "edit-statistics-element", { statisticId }); From cf5604c8db89ad46a0d06caf31a63696fe34ce8e Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Thu, 28 May 2026 13:56:55 +0300 Subject: [PATCH 10/12] Update src/components/entity/ha-statistic-picker.ts Co-authored-by: Petar Petrov --- src/components/entity/ha-statistic-picker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index 629bd8d1b98f..d0e94d74622d 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -145,7 +145,7 @@ export class HaStatisticPicker extends LitElement { @query("ha-generic-picker") private _picker?: HaGenericPicker; - @property({ attribute: "can-edit", type: Boolean }) public canEdit?; + @property({ attribute: "can-edit", type: Boolean }) public canEdit?: boolean; public willUpdate(changedProps: PropertyValues) { if ( From 8e4d2a659e2a880289f6dd1dde02a6f2697564bd Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Thu, 28 May 2026 14:20:40 +0300 Subject: [PATCH 11/12] Update ha-statistic-picker.ts --- src/components/entity/ha-statistic-picker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index d0e94d74622d..5b8ea682033a 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -10,7 +10,7 @@ import { html, LitElement, nothing, type PropertyValues } from "lit"; import { customElement, property, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { ensureArray } from "../../common/array/ensure-array"; -import { fireEvent } from "../../common/dom/fire_event"; +import { HASSDomEvent, fireEvent } from "../../common/dom/fire_event"; import { computeEntityNameList } from "../../common/entity/compute_entity_name_display"; import { computeStateName } from "../../common/entity/compute_state_name"; import { computeRTL } from "../../common/util/compute_rtl"; From 586ce4778108898d8139a1bc8b9372e2b6868f6d Mon Sep 17 00:00:00 2001 From: ildar170975 <71872483+ildar170975@users.noreply.github.com> Date: Thu, 28 May 2026 14:22:01 +0300 Subject: [PATCH 12/12] Update ha-statistic-picker.ts --- src/components/entity/ha-statistic-picker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index 5b8ea682033a..3e71beff6285 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -10,7 +10,7 @@ import { html, LitElement, nothing, type PropertyValues } from "lit"; import { customElement, property, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { ensureArray } from "../../common/array/ensure-array"; -import { HASSDomEvent, fireEvent } from "../../common/dom/fire_event"; +import { type HASSDomEvent, fireEvent } from "../../common/dom/fire_event"; import { computeEntityNameList } from "../../common/entity/compute_entity_name_display"; import { computeStateName } from "../../common/entity/compute_state_name"; import { computeRTL } from "../../common/util/compute_rtl";