diff --git a/src/data/recorder.ts b/src/data/recorder.ts index 1b89af2834..d6d2b215cf 100644 --- a/src/data/recorder.ts +++ b/src/data/recorder.ts @@ -332,3 +332,6 @@ export const getDisplayUnit = ( export const isExternalStatistic = (statisticsId: string): boolean => statisticsId.includes(":"); + +export const updateStatisticsIssues = (hass: HomeAssistant) => + hass.callWS({ type: "recorder/update_statistics_issues" }); diff --git a/src/panels/config/repairs/ha-config-repairs.ts b/src/panels/config/repairs/ha-config-repairs.ts index 50c4b9f2f4..98366f89bb 100644 --- a/src/panels/config/repairs/ha-config-repairs.ts +++ b/src/panels/config/repairs/ha-config-repairs.ts @@ -18,6 +18,7 @@ import { showRepairsIssueDialog } from "./show-repair-issue-dialog"; import { STATISTIC_TYPES, StatisticsValidationResult, + updateStatisticsIssues, } from "../../../data/recorder"; @customElement("ha-config-repairs") @@ -144,25 +145,19 @@ class HaConfigRepairs extends LitElement { issue.translation_key && STATISTIC_TYPES.includes(issue.translation_key as any) ) { - const localize = - await this.hass.loadFragmentTranslation("developer-tools"); + this.hass.loadFragmentTranslation("developer-tools"); const data = await fetchRepairsIssueData( this.hass.connection, issue.domain, issue.issue_id ); if ("issue_type" in data.issue_data) { - await fixStatisticsIssue( - this, - this.hass, - localize || this.hass.localize, - { - type: data.issue_data - .issue_type as StatisticsValidationResult["type"], - data: data.issue_data as any, - } - ); - this.hass.callWS({ type: "recorder/update_statistics_issues" }); + await fixStatisticsIssue(this, { + type: data.issue_data + .issue_type as StatisticsValidationResult["type"], + data: data.issue_data as any, + }); + updateStatisticsIssues(this.hass); } } else { showRepairsIssueDialog(this, { diff --git a/src/panels/developer-tools/statistics/developer-tools-statistics.ts b/src/panels/developer-tools/statistics/developer-tools-statistics.ts index 8baafaf909..3e4bb2526f 100644 --- a/src/panels/developer-tools/statistics/developer-tools-statistics.ts +++ b/src/panels/developer-tools/statistics/developer-tools-statistics.ts @@ -50,8 +50,6 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { private _disabledEntities = new Set(); - private _deletedStatistics = new Set(); - protected firstUpdated() { this._validateStatistics(); } @@ -225,9 +223,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { this._data = statisticIds .filter( - (statistic) => - !this._disabledEntities.has(statistic.statistic_id) && - !this._deletedStatistics.has(statistic.statistic_id) + (statistic) => !this._disabledEntities.has(statistic.statistic_id) ) .map((statistic) => { statsIds.add(statistic.statistic_id); @@ -241,8 +237,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { Object.keys(issues).forEach((statisticId) => { if ( !statsIds.has(statisticId) && - !this._disabledEntities.has(statisticId) && - !this._deletedStatistics.has(statisticId) + !this._disabledEntities.has(statisticId) ) { this._data.push({ statistic_id: statisticId, @@ -265,20 +260,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { (FIX_ISSUES_ORDER[itemB.type] ?? 99) ); const issue = issues[0]; - const result = await fixStatisticsIssue( - this, - this.hass, - this.hass.localize, - issue - ); - if ( - result && - ["no_state", "entity_no_longer_recorded", "state_class_removed"].includes( - issue.type - ) - ) { - this._deletedStatistics.add(issue.data.statistic_id); - } + await fixStatisticsIssue(this, issue); this._validateStatistics(); }; diff --git a/src/panels/developer-tools/statistics/dialog-statistics-fix.ts b/src/panels/developer-tools/statistics/dialog-statistics-fix.ts new file mode 100644 index 0000000000..f87c4f3d2e --- /dev/null +++ b/src/panels/developer-tools/statistics/dialog-statistics-fix.ts @@ -0,0 +1,201 @@ +import "@material/mwc-button/mwc-button"; +import { CSSResultGroup, html, LitElement, nothing } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import "../../../components/ha-circular-progress"; +import { fireEvent } from "../../../common/dom/fire_event"; +import "../../../components/ha-dialog"; +import { clearStatistics, getStatisticLabel } from "../../../data/recorder"; +import { haStyle, haStyleDialog } from "../../../resources/styles"; +import { HomeAssistant } from "../../../types"; +import { documentationUrl } from "../../../util/documentation-url"; +import type { DialogStatisticsFixParams } from "./show-dialog-statistics-fix"; +import { showAlertDialog } from "../../lovelace/custom-card-helpers"; + +@customElement("dialog-statistics-fix") +export class DialogStatisticsFix extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() private _params?: DialogStatisticsFixParams; + + @state() private _clearing = false; + + public showDialog(params: DialogStatisticsFixParams): void { + this._params = params; + } + + public closeDialog(): void { + this._cancel(); + } + + private _closeDialog(): void { + this._params = undefined; + this._clearing = false; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + protected render() { + if (!this._params) { + return nothing; + } + + const issue = this._params.issue; + + return html` + +

+ ${this.hass.localize( + `ui.panel.developer-tools.tabs.statistics.fix_issue.${issue.type}.info_text_1`, + { + name: getStatisticLabel( + this.hass, + this._params.issue.data.statistic_id, + undefined + ), + statistic_id: this._params.issue.data.statistic_id, + } + )}

+ ${this.hass.localize( + `ui.panel.developer-tools.tabs.statistics.fix_issue.${issue.type}.info_text_2`, + { statistic_id: issue.data.statistic_id } + )} + ${issue.type === "entity_not_recorded" + ? html`

+ + ${this.hass.localize( + "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_3_link" + )}` + : issue.type === "entity_no_longer_recorded" + ? html` + ${this.hass.localize( + "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_3_link" + )}

+ ${this.hass.localize( + "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_4" + )}` + : issue.type === "state_class_removed" + ? html`

+ ${this.hass.localize( + "ui.panel.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_6", + { statistic_id: issue.data.statistic_id } + )}` + : nothing} +

+ + ${issue.type !== "entity_not_recorded" + ? html` + ${this._clearing + ? html`` + : nothing} + ${this.hass.localize("ui.common.delete")} + + + ${this.hass.localize("ui.common.close")} + ` + : html` + ${this.hass.localize("ui.common.ok")} + `} +
+ `; + } + + private _cancel(): void { + this._params?.cancelCallback!(); + this._closeDialog(); + } + + private async _clearStatistics(): Promise { + this._clearing = true; + try { + await clearStatistics(this.hass, [this._params!.issue.data.statistic_id]); + } catch (err: any) { + await showAlertDialog(this, { + title: + err.code === "timeout" + ? this.hass.localize( + "ui.panel.developer-tools.tabs.statistics.fix_issue.clearing_timeout_title" + ) + : this.hass.localize( + "ui.panel.developer-tools.tabs.statistics.fix_issue.clearing_failed" + ), + text: + err.code === "timeout" + ? this.hass.localize( + "ui.panel.developer-tools.tabs.statistics.fix_issue.clearing_timeout_text" + ) + : err.message, + }); + } finally { + this._clearing = false; + this._params?.fixedCallback!(); + this._closeDialog(); + } + } + + static get styles(): CSSResultGroup { + return [haStyle, haStyleDialog]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-statistics-fix": DialogStatisticsFix; + } +} diff --git a/src/panels/developer-tools/statistics/fix-statistics.ts b/src/panels/developer-tools/statistics/fix-statistics.ts index 0329cf77be..fdaf571e0b 100644 --- a/src/panels/developer-tools/statistics/fix-statistics.ts +++ b/src/panels/developer-tools/statistics/fix-statistics.ts @@ -1,171 +1,17 @@ -import { html } from "lit"; -import { - clearStatistics, - getStatisticLabel, - StatisticsValidationResult, -} from "../../../data/recorder"; -import { documentationUrl } from "../../../util/documentation-url"; -import { - showConfirmationDialog, - showAlertDialog, -} from "../../lovelace/custom-card-helpers"; +import { StatisticsValidationResult } from "../../../data/recorder"; +import { showFixStatisticsDialog } from "./show-dialog-statistics-fix"; import { showFixStatisticsUnitsChangedDialog } from "./show-dialog-statistics-fix-units-changed"; -import { LocalizeFunc } from "../../../common/translations/localize"; -import { HomeAssistant } from "../../../types"; export const fixStatisticsIssue = async ( element: HTMLElement, - hass: HomeAssistant, - localize: LocalizeFunc, issue: StatisticsValidationResult ) => { - switch (issue.type) { - case "no_state": - return showConfirmationDialog(element, { - title: localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.title" - ), - text: html`${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.info_text_1", - { - name: getStatisticLabel(hass, issue.data.statistic_id, undefined), - statistic_id: issue.data.statistic_id, - } - )}

${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.info_text_2", - { statistic_id: issue.data.statistic_id } - )}`, - confirmText: localize("ui.common.delete"), - destructive: true, - confirm: async () => { - await clearStatistics(hass, [issue.data.statistic_id]); - }, - }); - case "entity_not_recorded": - return showAlertDialog(element, { - title: localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.title" - ), - text: html`${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_1", - { - name: getStatisticLabel(hass, issue.data.statistic_id, undefined), - } - )}

${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_2" - )}

- - ${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_3_link" - )}`, - }); - case "entity_no_longer_recorded": - return showConfirmationDialog(element, { - title: localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.title" - ), - text: html`${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_1", - { - name: getStatisticLabel(hass, issue.data.statistic_id, undefined), - statistic_id: issue.data.statistic_id, - } - )} - ${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_2" - )} - - ${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_3_link" - )}

- ${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_4" - )}`, - confirmText: localize("ui.common.delete"), - destructive: true, - confirm: async () => { - await clearStatistics(hass, [issue.data.statistic_id]); - }, - }); - case "state_class_removed": - return showConfirmationDialog(element, { - title: localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.state_class_removed.title" - ), - text: html`${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_1", - { - name: getStatisticLabel(hass, issue.data.statistic_id, undefined), - statistic_id: issue.data.statistic_id, - } - )}

- ${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_2" - )} - - ${localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.state_class_removed.info_text_6", - { statistic_id: issue.data.statistic_id } - )}`, - confirmText: localize("ui.common.delete"), - destructive: true, - confirm: async () => { - await clearStatistics(hass, [issue.data.statistic_id]); - }, - }); - case "units_changed": - return showFixStatisticsUnitsChangedDialog(element, { - issue, - }); - default: - return showAlertDialog(element, { - title: localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.no_support.title" - ), - text: localize( - "ui.panel.developer-tools.tabs.statistics.fix_issue.no_support.info_text_1" - ), - }); + if (issue.type === "units_changed") { + return showFixStatisticsUnitsChangedDialog(element, { + issue, + }); } + return showFixStatisticsDialog(element, { + issue, + }); }; diff --git a/src/panels/developer-tools/statistics/show-dialog-statistics-fix.ts b/src/panels/developer-tools/statistics/show-dialog-statistics-fix.ts new file mode 100644 index 0000000000..70ffa4f0c3 --- /dev/null +++ b/src/panels/developer-tools/statistics/show-dialog-statistics-fix.ts @@ -0,0 +1,33 @@ +import { fireEvent } from "../../../common/dom/fire_event"; +import { StatisticsValidationResult } from "../../../data/recorder"; + +export const loadFixDialog = () => import("./dialog-statistics-fix"); + +export interface DialogStatisticsFixParams { + issue: StatisticsValidationResult; + fixedCallback?: () => void; + cancelCallback?: () => void; +} + +export const showFixStatisticsDialog = ( + element: HTMLElement, + detailParams: DialogStatisticsFixParams +) => + new Promise((resolve) => { + const origCallback = detailParams.fixedCallback; + + fireEvent(element, "show-dialog", { + dialogTag: "dialog-statistics-fix", + dialogImport: loadFixDialog, + dialogParams: { + ...detailParams, + cancelCallback: () => { + resolve(false); + }, + fixedCallback: () => { + resolve(true); + origCallback?.(); + }, + }, + }); + }); diff --git a/src/panels/lovelace/editor/section-editor/hui-dialog-edit-section.ts b/src/panels/lovelace/editor/section-editor/hui-dialog-edit-section.ts index 7801e58a3d..e6973e606a 100644 --- a/src/panels/lovelace/editor/section-editor/hui-dialog-edit-section.ts +++ b/src/panels/lovelace/editor/section-editor/hui-dialog-edit-section.ts @@ -15,7 +15,6 @@ import { fireEvent } from "../../../../common/dom/fire_event"; import { stopPropagation } from "../../../../common/dom/stop_propagation"; import "../../../../components/ha-button"; import "../../../../components/ha-button-menu"; -import "../../../../components/ha-circular-progress"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; import "../../../../components/ha-icon-button"; diff --git a/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts b/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts index 2d4c3c6bd3..84c7eb5679 100644 --- a/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts +++ b/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts @@ -507,12 +507,6 @@ export class HuiDialogEditView extends LitElement { margin-inline-end: auto; margin-inline-start: initial; } - ha-circular-progress { - display: none; - } - ha-circular-progress[indeterminate] { - display: block; - } .selected_menu_item { color: var(--primary-color); } diff --git a/src/translations/en.json b/src/translations/en.json index fc4b61bc24..06c27f4a93 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -6968,6 +6968,9 @@ }, "fix_issue": { "fix": "Fix issue", + "clearing_failed": "Clearing the statistics failed", + "clearing_timeout_title": "Clearing not done yet", + "clearing_timeout_text": "The clearing of the statistics took longer than expected, it might take longer for the issue to disappear.", "no_support": { "title": "Fix issue", "info_text_1": "Fixing this issue is not supported yet."