Fix duplicated name in entity name picker and fix missing entity id support (#27538)

This commit is contained in:
Paul Bottein
2025-10-16 14:47:47 +02:00
committed by GitHub
parent 8d03ac5f64
commit 089316b8ae

View File

@@ -86,8 +86,8 @@ export class HaEntityNamePicker extends LitElement {
private _editIndex?: number; private _editIndex?: number;
private _validOptions = memoizeOne((entityId?: string) => { private _validTypes = memoizeOne((entityId?: string) => {
const options = new Set<string>(); const options = new Set<string>(["text"]);
if (!entityId) { if (!entityId) {
return options; return options;
} }
@@ -119,22 +119,22 @@ export class HaEntityNamePicker extends LitElement {
return []; return [];
} }
const options = this._validOptions(entityId); const types = this._validTypes(entityId);
const items = ( const items = (
["entity", "device", "area", "floor"] as const ["entity", "device", "area", "floor"] as const
).map<EntityNameOption>((name) => { ).map<EntityNameOption>((name) => {
const stateObj = this.hass.states[entityId]; const stateObj = this.hass.states[entityId];
const isValid = options.has(name); const isValid = types.has(name);
const primary = this.hass.localize( const primary = this.hass.localize(
`ui.components.entity.entity-name-picker.types.${name}` `ui.components.entity.entity-name-picker.types.${name}`
); );
const secondary = const secondary =
stateObj && isValid (stateObj && isValid
? this.hass.formatEntityName(stateObj, { type: name }) ? this.hass.formatEntityName(stateObj, { type: name })
: this.hass.localize( : this.hass.localize(
`ui.components.entity.entity-name-picker.types.${name}_missing` as LocalizeKeys `ui.components.entity.entity-name-picker.types.${name}_missing` as LocalizeKeys
) || "-"; )) || "-";
return { return {
primary, primary,
@@ -169,9 +169,9 @@ export class HaEntityNamePicker extends LitElement {
}; };
protected render() { protected render() {
const value = this._value; const value = this._items;
const options = this._getOptions(this.entityId); const options = this._getOptions(this.entityId);
const validOptions = this._validOptions(this.entityId); const validTypes = this._validTypes(this.entityId);
return html` return html`
${this.label ? html`<label>${this.label}</label>` : nothing} ${this.label ? html`<label>${this.label}</label>` : nothing}
@@ -185,12 +185,11 @@ export class HaEntityNamePicker extends LitElement {
> >
<ha-chip-set> <ha-chip-set>
${repeat( ${repeat(
this._value, this._items,
(item) => item, (item) => item,
(item: EntityNameItem, idx) => { (item: EntityNameItem, idx) => {
const label = this._formatItem(item); const label = this._formatItem(item);
const isValid = const isValid = validTypes.has(item.type);
item.type === "text" || validOptions.has(item.type);
return html` return html`
<ha-input-chip <ha-input-chip
data-idx=${idx} data-idx=${idx}
@@ -238,7 +237,7 @@ export class HaEntityNamePicker extends LitElement {
.hass=${this.hass} .hass=${this.hass}
.value=${""} .value=${""}
.autofocus=${this.autofocus} .autofocus=${this.autofocus}
.disabled=${this.disabled || !this.entityId} .disabled=${this.disabled}
.required=${this.required && !value.length} .required=${this.required && !value.length}
.helper=${this.helper} .helper=${this.helper}
.items=${options} .items=${options}
@@ -285,7 +284,7 @@ export class HaEntityNamePicker extends LitElement {
this._opened = true; this._opened = true;
} }
private get _value(): EntityNameItem[] { private get _items(): EntityNameItem[] {
return this._toItems(this.value); return this._toItems(this.value);
} }
@@ -318,19 +317,21 @@ export class HaEntityNamePicker extends LitElement {
const options = this._comboBox.items || []; const options = this._comboBox.items || [];
const initialItem = const initialItem =
this._editIndex != null ? this._value[this._editIndex] : undefined; this._editIndex != null ? this._items[this._editIndex] : undefined;
const initialValue = initialItem ? formatOptionValue(initialItem) : ""; const initialValue = initialItem ? formatOptionValue(initialItem) : "";
const filteredItems = this._filterSelectedOptions(options, initialValue); const filteredItems = this._filterSelectedOptions(options, initialValue);
if (initialItem && initialItem.type === "text" && initialItem.text) { if (initialItem?.type === "text" && initialItem.text) {
filteredItems.push(this._customNameOption(initialItem.text)); filteredItems.push(this._customNameOption(initialItem.text));
} }
this._comboBox.filteredItems = filteredItems; this._comboBox.filteredItems = filteredItems;
this._comboBox.setInputValue(initialValue); this._comboBox.setInputValue(initialValue);
} else { } else {
this._opened = false; this._opened = false;
this._comboBox.setInputValue("");
} }
} }
@@ -338,15 +339,16 @@ export class HaEntityNamePicker extends LitElement {
options: EntityNameOption[], options: EntityNameOption[],
current?: string current?: string
) => { ) => {
const value = this._value; const items = this._items;
const types = value.map((item) => item.type) as string[]; const excludedValues = new Set(
items
.filter((item) => UNIQUE_TYPES.has(item.type))
.map((item) => formatOptionValue(item))
);
const filteredOptions = options.filter( const filteredOptions = options.filter(
(option) => (option) => !excludedValues.has(option.value) || option.value === current
!UNIQUE_TYPES.has(option.value) ||
!types.includes(option.value) ||
option.value === current
); );
return filteredOptions; return filteredOptions;
}; };
@@ -357,16 +359,14 @@ export class HaEntityNamePicker extends LitElement {
const options = this._comboBox.items || []; const options = this._comboBox.items || [];
const currentItem = const currentItem =
this._editIndex != null ? this._value[this._editIndex] : undefined; this._editIndex != null ? this._items[this._editIndex] : undefined;
const currentValue = currentItem ? formatOptionValue(currentItem) : ""; const currentValue = currentItem ? formatOptionValue(currentItem) : "";
this._comboBox.filteredItems = this._filterSelectedOptions( let filteredItems = this._filterSelectedOptions(options, currentValue);
options,
currentValue
);
if (!filter) { if (!filter) {
this._comboBox.filteredItems = filteredItems;
return; return;
} }
@@ -378,9 +378,8 @@ export class HaEntityNamePicker extends LitElement {
ignoreDiacritics: true, ignoreDiacritics: true,
}; };
const fuse = new Fuse(this._comboBox.filteredItems, fuseOptions); const fuse = new Fuse(filteredItems, fuseOptions);
const filteredItems = fuse.search(filter).map((result) => result.item); filteredItems = fuse.search(filter).map((result) => result.item);
filteredItems.push(this._customNameOption(input)); filteredItems.push(this._customNameOption(input));
this._comboBox.filteredItems = filteredItems; this._comboBox.filteredItems = filteredItems;
} }
@@ -388,7 +387,7 @@ export class HaEntityNamePicker extends LitElement {
private async _moveItem(ev: CustomEvent) { private async _moveItem(ev: CustomEvent) {
ev.stopPropagation(); ev.stopPropagation();
const { oldIndex, newIndex } = ev.detail; const { oldIndex, newIndex } = ev.detail;
const value = this._value; const value = this._items;
const newValue = value.concat(); const newValue = value.concat();
const element = newValue.splice(oldIndex, 1)[0]; const element = newValue.splice(oldIndex, 1)[0];
newValue.splice(newIndex, 0, element); newValue.splice(newIndex, 0, element);
@@ -399,7 +398,7 @@ export class HaEntityNamePicker extends LitElement {
private async _removeItem(ev) { private async _removeItem(ev) {
ev.stopPropagation(); ev.stopPropagation();
const value = [...this._value]; const value = [...this._items];
const idx = parseInt(ev.target.dataset.idx, 10); const idx = parseInt(ev.target.dataset.idx, 10);
value.splice(idx, 1); value.splice(idx, 1);
this._setValue(value); this._setValue(value);
@@ -417,7 +416,7 @@ export class HaEntityNamePicker extends LitElement {
const item: EntityNameItem = parseOptionValue(value); const item: EntityNameItem = parseOptionValue(value);
const newValue = [...this._value]; const newValue = [...this._items];
if (this._editIndex != null) { if (this._editIndex != null) {
newValue[this._editIndex] = item; newValue[this._editIndex] = item;