diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index cf8407ed66..015f54130e 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -21,7 +21,8 @@ import { nextRender } from "../../common/util/render-status"; import "../ha-checkbox"; import type { HaCheckbox } from "../ha-checkbox"; import "../ha-icon"; -import { filterSortData } from "./sort-filter"; +import { filterData, sortData } from "./sort-filter"; +import memoizeOne from "memoize-one"; declare global { // for fire event @@ -72,6 +73,10 @@ export interface DataTableRowData { selectable?: boolean; } +export interface SortableColumnContainer { + [key: string]: DataTableSortColumnData; +} + @customElement("ha-data-table") export class HaDataTable extends LitElement { @property({ type: Object }) public columns: DataTableColumnContainer = {}; @@ -109,9 +114,7 @@ export class HaDataTable extends LitElement { private _checkedRows: string[] = []; - private _sortColumns: { - [key: string]: DataTableSortColumnData; - } = {}; + private _sortColumns: SortableColumnContainer = {}; private curRequest = 0; @@ -179,7 +182,7 @@ export class HaDataTable extends LitElement { properties.has("_sortColumn") || properties.has("_sortDirection") ) { - this._filterData(); + this._sortFilterData(); } } @@ -369,20 +372,30 @@ export class HaDataTable extends LitElement { `; } - private async _filterData() { + private async _sortFilterData() { const startTime = new Date().getTime(); this.curRequest++; const curRequest = this.curRequest; - const filterProm = filterSortData( - this.data, - this._sortColumns, - this._filter, - this._sortDirection, - this._sortColumn - ); + let filteredData = this.data; + if (this._filter) { + filteredData = await this._memFilterData( + this.data, + this._sortColumns, + this.filter + ); + } - const [data] = await Promise.all([filterProm, nextRender]); + const prom = this._sortColumn + ? sortData( + filteredData, + this._sortColumns, + this._sortDirection, + this._sortColumn + ) + : filteredData; + + const [data] = await Promise.all([prom, nextRender]); const curTime = new Date().getTime(); const elapsed = curTime - startTime; @@ -396,6 +409,16 @@ export class HaDataTable extends LitElement { this._filteredData = data; } + private _memFilterData = memoizeOne( + async ( + data: DataTableRowData[], + columns: SortableColumnContainer, + filter: string + ): Promise => { + return filterData(data, columns, filter); + } + ); + private _handleHeaderClick(ev: Event) { const columnId = ((ev.target as HTMLElement).closest( ".mdc-data-table__header-cell" diff --git a/src/components/data-table/sort-filter.ts b/src/components/data-table/sort-filter.ts index 766a167fba..9e89e866df 100644 --- a/src/components/data-table/sort-filter.ts +++ b/src/components/data-table/sort-filter.ts @@ -1,26 +1,34 @@ import { wrap } from "comlink"; -type FilterSortDataType = typeof import("./sort_filter_worker").api["filterSortData"]; -type filterSortDataParamTypes = Parameters; +type FilterDataType = typeof import("./sort_filter_worker").api["filterData"]; +type FilterDataParamTypes = Parameters; + +type SortDataType = typeof import("./sort_filter_worker").api["sortData"]; +type SortDataParamTypes = Parameters; let worker: any | undefined; -export const filterSortData = async ( - data: filterSortDataParamTypes[0], - columns: filterSortDataParamTypes[1], - filter: filterSortDataParamTypes[2], - direction: filterSortDataParamTypes[3], - sortColumn: filterSortDataParamTypes[4] -): Promise> => { +export const filterData = async ( + data: FilterDataParamTypes[0], + columns: FilterDataParamTypes[1], + filter: FilterDataParamTypes[2] +): Promise> => { if (!worker) { worker = wrap(new Worker("./sort_filter_worker", { type: "module" })); } - return await worker.filterSortData( - data, - columns, - filter, - direction, - sortColumn - ); + return await worker.filterData(data, columns, filter); +}; + +export const sortData = async ( + data: SortDataParamTypes[0], + columns: SortDataParamTypes[1], + direction: SortDataParamTypes[2], + sortColumn: SortDataParamTypes[3] +): Promise> => { + if (!worker) { + worker = wrap(new Worker("./sort_filter_worker", { type: "module" })); + } + + return await worker.sortData(data, columns, direction, sortColumn); }; diff --git a/src/components/data-table/sort_filter_worker.ts b/src/components/data-table/sort_filter_worker.ts index f7b71bdd2c..de3e1c67b2 100644 --- a/src/components/data-table/sort_filter_worker.ts +++ b/src/components/data-table/sort_filter_worker.ts @@ -5,33 +5,16 @@ import type { DataTableSortColumnData, DataTableRowData, SortingDirection, - HaDataTable, + SortableColumnContainer, } from "./ha-data-table"; -type SortableColumnContainer = HaDataTable["_sortColumns"]; - -const filterSortData = ( - data: DataTableRowData[], - columns: SortableColumnContainer, - filter: string, - direction: SortingDirection, - sortColumn?: string -) => { - const filteredData = filter ? filterData(data, columns, filter) : data; - - if (!sortColumn) { - return filteredData; - } - - return sortData(filteredData, columns, direction, sortColumn); -}; - const filterData = ( data: DataTableRowData[], columns: SortableColumnContainer, filter: string -) => - data.filter((row) => { +) => { + filter = filter.toUpperCase(); + return data.filter((row) => { return Object.entries(columns).some((columnEntry) => { const [key, column] = columnEntry; if (column.filterable) { @@ -46,6 +29,7 @@ const filterData = ( return false; }); }); +}; const sortData = ( data: DataTableRowData[], @@ -85,7 +69,8 @@ const sortData = ( // Export for types export const api = { - filterSortData, + filterData, + sortData, }; expose(api);