@@ -528,61 +528,77 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
528528 }
529529 } , [ shownPythonToolboxCategories ] ) ;
530530
531- // Fetch modules when project changes.
531+ // Fetch any unfetched modules when project changes.
532532 React . useEffect ( ( ) => {
533- if ( project && storage ) {
534- const fetchModules = async ( ) => {
535- const promises : { [ modulePath : string ] : Promise < string > } = { } ; // value is promise of module content.
536- promises [ project . robot . modulePath ] = storage . fetchFileContentText ( project . robot . modulePath ) ;
537- project . mechanisms . forEach ( mechanism => {
538- promises [ mechanism . modulePath ] = storage . fetchFileContentText ( mechanism . modulePath ) ;
539- } ) ;
540- project . opModes . forEach ( opmode => {
541- promises [ opmode . modulePath ] = storage . fetchFileContentText ( opmode . modulePath ) ;
542- } ) ;
543- const updatedModulePathToContentText : { [ modulePath : string ] : string } = { } ; // value is module content text
544- await Promise . all (
545- Object . entries ( promises ) . map ( async ( [ modulePath , promise ] ) => {
546- updatedModulePathToContentText [ modulePath ] = await promise ;
547- } )
548- ) ;
549- const oldModulePathToContentText = modulePathToContentText ;
550- setModulePathToContentText ( updatedModulePathToContentText ) ;
551-
552- // Remove any deleted modules from modulePaths, modulePathToBlocklyComponent, and
553- // modulePathToEditor. Update currentModule if the current module was deleted.
554- for ( const modulePath in oldModulePathToContentText ) {
555- if ( modulePath in updatedModulePathToContentText ) {
556- continue ;
557- }
558- if ( currentModule && currentModule . modulePath === modulePath ) {
559- setCurrentModule ( project . robot ) ;
560- setActiveTab ( project . robot . modulePath ) ;
561- }
562- const indexToRemove : number = modulePaths . current . indexOf ( modulePath ) ;
563- if ( indexToRemove !== - 1 ) {
564- modulePaths . current . splice ( indexToRemove , 1 ) ;
565- }
566- if ( modulePath in modulePathToBlocklyComponent . current ) {
567- delete modulePathToBlocklyComponent . current [ modulePath ] ;
568- }
569- if ( modulePath in modulePathToEditor . current ) {
570- const editor = modulePathToEditor . current [ modulePath ] ;
571- editor . abandon ( ) ;
572- delete modulePathToEditor . current [ modulePath ] ;
573- }
574- }
575- } ;
576- fetchModules ( ) ;
577- }
533+ fetchModules ( ) ;
578534 } , [ project ] ) ;
579535
536+ const fetchModules = async ( ) => {
537+ if ( ! project || ! storage ) {
538+ return ;
539+ }
540+ const oldModulePathToContentText = modulePathToContentText ;
541+ const promises : { [ modulePath : string ] : Promise < string > } = { } ; // value is promise of module content.
542+ const updatedModulePathToContentText : { [ modulePath : string ] : string } = { } ; // value is module content text
543+ if ( project . robot . modulePath in modulePathToContentText ) {
544+ updatedModulePathToContentText [ project . robot . modulePath ] = modulePathToContentText [ project . robot . modulePath ] ;
545+ } else {
546+ promises [ project . robot . modulePath ] = storage . fetchFileContentText ( project . robot . modulePath ) ;
547+ }
548+ project . mechanisms . forEach ( mechanism => {
549+ if ( mechanism . modulePath in modulePathToContentText ) {
550+ updatedModulePathToContentText [ mechanism . modulePath ] = modulePathToContentText [ mechanism . modulePath ] ;
551+ } else {
552+ promises [ mechanism . modulePath ] = storage . fetchFileContentText ( mechanism . modulePath ) ;
553+ }
554+ } ) ;
555+ project . opModes . forEach ( opmode => {
556+ if ( opmode . modulePath in modulePathToContentText ) {
557+ updatedModulePathToContentText [ opmode . modulePath ] = modulePathToContentText [ opmode . modulePath ] ;
558+ } else {
559+ promises [ opmode . modulePath ] = storage . fetchFileContentText ( opmode . modulePath ) ;
560+ }
561+ } ) ;
562+ if ( Object . keys ( promises ) . length ) {
563+ await Promise . all (
564+ Object . entries ( promises ) . map ( async ( [ modulePath , promise ] ) => {
565+ updatedModulePathToContentText [ modulePath ] = await promise ;
566+ } )
567+ ) ;
568+ setModulePathToContentText ( updatedModulePathToContentText ) ;
569+ }
570+
571+ // Remove any deleted modules from modulePaths, modulePathToBlocklyComponent, and
572+ // modulePathToEditor. Update currentModule if the current module was deleted.
573+ for ( const modulePath in oldModulePathToContentText ) {
574+ if ( modulePath in updatedModulePathToContentText ) {
575+ continue ;
576+ }
577+ if ( currentModule && currentModule . modulePath === modulePath ) {
578+ setCurrentModule ( project . robot ) ;
579+ setActiveTab ( project . robot . modulePath ) ;
580+ }
581+ const indexToRemove : number = modulePaths . current . indexOf ( modulePath ) ;
582+ if ( indexToRemove !== - 1 ) {
583+ modulePaths . current . splice ( indexToRemove , 1 ) ;
584+ }
585+ if ( modulePath in modulePathToBlocklyComponent . current ) {
586+ delete modulePathToBlocklyComponent . current [ modulePath ] ;
587+ }
588+ if ( modulePath in modulePathToEditor . current ) {
589+ const editor = modulePathToEditor . current [ modulePath ] ;
590+ editor . abandon ( ) ;
591+ delete modulePathToEditor . current [ modulePath ] ;
592+ }
593+ }
594+ } ;
595+
580596 // Load saved tabs when project changes
581597 React . useEffect ( ( ) => {
582598 const loadSavedTabs = async ( ) => {
583599 if ( project && ! isLoading ) {
584600 setIsLoadingTabs ( true ) ;
585-
601+
586602 // Add a small delay to ensure UserSettingsProvider context is updated
587603 await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
588604
@@ -705,7 +721,7 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
705721 }
706722 return tab ;
707723 } ) ;
708-
724+
709725 // Only update if something actually changed
710726 const titlesChanged = updatedTabs . some ( ( tab , index ) => tab . title !== tabItems [ index ] ?. title ) ;
711727 if ( titlesChanged ) {
@@ -734,6 +750,10 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
734750 return ( ) => clearTimeout ( timeoutId ) ;
735751 } , [ tabItems , project ?. projectName , isLoadingTabs ] ) ;
736752
753+ const onProjectChanged = async ( ) : Promise < void > => {
754+ await fetchModules ( ) ;
755+ } ;
756+
737757 const { Sider, Content } = Antd . Layout ;
738758
739759 return (
@@ -766,6 +786,7 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
766786 gotoTab = { setActiveTab }
767787 project = { project }
768788 setProject = { setProject }
789+ onProjectChanged = { onProjectChanged }
769790 openWPIToolboxSettings = { ( ) => setToolboxSettingsModalIsOpen ( true ) }
770791 theme = { theme }
771792 setTheme = { setTheme }
@@ -784,7 +805,7 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
784805 currentModule = { currentModule }
785806 setCurrentModule = { changeModule }
786807 project = { project }
787- setProject = { setProject }
808+ onProjectChanged = { onProjectChanged }
788809 storage = { storage }
789810 />
790811 < div style = { { display : 'flex' , height : FULL_HEIGHT } } >
0 commit comments