@@ -5,36 +5,25 @@ import { customElement, property, query, state } from "lit/decorators";
55import memoizeOne from "memoize-one" ;
66import { fireEvent } from "../../common/dom/fire_event" ;
77import { computeAreaName } from "../../common/entity/compute_area_name" ;
8- import {
9- computeDeviceName ,
10- computeDeviceNameDisplay ,
11- } from "../../common/entity/compute_device_name" ;
12- import { computeDomain } from "../../common/entity/compute_domain" ;
8+ import { computeDeviceName } from "../../common/entity/compute_device_name" ;
139import { getDeviceContext } from "../../common/entity/context/get_device_context" ;
1410import { getConfigEntries , type ConfigEntry } from "../../data/config_entries" ;
1511import {
16- getDeviceEntityDisplayLookup ,
17- type DeviceEntityDisplayLookup ,
12+ getDevices ,
13+ type DevicePickerItem ,
1814 type DeviceRegistryEntry ,
1915} from "../../data/device_registry" ;
20- import { domainToName } from "../../data/integration" ;
2116import type { HomeAssistant } from "../../types" ;
2217import { brandsUrl } from "../../util/brands-url" ;
2318import "../ha-generic-picker" ;
2419import type { HaGenericPicker } from "../ha-generic-picker" ;
25- import type { PickerComboBoxItem } from "../ha-picker-combo-box" ;
2620
2721export type HaDevicePickerDeviceFilterFunc = (
2822 device : DeviceRegistryEntry
2923) => boolean ;
3024
3125export type HaDevicePickerEntityFilterFunc = ( entity : HassEntity ) => boolean ;
3226
33- interface DevicePickerItem extends PickerComboBoxItem {
34- domain ?: string ;
35- domain_name ?: string ;
36- }
37-
3827@customElement ( "ha-device-picker" )
3928export class HaDevicePicker extends LitElement {
4029 @property ( { attribute : false } ) public hass ! : HomeAssistant ;
@@ -104,6 +93,8 @@ export class HaDevicePicker extends LitElement {
10493
10594 @state ( ) private _configEntryLookup : Record < string , ConfigEntry > = { } ;
10695
96+ private _getDevicesMemoized = memoizeOne ( getDevices ) ;
97+
10798 protected firstUpdated ( _changedProperties : PropertyValues ) : void {
10899 super . firstUpdated ( _changedProperties ) ;
109100 this . _loadConfigEntries ( ) ;
@@ -117,162 +108,18 @@ export class HaDevicePicker extends LitElement {
117108 }
118109
119110 private _getItems = ( ) =>
120- this . _getDevices (
121- this . hass . devices ,
122- this . hass . entities ,
111+ this . _getDevicesMemoized (
112+ this . hass ,
123113 this . _configEntryLookup ,
124114 this . includeDomains ,
125115 this . excludeDomains ,
126116 this . includeDeviceClasses ,
127117 this . deviceFilter ,
128118 this . entityFilter ,
129- this . excludeDevices
119+ this . excludeDevices ,
120+ this . value
130121 ) ;
131122
132- private _getDevices = memoizeOne (
133- (
134- haDevices : HomeAssistant [ "devices" ] ,
135- haEntities : HomeAssistant [ "entities" ] ,
136- configEntryLookup : Record < string , ConfigEntry > ,
137- includeDomains : this[ "includeDomains" ] ,
138- excludeDomains : this[ "excludeDomains" ] ,
139- includeDeviceClasses : this[ "includeDeviceClasses" ] ,
140- deviceFilter : this[ "deviceFilter" ] ,
141- entityFilter : this[ "entityFilter" ] ,
142- excludeDevices : this[ "excludeDevices" ]
143- ) : DevicePickerItem [ ] => {
144- const devices = Object . values ( haDevices ) ;
145- const entities = Object . values ( haEntities ) ;
146-
147- let deviceEntityLookup : DeviceEntityDisplayLookup = { } ;
148-
149- if (
150- includeDomains ||
151- excludeDomains ||
152- includeDeviceClasses ||
153- entityFilter
154- ) {
155- deviceEntityLookup = getDeviceEntityDisplayLookup ( entities ) ;
156- }
157-
158- let inputDevices = devices . filter (
159- ( device ) => device . id === this . value || ! device . disabled_by
160- ) ;
161-
162- if ( includeDomains ) {
163- inputDevices = inputDevices . filter ( ( device ) => {
164- const devEntities = deviceEntityLookup [ device . id ] ;
165- if ( ! devEntities || ! devEntities . length ) {
166- return false ;
167- }
168- return deviceEntityLookup [ device . id ] . some ( ( entity ) =>
169- includeDomains . includes ( computeDomain ( entity . entity_id ) )
170- ) ;
171- } ) ;
172- }
173-
174- if ( excludeDomains ) {
175- inputDevices = inputDevices . filter ( ( device ) => {
176- const devEntities = deviceEntityLookup [ device . id ] ;
177- if ( ! devEntities || ! devEntities . length ) {
178- return true ;
179- }
180- return entities . every (
181- ( entity ) =>
182- ! excludeDomains . includes ( computeDomain ( entity . entity_id ) )
183- ) ;
184- } ) ;
185- }
186-
187- if ( excludeDevices ) {
188- inputDevices = inputDevices . filter (
189- ( device ) => ! excludeDevices ! . includes ( device . id )
190- ) ;
191- }
192-
193- if ( includeDeviceClasses ) {
194- inputDevices = inputDevices . filter ( ( device ) => {
195- const devEntities = deviceEntityLookup [ device . id ] ;
196- if ( ! devEntities || ! devEntities . length ) {
197- return false ;
198- }
199- return deviceEntityLookup [ device . id ] . some ( ( entity ) => {
200- const stateObj = this . hass . states [ entity . entity_id ] ;
201- if ( ! stateObj ) {
202- return false ;
203- }
204- return (
205- stateObj . attributes . device_class &&
206- includeDeviceClasses . includes ( stateObj . attributes . device_class )
207- ) ;
208- } ) ;
209- } ) ;
210- }
211-
212- if ( entityFilter ) {
213- inputDevices = inputDevices . filter ( ( device ) => {
214- const devEntities = deviceEntityLookup [ device . id ] ;
215- if ( ! devEntities || ! devEntities . length ) {
216- return false ;
217- }
218- return devEntities . some ( ( entity ) => {
219- const stateObj = this . hass . states [ entity . entity_id ] ;
220- if ( ! stateObj ) {
221- return false ;
222- }
223- return entityFilter ( stateObj ) ;
224- } ) ;
225- } ) ;
226- }
227-
228- if ( deviceFilter ) {
229- inputDevices = inputDevices . filter (
230- ( device ) =>
231- // We always want to include the device of the current value
232- device . id === this . value || deviceFilter ! ( device )
233- ) ;
234- }
235-
236- const outputDevices = inputDevices . map < DevicePickerItem > ( ( device ) => {
237- const deviceName = computeDeviceNameDisplay (
238- device ,
239- this . hass ,
240- deviceEntityLookup [ device . id ]
241- ) ;
242-
243- const { area } = getDeviceContext ( device , this . hass ) ;
244-
245- const areaName = area ? computeAreaName ( area ) : undefined ;
246-
247- const configEntry = device . primary_config_entry
248- ? configEntryLookup ?. [ device . primary_config_entry ]
249- : undefined ;
250-
251- const domain = configEntry ?. domain ;
252- const domainName = domain
253- ? domainToName ( this . hass . localize , domain )
254- : undefined ;
255-
256- return {
257- id : device . id ,
258- label : "" ,
259- primary :
260- deviceName ||
261- this . hass . localize ( "ui.components.device-picker.unnamed_device" ) ,
262- secondary : areaName ,
263- domain : configEntry ?. domain ,
264- domain_name : domainName ,
265- search_labels : [ deviceName , areaName , domain , domainName ] . filter (
266- Boolean
267- ) as string [ ] ,
268- sorting_label : deviceName || "zzz" ,
269- } ;
270- } ) ;
271-
272- return outputDevices ;
273- }
274- ) ;
275-
276123 private _valueRenderer = memoizeOne (
277124 ( configEntriesLookup : Record < string , ConfigEntry > ) => ( value : string ) => {
278125 const deviceId = value ;
0 commit comments