Add floor selector (#20295)
parent
1ce3347c2e
commit
85f2016371
|
@ -4,4 +4,11 @@ import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
export const mockAreaRegistry = (
|
export const mockAreaRegistry = (
|
||||||
hass: MockHomeAssistant,
|
hass: MockHomeAssistant,
|
||||||
data: AreaRegistryEntry[] = []
|
data: AreaRegistryEntry[] = []
|
||||||
) => hass.mockWS("config/area_registry/list", () => data);
|
) => {
|
||||||
|
hass.mockWS("config/area_registry/list", () => data);
|
||||||
|
const areas = {};
|
||||||
|
data.forEach((area) => {
|
||||||
|
areas[area.area_id] = area;
|
||||||
|
});
|
||||||
|
hass.updateHass({ areas });
|
||||||
|
};
|
||||||
|
|
|
@ -4,4 +4,11 @@ import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
export const mockDeviceRegistry = (
|
export const mockDeviceRegistry = (
|
||||||
hass: MockHomeAssistant,
|
hass: MockHomeAssistant,
|
||||||
data: DeviceRegistryEntry[] = []
|
data: DeviceRegistryEntry[] = []
|
||||||
) => hass.mockWS("config/device_registry/list", () => data);
|
) => {
|
||||||
|
hass.mockWS("config/device_registry/list", () => data);
|
||||||
|
const devices = {};
|
||||||
|
data.forEach((device) => {
|
||||||
|
devices[device.id] = device;
|
||||||
|
});
|
||||||
|
hass.updateHass({ devices });
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { FloorRegistryEntry } from "../../../src/data/floor_registry";
|
||||||
|
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockFloorRegistry = (
|
||||||
|
hass: MockHomeAssistant,
|
||||||
|
data: FloorRegistryEntry[] = []
|
||||||
|
) => hass.mockWS("config/floor_registry/list", () => data);
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { LabelRegistryEntry } from "../../../src/data/label_registry";
|
||||||
|
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockLabelRegistry = (
|
||||||
|
hass: MockHomeAssistant,
|
||||||
|
data: LabelRegistryEntry[] = []
|
||||||
|
) => hass.mockWS("config/label_registry/list", () => data);
|
|
@ -17,6 +17,10 @@ import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
|
import { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
|
||||||
import type { HomeAssistant } from "../../../../src/types";
|
import type { HomeAssistant } from "../../../../src/types";
|
||||||
import "../../components/demo-black-white-row";
|
import "../../components/demo-black-white-row";
|
||||||
|
import { FloorRegistryEntry } from "../../../../src/data/floor_registry";
|
||||||
|
import { LabelRegistryEntry } from "../../../../src/data/label_registry";
|
||||||
|
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
|
||||||
|
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
||||||
|
@ -100,7 +104,7 @@ const DEVICES = [
|
||||||
const AREAS: AreaRegistryEntry[] = [
|
const AREAS: AreaRegistryEntry[] = [
|
||||||
{
|
{
|
||||||
area_id: "backyard",
|
area_id: "backyard",
|
||||||
floor_id: null,
|
floor_id: "ground",
|
||||||
name: "Backyard",
|
name: "Backyard",
|
||||||
icon: null,
|
icon: null,
|
||||||
picture: null,
|
picture: null,
|
||||||
|
@ -109,7 +113,7 @@ const AREAS: AreaRegistryEntry[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "bedroom",
|
area_id: "bedroom",
|
||||||
floor_id: null,
|
floor_id: "first",
|
||||||
name: "Bedroom",
|
name: "Bedroom",
|
||||||
icon: "mdi:bed",
|
icon: "mdi:bed",
|
||||||
picture: null,
|
picture: null,
|
||||||
|
@ -118,7 +122,7 @@ const AREAS: AreaRegistryEntry[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "livingroom",
|
area_id: "livingroom",
|
||||||
floor_id: null,
|
floor_id: "ground",
|
||||||
name: "Livingroom",
|
name: "Livingroom",
|
||||||
icon: "mdi:sofa",
|
icon: "mdi:sofa",
|
||||||
picture: null,
|
picture: null,
|
||||||
|
@ -127,6 +131,45 @@ const AREAS: AreaRegistryEntry[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const FLOORS: FloorRegistryEntry[] = [
|
||||||
|
{
|
||||||
|
floor_id: "ground",
|
||||||
|
name: "Ground floor",
|
||||||
|
level: 0,
|
||||||
|
icon: null,
|
||||||
|
aliases: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
floor_id: "first",
|
||||||
|
name: "First floor",
|
||||||
|
level: 1,
|
||||||
|
icon: "mdi:numeric-1",
|
||||||
|
aliases: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
floor_id: "second",
|
||||||
|
name: "Second floor",
|
||||||
|
level: 2,
|
||||||
|
icon: "mdi:numeric-2",
|
||||||
|
aliases: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const LABELS: LabelRegistryEntry[] = [
|
||||||
|
{
|
||||||
|
label_id: "energy",
|
||||||
|
name: "Energy",
|
||||||
|
icon: null,
|
||||||
|
color: "yellow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label_id: "entertainment",
|
||||||
|
name: "Entertainment",
|
||||||
|
icon: "mdi:popcorn",
|
||||||
|
color: "blue",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const SCHEMAS: {
|
const SCHEMAS: {
|
||||||
name: string;
|
name: string;
|
||||||
input: Record<string, (BlueprintInput & { required?: boolean }) | null>;
|
input: Record<string, (BlueprintInput & { required?: boolean }) | null>;
|
||||||
|
@ -134,7 +177,12 @@ const SCHEMAS: {
|
||||||
{
|
{
|
||||||
name: "One of each",
|
name: "One of each",
|
||||||
input: {
|
input: {
|
||||||
|
label: { name: "Label", selector: { label: {} } },
|
||||||
|
floor: { name: "Floor", selector: { floor: {} } },
|
||||||
|
area: { name: "Area", selector: { area: {} } },
|
||||||
|
device: { name: "Device", selector: { device: {} } },
|
||||||
entity: { name: "Entity", selector: { entity: {} } },
|
entity: { name: "Entity", selector: { entity: {} } },
|
||||||
|
target: { name: "Target", selector: { target: {} } },
|
||||||
state: {
|
state: {
|
||||||
name: "State",
|
name: "State",
|
||||||
selector: { state: { entity_id: "alarm_control_panel.alarm" } },
|
selector: { state: { entity_id: "alarm_control_panel.alarm" } },
|
||||||
|
@ -143,15 +191,12 @@ const SCHEMAS: {
|
||||||
name: "Attribute",
|
name: "Attribute",
|
||||||
selector: { attribute: { entity_id: "" } },
|
selector: { attribute: { entity_id: "" } },
|
||||||
},
|
},
|
||||||
device: { name: "Device", selector: { device: {} } },
|
|
||||||
config_entry: {
|
config_entry: {
|
||||||
name: "Integration",
|
name: "Integration",
|
||||||
selector: { config_entry: {} },
|
selector: { config_entry: {} },
|
||||||
},
|
},
|
||||||
duration: { name: "Duration", selector: { duration: {} } },
|
duration: { name: "Duration", selector: { duration: {} } },
|
||||||
addon: { name: "Addon", selector: { addon: {} } },
|
addon: { name: "Addon", selector: { addon: {} } },
|
||||||
area: { name: "Area", selector: { area: {} } },
|
|
||||||
target: { name: "Target", selector: { target: {} } },
|
|
||||||
number_box: {
|
number_box: {
|
||||||
name: "Number Box",
|
name: "Number Box",
|
||||||
selector: {
|
selector: {
|
||||||
|
@ -300,6 +345,8 @@ const SCHEMAS: {
|
||||||
entity: { name: "Entity", selector: { entity: { multiple: true } } },
|
entity: { name: "Entity", selector: { entity: { multiple: true } } },
|
||||||
device: { name: "Device", selector: { device: { multiple: true } } },
|
device: { name: "Device", selector: { device: { multiple: true } } },
|
||||||
area: { name: "Area", selector: { area: { multiple: true } } },
|
area: { name: "Area", selector: { area: { multiple: true } } },
|
||||||
|
floor: { name: "Floor", selector: { floor: { multiple: true } } },
|
||||||
|
label: { name: "Label", selector: { label: { multiple: true } } },
|
||||||
select: {
|
select: {
|
||||||
name: "Select Multiple",
|
name: "Select Multiple",
|
||||||
selector: {
|
selector: {
|
||||||
|
@ -356,6 +403,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
||||||
mockDeviceRegistry(hass, DEVICES);
|
mockDeviceRegistry(hass, DEVICES);
|
||||||
mockConfigEntries(hass);
|
mockConfigEntries(hass);
|
||||||
mockAreaRegistry(hass, AREAS);
|
mockAreaRegistry(hass, AREAS);
|
||||||
|
mockFloorRegistry(hass, FLOORS);
|
||||||
|
mockLabelRegistry(hass, LABELS);
|
||||||
mockHassioSupervisor(hass);
|
mockHassioSupervisor(hass);
|
||||||
hass.mockWS("auth/sign_path", (params) => params);
|
hass.mockWS("auth/sign_path", (params) => params);
|
||||||
hass.mockWS("media_player/browse_media", this._browseMedia);
|
hass.mockWS("media_player/browse_media", this._browseMedia);
|
||||||
|
|
|
@ -274,7 +274,7 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
|
||||||
if (areaIds) {
|
if (areaIds) {
|
||||||
const floorAreaLookup = getFloorAreaLookup(areas);
|
const floorAreaLookup = getFloorAreaLookup(areas);
|
||||||
outputFloors = outputFloors.filter((floor) =>
|
outputFloors = outputFloors.filter((floor) =>
|
||||||
floorAreaLookup[floor.floor_id].some((area) =>
|
floorAreaLookup[floor.floor_id]?.some((area) =>
|
||||||
areaIds!.includes(area.area_id)
|
areaIds!.includes(area.area_id)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
||||||
|
import type { HomeAssistant } from "../types";
|
||||||
|
import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker";
|
||||||
|
import "./ha-floor-picker";
|
||||||
|
|
||||||
|
@customElement("ha-floors-picker")
|
||||||
|
export class HaFloorsPicker extends SubscribeMixin(LitElement) {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public label?: string;
|
||||||
|
|
||||||
|
@property({ type: Array }) public value?: string[];
|
||||||
|
|
||||||
|
@property() public helper?: string;
|
||||||
|
|
||||||
|
@property() public placeholder?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean, attribute: "no-add" })
|
||||||
|
public noAdd = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show only floors with entities from specific domains.
|
||||||
|
* @type {Array}
|
||||||
|
* @attr include-domains
|
||||||
|
*/
|
||||||
|
@property({ type: Array, attribute: "include-domains" })
|
||||||
|
public includeDomains?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show no floors with entities of these domains.
|
||||||
|
* @type {Array}
|
||||||
|
* @attr exclude-domains
|
||||||
|
*/
|
||||||
|
@property({ type: Array, attribute: "exclude-domains" })
|
||||||
|
public excludeDomains?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show only floors with entities of these device classes.
|
||||||
|
* @type {Array}
|
||||||
|
* @attr include-device-classes
|
||||||
|
*/
|
||||||
|
@property({ type: Array, attribute: "include-device-classes" })
|
||||||
|
public includeDeviceClasses?: string[];
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public deviceFilter?: HaDevicePickerDeviceFilterFunc;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public entityFilter?: (entity: HassEntity) => boolean;
|
||||||
|
|
||||||
|
@property({ attribute: "picked-floor-label" })
|
||||||
|
public pickedFloorLabel?: string;
|
||||||
|
|
||||||
|
@property({ attribute: "pick-floor-label" })
|
||||||
|
public pickFloorLabel?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public required = false;
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this.hass) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentFloors = this._currentFloors;
|
||||||
|
return html`
|
||||||
|
${currentFloors.map(
|
||||||
|
(floor) => html`
|
||||||
|
<div>
|
||||||
|
<ha-floor-picker
|
||||||
|
.curValue=${floor}
|
||||||
|
.noAdd=${this.noAdd}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${floor}
|
||||||
|
.label=${this.pickedFloorLabel}
|
||||||
|
.includeDomains=${this.includeDomains}
|
||||||
|
.excludeDomains=${this.excludeDomains}
|
||||||
|
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||||
|
.deviceFilter=${this.deviceFilter}
|
||||||
|
.entityFilter=${this.entityFilter}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
@value-changed=${this._floorChanged}
|
||||||
|
></ha-floor-picker>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
<div>
|
||||||
|
<ha-floor-picker
|
||||||
|
.noAdd=${this.noAdd}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.label=${this.pickFloorLabel}
|
||||||
|
.helper=${this.helper}
|
||||||
|
.includeDomains=${this.includeDomains}
|
||||||
|
.excludeDomains=${this.excludeDomains}
|
||||||
|
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||||
|
.deviceFilter=${this.deviceFilter}
|
||||||
|
.entityFilter=${this.entityFilter}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
.placeholder=${this.placeholder}
|
||||||
|
.required=${this.required && !currentFloors.length}
|
||||||
|
@value-changed=${this._addFloor}
|
||||||
|
.excludeFloors=${currentFloors}
|
||||||
|
></ha-floor-picker>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _currentFloors(): string[] {
|
||||||
|
return this.value || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _updateFloors(floors) {
|
||||||
|
this.value = floors;
|
||||||
|
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: floors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _floorChanged(ev: CustomEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const curValue = (ev.currentTarget as any).curValue;
|
||||||
|
const newValue = ev.detail.value;
|
||||||
|
if (newValue === curValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentFloors = this._currentFloors;
|
||||||
|
if (!newValue || currentFloors.includes(newValue)) {
|
||||||
|
this._updateFloors(currentFloors.filter((ent) => ent !== curValue));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._updateFloors(
|
||||||
|
currentFloors.map((ent) => (ent === curValue ? newValue : ent))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addFloor(ev: CustomEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
const toAdd = ev.detail.value;
|
||||||
|
if (!toAdd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(ev.currentTarget as any).value = "";
|
||||||
|
const currentFloors = this._currentFloors;
|
||||||
|
if (currentFloors.includes(toAdd)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateFloors([...currentFloors, toAdd]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static override styles = css`
|
||||||
|
div {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-floors-picker": HaFloorsPicker;
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,8 +87,12 @@ export class HaAreaSelector extends LitElement {
|
||||||
.label=${this.label}
|
.label=${this.label}
|
||||||
.helper=${this.helper}
|
.helper=${this.helper}
|
||||||
no-add
|
no-add
|
||||||
.deviceFilter=${this._filterDevices}
|
.deviceFilter=${this.selector.area?.device
|
||||||
.entityFilter=${this._filterEntities}
|
? this._filterDevices
|
||||||
|
: undefined}
|
||||||
|
.entityFilter=${this.selector.area?.entity
|
||||||
|
? this._filterEntities
|
||||||
|
: undefined}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.required=${this.required}
|
.required=${this.required}
|
||||||
></ha-area-picker>
|
></ha-area-picker>
|
||||||
|
@ -102,8 +106,12 @@ export class HaAreaSelector extends LitElement {
|
||||||
.helper=${this.helper}
|
.helper=${this.helper}
|
||||||
.pickAreaLabel=${this.label}
|
.pickAreaLabel=${this.label}
|
||||||
no-add
|
no-add
|
||||||
.deviceFilter=${this._filterDevices}
|
.deviceFilter=${this.selector.area?.device
|
||||||
.entityFilter=${this._filterEntities}
|
? this._filterDevices
|
||||||
|
: undefined}
|
||||||
|
.entityFilter=${this.selector.area?.entity
|
||||||
|
? this._filterEntities
|
||||||
|
: undefined}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.required=${this.required}
|
.required=${this.required}
|
||||||
></ha-areas-picker>
|
></ha-areas-picker>
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { html, LitElement, PropertyValues, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { ensureArray } from "../../common/array/ensure-array";
|
||||||
|
import type { DeviceRegistryEntry } from "../../data/device_registry";
|
||||||
|
import { getDeviceIntegrationLookup } from "../../data/device_registry";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import {
|
||||||
|
EntitySources,
|
||||||
|
fetchEntitySourcesWithCache,
|
||||||
|
} from "../../data/entity_sources";
|
||||||
|
import type { FloorSelector } from "../../data/selector";
|
||||||
|
import {
|
||||||
|
filterSelectorDevices,
|
||||||
|
filterSelectorEntities,
|
||||||
|
} from "../../data/selector";
|
||||||
|
import { HomeAssistant } from "../../types";
|
||||||
|
import "../ha-floor-picker";
|
||||||
|
import "../ha-floors-picker";
|
||||||
|
|
||||||
|
@customElement("ha-selector-floor")
|
||||||
|
export class HaFloorSelector extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public selector!: FloorSelector;
|
||||||
|
|
||||||
|
@property() public value?: any;
|
||||||
|
|
||||||
|
@property() public label?: string;
|
||||||
|
|
||||||
|
@property() public helper?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public required = true;
|
||||||
|
|
||||||
|
@state() private _entitySources?: EntitySources;
|
||||||
|
|
||||||
|
private _deviceIntegrationLookup = memoizeOne(getDeviceIntegrationLookup);
|
||||||
|
|
||||||
|
private _hasIntegration(selector: FloorSelector) {
|
||||||
|
return (
|
||||||
|
(selector.floor?.entity &&
|
||||||
|
ensureArray(selector.floor.entity).some(
|
||||||
|
(filter) => filter.integration
|
||||||
|
)) ||
|
||||||
|
(selector.floor?.device &&
|
||||||
|
ensureArray(selector.floor.device).some((device) => device.integration))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected willUpdate(changedProperties: PropertyValues): void {
|
||||||
|
if (changedProperties.has("selector") && this.value !== undefined) {
|
||||||
|
if (this.selector.floor?.multiple && !Array.isArray(this.value)) {
|
||||||
|
this.value = [this.value];
|
||||||
|
fireEvent(this, "value-changed", { value: this.value });
|
||||||
|
} else if (!this.selector.floor?.multiple && Array.isArray(this.value)) {
|
||||||
|
this.value = this.value[0];
|
||||||
|
fireEvent(this, "value-changed", { value: this.value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
|
if (
|
||||||
|
changedProperties.has("selector") &&
|
||||||
|
this._hasIntegration(this.selector) &&
|
||||||
|
!this._entitySources
|
||||||
|
) {
|
||||||
|
fetchEntitySourcesWithCache(this.hass).then((sources) => {
|
||||||
|
this._entitySources = sources;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (this._hasIntegration(this.selector) && !this._entitySources) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.selector.floor?.multiple) {
|
||||||
|
return html`
|
||||||
|
<ha-floor-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this.value}
|
||||||
|
.label=${this.label}
|
||||||
|
.helper=${this.helper}
|
||||||
|
no-add
|
||||||
|
.deviceFilter=${this.selector.floor?.device
|
||||||
|
? this._filterDevices
|
||||||
|
: undefined}
|
||||||
|
.entityFilter=${this.selector.floor?.entity
|
||||||
|
? this._filterEntities
|
||||||
|
: undefined}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
.required=${this.required}
|
||||||
|
></ha-floor-picker>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-floors-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this.value}
|
||||||
|
.helper=${this.helper}
|
||||||
|
.pickFloorLabel=${this.label}
|
||||||
|
no-add
|
||||||
|
.deviceFilter=${this.selector.floor?.device
|
||||||
|
? this._filterDevices
|
||||||
|
: undefined}
|
||||||
|
.entityFilter=${this.selector.floor?.entity
|
||||||
|
? this._filterEntities
|
||||||
|
: undefined}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
.required=${this.required}
|
||||||
|
></ha-floors-picker>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _filterEntities = (entity: HassEntity): boolean => {
|
||||||
|
if (!this.selector.floor?.entity) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ensureArray(this.selector.floor.entity).some((filter) =>
|
||||||
|
filterSelectorEntities(filter, entity, this._entitySources)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
private _filterDevices = (device: DeviceRegistryEntry): boolean => {
|
||||||
|
if (!this.selector.floor?.device) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deviceIntegrations = this._entitySources
|
||||||
|
? this._deviceIntegrationLookup(
|
||||||
|
this._entitySources,
|
||||||
|
Object.values(this.hass.entities)
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return ensureArray(this.selector.floor.device).some((filter) =>
|
||||||
|
filterSelectorDevices(filter, device, deviceIntegrations)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-selector-floor": HaFloorSelector;
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ const LOAD_ELEMENTS = {
|
||||||
entity: () => import("./ha-selector-entity"),
|
entity: () => import("./ha-selector-entity"),
|
||||||
statistic: () => import("./ha-selector-statistic"),
|
statistic: () => import("./ha-selector-statistic"),
|
||||||
file: () => import("./ha-selector-file"),
|
file: () => import("./ha-selector-file"),
|
||||||
|
floor: () => import("./ha-selector-floor"),
|
||||||
label: () => import("./ha-selector-label"),
|
label: () => import("./ha-selector-label"),
|
||||||
language: () => import("./ha-selector-language"),
|
language: () => import("./ha-selector-language"),
|
||||||
navigation: () => import("./ha-selector-navigation"),
|
navigation: () => import("./ha-selector-navigation"),
|
||||||
|
|
|
@ -31,6 +31,7 @@ export type Selector =
|
||||||
| DateSelector
|
| DateSelector
|
||||||
| DateTimeSelector
|
| DateTimeSelector
|
||||||
| DeviceSelector
|
| DeviceSelector
|
||||||
|
| FloorSelector
|
||||||
| LegacyDeviceSelector
|
| LegacyDeviceSelector
|
||||||
| DurationSelector
|
| DurationSelector
|
||||||
| EntitySelector
|
| EntitySelector
|
||||||
|
@ -170,6 +171,14 @@ export interface DeviceSelector {
|
||||||
} | null;
|
} | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FloorSelector {
|
||||||
|
floor: {
|
||||||
|
entity?: EntitySelectorFilter | readonly EntitySelectorFilter[];
|
||||||
|
device?: DeviceSelectorFilter | readonly DeviceSelectorFilter[];
|
||||||
|
multiple?: boolean;
|
||||||
|
} | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface LegacyDeviceSelector {
|
export interface LegacyDeviceSelector {
|
||||||
device: DeviceSelector["device"] & {
|
device: DeviceSelector["device"] & {
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue