Compare commits

..

10 Commits

Author SHA1 Message Date
Bram Kragten
cc1a0b24f0 Fix background overflow on outlined text field 2024-04-04 12:19:52 +02:00
Paul Bottein
3a4e9b6856 Avoid duplicate entity ids in history (#20402)
* Avoid duplicate entity ids in history

* Don't need to check for size
2024-04-04 12:12:04 +02:00
Bram Kragten
5f5ac5419b Add floor and label support to history panel (#20388) 2024-04-04 00:06:03 +02:00
Bram Kragten
92b7a3b477 Adjust integration filter height for search bar (#20382) 2024-04-03 21:54:27 +02:00
Bram Kragten
00837acdfc Bumped version to 20240403.1 2024-04-03 16:52:23 +02:00
Bram Kragten
7704be12b1 When creating a label or category with multi select, also assign it (#20379)
* When creating a label or category with multi select, also assign it

* correct scope

* again
2024-04-03 16:51:33 +02:00
Bram Kragten
712ddb531b Make selection bar responsive (#20378) 2024-04-03 16:48:02 +02:00
Bram Kragten
d52afc3f71 Add settings shortcut to scene and script table (#20375) 2024-04-03 16:11:32 +02:00
Bram Kragten
92f6083e0b Faulty helpers should not be selectable (#20373) 2024-04-03 15:19:05 +02:00
Bram Kragten
5751fdbe56 Improve entity integration filter (#20372) 2024-04-03 15:18:40 +02:00
10 changed files with 334 additions and 175 deletions

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "home-assistant-frontend" name = "home-assistant-frontend"
version = "20240403.0" version = "20240403.1"
license = {text = "Apache-2.0"} license = {text = "Apache-2.0"}
description = "The Home Assistant frontend" description = "The Home Assistant frontend"
readme = "README.md" readme = "README.md"

View File

@@ -92,7 +92,7 @@ export class HaFilterIntegrations extends LitElement {
setTimeout(() => { setTimeout(() => {
if (!this.expanded) return; if (!this.expanded) return;
this.renderRoot.querySelector("mwc-list")!.style.height = this.renderRoot.querySelector("mwc-list")!.style.height =
`${this.clientHeight - 49}px`; `${this.clientHeight - 49 - 32}px`; // 32px is the height of the search input
}, 300); }, 300);
} }
} }

View File

@@ -30,6 +30,10 @@ export class HaOutlinedTextField extends MdOutlinedTextField {
md-outlined-field { md-outlined-field {
background: var(--ha-outlined-text-field-container-color, transparent); background: var(--ha-outlined-text-field-container-color, transparent);
opacity: var(--ha-outlined-text-field-container-opacity, 1); opacity: var(--ha-outlined-text-field-container-opacity, 1);
border-start-start-radius: var(--_container-shape-start-start);
border-start-end-radius: var(--_container-shape-start-end);
border-end-end-radius: var(--_container-shape-end-end);
border-end-start-radius: var(--_container-shape-end-start);
} }
.input { .input {
font-family: Roboto, sans-serif; font-family: Roboto, sans-serif;

View File

@@ -1,4 +1,5 @@
import { consume } from "@lit-labs/context"; import { consume } from "@lit-labs/context";
import { ResizeController } from "@lit-labs/observers/resize-controller";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import "@material/web/divider/divider"; import "@material/web/divider/divider";
import { import {
@@ -153,6 +154,10 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
@query("#overflow-menu") private _overflowMenu!: HaMenu; @query("#overflow-menu") private _overflowMenu!: HaMenu;
private _sizeController = new ResizeController(this, {
callback: (entries) => entries[0]?.contentRect.width,
});
private _automations = memoizeOne( private _automations = memoizeOne(
( (
automations: AutomationEntity[], automations: AutomationEntity[],
@@ -373,7 +378,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
</div> </div>
</ha-menu-item> </ha-menu-item>
<md-divider role="separator" tabindex="-1"></md-divider> <md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createCategory}> <ha-menu-item @click=${this._bulkCreateCategory}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.category.editor.add")} ${this.hass.localize("ui.panel.config.category.editor.add")}
</div> </div>
@@ -409,12 +414,14 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
</ha-menu-item>`; </ha-menu-item>`;
})} })}
<md-divider role="separator" tabindex="-1"></md-divider> <md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createLabel}> <ha-menu-item @click=${this._bulkCreateLabel}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.labels.add_label")} ${this.hass.localize("ui.panel.config.labels.add_label")}
</div></ha-menu-item </div></ha-menu-item
>`; >`;
const labelsInOverflow =
(this._sizeController.value && this._sizeController.value < 700) ||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
return html` return html`
<hass-tabs-subpage-data-table <hass-tabs-subpage-data-table
.hass=${this.hass} .hass=${this.hass}
@@ -538,7 +545,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
</ha-assist-chip> </ha-assist-chip>
${categoryItems} ${categoryItems}
</ha-button-menu-new> </ha-button-menu-new>
${this.hass.dockedSidebar === "docked" ${labelsInOverflow
? nothing ? nothing
: html`<ha-button-menu-new slot="selection-bar"> : html`<ha-button-menu-new slot="selection-bar">
<ha-assist-chip <ha-assist-chip
@@ -600,8 +607,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
: nothing : nothing
} }
${ ${
this.narrow || this.hass.dockedSidebar === "docked" this.narrow || labelsInOverflow
? html` <ha-sub-menu> ? html`<ha-sub-menu>
<ha-menu-item slot="item"> <ha-menu-item slot="item">
<div slot="headline"> <div slot="headline">
${this.hass.localize( ${this.hass.localize(
@@ -1082,6 +1089,10 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
private async _handleBulkCategory(ev) { private async _handleBulkCategory(ev) {
const category = ev.currentTarget.value; const category = ev.currentTarget.value;
this._bulkAddCategory(category);
}
private async _bulkAddCategory(category: string) {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
promises.push( promises.push(
@@ -1096,6 +1107,10 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
private async _handleBulkLabel(ev) { private async _handleBulkLabel(ev) {
const label = ev.currentTarget.value; const label = ev.currentTarget.value;
const action = ev.currentTarget.action; const action = ev.currentTarget.action;
this._bulkLabel(label, action);
}
private async _bulkLabel(label: string, action: "add" | "remove") {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
promises.push( promises.push(
@@ -1128,17 +1143,28 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
await Promise.all(promises); await Promise.all(promises);
} }
private _createCategory() { private async _bulkCreateCategory() {
showCategoryRegistryDetailDialog(this, { showCategoryRegistryDetailDialog(this, {
scope: "automation", scope: "automation",
createEntry: (values) => createEntry: async (values) => {
createCategoryRegistryEntry(this.hass, "automation", values), const category = await createCategoryRegistryEntry(
this.hass,
"automation",
values
);
this._bulkAddCategory(category.category_id);
return category;
},
}); });
} }
private _createLabel() { private _bulkCreateLabel() {
showLabelDetailDialog(this, { showLabelDetailDialog(this, {
createEntry: (values) => createLabelRegistryEntry(this.hass, values), createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
this._bulkLabel(label.label_id, "add");
return label;
},
}); });
} }
@@ -1146,6 +1172,9 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
return [ return [
haStyle, haStyle,
css` css`
:host {
display: block;
}
hass-tabs-subpage-data-table { hass-tabs-subpage-data-table {
--data-table-row-height: 60px; --data-table-row-height: 60px;
} }

View File

@@ -575,7 +575,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
</ha-menu-item>`; </ha-menu-item>`;
})} })}
<md-divider role="separator" tabindex="-1"></md-divider> <md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createLabel}> <ha-menu-item @click=${this._bulkCreateLabel}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.labels.add_label")} ${this.hass.localize("ui.panel.config.labels.add_label")}
</div></ha-menu-item </div></ha-menu-item
@@ -801,6 +801,10 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
private async _handleBulkLabel(ev) { private async _handleBulkLabel(ev) {
const label = ev.currentTarget.value; const label = ev.currentTarget.value;
const action = ev.currentTarget.action; const action = ev.currentTarget.action;
this._bulkLabel(label, action);
}
private async _bulkLabel(label: string, action: "add" | "remove") {
const promises: Promise<DeviceRegistryEntry>[] = []; const promises: Promise<DeviceRegistryEntry>[] = [];
this._selected.forEach((deviceId) => { this._selected.forEach((deviceId) => {
promises.push( promises.push(
@@ -817,9 +821,13 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
await Promise.all(promises); await Promise.all(promises);
} }
private _createLabel() { private _bulkCreateLabel() {
showLabelDetailDialog(this, { showLabelDetailDialog(this, {
createEntry: (values) => createLabelRegistryEntry(this.hass, values), createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
this._bulkLabel(label.label_id, "add");
return label;
},
}); });
} }

View File

@@ -88,6 +88,10 @@ import { configSections } from "../ha-panel-config";
import "../integrations/ha-integration-overflow-menu"; import "../integrations/ha-integration-overflow-menu";
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog"; import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail"; import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import {
EntitySources,
fetchEntitySourcesWithCache,
} from "../../../data/entity_sources";
export interface StateEntity export interface StateEntity
extends Omit<EntityRegistryEntry, "id" | "unique_id"> { extends Omit<EntityRegistryEntry, "id" | "unique_id"> {
@@ -141,6 +145,8 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
@state() @state()
_labels!: LabelRegistryEntry[]; _labels!: LabelRegistryEntry[];
@state() private _entitySources?: EntitySources;
@query("hass-tabs-subpage-data-table", true) @query("hass-tabs-subpage-data-table", true)
private _dataTable!: HaTabsSubpageDataTable; private _dataTable!: HaTabsSubpageDataTable;
@@ -405,10 +411,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
const entryIds = entries const entryIds = entries
.filter((entry) => filter.value!.includes(entry.domain)) .filter((entry) => filter.value!.includes(entry.domain))
.map((entry) => entry.entry_id); .map((entry) => entry.entry_id);
filteredEntities = filteredEntities.filter( filteredEntities = filteredEntities.filter(
(entity) => (entity) =>
entity.config_entry_id && filter.value?.includes(entity.platform) ||
entryIds.includes(entity.config_entry_id) (entity.config_entry_id &&
entryIds.includes(entity.config_entry_id))
); );
filter.value!.forEach((domain) => filteredDomains.add(domain)); filter.value!.forEach((domain) => filteredDomains.add(domain));
} else if (key === "ha-filter-labels" && filter.value?.length) { } else if (key === "ha-filter-labels" && filter.value?.length) {
@@ -547,7 +555,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
</ha-menu-item>`; </ha-menu-item>`;
})} })}
<md-divider role="separator" tabindex="-1"></md-divider> <md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createLabel}> <ha-menu-item @click=${this._bulkCreateLabel}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.labels.add_label")} ${this.hass.localize("ui.panel.config.labels.add_label")}
</div></ha-menu-item </div></ha-menu-item
@@ -807,6 +815,9 @@ ${
}, },
}; };
this._setFiltersFromUrl(); this._setFiltersFromUrl();
fetchEntitySourcesWithCache(this.hass).then((sources) => {
this._entitySources = sources;
});
} }
private _setFiltersFromUrl() { private _setFiltersFromUrl() {
@@ -865,14 +876,18 @@ ${
this._filters = {}; this._filters = {};
} }
public willUpdate(changedProps: PropertyValues<this>): void { public willUpdate(changedProps: PropertyValues): void {
super.willUpdate(changedProps); super.willUpdate(changedProps);
const oldHass = changedProps.get("hass"); const oldHass = changedProps.get("hass");
let changed = false; let changed = false;
if (!this.hass || !this._entities) { if (!this.hass || !this._entities) {
return; return;
} }
if (changedProps.has("hass") || changedProps.has("_entities")) { if (
changedProps.has("hass") ||
changedProps.has("_entities") ||
changedProps.has("_entitySources")
) {
const stateEntities: StateEntity[] = []; const stateEntities: StateEntity[] = [];
const regEntityIds = new Set( const regEntityIds = new Set(
this._entities.map((entity) => entity.entity_id) this._entities.map((entity) => entity.entity_id)
@@ -883,6 +898,7 @@ ${
} }
if ( if (
!oldHass || !oldHass ||
changedProps.has("_entitySources") ||
this.hass.states[entityId] !== oldHass.states[entityId] this.hass.states[entityId] !== oldHass.states[entityId]
) { ) {
changed = true; changed = true;
@@ -890,7 +906,8 @@ ${
stateEntities.push({ stateEntities.push({
name: computeStateName(this.hass.states[entityId]), name: computeStateName(this.hass.states[entityId]),
entity_id: entityId, entity_id: entityId,
platform: computeDomain(entityId), platform:
this._entitySources?.[entityId]?.domain || computeDomain(entityId),
disabled_by: null, disabled_by: null,
hidden_by: null, hidden_by: null,
area_id: null, area_id: null,
@@ -1027,6 +1044,10 @@ ${
private async _handleBulkLabel(ev) { private async _handleBulkLabel(ev) {
const label = ev.currentTarget.value; const label = ev.currentTarget.value;
const action = ev.currentTarget.action; const action = ev.currentTarget.action;
await this._bulkLabel(label, action);
}
private async _bulkLabel(label: string, action: "add" | "remove") {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
const entityReg = const entityReg =
@@ -1047,6 +1068,16 @@ ${
await Promise.all(promises); await Promise.all(promises);
} }
private _bulkCreateLabel() {
showLabelDetailDialog(this, {
createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
this._bulkLabel(label.label_id, "add");
return label;
},
});
}
private _removeSelected() { private _removeSelected() {
const removeableEntities = this._selected.filter((entity) => { const removeableEntities = this._selected.filter((entity) => {
const stateObj = this.hass.states[entity]; const stateObj = this.hass.states[entity];
@@ -1123,12 +1154,6 @@ ${
}); });
} }
private _createLabel() {
showLabelDetailDialog(this, {
createEntry: (values) => createLabelRegistryEntry(this.hass, values),
});
}
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return [ return [
haStyle, haStyle,

View File

@@ -1,4 +1,5 @@
import { consume } from "@lit-labs/context"; import { consume } from "@lit-labs/context";
import { ResizeController } from "@lit-labs/observers/resize-controller";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { import {
mdiAlertCircle, mdiAlertCircle,
@@ -83,12 +84,12 @@ import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types"; import { HomeAssistant, Route } from "../../../types";
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category"; import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
import { configSections } from "../ha-panel-config"; import { configSections } from "../ha-panel-config";
import "../integrations/ha-integration-overflow-menu"; import "../integrations/ha-integration-overflow-menu";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import { isHelperDomain } from "./const"; import { isHelperDomain } from "./const";
import { showHelperDetailDialog } from "./show-dialog-helper-detail"; import { showHelperDetailDialog } from "./show-dialog-helper-detail";
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
type HelperItem = { type HelperItem = {
id: string; id: string;
@@ -163,6 +164,10 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
@state() private _filteredStateItems?: string[] | null; @state() private _filteredStateItems?: string[] | null;
private _sizeController = new ResizeController(this, {
callback: (entries) => entries[0]?.contentRect.width,
});
public hassSubscribe() { public hassSubscribe() {
return [ return [
subscribeConfigEntries( subscribeConfigEntries(
@@ -375,6 +380,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
type: configEntry.domain, type: configEntry.domain,
configEntry, configEntry,
entity: undefined, entity: undefined,
selectable: false,
})); }));
return [...states, ...entries] return [...states, ...entries]
@@ -437,7 +443,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
</div> </div>
</ha-menu-item> </ha-menu-item>
<md-divider role="separator" tabindex="-1"></md-divider> <md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createCategory}> <ha-menu-item @click=${this._bulkCreateCategory}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.category.editor.add")} ${this.hass.localize("ui.panel.config.category.editor.add")}
</div> </div>
@@ -472,12 +478,14 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
</ha-label> </ha-label>
</ha-menu-item> `; </ha-menu-item> `;
})}<md-divider role="separator" tabindex="-1"></md-divider> })}<md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createLabel}> <ha-menu-item @click=${this._bulkCreateLabel}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.labels.add_label")} ${this.hass.localize("ui.panel.config.labels.add_label")}
</div> </div>
</ha-menu-item>`; </ha-menu-item>`;
const labelsInOverflow =
(this._sizeController.value && this._sizeController.value < 700) ||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
return html` return html`
<hass-tabs-subpage-data-table <hass-tabs-subpage-data-table
.hass=${this.hass} .hass=${this.hass}
@@ -569,7 +577,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
</ha-assist-chip> </ha-assist-chip>
${categoryItems} ${categoryItems}
</ha-button-menu-new> </ha-button-menu-new>
${this.hass.dockedSidebar === "docked" ${labelsInOverflow
? nothing ? nothing
: html`<ha-button-menu-new slot="selection-bar"> : html`<ha-button-menu-new slot="selection-bar">
<ha-assist-chip <ha-assist-chip
@@ -586,7 +594,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
${labelItems} ${labelItems}
</ha-button-menu-new>`}` </ha-button-menu-new>`}`
: nothing} : nothing}
${this.narrow || this.hass.dockedSidebar === "docked" ${this.narrow || labelsInOverflow
? html` ? html`
<ha-button-menu-new has-overflow slot="selection-bar"> <ha-button-menu-new has-overflow slot="selection-bar">
${ ${
@@ -771,6 +779,10 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
private async _handleBulkCategory(ev) { private async _handleBulkCategory(ev) {
const category = ev.currentTarget.value; const category = ev.currentTarget.value;
this._bulkAddCategory(category);
}
private async _bulkAddCategory(category: string) {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
promises.push( promises.push(
@@ -785,6 +797,10 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
private async _handleBulkLabel(ev) { private async _handleBulkLabel(ev) {
const label = ev.currentTarget.value; const label = ev.currentTarget.value;
const action = ev.currentTarget.action; const action = ev.currentTarget.action;
this._bulkLabel(label, action);
}
private async _bulkLabel(label: string, action: "add" | "remove") {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
promises.push( promises.push(
@@ -939,17 +955,28 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
showHelperDetailDialog(this, {}); showHelperDetailDialog(this, {});
} }
private _createCategory() { private async _bulkCreateCategory() {
showCategoryRegistryDetailDialog(this, { showCategoryRegistryDetailDialog(this, {
scope: "helpers", scope: "helpers",
createEntry: (values) => createEntry: async (values) => {
createCategoryRegistryEntry(this.hass, "helpers", values), const category = await createCategoryRegistryEntry(
this.hass,
"helpers",
values
);
this._bulkAddCategory(category.category_id);
return category;
},
}); });
} }
private _createLabel() { private _bulkCreateLabel() {
showLabelDetailDialog(this, { showLabelDetailDialog(this, {
createEntry: (values) => createLabelRegistryEntry(this.hass, values), createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
this._bulkLabel(label.label_id, "add");
return label;
},
}); });
} }
@@ -957,6 +984,9 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
return [ return [
haStyle, haStyle,
css` css`
:host {
display: block;
}
hass-tabs-subpage-data-table { hass-tabs-subpage-data-table {
--data-table-row-height: 60px; --data-table-row-height: 60px;
} }

View File

@@ -1,7 +1,9 @@
import { consume } from "@lit-labs/context"; import { consume } from "@lit-labs/context";
import { ResizeController } from "@lit-labs/observers/resize-controller";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { import {
mdiChevronRight, mdiChevronRight,
mdiCog,
mdiContentDuplicate, mdiContentDuplicate,
mdiDelete, mdiDelete,
mdiDotsVertical, mdiDotsVertical,
@@ -82,6 +84,7 @@ import {
showAlertDialog, showAlertDialog,
showConfirmationDialog, showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box"; } from "../../../dialogs/generic/show-dialog-box";
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
import "../../../layouts/hass-tabs-subpage-data-table"; import "../../../layouts/hass-tabs-subpage-data-table";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";
@@ -137,6 +140,10 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
@consume({ context: fullEntitiesContext, subscribe: true }) @consume({ context: fullEntitiesContext, subscribe: true })
_entityReg!: EntityRegistryEntry[]; _entityReg!: EntityRegistryEntry[];
private _sizeController = new ResizeController(this, {
callback: (entries) => entries[0]?.contentRect.width,
});
private _scenes = memoizeOne( private _scenes = memoizeOne(
( (
scenes: SceneEntity[], scenes: SceneEntity[],
@@ -283,6 +290,13 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
), ),
action: () => this._showInfo(scene), action: () => this._showInfo(scene),
}, },
{
path: mdiCog,
label: this.hass.localize(
"ui.panel.config.automation.picker.show_settings"
),
action: () => this._openSettings(scene),
},
{ {
path: mdiPlay, path: mdiPlay,
label: this.hass.localize( label: this.hass.localize(
@@ -367,7 +381,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
</div> </div>
</ha-menu-item> </ha-menu-item>
<md-divider role="separator" tabindex="-1"></md-divider> <md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createCategory}> <ha-menu-item @click=${this._bulkCreateCategory}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.category.editor.add")} ${this.hass.localize("ui.panel.config.category.editor.add")}
</div> </div>
@@ -403,12 +417,14 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
</ha-menu-item>`; </ha-menu-item>`;
})} })}
<md-divider role="separator" tabindex="-1"></md-divider> <md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createLabel}> <ha-menu-item @click=${this._bulkCreateLabel}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.labels.add_label")} ${this.hass.localize("ui.panel.config.labels.add_label")}
</div></ha-menu-item </div></ha-menu-item
>`; >`;
const labelsInOverflow =
(this._sizeController.value && this._sizeController.value < 700) ||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
return html` return html`
<hass-tabs-subpage-data-table <hass-tabs-subpage-data-table
.hass=${this.hass} .hass=${this.hass}
@@ -516,7 +532,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
</ha-assist-chip> </ha-assist-chip>
${categoryItems} ${categoryItems}
</ha-button-menu-new> </ha-button-menu-new>
${this.hass.dockedSidebar === "docked" ${labelsInOverflow
? nothing ? nothing
: html`<ha-button-menu-new slot="selection-bar"> : html`<ha-button-menu-new slot="selection-bar">
<ha-assist-chip <ha-assist-chip
@@ -533,7 +549,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
${labelItems} ${labelItems}
</ha-button-menu-new>`}` </ha-button-menu-new>`}`
: nothing} : nothing}
${this.narrow || this.hass.dockedSidebar === "docked" ${this.narrow || labelsInOverflow
? html` ? html`
<ha-button-menu-new has-overflow slot="selection-bar"> <ha-button-menu-new has-overflow slot="selection-bar">
${ ${
@@ -760,6 +776,10 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
private async _handleBulkCategory(ev) { private async _handleBulkCategory(ev) {
const category = ev.currentTarget.value; const category = ev.currentTarget.value;
this._bulkAddCategory(category);
}
private async _bulkAddCategory(category: string) {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
promises.push( promises.push(
@@ -774,6 +794,10 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
private async _handleBulkLabel(ev) { private async _handleBulkLabel(ev) {
const label = ev.currentTarget.value; const label = ev.currentTarget.value;
const action = ev.currentTarget.action; const action = ev.currentTarget.action;
this._bulkLabel(label, action);
}
private async _bulkLabel(label: string, action: "add" | "remove") {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
promises.push( promises.push(
@@ -815,6 +839,13 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
fireEvent(this, "hass-more-info", { entityId: scene.entity_id }); fireEvent(this, "hass-more-info", { entityId: scene.entity_id });
} }
private _openSettings(scene: SceneEntity) {
showMoreInfoDialog(this, {
entityId: scene.entity_id,
view: "settings",
});
}
private _activateScene = async (scene: SceneEntity) => { private _activateScene = async (scene: SceneEntity) => {
await activateScene(this.hass, scene.entity_id); await activateScene(this.hass, scene.entity_id);
showToast(this, { showToast(this, {
@@ -878,17 +909,28 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
}); });
} }
private _createCategory() { private async _bulkCreateCategory() {
showCategoryRegistryDetailDialog(this, { showCategoryRegistryDetailDialog(this, {
scope: "scene", scope: "scene",
createEntry: (values) => createEntry: async (values) => {
createCategoryRegistryEntry(this.hass, "scene", values), const category = await createCategoryRegistryEntry(
this.hass,
"scene",
values
);
this._bulkAddCategory(category.category_id);
return category;
},
}); });
} }
private _createLabel() { private _bulkCreateLabel() {
showLabelDetailDialog(this, { showLabelDetailDialog(this, {
createEntry: (values) => createLabelRegistryEntry(this.hass, values), createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
this._bulkLabel(label.label_id, "add");
return label;
},
}); });
} }
@@ -896,6 +938,9 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
return [ return [
haStyle, haStyle,
css` css`
:host {
display: block;
}
hass-tabs-subpage-data-table { hass-tabs-subpage-data-table {
--data-table-row-height: 60px; --data-table-row-height: 60px;
} }

View File

@@ -1,6 +1,8 @@
import { consume } from "@lit-labs/context"; import { consume } from "@lit-labs/context";
import { ResizeController } from "@lit-labs/observers/resize-controller";
import { import {
mdiChevronRight, mdiChevronRight,
mdiCog,
mdiContentDuplicate, mdiContentDuplicate,
mdiDelete, mdiDelete,
mdiDotsVertical, mdiDotsVertical,
@@ -83,6 +85,7 @@ import {
showAlertDialog, showAlertDialog,
showConfirmationDialog, showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box"; } from "../../../dialogs/generic/show-dialog-box";
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
import "../../../layouts/hass-tabs-subpage-data-table"; import "../../../layouts/hass-tabs-subpage-data-table";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";
@@ -141,6 +144,10 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
@consume({ context: fullEntitiesContext, subscribe: true }) @consume({ context: fullEntitiesContext, subscribe: true })
_entityReg!: EntityRegistryEntry[]; _entityReg!: EntityRegistryEntry[];
private _sizeController = new ResizeController(this, {
callback: (entries) => entries[0]?.contentRect.width,
});
private _scripts = memoizeOne( private _scripts = memoizeOne(
( (
scripts: ScriptEntity[], scripts: ScriptEntity[],
@@ -294,6 +301,13 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
), ),
action: () => this._showInfo(script), action: () => this._showInfo(script),
}, },
{
path: mdiCog,
label: this.hass.localize(
"ui.panel.config.automation.picker.show_settings"
),
action: () => this._openSettings(script),
},
{ {
path: mdiTag, path: mdiTag,
label: this.hass.localize( label: this.hass.localize(
@@ -379,7 +393,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
)} )}
</div> </ha-menu-item </div> </ha-menu-item
><md-divider role="separator" tabindex="-1"></md-divider> ><md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createCategory}> <ha-menu-item @click=${this._bulkCreateCategory}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.category.editor.add")} ${this.hass.localize("ui.panel.config.category.editor.add")}
</div> </div>
@@ -415,12 +429,14 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
</ha-menu-item>`; </ha-menu-item>`;
})} })}
<md-divider role="separator" tabindex="-1"></md-divider> <md-divider role="separator" tabindex="-1"></md-divider>
<ha-menu-item @click=${this._createLabel}> <ha-menu-item @click=${this._bulkCreateLabel}>
<div slot="headline"> <div slot="headline">
${this.hass.localize("ui.panel.config.labels.add_label")} ${this.hass.localize("ui.panel.config.labels.add_label")}
</div></ha-menu-item </div></ha-menu-item
>`; >`;
const labelsInOverflow =
(this._sizeController.value && this._sizeController.value < 700) ||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
return html` return html`
<hass-tabs-subpage-data-table <hass-tabs-subpage-data-table
.hass=${this.hass} .hass=${this.hass}
@@ -542,7 +558,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
</ha-assist-chip> </ha-assist-chip>
${categoryItems} ${categoryItems}
</ha-button-menu-new> </ha-button-menu-new>
${this.hass.dockedSidebar === "docked" ${labelsInOverflow
? nothing ? nothing
: html`<ha-button-menu-new slot="selection-bar"> : html`<ha-button-menu-new slot="selection-bar">
<ha-assist-chip <ha-assist-chip
@@ -559,7 +575,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
${labelItems} ${labelItems}
</ha-button-menu-new>`}` </ha-button-menu-new>`}`
: nothing} : nothing}
${this.narrow || this.hass.dockedSidebar === "docked" ${this.narrow || labelsInOverflow
? html` ? html`
<ha-button-menu-new has-overflow slot="selection-bar"> <ha-button-menu-new has-overflow slot="selection-bar">
${ ${
@@ -829,6 +845,10 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
private async _handleBulkCategory(ev) { private async _handleBulkCategory(ev) {
const category = ev.currentTarget.value; const category = ev.currentTarget.value;
this._bulkAddCategory(category);
}
private async _bulkAddCategory(category: string) {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
promises.push( promises.push(
@@ -843,6 +863,10 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
private async _handleBulkLabel(ev) { private async _handleBulkLabel(ev) {
const label = ev.currentTarget.value; const label = ev.currentTarget.value;
const action = ev.currentTarget.action; const action = ev.currentTarget.action;
this._bulkLabel(label, action);
}
private async _bulkLabel(label: string, action: "add" | "remove") {
const promises: Promise<UpdateEntityRegistryEntryResult>[] = []; const promises: Promise<UpdateEntityRegistryEntryResult>[] = [];
this._selected.forEach((entityId) => { this._selected.forEach((entityId) => {
promises.push( promises.push(
@@ -895,6 +919,13 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
fireEvent(this, "hass-more-info", { entityId: script.entity_id }); fireEvent(this, "hass-more-info", { entityId: script.entity_id });
} }
private _openSettings(script: any) {
showMoreInfoDialog(this, {
entityId: script.entity_id,
view: "settings",
});
}
private _showTrace(script: any) { private _showTrace(script: any) {
const entry = this.entityRegistry.find( const entry = this.entityRegistry.find(
(e) => e.entity_id === script.entity_id (e) => e.entity_id === script.entity_id
@@ -994,17 +1025,28 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
} }
} }
private _createCategory() { private async _bulkCreateCategory() {
showCategoryRegistryDetailDialog(this, { showCategoryRegistryDetailDialog(this, {
scope: "script", scope: "script",
createEntry: (values) => createEntry: async (values) => {
createCategoryRegistryEntry(this.hass, "script", values), const category = await createCategoryRegistryEntry(
this.hass,
"script",
values
);
this._bulkAddCategory(category.category_id);
return category;
},
}); });
} }
private _createLabel() { private _bulkCreateLabel() {
showLabelDetailDialog(this, { showLabelDetailDialog(this, {
createEntry: (values) => createLabelRegistryEntry(this.hass, values), createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
this._bulkLabel(label.label_id, "add");
return label;
},
}); });
} }
@@ -1012,6 +1054,9 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
return [ return [
haStyle, haStyle,
css` css`
:host {
display: block;
}
hass-tabs-subpage-data-table { hass-tabs-subpage-data-table {
--data-table-row-height: 60px; --data-table-row-height: 60px;
} }

View File

@@ -9,6 +9,7 @@ import { property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { ensureArray } from "../../common/array/ensure-array"; import { ensureArray } from "../../common/array/ensure-array";
import { storage } from "../../common/decorators/storage"; import { storage } from "../../common/decorators/storage";
import { computeDomain } from "../../common/entity/compute_domain";
import { navigate } from "../../common/navigate"; import { navigate } from "../../common/navigate";
import { constructUrlCurrentPath } from "../../common/url/construct-url"; import { constructUrlCurrentPath } from "../../common/url/construct-url";
import { import {
@@ -27,37 +28,29 @@ import "../../components/ha-menu-button";
import "../../components/ha-target-picker"; import "../../components/ha-target-picker";
import "../../components/ha-top-app-bar-fixed"; import "../../components/ha-top-app-bar-fixed";
import { import {
AreaDeviceLookup,
AreaEntityLookup,
getAreaDeviceLookup,
getAreaEntityLookup,
} from "../../data/area_registry";
import {
DeviceEntityLookup,
getDeviceEntityLookup,
subscribeDeviceRegistry,
} from "../../data/device_registry";
import { subscribeEntityRegistry } from "../../data/entity_registry";
import {
HistoryResult,
computeHistory,
subscribeHistory,
HistoryStates,
EntityHistoryState, EntityHistoryState,
HistoryResult,
HistoryStates,
LineChartState,
LineChartUnit, LineChartUnit,
computeGroupKey, computeGroupKey,
LineChartState, computeHistory,
subscribeHistory,
} from "../../data/history"; } from "../../data/history";
import { fetchStatistics, Statistics } from "../../data/recorder"; import { Statistics, fetchStatistics } from "../../data/recorder";
import {
expandAreaTarget,
expandDeviceTarget,
expandFloorTarget,
expandLabelTarget,
} from "../../data/selector";
import { getSensorNumericDeviceClasses } from "../../data/sensor"; import { getSensorNumericDeviceClasses } from "../../data/sensor";
import { SubscribeMixin } from "../../mixins/subscribe-mixin"; import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { fileDownload } from "../../util/file_download"; import { fileDownload } from "../../util/file_download";
import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
import { computeDomain } from "../../common/entity/compute_domain";
class HaPanelHistory extends SubscribeMixin(LitElement) { class HaPanelHistory extends LitElement {
@property({ attribute: false }) hass!: HomeAssistant; @property({ attribute: false }) hass!: HomeAssistant;
@property({ reflect: true, type: Boolean }) public narrow = false; @property({ reflect: true, type: Boolean }) public narrow = false;
@@ -83,12 +76,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
@state() private _statisticsHistory?: HistoryResult; @state() private _statisticsHistory?: HistoryResult;
@state() private _deviceEntityLookup?: DeviceEntityLookup;
@state() private _areaEntityLookup?: AreaEntityLookup;
@state() private _areaDeviceLookup?: AreaDeviceLookup;
@state() @state()
private _showBack?: boolean; private _showBack?: boolean;
@@ -123,18 +110,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
this._unsubscribeHistory(); this._unsubscribeHistory();
} }
public hassSubscribe(): UnsubscribeFunc[] {
return [
subscribeEntityRegistry(this.hass.connection!, (entities) => {
this._deviceEntityLookup = getDeviceEntityLookup(entities);
this._areaEntityLookup = getAreaEntityLookup(entities);
}),
subscribeDeviceRegistry(this.hass.connection!, (devices) => {
this._areaDeviceLookup = getAreaDeviceLookup(devices);
}),
];
}
private _goBack(): void { private _goBack(): void {
history.back(); history.back();
} }
@@ -332,7 +307,9 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
const entityIds = searchParams.entity_id; const entityIds = searchParams.entity_id;
const deviceIds = searchParams.device_id; const deviceIds = searchParams.device_id;
const areaIds = searchParams.area_id; const areaIds = searchParams.area_id;
if (entityIds || deviceIds || areaIds) { const floorIds = searchParams.floor_id;
const labelsIds = searchParams.label_id;
if (entityIds || deviceIds || areaIds || floorIds || labelsIds) {
this._targetPickerValue = {}; this._targetPickerValue = {};
} }
if (entityIds) { if (entityIds) {
@@ -347,6 +324,14 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
const splitIds = areaIds.split(","); const splitIds = areaIds.split(",");
this._targetPickerValue!.area_id = splitIds; this._targetPickerValue!.area_id = splitIds;
} }
if (floorIds) {
const splitIds = floorIds.split(",");
this._targetPickerValue!.floor_id = splitIds;
}
if (labelsIds) {
const splitIds = labelsIds.split(",");
this._targetPickerValue!.label_id = splitIds;
}
const startDate = searchParams.start_date; const startDate = searchParams.start_date;
if (startDate) { if (startDate) {
@@ -522,95 +507,77 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
private _getEntityIds(): string[] { private _getEntityIds(): string[] {
return this.__getEntityIds( return this.__getEntityIds(
this._targetPickerValue, this._targetPickerValue,
this._deviceEntityLookup, this.hass.entities,
this._areaEntityLookup, this.hass.devices,
this._areaDeviceLookup this.hass.areas
); );
} }
private __getEntityIds = memoizeOne( private __getEntityIds = memoizeOne(
( (
targetPickerValue: HassServiceTarget, targetPickerValue: HassServiceTarget,
deviceEntityLookup: DeviceEntityLookup | undefined, entities: HomeAssistant["entities"],
areaEntityLookup: AreaEntityLookup | undefined, devices: HomeAssistant["devices"],
areaDeviceLookup: AreaDeviceLookup | undefined areas: HomeAssistant["areas"]
): string[] => { ): string[] => {
if ( if (!targetPickerValue) {
!targetPickerValue ||
deviceEntityLookup === undefined ||
areaEntityLookup === undefined ||
areaDeviceLookup === undefined
) {
return []; return [];
} }
const entityIds = new Set<string>(); const targetSelector = { target: {} };
let { const targetEntities = new Set(ensureArray(targetPickerValue.entity_id));
area_id: searchingAreaId, const targetDevices = new Set(ensureArray(targetPickerValue.device_id));
device_id: searchingDeviceId, const targetAreas = new Set(ensureArray(targetPickerValue.area_id));
entity_id: searchingEntityId, const targetFloors = new Set(ensureArray(targetPickerValue.floor_id));
} = targetPickerValue; const targetLabels = new Set(ensureArray(targetPickerValue.label_id));
if (searchingAreaId) { targetLabels.forEach((labelId) => {
searchingAreaId = ensureArray(searchingAreaId); const expanded = expandLabelTarget(
for (const singleSearchingAreaId of searchingAreaId) { this.hass,
const foundEntities = areaEntityLookup[singleSearchingAreaId]; labelId,
if (foundEntities?.length) { areas,
for (const foundEntity of foundEntities) { devices,
if (foundEntity.entity_category === null) { entities,
entityIds.add(foundEntity.entity_id); targetSelector
} );
} expanded.devices.forEach((id) => targetDevices.add(id));
} expanded.entities.forEach((id) => targetEntities.add(id));
expanded.areas.forEach((id) => targetAreas.add(id));
});
const foundDevices = areaDeviceLookup[singleSearchingAreaId]; targetFloors.forEach((floorId) => {
if (!foundDevices?.length) { const expanded = expandFloorTarget(
continue; this.hass,
} floorId,
areas,
targetSelector
);
expanded.areas.forEach((id) => targetAreas.add(id));
});
for (const foundDevice of foundDevices) { targetAreas.forEach((areaId) => {
const foundDeviceEntities = deviceEntityLookup[foundDevice.id]; const expanded = expandAreaTarget(
if (!foundDeviceEntities?.length) { this.hass,
continue; areaId,
} devices,
entities,
targetSelector
);
expanded.devices.forEach((id) => targetDevices.add(id));
expanded.entities.forEach((id) => targetEntities.add(id));
});
for (const foundDeviceEntity of foundDeviceEntities) { targetDevices.forEach((deviceId) => {
if ( const expanded = expandDeviceTarget(
(!foundDeviceEntity.area_id || this.hass,
foundDeviceEntity.area_id === singleSearchingAreaId) && deviceId,
foundDeviceEntity.entity_category === null entities,
) { targetSelector
entityIds.add(foundDeviceEntity.entity_id); );
} expanded.entities.forEach((id) => targetEntities.add(id));
} });
}
}
}
if (searchingDeviceId) { return Array.from(targetEntities);
searchingDeviceId = ensureArray(searchingDeviceId);
for (const singleSearchingDeviceId of searchingDeviceId) {
const foundEntities = deviceEntityLookup[singleSearchingDeviceId];
if (!foundEntities?.length) {
continue;
}
for (const foundEntity of foundEntities) {
if (foundEntity.entity_category === null) {
entityIds.add(foundEntity.entity_id);
}
}
}
}
if (searchingEntityId) {
searchingEntityId = ensureArray(searchingEntityId);
for (const singleSearchingEntityId of searchingEntityId) {
entityIds.add(singleSearchingEntityId);
}
}
return [...entityIds];
} }
); );
@@ -639,6 +606,12 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
"," ","
); );
} }
if (this._targetPickerValue.label_id) {
params.label_id = ensureArray(this._targetPickerValue.label_id).join(",");
}
if (this._targetPickerValue.floor_id) {
params.floor_id = ensureArray(this._targetPickerValue.floor_id).join(",");
}
if (this._targetPickerValue.area_id) { if (this._targetPickerValue.area_id) {
params.area_id = ensureArray(this._targetPickerValue.area_id).join(","); params.area_id = ensureArray(this._targetPickerValue.area_id).join(",");
} }