11import { useFileUploadManager } from './FileUploadManager' ;
22import FolderExplorerHeader from './FolderExplorerHeader' ;
33import VFolderNodeDescription from './VFolderNodeDescription' ;
4- import { Alert , Divider , Grid , Splitter , theme } from 'antd' ;
4+ import { Alert , Divider , Grid , Skeleton , Splitter , theme } from 'antd' ;
55import { createStyles } from 'antd-style' ;
66import { RcFile } from 'antd/es/upload' ;
77import {
@@ -12,7 +12,7 @@ import {
1212 toGlobalId ,
1313} from 'backend.ai-ui' ;
1414import _ from 'lodash' ;
15- import { useEffect , useRef } from 'react' ;
15+ import { Suspense , useDeferredValue , useEffect , useRef } from 'react' ;
1616import { useTranslation } from 'react-i18next' ;
1717import { graphql , useLazyLoadQuery } from 'react-relay' ;
1818import { FolderExplorerModalQuery } from 'src/__generated__/FolderExplorerModalQuery.graphql' ;
@@ -54,7 +54,6 @@ const FolderExplorerModal: React.FC<FolderExplorerProps> = ({
5454 const { xl } = Grid . useBreakpoint ( ) ;
5555 const { styles } = useStyles ( ) ;
5656 const folderExplorerRef = useRef < FolderExplorerElement > ( null ) ;
57- const { uploadStatus, uploadFiles } = useFileUploadManager ( vfolderID ) ;
5857 const [ fetchKey , updateFetchKey ] = useFetchKey ( ) ;
5958 const baiClient = useSuspendedBackendaiClient ( ) ;
6059 const currentDomain = useCurrentDomainValue ( ) ;
@@ -68,12 +67,7 @@ const FolderExplorerModal: React.FC<FolderExplorerProps> = ({
6867 ) ;
6968 const bodyRef = useRef < HTMLDivElement | null > ( null ) ;
7069
71- useEffect ( ( ) => {
72- if ( uploadStatus && _ . isEmpty ( uploadStatus ?. pendingFiles ) ) {
73- updateFetchKey ( ) ;
74- }
75- } , [ uploadStatus , updateFetchKey ] ) ;
76-
70+ const deferredOpen = useDeferredValue ( modalProps . open ) ;
7771 const { vfolder_node } = useLazyLoadQuery < FolderExplorerModalQuery > (
7872 graphql `
7973 query FolderExplorerModalQuery($vfolderGlobalId: String!) {
@@ -82,6 +76,8 @@ const FolderExplorerModal: React.FC<FolderExplorerProps> = ({
8276 unmanaged_path @since(version: "25.04.0")
8377 permissions
8478 host
79+ id
80+ name
8581 ...FolderExplorerHeaderFragment
8682 ...VFolderNodeDescriptionFragment
8783 ...VFolderNameTitleNodeFragment
@@ -90,9 +86,20 @@ const FolderExplorerModal: React.FC<FolderExplorerProps> = ({
9086 ` ,
9187 { vfolderGlobalId : toGlobalId ( 'VirtualFolderNode' , vfolderID ) } ,
9288 {
93- fetchPolicy : modalProps . open ? 'network-only' : 'store-only' ,
89+ // Only fetch when both deferredOpen and modalProps.open are true to prevent unnecessary requests during React transitions
90+ fetchPolicy :
91+ deferredOpen && modalProps . open ? 'network-only' : 'store-only' ,
9492 } ,
9593 ) ;
94+ const { uploadStatus, uploadFiles } = useFileUploadManager (
95+ vfolder_node ?. id ,
96+ vfolder_node ?. name || undefined ,
97+ ) ;
98+ useEffect ( ( ) => {
99+ if ( uploadStatus && _ . isEmpty ( uploadStatus ?. pendingFiles ) ) {
100+ updateFetchKey ( ) ;
101+ }
102+ } , [ uploadStatus , updateFetchKey ] ) ;
96103
97104 const hasDownloadContentPermission = _ . includes (
98105 unitedAllowedPermissionByVolume [ vfolder_node ?. host ?? '' ] ,
@@ -114,7 +121,7 @@ const FolderExplorerModal: React.FC<FolderExplorerProps> = ({
114121 message = { t ( 'explorer.NoExplorerSupportForUnmanagedFolder' ) }
115122 showIcon
116123 />
117- ) : ! hasNoPermissions ? (
124+ ) : ! hasNoPermissions && vfolder_node ? (
118125 < BAIFileExplorer
119126 targetVFolderId = { vfolderID }
120127 fetchKey = { fetchKey }
@@ -149,10 +156,15 @@ const FolderExplorerModal: React.FC<FolderExplorerProps> = ({
149156 < BAIModal
150157 className = { styles . baiModalHeader }
151158 width = { '90%' }
152- centered
153159 keyboard
154160 destroyOnHidden
155161 footer = { null }
162+ style = { { maxWidth : '1600px' } }
163+ styles = { {
164+ body : {
165+ height : '100vh' ,
166+ } ,
167+ } }
156168 title = {
157169 vfolder_node ? (
158170 < FolderExplorerHeader
@@ -171,58 +183,68 @@ const FolderExplorerModal: React.FC<FolderExplorerProps> = ({
171183 } }
172184 { ...modalProps }
173185 >
174- < BAIFlex direction = "column" gap = { 'lg' } align = "stretch" >
175- { ! vfolder_node ? (
176- < Alert
177- message = { t ( 'explorer.FolderNotFoundOrNoAccess' ) }
178- type = "error"
179- showIcon
180- />
181- ) : hasNoPermissions ? (
182- < Alert message = { t ( 'explorer.NoPermissions' ) } type = "error" showIcon />
183- ) : currentProject ?. id !== vfolder_node ?. group &&
184- ! ! vfolder_node ?. group ? (
185- < Alert message = { t ( 'data.NotInProject' ) } type = "warning" showIcon />
186- ) : null }
187-
188- { xl ? (
189- < Splitter
190- // Force re-render component when xl breakpoint changes to reset panel sizes
191- // This ensures defaultSize is recalculated based on current screen size
192- key = { xl ? 'large' : 'small' }
193- style = { {
194- gap : token . size ,
195- // maxHeight: 'calc(100vh - 220px)',
196- } }
197- layout = { xl ? 'horizontal' : 'vertical' }
198- >
199- < Splitter . Panel resizable = { false } >
200- { fileExplorerElement }
201- </ Splitter . Panel >
202- < Splitter . Panel defaultSize = { 500 } >
203- { vFolderDescriptionElement }
204- </ Splitter . Panel >
205- </ Splitter >
186+ < Suspense fallback = { < Skeleton active /> } >
187+ { /* Use <Skeleton/> instead of using `loading` prop because layout align issue. */ }
188+ { deferredOpen !== modalProps . open ? (
189+ < Skeleton active />
206190 ) : (
207- < BAIFlex direction = "column" align = "stretch" >
208- { fileExplorerElement }
209- < Divider
210- style = { {
211- borderColor : token . colorBorderSecondary ,
212- } }
213- />
214- { vFolderDescriptionElement }
191+ < BAIFlex direction = "column" gap = { 'lg' } align = "stretch" >
192+ { ! vfolder_node ? (
193+ < Alert
194+ message = { t ( 'explorer.FolderNotFoundOrNoAccess' ) }
195+ type = "error"
196+ showIcon
197+ />
198+ ) : hasNoPermissions ? (
199+ < Alert
200+ message = { t ( 'explorer.NoPermissions' ) }
201+ type = "error"
202+ showIcon
203+ />
204+ ) : currentProject ?. id !== vfolder_node ?. group &&
205+ ! ! vfolder_node ?. group ? (
206+ < Alert message = { t ( 'data.NotInProject' ) } type = "warning" showIcon />
207+ ) : null }
208+
209+ { xl ? (
210+ < Splitter
211+ // Force re-render component when xl breakpoint changes to reset panel sizes
212+ // This ensures defaultSize is recalculated based on current screen size
213+ key = { 'large' }
214+ style = { {
215+ gap : token . size ,
216+ } }
217+ layout = { 'horizontal' }
218+ >
219+ < Splitter . Panel resizable = { false } >
220+ { fileExplorerElement }
221+ </ Splitter . Panel >
222+ < Splitter . Panel defaultSize = { 500 } >
223+ { vFolderDescriptionElement }
224+ </ Splitter . Panel >
225+ </ Splitter >
226+ ) : (
227+ < BAIFlex direction = "column" align = "stretch" >
228+ { fileExplorerElement }
229+ < Divider
230+ style = { {
231+ borderColor : token . colorBorderSecondary ,
232+ } }
233+ />
234+ { vFolderDescriptionElement }
235+ </ BAIFlex >
236+ ) }
237+ < div style = { { display : 'none' } } >
238+ { /* @ts -ignore TODO: delete below after https://lablup.atlassian.net/browse/FR-1150 */ }
239+ < backend-ai-folder-explorer
240+ ref = { folderExplorerRef }
241+ active
242+ vfolderID = { vfolderID }
243+ />
244+ </ div >
215245 </ BAIFlex >
216246 ) }
217- < div style = { { display : 'none' } } >
218- { /* @ts -ignore TODO: delete below after https://lablup.atlassian.net/browse/FR-1150 */ }
219- < backend-ai-folder-explorer
220- ref = { folderExplorerRef }
221- active
222- vfolderID = { vfolderID }
223- />
224- </ div >
225- </ BAIFlex >
247+ </ Suspense >
226248 </ BAIModal >
227249 ) ;
228250} ;
0 commit comments