mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 09:13:33 +00:00
[SM-497] Add filtering capabilities to the table datasource (#4717)
* Add filtering capabilities to the table datasource
This commit is contained in:
@@ -15,6 +15,7 @@ export type Sort = {
|
||||
export class TableDataSource<T> extends DataSource<T> {
|
||||
private readonly _data: BehaviorSubject<T[]>;
|
||||
private readonly _sort: BehaviorSubject<Sort>;
|
||||
private readonly _filter = new BehaviorSubject<string>("");
|
||||
private readonly _renderData = new BehaviorSubject<T[]>([]);
|
||||
|
||||
private _renderChangesSubscription: Subscription | null = null;
|
||||
@@ -41,6 +42,14 @@ export class TableDataSource<T> extends DataSource<T> {
|
||||
return this._sort.value;
|
||||
}
|
||||
|
||||
get filter() {
|
||||
return this._filter.value;
|
||||
}
|
||||
|
||||
set filter(filter: string) {
|
||||
this._filter.next(filter);
|
||||
}
|
||||
|
||||
connect(): Observable<readonly T[]> {
|
||||
if (!this._renderChangesSubscription) {
|
||||
this.updateChangeSubscription();
|
||||
@@ -55,20 +64,32 @@ export class TableDataSource<T> extends DataSource<T> {
|
||||
}
|
||||
|
||||
private updateChangeSubscription() {
|
||||
const orderedData = combineLatest([this._data, this._sort]).pipe(
|
||||
map(([data]) => this.orderData(data))
|
||||
const filteredData = combineLatest([this._data, this._filter]).pipe(
|
||||
map(([data, filter]) => this.filterData(data, filter))
|
||||
);
|
||||
|
||||
const orderedData = combineLatest([filteredData, this._sort]).pipe(
|
||||
map(([data, sort]) => this.orderData(data, sort))
|
||||
);
|
||||
|
||||
this._renderChangesSubscription?.unsubscribe();
|
||||
this._renderChangesSubscription = orderedData.subscribe((data) => this._renderData.next(data));
|
||||
}
|
||||
|
||||
private orderData(data: T[]): T[] {
|
||||
if (!this.sort) {
|
||||
private filterData(data: T[], filter: string): T[] {
|
||||
if (filter == null || filter == "") {
|
||||
return data;
|
||||
}
|
||||
|
||||
return this.sortData(data, this.sort);
|
||||
return data.filter((obj) => this.filterPredicate(obj, filter));
|
||||
}
|
||||
|
||||
private orderData(data: T[], sort: Sort): T[] {
|
||||
if (!sort) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return this.sortData(data, sort);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,4 +182,38 @@ export class TableDataSource<T> extends DataSource<T> {
|
||||
return comparatorResult * (direction === "asc" ? 1 : -1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from https://github.com/angular/components/blob/main/src/material/table/table-data-source.ts
|
||||
* License: MIT
|
||||
* Copyright (c) 2022 Google LLC.
|
||||
*
|
||||
* Checks if a data object matches the data source's filter string. By default, each data object
|
||||
* is converted to a string of its properties and returns true if the filter has
|
||||
* at least one occurrence in that string. By default, the filter string has its whitespace
|
||||
* trimmed and the match is case-insensitive. May be overridden for a custom implementation of
|
||||
* filter matching.
|
||||
* @param data Data object used to check against the filter.
|
||||
* @param filter Filter string that has been set on the data source.
|
||||
* @returns Whether the filter matches against the data
|
||||
*/
|
||||
protected filterPredicate(data: T, filter: string): boolean {
|
||||
// Transform the data into a lowercase string of all property values.
|
||||
const dataStr = Object.keys(data as unknown as Record<string, any>)
|
||||
.reduce((currentTerm: string, key: string) => {
|
||||
// Use an obscure Unicode character to delimit the words in the concatenated string.
|
||||
// This avoids matches where the values of two columns combined will match the user's query
|
||||
// (e.g. `Flute` and `Stop` will match `Test`). The character is intended to be something
|
||||
// that has a very low chance of being typed in by somebody in a text field. This one in
|
||||
// particular is "White up-pointing triangle with dot" from
|
||||
// https://en.wikipedia.org/wiki/List_of_Unicode_characters
|
||||
return currentTerm + (data as unknown as Record<string, any>)[key] + "◬";
|
||||
}, "")
|
||||
.toLowerCase();
|
||||
|
||||
// Transform the filter by converting it to lowercase and removing whitespace.
|
||||
const transformedFilter = filter.trim().toLowerCase();
|
||||
|
||||
return dataStr.indexOf(transformedFilter) != -1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user