mirror of
https://github.com/home-assistant/frontend.git
synced 2026-10-13 16:37:14 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d185e5ee37 |
No files matched your search
@@ -4,14 +4,13 @@ import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { debounce } from "../common/util/debounce";
|
||||
import type { ConfigEntry, SubEntry } from "../data/config_entries";
|
||||
import { getConfigEntry, getSubEntries } from "../data/config_entries";
|
||||
import type { Agent } from "../data/conversation";
|
||||
import { listAgents } from "../data/conversation";
|
||||
import { getExtendedEntityRegistryEntry } from "../data/entity/entity_registry";
|
||||
import { fetchIntegrationManifest } from "../data/integration";
|
||||
import { showOptionsFlowDialog } from "../dialogs/config-flow/show-dialog-options-flow";
|
||||
import { showSubConfigFlowDialog } from "../dialogs/config-flow/show-dialog-sub-config-flow";
|
||||
import type { EntityConfigFlow } from "../dialogs/config-flow/entity-config-flow";
|
||||
import {
|
||||
fetchEntityConfigFlow,
|
||||
showEntityConfigFlow,
|
||||
} from "../dialogs/config-flow/entity-config-flow";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import "./ha-select";
|
||||
import type { HaSelectOption, HaSelectSelectEvent } from "./ha-select";
|
||||
@@ -34,9 +33,7 @@ export class HaConversationAgentPicker extends LitElement {
|
||||
|
||||
@state() _agents?: Agent[];
|
||||
|
||||
@state() private _configEntry?: ConfigEntry;
|
||||
|
||||
@state() private _subConfigEntry?: SubEntry;
|
||||
@state() private _configFlow?: EntityConfigFlow;
|
||||
|
||||
protected render() {
|
||||
if (!this._agents) {
|
||||
@@ -79,16 +76,15 @@ export class HaConversationAgentPicker extends LitElement {
|
||||
.options=${options}
|
||||
></ha-select
|
||||
>${
|
||||
(this._subConfigEntry &&
|
||||
this._configEntry?.supported_subentry_types[
|
||||
this._subConfigEntry.subentry_type
|
||||
]?.supports_reconfigure) ||
|
||||
this._configEntry?.supports_options
|
||||
this._configFlow
|
||||
? html`<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.conversation-agent-picker.settings"
|
||||
)}
|
||||
.path=${mdiCog}
|
||||
@click=${this._openOptionsFlow}
|
||||
@click=${this._openConfigFlow}
|
||||
></ha-icon-button>`
|
||||
: ""
|
||||
: nothing
|
||||
}
|
||||
`;
|
||||
}
|
||||
@@ -102,40 +98,22 @@ export class HaConversationAgentPicker extends LitElement {
|
||||
}
|
||||
|
||||
if (changedProperties.has("value")) {
|
||||
this._maybeFetchConfigEntry();
|
||||
this._fetchConfigFlow();
|
||||
}
|
||||
}
|
||||
|
||||
private async _maybeFetchConfigEntry() {
|
||||
if (!this.value || !(this.value in this.hass.entities)) {
|
||||
this._configEntry = undefined;
|
||||
return;
|
||||
}
|
||||
private async _fetchConfigFlow() {
|
||||
const entityId = this.value;
|
||||
let configFlow: EntityConfigFlow | undefined;
|
||||
try {
|
||||
const regEntry = await getExtendedEntityRegistryEntry(
|
||||
this.hass,
|
||||
this.value
|
||||
);
|
||||
|
||||
if (!regEntry.config_entry_id) {
|
||||
this._configEntry = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
this._configEntry = (
|
||||
await getConfigEntry(this.hass, regEntry.config_entry_id)
|
||||
).config_entry;
|
||||
|
||||
if (!regEntry.config_subentry_id) {
|
||||
this._subConfigEntry = undefined;
|
||||
} else {
|
||||
this._subConfigEntry = (
|
||||
await getSubEntries(this.hass, regEntry.config_entry_id)
|
||||
).find((entry) => entry.subentry_id === regEntry.config_subentry_id);
|
||||
}
|
||||
configFlow = entityId
|
||||
? await fetchEntityConfigFlow(this.hass, entityId)
|
||||
: undefined;
|
||||
} catch (_err) {
|
||||
this._configEntry = undefined;
|
||||
this._subConfigEntry = undefined;
|
||||
configFlow = undefined;
|
||||
}
|
||||
if (entityId === this.value) {
|
||||
this._configFlow = configFlow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,35 +181,10 @@ export class HaConversationAgentPicker extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _openOptionsFlow() {
|
||||
if (!this._configEntry) {
|
||||
return;
|
||||
private _openConfigFlow() {
|
||||
if (this._configFlow) {
|
||||
showEntityConfigFlow(this, this.hass, this._configFlow);
|
||||
}
|
||||
|
||||
if (
|
||||
this._subConfigEntry &&
|
||||
this._configEntry.supported_subentry_types[
|
||||
this._subConfigEntry.subentry_type
|
||||
]?.supports_reconfigure
|
||||
) {
|
||||
showSubConfigFlowDialog(
|
||||
this,
|
||||
this._configEntry,
|
||||
this._subConfigEntry.subentry_type,
|
||||
{
|
||||
startFlowHandler: this._configEntry.entry_id,
|
||||
subEntryId: this._subConfigEntry.subentry_id,
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
showOptionsFlowDialog(this, this._configEntry, {
|
||||
manifest: await fetchIntegrationManifest(
|
||||
this.hass,
|
||||
this._configEntry.domain
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { ConfigEntry, SubEntry } from "../../data/config_entries";
|
||||
import { getConfigEntry, getSubEntries } from "../../data/config_entries";
|
||||
import { getExtendedEntityRegistryEntry } from "../../data/entity/entity_registry";
|
||||
import { fetchIntegrationManifest } from "../../data/integration";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { showOptionsFlowDialog } from "./show-dialog-options-flow";
|
||||
import { showSubConfigFlowDialog } from "./show-dialog-sub-config-flow";
|
||||
|
||||
export interface EntityConfigFlow {
|
||||
entry: ConfigEntry;
|
||||
subEntry?: SubEntry;
|
||||
}
|
||||
|
||||
export const fetchEntityConfigFlow = async (
|
||||
hass: HomeAssistant,
|
||||
entityId: string
|
||||
): Promise<EntityConfigFlow | undefined> => {
|
||||
if (!(entityId in hass.entities)) {
|
||||
return undefined;
|
||||
}
|
||||
const regEntry = await getExtendedEntityRegistryEntry(hass, entityId);
|
||||
if (!regEntry.config_entry_id) {
|
||||
return undefined;
|
||||
}
|
||||
const { config_entry: entry } = await getConfigEntry(
|
||||
hass,
|
||||
regEntry.config_entry_id
|
||||
);
|
||||
if (regEntry.config_subentry_id) {
|
||||
const subEntry = (await getSubEntries(hass, entry.entry_id)).find(
|
||||
(sub) => sub.subentry_id === regEntry.config_subentry_id
|
||||
);
|
||||
if (
|
||||
subEntry &&
|
||||
entry.supported_subentry_types[subEntry.subentry_type]
|
||||
?.supports_reconfigure
|
||||
) {
|
||||
return { entry, subEntry };
|
||||
}
|
||||
}
|
||||
return entry.supports_options ? { entry } : undefined;
|
||||
};
|
||||
|
||||
export const showEntityConfigFlow = async (
|
||||
element: HTMLElement,
|
||||
hass: HomeAssistant,
|
||||
{ entry, subEntry }: EntityConfigFlow
|
||||
) => {
|
||||
if (subEntry) {
|
||||
showSubConfigFlowDialog(element, entry, subEntry.subentry_type, {
|
||||
startFlowHandler: entry.entry_id,
|
||||
subEntryId: subEntry.subentry_id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
showOptionsFlowDialog(element, entry, {
|
||||
manifest: await fetchIntegrationManifest(hass, entry.domain),
|
||||
});
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import { mdiHelpCircleOutline, mdiStarFourPoints } from "@mdi/js";
|
||||
import { mdiCog, mdiHelpCircleOutline, mdiStarFourPoints } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
@@ -10,6 +10,7 @@ import type { HaProgressButton } from "../../../components/buttons/ha-progress-b
|
||||
import "../../../components/entity/ha-entity-picker";
|
||||
import type { HaEntityPicker } from "../../../components/entity/ha-entity-picker";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-settings-row";
|
||||
import {
|
||||
AITaskEntityFeature,
|
||||
@@ -17,6 +18,11 @@ import {
|
||||
saveAITaskPreferences,
|
||||
type AITaskPreferences,
|
||||
} from "../../../data/ai_task";
|
||||
import type { EntityConfigFlow } from "../../../dialogs/config-flow/entity-config-flow";
|
||||
import {
|
||||
fetchEntityConfigFlow,
|
||||
showEntityConfigFlow,
|
||||
} from "../../../dialogs/config-flow/entity-config-flow";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
|
||||
import { brandsUrl } from "../../../util/brands-url";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
@@ -36,6 +42,10 @@ export class AITaskPref extends LitElement {
|
||||
|
||||
@state() private _prefs?: AITaskPreferences;
|
||||
|
||||
@state() private _configFlows: Partial<
|
||||
Record<keyof AITaskPreferences, EntityConfigFlow>
|
||||
> = {};
|
||||
|
||||
private _gen_data_entity_id?: string | null;
|
||||
|
||||
private _gen_image_entity_id?: string | null;
|
||||
@@ -47,6 +57,8 @@ export class AITaskPref extends LitElement {
|
||||
}
|
||||
fetchAITaskPreferences(this.hass).then((prefs) => {
|
||||
this._prefs = prefs;
|
||||
this._updateConfigFlow("gen_data_entity_id");
|
||||
this._updateConfigFlow("gen_image_entity_id");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -97,18 +109,7 @@ export class AITaskPref extends LitElement {
|
||||
"ui.panel.config.ai_task.gen_data_description"
|
||||
)}
|
||||
</span>
|
||||
<ha-entity-picker
|
||||
data-name="gen_data_entity_id"
|
||||
.disabled=${
|
||||
this._prefs === undefined &&
|
||||
isComponentLoaded(this.hass.config, "ai_task")
|
||||
}
|
||||
.value=${
|
||||
this._gen_data_entity_id || this._prefs?.gen_data_entity_id
|
||||
}
|
||||
.entityFilter=${filterGenData}
|
||||
@value-changed=${this._handlePrefChange}
|
||||
></ha-entity-picker>
|
||||
${this._renderPicker("gen_data_entity_id", filterGenData)}
|
||||
</ha-settings-row>
|
||||
<ha-settings-row .narrow=${this.narrow}>
|
||||
<span slot="heading">
|
||||
@@ -119,18 +120,7 @@ export class AITaskPref extends LitElement {
|
||||
"ui.panel.config.ai_task.gen_image_description"
|
||||
)}
|
||||
</span>
|
||||
<ha-entity-picker
|
||||
data-name="gen_image_entity_id"
|
||||
.disabled=${
|
||||
this._prefs === undefined &&
|
||||
isComponentLoaded(this.hass.config, "ai_task")
|
||||
}
|
||||
.value=${
|
||||
this._gen_image_entity_id || this._prefs?.gen_image_entity_id
|
||||
}
|
||||
.entityFilter=${filterGenImage}
|
||||
@value-changed=${this._handlePrefChange}
|
||||
></ha-entity-picker>
|
||||
${this._renderPicker("gen_image_entity_id", filterGenImage)}
|
||||
</ha-settings-row>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
@@ -142,11 +132,71 @@ export class AITaskPref extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderPicker(
|
||||
key: keyof AITaskPreferences,
|
||||
entityFilter: (entity: HassEntity) => boolean
|
||||
) {
|
||||
const configFlow = this._configFlows[key];
|
||||
return html`
|
||||
<div class="picker">
|
||||
<ha-entity-picker
|
||||
data-name=${key}
|
||||
.disabled=${
|
||||
this._prefs === undefined &&
|
||||
isComponentLoaded(this.hass.config, "ai_task")
|
||||
}
|
||||
.value=${this._entityId(key)}
|
||||
.entityFilter=${entityFilter}
|
||||
@value-changed=${this._handlePrefChange}
|
||||
></ha-entity-picker>
|
||||
${
|
||||
configFlow
|
||||
? html`<ha-icon-button
|
||||
data-name=${key}
|
||||
.label=${this.hass.localize("ui.panel.config.ai_task.settings")}
|
||||
.path=${mdiCog}
|
||||
@click=${this._openConfigFlow}
|
||||
></ha-icon-button>`
|
||||
: nothing
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _entityId(key: keyof AITaskPreferences) {
|
||||
return this[`_${key}`] || this._prefs?.[key];
|
||||
}
|
||||
|
||||
private async _updateConfigFlow(key: keyof AITaskPreferences) {
|
||||
const entityId = this._entityId(key);
|
||||
let configFlow: EntityConfigFlow | undefined;
|
||||
try {
|
||||
configFlow = entityId
|
||||
? await fetchEntityConfigFlow(this.hass, entityId)
|
||||
: undefined;
|
||||
} catch (_err) {
|
||||
configFlow = undefined;
|
||||
}
|
||||
if (entityId === this._entityId(key)) {
|
||||
this._configFlows = { ...this._configFlows, [key]: configFlow };
|
||||
}
|
||||
}
|
||||
|
||||
private _handlePrefChange(ev: ValueChangedEvent<string | undefined>) {
|
||||
const input = ev.target as HaEntityPicker;
|
||||
const key = input.dataset.name as keyof AITaskPreferences;
|
||||
const value = ev.detail.value || null;
|
||||
this[`_${key}`] = value;
|
||||
this._updateConfigFlow(key);
|
||||
}
|
||||
|
||||
private _openConfigFlow(ev: Event) {
|
||||
const key = (ev.currentTarget as HTMLElement).dataset
|
||||
.name as keyof AITaskPreferences;
|
||||
const configFlow = this._configFlows[key];
|
||||
if (configFlow) {
|
||||
showEntityConfigFlow(this, this.hass, configFlow);
|
||||
}
|
||||
}
|
||||
|
||||
private async _update(ev) {
|
||||
@@ -207,12 +257,22 @@ export class AITaskPref extends LitElement {
|
||||
.card-actions {
|
||||
text-align: right;
|
||||
}
|
||||
ha-entity-picker {
|
||||
.picker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
margin-left: 16px;
|
||||
min-width: 0;
|
||||
margin-inline-start: var(--ha-space-4);
|
||||
}
|
||||
:host([narrow]) ha-entity-picker {
|
||||
margin-left: 0;
|
||||
:host([narrow]) .picker {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
.picker ha-entity-picker {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.picker ha-icon-button {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -928,7 +928,8 @@
|
||||
},
|
||||
"conversation-agent-picker": {
|
||||
"conversation_agent": "Conversation agent",
|
||||
"none": "None"
|
||||
"none": "None",
|
||||
"settings": "Agent settings"
|
||||
},
|
||||
"country-picker": {
|
||||
"country": "Country",
|
||||
@@ -3048,7 +3049,8 @@
|
||||
"gen_data_header": "Data generation tasks",
|
||||
"gen_data_description": "Suggest automation names.",
|
||||
"gen_image_header": "Image generation tasks",
|
||||
"gen_image_description": "Generate images."
|
||||
"gen_image_description": "Generate images.",
|
||||
"settings": "Task settings"
|
||||
},
|
||||
"mcp": {
|
||||
"header": "Model Context Protocol",
|
||||
|
||||
Reference in new issue
Block a user