From 088cc6908393ac96c4e9c147f971d45c03e8d554 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 20 Apr 2023 11:41:47 +0200 Subject: [PATCH] Add pipeline picker/selector (#16224) Co-authored-by: Paul Bottein --- src/components/ha-assist-pipeline-picker.ts | 107 ++++++++++++++++++ .../ha-selector-assist-pipeline.ts | 45 ++++++++ src/components/ha-selector/ha-selector.ts | 1 + src/data/selector.ts | 6 + .../debug/assist-pipeline-run-debug.ts | 50 ++++---- .../dialog-voice-assistant-pipeline-detail.ts | 2 +- src/translations/en.json | 4 + 7 files changed, 189 insertions(+), 26 deletions(-) create mode 100644 src/components/ha-assist-pipeline-picker.ts create mode 100644 src/components/ha-selector/ha-selector-assist-pipeline.ts diff --git a/src/components/ha-assist-pipeline-picker.ts b/src/components/ha-assist-pipeline-picker.ts new file mode 100644 index 0000000000..21a1f9bb00 --- /dev/null +++ b/src/components/ha-assist-pipeline-picker.ts @@ -0,0 +1,107 @@ +import { + css, + CSSResultGroup, + html, + LitElement, + nothing, + PropertyValueMap, +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { fireEvent } from "../common/dom/fire_event"; +import { stopPropagation } from "../common/dom/stop_propagation"; +import { AssistPipeline, fetchAssistPipelines } from "../data/assist_pipeline"; +import { HomeAssistant } from "../types"; +import "./ha-list-item"; +import "./ha-select"; +import type { HaSelect } from "./ha-select"; + +const PREFERRED = "__PREFERRED_PIPELINE_OPTION__"; + +@customElement("ha-assist-pipeline-picker") +export class HaAssistPipelinePicker extends LitElement { + @property() public value?: string; + + @property() public label?: string; + + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ type: Boolean, reflect: true }) public disabled = false; + + @property({ type: Boolean }) public required = false; + + @state() _pipelines?: AssistPipeline[]; + + @state() _preferredPipeline: string | null = null; + + protected render() { + if (!this._pipelines) { + return nothing; + } + const value = this.value ?? PREFERRED; + return html` + + + ${this.hass!.localize("ui.components.pipeline-picker.preferred", { + preferred: this._pipelines.find( + (pipeline) => pipeline.id === this._preferredPipeline + )?.name, + })} + + ${this._pipelines.map( + (pipeline) => + html` + ${pipeline.name} (${pipeline.language}) + ` + )} + + `; + } + + protected firstUpdated( + changedProperties: PropertyValueMap | Map + ): void { + super.firstUpdated(changedProperties); + fetchAssistPipelines(this.hass).then((pipelines) => { + this._pipelines = pipelines.pipelines; + this._preferredPipeline = pipelines.preferred_pipeline; + }); + } + + static get styles(): CSSResultGroup { + return css` + ha-select { + width: 100%; + } + `; + } + + private _changed(ev): void { + const target = ev.target as HaSelect; + if ( + !this.hass || + target.value === "" || + target.value === this.value || + (this.value === undefined && target.value === PREFERRED) + ) { + return; + } + this.value = target.value === PREFERRED ? undefined : target.value; + fireEvent(this, "value-changed", { value: this.value }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-assist-pipeline-picker": HaAssistPipelinePicker; + } +} diff --git a/src/components/ha-selector/ha-selector-assist-pipeline.ts b/src/components/ha-selector/ha-selector-assist-pipeline.ts new file mode 100644 index 0000000000..74a143b819 --- /dev/null +++ b/src/components/ha-selector/ha-selector-assist-pipeline.ts @@ -0,0 +1,45 @@ +import { css, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; +import { AssistPipelineSelector } from "../../data/selector"; +import { HomeAssistant } from "../../types"; +import "../ha-assist-pipeline-picker"; + +@customElement("ha-selector-assist_pipeline") +export class HaAssistPipelineSelector extends LitElement { + @property() public hass!: HomeAssistant; + + @property() public selector!: AssistPipelineSelector; + + @property() public value?: any; + + @property() public label?: string; + + @property() public helper?: string; + + @property({ type: Boolean }) public disabled = false; + + @property({ type: Boolean }) public required = true; + + protected render() { + return html``; + } + + static styles = css` + ha-conversation-agent-picker { + width: 100%; + } + `; +} + +declare global { + interface HTMLElementTagNameMap { + "ha-selector-assist_pipeline": HaAssistPipelineSelector; + } +} diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts index 46ee4b30ef..72a76e31b6 100644 --- a/src/components/ha-selector/ha-selector.ts +++ b/src/components/ha-selector/ha-selector.ts @@ -14,6 +14,7 @@ const LOAD_ELEMENTS = { addon: () => import("./ha-selector-addon"), area: () => import("./ha-selector-area"), attribute: () => import("./ha-selector-attribute"), + assist_pipeline: () => import("./ha-selector-assist-pipeline"), boolean: () => import("./ha-selector-boolean"), color_rgb: () => import("./ha-selector-color-rgb"), config_entry: () => import("./ha-selector-config-entry"), diff --git a/src/data/selector.ts b/src/data/selector.ts index 66ff5b0121..c4a08644fa 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -31,6 +31,7 @@ export type Selector = | NavigationSelector | NumberSelector | ObjectSelector + | AssistPipelineSelector | SelectSelector | StateSelector | StatisticSelector @@ -256,6 +257,11 @@ export interface ObjectSelector { object: {} | null; } +export interface AssistPipelineSelector { + // eslint-disable-next-line @typescript-eslint/ban-types + assist_pipeline: {} | null; +} + export interface SelectOption { value: any; label: string; diff --git a/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts b/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts index 2f67415dbe..d2462f11a8 100644 --- a/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts +++ b/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts @@ -1,26 +1,27 @@ import { css, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators"; +import { extractSearchParam } from "../../../../common/url/search-params"; import "../../../../components/ha-button"; +import "../../../../components/ha-checkbox"; +import type { HaCheckbox } from "../../../../components/ha-checkbox"; +import "../../../../components/ha-formfield"; +import "../../../../components/ha-assist-pipeline-picker"; +import "../../../../components/ha-textfield"; +import type { HaTextField } from "../../../../components/ha-textfield"; import { PipelineRun, PipelineRunOptions, runAssistPipeline, } from "../../../../data/assist_pipeline"; -import "../../../../layouts/hass-subpage"; -import "../../../../components/ha-formfield"; -import "../../../../components/ha-checkbox"; -import { haStyle } from "../../../../resources/styles"; -import type { HomeAssistant } from "../../../../types"; import { showAlertDialog, showPromptDialog, } from "../../../../dialogs/generic/show-dialog-box"; -import "./assist-render-pipeline-run"; -import type { HaCheckbox } from "../../../../components/ha-checkbox"; -import type { HaTextField } from "../../../../components/ha-textfield"; -import "../../../../components/ha-textfield"; +import "../../../../layouts/hass-subpage"; +import { haStyle } from "../../../../resources/styles"; +import type { HomeAssistant } from "../../../../types"; import { fileDownload } from "../../../../util/file_download"; -import { extractSearchParam } from "../../../../common/url/search-params"; +import "./assist-render-pipeline-run"; @customElement("assist-pipeline-run-debug") export class AssistPipelineRunDebug extends LitElement { @@ -66,16 +67,17 @@ export class AssistPipelineRunDebug extends LitElement { Download ` - : html` - - Pick pipeline - - `} + : ""}
${this._pipelineRuns.length === 0 ? html` + Run Text Pipeline @@ -324,16 +326,8 @@ export class AssistPipelineRunDebug extends LitElement { ); } - private async _pickPipeline() { - const pipeline = await showPromptDialog(this, { - title: "Set pipeline", - inputLabel: "Pipeline ID", - inputType: "text", - confirmText: "Set", - }); - if (pipeline) { - this._pipelineId = pipeline; - } + private _pipelinePicked(ev) { + this._pipelineId = ev.detail.value; } static styles = [ @@ -349,8 +343,14 @@ export class AssistPipelineRunDebug extends LitElement { display: flex; justify-content: space-around; align-items: center; + flex-wrap: wrap; margin: 0 16px 16px; } + ha-pipeline-picker { + display: block; + width: 100%; + margin-bottom: 16px; + } .start-row ha-textfield { flex: 1; } diff --git a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts index fd2e7f6d7c..820c291231 100644 --- a/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts +++ b/src/panels/config/voice-assistants/dialog-voice-assistant-pipeline-detail.ts @@ -90,7 +90,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement { .disabled=${this._preferred} slot="secondaryAction" @click=${this._setPreferred} - >Set as defaultSet as preferred