Skip to content

Commit ad3ddc9

Browse files
authored
add filter support to datatable (#439)
1 parent 102b0c7 commit ad3ddc9

15 files changed

Lines changed: 196 additions & 48 deletions

File tree

vuu-ui/packages/vuu-data/src/data-source.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ export interface DataSourceColumnsMessage extends MessageWithClientViewportId {
7575
}
7676
export interface DataSourceFilterMessage extends MessageWithClientViewportId {
7777
type: "filter";
78-
filter: Filter;
79-
filterQuery: string;
78+
filter: DataSourceFilter;
8079
}
8180
export interface DataSourceGroupByMessage extends MessageWithClientViewportId {
8281
type: "groupBy";

vuu-ui/packages/vuu-datagrid-types/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Filter } from "@finos/vuu-filter-types";
12
import {
23
VuuAggType,
34
VuuColumnDataType,
@@ -56,6 +57,7 @@ export interface ColumnDescriptor {
5657
export interface KeyedColumnDescriptor extends ColumnDescriptor {
5758
align?: "left" | "right";
5859
className?: string;
60+
filter?: Filter;
5961
flex?: number;
6062
heading?: [...string[]];
6163
isGroup?: boolean;

vuu-ui/packages/vuu-datatable/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@salt-ds/core": "1.0.0",
2020
"@salt-ds/icons": "1.0.0",
2121
"@heswell/salt-lab": "1.0.0-alpha.0",
22+
"@finos/vuu-filters": "0.0.26",
2223
"@finos/vuu-utils": "0.0.26",
2324
"classnames": "^2.2.6",
2425
"react": "^17.0.2",

vuu-ui/packages/vuu-datatable/src/TableHeaderCell.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
padding: 0 0 0 3px;
2626
}
2727

28+
.vuuTable-headerCell-inner:has(.vuuFilterIndicator){
29+
padding-left: 0;
30+
}
31+
2832
.vuuTable-headerCell-label {
2933
align-items: center;
3034
justify-content: var(--cell-align);

vuu-ui/packages/vuu-datatable/src/TableHeaderCell.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { TableColumnResizeHandler } from "./dataTableTypes";
88

99
import "./TableHeaderCell.css";
1010
import { useContextMenu } from "@finos/vuu-popups";
11+
import { FilterIndicator } from "./filter-indicator";
1112

1213
const classBase = "vuuTable-headerCell";
1314

@@ -73,6 +74,7 @@ export const TableHeaderCell = ({
7374
ref={rootRef}
7475
>
7576
<div className={`${classBase}-inner`}>
77+
<FilterIndicator column={column} />
7678
<div className={`${classBase}-label`}>{column.label}</div>
7779
<SortIndicator sorted={column.sorted} />
7880
{column.resizeable !== false ? (
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.vuuFilterIndicator {
2+
--menu-icon-size: 12px;
3+
--menu-item-icon-color: black;
4+
align-items: center;
5+
cursor: pointer;
6+
display: flex;
7+
flex: 0 0 18px;
8+
flex-direction: column;
9+
justify-content: center;
10+
position: relative;
11+
}
12+
13+
.vuuFilterIndicator + .vuuTable-headerCell-inner {
14+
padding-left: 0;
15+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { KeyedColumnDescriptor } from "@finos/vuu-datagrid-types";
2+
import { Filter } from "@finos/vuu-filter-types";
3+
import { useContextMenu } from "@finos/vuu-popups";
4+
import cx from "classnames";
5+
import { HTMLAttributes, useCallback } from "react";
6+
7+
import "./filter-indicator.css";
8+
9+
export const Direction = {
10+
ASC: "asc",
11+
DSC: "dsc",
12+
};
13+
14+
export interface FilterIndicatorProps extends HTMLAttributes<HTMLDivElement> {
15+
column: KeyedColumnDescriptor;
16+
filter?: Filter;
17+
}
18+
19+
export const FilterIndicator = ({ column, filter }: FilterIndicatorProps) => {
20+
//TODO handle this at header level
21+
const showContextMenu = useContextMenu();
22+
23+
const handleClick = useCallback(
24+
(evt) => {
25+
// if we do this through keyboard, need to get co-ords
26+
evt.stopPropagation();
27+
showContextMenu(evt, "filter", { column, filter });
28+
},
29+
[column, filter, showContextMenu]
30+
);
31+
32+
if (!column.filter) {
33+
return null;
34+
}
35+
36+
return (
37+
<div
38+
className={cx("vuuFilterIndicator")}
39+
data-icon="filter"
40+
onClick={handleClick}
41+
/>
42+
);
43+
};

vuu-ui/packages/vuu-datatable/src/useDataTable.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ export const useDataTable = ({
131131
type: "tableConfig",
132132
groupBy: message.groupBy,
133133
});
134+
case "filter":
135+
return dispatchColumnAction({
136+
type: "tableConfig",
137+
filter: message.filter,
138+
});
134139
case "sort":
135140
return dispatchColumnAction({
136141
type: "tableConfig",

vuu-ui/packages/vuu-datatable/src/useTableModel.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@ import {
1010
metadataKeys,
1111
} from "@finos/vuu-utils";
1212

13+
// TOSO eliminate this dependency
14+
import { extractFilterForColumn } from "@finos/vuu-filters";
15+
1316
import { Reducer, useReducer } from "react";
1417
import {
1518
VuuColumnDataType,
1619
VuuGroupBy,
1720
VuuSort,
1821
} from "@finos/vuu-protocol-types";
22+
import { DataSourceFilter } from "@finos/vuu-data";
1923

2024
const DEFAULT_COLUMN_WIDTH = 100;
2125
const KEY_OFFSET = metadataKeys.count;
@@ -87,6 +91,7 @@ export interface ColumnActionUpdateProp {
8791

8892
export interface ColumnActionTableConfig {
8993
type: "tableConfig";
94+
filter?: DataSourceFilter;
9095
groupBy?: VuuGroupBy;
9196
sort?: VuuSort;
9297
}
@@ -263,9 +268,10 @@ function updateColumnProp(
263268

264269
function updateTableConfig(
265270
state: GridModel,
266-
{ groupBy, sort }: ColumnActionTableConfig
271+
{ filter, groupBy, sort }: ColumnActionTableConfig
267272
) {
268273
const hasGroupBy = groupBy !== undefined;
274+
const hasFilter = typeof filter?.filter === "string";
269275
const hasSort = sort && sort.sortDefs.length > 0;
270276

271277
let result = state;
@@ -284,6 +290,13 @@ function updateTableConfig(
284290
};
285291
}
286292

293+
if (hasFilter) {
294+
result = {
295+
...state,
296+
columns: applyFilterToColumns(state.columns, filter),
297+
};
298+
}
299+
287300
return result;
288301
}
289302

@@ -294,6 +307,7 @@ function replaceColumn(
294307
return state.map((col) => (col.name === column.name ? column : col));
295308
}
296309

310+
//TOSDO move these functions to utils
297311
const applyGroupByToColumns = (
298312
columns: KeyedColumnDescriptor[],
299313
groupBy: VuuGroupBy
@@ -330,6 +344,28 @@ const applySortToColumns = (colunms: KeyedColumnDescriptor[], sort: VuuSort) =>
330344
}
331345
});
332346

347+
const applyFilterToColumns = (
348+
columns: KeyedColumnDescriptor[],
349+
{ filterStruct }: DataSourceFilter
350+
) =>
351+
columns.map((column) => {
352+
// TODO this gives us a dependency on vuu-filters
353+
const filter = extractFilterForColumn(filterStruct, column.name);
354+
if (filter !== undefined) {
355+
return {
356+
...column,
357+
filter,
358+
};
359+
} else if (column.filter) {
360+
return {
361+
...column,
362+
filter: undefined,
363+
};
364+
} else {
365+
return column;
366+
}
367+
});
368+
333369
const getSortType = (column: ColumnDescriptor, { sortDefs }: VuuSort) => {
334370
const sortDef = sortDefs.find((sortCol) => sortCol.column === column.name);
335371
if (sortDef) {

vuu-ui/packages/vuu-filters/src/filter-input/FilterInput.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const FilterInput = ({
2222
existingFilter,
2323
onSubmitFilter,
2424
suggestionProvider,
25+
...props
2526
}: FilterInputProps) => {
2627
const { editorRef, clearInput } = useCodeMirrorEditor({
2728
existingFilter,
@@ -30,7 +31,7 @@ export const FilterInput = ({
3031
});
3132

3233
return (
33-
<div className={classBase}>
34+
<div {...props} className={classBase}>
3435
<Button className={`${classBase}-FilterButton`} data-icon="filter" />
3536
<div className={`${classBase}-Editor`} ref={editorRef} />
3637
<Button

0 commit comments

Comments
 (0)