mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-09 02:49:51 +00:00
* Add MVP voice assist flow * filter on supported features * check for unavailable * Update step-flow-create-entry.ts
202 lines
5.9 KiB
TypeScript
202 lines
5.9 KiB
TypeScript
import "@material/mwc-button";
|
|
import {
|
|
css,
|
|
CSSResultGroup,
|
|
html,
|
|
LitElement,
|
|
PropertyValues,
|
|
TemplateResult,
|
|
} from "lit";
|
|
import { customElement, property } from "lit/decorators";
|
|
import memoizeOne from "memoize-one";
|
|
import { fireEvent } from "../../common/dom/fire_event";
|
|
import "../../components/ha-area-picker";
|
|
import { DataEntryFlowStepCreateEntry } from "../../data/data_entry_flow";
|
|
import {
|
|
computeDeviceName,
|
|
DeviceRegistryEntry,
|
|
updateDeviceRegistryEntry,
|
|
} from "../../data/device_registry";
|
|
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
|
import { HomeAssistant } from "../../types";
|
|
import { showAlertDialog } from "../generic/show-dialog-box";
|
|
import { FlowConfig } from "./show-dialog-data-entry-flow";
|
|
import { configFlowContentStyles } from "./styles";
|
|
import { computeDomain } from "../../common/entity/compute_domain";
|
|
import { showVoiceAssistantSetupDialog } from "../voice-assistant-setup/show-voice-assistant-setup-dialog";
|
|
import { assistSatelliteSupportsSetupFlow } from "../../data/assist_satellite";
|
|
|
|
@customElement("step-flow-create-entry")
|
|
class StepFlowCreateEntry extends LitElement {
|
|
@property({ attribute: false }) public flowConfig!: FlowConfig;
|
|
|
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
|
|
@property({ attribute: false }) public step!: DataEntryFlowStepCreateEntry;
|
|
|
|
@property({ attribute: false }) public devices!: DeviceRegistryEntry[];
|
|
|
|
private _deviceEntities = memoizeOne(
|
|
(
|
|
deviceId: string,
|
|
entities: EntityRegistryDisplayEntry[],
|
|
domain?: string
|
|
): EntityRegistryDisplayEntry[] =>
|
|
entities.filter(
|
|
(entity) =>
|
|
entity.device_id === deviceId &&
|
|
(!domain || computeDomain(entity.entity_id) === domain)
|
|
)
|
|
);
|
|
|
|
protected willUpdate(changedProps: PropertyValues) {
|
|
if (
|
|
(changedProps.has("devices") || changedProps.has("hass")) &&
|
|
this.devices.length === 1
|
|
) {
|
|
// integration_type === "device"
|
|
const assistSatellites = this._deviceEntities(
|
|
this.devices[0].id,
|
|
Object.values(this.hass.entities),
|
|
"assist_satellite"
|
|
);
|
|
if (
|
|
assistSatellites.length &&
|
|
assistSatellites.some((satellite) =>
|
|
assistSatelliteSupportsSetupFlow(
|
|
this.hass.states[satellite.entity_id]
|
|
)
|
|
)
|
|
) {
|
|
this._flowDone();
|
|
showVoiceAssistantSetupDialog(this, {
|
|
deviceId: this.devices[0].id,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
protected render(): TemplateResult {
|
|
const localize = this.hass.localize;
|
|
|
|
return html`
|
|
<h2>${localize("ui.panel.config.integrations.config_flow.success")}!</h2>
|
|
<div class="content">
|
|
${this.flowConfig.renderCreateEntryDescription(this.hass, this.step)}
|
|
${this.step.result?.state === "not_loaded"
|
|
? html`<span class="error"
|
|
>${localize(
|
|
"ui.panel.config.integrations.config_flow.not_loaded"
|
|
)}</span
|
|
>`
|
|
: ""}
|
|
${this.devices.length === 0
|
|
? ""
|
|
: html`
|
|
<p>
|
|
${localize(
|
|
"ui.panel.config.integrations.config_flow.found_following_devices"
|
|
)}:
|
|
</p>
|
|
<div class="devices">
|
|
${this.devices.map(
|
|
(device) => html`
|
|
<div class="device">
|
|
<div>
|
|
<b>${computeDeviceName(device, this.hass)}</b><br />
|
|
${!device.model && !device.manufacturer
|
|
? html` `
|
|
: html`${device.model}
|
|
${device.manufacturer
|
|
? html`(${device.manufacturer})`
|
|
: ""}`}
|
|
</div>
|
|
<ha-area-picker
|
|
.hass=${this.hass}
|
|
.device=${device.id}
|
|
.value=${device.area_id ?? undefined}
|
|
@value-changed=${this._areaPicked}
|
|
></ha-area-picker>
|
|
</div>
|
|
`
|
|
)}
|
|
</div>
|
|
`}
|
|
</div>
|
|
<div class="buttons">
|
|
<mwc-button @click=${this._flowDone}
|
|
>${localize(
|
|
"ui.panel.config.integrations.config_flow.finish"
|
|
)}</mwc-button
|
|
>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
private _flowDone(): void {
|
|
fireEvent(this, "flow-update", { step: undefined });
|
|
}
|
|
|
|
private async _areaPicked(ev: CustomEvent) {
|
|
const picker = ev.currentTarget as any;
|
|
const device = picker.device;
|
|
|
|
const area = ev.detail.value;
|
|
try {
|
|
await updateDeviceRegistryEntry(this.hass, device, {
|
|
area_id: area,
|
|
});
|
|
} catch (err: any) {
|
|
showAlertDialog(this, {
|
|
text: this.hass.localize(
|
|
"ui.panel.config.integrations.config_flow.error_saving_area",
|
|
{ error: err.message }
|
|
),
|
|
});
|
|
picker.value = null;
|
|
}
|
|
}
|
|
|
|
static get styles(): CSSResultGroup {
|
|
return [
|
|
configFlowContentStyles,
|
|
css`
|
|
.devices {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
margin: -4px;
|
|
max-height: 600px;
|
|
overflow-y: auto;
|
|
}
|
|
.device {
|
|
border: 1px solid var(--divider-color);
|
|
padding: 5px;
|
|
border-radius: 4px;
|
|
margin: 4px;
|
|
display: inline-block;
|
|
width: 250px;
|
|
}
|
|
.buttons > *:last-child {
|
|
margin-left: auto;
|
|
margin-inline-start: auto;
|
|
margin-inline-end: initial;
|
|
}
|
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
|
.device {
|
|
width: 100%;
|
|
}
|
|
}
|
|
.error {
|
|
color: var(--error-color);
|
|
}
|
|
`,
|
|
];
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
"step-flow-create-entry": StepFlowCreateEntry;
|
|
}
|
|
}
|