11/* eslint-disable react/jsx-props-no-spreading */
22/* eslint-disable react/no-unused-state */
33import React , { Component , type ReactElement , type RefObject } from 'react' ;
4+ import { IrisGridModel } from '@deephaven/iris-grid' ;
45import ConnectedIrisGridPanel , {
56 type IrisGridPanel ,
67 type OwnProps as IrisGridPanelOwnProps ,
@@ -16,6 +17,7 @@ export interface PandasPanelProps extends IrisGridPanelOwnProps {
1617interface PandasPanelState {
1718 shouldFocusGrid : boolean ;
1819 panelState : PanelState | null ;
20+ makeModel : IrisGridPanelOwnProps [ 'makeModel' ] ;
1921}
2022
2123/**
@@ -28,11 +30,17 @@ class PandasPanel extends Component<PandasPanelProps, PandasPanelState> {
2830
2931 static COMPONENT = 'PandasPanel' ;
3032
33+ // eslint-disable-next-line react/sort-comp
34+ private irisGridRef : RefObject < IrisGridPanel > ;
35+
36+ private model : IrisGridModel | null = null ;
37+
3138 constructor ( props : PandasPanelProps ) {
3239 super ( props ) ;
3340
3441 this . irisGridRef = React . createRef ( ) ;
3542
43+ this . handleDisconnect = this . handleDisconnect . bind ( this ) ;
3644 this . handleReload = this . handleReload . bind ( this ) ;
3745 this . handleGridStateChange = this . handleGridStateChange . bind ( this ) ;
3846 this . handlePanelStateUpdate = this . handlePanelStateUpdate . bind ( this ) ;
@@ -41,10 +49,58 @@ class PandasPanel extends Component<PandasPanelProps, PandasPanelState> {
4149 this . state = {
4250 shouldFocusGrid : false ,
4351 panelState, // Dehydrated panel state that can load this panel
52+ makeModel : this . wrapMakeModel ( props . makeModel ) ,
53+ } ;
54+ }
55+
56+ componentDidUpdate ( prevProps : Readonly < PandasPanelProps > ) : void {
57+ const { makeModel : prevMakeModel } = prevProps ;
58+ const { makeModel } = this . props ;
59+ if ( prevMakeModel !== makeModel ) {
60+ this . setState ( { makeModel : this . wrapMakeModel ( makeModel ) } ) ;
61+ }
62+ }
63+
64+ componentWillUnmount ( ) : void {
65+ if ( this . model != null ) {
66+ this . stopListening ( this . model ) ;
67+ }
68+ }
69+
70+ private wrapMakeModel (
71+ makeModel : IrisGridPanelOwnProps [ 'makeModel' ]
72+ ) : IrisGridPanelOwnProps [ 'makeModel' ] {
73+ return async ( ) => {
74+ // Need to listen for disconnect in the model, so we know when to throw this makeModel away
75+ const model = await makeModel ( ) ;
76+ if ( this . model != null ) {
77+ this . stopListening ( this . model ) ;
78+ }
79+ this . model = model ;
80+ this . startListening ( model ) ;
81+ return model ;
4482 } ;
4583 }
4684
47- irisGridRef : RefObject < IrisGridPanel > ;
85+ private startListening ( model : IrisGridModel ) : void {
86+ model . addEventListener (
87+ IrisGridModel . EVENT . DISCONNECT ,
88+ this . handleDisconnect
89+ ) ;
90+ }
91+
92+ private stopListening ( model : IrisGridModel ) : void {
93+ model . removeEventListener (
94+ IrisGridModel . EVENT . DISCONNECT ,
95+ this . handleDisconnect
96+ ) ;
97+ }
98+
99+ private handleDisconnect ( ) : void {
100+ // Once a Pandas widget is closed, the underlying table is closed and cannot be reconnected to.
101+ // Reset the model to undefined so IrisGridPanel doesn't try to use it anymore.
102+ this . irisGridRef . current ?. setState ( { model : undefined } ) ;
103+ }
48104
49105 handleReload ( ) : void {
50106 this . irisGridRef . current ?. initModel ( ) ;
@@ -70,12 +126,14 @@ class PandasPanel extends Component<PandasPanelProps, PandasPanelState> {
70126 }
71127
72128 render ( ) : ReactElement {
129+ const { makeModel } = this . state ;
73130 return (
74131 < ConnectedIrisGridPanel
75132 ref = { this . irisGridRef }
76133 onStateChange = { this . handleGridStateChange }
77134 onPanelStateUpdate = { this . handlePanelStateUpdate }
78135 { ...this . props }
136+ makeModel = { makeModel }
79137 >
80138 < PandasReloadButton onClick = { this . handleReload } />
81139 </ ConnectedIrisGridPanel >
0 commit comments