Skip to content

Commit fc13e9f

Browse files
committed
Table History
1 parent 51775f4 commit fc13e9f

4 files changed

Lines changed: 117 additions & 7 deletions

File tree

packages/code-studio/src/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ async function getCorePlugins() {
4646
);
4747
const {
4848
GridPluginConfig,
49-
GridMiddlewarePluginConfig,
5049
TableHistoryPluginConfig,
5150
PandasPluginConfig,
5251
ChartPluginConfig,
@@ -58,7 +57,6 @@ async function getCorePlugins() {
5857
} = dashboardCorePlugins;
5958
return [
6059
GridPluginConfig,
61-
GridMiddlewarePluginConfig,
6260
TableHistoryPluginConfig,
6361
PandasPluginConfig,
6462
ChartPluginConfig,

packages/dashboard-core-plugins/src/GridMiddlewarePlugin.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ function GridMiddleware({
3232
Component,
3333
...props
3434
}: WidgetMiddlewareComponentProps<dh.Table>): JSX.Element {
35+
// Register the option when the middleware mounts (not as a module side effect)
36+
useEffect(() => {
37+
defaultTableOptionsRegistry.register(MiddlewareCustomOption);
38+
return () => {
39+
defaultTableOptionsRegistry.unregister(MIDDLEWARE_OPTION_TYPE);
40+
};
41+
}, []);
42+
3543
// Log when middleware is mounted (for debugging)
3644
useEffect(() => {
3745
log.debug('GridMiddleware (component) mounted');
@@ -197,8 +205,8 @@ const MiddlewareCustomOption: TableOption = {
197205
Panel: MiddlewareConfigPanel,
198206
};
199207

200-
// Register the option with the default registry
201-
defaultTableOptionsRegistry.register(MiddlewareCustomOption);
208+
// Note: Registration moved to GridMiddleware component to avoid side effects at module load time
209+
// defaultTableOptionsRegistry.register(MiddlewareCustomOption);
202210

203211
/**
204212
* Panel middleware that wraps the GridPanelPlugin.

packages/dashboard-core-plugins/src/TableHistoryPlugin.tsx

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { type dh } from '@deephaven/jsapi-types';
99
import { Button } from '@deephaven/components';
1010
import { vsHistory, vsTrash } from '@deephaven/icons';
1111
import { usePersistentState } from '@deephaven/dashboard';
12+
import { type MoveOperation } from '@deephaven/grid';
1213
import {
1314
type TableOption,
1415
type TableOptionPanelProps,
@@ -49,6 +50,8 @@ interface DehydratedStateSnapshot {
4950
selectDistinctColumns: readonly ColumnName[];
5051
/** Custom columns */
5152
customColumns: readonly ColumnName[];
53+
/** Re-arranged columns (move operations) */
54+
movedColumns: readonly MoveOperation[];
5255
}
5356

5457
/**
@@ -84,6 +87,7 @@ function dehydrateSnapshot(
8487
invertSearchColumns: gridState.invertSearchColumns,
8588
selectDistinctColumns: [...gridState.selectDistinctColumns],
8689
customColumns: [...gridState.customColumns],
90+
movedColumns: [...gridState.movedColumns],
8791
};
8892
}
8993

@@ -198,6 +202,12 @@ function TableHistoryPanel(_props: TableOptionPanelProps): JSX.Element {
198202
dispatch({ type: 'SET_SORTS', sorts: hydratedSorts });
199203
dispatch({ type: 'SET_REVERSE', reverse: snapshot.reverse });
200204

205+
// Restore moved columns (re-arranged column order)
206+
dispatch({
207+
type: 'SET_MOVED_COLUMNS',
208+
columns: [...snapshot.movedColumns],
209+
});
210+
201211
// Stay on the Table History screen after restoring
202212
},
203213
[dispatch, model, irisGridUtils, gridState.selectDistinctColumns]
@@ -216,8 +226,104 @@ function TableHistoryPanel(_props: TableOptionPanelProps): JSX.Element {
216226
setState({ snapshots: [] });
217227
}, [setState]);
218228

229+
// Compute what has changed since the last saved snapshot
230+
const changedProperties = useMemo(() => {
231+
const lastSnapshot = snapshots[snapshots.length - 1];
232+
if (lastSnapshot == null) {
233+
return null; // No previous snapshot to compare against
234+
}
235+
236+
const currentDehydrated = dehydrateSnapshot(gridState, irisGridUtils);
237+
const changes: string[] = [];
238+
239+
// Compare sorts
240+
const sortsChanged =
241+
JSON.stringify(currentDehydrated.sorts) !==
242+
JSON.stringify(lastSnapshot.sorts);
243+
if (sortsChanged) {
244+
changes.push(`Sorts: ${currentDehydrated.sorts.length} column(s)`);
245+
}
246+
247+
// Compare quick filters
248+
const quickFiltersChanged =
249+
JSON.stringify(currentDehydrated.quickFilters) !==
250+
JSON.stringify(lastSnapshot.quickFilters);
251+
if (quickFiltersChanged) {
252+
changes.push(
253+
`Quick Filters: ${currentDehydrated.quickFilters.length} filter(s)`
254+
);
255+
}
256+
257+
// Compare advanced filters
258+
const advancedFiltersChanged =
259+
JSON.stringify(currentDehydrated.advancedFilters) !==
260+
JSON.stringify(lastSnapshot.advancedFilters);
261+
if (advancedFiltersChanged) {
262+
changes.push(
263+
`Advanced Filters: ${currentDehydrated.advancedFilters.length} filter(s)`
264+
);
265+
}
266+
267+
// Compare search
268+
if (currentDehydrated.searchValue !== lastSnapshot.searchValue) {
269+
changes.push(`Search: "${currentDehydrated.searchValue || '(empty)'}"`);
270+
}
271+
272+
// Compare reverse
273+
if (currentDehydrated.reverse !== lastSnapshot.reverse) {
274+
changes.push(`Reverse: ${currentDehydrated.reverse}`);
275+
}
276+
277+
// Compare select distinct
278+
const selectDistinctChanged =
279+
JSON.stringify(currentDehydrated.selectDistinctColumns) !==
280+
JSON.stringify(lastSnapshot.selectDistinctColumns);
281+
if (selectDistinctChanged) {
282+
changes.push(
283+
`Select Distinct: ${currentDehydrated.selectDistinctColumns.length} column(s)`
284+
);
285+
}
286+
287+
// Compare custom columns
288+
const customColumnsChanged =
289+
JSON.stringify(currentDehydrated.customColumns) !==
290+
JSON.stringify(lastSnapshot.customColumns);
291+
if (customColumnsChanged) {
292+
changes.push(
293+
`Custom Columns: ${currentDehydrated.customColumns.length} column(s)`
294+
);
295+
}
296+
297+
// Compare moved columns
298+
const movedColumnsChanged =
299+
JSON.stringify(currentDehydrated.movedColumns) !==
300+
JSON.stringify(lastSnapshot.movedColumns);
301+
if (movedColumnsChanged) {
302+
changes.push(
303+
`Column Order: ${currentDehydrated.movedColumns.length} move(s)`
304+
);
305+
}
306+
307+
return changes;
308+
}, [snapshots, gridState, irisGridUtils]);
309+
219310
return (
220311
<div className="container mt-3">
312+
{/* Show changed properties since last snapshot */}
313+
{changedProperties != null && changedProperties.length > 0 && (
314+
<div className="mb-3">
315+
<h6 className="text-muted mb-1">Changed since last snapshot:</h6>
316+
<ul className="list-unstyled text-muted small mb-0">
317+
{changedProperties.map(change => (
318+
<li key={change}>{change}</li>
319+
))}
320+
</ul>
321+
</div>
322+
)}
323+
{changedProperties != null && changedProperties.length === 0 && (
324+
<p className="text-muted small mb-3">No changes since last snapshot.</p>
325+
)}
326+
221327
<div className="d-flex flex-column gap-2">
222328
<Button kind="primary" onClick={handleSaveSnapshot}>
223329
Save Snapshot
@@ -280,7 +386,7 @@ const TableHistoryOption: TableOption = {
280386

281387
menuItem: {
282388
title: 'Table History',
283-
subtitle: 'Save and restore table state',
389+
// subtitle: 'Save and restore table state',
284390
icon: vsHistory,
285391
order: -50,
286392
isAvailable: () => true,

packages/embed-widget/src/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,13 @@ async function getCorePlugins() {
4444
);
4545
const {
4646
GridPluginConfig,
47-
GridMiddlewarePluginConfig,
4847
TableHistoryPluginConfig,
4948
PandasPluginConfig,
5049
ChartPluginConfig,
5150
WidgetLoaderPluginConfig,
5251
} = dashboardCorePlugins;
5352
return [
5453
GridPluginConfig,
55-
GridMiddlewarePluginConfig,
5654
TableHistoryPluginConfig,
5755
PandasPluginConfig,
5856
ChartPluginConfig,

0 commit comments

Comments
 (0)