From 200e099035f75584d7d43e6341b6c976d85d62d5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 15 Aug 2019 09:03:54 -0700 Subject: [PATCH] Refactor config flow dialog to make it reusable (#3488) * Refactor config flow dialog to make it reusable * More refactor * forgot to save * Render labels correcetly --- src/auth/ha-auth-flow.ts | 17 ++- src/data/config_entries.ts | 87 ++--------- src/data/data_entry_flow.ts | 68 +++++++++ ...nfig-flow.ts => dialog-data-entry-flow.ts} | 60 ++++---- .../config-flow/show-dialog-config-flow.ts | 138 ++++++++++++++++-- .../show-dialog-data-entry-flow.ts | 95 ++++++++++++ src/dialogs/config-flow/step-flow-abort.ts | 23 +-- .../config-flow/step-flow-create-entry.ts | 23 +-- src/dialogs/config-flow/step-flow-external.ts | 39 ++--- src/dialogs/config-flow/step-flow-form.ts | 44 ++---- .../config-flow/step-flow-pick-handler.ts | 9 +- src/onboarding/onboarding-integrations.ts | 4 +- 12 files changed, 382 insertions(+), 225 deletions(-) create mode 100644 src/data/data_entry_flow.ts rename src/dialogs/config-flow/{dialog-config-flow.ts => dialog-data-entry-flow.ts} (83%) create mode 100644 src/dialogs/config-flow/show-dialog-data-entry-flow.ts diff --git a/src/auth/ha-auth-flow.ts b/src/auth/ha-auth-flow.ts index f6f9b6c829..902c2a8e07 100644 --- a/src/auth/ha-auth-flow.ts +++ b/src/auth/ha-auth-flow.ts @@ -11,7 +11,10 @@ import "../components/ha-form"; import "../components/ha-markdown"; import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin"; import { AuthProvider } from "../data/auth"; -import { ConfigFlowStep, ConfigFlowStepForm } from "../data/config_entries"; +import { + DataEntryFlowStep, + DataEntryFlowStepForm, +} from "../data/data_entry_flow"; type State = "loading" | "error" | "step"; @@ -22,7 +25,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { @property() public oauth2State?: string; @property() private _state: State = "loading"; @property() private _stepData: any = {}; - @property() private _step?: ConfigFlowStep; + @property() private _step?: DataEntryFlowStep; @property() private _errorMessage?: string; protected render() { @@ -87,7 +90,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { } } - private _renderStep(step: ConfigFlowStep) { + private _renderStep(step: DataEntryFlowStep) { switch (step.type) { case "abort": return html` @@ -192,7 +195,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { document.location.assign(url); } - private async _updateStep(step: ConfigFlowStep) { + private async _updateStep(step: DataEntryFlowStep) { let stepData: any = null; if ( this._step && @@ -219,7 +222,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { }, 100); } - private _computeStepDescription(step: ConfigFlowStepForm) { + private _computeStepDescription(step: DataEntryFlowStepForm) { const resourceKey = `ui.panel.page-authorize.form.providers.${ step.handler[0] }.step.${step.step_id}.description`; @@ -232,7 +235,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { return this.localize(resourceKey, ...args); } - private _computeLabelCallback(step: ConfigFlowStepForm) { + private _computeLabelCallback(step: DataEntryFlowStepForm) { // Returns a callback for ha-form to calculate labels per schema object return (schema) => this.localize( @@ -242,7 +245,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { ); } - private _computeErrorCallback(step: ConfigFlowStepForm) { + private _computeErrorCallback(step: DataEntryFlowStepForm) { // Returns a callback for ha-form to calculate error messages return (error) => this.localize( diff --git a/src/data/config_entries.ts b/src/data/config_entries.ts index e0b773df70..1e2fd65020 100644 --- a/src/data/config_entries.ts +++ b/src/data/config_entries.ts @@ -2,15 +2,7 @@ import { HomeAssistant } from "../types"; import { createCollection } from "home-assistant-js-websocket"; import { debounce } from "../common/util/debounce"; import { LocalizeFunc } from "../common/translations/localize"; - -export interface DataEntryFlowProgressedEvent { - type: "data_entry_flow_progressed"; - data: { - handler: string; - flow_id: string; - refresh: boolean; - }; -} +import { DataEntryFlowStep, DataEntryFlowProgress } from "./data_entry_flow"; export interface ConfigEntry { entry_id: string; @@ -22,80 +14,23 @@ export interface ConfigEntry { supports_options: boolean; } -export interface FieldSchema { - name: string; - default?: any; - optional: boolean; -} - -export interface ConfigFlowProgress { - flow_id: string; - handler: string; - context: { - title_placeholders: { [key: string]: string }; - [key: string]: any; - }; -} - -export interface ConfigFlowStepForm { - type: "form"; - flow_id: string; - handler: string; - step_id: string; - data_schema: FieldSchema[]; - errors: { [key: string]: string }; - description_placeholders: { [key: string]: string }; -} - -export interface ConfigFlowStepExternal { - type: "external"; - flow_id: string; - handler: string; - step_id: string; - url: string; - description_placeholders: { [key: string]: string }; -} - -export interface ConfigFlowStepCreateEntry { - type: "create_entry"; - version: number; - flow_id: string; - handler: string; - title: string; - // Config entry ID - result: string; - description: string; - description_placeholders: { [key: string]: string }; -} - -export interface ConfigFlowStepAbort { - type: "abort"; - flow_id: string; - handler: string; - reason: string; - description_placeholders: { [key: string]: string }; -} - -export type ConfigFlowStep = - | ConfigFlowStepForm - | ConfigFlowStepExternal - | ConfigFlowStepCreateEntry - | ConfigFlowStepAbort; - export const createConfigFlow = (hass: HomeAssistant, handler: string) => - hass.callApi("POST", "config/config_entries/flow", { + hass.callApi("POST", "config/config_entries/flow", { handler, }); export const fetchConfigFlow = (hass: HomeAssistant, flowId: string) => - hass.callApi("GET", `config/config_entries/flow/${flowId}`); + hass.callApi( + "GET", + `config/config_entries/flow/${flowId}` + ); export const handleConfigFlowStep = ( hass: HomeAssistant, flowId: string, data: { [key: string]: any } ) => - hass.callApi( + hass.callApi( "POST", `config/config_entries/flow/${flowId}`, data @@ -105,7 +40,7 @@ export const deleteConfigFlow = (hass: HomeAssistant, flowId: string) => hass.callApi("DELETE", `config/config_entries/flow/${flowId}`); export const getConfigFlowsInProgress = (hass: HomeAssistant) => - hass.callApi("GET", "config/config_entries/flow"); + hass.callApi("GET", "config/config_entries/flow"); export const getConfigFlowHandlers = (hass: HomeAssistant) => hass.callApi("GET", "config/config_entries/flow_handlers"); @@ -130,9 +65,9 @@ const subscribeConfigFlowInProgressUpdates = (conn, store) => export const subscribeConfigFlowInProgress = ( hass: HomeAssistant, - onChange: (flows: ConfigFlowProgress[]) => void + onChange: (flows: DataEntryFlowProgress[]) => void ) => - createCollection( + createCollection( "_configFlowProgress", fetchConfigFlowInProgress, subscribeConfigFlowInProgressUpdates, @@ -145,7 +80,7 @@ export const getConfigEntries = (hass: HomeAssistant) => export const localizeConfigFlowTitle = ( localize: LocalizeFunc, - flow: ConfigFlowProgress + flow: DataEntryFlowProgress ) => { const placeholders = flow.context.title_placeholders || {}; const placeholderKeys = Object.keys(placeholders); diff --git a/src/data/data_entry_flow.ts b/src/data/data_entry_flow.ts new file mode 100644 index 0000000000..7f2e8ab894 --- /dev/null +++ b/src/data/data_entry_flow.ts @@ -0,0 +1,68 @@ +export interface DataEntryFlowProgressedEvent { + type: "data_entry_flow_progressed"; + data: { + handler: string; + flow_id: string; + refresh: boolean; + }; +} + +export interface FieldSchema { + name: string; + default?: any; + optional: boolean; +} + +export interface DataEntryFlowProgress { + flow_id: string; + handler: string; + context: { + title_placeholders: { [key: string]: string }; + [key: string]: any; + }; +} + +export interface DataEntryFlowStepForm { + type: "form"; + flow_id: string; + handler: string; + step_id: string; + data_schema: FieldSchema[]; + errors: { [key: string]: string }; + description_placeholders: { [key: string]: string }; +} + +export interface DataEntryFlowStepExternal { + type: "external"; + flow_id: string; + handler: string; + step_id: string; + url: string; + description_placeholders: { [key: string]: string }; +} + +export interface DataEntryFlowStepCreateEntry { + type: "create_entry"; + version: number; + flow_id: string; + handler: string; + title: string; + // Config entry ID + result: string; + description: string; + description_placeholders: { [key: string]: string }; +} + +export interface DataEntryFlowStepAbort { + type: "abort"; + flow_id: string; + handler: string; + reason: string; + description_placeholders: { [key: string]: string }; +} + +export type DataEntryFlowStep = + | DataEntryFlowStepForm + | DataEntryFlowStepExternal + | DataEntryFlowStepCreateEntry + | DataEntryFlowStepAbort; diff --git a/src/dialogs/config-flow/dialog-config-flow.ts b/src/dialogs/config-flow/dialog-data-entry-flow.ts similarity index 83% rename from src/dialogs/config-flow/dialog-config-flow.ts rename to src/dialogs/config-flow/dialog-data-entry-flow.ts index 1ca5932d34..1c59b3b451 100644 --- a/src/dialogs/config-flow/dialog-config-flow.ts +++ b/src/dialogs/config-flow/dialog-data-entry-flow.ts @@ -22,14 +22,8 @@ import "../../components/dialog/ha-paper-dialog"; // tslint:disable-next-line import { HaPaperDialog } from "../../components/dialog/ha-paper-dialog"; import { haStyleDialog } from "../../resources/styles"; -import { - fetchConfigFlow, - ConfigFlowStep, - deleteConfigFlow, - getConfigFlowHandlers, -} from "../../data/config_entries"; import { PolymerChangedEvent } from "../../polymer-types"; -import { HaConfigFlowParams } from "./show-dialog-config-flow"; +import { DataEntryFlowDialogParams } from "./show-dialog-data-entry-flow"; import "./step-flow-pick-handler"; import "./step-flow-loading"; @@ -46,7 +40,7 @@ import { subscribeAreaRegistry, } from "../../data/area_registry"; import { HomeAssistant } from "../../types"; -import { caseInsensitiveCompare } from "../../common/string/compare"; +import { DataEntryFlowStep } from "../../data/data_entry_flow"; let instance = 0; @@ -54,20 +48,20 @@ declare global { // for fire event interface HASSDomEvents { "flow-update": { - step?: ConfigFlowStep; - stepPromise?: Promise; + step?: DataEntryFlowStep; + stepPromise?: Promise; }; } } -@customElement("dialog-config-flow") -class ConfigFlowDialog extends LitElement { +@customElement("dialog-data-entry-flow") +class DataEntryFlowDialog extends LitElement { public hass!: HomeAssistant; - @property() private _params?: HaConfigFlowParams; + @property() private _params?: DataEntryFlowDialogParams; @property() private _loading = true; private _instance = instance; @property() private _step: - | ConfigFlowStep + | DataEntryFlowStep | undefined // Null means we need to pick a config flow | null; @@ -77,12 +71,15 @@ class ConfigFlowDialog extends LitElement { private _unsubAreas?: UnsubscribeFunc; private _unsubDevices?: UnsubscribeFunc; - public async showDialog(params: HaConfigFlowParams): Promise { + public async showDialog(params: DataEntryFlowDialogParams): Promise { this._params = params; this._instance = instance++; // Create a new config flow. Show picker if (!params.continueFlowId) { + if (!params.flowConfig.getFlowHandlers) { + throw new Error("No getFlowHandlers defined in flow config"); + } this._step = null; // We only load the handlers once @@ -90,13 +87,7 @@ class ConfigFlowDialog extends LitElement { this._loading = true; this.updateComplete.then(() => this._scheduleCenterDialog()); try { - this._handlers = (await getConfigFlowHandlers(this.hass)).sort( - (handlerA, handlerB) => - caseInsensitiveCompare( - this.hass.localize(`component.${handlerA}.config.title`), - this.hass.localize(`component.${handlerB}.config.title`) - ) - ); + this._handlers = await params.flowConfig.getFlowHandlers(this.hass); } finally { this._loading = false; } @@ -108,7 +99,10 @@ class ConfigFlowDialog extends LitElement { this._loading = true; const curInstance = this._instance; - const step = await fetchConfigFlow(this.hass, params.continueFlowId); + const step = await params.flowConfig.fetchFlow( + this.hass, + params.continueFlowId + ); // Happens if second showDialog called if (curInstance !== this._instance) { @@ -145,6 +139,7 @@ class ConfigFlowDialog extends LitElement { ? // Show handler picker html` @@ -152,6 +147,7 @@ class ConfigFlowDialog extends LitElement { : this._step.type === "form" ? html` @@ -159,6 +155,7 @@ class ConfigFlowDialog extends LitElement { : this._step.type === "external" ? html` @@ -166,6 +163,7 @@ class ConfigFlowDialog extends LitElement { : this._step.type === "abort" ? html` @@ -177,6 +175,7 @@ class ConfigFlowDialog extends LitElement { ` : html` + step: DataEntryFlowStep | undefined | Promise ): Promise { if (step instanceof Promise) { this._loading = true; @@ -267,7 +271,7 @@ class ConfigFlowDialog extends LitElement { // If we created this flow, delete it now. if (this._step && !flowFinished && !this._params.continueFlowId) { - deleteConfigFlow(this.hass, this._step.flow_id); + this._params.flowConfig.deleteFlow(this.hass, this._step.flow_id); } this._params.dialogClosedCallback({ @@ -319,6 +323,6 @@ class ConfigFlowDialog extends LitElement { declare global { interface HTMLElementTagNameMap { - "dialog-config-flow": ConfigFlowDialog; + "dialog-data-entry-flow": DataEntryFlowDialog; } } diff --git a/src/dialogs/config-flow/show-dialog-config-flow.ts b/src/dialogs/config-flow/show-dialog-config-flow.ts index a38db25f36..f8718393f4 100644 --- a/src/dialogs/config-flow/show-dialog-config-flow.ts +++ b/src/dialogs/config-flow/show-dialog-config-flow.ts @@ -1,20 +1,128 @@ -import { fireEvent } from "../../common/dom/fire_event"; +import { + getConfigFlowHandlers, + fetchConfigFlow, + handleConfigFlowStep, + deleteConfigFlow, + createConfigFlow, +} from "../../data/config_entries"; +import { html } from "lit-element"; +import { localizeKey } from "../../common/translations/localize"; +import { + showFlowDialog, + DataEntryFlowDialogParams, + loadDataEntryFlowDialog, +} from "./show-dialog-data-entry-flow"; +import { caseInsensitiveCompare } from "../../common/string/compare"; -export interface HaConfigFlowParams { - continueFlowId?: string; - dialogClosedCallback: (params: { flowFinished: boolean }) => void; -} - -export const loadConfigFlowDialog = () => - import(/* webpackChunkName: "dialog-config-flow" */ "./dialog-config-flow"); +export const loadConfigFlowDialog = loadDataEntryFlowDialog; export const showConfigFlowDialog = ( element: HTMLElement, - dialogParams: HaConfigFlowParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-config-flow", - dialogImport: loadConfigFlowDialog, - dialogParams, + dialogParams: Omit +): void => + showFlowDialog(element, dialogParams, { + loadDevicesAndAreas: true, + getFlowHandlers: (hass) => + getConfigFlowHandlers(hass).then((handlers) => + handlers.sort((handlerA, handlerB) => + caseInsensitiveCompare( + hass.localize(`component.${handlerA}.config.title`), + hass.localize(`component.${handlerB}.config.title`) + ) + ) + ), + createFlow: createConfigFlow, + fetchFlow: fetchConfigFlow, + handleFlowStep: handleConfigFlowStep, + deleteFlow: deleteConfigFlow, + + renderAbortDescription(hass, step) { + const description = localizeKey( + hass.localize, + `component.${step.handler}.config.abort.${step.reason}`, + step.description_placeholders + ); + + return description + ? html` + + ` + : ""; + }, + + renderShowFormStepHeader(hass, step) { + return hass.localize( + `component.${step.handler}.config.step.${step.step_id}.title` + ); + }, + + renderShowFormStepDescription(hass, step) { + const description = localizeKey( + hass.localize, + `component.${step.handler}.config.step.${step.step_id}.description`, + step.description_placeholders + ); + return description + ? html` + + ` + : ""; + }, + + renderShowFormStepFieldLabel(hass, step, field) { + return hass.localize( + `component.${step.handler}.config.step.${step.step_id}.data.${ + field.name + }` + ); + }, + + renderShowFormStepFieldError(hass, step, error) { + return hass.localize(`component.${step.handler}.config.error.${error}`); + }, + + renderExternalStepHeader(hass, step) { + return hass.localize( + `component.${step.handler}.config.step.${step.step_id}.title` + ); + }, + + renderExternalStepDescription(hass, step) { + const description = localizeKey( + hass.localize, + `component.${step.handler}.config.${step.step_id}.description`, + step.description_placeholders + ); + + return html` +

+ ${hass.localize( + "ui.panel.config.integrations.config_flow.external_step.description" + )} +

+ ${description + ? html` + + ` + : ""} + `; + }, + + renderCreateEntryDescription(hass, step) { + const description = localizeKey( + hass.localize, + `component.${step.handler}.config.create_entry.${step.description || + "default"}`, + step.description_placeholders + ); + + return html` + ${description + ? html` + + ` + : ""} +

Created config for ${step.title}.

+ `; + }, }); -}; diff --git a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts new file mode 100644 index 0000000000..072bce8083 --- /dev/null +++ b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts @@ -0,0 +1,95 @@ +import { TemplateResult } from "lit-html"; +import { fireEvent } from "../../common/dom/fire_event"; +import { HomeAssistant } from "../../types"; +import { + DataEntryFlowStepCreateEntry, + DataEntryFlowStepExternal, + DataEntryFlowStepForm, + DataEntryFlowStep, + DataEntryFlowStepAbort, + FieldSchema, +} from "../../data/data_entry_flow"; + +export interface FlowConfig { + loadDevicesAndAreas: boolean; + + getFlowHandlers?: (hass: HomeAssistant) => Promise; + + createFlow(hass: HomeAssistant, handler: string): Promise; + + fetchFlow(hass: HomeAssistant, flowId: string): Promise; + + handleFlowStep( + hass: HomeAssistant, + flowId: string, + data: { [key: string]: any } + ): Promise; + + deleteFlow(hass: HomeAssistant, flowId: string): Promise; + + renderAbortDescription( + hass: HomeAssistant, + step: DataEntryFlowStepAbort + ): TemplateResult | ""; + + renderShowFormStepHeader( + hass: HomeAssistant, + step: DataEntryFlowStepForm + ): string; + + renderShowFormStepDescription( + hass: HomeAssistant, + step: DataEntryFlowStepForm + ): TemplateResult | ""; + + renderShowFormStepFieldLabel( + hass: HomeAssistant, + step: DataEntryFlowStepForm, + field: FieldSchema + ): string; + + renderShowFormStepFieldError( + hass: HomeAssistant, + step: DataEntryFlowStepForm, + error: string + ): string; + + renderExternalStepHeader( + hass: HomeAssistant, + step: DataEntryFlowStepExternal + ): string; + + renderExternalStepDescription( + hass: HomeAssistant, + step: DataEntryFlowStepExternal + ): TemplateResult | ""; + + renderCreateEntryDescription( + hass: HomeAssistant, + step: DataEntryFlowStepCreateEntry + ): TemplateResult | ""; +} + +export interface DataEntryFlowDialogParams { + continueFlowId?: string; + dialogClosedCallback: (params: { flowFinished: boolean }) => void; + flowConfig: FlowConfig; +} + +export const loadDataEntryFlowDialog = () => + import(/* webpackChunkName: "dialog-config-flow" */ "./dialog-data-entry-flow"); + +export const showFlowDialog = ( + element: HTMLElement, + dialogParams: Omit, + flowConfig: FlowConfig +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-data-entry-flow", + dialogImport: loadDataEntryFlowDialog, + dialogParams: { + ...dialogParams, + flowConfig, + }, + }); +}; diff --git a/src/dialogs/config-flow/step-flow-abort.ts b/src/dialogs/config-flow/step-flow-abort.ts index e1dfdbe577..3af1b63d92 100644 --- a/src/dialogs/config-flow/step-flow-abort.ts +++ b/src/dialogs/config-flow/step-flow-abort.ts @@ -8,38 +8,27 @@ import { } from "lit-element"; import "@material/mwc-button"; -import { ConfigFlowStepAbort } from "../../data/config_entries"; +import { DataEntryFlowStepAbort } from "../../data/data_entry_flow"; import { HomeAssistant } from "../../types"; -import { localizeKey } from "../../common/translations/localize"; import { fireEvent } from "../../common/dom/fire_event"; import { configFlowContentStyles } from "./styles"; +import { FlowConfig } from "./show-dialog-data-entry-flow"; @customElement("step-flow-abort") class StepFlowAbort extends LitElement { + public flowConfig!: FlowConfig; + @property() public hass!: HomeAssistant; @property() - private step!: ConfigFlowStepAbort; + private step!: DataEntryFlowStepAbort; protected render(): TemplateResult | void { - const localize = this.hass.localize; - const step = this.step; - - const description = localizeKey( - localize, - `component.${step.handler}.config.abort.${step.reason}`, - step.description_placeholders - ); - return html`

Aborted

- ${description - ? html` - - ` - : ""} + ${this.flowConfig.renderAbortDescription(this.hass, this.step)}
Close diff --git a/src/dialogs/config-flow/step-flow-create-entry.ts b/src/dialogs/config-flow/step-flow-create-entry.ts index 801854ff49..cd1183ec16 100644 --- a/src/dialogs/config-flow/step-flow-create-entry.ts +++ b/src/dialogs/config-flow/step-flow-create-entry.ts @@ -12,9 +12,7 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { ConfigFlowStepCreateEntry } from "../../data/config_entries"; import { HomeAssistant } from "../../types"; -import { localizeKey } from "../../common/translations/localize"; import { fireEvent } from "../../common/dom/fire_event"; import { configFlowContentStyles } from "./styles"; import { @@ -25,14 +23,18 @@ import { AreaRegistryEntry, createAreaRegistryEntry, } from "../../data/area_registry"; +import { DataEntryFlowStepCreateEntry } from "../../data/data_entry_flow"; +import { FlowConfig } from "./show-dialog-data-entry-flow"; @customElement("step-flow-create-entry") class StepFlowCreateEntry extends LitElement { + public flowConfig!: FlowConfig; + @property() public hass!: HomeAssistant; @property() - public step!: ConfigFlowStepCreateEntry; + public step!: DataEntryFlowStepCreateEntry; @property() public devices!: DeviceRegistryEntry[]; @@ -42,24 +44,11 @@ class StepFlowCreateEntry extends LitElement { protected render(): TemplateResult | void { const localize = this.hass.localize; - const step = this.step; - - const description = localizeKey( - localize, - `component.${step.handler}.config.create_entry.${step.description || - "default"}`, - step.description_placeholders - ); return html`

Success!

- ${description - ? html` - - ` - : ""} -

Created config for ${step.title}.

+ ${this.flowConfig.renderCreateEntryDescription(this.hass, this.step)} ${this.devices.length === 0 ? "" : html` diff --git a/src/dialogs/config-flow/step-flow-external.ts b/src/dialogs/config-flow/step-flow-external.ts index 51175ce755..47cd149705 100644 --- a/src/dialogs/config-flow/step-flow-external.ts +++ b/src/dialogs/config-flow/step-flow-external.ts @@ -9,51 +9,34 @@ import { } from "lit-element"; import "@material/mwc-button"; -import { - ConfigFlowStepExternal, - DataEntryFlowProgressedEvent, - fetchConfigFlow, -} from "../../data/config_entries"; import { HomeAssistant } from "../../types"; -import { localizeKey } from "../../common/translations/localize"; import { fireEvent } from "../../common/dom/fire_event"; import { configFlowContentStyles } from "./styles"; +import { + DataEntryFlowStepExternal, + DataEntryFlowProgressedEvent, +} from "../../data/data_entry_flow"; +import { FlowConfig } from "./show-dialog-data-entry-flow"; @customElement("step-flow-external") class StepFlowExternal extends LitElement { + public flowConfig!: FlowConfig; + @property() public hass!: HomeAssistant; @property() - private step!: ConfigFlowStepExternal; + private step!: DataEntryFlowStepExternal; protected render(): TemplateResult | void { const localize = this.hass.localize; - const step = this.step; - - const description = localizeKey( - localize, - `component.${step.handler}.config.${step.step_id}.description`, - step.description_placeholders - ); return html`

- ${localize( - `component.${step.handler}.config.step.${step.step_id}.title` - )} + ${this.flowConfig.renderExternalStepHeader(this.hass, this.step)}

-

- ${localize( - "ui.panel.config.integrations.config_flow.external_step.description" - )} -

- ${description - ? html` - - ` - : ""} + ${this.flowConfig.renderExternalStepDescription(this.hass, this.step)}
@@ -76,7 +59,7 @@ class StepFlowExternal extends LitElement { } fireEvent(this, "flow-update", { - stepPromise: fetchConfigFlow(this.hass, this.step.flow_id), + stepPromise: this.flowConfig.fetchFlow(this.hass, this.step.flow_id), }); }, "data_entry_flow_progressed" diff --git a/src/dialogs/config-flow/step-flow-form.ts b/src/dialogs/config-flow/step-flow-form.ts index 9e24395f33..e492125650 100644 --- a/src/dialogs/config-flow/step-flow-form.ts +++ b/src/dialogs/config-flow/step-flow-form.ts @@ -15,21 +15,19 @@ import "@polymer/paper-spinner/paper-spinner"; import "../../components/ha-form"; import "../../components/ha-markdown"; import "../../resources/ha-style"; -import { - handleConfigFlowStep, - FieldSchema, - ConfigFlowStepForm, -} from "../../data/config_entries"; import { PolymerChangedEvent, applyPolymerEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; import { fireEvent } from "../../common/dom/fire_event"; -import { localizeKey } from "../../common/translations/localize"; import { configFlowContentStyles } from "./styles"; +import { DataEntryFlowStepForm, FieldSchema } from "../../data/data_entry_flow"; +import { FlowConfig } from "./show-dialog-data-entry-flow"; @customElement("step-flow-form") class StepFlowForm extends LitElement { + public flowConfig!: FlowConfig; + @property() - public step!: ConfigFlowStepForm; + public step!: DataEntryFlowStepForm; @property() public hass!: HomeAssistant; @@ -44,7 +42,6 @@ class StepFlowForm extends LitElement { private _errorMsg?: string; protected render(): TemplateResult | void { - const localize = this.hass.localize; const step = this.step; const allRequiredInfoFilledIn = @@ -59,17 +56,9 @@ class StepFlowForm extends LitElement { !["", undefined].includes(this._stepData![field.name]) ); - const description = localizeKey( - localize, - `component.${step.handler}.config.step.${step.step_id}.description`, - step.description_placeholders - ); - return html`

- ${localize( - `component.${step.handler}.config.step.${step.step_id}.title` - )} + ${this.flowConfig.renderShowFormStepHeader(this.hass, this.step)}

${this._errorMsg @@ -77,11 +66,7 @@ class StepFlowForm extends LitElement {
${this._errorMsg}
` : ""} - ${description - ? html` - - ` - : ""} + ${this.flowConfig.renderShowFormStepDescription(this.hass, this.step)} { - const step = this.step as ConfigFlowStepForm; - - return this.hass.localize( - `component.${step.handler}.config.step.${step.step_id}.data.${ - schema.name - }` - ); - }; + private _labelCallback = (field: FieldSchema): string => + this.flowConfig.renderShowFormStepFieldLabel(this.hass, this.step, field); private _errorCallback = (error: string) => - this.hass.localize(`component.${this.step.handler}.config.error.${error}`); + this.flowConfig.renderShowFormStepFieldError(this.hass, this.step, error); static get styles(): CSSResultArray { return [ diff --git a/src/dialogs/config-flow/step-flow-pick-handler.ts b/src/dialogs/config-flow/step-flow-pick-handler.ts index 7edc2b1f35..ef60141ba2 100644 --- a/src/dialogs/config-flow/step-flow-pick-handler.ts +++ b/src/dialogs/config-flow/step-flow-pick-handler.ts @@ -11,7 +11,6 @@ import "@polymer/paper-spinner/paper-spinner-lite"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; import { HomeAssistant } from "../../types"; -import { createConfigFlow } from "../../data/config_entries"; import { fireEvent } from "../../common/dom/fire_event"; import memoizeOne from "memoize-one"; import * as Fuse from "fuse.js"; @@ -19,6 +18,7 @@ import * as Fuse from "fuse.js"; import "../../components/ha-icon-next"; import "../../common/search/search-input"; import { styleMap } from "lit-html/directives/style-map"; +import { FlowConfig } from "./show-dialog-data-entry-flow"; interface HandlerObj { name: string; @@ -27,6 +27,8 @@ interface HandlerObj { @customElement("step-flow-pick-handler") class StepFlowPickHandler extends LitElement { + public flowConfig!: FlowConfig; + @property() public hass!: HomeAssistant; @property() public handlers!: string[]; @property() private filter?: string; @@ -97,7 +99,10 @@ class StepFlowPickHandler extends LitElement { private async _handlerPicked(ev) { fireEvent(this, "flow-update", { - stepPromise: createConfigFlow(this.hass, ev.currentTarget.handler.slug), + stepPromise: this.flowConfig.createFlow( + this.hass, + ev.currentTarget.handler.slug + ), }); } diff --git a/src/onboarding/onboarding-integrations.ts b/src/onboarding/onboarding-integrations.ts index c6a9e1b332..b8de3d44bb 100644 --- a/src/onboarding/onboarding-integrations.ts +++ b/src/onboarding/onboarding-integrations.ts @@ -18,7 +18,6 @@ import { getConfigFlowsInProgress, getConfigEntries, ConfigEntry, - ConfigFlowProgress, localizeConfigFlowTitle, } from "../data/config_entries"; import { compare } from "../common/string/compare"; @@ -28,13 +27,14 @@ import { debounce } from "../common/util/debounce"; import { fireEvent } from "../common/dom/fire_event"; import { onboardIntegrationStep } from "../data/onboarding"; import { genClientId } from "home-assistant-js-websocket"; +import { DataEntryFlowProgress } from "../data/data_entry_flow"; @customElement("onboarding-integrations") class OnboardingIntegrations extends LitElement { @property() public hass!: HomeAssistant; @property() public onboardingLocalize!: LocalizeFunc; @property() private _entries?: ConfigEntry[]; - @property() private _discovered?: ConfigFlowProgress[]; + @property() private _discovered?: DataEntryFlowProgress[]; private _unsubEvents?: () => void; public connectedCallback() {