Add support for options flows (#3491)

This commit is contained in:
Paulus Schoutsen 2019-08-15 13:34:26 -07:00 committed by GitHub
parent 200e099035
commit f458bdffe0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 145 additions and 9 deletions

View File

@ -94,3 +94,34 @@ export const localizeConfigFlowTitle = (
}); });
return localize(`component.${flow.handler}.config.flow_title`, ...args); return localize(`component.${flow.handler}.config.flow_title`, ...args);
}; };
// Options flow
export const createOptionsFlow = (hass: HomeAssistant, handler: string) =>
hass.callApi<DataEntryFlowStep>(
"POST",
"config/config_entries/options/flow",
{
handler,
}
);
export const fetchOptionsFlow = (hass: HomeAssistant, flowId: string) =>
hass.callApi<DataEntryFlowStep>(
"GET",
`config/config_entries/options/flow/${flowId}`
);
export const handleOptionsFlowStep = (
hass: HomeAssistant,
flowId: string,
data: { [key: string]: any }
) =>
hass.callApi<DataEntryFlowStep>(
"POST",
`config/config_entries/options/flow/${flowId}`,
data
);
export const deleteOptionsFlow = (hass: HomeAssistant, flowId: string) =>
hass.callApi("DELETE", `config/config_entries/options/flow/${flowId}`);

View File

@ -76,7 +76,7 @@ class DataEntryFlowDialog extends LitElement {
this._instance = instance++; this._instance = instance++;
// Create a new config flow. Show picker // Create a new config flow. Show picker
if (!params.continueFlowId) { if (!params.continueFlowId && !params.startFlowHandler) {
if (!params.flowConfig.getFlowHandlers) { if (!params.flowConfig.getFlowHandlers) {
throw new Error("No getFlowHandlers defined in flow config"); throw new Error("No getFlowHandlers defined in flow config");
} }
@ -99,10 +99,9 @@ class DataEntryFlowDialog extends LitElement {
this._loading = true; this._loading = true;
const curInstance = this._instance; const curInstance = this._instance;
const step = await params.flowConfig.fetchFlow( const step = await (params.continueFlowId
this.hass, ? params.flowConfig.fetchFlow(this.hass, params.continueFlowId)
params.continueFlowId : params.flowConfig.createFlow(this.hass, params.startFlowHandler!));
);
// Happens if second showDialog called // Happens if second showDialog called
if (curInstance !== this._instance) { if (curInstance !== this._instance) {
@ -274,9 +273,11 @@ class DataEntryFlowDialog extends LitElement {
this._params.flowConfig.deleteFlow(this.hass, this._step.flow_id); this._params.flowConfig.deleteFlow(this.hass, this._step.flow_id);
} }
this._params.dialogClosedCallback({ if (this._params.dialogClosedCallback) {
flowFinished, this._params.dialogClosedCallback({
}); flowFinished,
});
}
this._step = undefined; this._step = undefined;
this._params = undefined; this._params = undefined;

View File

@ -71,8 +71,9 @@ export interface FlowConfig {
} }
export interface DataEntryFlowDialogParams { export interface DataEntryFlowDialogParams {
startFlowHandler?: string;
continueFlowId?: string; continueFlowId?: string;
dialogClosedCallback: (params: { flowFinished: boolean }) => void; dialogClosedCallback?: (params: { flowFinished: boolean }) => void;
flowConfig: FlowConfig; flowConfig: FlowConfig;
} }

View File

@ -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`
<ha-markdown .content=${description}></ha-markdown>
`
: "";
},
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`
<p>${hass.localize(`ui.dialogs.options_flow.success.description`)}</p>
`;
},
}
);

View File

@ -11,6 +11,7 @@ import "./ha-ce-entities-card";
import { EventsMixin } from "../../../mixins/events-mixin"; import { EventsMixin } from "../../../mixins/events-mixin";
import LocalizeMixin from "../../../mixins/localize-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin";
import NavigateMixin from "../../../mixins/navigate-mixin"; import NavigateMixin from "../../../mixins/navigate-mixin";
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
class HaConfigEntryPage extends NavigateMixin( class HaConfigEntryPage extends NavigateMixin(
EventsMixin(LocalizeMixin(PolymerElement)) EventsMixin(LocalizeMixin(PolymerElement))
@ -34,6 +35,13 @@ class HaConfigEntryPage extends NavigateMixin(
} }
</style> </style>
<hass-subpage header="[[configEntry.title]]"> <hass-subpage header="[[configEntry.title]]">
<template is="dom-if" if="[[configEntry.supports_options]]">
<paper-icon-button
slot="toolbar-icon"
icon="hass:settings"
on-click="_showSettings"
></paper-icon-button>
</template>
<paper-icon-button <paper-icon-button
slot="toolbar-icon" slot="toolbar-icon"
icon="hass:delete" icon="hass:delete"
@ -141,6 +149,10 @@ class HaConfigEntryPage extends NavigateMixin(
return configEntryDevices.length === 0 && noDeviceEntities.length === 0; return configEntryDevices.length === 0 && noDeviceEntities.length === 0;
} }
_showSettings() {
showOptionsFlowDialog(this, this.configEntry);
}
_removeEntry() { _removeEntry() {
if ( if (
!confirm( !confirm(

View File

@ -530,6 +530,14 @@
"save": "Save", "save": "Save",
"name": "Name Override", "name": "Name Override",
"entity_id": "Entity ID" "entity_id": "Entity ID"
},
"options_flow": {
"form": {
"header": "Options"
},
"success": {
"description": "Options successfully saved."
}
} }
}, },
"duration": { "duration": {