diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts index 1161505eeb..d1a7d2b55a 100644 --- a/src/components/device/ha-device-picker.ts +++ b/src/components/device/ha-device-picker.ts @@ -38,7 +38,7 @@ export type HaDevicePickerDeviceFilterFunc = ( ) => boolean; const rowRenderer: ComboBoxLitRenderer = (item) => html` ${item.name} ${item.area} @@ -105,7 +105,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { if (!devices.length) { return [ { - id: "", + id: "no_devices", area: "", name: this.hass.localize("ui.components.device-picker.no_devices"), }, @@ -201,7 +201,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { if (!outputDevices.length) { return [ { - id: "", + id: "no_devices", area: "", name: this.hass.localize("ui.components.device-picker.no_match"), }, @@ -270,7 +270,6 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { .renderer=${rowRenderer} .disabled=${this.disabled} item-value-path="id" - item-id-path="id" item-label-path="name" @opened-changed=${this._openedChanged} @value-changed=${this._deviceChanged} @@ -284,7 +283,11 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { private _deviceChanged(ev: PolymerChangedEvent) { ev.stopPropagation(); - const newValue = ev.detail.value; + let newValue = ev.detail.value; + + if (newValue === "no_devices") { + newValue = ""; + } if (newValue !== this._value) { this._setValue(newValue); diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index a455bb988a..d24f6fbac4 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -1,25 +1,16 @@ -import { mdiCheck, mdiClose, mdiMenuDown, mdiMenuUp } from "@mdi/js"; -import "@polymer/paper-input/paper-input"; -import "@polymer/paper-item/paper-icon-item"; -import "@polymer/paper-item/paper-item-body"; -import "@vaadin/combo-box/theme/material/vaadin-combo-box-light"; +import "@material/mwc-list/mwc-list-item"; import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResultGroup, - html, - LitElement, - PropertyValues, - TemplateResult, -} from "lit"; -import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; -import { customElement, property, query } from "lit/decorators"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { ComboBoxLitRenderer } from "lit-vaadin-helpers"; +import { customElement, property, query, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import { computeDomain } from "../../common/entity/compute_domain"; import { computeStateName } from "../../common/entity/compute_state_name"; import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; +import "../ha-combo-box"; +import type { HaComboBox } from "../ha-combo-box"; import "../ha-icon-button"; import "../ha-svg-icon"; import "./state-badge"; @@ -27,35 +18,15 @@ import "./state-badge"; export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean; // eslint-disable-next-line lit/prefer-static-styles -const rowRenderer: ComboBoxLitRenderer = (item) => html` - - - - - ${computeStateName(item)} - ${item.entity_id} - - `; - +const rowRenderer: ComboBoxLitRenderer = + (item) => + html` + ${item.state + ? html`` + : ""} + ${item.friendly_name} + ${item.entity_id} + `; @customElement("ha-entity-picker") export class HaEntityPicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -107,19 +78,19 @@ export class HaEntityPicker extends LitElement { @property({ type: Boolean }) public hideClearIcon = false; - @property({ type: Boolean }) private _opened = false; + @state() private _opened = false; - @query("vaadin-combo-box-light", true) private comboBox!: HTMLElement; + @query("ha-combo-box", true) public comboBox!: HaComboBox; public open() { this.updateComplete.then(() => { - (this.shadowRoot?.querySelector("vaadin-combo-box-light") as any)?.open(); + this.comboBox?.open(); }); } public focus() { this.updateComplete.then(() => { - this.shadowRoot?.querySelector("paper-input")?.focus(); + this.comboBox?.focus(); }); } @@ -144,6 +115,27 @@ export class HaEntityPicker extends LitElement { } let entityIds = Object.keys(hass.states); + if (!entityIds.length) { + return [ + { + entity_id: "", + state: "", + last_changed: "", + last_updated: "", + context: { id: "", user_id: null }, + friendly_name: this.hass!.localize( + "ui.components.entity.entity-picker.no_entities" + ), + attributes: { + friendly_name: this.hass!.localize( + "ui.components.entity.entity-picker.no_entities" + ), + icon: "mdi:magnify", + }, + }, + ]; + } + if (includeDomains) { entityIds = entityIds.filter((eid) => includeDomains.includes(computeDomain(eid)) @@ -156,7 +148,10 @@ export class HaEntityPicker extends LitElement { ); } - states = entityIds.sort().map((key) => hass!.states[key]); + states = entityIds.sort().map((key) => ({ + ...hass!.states[key], + friendly_name: computeStateName(hass!.states[key]) || key, + })); if (includeDeviceClasses) { states = states.filter( @@ -196,6 +191,9 @@ export class HaEntityPicker extends LitElement { last_changed: "", last_updated: "", context: { id: "", user_id: null }, + friendly_name: this.hass!.localize( + "ui.components.entity.entity-picker.no_match" + ), attributes: { friendly_name: this.hass!.localize( "ui.components.entity.entity-picker.no_match" @@ -241,64 +239,25 @@ export class HaEntityPicker extends LitElement { protected render(): TemplateResult { return html` - - -
- ${this.value && !this.hideClearIcon - ? html` - - ` - : ""} - - -
-
-
+ `; } - private _clearValue(ev: Event) { - ev.stopPropagation(); - this._setValue(""); - } - private get _value() { return this.value || ""; } @@ -308,6 +267,7 @@ export class HaEntityPicker extends LitElement { } private _valueChanged(ev: PolymerChangedEvent) { + ev.stopPropagation(); const newValue = ev.detail.value; if (newValue !== this._value) { this._setValue(newValue); @@ -317,9 +277,9 @@ export class HaEntityPicker extends LitElement { private _filterChanged(ev: CustomEvent): void { const filterString = ev.detail.value.toLowerCase(); (this.comboBox as any).filteredItems = this._states.filter( - (state) => - state.entity_id.toLowerCase().includes(filterString) || - computeStateName(state).toLowerCase().includes(filterString) + (entityState) => + entityState.entity_id.toLowerCase().includes(filterString) || + computeStateName(entityState).toLowerCase().includes(filterString) ); } @@ -330,22 +290,6 @@ export class HaEntityPicker extends LitElement { fireEvent(this, "change"); }, 0); } - - static get styles(): CSSResultGroup { - return css` - .suffix { - display: flex; - } - ha-icon-button { - --mdc-icon-button-size: 24px; - padding: 0px 2px; - color: var(--secondary-text-color); - } - [hidden] { - display: none; - } - `; - } } declare global { diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index 511b46353a..6fc0f34a1f 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -67,7 +67,7 @@ export class HaStatisticPicker extends LitElement { id: string; name: string; state?: HassEntity; - }> = (item) => html` + }> = (item) => html` ${item.state ? html`` : ""} diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts index bfb39ac3da..a671893737 100644 --- a/src/components/ha-area-picker.ts +++ b/src/components/ha-area-picker.ts @@ -139,7 +139,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { if (!areas.length) { return [ { - area_id: "", + area_id: "no_areas", name: this.hass.localize("ui.components.area-picker.no_areas"), picture: null, }, @@ -263,7 +263,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { if (!outputAreas.length) { outputAreas = [ { - area_id: "", + area_id: "no_areas", name: this.hass.localize("ui.components.area-picker.no_match"), picture: null, }, @@ -369,7 +369,11 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { private _areaChanged(ev: PolymerChangedEvent) { ev.stopPropagation(); - const newValue = ev.detail.value; + let newValue = ev.detail.value; + + if (newValue === "no_areas") { + newValue = ""; + } if (!["add_new_suggestion", "add_new"].includes(newValue)) { if (newValue !== this._value) { diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts index d426ec0b49..e3eda4a3df 100644 --- a/src/components/ha-selector/ha-selector.ts +++ b/src/components/ha-selector/ha-selector.ts @@ -31,11 +31,7 @@ export class HaSelector extends LitElement { @property({ type: Boolean }) public disabled = false; public focus() { - const input = this.shadowRoot!.getElementById("selector"); - if (!input) { - return; - } - (input as HTMLElement).focus(); + this.shadowRoot!.getElementById("selector")?.focus(); } private get _type() { diff --git a/src/translations/en.json b/src/translations/en.json index 42eb7db2f6..ed8ff943bf 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -358,6 +358,7 @@ "entity": "Entity", "edit": "Edit", "clear": "Clear", + "no_entities": "You don't have any entities", "no_match": "No matching entities found", "show_entities": "Show entities" },