@@ -11,7 +11,7 @@ import { KernelMessage } from '@jupyterlab/services';
1111import { withIgnoredSidebarKernelUpdates } from '../utils/kernelOperationNotifier' ;
1212import { variableDict } from '../python_code/getVariables' ;
1313
14- interface VariableInfo {
14+ interface IVariableInfo {
1515 name : string ;
1616 type : string ;
1717 shape : string ;
@@ -20,8 +20,8 @@ interface VariableInfo {
2020 value : string ;
2121}
2222
23- interface VariableContextProps {
24- variables : VariableInfo [ ] ;
23+ interface IVariableContextProps {
24+ variables : IVariableInfo [ ] ;
2525 loading : boolean ;
2626 error : string | null ;
2727 searchTerm : string ;
@@ -31,34 +31,82 @@ interface VariableContextProps {
3131 refreshCount : number ;
3232}
3333
34- const VariableContext = createContext < VariableContextProps | undefined > (
34+ const VariableContext = createContext < IVariableContextProps | undefined > (
3535 undefined
3636) ;
3737
38+ type Task = ( ) => Promise < void > | void ;
39+
40+ class DebouncedTaskQueue {
41+ // Holds the timer handle.
42+ private timer : ReturnType < typeof setTimeout > | null = null ;
43+ // Holds the most recently added task.
44+ private lastTask : Task | null = null ;
45+ private delay : number ;
46+
47+ /**
48+ * @param delay Time in milliseconds to wait before executing the last task.
49+ */
50+ constructor ( delay : number = 500 ) {
51+ this . delay = delay ;
52+ }
53+
54+ /**
55+ * Adds a new task to the queue. Only the last task added within the delay period will be executed.
56+ * @param task A function representing the task.
57+ */
58+ add ( task : Task ) : void {
59+ // Save (or overwrite) the latest task.
60+ this . lastTask = task ;
61+
62+ // If there’s already a pending timer, clear it.
63+ if ( this . timer ) {
64+ clearTimeout ( this . timer ) ;
65+ }
66+
67+ // Start (or restart) the timer.
68+ this . timer = setTimeout ( async ( ) => {
69+ if ( this . lastTask ) {
70+ try {
71+ // Execute the latest task.
72+ await this . lastTask ( ) ;
73+ } catch ( error ) {
74+ console . error ( 'Task execution failed:' , error ) ;
75+ }
76+ }
77+ // After execution, clear the stored task and timer.
78+ this . lastTask = null ;
79+ this . timer = null ;
80+ } , this . delay ) ;
81+ }
82+ }
83+
3884export const VariableContextProvider : React . FC < {
3985 children : React . ReactNode ;
4086} > = ( { children } ) => {
4187 const notebookPanel = useNotebookPanelContext ( ) ;
4288 const kernel = useNotebookKernelContext ( ) ;
43- const [ variables , setVariables ] = useState < VariableInfo [ ] > ( [ ] ) ;
89+ const [ variables , setVariables ] = useState < IVariableInfo [ ] > ( [ ] ) ;
4490 const [ loading , setLoading ] = useState < boolean > ( false ) ;
4591 const [ error , setError ] = useState < string | null > ( null ) ;
4692 const [ searchTerm , setSearchTerm ] = useState < string > ( '' ) ;
4793 const [ isRefreshing , setIsRefreshing ] = useState < boolean > ( false ) ;
4894 const [ refreshCount , setRefreshCount ] = useState < number > ( 0 ) ;
95+ const queue = new DebouncedTaskQueue ( 250 ) ;
4996
5097 const executeCode = useCallback ( async ( ) => {
5198 await withIgnoredSidebarKernelUpdates ( async ( ) => {
52- setIsRefreshing ( true ) ;
53- setLoading ( true ) ;
99+ // setIsRefreshing(true);
100+ // setLoading(true);
54101 setError ( null ) ;
55102
56103 if ( ! notebookPanel ) {
104+ setVariables ( [ ] ) ;
57105 setLoading ( false ) ;
58106 setIsRefreshing ( false ) ;
59107 return ;
60108 }
61- setVariables ( [ ] ) ;
109+ // setVariables([]);
62110
63111 try {
64112 const future =
@@ -86,10 +134,10 @@ export const VariableContextProvider: React.FC<{
86134 try {
87135 const cleanedData = textData . replace ( / ^ [ ' " ] | [ ' " ] $ / g, '' ) ;
88136 const doubleQuotedData = cleanedData . replace ( / ' / g, '"' ) ;
89- const parsedData : VariableInfo [ ] =
137+ const parsedData : IVariableInfo [ ] =
90138 JSON . parse ( doubleQuotedData ) ;
91139 if ( Array . isArray ( parsedData ) ) {
92- const mappedVariables : VariableInfo [ ] = parsedData . map (
140+ const mappedVariables : IVariableInfo [ ] = parsedData . map (
93141 ( item : any ) => ( {
94142 name : item . varName ,
95143 type : item . varType ,
@@ -108,6 +156,7 @@ export const VariableContextProvider: React.FC<{
108156 setRefreshCount ( prev => prev + 1 ) ;
109157 } catch ( err ) {
110158 setError ( 'Error during export JSON.' ) ;
159+ setVariables ( [ ] ) ;
111160 setLoading ( false ) ;
112161 setIsRefreshing ( false ) ;
113162 }
@@ -121,6 +170,7 @@ export const VariableContextProvider: React.FC<{
121170 setIsRefreshing ( false ) ;
122171 }
123172 } ) ;
173+ return ;
124174 } , [ notebookPanel , kernel ] ) ;
125175
126176 useEffect ( ( ) => {
@@ -135,7 +185,7 @@ export const VariableContextProvider: React.FC<{
135185 error,
136186 searchTerm,
137187 setSearchTerm,
138- refreshVariables : executeCode ,
188+ refreshVariables : ( ) => queue . add ( ( ) => executeCode ( ) ) ,
139189 isRefreshing,
140190 refreshCount
141191 } }
@@ -145,7 +195,7 @@ export const VariableContextProvider: React.FC<{
145195 ) ;
146196} ;
147197
148- export const useVariableContext = ( ) : VariableContextProps => {
198+ export const useVariableContext = ( ) : IVariableContextProps => {
149199 const context = useContext ( VariableContext ) ;
150200 if ( context === undefined ) {
151201 throw new Error (
0 commit comments