Add filter exceptions to DataSource
Summary: Filter exceptions allow us to add singular items to table views. Extremely useful for Bloks Debugger where we have to jump between multiple types of rows that could be filtered out Reviewed By: LukeDefeo Differential Revision: D47472006 fbshipit-source-id: 74d21a65d364ec5ab88652effc06aade20ad80b2
This commit is contained in:
committed by
Facebook GitHub Bot
parent
cba5af60c8
commit
8397b2bab8
@@ -664,6 +664,7 @@ export class DataSourceView<T, KeyType> {
|
|||||||
private sortBy: undefined | ((a: T) => Primitive) = undefined;
|
private sortBy: undefined | ((a: T) => Primitive) = undefined;
|
||||||
private reverse: boolean = false;
|
private reverse: boolean = false;
|
||||||
private filter?: (value: T) => boolean = undefined;
|
private filter?: (value: T) => boolean = undefined;
|
||||||
|
private filterExceptions?: Set<KeyType> = undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @readonly
|
* @readonly
|
||||||
@@ -760,10 +761,22 @@ export class DataSourceView<T, KeyType> {
|
|||||||
public setFilter(filter: undefined | ((value: T) => boolean)) {
|
public setFilter(filter: undefined | ((value: T) => boolean)) {
|
||||||
if (this.filter !== filter) {
|
if (this.filter !== filter) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
// Filter exceptions are relevant for one filter only
|
||||||
|
this.filterExceptions = undefined;
|
||||||
this.rebuild();
|
this.rebuild();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Granular control over filters to add one-off exceptions to them.
|
||||||
|
* They allow us to add singular items to table views.
|
||||||
|
* Extremely useful for Bloks Debugger where we have to jump between multiple types of rows that could be filtered out
|
||||||
|
*/
|
||||||
|
public setFilterExpections(ids: KeyType[]) {
|
||||||
|
this.filterExceptions = new Set(ids);
|
||||||
|
this.rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
public toggleReversed() {
|
public toggleReversed() {
|
||||||
this.setReversed(!this.reverse);
|
this.setReversed(!this.reverse);
|
||||||
}
|
}
|
||||||
@@ -782,6 +795,7 @@ export class DataSourceView<T, KeyType> {
|
|||||||
this.sortBy = undefined;
|
this.sortBy = undefined;
|
||||||
this.reverse = false;
|
this.reverse = false;
|
||||||
this.filter = undefined;
|
this.filter = undefined;
|
||||||
|
this.filterExceptions = undefined;
|
||||||
this.windowStart = 0;
|
this.windowStart = 0;
|
||||||
this.windowEnd = 0;
|
this.windowEnd = 0;
|
||||||
this.rebuild();
|
this.rebuild();
|
||||||
@@ -891,6 +905,7 @@ export class DataSourceView<T, KeyType> {
|
|||||||
case 'append': {
|
case 'append': {
|
||||||
const {entry} = event;
|
const {entry} = event;
|
||||||
entry.visible[this.viewId] = filter ? filter(entry.value) : true;
|
entry.visible[this.viewId] = filter ? filter(entry.value) : true;
|
||||||
|
this.applyFilterExceptions(entry);
|
||||||
if (!entry.visible[this.viewId]) {
|
if (!entry.visible[this.viewId]) {
|
||||||
// not in filter? skip this entry
|
// not in filter? skip this entry
|
||||||
return;
|
return;
|
||||||
@@ -908,6 +923,7 @@ export class DataSourceView<T, KeyType> {
|
|||||||
case 'update': {
|
case 'update': {
|
||||||
const {entry} = event;
|
const {entry} = event;
|
||||||
entry.visible[this.viewId] = filter ? filter(entry.value) : true;
|
entry.visible[this.viewId] = filter ? filter(entry.value) : true;
|
||||||
|
this.applyFilterExceptions(entry);
|
||||||
// short circuit; no view active so update straight away
|
// short circuit; no view active so update straight away
|
||||||
if (!filter && !sortBy) {
|
if (!filter && !sortBy) {
|
||||||
output[event.index].approxIndex[this.viewId] = event.index;
|
output[event.index].approxIndex[this.viewId] = event.index;
|
||||||
@@ -1015,6 +1031,7 @@ export class DataSourceView<T, KeyType> {
|
|||||||
let output = filter
|
let output = filter
|
||||||
? records.filter((entry) => {
|
? records.filter((entry) => {
|
||||||
entry.visible[this.viewId] = filter(entry.value);
|
entry.visible[this.viewId] = filter(entry.value);
|
||||||
|
this.applyFilterExceptions(entry);
|
||||||
return entry.visible[this.viewId];
|
return entry.visible[this.viewId];
|
||||||
})
|
})
|
||||||
: records.slice();
|
: records.slice();
|
||||||
@@ -1082,4 +1099,16 @@ export class DataSourceView<T, KeyType> {
|
|||||||
this._output.splice(insertionIndex, 0, entry);
|
this._output.splice(insertionIndex, 0, entry);
|
||||||
this.notifyItemShift(insertionIndex, 1);
|
this.notifyItemShift(insertionIndex, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private applyFilterExceptions(entry: Entry<T>) {
|
||||||
|
if (
|
||||||
|
this.datasource.keyAttribute &&
|
||||||
|
this.filter &&
|
||||||
|
this.filterExceptions &&
|
||||||
|
!entry.visible[this.viewId]
|
||||||
|
) {
|
||||||
|
const keyValue = entry.value[this.datasource.keyAttribute] as KeyType;
|
||||||
|
entry.visible[this.viewId] = this.filterExceptions.has(keyValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -356,6 +356,21 @@ test('filter', () => {
|
|||||||
expect(rawOutput(ds)).toEqual([newCookie, newCoffee, submitBug, a, b]);
|
expect(rawOutput(ds)).toEqual([newCookie, newCoffee, submitBug, a, b]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('filter + filterExceptions', () => {
|
||||||
|
const ds = createDataSource<Todo, 'id'>([eatCookie, drinkCoffee, submitBug], {
|
||||||
|
key: 'id',
|
||||||
|
});
|
||||||
|
|
||||||
|
ds.view.setFilter((t) => t.title.indexOf('c') === -1);
|
||||||
|
|
||||||
|
expect(rawOutput(ds)).toEqual([submitBug]);
|
||||||
|
|
||||||
|
// add exception
|
||||||
|
ds.view.setFilterExpections([drinkCoffee.id]);
|
||||||
|
|
||||||
|
expect(rawOutput(ds)).toEqual([drinkCoffee, submitBug]);
|
||||||
|
});
|
||||||
|
|
||||||
test('reverse without sorting', () => {
|
test('reverse without sorting', () => {
|
||||||
const ds = createDataSource<Todo>([eatCookie, drinkCoffee]);
|
const ds = createDataSource<Todo>([eatCookie, drinkCoffee]);
|
||||||
ds.view.setWindow(0, 100);
|
ds.view.setWindow(0, 100);
|
||||||
@@ -452,8 +467,12 @@ test('reset', () => {
|
|||||||
key: 'id',
|
key: 'id',
|
||||||
});
|
});
|
||||||
ds.view.setSortBy('title');
|
ds.view.setSortBy('title');
|
||||||
ds.view.setFilter((v) => v.id !== 'cookie');
|
ds.view.setFilter((v) => v.id === 'cookie');
|
||||||
expect(rawOutput(ds)).toEqual([drinkCoffee, submitBug]);
|
expect(rawOutput(ds)).toEqual([eatCookie]);
|
||||||
|
expect([...ds.keys()]).toEqual(['bug', 'coffee', 'cookie']);
|
||||||
|
|
||||||
|
ds.view.setFilterExpections([drinkCoffee.id]);
|
||||||
|
expect(rawOutput(ds)).toEqual([drinkCoffee, eatCookie]);
|
||||||
expect([...ds.keys()]).toEqual(['bug', 'coffee', 'cookie']);
|
expect([...ds.keys()]).toEqual(['bug', 'coffee', 'cookie']);
|
||||||
|
|
||||||
ds.view.reset();
|
ds.view.reset();
|
||||||
|
|||||||
Reference in New Issue
Block a user