import "@material/mwc-button"; import "@polymer/paper-tooltip/paper-tooltip"; import { css, CSSResultGroup, html, LitElement, PropertyValues, TemplateResult, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-circular-progress"; import { computeInitialHaFormData } from "../../components/ha-form/compute-initial-ha-form-data"; import type { HaFormSchema } from "../../components/ha-form/types"; import "../../components/ha-form/ha-form"; import "../../components/ha-markdown"; import "../../components/ha-alert"; 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 { @property({ attribute: false }) public flowConfig!: FlowConfig; @property({ attribute: false }) public step!: DataEntryFlowStepForm; @property({ attribute: false }) public hass!: HomeAssistant; @state() private _loading = false; @state() private _stepData?: Record; @state() private _errorMsg?: string; protected render(): TemplateResult { const step = this.step; const stepData = this._stepDataProcessed; return html`

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

${this.flowConfig.renderShowFormStepDescription(this.hass, this.step)} ${this._errorMsg ? html`${this._errorMsg}` : ""}
${this._loading ? html`
` : html`
${this.hass.localize( `ui.panel.config.integrations.config_flow.${ this.step.last_step === false ? "next" : "submit" }` )}
`}
`; } 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; } this._stepData = computeInitialHaFormData(this.step.data_schema); return this._stepData; } private async _submitStep(): Promise { const stepData = this._stepData || {}; const allRequiredInfoFilledIn = stepData === undefined ? // If no data filled in, just check that any field is required this.step.data_schema.find((field) => field.required) === undefined : // If data is filled in, make sure all required fields are stepData && this.step.data_schema.every( (field) => !field.required || !["", undefined].includes(stepData![field.name]) ); if (!allRequiredInfoFilledIn) { this._errorMsg = this.hass.localize( "ui.panel.config.integrations.config_flow.not_all_required_fields" ); return; } this._loading = true; this._errorMsg = undefined; const flowId = this.step.flow_id; 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: any) { 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 _helperCallback = (field: HaFormSchema): string => this.flowConfig.renderShowFormStepFieldHelper(this.hass, this.step, field); private _errorCallback = (error: string) => this.flowConfig.renderShowFormStepFieldError(this.hass, this.step, error); static get styles(): CSSResultGroup { return [ configFlowContentStyles, css` .error { color: red; } .submit-spinner { margin-right: 16px; } ha-alert, ha-form { margin-top: 24px; display: block; } h2 { word-break: break-word; padding-right: 72px; } :host-context([style*="direction: rtl;"]) h2 { padding-right: auto !important; padding-left: 72px !important; } `, ]; } } declare global { interface HTMLElementTagNameMap { "step-flow-form": StepFlowForm; } }