From f458bdffe03497d275ae82a83b8c5a27e4554234 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 15 Aug 2019 13:34:26 -0700 Subject: [PATCH] Add support for options flows (#3491) --- src/data/config_entries.ts | 31 +++++++ .../config-flow/dialog-data-entry-flow.ts | 17 ++-- .../show-dialog-data-entry-flow.ts | 3 +- .../config-flow/show-dialog-options-flow.ts | 83 +++++++++++++++++++ .../integrations/ha-config-entry-page.js | 12 +++ src/translations/en.json | 8 ++ 6 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 src/dialogs/config-flow/show-dialog-options-flow.ts diff --git a/src/data/config_entries.ts b/src/data/config_entries.ts index 1e2fd65020..c8119f1983 100644 --- a/src/data/config_entries.ts +++ b/src/data/config_entries.ts @@ -94,3 +94,34 @@ export const localizeConfigFlowTitle = ( }); return localize(`component.${flow.handler}.config.flow_title`, ...args); }; + +// Options flow + +export const createOptionsFlow = (hass: HomeAssistant, handler: string) => + hass.callApi( + "POST", + "config/config_entries/options/flow", + { + handler, + } + ); + +export const fetchOptionsFlow = (hass: HomeAssistant, flowId: string) => + hass.callApi( + "GET", + `config/config_entries/options/flow/${flowId}` + ); + +export const handleOptionsFlowStep = ( + hass: HomeAssistant, + flowId: string, + data: { [key: string]: any } +) => + hass.callApi( + "POST", + `config/config_entries/options/flow/${flowId}`, + data + ); + +export const deleteOptionsFlow = (hass: HomeAssistant, flowId: string) => + hass.callApi("DELETE", `config/config_entries/options/flow/${flowId}`); diff --git a/src/dialogs/config-flow/dialog-data-entry-flow.ts b/src/dialogs/config-flow/dialog-data-entry-flow.ts index 1c59b3b451..c10900e340 100644 --- a/src/dialogs/config-flow/dialog-data-entry-flow.ts +++ b/src/dialogs/config-flow/dialog-data-entry-flow.ts @@ -76,7 +76,7 @@ class DataEntryFlowDialog extends LitElement { this._instance = instance++; // Create a new config flow. Show picker - if (!params.continueFlowId) { + if (!params.continueFlowId && !params.startFlowHandler) { if (!params.flowConfig.getFlowHandlers) { throw new Error("No getFlowHandlers defined in flow config"); } @@ -99,10 +99,9 @@ class DataEntryFlowDialog extends LitElement { this._loading = true; const curInstance = this._instance; - const step = await params.flowConfig.fetchFlow( - this.hass, - params.continueFlowId - ); + const step = await (params.continueFlowId + ? params.flowConfig.fetchFlow(this.hass, params.continueFlowId) + : params.flowConfig.createFlow(this.hass, params.startFlowHandler!)); // Happens if second showDialog called if (curInstance !== this._instance) { @@ -274,9 +273,11 @@ class DataEntryFlowDialog extends LitElement { this._params.flowConfig.deleteFlow(this.hass, this._step.flow_id); } - this._params.dialogClosedCallback({ - flowFinished, - }); + if (this._params.dialogClosedCallback) { + this._params.dialogClosedCallback({ + flowFinished, + }); + } this._step = undefined; this._params = undefined; diff --git a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts index 072bce8083..a3609a733f 100644 --- a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts +++ b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts @@ -71,8 +71,9 @@ export interface FlowConfig { } export interface DataEntryFlowDialogParams { + startFlowHandler?: string; continueFlowId?: string; - dialogClosedCallback: (params: { flowFinished: boolean }) => void; + dialogClosedCallback?: (params: { flowFinished: boolean }) => void; flowConfig: FlowConfig; } diff --git a/src/dialogs/config-flow/show-dialog-options-flow.ts b/src/dialogs/config-flow/show-dialog-options-flow.ts new file mode 100644 index 0000000000..a4f8f5126c --- /dev/null +++ b/src/dialogs/config-flow/show-dialog-options-flow.ts @@ -0,0 +1,83 @@ +import { + fetchOptionsFlow, + handleOptionsFlowStep, + deleteOptionsFlow, + createOptionsFlow, + ConfigEntry, +} from "../../data/config_entries"; +import { html } from "lit-element"; +import { localizeKey } from "../../common/translations/localize"; +import { + showFlowDialog, + loadDataEntryFlowDialog, +} from "./show-dialog-data-entry-flow"; + +export const loadOptionsFlowDialog = loadDataEntryFlowDialog; + +export const showOptionsFlowDialog = ( + element: HTMLElement, + configEntry: ConfigEntry +): void => + showFlowDialog( + element, + { + startFlowHandler: configEntry.entry_id, + }, + { + loadDevicesAndAreas: false, + createFlow: createOptionsFlow, + fetchFlow: fetchOptionsFlow, + handleFlowStep: handleOptionsFlowStep, + deleteFlow: deleteOptionsFlow, + + renderAbortDescription(hass, step) { + const description = localizeKey( + hass.localize, + `component.${configEntry.domain}.options.abort.${step.reason}`, + step.description_placeholders + ); + + return description + ? html` + + ` + : ""; + }, + + renderShowFormStepHeader(hass, _step) { + return hass.localize(`ui.dialogs.options_flow.form.header`); + }, + + renderShowFormStepDescription(_hass, _step) { + return ""; + }, + + renderShowFormStepFieldLabel(hass, step, field) { + return hass.localize( + `component.${configEntry.domain}.options.step.${step.step_id}.data.${ + field.name + }` + ); + }, + + renderShowFormStepFieldError(hass, _step, error) { + return hass.localize( + `component.${configEntry.domain}.options.error.${error}` + ); + }, + + renderExternalStepHeader(_hass, _step) { + return ""; + }, + + renderExternalStepDescription(_hass, _step) { + return ""; + }, + + renderCreateEntryDescription(hass, _step) { + return html` +

${hass.localize(`ui.dialogs.options_flow.success.description`)}

+ `; + }, + } + ); diff --git a/src/panels/config/integrations/ha-config-entry-page.js b/src/panels/config/integrations/ha-config-entry-page.js index dcad335b18..59cb34878c 100644 --- a/src/panels/config/integrations/ha-config-entry-page.js +++ b/src/panels/config/integrations/ha-config-entry-page.js @@ -11,6 +11,7 @@ import "./ha-ce-entities-card"; import { EventsMixin } from "../../../mixins/events-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin"; import NavigateMixin from "../../../mixins/navigate-mixin"; +import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow"; class HaConfigEntryPage extends NavigateMixin( EventsMixin(LocalizeMixin(PolymerElement)) @@ -34,6 +35,13 @@ class HaConfigEntryPage extends NavigateMixin( } +