Compare commits

...

45 Commits

Author SHA1 Message Date
Wendelin
5c15354302 fix getAreasNestedInFloors 2025-11-21 13:43:59 +01:00
Wendelin
fedcf85264 Add keyboard shortcuts 2025-11-21 13:37:05 +01:00
Wendelin
4b9a716df7 Merge branch 'dev' of github.com:home-assistant/frontend into add-automation-element-by-target 2025-11-21 13:01:37 +01:00
Wendelin
e319d116dc add code regions 2025-11-21 12:21:08 +01:00
Wendelin
c8b1fd074c TARGET_SEPARATOR to data 2025-11-21 12:06:33 +01:00
Wendelin
ec9bf7dd94 Fix item target 2025-11-21 12:04:36 +01:00
Wendelin
6d01949ff5 Add target to items 2025-11-21 12:03:25 +01:00
Wendelin
8a8d7dc77a add regions 2025-11-21 11:54:55 +01:00
Wendelin
5fc629f5c5 optimize render code 2025-11-21 11:48:42 +01:00
Wendelin
d070754bb9 Fix load conditions 2025-11-21 08:56:25 +01:00
Wendelin
a2a0f900a8 Add action service lists 2025-11-20 16:19:31 +01:00
Wendelin
b18d3bff21 fix narrow title and subtitle 2025-11-20 16:05:18 +01:00
Wendelin
b06b51d03d Fix mobile scroll 2025-11-20 15:50:51 +01:00
Wendelin
022343c113 Add memoize rendering 2025-11-20 15:30:10 +01:00
Wendelin
5ca10f4a38 Fix reset after search select 2025-11-20 15:12:04 +01:00
Wendelin
33af5b6a08 Fix domain tree items 2025-11-20 14:54:56 +01:00
Wendelin
0c89415c1c Fix font weight 2025-11-20 14:50:49 +01:00
Wendelin
bd6b2c685c Rebuild tree with unassigned 2025-11-20 14:33:32 +01:00
Wendelin
cdb37edc5f add sub unassigned 2025-11-19 17:47:37 +01:00
Wendelin
d68b1571ae Rearrange unassigned 2025-11-19 16:06:18 +01:00
Wendelin
a274727713 Update webawesome 2025-11-19 16:04:36 +01:00
Wendelin
58a1aac131 remove some usage of hass 2025-11-19 15:39:28 +01:00
Wendelin
4cdbda25ed Increase dialog size 2025-11-19 14:48:24 +01:00
Wendelin
618c6e1ef2 change ha-wa-dialog large width 2025-11-19 14:47:53 +01:00
Wendelin
10b308b906 Use core triggers for target 2025-11-19 14:31:11 +01:00
Wendelin
563c6f0fbf Load tree via frontend 2025-11-19 11:58:49 +01:00
Wendelin
1dc7f0ab73 Fix scroll styles 2025-11-19 09:31:57 +01:00
Wendelin
5c8954b714 Fix search 2025-11-19 09:29:52 +01:00
Wendelin
e506e4b082 Add search 2025-11-18 17:27:45 +01:00
Wendelin
9628d69998 Fix sort 2025-11-18 09:49:43 +01:00
Wendelin
350d8e7a49 remove todo 2025-11-18 09:21:40 +01:00
Wendelin
61a5b607e0 Fix show more button 2025-11-18 09:19:51 +01:00
Wendelin
2f3a2b8418 Add unassigned section 2025-11-17 15:57:19 +01:00
Wendelin
12c1e4eec4 Add mobile max height 50percent 2025-11-17 14:25:16 +01:00
Wendelin
b704b621f2 Fix hidden addFromTarget 2025-11-17 10:41:40 +01:00
Wendelin
0eb993a8df Merge branch 'dev' of github.com:home-assistant/frontend into add-automation-element-by-target 2025-11-17 09:55:31 +01:00
Wendelin
cda97766ac also hide narrow target selector when entity is active 2025-11-17 09:47:16 +01:00
Wendelin
e6936a9294 Add mobile view 2025-11-13 15:56:14 +01:00
Wendelin
5ad73287a2 Merge branch 'dev' of github.com:home-assistant/frontend into add-automation-element-by-target 2025-11-13 09:07:37 +01:00
Wendelin
591b464508 Add devices and entities to tree 2025-11-12 17:00:26 +01:00
Wendelin
acf963d38c Merge branch 'dev' of github.com:home-assistant/frontend into add-automation-element-by-target 2025-11-12 15:30:41 +01:00
Wendelin
68f383c293 Use areas and floors in add from target picker 2025-11-12 08:22:35 +01:00
Wendelin
0a25d8106c Merge branch 'dev' of github.com:home-assistant/frontend into add-automation-element-by-target 2025-11-11 09:11:48 +01:00
Wendelin
5c3cf17df9 Merge branch 'dev' of github.com:home-assistant/frontend into add-automation-element-by-target 2025-11-10 17:15:28 +01:00
Wendelin
e905fa6f23 Add tree 2025-11-10 17:12:13 +01:00
18 changed files with 3967 additions and 662 deletions

