Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
e905fa6
Add tree
wendevlin Nov 10, 2025
5c3cf17
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 10, 2025
0a25d81
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 11, 2025
68f383c
Use areas and floors in add from target picker
wendevlin Nov 12, 2025
acf963d
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 12, 2025
591b464
Add devices and entities to tree
wendevlin Nov 12, 2025
5ad7328
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 13, 2025
e6936a9
Add mobile view
wendevlin Nov 13, 2025
cda9776
also hide narrow target selector when entity is active
wendevlin Nov 17, 2025
0eb993a
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 17, 2025
b704b62
Fix hidden addFromTarget
wendevlin Nov 17, 2025
12c1e4e
Add mobile max height 50percent
wendevlin Nov 17, 2025
2f3a2b8
Add unassigned section
wendevlin Nov 17, 2025
61a5b60
Fix show more button
wendevlin Nov 18, 2025
350d8e7
remove todo
wendevlin Nov 18, 2025
9628d69
Fix sort
wendevlin Nov 18, 2025
e506e4b
Add search
wendevlin Nov 18, 2025
5c8954b
Fix search
wendevlin Nov 19, 2025
1dc7f0a
Fix scroll styles
wendevlin Nov 19, 2025
563c6f0
Load tree via frontend
wendevlin Nov 19, 2025
10b308b
Use core triggers for target
wendevlin Nov 19, 2025
618c6e1
change ha-wa-dialog large width
wendevlin Nov 19, 2025
4cdbda2
Increase dialog size
wendevlin Nov 19, 2025
58a1aac
remove some usage of hass
wendevlin Nov 19, 2025
a274727
Update webawesome
wendevlin Nov 19, 2025
d68b157
Rearrange unassigned
wendevlin Nov 19, 2025
cdb37ed
add sub unassigned
wendevlin Nov 19, 2025
bd6b2c6
Rebuild tree with unassigned
wendevlin Nov 20, 2025
0c89415
Fix font weight
wendevlin Nov 20, 2025
33af5b6
Fix domain tree items
wendevlin Nov 20, 2025
5ca10f4
Fix reset after search select
wendevlin Nov 20, 2025
022343c
Add memoize rendering
wendevlin Nov 20, 2025
b06b51d
Fix mobile scroll
wendevlin Nov 20, 2025
b18d3bf
fix narrow title and subtitle
wendevlin Nov 20, 2025
a2a0f90
Add action service lists
wendevlin Nov 20, 2025
d070754
Fix load conditions
wendevlin Nov 21, 2025
5fc629f
optimize render code
wendevlin Nov 21, 2025
8a8d7dc
add regions
wendevlin Nov 21, 2025
6d01949
Add target to items
wendevlin Nov 21, 2025
ec9bf7d
Fix item target
wendevlin Nov 21, 2025
c8b1fd0
TARGET_SEPARATOR to data
wendevlin Nov 21, 2025
e319d11
add code regions
wendevlin Nov 21, 2025
4b9a716
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 21, 2025
fedcf85
Add keyboard shortcuts
wendevlin Nov 21, 2025
5c15354
fix getAreasNestedInFloors
wendevlin Nov 21, 2025
75a127d
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 24, 2025
1dbdad5
Fix types
wendevlin Nov 24, 2025
cb7f359
Remove export from getAreasAndFloorsItems
wendevlin Nov 24, 2025
0b89f7a
Fix SingleHassServiceTarget
wendevlin Nov 24, 2025
fa58b07
use stringCompare instead of localecompare
wendevlin Nov 24, 2025
d410363
Group target results by domain
wendevlin Nov 24, 2025
e041658
Add info icon
wendevlin Nov 24, 2025
7ac34f4
Search into a external component
wendevlin Nov 25, 2025
a3f0e35
extract render items to own element
wendevlin Nov 25, 2025
f89caaf
Fix possible undefined entity
wendevlin Nov 25, 2025
f9f9622
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 25, 2025
2a6e48b
fix styles
wendevlin Nov 25, 2025
bf36d44
fix services name
wendevlin Nov 25, 2025
5fde08b
Fix scroll to
wendevlin Nov 25, 2025
1a6d158
Make show more, more visible
wendevlin Nov 25, 2025
161ccc7
Review
wendevlin Nov 25, 2025
e7edb1b
Review simplify render
wendevlin Nov 25, 2025
6c52b22
Merge branch 'dev' of github.com:home-assistant/frontend into add-aut…
wendevlin Nov 25, 2025
c74d59d
Use feature flag
wendevlin Nov 25, 2025
5fe89ab
Use selected target
wendevlin Nov 26, 2025
39bc4c5
Get conditions for target
wendevlin Nov 26, 2025
252de4d
Get conditions for target
wendevlin Nov 26, 2025
1289a6c
Only allow triggers to use target picker
wendevlin Nov 26, 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"@fullcalendar/list": "6.1.19",
"@fullcalendar/luxon3": "6.1.19",
"@fullcalendar/timegrid": "6.1.19",
"@home-assistant/webawesome": "3.0.0",
"@home-assistant/webawesome": "3.0.0-ha.0",
"@lezer/highlight": "1.2.3",
"@lit-labs/motion": "1.0.9",
"@lit-labs/observers": "2.0.6",
Expand Down
7 changes: 5 additions & 2 deletions src/components/ha-floor-icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
mdiHomeFloor3,
mdiHomeFloorNegative1,
} from "@mdi/js";
import { LitElement, html } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import type { FloorRegistryEntry } from "../data/floor_registry";
import "./ha-icon";
Expand Down Expand Up @@ -48,14 +48,17 @@ export const floorDefaultIcon = (floor: Pick<FloorRegistryEntry, "level">) => {

@customElement("ha-floor-icon")
export class HaFloorIcon extends LitElement {
@property({ attribute: false }) public floor!: Pick<
@property({ attribute: false }) public floor?: Pick<
FloorRegistryEntry,
"icon" | "level"
>;

@property() public icon?: string;

protected render() {
if (!this.floor) {
return nothing;
}
if (this.floor.icon) {
return html`<ha-icon .icon=${this.floor.icon}></ha-icon>`;
}
Expand Down
5 changes: 4 additions & 1 deletion src/components/ha-label-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ export class HaLabelPicker extends SubscribeMixin(LitElement) {
}

return this._getLabelsMemoized(
this.hass,
this.hass.states,
this.hass.areas,
this.hass.devices,
this.hass.entities,
this._labels,
this.includeDomains,
this.excludeDomains,
Expand Down
2 changes: 1 addition & 1 deletion src/components/ha-picker-combo-box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ export class HaPickerComboBox extends LitElement {
@focus=${this._focusList}
@visibilityChanged=${this._visibilityChanged}
>
</lit-virtualizer> `;
</lit-virtualizer>`;
}

private _renderSectionButtons() {
Expand Down
28 changes: 28 additions & 0 deletions src/components/ha-section-title.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";

@customElement("ha-section-title")
class HaSectionTitle extends LitElement {
protected render() {
return html`<slot></slot>`;
}

static styles = css`
:host {
background-color: var(--ha-color-fill-neutral-quiet-resting);
padding: var(--ha-space-1) var(--ha-space-2);
font-weight: var(--ha-font-weight-bold);
color: var(--secondary-text-color);
min-height: var(--ha-space-6);
display: flex;
align-items: center;
box-sizing: border-box;
}
`;
}

declare global {
interface HTMLElementTagNameMap {
"ha-section-title": HaSectionTitle;
}
}
40 changes: 7 additions & 33 deletions src/components/ha-target-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
areaMeetsFilter,
deviceMeetsFilter,
entityRegMeetsFilter,
getTargetComboBoxItemType,
type TargetType,
type TargetTypeFloorless,
} from "../data/target";
Expand All @@ -47,7 +48,6 @@ import "./ha-tree-indicator";
import "./target-picker/ha-target-picker-item-group";
import "./target-picker/ha-target-picker-value-chip";

const EMPTY_SEARCH = "___EMPTY_SEARCH___";
const SEPARATOR = "________";
const CREATE_ID = "___create-new-entity___";

Expand Down Expand Up @@ -634,35 +634,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
return undefined;
}

private _getRowType = (
item:
| PickerComboBoxItem
| (FloorComboBoxItem & { last?: boolean | undefined })
| EntityComboBoxItem
| DevicePickerItem
) => {
if (
(item as FloorComboBoxItem).type === "area" ||
(item as FloorComboBoxItem).type === "floor"
) {
return (item as FloorComboBoxItem).type;
}

if ("domain" in item) {
return "device";
}

if ("stateObj" in item) {
return "entity";
}

if (item.id === EMPTY_SEARCH) {
return "empty";
}

return "label";
};

private _sectionTitleFunction = ({
firstIndex,
lastIndex,
Expand All @@ -686,7 +657,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
return undefined;
}

const type = this._getRowType(firstItem as PickerComboBoxItem);
const type = getTargetComboBoxItemType(firstItem as PickerComboBoxItem);
const translationType:
| "areas"
| "entities"
Expand Down Expand Up @@ -858,7 +829,10 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {

if (!filterType || filterType === "label") {
let labels = this._getLabelsMemoized(
this.hass,
this.hass.states,
this.hass.areas,
this.hass.devices,
this.hass.entities,
this._labelRegistry,
includeDomains,
undefined,
Expand Down Expand Up @@ -974,7 +948,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
return nothing;
}

const type = this._getRowType(item);
const type = getTargetComboBoxItemType(item);
let hasFloor = false;
let rtl = false;
let showEntityId = false;
Expand Down
2 changes: 1 addition & 1 deletion src/components/ha-wa-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export class HaWaDialog extends LitElement {
}

:host([width="large"]) wa-dialog {
--width: min(var(--ha-dialog-width-lg, 720px), var(--full-width));
--width: min(var(--ha-dialog-width-lg, 1024px), var(--full-width));
}

:host([width="full"]) wa-dialog {
Expand Down
153 changes: 123 additions & 30 deletions src/data/area_floor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,52 @@ export interface FloorComboBoxItem extends PickerComboBoxItem {
area?: AreaRegistryEntry;
}

export interface FloorNestedComboBoxItem extends PickerComboBoxItem {
floor?: FloorRegistryEntry;
areas: FloorComboBoxItem[];
}

export interface UnassignedAreasFloorComboBoxItem extends PickerComboBoxItem {
areas: FloorComboBoxItem[];
}

export interface AreaFloorValue {
id: string;
type: "floor" | "area";
}

export const getAreasNestedInFloors = (
states: HomeAssistant["states"],
haFloors: HomeAssistant["floors"],
haAreas: HomeAssistant["areas"],
haDevices: HomeAssistant["devices"],
haEntities: HomeAssistant["entities"],
formatId: (value: AreaFloorValue) => string,
includeDomains?: string[],
excludeDomains?: string[],
includeDeviceClasses?: string[],
deviceFilter?: HaDevicePickerDeviceFilterFunc,
entityFilter?: HaEntityPickerEntityFilterFunc,
excludeAreas?: string[],
excludeFloors?: string[]
) =>
getAreasAndFloorsItems(
states,
haFloors,
haAreas,
haDevices,
haEntities,
formatId,
includeDomains,
excludeDomains,
includeDeviceClasses,
deviceFilter,
entityFilter,
excludeAreas,
excludeFloors,
true
) as (FloorNestedComboBoxItem | UnassignedAreasFloorComboBoxItem)[];

export const getAreasAndFloors = (
states: HomeAssistant["states"],
haFloors: HomeAssistant["floors"],
Expand All @@ -40,7 +81,43 @@ export const getAreasAndFloors = (
entityFilter?: HaEntityPickerEntityFilterFunc,
excludeAreas?: string[],
excludeFloors?: string[]
): FloorComboBoxItem[] => {
) =>
getAreasAndFloorsItems(
states,
haFloors,
haAreas,
haDevices,
haEntities,
formatId,
includeDomains,
excludeDomains,
includeDeviceClasses,
deviceFilter,
entityFilter,
excludeAreas,
excludeFloors
) as FloorComboBoxItem[];

const getAreasAndFloorsItems = (
states: HomeAssistant["states"],
haFloors: HomeAssistant["floors"],
haAreas: HomeAssistant["areas"],
haDevices: HomeAssistant["devices"],
haEntities: HomeAssistant["entities"],
formatId: (value: AreaFloorValue) => string,
includeDomains?: string[],
excludeDomains?: string[],
includeDeviceClasses?: string[],
deviceFilter?: HaDevicePickerDeviceFilterFunc,
entityFilter?: HaEntityPickerEntityFilterFunc,
excludeAreas?: string[],
excludeFloors?: string[],
nested = false
): (
| FloorComboBoxItem
| FloorNestedComboBoxItem
| UnassignedAreasFloorComboBoxItem
)[] => {
const floors = Object.values(haFloors);
const areas = Object.values(haAreas);
const devices = Object.values(haDevices);
Expand Down Expand Up @@ -181,7 +258,11 @@ export const getAreasAndFloors = (

const hierarchy = getAreasFloorHierarchy(floors, outputAreas);

const items: FloorComboBoxItem[] = [];
const items: (
| FloorComboBoxItem
| FloorNestedComboBoxItem
| UnassignedAreasFloorComboBoxItem
)[] = [];

hierarchy.floors.forEach((f) => {
const floor = haFloors[f.id];
Expand All @@ -196,7 +277,7 @@ export const getAreasAndFloors = (
})
.flat();

items.push({
const floorItem: FloorComboBoxItem | FloorNestedComboBoxItem = {
id: formatId({ id: floor.floor_id, type: "floor" }),
type: "floor",
primary: floorName,
Expand All @@ -208,41 +289,53 @@ export const getAreasAndFloors = (
...floor.aliases,
...areaSearchLabels,
],
});
};

items.push(
...floorAreas.map((area) => {
const areaName = computeAreaName(area);
return {
id: formatId({ id: area.area_id, type: "area" }),
type: "area" as const,
primary: areaName || area.area_id,
area: area,
icon: area.icon || undefined,
search_labels: [
area.area_id,
...(areaName ? [areaName] : []),
...area.aliases,
],
};
})
);
});
items.push(floorItem);

items.push(
...hierarchy.areas.map((areaId) => {
const area = haAreas[areaId];
const areaName = computeAreaName(area) || area.area_id;
const floorAreasItems = floorAreas.map((area) => {
const areaName = computeAreaName(area);
return {
id: formatId({ id: area.area_id, type: "area" }),
type: "area" as const,
primary: areaName,
primary: areaName || area.area_id,
area: area,
icon: area.icon || undefined,
search_labels: [area.area_id, areaName, ...area.aliases],
search_labels: [
area.area_id,
...(areaName ? [areaName] : []),
...area.aliases,
],
};
})
);
});

if (nested && floor) {
(floorItem as unknown as FloorNestedComboBoxItem).areas = floorAreasItems;
} else {
items.push(...floorAreasItems);
}
});

const unassignedAreaItems = hierarchy.areas.map((areaId) => {
const area = haAreas[areaId];
const areaName = computeAreaName(area) || area.area_id;
return {
id: formatId({ id: area.area_id, type: "area" }),
type: "area" as const,
primary: areaName,
area: area,
icon: area.icon || undefined,
search_labels: [area.area_id, areaName, ...area.aliases],
};
});

if (nested && unassignedAreaItems.length) {
items.push({
areas: unassignedAreaItems,
} as UnassignedAreasFloorComboBoxItem);
} else {
items.push(...unassignedAreaItems);
}

return items;
};
Loading
Loading