From c73a9fccb825b4c6ea28bb908256777a74ad5661 Mon Sep 17 00:00:00 2001 From: Petar Petrov Date: Thu, 17 Apr 2025 10:42:52 +0300 Subject: [PATCH] Add support for exact % progress reports in options flow (#25082) Co-authored-by: Bram Kragten --- src/data/data_entry_flow.ts | 18 ++++++++ .../config-flow/dialog-data-entry-flow.ts | 42 ++++++++++++------- src/dialogs/config-flow/step-flow-abort.ts | 4 +- src/dialogs/config-flow/step-flow-progress.ts | 15 ++++++- src/translations/en.json | 3 +- 5 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/data/data_entry_flow.ts b/src/data/data_entry_flow.ts index ded6ecf806..954930e8ed 100644 --- a/src/data/data_entry_flow.ts +++ b/src/data/data_entry_flow.ts @@ -17,6 +17,15 @@ export interface DataEntryFlowProgressedEvent { }; } +export interface DataEntryFlowProgressEvent { + type: "data_entry_flow_progress_update"; + data: { + handler: string; + flow_id: string; + progress: number; + }; +} + export interface DataEntryFlowProgress { flow_id: string; handler: string; @@ -108,3 +117,12 @@ export const subscribeDataEntryFlowProgressed = ( callback, "data_entry_flow_progressed" ); + +export const subscribeDataEntryFlowProgress = ( + conn: Connection, + callback: (ev: DataEntryFlowProgressEvent) => void +) => + conn.subscribeEvents( + callback, + "data_entry_flow_progress_update" + ); diff --git a/src/dialogs/config-flow/dialog-data-entry-flow.ts b/src/dialogs/config-flow/dialog-data-entry-flow.ts index 21b032a9d0..94959185ec 100644 --- a/src/dialogs/config-flow/dialog-data-entry-flow.ts +++ b/src/dialogs/config-flow/dialog-data-entry-flow.ts @@ -9,7 +9,10 @@ import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-dialog"; import "../../components/ha-icon-button"; import type { DataEntryFlowStep } from "../../data/data_entry_flow"; -import { subscribeDataEntryFlowProgressed } from "../../data/data_entry_flow"; +import { + subscribeDataEntryFlowProgress, + subscribeDataEntryFlowProgressed, +} from "../../data/data_entry_flow"; import { haStyleDialog } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; import { documentationUrl } from "../../util/documentation-url"; @@ -52,6 +55,8 @@ class DataEntryFlowDialog extends LitElement { @state() private _loading?: LoadingReason; + @state() private _progress?: number; + private _instance = instance; @state() private _step: @@ -62,7 +67,7 @@ class DataEntryFlowDialog extends LitElement { @state() private _handler?: string; - private _unsubDataEntryFlowProgressed?: Promise; + private _unsubDataEntryFlowProgress?: UnsubscribeFunc; public async showDialog(params: DataEntryFlowDialogParams): Promise { this._params = params; @@ -160,11 +165,9 @@ class DataEntryFlowDialog extends LitElement { this._step = undefined; this._params = undefined; this._handler = undefined; - if (this._unsubDataEntryFlowProgressed) { - this._unsubDataEntryFlowProgressed.then((unsub) => { - unsub(); - }); - this._unsubDataEntryFlowProgressed = undefined; + if (this._unsubDataEntryFlowProgress) { + this._unsubDataEntryFlowProgress(); + this._unsubDataEntryFlowProgress = undefined; } fireEvent(this, "dialog-closed", { dialog: this.localName }); } @@ -255,7 +258,9 @@ class DataEntryFlowDialog extends LitElement { .params=${this._params} .step=${this._step} .hass=${this.hass} - .domain=${this._step.handler} + .handler=${this._step.handler} + .domain=${this._params.domain ?? + this._step.handler} > ` : this._step.type === "progress" @@ -264,6 +269,7 @@ class DataEntryFlowDialog extends LitElement { .flowConfig=${this._params.flowConfig} .step=${this._step} .hass=${this.hass} + .progress=${this._progress} > ` : this._step.type === "menu" @@ -339,20 +345,28 @@ class DataEntryFlowDialog extends LitElement { } private async _subscribeDataEntryFlowProgressed() { - if (this._unsubDataEntryFlowProgressed) { + if (this._unsubDataEntryFlowProgress) { return; } - this._unsubDataEntryFlowProgressed = subscribeDataEntryFlowProgressed( - this.hass.connection, - async (ev) => { + this._progress = undefined; + const unsubs = [ + subscribeDataEntryFlowProgressed(this.hass.connection, (ev) => { if (ev.data.flow_id !== this._step?.flow_id) { return; } this._processStep( this._params!.flowConfig.fetchFlow(this.hass, this._step.flow_id) ); - } - ); + this._progress = undefined; + }), + subscribeDataEntryFlowProgress(this.hass.connection, (ev) => { + // ha-progress-ring has an issue with 0 so we round up + this._progress = Math.ceil(ev.data.progress * 100); + }), + ]; + this._unsubDataEntryFlowProgress = async () => { + (await Promise.all(unsubs)).map((unsub) => unsub()); + }; } static get styles(): CSSResultGroup { diff --git a/src/dialogs/config-flow/step-flow-abort.ts b/src/dialogs/config-flow/step-flow-abort.ts index c509dca607..fa54d4ca57 100644 --- a/src/dialogs/config-flow/step-flow-abort.ts +++ b/src/dialogs/config-flow/step-flow-abort.ts @@ -20,6 +20,8 @@ class StepFlowAbort extends LitElement { @property({ attribute: false }) public domain!: string; + @property({ attribute: false }) public handler!: string; + protected firstUpdated(changed: PropertyValues) { super.firstUpdated(changed); if (this.step.reason === "missing_credentials") { @@ -58,7 +60,7 @@ class StepFlowAbort extends LitElement { applicationCredentialAddedCallback: () => { showConfigFlowDialog(this.params.dialogParentElement!, { dialogClosedCallback: this.params.dialogClosedCallback, - startFlowHandler: this.domain, + startFlowHandler: this.handler, showAdvanced: this.hass.userData?.showAdvanced, navigateToResult: this.params.navigateToResult, }); diff --git a/src/dialogs/config-flow/step-flow-progress.ts b/src/dialogs/config-flow/step-flow-progress.ts index 0968478bd0..ef56fa271d 100644 --- a/src/dialogs/config-flow/step-flow-progress.ts +++ b/src/dialogs/config-flow/step-flow-progress.ts @@ -2,11 +2,13 @@ import "@material/mwc-button"; import type { CSSResultGroup, TemplateResult } from "lit"; import { css, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; +import "../../components/ha-progress-ring"; import "../../components/ha-spinner"; import type { DataEntryFlowStepProgress } from "../../data/data_entry_flow"; import type { HomeAssistant } from "../../types"; import type { FlowConfig } from "./show-dialog-data-entry-flow"; import { configFlowContentStyles } from "./styles"; +import { blankBeforePercent } from "../../common/translations/blank_before_percent"; @customElement("step-flow-progress") class StepFlowProgress extends LitElement { @@ -19,13 +21,24 @@ class StepFlowProgress extends LitElement { @property({ attribute: false }) public step!: DataEntryFlowStepProgress; + @property({ type: Number }) + public progress?: number; + protected render(): TemplateResult { return html`

${this.flowConfig.renderShowFormProgressHeader(this.hass, this.step)}

- + ${this.progress + ? html` + ${this.progress}${blankBeforePercent( + this.hass.locale + )}% + ` + : html` `} ${this.flowConfig.renderShowFormProgressDescription( this.hass, this.step diff --git a/src/translations/en.json b/src/translations/en.json index 80f1a0642b..6e9e10bff6 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5673,8 +5673,7 @@ "backup_failed": "Failed to download backup", "restore_complete": "Backup restored", "restore_failed": "Failed to restore backup", - "downloading": "Downloading backup", - "restoring": "Restoring backup" + "downloading": "Downloading backup" }, "statistics": { "title": "Controller statistics",