View File

@@ -52,7 +52,7 @@
"@fullcalendar/list": "6.1.19", "@fullcalendar/list": "6.1.19",
"@fullcalendar/luxon3": "6.1.19", "@fullcalendar/luxon3": "6.1.19",
"@fullcalendar/timegrid": "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", "@lezer/highlight": "1.2.3",
"@lit-labs/motion": "1.0.9", "@lit-labs/motion": "1.0.9",
"@lit-labs/observers": "2.0.6", "@lit-labs/observers": "2.0.6",

View File

@@ -154,7 +154,10 @@ export class HaLabelPicker extends SubscribeMixin(LitElement) {
} }
return this._getLabelsMemoized( return this._getLabelsMemoized(
this.hass, this.hass.states,
this.hass.areas,
this.hass.devices,
this.hass.entities,
this._labels, this._labels,
this.includeDomains, this.includeDomains,
this.excludeDomains, this.excludeDomains,

View File

@@ -192,7 +192,7 @@ export class HaPickerComboBox extends LitElement {
@focus=${this._focusList} @focus=${this._focusList}
@visibilityChanged=${this._visibilityChanged} @visibilityChanged=${this._visibilityChanged}
> >
</lit-virtualizer> `; </lit-virtualizer>`;
} }
private _renderSectionButtons() { private _renderSectionButtons() {

View File

@@ -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;
}
}

View File

@@ -30,6 +30,7 @@ import {
areaMeetsFilter, areaMeetsFilter,
deviceMeetsFilter, deviceMeetsFilter,
entityRegMeetsFilter, entityRegMeetsFilter,
getTargetComboBoxItemType,
type TargetType, type TargetType,
type TargetTypeFloorless, type TargetTypeFloorless,
} from "../data/target"; } from "../data/target";
@@ -47,7 +48,6 @@ import "./ha-tree-indicator";
import "./target-picker/ha-target-picker-item-group"; import "./target-picker/ha-target-picker-item-group";
import "./target-picker/ha-target-picker-value-chip"; import "./target-picker/ha-target-picker-value-chip";
const EMPTY_SEARCH = "___EMPTY_SEARCH___";
const SEPARATOR = "________"; const SEPARATOR = "________";
const CREATE_ID = "___create-new-entity___"; const CREATE_ID = "___create-new-entity___";
@@ -634,35 +634,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
return undefined; 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 = ({ private _sectionTitleFunction = ({
firstIndex, firstIndex,
lastIndex, lastIndex,
@@ -686,7 +657,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
return undefined; return undefined;
} }
const type = this._getRowType(firstItem as PickerComboBoxItem); const type = getTargetComboBoxItemType(firstItem as PickerComboBoxItem);
const translationType: const translationType:
| "areas" | "areas"
| "entities" | "entities"
@@ -858,7 +829,10 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
if (!filterType || filterType === "label") { if (!filterType || filterType === "label") {
let labels = this._getLabelsMemoized( let labels = this._getLabelsMemoized(
this.hass, this.hass.states,
this.hass.areas,
this.hass.devices,
this.hass.entities,
this._labelRegistry, this._labelRegistry,
includeDomains, includeDomains,
undefined, undefined,
@@ -974,7 +948,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
return nothing; return nothing;
} }
const type = this._getRowType(item); const type = getTargetComboBoxItemType(item);
let hasFloor = false; let hasFloor = false;
let rtl = false; let rtl = false;
let showEntityId = false; let showEntityId = false;

View File

@@ -235,7 +235,7 @@ export class HaWaDialog extends LitElement {
} }
:host([width="large"]) wa-dialog { :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 { :host([width="full"]) wa-dialog {

View File

@@ -21,11 +21,52 @@ export interface FloorComboBoxItem extends PickerComboBoxItem {
area?: AreaRegistryEntry; area?: AreaRegistryEntry;
} }
export interface FloorNestedComboBoxItem extends PickerComboBoxItem {
floor?: FloorRegistryEntry;
areas: FloorComboBoxItem[];
}
export interface UnassignedAreasFloorComboBoxItem extends PickerComboBoxItem {
areas: FloorComboBoxItem[];
}
export interface AreaFloorValue { export interface AreaFloorValue {
id: string; id: string;
type: "floor" | "area"; 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 = ( export const getAreasAndFloors = (
states: HomeAssistant["states"], states: HomeAssistant["states"],
haFloors: HomeAssistant["floors"], haFloors: HomeAssistant["floors"],
@@ -40,7 +81,43 @@ export const getAreasAndFloors = (
entityFilter?: HaEntityPickerEntityFilterFunc, entityFilter?: HaEntityPickerEntityFilterFunc,
excludeAreas?: string[], excludeAreas?: string[],
excludeFloors?: string[] excludeFloors?: string[]
): FloorComboBoxItem[] => { ) =>
getAreasAndFloorsItems(
states,
haFloors,
haAreas,
haDevices,
haEntities,
formatId,
includeDomains,
excludeDomains,
includeDeviceClasses,
deviceFilter,
entityFilter,
excludeAreas,
excludeFloors
) as FloorComboBoxItem[];
export 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 floors = Object.values(haFloors);
const areas = Object.values(haAreas); const areas = Object.values(haAreas);
const devices = Object.values(haDevices); const devices = Object.values(haDevices);
@@ -181,7 +258,11 @@ export const getAreasAndFloors = (
const hierarchy = getAreasFloorHierarchy(floors, outputAreas); const hierarchy = getAreasFloorHierarchy(floors, outputAreas);
const items: FloorComboBoxItem[] = []; const items: (
| FloorComboBoxItem
| FloorNestedComboBoxItem
| UnassignedAreasFloorComboBoxItem
)[] = [];
hierarchy.floors.forEach((f) => { hierarchy.floors.forEach((f) => {
const floor = haFloors[f.id]; const floor = haFloors[f.id];
@@ -196,7 +277,7 @@ export const getAreasAndFloors = (
}) })
.flat(); .flat();
items.push({ const floorItem: FloorComboBoxItem | FloorNestedComboBoxItem = {
id: formatId({ id: floor.floor_id, type: "floor" }), id: formatId({ id: floor.floor_id, type: "floor" }),
type: "floor", type: "floor",
primary: floorName, primary: floorName,
@@ -208,41 +289,53 @@ export const getAreasAndFloors = (
...floor.aliases, ...floor.aliases,
...areaSearchLabels, ...areaSearchLabels,
], ],
}); };
items.push( items.push(floorItem);
...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( const floorAreasItems = floorAreas.map((area) => {
...hierarchy.areas.map((areaId) => { const areaName = computeAreaName(area);
const area = haAreas[areaId];
const areaName = computeAreaName(area) || area.area_id;
return { return {
id: formatId({ id: area.area_id, type: "area" }), id: formatId({ id: area.area_id, type: "area" }),
type: "area" as const, type: "area" as const,
primary: areaName, primary: areaName || area.area_id,
area: area, area: area,
icon: area.icon || undefined, 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; return items;
}; };

View File

@@ -1,7 +1,10 @@
import { stringCompare } from "../common/string/compare"; import { stringCompare } from "../common/string/compare";
import type { HomeAssistant } from "../types"; import type { HomeAssistant } from "../types";
import type { DeviceRegistryEntry } from "./device_registry"; import type { DeviceRegistryEntry } from "./device_registry";
import type { EntityRegistryEntry } from "./entity_registry"; import type {
EntityRegistryDisplayEntry,
EntityRegistryEntry,
} from "./entity_registry";
import type { RegistryEntry } from "./registry"; import type { RegistryEntry } from "./registry";
export { subscribeAreaRegistry } from "./ws-area_registry"; export { subscribeAreaRegistry } from "./ws-area_registry";
@@ -18,7 +21,10 @@ export interface AreaRegistryEntry extends RegistryEntry {
temperature_entity_id: string | null; temperature_entity_id: string | null;
} }
export type AreaEntityLookup = Record<string, EntityRegistryEntry[]>; export type AreaEntityLookup = Record<
string,
(EntityRegistryEntry | EntityRegistryDisplayEntry)[]
>;
export type AreaDeviceLookup = Record<string, DeviceRegistryEntry[]>; export type AreaDeviceLookup = Record<string, DeviceRegistryEntry[]>;
@@ -69,11 +75,17 @@ export const reorderAreaRegistryEntries = (
}); });
export const getAreaEntityLookup = ( export const getAreaEntityLookup = (
entities: EntityRegistryEntry[] entities: (EntityRegistryEntry | EntityRegistryDisplayEntry)[],
filterHidden = false
): AreaEntityLookup => { ): AreaEntityLookup => {
const areaEntityLookup: AreaEntityLookup = {}; const areaEntityLookup: AreaEntityLookup = {};
for (const entity of entities) { for (const entity of entities) {
if (!entity.area_id) { if (
!entity.area_id ||
(filterHidden &&
((entity as EntityRegistryDisplayEntry).hidden ||
(entity as EntityRegistryEntry).hidden_by))
) {
continue; continue;
} }
if (!(entity.area_id in areaEntityLookup)) { if (!(entity.area_id in areaEntityLookup)) {

View File

@@ -50,7 +50,10 @@ export type DeviceEntityDisplayLookup = Record<
EntityRegistryDisplayEntry[] EntityRegistryDisplayEntry[]
>; >;
export type DeviceEntityLookup = Record<string, EntityRegistryEntry[]>; export type DeviceEntityLookup = Record<
string,
(EntityRegistryEntry | EntityRegistryDisplayEntry)[]
>;
export interface DeviceRegistryEntryMutableParams { export interface DeviceRegistryEntryMutableParams {
area_id?: string | null; area_id?: string | null;
@@ -107,11 +110,17 @@ export const sortDeviceRegistryByName = (
); );
export const getDeviceEntityLookup = ( export const getDeviceEntityLookup = (
entities: EntityRegistryEntry[] entities: (EntityRegistryEntry | EntityRegistryDisplayEntry)[],
filterHidden = false
): DeviceEntityLookup => { ): DeviceEntityLookup => {
const deviceEntityLookup: DeviceEntityLookup = {}; const deviceEntityLookup: DeviceEntityLookup = {};
for (const entity of entities) { for (const entity of entities) {
if (!entity.device_id) { if (
!entity.device_id ||
(filterHidden &&
((entity as EntityRegistryDisplayEntry).hidden ||
(entity as EntityRegistryEntry).hidden_by))
) {
continue; continue;
} }
if (!(entity.device_id in deviceEntityLookup)) { if (!(entity.device_id in deviceEntityLookup)) {

View File

@@ -1,8 +1,8 @@
import type { Connection } from "home-assistant-js-websocket"; import type { Connection } from "home-assistant-js-websocket";
import { createCollection } from "home-assistant-js-websocket"; import { createCollection } from "home-assistant-js-websocket";
import type { LocalizeFunc } from "../common/translations/localize"; import type { LocalizeFunc } from "../common/translations/localize";
import type { HomeAssistant } from "../types";
import { debounce } from "../common/util/debounce"; import { debounce } from "../common/util/debounce";
import type { HomeAssistant } from "../types";
export const integrationsWithPanel = { export const integrationsWithPanel = {
bluetooth: "config/bluetooth", bluetooth: "config/bluetooth",
@@ -25,6 +25,8 @@ export type IntegrationType =
| "entity" | "entity"
| "system"; | "system";
export type DomainManifestLookup = Record<string, IntegrationManifest>;
export interface IntegrationManifest { export interface IntegrationManifest {
is_built_in: boolean; is_built_in: boolean;
overwrites_built_in?: boolean; overwrites_built_in?: boolean;

View File

@@ -101,7 +101,10 @@ export const deleteLabelRegistryEntry = (
}); });
export const getLabels = ( export const getLabels = (
hass: HomeAssistant, hassStates: HomeAssistant["states"],
hassAreas: HomeAssistant["areas"],
hassDevices: HomeAssistant["devices"],
hassEntities: HomeAssistant["entities"],
labels?: LabelRegistryEntry[], labels?: LabelRegistryEntry[],
includeDomains?: string[], includeDomains?: string[],
excludeDomains?: string[], excludeDomains?: string[],
@@ -115,8 +118,8 @@ export const getLabels = (
return []; return [];
} }
const devices = Object.values(hass.devices); const devices = Object.values(hassDevices);
const entities = Object.values(hass.entities); const entities = Object.values(hassEntities);
let deviceEntityLookup: DeviceEntityDisplayLookup = {}; let deviceEntityLookup: DeviceEntityDisplayLookup = {};
let inputDevices: DeviceRegistryEntry[] | undefined; let inputDevices: DeviceRegistryEntry[] | undefined;
@@ -170,7 +173,7 @@ export const getLabels = (
return false; return false;
} }
return deviceEntityLookup[device.id].some((entity) => { return deviceEntityLookup[device.id].some((entity) => {
const stateObj = hass.states[entity.entity_id]; const stateObj = hassStates[entity.entity_id];
if (!stateObj) { if (!stateObj) {
return false; return false;
} }
@@ -181,7 +184,7 @@ export const getLabels = (
}); });
}); });
inputEntities = inputEntities!.filter((entity) => { inputEntities = inputEntities!.filter((entity) => {
const stateObj = hass.states[entity.entity_id]; const stateObj = hassStates[entity.entity_id];
return ( return (
stateObj.attributes.device_class && stateObj.attributes.device_class &&
includeDeviceClasses.includes(stateObj.attributes.device_class) includeDeviceClasses.includes(stateObj.attributes.device_class)
@@ -200,7 +203,7 @@ export const getLabels = (
return false; return false;
} }
return deviceEntityLookup[device.id].some((entity) => { return deviceEntityLookup[device.id].some((entity) => {
const stateObj = hass.states[entity.entity_id]; const stateObj = hassStates[entity.entity_id];
if (!stateObj) { if (!stateObj) {
return false; return false;
} }
@@ -208,7 +211,7 @@ export const getLabels = (
}); });
}); });
inputEntities = inputEntities!.filter((entity) => { inputEntities = inputEntities!.filter((entity) => {
const stateObj = hass.states[entity.entity_id]; const stateObj = hassStates[entity.entity_id];
if (!stateObj) { if (!stateObj) {
return false; return false;
} }
@@ -245,7 +248,7 @@ export const getLabels = (
if (areaIds) { if (areaIds) {
areaIds.forEach((areaId) => { areaIds.forEach((areaId) => {
const area = hass.areas[areaId]; const area = hassAreas[areaId];
area.labels.forEach((label) => usedLabels.add(label)); area.labels.forEach((label) => usedLabels.add(label));
}); });
} }

View File

@@ -1,11 +1,18 @@
import type { HassServiceTarget } from "home-assistant-js-websocket"; import type { HassServiceTarget } from "home-assistant-js-websocket";
import { computeDomain } from "../common/entity/compute_domain"; import { computeDomain } from "../common/entity/compute_domain";
import type { HaDevicePickerDeviceFilterFunc } from "../components/device/ha-device-picker"; import type { HaDevicePickerDeviceFilterFunc } from "../components/device/ha-device-picker";
import type { PickerComboBoxItem } from "../components/ha-picker-combo-box";
import type { HomeAssistant } from "../types"; import type { HomeAssistant } from "../types";
import type { FloorComboBoxItem } from "./area_floor";
import type { AreaRegistryEntry } from "./area_registry"; import type { AreaRegistryEntry } from "./area_registry";
import type { DeviceRegistryEntry } from "./device_registry"; import type { DevicePickerItem, DeviceRegistryEntry } from "./device_registry";
import type { HaEntityPickerEntityFilterFunc } from "./entity"; import type { HaEntityPickerEntityFilterFunc } from "./entity";
import type { EntityRegistryDisplayEntry } from "./entity_registry"; import type {
EntityComboBoxItem,
EntityRegistryDisplayEntry,
} from "./entity_registry";
export const TARGET_SEPARATOR = "________";
export type TargetType = "entity" | "device" | "area" | "label" | "floor"; export type TargetType = "entity" | "device" | "area" | "label" | "floor";
export type TargetTypeFloorless = Exclude<TargetType, "floor">; export type TargetTypeFloorless = Exclude<TargetType, "floor">;
@@ -35,6 +42,28 @@ export const extractFromTarget = async (
target, target,
}); });
export const getTriggersForTarget = async (
callWS: HomeAssistant["callWS"],
target: HassServiceTarget,
expandGroup = true
) =>
callWS<string[]>({
type: "get_triggers_for_target",
target,
expand_group: expandGroup,
});
export const getServicesForTarget = async (
callWS: HomeAssistant["callWS"],
target: HassServiceTarget,
expandGroup = true
) =>
callWS<string[]>({
type: "get_services_for_target",
target,
expand_group: expandGroup,
});
export const areaMeetsFilter = ( export const areaMeetsFilter = (
area: AreaRegistryEntry, area: AreaRegistryEntry,
devices: HomeAssistant["devices"], devices: HomeAssistant["devices"],
@@ -162,3 +191,32 @@ export const entityRegMeetsFilter = (
} }
return true; return true;
}; };
export const getTargetComboBoxItemType = (
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";
};

File diff suppressed because it is too large Load Diff

View File

@@ -52,6 +52,8 @@ export const waColorStyles = css`
--wa-color-danger-on-normal: var(--ha-color-on-danger-normal); --wa-color-danger-on-normal: var(--ha-color-on-danger-normal);
--wa-color-danger-on-quiet: var(--ha-color-on-danger-quiet); --wa-color-danger-on-quiet: var(--ha-color-on-danger-quiet);
--wa-color-text-quiet: var(--ha-color-text-secondary);
--wa-color-text-normal: var(--ha-color-text-primary); --wa-color-text-normal: var(--ha-color-text-primary);
--wa-color-surface-default: var(--card-background-color); --wa-color-surface-default: var(--card-background-color);
--wa-color-surface-raised: var(--ha-dialog-surface-background, var(--mdc-theme-surface, #fff)); --wa-color-surface-raised: var(--ha-dialog-surface-background, var(--mdc-theme-surface, #fff));
@@ -62,5 +64,7 @@ export const waColorStyles = css`
--wa-focus-ring-color: var(--ha-color-neutral-60); --wa-focus-ring-color: var(--ha-color-neutral-60);
--wa-shadow-l: 4px 8px 12px 0 rgba(0, 0, 0, 0.3); --wa-shadow-l: 4px 8px 12px 0 rgba(0, 0, 0, 0.3);
--wa-color-text-normal: var(--ha-color-text-primary);
} }
`; `;

View File

@@ -9,12 +9,16 @@ export const waMainStyles = css`
--wa-focus-ring-offset: 2px; --wa-focus-ring-offset: 2px;
--wa-focus-ring: var(--wa-focus-ring-style) var(--wa-focus-ring-width) var(--wa-focus-ring-color); --wa-focus-ring: var(--wa-focus-ring-style) var(--wa-focus-ring-width) var(--wa-focus-ring-color);
--wa-space-xs: var(--ha-space-2);
--wa-space-m: var(--ha-space-4);
--wa-space-l: var(--ha-space-6); --wa-space-l: var(--ha-space-6);
--wa-space-xl: var(--ha-space-8); --wa-space-xl: var(--ha-space-8);
--wa-form-control-padding-block: 0.75em; --wa-form-control-padding-block: 0.75em;
--wa-form-control-value-line-height: var(--ha-line-height-condensed);
--wa-font-weight-action: var(--ha-font-weight-medium); --wa-font-weight-action: var(--ha-font-weight-medium);
--wa-transition-normal: 150ms;
--wa-transition-fast: 75ms; --wa-transition-fast: 75ms;
--wa-transition-easing: ease; --wa-transition-easing: ease;
@@ -28,6 +32,7 @@ export const waMainStyles = css`
--wa-line-height-condensed: var(--ha-line-height-condensed); --wa-line-height-condensed: var(--ha-line-height-condensed);
--wa-font-size-m: var(--ha-font-size-m);
--wa-shadow-s: var(--ha-box-shadow-s); --wa-shadow-s: var(--ha-box-shadow-s);
--wa-shadow-m: var(--ha-box-shadow-m); --wa-shadow-m: var(--ha-box-shadow-m);
--wa-shadow-l: var(--ha-box-shadow-l); --wa-shadow-l: var(--ha-box-shadow-l);

View File

@@ -3998,7 +3998,25 @@
"item_pasted": "{item} pasted", "item_pasted": "{item} pasted",
"ctrl": "Ctrl", "ctrl": "Ctrl",
"del": "Del", "del": "Del",
"targets": "Targets",
"select_target": "Select a target",
"home": "Home",
"unassigned": "Unassigned",
"blocks": "Blocks", "blocks": "Blocks",
"show_more": "Show more",
"unassigned_entities": "Unassigned entities",
"unassigned_devices": "Unassigned devices",
"empty_section_search": {
"block": "No blocks found for {term}",
"entity": "No entities found for {term}",
"device": "No devices found for {term}",
"area": "No areas or floors found for {term}",
"label": "No labels found for {term}"
},
"load_target_items_failed": "Failed to load target items for",
"other_areas": "Other areas",
"services": "Services",
"helpers": "Helpers",
"triggers": { "triggers": {
"name": "Triggers", "name": "Triggers",
"header": "When", "header": "When",
@@ -4006,7 +4024,10 @@
"learn_more": "Learn more about triggers", "learn_more": "Learn more about triggers",
"triggered": "Triggered", "triggered": "Triggered",
"add": "Add trigger", "add": "Add trigger",
"empty_search": "No triggers found for {term}", "empty_search": {
"global": "No triggers and targets found for {term}",
"item": "No triggers found for {term}"
},
"id": "Trigger ID", "id": "Trigger ID",
"optional": "Optional", "optional": "Optional",
"edit_id": "Edit ID", "edit_id": "Edit ID",
@@ -4027,6 +4048,7 @@
"copied_to_clipboard": "Trigger copied to clipboard", "copied_to_clipboard": "Trigger copied to clipboard",
"cut_to_clipboard": "Trigger cut to clipboard", "cut_to_clipboard": "Trigger cut to clipboard",
"select": "Select a trigger", "select": "Select a trigger",
"no_items_for_target": "No triggers available for",
"groups": { "groups": {
"device": { "device": {
"label": "Device" "label": "Device"
@@ -4268,7 +4290,10 @@
"description": "All conditions added here need to be satisfied for the automation to run. A condition can be satisfied or not at any given time, for example: ''If {user} is home''. You can use building blocks to create more complex conditions.", "description": "All conditions added here need to be satisfied for the automation to run. A condition can be satisfied or not at any given time, for example: ''If {user} is home''. You can use building blocks to create more complex conditions.",
"learn_more": "Learn more about conditions", "learn_more": "Learn more about conditions",
"add": "Add condition", "add": "Add condition",
"empty_search": "No conditions and blocks found for {term}", "empty_search": {
"global": "No conditions, blocks and targets found for {term}",
"item": "No conditions found for {term}"
},
"add_building_block": "Add building block", "add_building_block": "Add building block",
"test": "Test", "test": "Test",
"testing_error": "Condition did not pass", "testing_error": "Condition did not pass",
@@ -4291,6 +4316,7 @@
"copied_to_clipboard": "Condition copied to clipboard", "copied_to_clipboard": "Condition copied to clipboard",
"cut_to_clipboard": "Condition cut to clipboard", "cut_to_clipboard": "Condition cut to clipboard",
"select": "Select a condition", "select": "Select a condition",
"no_items_for_target": "No conditions available for",
"groups": { "groups": {
"device": { "device": {
"label": "Device" "label": "Device"
@@ -4436,7 +4462,10 @@
"description": "All actions added here will be performed in sequence when the automation runs. An action usually controls one of your areas, devices, or entities, for example: 'Turn on the lights'. You can use building blocks to create more complex sequences of actions.", "description": "All actions added here will be performed in sequence when the automation runs. An action usually controls one of your areas, devices, or entities, for example: 'Turn on the lights'. You can use building blocks to create more complex sequences of actions.",
"learn_more": "Learn more about actions", "learn_more": "Learn more about actions",
"add": "Add action", "add": "Add action",
"empty_search": "No actions and blocks found for {term}", "empty_search": {
"global": "No actions, blocks and targets found for {term}",
"item": "No actions found for {term}"
},
"add_building_block": "Add building block", "add_building_block": "Add building block",
"invalid_action": "Invalid action", "invalid_action": "Invalid action",
"run": "Run action", "run": "Run action",
@@ -4461,6 +4490,7 @@
"copied_to_clipboard": "Action copied to clipboard", "copied_to_clipboard": "Action copied to clipboard",
"cut_to_clipboard": "Action cut to clipboard", "cut_to_clipboard": "Action cut to clipboard",
"select": "Select an action", "select": "Select an action",
"no_items_for_target": "No actions available for",
"groups": { "groups": {
"device_id": { "device_id": {
"label": "Device" "label": "Device"

View File

@@ -1940,9 +1940,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@home-assistant/webawesome@npm:3.0.0": "@home-assistant/webawesome@npm:3.0.0-ha.0":
version: 3.0.0 version: 3.0.0-ha.0
resolution: "@home-assistant/webawesome@npm:3.0.0" resolution: "@home-assistant/webawesome@npm:3.0.0-ha.0"
dependencies: dependencies:
"@ctrl/tinycolor": "npm:4.1.0" "@ctrl/tinycolor": "npm:4.1.0"
"@floating-ui/dom": "npm:^1.6.13" "@floating-ui/dom": "npm:^1.6.13"
@@ -1953,7 +1953,7 @@ __metadata:
lit: "npm:^3.2.1" lit: "npm:^3.2.1"
nanoid: "npm:^5.1.5" nanoid: "npm:^5.1.5"
qr-creator: "npm:^1.0.0" qr-creator: "npm:^1.0.0"
checksum: 10/03400894cfee8548fd5b1f5c56d31d253830e704b18ba69d36ce6b761d8b1bef2fb52cffba8d9b033033bb582f2f51a2d6444d82622f66d70150e2104fcb49e2 checksum: 10/2034d498d5b26bb0573ebc2c9aadd144604bb48c04becbae0c67b16857d8e5d6562626e795974362c3fc41e9b593a9005595d8b5ff434b1569b2d724af13043b
languageName: node languageName: node
linkType: hard linkType: hard
@@ -9226,7 +9226,7 @@ __metadata:
"@fullcalendar/list": "npm:6.1.19" "@fullcalendar/list": "npm:6.1.19"
"@fullcalendar/luxon3": "npm:6.1.19" "@fullcalendar/luxon3": "npm:6.1.19"
"@fullcalendar/timegrid": "npm:6.1.19" "@fullcalendar/timegrid": "npm:6.1.19"
"@home-assistant/webawesome": "npm:3.0.0" "@home-assistant/webawesome": "npm:3.0.0-ha.0"
"@lezer/highlight": "npm:1.2.3" "@lezer/highlight": "npm:1.2.3"
"@lit-labs/motion": "npm:1.0.9" "@lit-labs/motion": "npm:1.0.9"
"@lit-labs/observers": "npm:2.0.6" "@lit-labs/observers": "npm:2.0.6"