Skip to content

Commit 105ea6e

Browse files
committed
perspective-select API change+enhancement
Add removeConfigs support to perspective-select for off-candidates filter removal The workspace's global filter propagation could not remove filters applied to columns outside the master viewer's group_by/split_by/filter candidates set. Once such a filter was applied it was permanently stuck on slave viewers. Introduces removeConfigs: ViewConfigUpdate[] on the perspective-select event detail, which explicitly removes filters from slave viewers by column regardless of the candidates set. Also replaces the untyped event detail object with a typed PerspectiveSelectDetail class exported from @perspective-dev/viewer. Breaking change: the config field on perspective-select event details is replaced by insertConfigs and removeConfigs. viewer-datagrid and viewer-d3fc are updated accordingly. Signed-off-by: Davis Silverman <davis@thedav.is>
1 parent bfc12d8 commit 105ea6e

File tree

9 files changed

+305
-37
lines changed

9 files changed

+305
-37
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,4 @@ docs/static/browser
6565
docs/static/viewer
6666
docs/static/react
6767
rust/perspective-server/build
68+
target/

packages/react/src/workspace.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export interface ToggleGloalFilterEventDetail {
2727
isGlobalFilter: boolean;
2828
}
2929

30-
interface PerspectiveWorkspaceProps extends React.HTMLAttributes<HTMLElement> {
30+
export interface PerspectiveWorkspaceProps
31+
extends React.HTMLAttributes<HTMLElement> {
3132
client: psp.Client | Promise<psp.Client>;
3233
layout: PerspectiveWorkspaceConfig;
3334
onLayoutUpdate?: (layout: PerspectiveWorkspaceConfig) => void;

packages/viewer-d3fc/src/ts/tooltip/selectionEvent.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
1212

1313
import { getGroupValues, getSplitValues, getDataValues } from "./selectionData";
14+
import { PerspectiveSelectDetail } from "@perspective-dev/viewer";
1415

1516
const mapToFilter = (d) => [d.name, "==", d.value];
1617

@@ -19,15 +20,18 @@ export const raiseEvent = (node, data, settings) => {
1920
const groupFilters = getGroupValues(data, settings).map(mapToFilter);
2021
const splitFilters = getSplitValues(data, settings).map(mapToFilter);
2122
const filter = settings.filter.concat(groupFilters).concat(splitFilters);
23+
const detail = new PerspectiveSelectDetail(
24+
true,
25+
data === null ? null : data?.row,
26+
column_names,
27+
[],
28+
[{ filter }],
29+
);
2230
node.dispatchEvent(
2331
new CustomEvent("perspective-select", {
2432
bubbles: true,
2533
composed: true,
26-
detail: {
27-
column_names,
28-
config: { filter },
29-
row: data === null ? null : data?.row,
30-
},
34+
detail,
3135
}),
3236
);
3337
};

packages/viewer-datagrid/src/ts/event_handlers/row_select_click.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
1212

1313
import getCellConfig from "../get_cell_config.js";
14-
import type {
15-
RegularTable,
16-
DatagridModel,
17-
PerspectiveViewerElement,
18-
HandledMouseEvent,
14+
import {
15+
type RegularTable,
16+
type DatagridModel,
17+
type PerspectiveViewerElement,
18+
type HandledMouseEvent,
1919
PerspectiveSelectDetail,
2020
} from "../types.js";
2121

@@ -52,28 +52,31 @@ export async function selectionListener(
5252
const is_deselect =
5353
!!selected && id.length === selected.length && key_match;
5454

55-
let detail: PerspectiveSelectDetail = {
56-
selected: !is_deselect,
57-
row: {},
58-
config: { filter: [] },
59-
};
60-
6155
const { row, column_names, config } = await getCellConfig(
6256
this,
6357
meta.y,
6458
meta.type === "body" ? meta.x : 0,
6559
);
6660

61+
let detail: PerspectiveSelectDetail;
6762
if (is_deselect) {
6863
selected_rows_map.delete(regularTable);
69-
detail = {
70-
...detail,
64+
detail = new PerspectiveSelectDetail(
65+
false,
7166
row,
72-
config: { filter: structuredClone(this._config.filter) },
73-
};
67+
[],
68+
[],
69+
[{ filter: structuredClone(this._config.filter) }],
70+
);
7471
} else {
7572
selected_rows_map.set(regularTable, id);
76-
detail = { ...detail, row, column_names, config };
73+
detail = new PerspectiveSelectDetail(
74+
true,
75+
row,
76+
column_names,
77+
[],
78+
[config],
79+
);
7780
}
7881

7982
await regularTable.draw({ preserve_width: true });

packages/viewer-datagrid/src/ts/types.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type {
1717
ColumnType,
1818
SortDir,
1919
ViewWindow,
20+
ViewConfigUpdate,
2021
} from "@perspective-dev/client";
2122
import { RegularTableElement } from "regular-table";
2223
import { CellMetadata, DataResponse } from "regular-table/dist/esm/types";
@@ -244,7 +245,7 @@ export type FormatterCache = Map<string, FormatterCacheEntry>;
244245
export interface CellConfigResult {
245246
row: Record<string, unknown>;
246247
column_names: string[];
247-
config: Partial<ViewConfig>;
248+
config: ViewConfigUpdate;
248249
}
249250

250251
// Custom event detail types
@@ -254,12 +255,8 @@ export interface PerspectiveClickDetail {
254255
config: Partial<ViewConfig>;
255256
}
256257

257-
export interface PerspectiveSelectDetail {
258-
selected: boolean;
259-
row: Record<string, unknown>;
260-
column_names?: string[];
261-
config: Partial<ViewConfig>;
262-
}
258+
export { PerspectiveSelectDetail } from "@perspective-dev/viewer";
259+
263260

264261
// Mouse event with handled flag
265262
export interface HandledMouseEvent extends MouseEvent {

packages/workspace/src/ts/workspace/workspace.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -683,20 +683,23 @@ export class PerspectiveWorkspace extends SplitPanel {
683683

684684
async _filterViewer(
685685
viewer: HTMLPerspectiveViewerElement,
686-
filters: [string, string, string][],
686+
removeFilters: psp.Filter[],
687+
insertFilters: psp.Filter[],
687688
candidates: Set<string>,
688689
) {
689690
const config = await viewer.save();
690691
const table = await viewer.getTable();
691692
const availableColumns = Object.keys(await table.schema());
692693
const currentFilters = config.filter || [];
693-
const columnAvailable = (filter: [string, string, any]) =>
694+
const columnAvailable = (filter: psp.Filter) =>
694695
filter[0] && availableColumns.includes(filter[0]);
695696

696-
const validFilters = filters.filter(columnAvailable);
697+
const clearColumns = new Set<string>(removeFilters.map((f) => f[0]));
698+
const validFilters = insertFilters.filter(columnAvailable);
697699
validFilters.push(
698700
...currentFilters.filter(
699-
(x: [string, ..._: string[]]) => !candidates.has(x[0]),
701+
(x: [string, ..._: string[]]) =>
702+
!candidates.has(x[0]) && !clearColumns.has(x[0]),
700703
),
701704
);
702705

@@ -712,14 +715,21 @@ export class PerspectiveWorkspace extends SplitPanel {
712715
const candidates = new Set([
713716
...(config["group_by"] || []),
714717
...(config["split_by"] || []),
715-
...(config.filter || []).map((x: [string, string, any]) => x[0]),
718+
...(config.filter || []).map((x: psp.Filter) => x[0]),
716719
]);
717720

718-
const filters = [...event.detail.config.filter];
721+
const removeFilters = (
722+
(event.detail.removeConfigs ?? []) as psp.ViewConfigUpdate[]
723+
).flatMap((x) => x.filter ?? []);
724+
const insertFilters = (
725+
(event.detail.insertConfigs ?? []) as psp.ViewConfigUpdate[]
726+
).flatMap((x) => x.filter ?? []);
727+
719728
toArray(this.dockpanel.widgets()).forEach((widget) => {
720729
this._filterViewer(
721730
(widget as PerspectiveViewerWidget).viewer,
722-
filters,
731+
removeFilters,
732+
insertFilters,
723733
candidates,
724734
);
725735
});

0 commit comments

Comments
 (0)