Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
11f65ef
Add new target selected value view
wendevlin Sep 9, 2025
f8cc153
Use extractFromTarget
wendevlin Sep 11, 2025
f53ee52
Fix typo
wendevlin Sep 11, 2025
f8d90d0
fix entity domain name
wendevlin Sep 11, 2025
9cdb574
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Sep 11, 2025
9a69566
Fix sublist
wendevlin Sep 12, 2025
043849b
Group floor and area, add label icon, remove remove group
wendevlin Sep 12, 2025
a5be92c
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Sep 16, 2025
e3655fe
Keep chips in history and logbook
wendevlin Sep 16, 2025
a2e99de
Do not show entities count for sub entries
wendevlin Sep 16, 2025
b149ddc
Enhance target picker with filtering options for devices and entities
wendevlin Sep 16, 2025
89ef753
Fix filtering
wendevlin Sep 17, 2025
c68d73b
Add overview dialog
wendevlin Sep 18, 2025
cf97566
Fix dialog title
wendevlin Sep 18, 2025
32e4c23
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Sep 25, 2025
b443ebf
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Sep 25, 2025
eabe7e5
WIP target picker popover
wendevlin Sep 25, 2025
4f31761
Add entities
wendevlin Sep 26, 2025
61daab7
Add devices and labels
wendevlin Sep 29, 2025
f312381
Update webawesome
wendevlin Sep 30, 2025
1371af5
Add filter translation
wendevlin Sep 30, 2025
6cdf9ba
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Sep 30, 2025
cdf5d2c
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Sep 30, 2025
36bcaad
Fix target details button and expansion panel keyboard focus
wendevlin Sep 30, 2025
06355f6
Fix target details for labels
wendevlin Sep 30, 2025
ccd756d
Merge branch 'target-selected-value' of github.com:home-assistant/fro…
wendevlin Sep 30, 2025
425e94d
Add WIP keyboard shortcuts
wendevlin Sep 30, 2025
9224334
Fix keyboard selection
wendevlin Oct 1, 2025
7c98cab
clean up, use bottom sheet
wendevlin Oct 1, 2025
245c940
Add createDomain
wendevlin Oct 1, 2025
b22bbac
improve search
wendevlin Oct 1, 2025
78d9a16
Prevent popover jumping
wendevlin Oct 1, 2025
a91471b
Fix click event handler
wendevlin Oct 1, 2025
1f2ed1a
Unify renderer
wendevlin Oct 1, 2025
e31ca95
fix types
wendevlin Oct 2, 2025
310b11b
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Oct 2, 2025
b0b68f9
Merge branches 'target-selector' and 'dev' of github.com:home-assista…
wendevlin Oct 6, 2025
0bfa675
Fix domain name
wendevlin Oct 7, 2025
6f67166
Add sticky list headers
wendevlin Oct 8, 2025
1257b39
Show bottom sheet on small height.
wendevlin Oct 8, 2025
bd4e881
Fix drawer list
wendevlin Oct 8, 2025
60daeca
use ha-bottom-sheet
wendevlin Oct 8, 2025
a889856
Use space tokens
wendevlin Oct 8, 2025
bddf74e
fix translation
wendevlin Oct 8, 2025
dfd2eda
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Oct 8, 2025
4252f29
use computeEntityNameList
wendevlin Oct 8, 2025
4c102e0
Update src/resources/theme/color/wa.globals.ts
wendevlin Oct 8, 2025
7f3abcd
Review
wendevlin Oct 9, 2025
bb61475
Split value render options
wendevlin Oct 9, 2025
850b3a3
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Oct 9, 2025
c0b3ad9
Fix variable naming and popover
wendevlin Oct 9, 2025
48b4ffc
Fix empty rows
wendevlin Oct 9, 2025
e2bb56b
Fix list order
wendevlin Oct 9, 2025
f5b3f8e
Fix keyboard select
wendevlin Oct 9, 2025
b840a53
Reset header on filter change
wendevlin Oct 9, 2025
6dbc8c8
add key function
wendevlin Oct 9, 2025
308f6b1
Improve keyboard navigation
wendevlin Oct 10, 2025
5b4c575
Add keyboard home, end
wendevlin Oct 10, 2025
83820a6
Fix overflow
wendevlin Oct 10, 2025
04f14e7
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Oct 10, 2025
2d24e18
Fix mobile target picker
wendevlin Oct 10, 2025
11cb4ee
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Oct 10, 2025
dbd2f6b
Remove md list
wendevlin Oct 14, 2025
2067792
Fix filter focus
wendevlin Oct 14, 2025
883cd94
Focus textfield when list is focused with keyboard
wendevlin Oct 14, 2025
becaccc
Fix device icons
wendevlin Oct 14, 2025
28a3e6e
Fix initial rendering in popover
wendevlin Oct 14, 2025
67cf38b
Fix dialog mode filter buttons
wendevlin Oct 14, 2025
a4ba1c8
Fix dark mode
wendevlin Oct 14, 2025
da9cc43
Fix autofocus
wendevlin Oct 14, 2025
ac4c69d
Fix android
wendevlin Oct 14, 2025
828fb12
Merge branch 'dev' of github.com:home-assistant/frontend into target-…
wendevlin Oct 14, 2025
ecb26d2
Fix small height popover
wendevlin Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/common/entity/context/get_area_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ interface AreaContext {
}
export const getAreaContext = (
area: AreaRegistryEntry,
hass: HomeAssistant
hassFloors: HomeAssistant["floors"]
): AreaContext => {
const floorId = area.floor_id;
const floor = floorId ? hass.floors[floorId] : undefined;
const floor = floorId ? hassFloors[floorId] : undefined;

return {
area: area,
Expand Down
171 changes: 9 additions & 162 deletions src/components/device/ha-device-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,25 @@ import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../common/dom/fire_event";
import { computeAreaName } from "../../common/entity/compute_area_name";
import {
computeDeviceName,
computeDeviceNameDisplay,
} from "../../common/entity/compute_device_name";
import { computeDomain } from "../../common/entity/compute_domain";
import { computeDeviceName } from "../../common/entity/compute_device_name";
import { getDeviceContext } from "../../common/entity/context/get_device_context";
import { getConfigEntries, type ConfigEntry } from "../../data/config_entries";
import {
getDeviceEntityDisplayLookup,
type DeviceEntityDisplayLookup,
getDevices,
type DevicePickerItem,
type DeviceRegistryEntry,
} from "../../data/device_registry";
import { domainToName } from "../../data/integration";
import type { HomeAssistant } from "../../types";
import { brandsUrl } from "../../util/brands-url";
import "../ha-generic-picker";
import type { HaGenericPicker } from "../ha-generic-picker";
import type { PickerComboBoxItem } from "../ha-picker-combo-box";

export type HaDevicePickerDeviceFilterFunc = (
device: DeviceRegistryEntry
) => boolean;

export type HaDevicePickerEntityFilterFunc = (entity: HassEntity) => boolean;

interface DevicePickerItem extends PickerComboBoxItem {
domain?: string;
domain_name?: string;
}

@customElement("ha-device-picker")
export class HaDevicePicker extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
Expand Down Expand Up @@ -104,6 +93,8 @@ export class HaDevicePicker extends LitElement {

@state() private _configEntryLookup: Record<string, ConfigEntry> = {};

private _getDevicesMemoized = memoizeOne(getDevices);

protected firstUpdated(_changedProperties: PropertyValues): void {
super.firstUpdated(_changedProperties);
this._loadConfigEntries();
Expand All @@ -117,162 +108,18 @@ export class HaDevicePicker extends LitElement {
}

private _getItems = () =>
this._getDevices(
this.hass.devices,
this.hass.entities,
this._getDevicesMemoized(
this.hass,
this._configEntryLookup,
this.includeDomains,
this.excludeDomains,
this.includeDeviceClasses,
this.deviceFilter,
this.entityFilter,
this.excludeDevices
this.excludeDevices,
this.value
);

private _getDevices = memoizeOne(
(
haDevices: HomeAssistant["devices"],
haEntities: HomeAssistant["entities"],
configEntryLookup: Record<string, ConfigEntry>,
includeDomains: this["includeDomains"],
excludeDomains: this["excludeDomains"],
includeDeviceClasses: this["includeDeviceClasses"],
deviceFilter: this["deviceFilter"],
entityFilter: this["entityFilter"],
excludeDevices: this["excludeDevices"]
): DevicePickerItem[] => {
const devices = Object.values(haDevices);
const entities = Object.values(haEntities);

let deviceEntityLookup: DeviceEntityDisplayLookup = {};

if (
includeDomains ||
excludeDomains ||
includeDeviceClasses ||
entityFilter
) {
deviceEntityLookup = getDeviceEntityDisplayLookup(entities);
}

let inputDevices = devices.filter(
(device) => device.id === this.value || !device.disabled_by
);

if (includeDomains) {
inputDevices = inputDevices.filter((device) => {
const devEntities = deviceEntityLookup[device.id];
if (!devEntities || !devEntities.length) {
return false;
}
return deviceEntityLookup[device.id].some((entity) =>
includeDomains.includes(computeDomain(entity.entity_id))
);
});
}

if (excludeDomains) {
inputDevices = inputDevices.filter((device) => {
const devEntities = deviceEntityLookup[device.id];
if (!devEntities || !devEntities.length) {
return true;
}
return entities.every(
(entity) =>
!excludeDomains.includes(computeDomain(entity.entity_id))
);
});
}

if (excludeDevices) {
inputDevices = inputDevices.filter(
(device) => !excludeDevices!.includes(device.id)
);
}

if (includeDeviceClasses) {
inputDevices = inputDevices.filter((device) => {
const devEntities = deviceEntityLookup[device.id];
if (!devEntities || !devEntities.length) {
return false;
}
return deviceEntityLookup[device.id].some((entity) => {
const stateObj = this.hass.states[entity.entity_id];
if (!stateObj) {
return false;
}
return (
stateObj.attributes.device_class &&
includeDeviceClasses.includes(stateObj.attributes.device_class)
);
});
});
}

if (entityFilter) {
inputDevices = inputDevices.filter((device) => {
const devEntities = deviceEntityLookup[device.id];
if (!devEntities || !devEntities.length) {
return false;
}
return devEntities.some((entity) => {
const stateObj = this.hass.states[entity.entity_id];
if (!stateObj) {
return false;
}
return entityFilter(stateObj);
});
});
}

if (deviceFilter) {
inputDevices = inputDevices.filter(
(device) =>
// We always want to include the device of the current value
device.id === this.value || deviceFilter!(device)
);
}

const outputDevices = inputDevices.map<DevicePickerItem>((device) => {
const deviceName = computeDeviceNameDisplay(
device,
this.hass,
deviceEntityLookup[device.id]
);

const { area } = getDeviceContext(device, this.hass);

const areaName = area ? computeAreaName(area) : undefined;

const configEntry = device.primary_config_entry
? configEntryLookup?.[device.primary_config_entry]
: undefined;

const domain = configEntry?.domain;
const domainName = domain
? domainToName(this.hass.localize, domain)
: undefined;

return {
id: device.id,
label: "",
primary:
deviceName ||
this.hass.localize("ui.components.device-picker.unnamed_device"),
secondary: areaName,
domain: configEntry?.domain,
domain_name: domainName,
search_labels: [deviceName, areaName, domain, domainName].filter(
Boolean
) as string[],
sorting_label: deviceName || "zzz",
};
});

return outputDevices;
}
);

private _valueRenderer = memoizeOne(
(configEntriesLookup: Record<string, ConfigEntry>) => (value: string) => {
const deviceId = value;
Expand Down
2 changes: 1 addition & 1 deletion src/components/entity/ha-entities-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { isValidEntityId } from "../../common/entity/valid_entity_id";
import type { HomeAssistant, ValueChangedEvent } from "../../types";
import "../ha-sortable";
import "./ha-entity-picker";
import type { HaEntityPickerEntityFilterFunc } from "./ha-entity-picker";
import type { HaEntityPickerEntityFilterFunc } from "../../data/entity";

@customElement("ha-entities-picker")
class HaEntitiesPicker extends LitElement {
Expand Down
3 changes: 0 additions & 3 deletions src/components/entity/ha-entity-attribute-picker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { HassEntity } from "home-assistant-js-websocket";
import type { PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
Expand All @@ -8,8 +7,6 @@ import type { HomeAssistant, ValueChangedEvent } from "../../types";
import "../ha-combo-box";
import type { HaComboBox } from "../ha-combo-box";

export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;

interface AttributeOption {
value: string;
label: string;
Expand Down
Loading
Loading