Add pipeline picker/selector (#16224)

Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
This commit is contained in:
Bram Kragten 2023-04-20 11:41:47 +02:00 committed by GitHub
parent be005b4c88
commit 088cc69083
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 189 additions and 26 deletions

View File

@ -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`
<ha-select
.label=${this.label ||
this.hass!.localize("ui.components.pipeline-picker.pipeline")}
.value=${value}
.required=${this.required}
.disabled=${this.disabled}
@selected=${this._changed}
@closed=${stopPropagation}
fixedMenuPosition
naturalMenuWidth
>
<ha-list-item .value=${PREFERRED}>
${this.hass!.localize("ui.components.pipeline-picker.preferred", {
preferred: this._pipelines.find(
(pipeline) => pipeline.id === this._preferredPipeline
)?.name,
})}
</ha-list-item>
${this._pipelines.map(
(pipeline) =>
html`<ha-list-item .value=${pipeline.id}>
${pipeline.name} (${pipeline.language})
</ha-list-item>`
)}
</ha-select>
`;
}
protected firstUpdated(
changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>
): 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;
}
}

View File

@ -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`<ha-assist-pipeline-picker
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
></ha-assist-pipeline-picker>`;
}
static styles = css`
ha-conversation-agent-picker {
width: 100%;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-selector-assist_pipeline": HaAssistPipelineSelector;
}
}

View File

@ -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"),

View File

@ -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;

View File

@ -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
</ha-button>
`
: html`
<ha-button slot="toolbar-icon" @click=${this._pickPipeline}>
Pick pipeline
</ha-button>
`}
: ""}
<div class="content">
<div class="start-row">
${this._pipelineRuns.length === 0
? html`
<ha-assist-pipeline-picker
.hass=${this.hass}
.value=${this._pipelineId}
@value-changed=${this._pipelinePicked}
></ha-assist-pipeline-picker>
<ha-button raised @click=${this._runTextPipeline}>
Run Text Pipeline
</ha-button>
@ -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;
}

View File

@ -90,7 +90,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
.disabled=${this._preferred}
slot="secondaryAction"
@click=${this._setPreferred}
>Set as default</ha-button
>Set as preferred</ha-button
>
<a
href="/config/voice-assistants/debug/${this._params.pipeline

View File

@ -405,6 +405,10 @@
"conversation_agent": "Conversation agent",
"none": "None"
},
"pipeline-picker": {
"pipeline": "Assistant",
"preferred": "Preferred assistant ({preferred})"
},
"theme-picker": {
"theme": "Theme",
"no_theme": "No theme"