1- import React , { useCallback , useEffect , useMemo , useState } from 'react' ;
1+ import React , {
2+ useCallback ,
3+ useEffect ,
4+ useMemo ,
5+ useRef ,
6+ useState ,
7+ } from 'react' ;
28import { useSelector } from 'react-redux' ;
39import classNames from 'classnames' ;
410import {
@@ -8,6 +14,8 @@ import {
814 type IrisGridContextMenuData ,
915 IrisGridProps ,
1016 IrisGridUtils ,
17+ IrisGridState ,
18+ DehydratedIrisGridState ,
1119} from '@deephaven/iris-grid' ;
1220import {
1321 ColorValues ,
@@ -37,6 +45,7 @@ import UITableContextMenuHandler, {
3745} from './UITableContextMenuHandler' ;
3846import UITableModel , { makeUiTableModel } from './UITableModel' ;
3947import { UITableLayoutHints } from './JsTableProxy' ;
48+ import usePersistentState from '../hooks/usePersistentState' ;
4049
4150const log = Log . module ( '@deephaven/js-plugin-ui/UITable' ) ;
4251
@@ -167,6 +176,8 @@ export function UITable({
167176 databars = EMPTY_ARRAY as unknown as DatabarConfig [ ] ,
168177 ...userStyleProps
169178} : UITableProps ) : JSX . Element | null {
179+ const id = useMemo ( ( ) => Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) , [ ] ) ;
180+ console . log ( 'render table' , id ) ;
170181 const [ throwError ] = useThrowError ( ) ;
171182
172183 // Margin looks wrong with ui.table, so we want to map margin to padding instead
@@ -275,6 +286,43 @@ export function UITable({
275286 model . setColorMap ( colorMap ) ;
276287 }
277288
289+ const prevState = useRef < IrisGridState | undefined > ( ) ;
290+ const [ dehydratedState , setDehydratedState ] = usePersistentState <
291+ DehydratedIrisGridState | undefined
292+ > ( undefined ) ;
293+ const initialState = useRef ( dehydratedState ) ;
294+
295+ const onStateChange = useCallback (
296+ ( newState : IrisGridState ) => {
297+ if (
298+ model == null ||
299+ newState . metrics == null ||
300+ newState === prevState . current ||
301+ newState . sorts === prevState . current ?. sorts
302+ ) {
303+ return ;
304+ }
305+ // console.log('onStateChange', newState);
306+ prevState . current = newState ;
307+ setDehydratedState (
308+ utils . dehydrateIrisGridState ( model , {
309+ ...newState ,
310+ metrics : {
311+ userColumnWidths : newState . metrics . userColumnWidths ,
312+ userRowHeights : newState . metrics . userRowHeights ,
313+ } ,
314+ } )
315+ ) ;
316+ } ,
317+ [ model , setDehydratedState , utils ]
318+ ) ;
319+
320+ const hydratedState = useMemo ( ( ) => {
321+ if ( model && initialState . current ) {
322+ return utils . hydrateIrisGridState ( model , initialState . current ) ;
323+ }
324+ } , [ model , utils ] ) ;
325+
278326 const hydratedSorts = useMemo ( ( ) => {
279327 if ( sorts !== undefined && columns !== undefined ) {
280328 log . debug ( 'Hydrating sorts' , sorts ) ;
@@ -401,59 +449,66 @@ export function UITable({
401449 [ contextMenu , alwaysFetchColumns ]
402450 ) ;
403451
404- const irisGridProps = useMemo (
405- ( ) =>
406- ( {
407- mouseHandlers,
408- alwaysFetchColumns,
409- showSearchBar,
410- sorts : hydratedSorts ,
411- quickFilters : hydratedQuickFilters ,
412- isFilterBarShown : showQuickFilters ,
413- reverseType : reverse
414- ? TableUtils . REVERSE_TYPE . POST_SORT
415- : TableUtils . REVERSE_TYPE . NONE ,
416- density,
417- settings : { ...settings , showExtraGroupColumn : showGroupingColumn } ,
418- onContextMenu,
419- aggregationSettings : {
420- aggregations :
421- aggregations != null
422- ? ensureArray ( aggregations ) . map ( agg => {
423- if ( agg . cols != null && agg . ignore_cols != null ) {
424- throw new Error (
425- 'Cannot specify both cols and ignore_cols in a UI table aggregation'
426- ) ;
427- }
428- return {
429- operation : getAggregationOperation ( agg . agg ) ,
430- selected : ensureArray ( agg . cols ?? agg . ignore_cols ?? [ ] ) ,
431- // If agg.cols is set, we don't want to invert
432- // If it is not set, then the only other options are ignore_cols or neither
433- // In both cases, we want to invert since we are either ignoring, or selecting all as [] inverted
434- invert : agg . cols == null ,
435- } ;
436- } )
437- : [ ] ,
438- showOnTop : aggregationsPosition === 'top' ,
439- } ,
440- } ) satisfies Partial < IrisGridProps > ,
441- [
452+ const irisGridProps = useMemo ( ( ) => {
453+ const props = {
442454 mouseHandlers,
443455 alwaysFetchColumns,
444456 showSearchBar,
445- showQuickFilters ,
446- hydratedSorts ,
447- hydratedQuickFilters ,
448- reverse ,
457+ sorts : hydratedSorts ,
458+ quickFilters : hydratedQuickFilters ,
459+ isFilterBarShown : showQuickFilters ,
460+ reverseType : reverse
461+ ? TableUtils . REVERSE_TYPE . POST_SORT
462+ : TableUtils . REVERSE_TYPE . NONE ,
449463 density,
450- settings ,
451- showGroupingColumn ,
464+ settings : { ...settings , showExtraGroupColumn : showGroupingColumn } ,
452465 onContextMenu,
453- aggregations ,
454- aggregationsPosition ,
455- ]
456- ) ;
466+ aggregationSettings : {
467+ aggregations :
468+ aggregations != null
469+ ? ensureArray ( aggregations ) . map ( agg => {
470+ if ( agg . cols != null && agg . ignore_cols != null ) {
471+ throw new Error (
472+ 'Cannot specify both cols and ignore_cols in a UI table aggregation'
473+ ) ;
474+ }
475+ return {
476+ operation : getAggregationOperation ( agg . agg ) ,
477+ selected : ensureArray ( agg . cols ?? agg . ignore_cols ?? [ ] ) ,
478+ // If agg.cols is set, we don't want to invert
479+ // If it is not set, then the only other options are ignore_cols or neither
480+ // In both cases, we want to invert since we are either ignoring, or selecting all as [] inverted
481+ invert : agg . cols == null ,
482+ } ;
483+ } )
484+ : [ ] ,
485+ showOnTop : aggregationsPosition === 'top' ,
486+ } ,
487+ } satisfies Partial < IrisGridProps > ;
488+
489+ // Remove any explicit undefined values
490+ Object . entries ( props ) . forEach ( ( [ key , value ] ) => {
491+ if ( value === undefined ) {
492+ delete props [ key ] ;
493+ }
494+ } ) ;
495+
496+ return props ;
497+ } , [
498+ mouseHandlers ,
499+ alwaysFetchColumns ,
500+ showSearchBar ,
501+ showQuickFilters ,
502+ hydratedSorts ,
503+ hydratedQuickFilters ,
504+ reverse ,
505+ density ,
506+ settings ,
507+ showGroupingColumn ,
508+ onContextMenu ,
509+ aggregations ,
510+ aggregationsPosition ,
511+ ] ) ;
457512
458513 return model ? (
459514 < div
@@ -464,6 +519,9 @@ export function UITable({
464519 < IrisGrid
465520 ref = { ref => setIrisGrid ( ref ) }
466521 model = { model }
522+ onStateChange = { onStateChange }
523+ // eslint-disable-next-line react/jsx-props-no-spreading
524+ { ...hydratedState }
467525 // eslint-disable-next-line react/jsx-props-no-spreading
468526 { ...irisGridProps }
469527 />
0 commit comments