Skip to content
Open
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
34 changes: 33 additions & 1 deletion src/components/entity/ha-statistic-picker.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -53,6 +58,16 @@
{ 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;
Expand Down Expand Up @@ -130,6 +145,8 @@

@query("ha-generic-picker") private _picker?: HaGenericPicker;

@property({ attribute: "can-edit", type: Boolean }) public canEdit?: boolean;

public willUpdate(changedProps: PropertyValues<this>) {
if (
(!this.hasUpdated && !this.statisticIds) ||
Expand Down Expand Up @@ -341,6 +358,15 @@
${item.secondary
? html`<span slot="supporting-text">${item.secondary}</span>`
: nothing}
${this.canEdit
? html`<ha-icon-button
slot="end"
.value=${statisticId}
.label=${this.hass.localize("ui.common.edit")}
.path=${mdiPencil}
@click=${this._editItem}
></ha-icon-button>`
: nothing}
`;
}

Expand All @@ -350,6 +376,12 @@

private _valueRenderer: PickerValueRenderer = this._makeValueRenderer();

private _editItem(ev: HASSDomEvent<StatisticElementChangedEvent>) {

Check failure on line 379 in src/components/entity/ha-statistic-picker.ts

View workflow job for this annotation

GitHub Actions / Lint and check format

Cannot find name 'HASSDomEvent'. Did you mean 'HASSDomEvents'?
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];

Expand Down
18 changes: 17 additions & 1 deletion src/components/entity/ha-statistics-picker.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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}
></ha-statistic-picker>
</div>
`
Expand All @@ -122,6 +127,17 @@ class HaStatisticsPicker extends LitElement {
`;
}

private _editItem(ev: HASSDomEvent<StatisticElementChangedEvent>) {
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 || [];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -32,13 +35,19 @@ import {
isExternalStatistic,
statisticsMetaHasType,
} from "../../../../data/recorder";
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 { 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([
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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`
<hui-sub-element-editor
.hass=${this.hass}
.config=${this._subElementEditorConfig}
.form=${this._subForm(this.hass.localize)}
@go-back=${this._goBack}
@config-changed=${this._handleSubEntityChanged}
>
</hui-sub-element-editor>
`;
}

const schema = this._schema(
this.hass.localize,
this._configEntities,
Expand Down Expand Up @@ -388,11 +442,29 @@ export class HuiStatisticsGraphCardEditor
.ignoreRestrictionsOnFirstStatistic=${true}
.value=${this._configEntities}
.configValue=${"entities"}
can-edit
@value-changed=${this._entitiesChanged}
@edit-detail-element=${this._editDetailElement}
></ha-statistics-picker>
`;
}

private _goBack(): void {
this._subElementEditorConfig = undefined;
}

private _editDetailElement(ev: HASSDomEvent<EditDetailElementEvent>): 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 });
Expand All @@ -410,15 +482,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<void> {
ev.stopPropagation();

// get updated entity config
const 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<StatisticsGraphCardConfig> {
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) =>
Expand All @@ -438,10 +561,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
Expand Down
Loading