Update Assist config page (#22338)

This commit is contained in:
Paulus Schoutsen 2024-10-15 15:32:21 -04:00 committed by GitHub
parent 79ac2a72fa
commit 9e509e3bc9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 143 additions and 147 deletions

View File

@ -8,7 +8,6 @@ import "../../components/ha-tts-voice-picker";
import {
AssistPipeline,
listAssistPipelines,
setAssistPipelinePreferred,
updateAssistPipeline,
} from "../../data/assist_pipeline";
import {
@ -17,13 +16,13 @@ import {
setWakeWords,
} from "../../data/assist_satellite";
import { fetchCloudStatus } from "../../data/cloud";
import { InputSelectEntity } from "../../data/input_select";
import { setSelectOption } from "../../data/select";
import { showVoiceAssistantPipelineDetailDialog } from "../../panels/config/voice-assistants/show-dialog-voice-assistant-pipeline-detail";
import "../../panels/lovelace/entity-rows/hui-select-entity-row";
import { HomeAssistant } from "../../types";
import { AssistantSetupStyles } from "./styles";
import { STEP } from "./voice-assistant-setup-dialog";
import { setSelectOption } from "../../data/select";
import { InputSelectEntity } from "../../data/input_select";
@customElement("ha-voice-assistant-setup-step-success")
export class HaVoiceAssistantSetupStepSuccess extends LitElement {
@ -233,7 +232,7 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
}
private async _openPipeline() {
const [pipeline, preferred_pipeline] = await this._getPipeline();
const [pipeline] = await this._getPipeline();
if (!pipeline) {
return;
@ -245,13 +244,9 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
cloudActiveSubscription:
cloudStatus.logged_in && cloudStatus.active_subscription,
pipeline,
preferred: pipeline.id === preferred_pipeline,
updatePipeline: async (values) => {
await updateAssistPipeline(this.hass!, pipeline!.id, values);
},
setPipelinePreferred: async () => {
await setAssistPipelinePreferred(this.hass!, pipeline!.id);
},
hideWakeWord: true,
});
}

View File

@ -1,13 +1,22 @@
import "@material/mwc-list/mwc-list";
import { mdiHelpCircle, mdiPlus, mdiStar } from "@mdi/js";
import {
mdiBug,
mdiCommentProcessingOutline,
mdiDotsVertical,
mdiHelpCircle,
mdiPlus,
mdiStar,
mdiTrashCan,
} from "@mdi/js";
import { CSSResultGroup, LitElement, PropertyValues, css, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { formatLanguageCode } from "../../../common/language/format_language";
import "../../../components/ha-alert";
import "../../../components/ha-button";
import "../../../components/ha-button-menu";
import "../../../components/ha-card";
import "../../../components/ha-icon-next";
import "../../../components/ha-icon-button";
import "../../../components/ha-list-item";
import "../../../components/ha-svg-icon";
import "../../../components/ha-switch";
@ -23,11 +32,16 @@ import {
} from "../../../data/assist_pipeline";
import { CloudStatus } from "../../../data/cloud";
import { ExposeEntitySettings } from "../../../data/expose";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
import { documentationUrl } from "../../../util/documentation-url";
import { showVoiceAssistantPipelineDetailDialog } from "./show-dialog-voice-assistant-pipeline-detail";
import { showVoiceCommandDialog } from "../../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
import { stopPropagation } from "../../../common/dom/stop_propagation";
@customElement("assist-pref")
export class AssistPref extends LitElement {
@ -101,20 +115,71 @@ export class AssistPref extends LitElement {
twoline
hasMeta
role="button"
@click=${this._editPipeline}
.id=${pipeline.id}
@click=${this._editPipeline}
>
${pipeline.name}
<span>
${pipeline.name}
${this._preferred === pipeline.id
? html`<ha-svg-icon .path=${mdiStar}></ha-svg-icon>`
: ""}
</span>
<span slot="secondary">
${formatLanguageCode(pipeline.language, this.hass.locale)}
</span>
${this._preferred === pipeline.id
? html`<ha-svg-icon
slot="meta"
.path=${mdiStar}
></ha-svg-icon>`
: ""}
<ha-icon-next slot="meta"></ha-icon-next>
<ha-button-menu fixed slot="meta" @click=${stopPropagation}>
<ha-icon-button
slot="trigger"
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.menu.open"
)}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item
graphic="icon"
.id=${pipeline.id}
@request-selected=${this._talkWithPipeline}
>
${this.hass!.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.start_conversation"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiCommentProcessingOutline}
></ha-svg-icon>
</ha-list-item>
<ha-list-item
graphic="icon"
.disabled=${this._preferred === pipeline.id}
.id=${pipeline.id}
@request-selected=${this._setPreferredPipeline}
>
${this.hass.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.detail.set_as_preferred"
)}
<ha-svg-icon slot="graphic" .path=${mdiStar}></ha-svg-icon>
</ha-list-item>
<a href=${`/config/voice-assistants/debug/${pipeline.id}`}>
<ha-list-item graphic="icon">
${this.hass.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.detail.debug"
)}
<ha-svg-icon slot="graphic" .path=${mdiBug}></ha-svg-icon>
</ha-list-item>
</a>
<ha-list-item
class="danger"
graphic="icon"
.id=${pipeline.id}
@request-selected=${this._deletePipeline}
>
${this.hass.localize("ui.common.delete")}
<ha-svg-icon
slot="graphic"
.path=${mdiTrashCan}
></ha-svg-icon>
</ha-list-item>
</ha-button-menu>
</ha-list-item>
`
)}
@ -157,6 +222,49 @@ export class AssistPref extends LitElement {
`;
}
private _talkWithPipeline(ev) {
const id = ev.currentTarget.id as string;
showVoiceCommandDialog(this, this.hass, { pipeline_id: id });
}
private async _setPreferredPipeline(ev) {
const id = ev.currentTarget.id as string;
await setAssistPipelinePreferred(this.hass!, id);
this._preferred = id;
}
private async _deletePipeline(ev) {
const id = ev.currentTarget.id as string;
if (this._preferred === id) {
showAlertDialog(this, {
text: this.hass!.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.delete.error_preferred"
),
});
return;
}
const pipeline = this._pipelines.find((res) => res.id === id);
if (
!(await showConfirmationDialog(this, {
title: this.hass!.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.delete.confirm_title",
{ name: pipeline!.name }
),
text: this.hass!.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.delete.confirm_text",
{ name: pipeline!.name }
),
confirmText: this.hass!.localize("ui.common.delete"),
destructive: true,
}))
) {
return;
}
await deleteAssistPipeline(this.hass!, pipeline!.id);
this._pipelines = this._pipelines!.filter((res) => res !== pipeline);
}
private _editPipeline(ev) {
const id = ev.currentTarget.id as string;
@ -173,7 +281,6 @@ export class AssistPref extends LitElement {
cloudActiveSubscription:
this.cloudStatus?.logged_in && this.cloudStatus.active_subscription,
pipeline,
preferred: pipeline?.id === this._preferred,
createPipeline: async (values) => {
const created = await createAssistPipeline(this.hass!, values);
this._pipelines = this._pipelines!.concat(created);
@ -188,32 +295,6 @@ export class AssistPref extends LitElement {
res === pipeline ? updated : res
);
},
setPipelinePreferred: async () => {
await setAssistPipelinePreferred(this.hass!, pipeline!.id);
this._preferred = pipeline!.id;
},
deletePipeline: async () => {
if (
!(await showConfirmationDialog(this, {
title: this.hass!.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.delete.confirm_title",
{ name: pipeline!.name }
),
text: this.hass!.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.delete.confirm_text",
{ name: pipeline!.name }
),
confirmText: this.hass!.localize("ui.common.delete"),
destructive: true,
}))
) {
return false;
}
await deleteAssistPipeline(this.hass!, pipeline!.id);
this._pipelines = this._pipelines!.filter((res) => res !== pipeline);
return true;
},
});
}
@ -242,11 +323,23 @@ export class AssistPref extends LitElement {
ha-list-item {
--mdc-list-item-meta-size: auto;
--mdc-list-item-meta-display: flex;
--mdc-list-side-padding-right: 8px;
}
ha-svg-icon,
ha-icon-next {
width: 24px;
ha-list-item.danger {
color: var(--error-color);
border-top: 1px solid var(--divider-color);
}
ha-button-menu a {
text-decoration: none;
}
ha-svg-icon {
color: currentColor;
width: 16px;
}
.add {
margin: 0 16px 16px;
}

View File

@ -1,16 +1,7 @@
import {
mdiBug,
mdiClose,
mdiDotsVertical,
mdiStar,
mdiStarOutline,
} from "@mdi/js";
import { mdiClose } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
import { navigate } from "../../../common/navigate";
import "../../../components/ha-button";
import "../../../components/ha-dialog-header";
import "../../../components/ha-form/ha-form";
@ -38,8 +29,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
@state() private _data?: Partial<AssistPipeline>;
@state() private _preferred?: boolean;
@state() private _cloudActive?: boolean;
@state() private _error?: Record<string, string>;
@ -54,7 +43,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
this._cloudActive = this._params.cloudActiveSubscription;
if (this._params.pipeline) {
this._data = this._params.pipeline;
this._preferred = this._params.preferred;
return;
}
@ -129,39 +117,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
.path=${mdiClose}
></ha-icon-button>
<span slot="title" .title=${title}>${title}</span>
${this._params.pipeline?.id
? html`
<ha-icon-button
slot="actionItems"
.label=${this.hass.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.detail.set_as_preferred"
)}
.path=${this._preferred ? mdiStar : mdiStarOutline}
@click=${this._setPreferred}
.disabled=${Boolean(this._preferred)}
></ha-icon-button>
<ha-button-menu
corner="BOTTOM_END"
menuCorner="END"
slot="actionItems"
@closed=${stopPropagation}
fixed
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item graphic="icon" @request-selected=${this._debug}>
${this.hass.localize(
"ui.panel.config.voice_assistants.assistants.pipeline.detail.debug"
)}
<ha-svg-icon slot="graphic" .path=${mdiBug}></ha-svg-icon>
</ha-list-item>
</ha-button-menu>
`
: nothing}
</ha-dialog-header>
<div class="content">
${this._error
@ -173,7 +128,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
.supportedLanguages=${this._supportedLanguages}
keys="name,language"
@value-changed=${this._valueChanged}
dialogInitialFocus
?dialogInitialFocus=${!this._params.pipeline?.id}
></assist-pipeline-detail-config>
<assist-pipeline-detail-conversation
.hass=${this.hass}
@ -224,18 +179,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
@value-changed=${this._valueChanged}
></assist-pipeline-detail-wakeword>`}
</div>
${this._params.pipeline?.id && this._params.deletePipeline
? html`
<ha-button
slot="secondaryAction"
class="warning"
.disabled=${this._preferred || this._submitting}
@click=${this._deletePipeline}
>
${this.hass.localize("ui.common.delete")}
</ha-button>
`
: nothing}
<ha-button
slot="primaryAction"
@click=${this._updatePipeline}
@ -299,40 +242,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
}
}
private async _setPreferred() {
this._submitting = true;
try {
await this._params!.setPipelinePreferred();
this._preferred = true;
} catch (err: any) {
this._error = err?.message || "Unknown error";
} finally {
this._submitting = false;
}
}
private _debug(ev) {
if (!shouldHandleRequestSelectedEvent(ev)) return;
navigate(`/config/voice-assistants/debug/${this._params!.pipeline!.id}`);
this.closeDialog();
}
private async _deletePipeline() {
if (!this._params?.deletePipeline) {
return;
}
this._submitting = true;
try {
if (await this._params!.deletePipeline()) {
this.closeDialog();
}
} catch (err: any) {
this._error = err?.message || "Unknown error";
} finally {
this._submitting = false;
}
}
static get styles(): CSSResultGroup {
return [
haStyleDialog,

View File

@ -7,12 +7,9 @@ import {
export interface VoiceAssistantPipelineDetailsDialogParams {
cloudActiveSubscription?: boolean;
pipeline?: AssistPipeline;
preferred?: boolean;
hideWakeWord?: boolean;
updatePipeline: (updates: AssistPipelineMutableParams) => Promise<unknown>;
setPipelinePreferred: () => Promise<unknown>;
createPipeline?: (values: AssistPipelineMutableParams) => Promise<unknown>;
deletePipeline?: () => Promise<boolean>;
}
export const loadVoiceAssistantPipelineDetailDialog = () =>

View File

@ -2616,8 +2616,10 @@
"assist_devices": "{number} Assist {number, plural,\n one {device}\n other {devices}\n}",
"delete": {
"confirm_title": "Delete {name}?",
"confirm_text": "{name} will be permanently deleted."
"confirm_text": "{name} will be permanently deleted.",
"error_preferred": "You cannot delete the preferred assistant"
},
"start_conversation": "Start conversation",
"devices": {
"title": "Assist devices",
"device": "Device",