import "@material/mwc-button"; import "../../components/ha-circular-progress"; import "@polymer/paper-tooltip/paper-tooltip"; import { css, CSSResultArray, customElement, html, LitElement, property, PropertyValues, TemplateResult, } from "lit-element"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-form/ha-form"; import type { HaFormSchema } from "../../components/ha-form/ha-form"; import "../../components/ha-markdown"; import type { DataEntryFlowStepForm } from "../../data/data_entry_flow"; import type { HomeAssistant } from "../../types"; import type { FlowConfig } from "./show-dialog-data-entry-flow"; import { configFlowContentStyles } from "./styles"; @customElement("step-flow-form") class StepFlowForm extends LitElement { public flowConfig!: FlowConfig; @property() public step!: DataEntryFlowStepForm; @property() public hass!: HomeAssistant; @property() private _loading = false; @property() private _stepData?: { [key: string]: any }; @property() private _errorMsg?: string; protected render(): TemplateResult { const step = this.step; const stepData = this._stepDataProcessed; const allRequiredInfoFilledIn = stepData === undefined ? // If no data filled in, just check that any field is required step.data_schema.find((field) => !field.optional) === undefined : // If data is filled in, make sure all required fields are stepData && step.data_schema.every( (field) => field.optional || !["", undefined].includes(stepData![field.name]) ); return html`

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

${this._errorMsg ? html`
${this._errorMsg}
` : ""} ${this.flowConfig.renderShowFormStepDescription(this.hass, this.step)}
${this._loading ? html`
` : html`
${this.hass.localize( "ui.panel.config.integrations.config_flow.submit" )} ${!allRequiredInfoFilledIn ? html` ${this.hass.localize( "ui.panel.config.integrations.config_flow.not_all_required_fields" )} ` : html``}
`}
`; } protected firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); setTimeout(() => this.shadowRoot!.querySelector("ha-form")!.focus(), 0); this.addEventListener("keypress", (ev) => { if (ev.keyCode === 13) { this._submitStep(); } }); } private get _stepDataProcessed() { if (this._stepData !== undefined) { return this._stepData; } const data = {}; this.step.data_schema.forEach((field) => { if (field.description?.suggested_value) { data[field.name] = field.description.suggested_value; } else if ("default" in field) { data[field.name] = field.default; } }); this._stepData = data; return data; } private async _submitStep(): Promise { this._loading = true; this._errorMsg = undefined; const flowId = this.step.flow_id; const stepData = this._stepData || {}; const toSendData = {}; Object.keys(stepData).forEach((key) => { const value = stepData[key]; const isEmpty = [undefined, ""].includes(value); if (!isEmpty) { toSendData[key] = value; } }); try { const step = await this.flowConfig.handleFlowStep( this.hass, this.step.flow_id, toSendData ); // make sure we're still showing the same step as when we // fired off request. if (!this.step || flowId !== this.step.flow_id) { return; } fireEvent(this, "flow-update", { step, }); } catch (err) { this._errorMsg = (err && err.body && err.body.message) || "Unknown error occurred"; } finally { this._loading = false; } } private _stepDataChanged(ev: CustomEvent): void { this._stepData = ev.detail.value; } private _labelCallback = (field: HaFormSchema): string => this.flowConfig.renderShowFormStepFieldLabel(this.hass, this.step, field); private _errorCallback = (error: string) => this.flowConfig.renderShowFormStepFieldError(this.hass, this.step, error); static get styles(): CSSResultArray { return [ configFlowContentStyles, css` .error { color: red; } .submit-spinner { margin-right: 16px; } `, ]; } } declare global { interface HTMLElementTagNameMap { "step-flow-form": StepFlowForm; } }