import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit"; import type { TemplateResult } from "lit"; import { html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import type { User } from "../../data/user"; import { fetchUsers } from "../../data/user"; import type { HomeAssistant } from "../../types"; import "../ha-combo-box-item"; import "../ha-generic-picker"; import type { PickerComboBoxItem } from "../ha-picker-combo-box"; import type { PickerValueRenderer } from "../ha-picker-field"; import "./ha-user-badge"; interface UserComboBoxItem extends PickerComboBoxItem { user?: User; } @customElement("ha-user-picker") class HaUserPicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @property() public label?: string; @property() public placeholder?: string; @property({ attribute: false }) public noUserLabel?: string; @property() public value = ""; @property({ attribute: false }) public users?: User[]; @property({ type: Boolean }) public disabled = false; protected firstUpdated(changedProps) { super.firstUpdated(changedProps); if (!this.users) { this._fetchUsers(); } } private async _fetchUsers() { this.users = await fetchUsers(this.hass); } private usersMap = memoizeOne((users?: User[]): Map => { if (!users) { return new Map(); } return new Map(users.map((user) => [user.id, user])); }); private _valueRenderer: PickerValueRenderer = (value) => { const user = this.usersMap(this.users).get(value); if (!user) { return html` ${value} `; } return html` ${user.name} `; }; private _rowRenderer: ComboBoxLitRenderer = (item) => { const user = item.user; if (!user) { return html` ${item.icon ? html`` : item.icon_path ? html`` : nothing} ${item.primary} ${item.secondary ? html`${item.secondary}` : nothing} `; } return html` ${item.primary} `; }; private _getUsers = memoizeOne((users?: User[]) => { if (!users) { return []; } return users .filter((user) => !user.system_generated) .map((user) => ({ id: user.id, primary: user.name, domain_name: user.name, search_labels: [user.name, user.id, user.username].filter( Boolean ) as string[], sorting_label: user.name, user, })); }); private _getItems = () => this._getUsers(this.users); protected render(): TemplateResult { const placeholder = this.placeholder ?? this.hass.localize("ui.components.user-picker.user"); return html` `; } private _valueChanged(ev) { const value = ev.detail.value; this.value = value; fireEvent(this, "value-changed", { value }); fireEvent(this, "change"); } private _notFoundLabel = (search: string) => this.hass.localize("ui.components.user-picker.no_match", { term: html`‘${search}’`, }); } declare global { interface HTMLElementTagNameMap { "ha-user-picker": HaUserPicker; } }