Save data table filters in session storage (#20894)

* Save data table filters in session storage

* typing fix

* remove url logic, rename storage key
This commit is contained in:
Bram Kragten 2024-05-29 12:20:30 +02:00 committed by GitHub
parent 91e5fcacd5
commit 2921161336
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 324 additions and 95 deletions

View File

@ -108,6 +108,8 @@ export const storage =
subscribe?: boolean;
state?: boolean;
stateOptions?: InternalPropertyDeclaration;
serializer?: (value: any) => any;
deserializer?: (value: any) => any;
}): any =>
(clsElement: ClassElement) => {
const storageName = options.storage || "localStorage";
@ -141,7 +143,9 @@ export const storage =
const getValue = (): any =>
storageInstance.hasKey(storageKey!)
? storageInstance.getValue(storageKey!)
? options.deserializer
? options.deserializer(storageInstance.getValue(storageKey!))
: storageInstance.getValue(storageKey!)
: initVal;
const setValue = (el: ReactiveElement, value: any) => {
@ -149,7 +153,10 @@ export const storage =
if (options.state) {
oldValue = getValue();
}
storageInstance.setValue(storageKey!, value);
storageInstance.setValue(
storageKey!,
options.serializer ? options.serializer(value) : value
);
if (options.state) {
el.requestUpdate(clsElement.key, oldValue);
}

View File

@ -11,6 +11,7 @@ declare global {
export interface NavigateOptions {
replace?: boolean;
data?: any;
}
export const navigate = (path: string, options?: NavigateOptions) => {
@ -24,7 +25,7 @@ export const navigate = (path: string, options?: NavigateOptions) => {
if (__DEMO__) {
if (replace) {
mainWindow.history.replaceState(
mainWindow.history.state?.root ? { root: true } : null,
mainWindow.history.state?.root ? { root: true } : options?.data ?? null,
"",
`${mainWindow.location.pathname}#${path}`
);
@ -33,12 +34,12 @@ export const navigate = (path: string, options?: NavigateOptions) => {
}
} else if (replace) {
mainWindow.history.replaceState(
mainWindow.history.state?.root ? { root: true } : null,
mainWindow.history.state?.root ? { root: true } : options?.data ?? null,
"",
path
);
} else {
mainWindow.history.pushState(null, "", path);
mainWindow.history.pushState(options?.data ?? null, "", path);
}
fireEvent(mainWindow, "location-changed", {
replace,

View File

@ -1,7 +1,14 @@
import { SelectedDetail } from "@material/mwc-list";
import "@material/mwc-menu/mwc-menu-surface";
import { mdiFilterVariantRemove } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import {
css,
CSSResultGroup,
html,
LitElement,
nothing,
PropertyValues,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { Blueprints, fetchBlueprints } from "../data/blueprint";
@ -25,6 +32,16 @@ export class HaFilterBlueprints extends LitElement {
@state() private _blueprints?: Blueprints;
public willUpdate(properties: PropertyValues) {
super.willUpdate(properties);
if (!this.hasUpdated) {
if (this.value?.length) {
this._findRelated();
}
}
}
protected render() {
return html`
<ha-expansion-panel
@ -96,7 +113,6 @@ export class HaFilterBlueprints extends LitElement {
ev: CustomEvent<SelectedDetail<Set<number>>>
) {
const blueprints = this._blueprints!;
const relatedPromises: Promise<RelatedResult>[] = [];
if (!ev.detail.index.size) {
fireEvent(this, "data-table-filter-changed", {
@ -112,13 +128,33 @@ export class HaFilterBlueprints extends LitElement {
for (const index of ev.detail.index) {
const blueprintId = Object.keys(blueprints)[index];
value.push(blueprintId);
}
this.value = value;
this._findRelated();
}
private async _findRelated() {
if (!this.value?.length) {
fireEvent(this, "data-table-filter-changed", {
value: [],
items: undefined,
});
this.value = [];
return;
}
const relatedPromises: Promise<RelatedResult>[] = [];
for (const blueprintId of this.value) {
if (this.type) {
relatedPromises.push(
findRelated(this.hass, `${this.type}_blueprint`, blueprintId)
);
}
}
this.value = value;
const results = await Promise.all(relatedPromises);
const items: Set<string> = new Set();
for (const result of results) {
@ -128,7 +164,7 @@ export class HaFilterBlueprints extends LitElement {
}
fireEvent(this, "data-table-filter-changed", {
value,
value: this.value,
items: this.type ? items : undefined,
});
}

View File

@ -41,6 +41,9 @@ export class HaFilterDevices extends LitElement {
if (!this.hasUpdated) {
loadVirtualizer();
if (this.value?.length) {
this._findRelated();
}
}
}

View File

@ -42,6 +42,9 @@ export class HaFilterEntities extends LitElement {
if (!this.hasUpdated) {
loadVirtualizer();
if (this.value?.length) {
this._findRelated();
}
}
}
@ -186,15 +189,12 @@ export class HaFilterEntities extends LitElement {
return;
}
const value: string[] = [];
for (const entityId of this.value) {
value.push(entityId);
if (this.type) {
relatedPromises.push(findRelated(this.hass, "entity", entityId));
}
}
this.value = value;
const results = await Promise.all(relatedPromises);
const items: Set<string> = new Set();
for (const result of results) {
@ -204,7 +204,7 @@ export class HaFilterEntities extends LitElement {
}
fireEvent(this, "data-table-filter-changed", {
value,
value: this.value,
items: this.type ? items : undefined,
});
}

View File

@ -1,7 +1,14 @@
import "@material/mwc-menu/mwc-menu-surface";
import { mdiFilterVariantRemove, mdiTextureBox } from "@mdi/js";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
import {
CSSResultGroup,
LitElement,
PropertyValues,
css,
html,
nothing,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { repeat } from "lit/directives/repeat";
@ -42,6 +49,16 @@ export class HaFilterFloorAreas extends SubscribeMixin(LitElement) {
@state() private _floors?: FloorRegistryEntry[];
public willUpdate(properties: PropertyValues) {
super.willUpdate(properties);
if (!this.hasUpdated) {
if (this.value?.floors?.length || this.value?.areas?.length) {
this._findRelated();
}
}
}
protected render() {
const areas = this._areas(this.hass.areas, this._floors);
@ -190,6 +207,10 @@ export class HaFilterFloorAreas extends SubscribeMixin(LitElement) {
}
}
protected firstUpdated() {
this._findRelated();
}
private _expandedWillChange(ev) {
this._shouldRender = ev.detail.expanded;
}

View File

@ -0,0 +1,28 @@
export interface DataTableFilters {
[key: string]: {
value: string[] | { key: string[] } | undefined;
items: Set<string> | undefined;
};
}
export const serializeFilters = (value: DataTableFilters) => {
const serializedValue = {};
Object.entries(value).forEach(([key, val]) => {
serializedValue[key] = {
value: val.value,
items: val.items instanceof Set ? Array.from(val.items) : val.items,
};
});
return serializedValue;
};
export const deserializeFilters = (value: DataTableFilters) => {
const deserializedValue = {};
Object.entries(value).forEach(([key, val]) => {
deserializedValue[key] = {
value: val.value,
items: Array.isArray(val.items) ? new Set(val.items) : val.items,
};
});
return deserializedValue;
};

View File

@ -114,6 +114,11 @@ import { showCategoryRegistryDetailDialog } from "../category/show-dialog-catego
import { configSections } from "../ha-panel-config";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import { showNewAutomationDialog } from "./show-dialog-new-automation";
import {
DataTableFilters,
deserializeFilters,
serializeFilters,
} from "../../../data/data_table_filters";
type AutomationItem = AutomationEntity & {
name: string;
@ -140,10 +145,15 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
@state() private _filteredAutomations?: string[] | null;
@state() private _filters: Record<
string,
{ value: string[] | undefined; items: Set<string> | undefined }
> = {};
@storage({
storage: "sessionStorage",
key: "automation-table-filters-full",
state: true,
subscribe: false,
serializer: serializeFilters,
deserializer: deserializeFilters,
})
private _filters: DataTableFilters = {};
@state() private _expandedFilter?: string;
@ -916,7 +926,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
private _filterChanged(ev) {
const type = ev.target.localName;
this._filters[type] = ev.detail;
this._filters = { ...this._filters, [type]: ev.detail };
this._applyFilters();
}
@ -935,7 +945,11 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
items.intersection(filter.items)
: new Set([...items].filter((x) => filter.items!.has(x)));
}
if (key === "ha-filter-categories" && filter.value?.length) {
if (
key === "ha-filter-categories" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const categoryItems: Set<string> = new Set();
this.automations
.filter(
@ -956,13 +970,17 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
items.intersection(categoryItems)
: new Set([...items].filter((x) => categoryItems!.has(x)));
}
if (key === "ha-filter-labels" && filter.value?.length) {
if (
key === "ha-filter-labels" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const labelItems: Set<string> = new Set();
this.automations
.filter((automation) =>
this._entityReg
.find((reg) => reg.entity_id === automation.entity_id)
?.labels.some((lbl) => filter.value!.includes(lbl))
?.labels.some((lbl) => (filter.value as string[]).includes(lbl))
)
.forEach((automation) => labelItems.add(automation.entity_id));
if (!items) {

View File

@ -10,6 +10,7 @@ import {
import {
CSSResultGroup,
LitElement,
PropertyValues,
TemplateResult,
css,
html,
@ -85,6 +86,11 @@ import "../integrations/ha-integration-overflow-menu";
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import {
serializeFilters,
deserializeFilters,
DataTableFilters,
} from "../../../data/data_table_filters";
interface DeviceRowData extends DeviceRegistryEntry {
device?: DeviceRowData;
@ -118,10 +124,15 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
@state() private _filter: string = history.state?.filter || "";
@state() private _filters: Record<
string,
{ value: string[] | undefined; items: Set<string> | undefined }
> = {};
@storage({
storage: "sessionStorage",
key: "devices-table-filters-full",
state: true,
subscribe: false,
serializer: serializeFilters,
deserializer: deserializeFilters,
})
private _filters: DataTableFilters = {};
@state() private _expandedFilter?: string;
@ -180,14 +191,11 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
},
]);
firstUpdated() {
this._filters = {
"ha-filter-states": {
value: [],
items: undefined,
},
};
this._setFiltersFromUrl();
willUpdate(changedProps: PropertyValues) {
super.willUpdate(changedProps);
if (!this.hasUpdated) {
this._setFiltersFromUrl();
}
}
private _setFiltersFromUrl() {
@ -196,7 +204,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
...this._filters,
"ha-filter-states": {
value: [
...(this._filters["ha-filter-states"]?.value || []),
...((this._filters["ha-filter-states"]?.value as string[]) || []),
"disabled",
],
items: undefined,
@ -212,7 +220,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
...this._filters,
"ha-filter-states": {
value: [
...(this._filters["ha-filter-states"]?.value || []),
...((this._filters["ha-filter-states"]?.value as string[]) || []),
"disabled",
],
items: undefined,
@ -253,10 +261,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
entities: EntityRegistryEntry[],
areas: HomeAssistant["areas"],
manifests: IntegrationManifest[],
filters: Record<
string,
{ value: string[] | undefined; items: Set<string> | undefined }
>,
filters: DataTableFilters,
localize: LocalizeFunc,
labelReg?: LabelRegistryEntry[]
) => {
@ -295,15 +300,21 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
const filteredDomains = new Set<string>();
Object.entries(filters).forEach(([key, filter]) => {
if (key === "config_entry" && filter.value?.length) {
if (
key === "config_entry" &&
Array.isArray(filter.value) &&
filter.value.length
) {
outputDevices = outputDevices.filter((device) =>
device.config_entries.some((entryId) =>
filter.value?.includes(entryId)
(filter.value as string[]).includes(entryId)
)
);
const configEntries = entries.filter(
(entry) => entry.entry_id && filter.value?.includes(entry.entry_id)
(entry) =>
entry.entry_id &&
(filter.value as string[]).includes(entry.entry_id)
);
configEntries.forEach((configEntry) => {
@ -312,17 +323,31 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
if (configEntries.length === 1) {
filteredConfigEntry = configEntries[0];
}
} else if (key === "ha-filter-integrations" && filter.value?.length) {
} else if (
key === "ha-filter-integrations" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const entryIds = entries
.filter((entry) => filter.value!.includes(entry.domain))
.filter((entry) =>
(filter.value as string[]).includes(entry.domain)
)
.map((entry) => entry.entry_id);
outputDevices = outputDevices.filter((device) =>
device.config_entries.some((entryId) => entryIds.includes(entryId))
);
filter.value!.forEach((domain) => filteredDomains.add(domain));
} else if (key === "ha-filter-labels" && filter.value?.length) {
(filter.value as string[]).forEach((domain) =>
filteredDomains.add(domain)
);
} else if (
key === "ha-filter-labels" &&
Array.isArray(filter.value) &&
filter.value.length
) {
outputDevices = outputDevices.filter((device) =>
device.labels.some((lbl) => filter.value!.includes(lbl))
device.labels.some((lbl) =>
(filter.value as string[]).includes(lbl)
)
);
} else if (filter.items) {
outputDevices = outputDevices.filter((device) =>
@ -331,7 +356,9 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
}
});
const stateFilters = filters["ha-filter-states"]?.value;
const stateFilters = filters["ha-filter-states"]?.value as
| string[]
| undefined;
const showDisabled =
stateFilters?.length && stateFilters.includes("disabled");
@ -698,7 +725,8 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
>
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
</ha-fab>
${this._filters.config_entry?.value?.length
${Array.isArray(this._filters.config_entry?.value) &&
this._filters.config_entry?.value.length
? html`<ha-alert slot="filter-pane">
Filtering by config entry
${this.entries?.find(

View File

@ -98,6 +98,11 @@ import { configSections } from "../ha-panel-config";
import "../integrations/ha-integration-overflow-menu";
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import {
serializeFilters,
deserializeFilters,
DataTableFilters,
} from "../../../data/data_table_filters";
export interface StateEntity
extends Omit<EntityRegistryEntry, "id" | "unique_id"> {
@ -143,10 +148,15 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
@state() private _searchParms = new URLSearchParams(window.location.search);
@state() private _filters: Record<
string,
{ value: string[] | undefined; items: Set<string> | undefined }
> = {};
@storage({
storage: "sessionStorage",
key: "entities-table-filters-full",
state: true,
subscribe: false,
serializer: serializeFilters,
deserializer: deserializeFilters,
})
private _filters: DataTableFilters = {};
@state() private _selected: string[] = [];
@ -414,16 +424,13 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
devices: HomeAssistant["devices"],
areas: HomeAssistant["areas"],
stateEntities: StateEntity[],
filters: Record<
string,
{ value: string[] | undefined; items: Set<string> | undefined }
>,
filters: DataTableFilters,
entries?: ConfigEntry[],
labelReg?: LabelRegistryEntry[]
) => {
const result: EntityRow[] = [];
const stateFilters = filters["ha-filter-states"]?.value;
const stateFilters = filters["ha-filter-states"]?.value as string[];
const showEnabled =
!stateFilters?.length || stateFilters.includes("enabled");
@ -448,11 +455,15 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
const filteredDomains = new Set<string>();
Object.entries(filters).forEach(([key, filter]) => {
if (key === "config_entry" && filter.value?.length) {
if (
key === "config_entry" &&
Array.isArray(filter.value) &&
filter.value.length
) {
filteredEntities = filteredEntities.filter(
(entity) =>
entity.config_entry_id &&
filter.value?.includes(entity.config_entry_id)
(filter.value as string[]).includes(entity.config_entry_id)
);
if (!entries) {
@ -461,7 +472,9 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
}
const configEntries = entries.filter(
(entry) => entry.entry_id && filter.value?.includes(entry.entry_id)
(entry) =>
entry.entry_id &&
(filter.value as string[]).includes(entry.entry_id)
);
configEntries.forEach((configEntry) => {
@ -470,29 +483,45 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
if (configEntries.length === 1) {
filteredConfigEntry = configEntries[0];
}
} else if (key === "ha-filter-integrations" && filter.value?.length) {
} else if (
key === "ha-filter-integrations" &&
Array.isArray(filter.value) &&
filter.value.length
) {
if (!entries) {
this._loadConfigEntries();
return;
}
const entryIds = entries
.filter((entry) => filter.value!.includes(entry.domain))
.filter((entry) =>
(filter.value as string[]).includes(entry.domain)
)
.map((entry) => entry.entry_id);
filteredEntities = filteredEntities.filter(
(entity) =>
filter.value?.includes(entity.platform) ||
(filter.value as string[]).includes(entity.platform) ||
(entity.config_entry_id &&
entryIds.includes(entity.config_entry_id))
);
filter.value!.forEach((domain) => filteredDomains.add(domain));
} else if (key === "ha-filter-domains" && filter.value?.length) {
} else if (
key === "ha-filter-domains" &&
Array.isArray(filter.value) &&
filter.value.length
) {
filteredEntities = filteredEntities.filter((entity) =>
filter.value?.includes(computeDomain(entity.entity_id))
(filter.value as string[]).includes(computeDomain(entity.entity_id))
);
} else if (key === "ha-filter-labels" && filter.value?.length) {
} else if (
key === "ha-filter-labels" &&
Array.isArray(filter.value) &&
filter.value.length
) {
filteredEntities = filteredEntities.filter((entity) =>
entity.labels.some((lbl) => filter.value!.includes(lbl))
entity.labels.some((lbl) =>
(filter.value as string[]).includes(lbl)
)
);
} else if (filter.items) {
filteredEntities = filteredEntities.filter((entity) =>
@ -811,7 +840,8 @@ ${
</ha-button-menu-new>
${
this._filters.config_entry?.value?.length
Array.isArray(this._filters.config_entry?.value) &&
this._filters.config_entry?.value.length
? html`<ha-alert slot="filter-pane">
Filtering by config entry
${this._entries?.find(
@ -913,6 +943,9 @@ ${
}
protected firstUpdated() {
if (Object.keys(this._filters).length) {
return;
}
this._filters = {
"ha-filter-states": {
value: ["enabled"],

View File

@ -96,6 +96,11 @@ import "../integrations/ha-integration-overflow-menu";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import { isHelperDomain } from "./const";
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
import {
serializeFilters,
deserializeFilters,
DataTableFilters,
} from "../../../data/data_table_filters";
type HelperItem = {
id: string;
@ -164,10 +169,15 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
@state() private _activeFilters?: string[];
@state() private _filters: Record<
string,
{ value: string[] | undefined; items: Set<string> | undefined }
> = {};
@storage({
storage: "sessionStorage",
key: "helpers-table-filters-full",
state: true,
subscribe: false,
serializer: serializeFilters,
deserializer: deserializeFilters,
})
private _filters: DataTableFilters = {};
@state() private _expandedFilter?: string;
@ -722,7 +732,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
private _filterChanged(ev) {
const type = ev.target.localName;
this._filters[type] = ev.detail;
this._filters = { ...this._filters, [type]: ev.detail };
this._applyFilters();
}
@ -741,13 +751,17 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
items.intersection(filter.items)
: new Set([...items].filter((x) => filter.items!.has(x)));
}
if (key === "ha-filter-labels" && filter.value?.length) {
if (
key === "ha-filter-labels" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const labelItems: Set<string> = new Set();
this._stateItems
.filter((stateItem) =>
this._entityReg
.find((reg) => reg.entity_id === stateItem.entity_id)
?.labels.some((lbl) => filter.value!.includes(lbl))
?.labels.some((lbl) => (filter.value as string[]).includes(lbl))
)
.forEach((stateItem) => labelItems.add(stateItem.entity_id));
if (!items) {
@ -760,7 +774,11 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
items.intersection(labelItems)
: new Set([...items].filter((x) => labelItems!.has(x)));
}
if (key === "ha-filter-categories" && filter.value?.length) {
if (
key === "ha-filter-categories" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const categoryItems: Set<string> = new Set();
this._stateItems
.filter(

View File

@ -104,6 +104,11 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
import { configSections } from "../ha-panel-config";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import {
serializeFilters,
deserializeFilters,
DataTableFilters,
} from "../../../data/data_table_filters";
type SceneItem = SceneEntity & {
name: string;
@ -132,10 +137,15 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
@state() private _filteredScenes?: string[] | null;
@state() private _filters: Record<
string,
{ value: string[] | undefined; items: Set<string> | undefined }
> = {};
@storage({
storage: "sessionStorage",
key: "scene-table-filters-full",
state: true,
subscribe: false,
serializer: serializeFilters,
deserializer: deserializeFilters,
})
private _filters: DataTableFilters = {};
@state() private _expandedFilter?: string;
@ -783,7 +793,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
private _filterChanged(ev) {
const type = ev.target.localName;
this._filters[type] = ev.detail;
this._filters = { ...this._filters, [type]: ev.detail };
this._applyFilters();
}
@ -802,7 +812,11 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
items.intersection(filter.items)
: new Set([...items].filter((x) => filter.items!.has(x)));
}
if (key === "ha-filter-categories" && filter.value?.length) {
if (
key === "ha-filter-categories" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const categoryItems: Set<string> = new Set();
this.scenes
.filter(
@ -822,13 +836,17 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
items.intersection(categoryItems)
: new Set([...items].filter((x) => categoryItems!.has(x)));
}
if (key === "ha-filter-labels" && filter.value?.length) {
if (
key === "ha-filter-labels" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const labelItems: Set<string> = new Set();
this.scenes
.filter((scene) =>
this._entityReg
.find((reg) => reg.entity_id === scene.entity_id)
?.labels.some((lbl) => filter.value!.includes(lbl))
?.labels.some((lbl) => (filter.value as string[]).includes(lbl))
)
.forEach((scene) => labelItems.add(scene.entity_id));
if (!items) {

View File

@ -106,6 +106,11 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
import { configSections } from "../ha-panel-config";
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import {
serializeFilters,
deserializeFilters,
DataTableFilters,
} from "../../../data/data_table_filters";
type ScriptItem = ScriptEntity & {
name: string;
@ -136,10 +141,15 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
@state() private _filteredScripts?: string[] | null;
@state() private _filters: Record<
string,
{ value: string[] | undefined; items: Set<string> | undefined }
> = {};
@storage({
storage: "sessionStorage",
key: "script-table-filters-full",
state: true,
subscribe: false,
serializer: serializeFilters,
deserializer: deserializeFilters,
})
private _filters: DataTableFilters = {};
@state() private _expandedFilter?: string;
@ -812,7 +822,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
private _filterChanged(ev) {
const type = ev.target.localName;
this._filters[type] = ev.detail;
this._filters = { ...this._filters, [type]: ev.detail };
this._applyFilters();
}
@ -836,7 +846,11 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
items.intersection(filter.items)
: new Set([...items].filter((x) => filter.items!.has(x)));
}
if (key === "ha-filter-categories" && filter.value?.length) {
if (
key === "ha-filter-categories" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const categoryItems: Set<string> = new Set();
this.scripts
.filter(
@ -856,13 +870,17 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
items.intersection(categoryItems)
: new Set([...items].filter((x) => categoryItems!.has(x)));
}
if (key === "ha-filter-labels" && filter.value?.length) {
if (
key === "ha-filter-labels" &&
Array.isArray(filter.value) &&
filter.value.length
) {
const labelItems: Set<string> = new Set();
this.scripts
.filter((script) =>
this._entityReg
.find((reg) => reg.entity_id === script.entity_id)
?.labels.some((lbl) => filter.value!.includes(lbl))
?.labels.some((lbl) => (filter.value as string[]).includes(lbl))
)
.forEach((script) => labelItems.add(script.entity_id));
if (!items) {