feat: DH-19000: Persist deephaven UI table client-side state#1152
Conversation
|
ui docs preview (Available for 14 days) |
|
ui docs preview (Available for 14 days) |
7e6d8be to
45cf06a
Compare
There was a problem hiding this comment.
Pull Request Overview
This PR adds client-side persistence for the Deephaven UI table and widget panel state.
- Introduces a new optional property (panelStates) in the widget data type.
- Adds onDataChange and getInitialData callbacks to the React panel manager components, updating their interfaces and usage in DocumentHandler, ReactPanel, and associated tests.
- Integrates persistent state support in the ReactPanel and UITable components.
Reviewed Changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| plugins/ui/src/js/src/widget/WidgetTypes.ts | Added an optional panelStates property to support persisting panel state |
| plugins/ui/src/js/src/widget/DocumentHandler.tsx | Added onDataChange and getInitialData callbacks to propagate panel state changes |
| plugins/ui/src/js/src/layout/ReactPanelManager.ts | Updated ReactPanelManager and ReactPanelControl interfaces to include state persistence methods |
| plugins/ui/src/js/src/layout/ReactPanel.tsx | Wrapped children in PersistentStateProvider for persisted state updates |
| plugins/ui/src/js/src/layout/ReactPanel.test.tsx | Updated tests to include mocks for the new persistence callbacks |
| plugins/ui/src/js/src/elements/UITable/UITable.tsx | Integrated client-side state persistence by using usePersistentState and merging server and hydrated client state |
Files not reviewed (1)
- plugins/ui/src/js/package.json: Language not supported
| * In the future we may want to do a smarter merge of these. | ||
| */ | ||
| const mergedIrisGridProps = useMemo(() => { | ||
| if (initialIrisGridServerProps.current === irisGridServerProps) { |
There was a problem hiding this comment.
Comparing initialIrisGridServerProps.current with irisGridServerProps using reference equality may be unreliable if the server state object is recreated on each render. Consider using a deep comparison utility or ensuring that the server props maintain stable references so that rehydration logic behaves as intended.
|
ui docs preview (Available for 14 days) |
1 similar comment
|
ui docs preview (Available for 14 days) |
|
ui docs preview (Available for 14 days) |
There was a problem hiding this comment.
Published new web-client-ui packages so you should be able to use this now
|
ui docs preview (Available for 14 days) |
|
This needs a nightly build of DHC with the latest web-client-ui for e2e tests to work because of the new externalized imports |
There was a problem hiding this comment.
Pull Request Overview
This PR introduces client-side state persistence for Deephaven UI tables by integrating persistent state handling into panel management and table components.
- Adds a new panelStates field to widget data and updates the panel manager interface with onDataChange and getInitialData methods.
- Integrates a PersistentStateProvider in ReactPanel and updates UITable to merge client and server state for rehydration.
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/ui/src/js/src/widget/WidgetTypes.ts | Added panelStates support to WidgetData. |
| plugins/ui/src/js/src/widget/DocumentHandler.tsx | Introduced onDataChange handler for state persistence. |
| plugins/ui/src/js/src/layout/ReactPanelManager.ts | Updated interface and hooks to include data persistence functions. |
| plugins/ui/src/js/src/layout/ReactPanelErrorBoundary.tsx | Enhanced error handling to provide a reset action via onReset. |
| plugins/ui/src/js/src/layout/ReactPanel.tsx | Integrated PersistentStateProvider and error reset logic for rehydration. |
| plugins/ui/src/js/src/layout/ReactPanel.test.tsx | Updated tests to accommodate new data persistence behaviors. |
| plugins/ui/src/js/src/elements/UITable/UITable.tsx | Merged persistent client state with server state for the table component. |
| plugins/ui/src/js/package.json | Updated dependencies to newer versions. |
| * Otherwise, we have received changes from the server and we should use those over client state. | ||
| * In the future we may want to do a smarter merge of these. | ||
| */ | ||
| const mergedIrisGridProps = useMemo(() => { |
There was a problem hiding this comment.
[nitpick] The conditional merge using reference equality to compare irisGridServerProps may be fragile. Consider using a more robust state comparison (or an explicit rehydration flag) to ensure the correct precedence of client vs server state.
| const onErrorReset = useCallback(() => { | ||
| // Not EMPTY_ARRAY, because we always want to trigger a re-render | ||
| // in case a panel is reloaded and errors again | ||
| setInitialData([]); |
There was a problem hiding this comment.
[nitpick] Using a literal empty array to reset state may be less clear in intent. Consider extracting this value to a named constant or adding an inline comment to clarify that an empty array forces a re-render for error recovery.
| const onErrorReset = useCallback(() => { | |
| // Not EMPTY_ARRAY, because we always want to trigger a re-render | |
| // in case a panel is reloaded and errors again | |
| setInitialData([]); | |
| const EMPTY_ARRAY: never[] = []; // Used to reset state and trigger a re-render | |
| const onErrorReset = useCallback(() => { | |
| // Always use EMPTY_ARRAY to ensure a re-render for error recovery | |
| setInitialData(EMPTY_ARRAY); |
|
Added an |
|
ui docs preview (Available for 14 days) |
|
ui docs preview (Available for 14 days) |
| log.error('Error caught by ErrorBoundary', error, errorInfo); | ||
| } | ||
|
|
||
| getError(): WidgetError | undefined { |
There was a problem hiding this comment.
We can, although it probably won't provide much benefit. The object is cheap to create and this component should basically never re-render until the action button is clicked
|
Added memoization (although I don't think it's really necessary for this case) |
|
ui docs preview (Available for 14 days) |
Needs to run with un-released web-client-ui.
Simple example that uses both regular and ui.table to show persistence.
Note that there is an issue with not many props in
IrisGridresponding to changes, so the merging of client and server state is a best guess for what we'll want when it does respond to prop changes on those other props (sort, filters, etc.)Should probably add