11import { FolderExplorerHeaderFragment$key } from '../__generated__/FolderExplorerHeaderFragment.graphql' ;
22import EditableVFolderName from './EditableVFolderName' ;
33import VFolderNodeIdenticon from './VFolderNodeIdenticon' ;
4- import { Button , Tooltip , Image , Grid , theme , Typography } from 'antd' ;
4+ import { Button , Tooltip , Image , Grid , theme , Typography , App } from 'antd' ;
55import { BAIFlex } from 'backend.ai-ui' ;
6- import React , { LegacyRef } from 'react' ;
6+ import _ from 'lodash' ;
7+ import React , { LegacyRef , useState } from 'react' ;
78import { useTranslation } from 'react-i18next' ;
8- import { graphql , useFragment } from 'react-relay' ;
9+ import {
10+ fetchQuery ,
11+ graphql ,
12+ useFragment ,
13+ useRelayEnvironment ,
14+ } from 'react-relay' ;
15+ import { FolderExplorerHeader_ImageQuery } from 'src/__generated__/FolderExplorerHeader_ImageQuery.graphql' ;
16+ import { getImageFullName } from 'src/helper' ;
17+ import { useSuspendedBackendaiClient } from 'src/hooks' ;
18+ import { useStartSession } from 'src/hooks/useStartSession' ;
19+ import { SessionLauncherFormValue } from 'src/pages/SessionLauncherPage' ;
920
1021interface FolderExplorerHeaderProps {
1122 vfolderNodeFrgmt ?: FolderExplorerHeaderFragment$key | null ;
@@ -18,16 +29,27 @@ const FolderExplorerHeader: React.FC<FolderExplorerHeaderProps> = ({
1829 folderExplorerRef,
1930 titleStyle,
2031} ) => {
32+ 'use memo' ;
33+
2134 const { t } = useTranslation ( ) ;
2235 const { token } = theme . useToken ( ) ;
2336 const { lg } = Grid . useBreakpoint ( ) ;
37+ const { message } = App . useApp ( ) ;
38+
39+ const relayEnv = useRelayEnvironment ( ) ;
40+ const baiClient = useSuspendedBackendaiClient ( ) ;
41+ const { startSession, defaultFormValues, upsertSessionNotification } =
42+ useStartSession ( ) ;
43+ const [ isLoadingToStartFileBrowser , setIsLoadingToStartFileBrowser ] =
44+ useState ( false ) ;
2445
2546 const vfolderNode = useFragment (
2647 graphql `
2748 fragment FolderExplorerHeaderFragment on VirtualFolderNode {
2849 id
2950 user
3051 permission
52+ row_id @required(action: THROW)
3153 unmanaged_path @since(version: "25.04.0")
3254 ...VFolderNameTitleNodeFragment
3355 ...VFolderNodeIdenticonFragment
@@ -105,10 +127,141 @@ const FolderExplorerHeader: React.FC<FolderExplorerHeaderProps> = ({
105127 preview = { false }
106128 />
107129 }
108- onClick = { ( ) =>
109- // @ts -ignore
110- folderExplorerRef . current ?. _executeFileBrowser ( )
111- }
130+ loading = { isLoadingToStartFileBrowser }
131+ onClick = { ( ) => {
132+ // FIXME: Currently, file browser filtering by server-side is not supported.
133+ setIsLoadingToStartFileBrowser ( true ) ;
134+ fetchQuery < FolderExplorerHeader_ImageQuery > (
135+ relayEnv ,
136+ graphql `
137+ query FolderExplorerHeader_ImageQuery(
138+ $installed: Boolean
139+ ) {
140+ images(is_installed: $installed) {
141+ id
142+ name @deprecatedSince(version: "24.12.0")
143+ humanized_name
144+ tag
145+ registry
146+ architecture
147+ digest
148+ installed
149+ resource_limits {
150+ key
151+ min
152+ max
153+ }
154+ labels {
155+ key
156+ value
157+ }
158+ namespace @since(version: "24.12.0")
159+ base_image_name @since(version: "24.12.0")
160+ tags @since(version: "24.12.0") {
161+ key
162+ value
163+ }
164+ version @since(version: "24.12.0")
165+ supported_accelerators
166+ }
167+ }
168+ ` ,
169+ {
170+ installed : true ,
171+ } ,
172+ {
173+ fetchPolicy : 'store-or-network' ,
174+ } ,
175+ )
176+ . toPromise ( )
177+ . then ( ( response ) =>
178+ response ?. images ?. filter ( ( image ) =>
179+ image ?. labels ?. find (
180+ ( label ) =>
181+ label ?. key === 'ai.backend.service-ports' &&
182+ label ?. value ?. toLowerCase ( ) . includes ( 'filebrowser' ) ,
183+ ) ,
184+ ) ,
185+ )
186+ . then ( ( filebrowserImages ) => {
187+ if ( _ . isEmpty ( filebrowserImages ) ) {
188+ message . error (
189+ t ( 'data.explorer.NoImagesSupportingFileBrowser' ) ,
190+ ) ;
191+ setIsLoadingToStartFileBrowser ( false ) ;
192+ return ;
193+ }
194+
195+ const registry = filebrowserImages ?. [ 0 ] ?. registry ;
196+ const namespace = filebrowserImages ?. [ 0 ] ?. namespace ;
197+ const customizedImageTag = _ . find (
198+ filebrowserImages ?. [ 0 ] ?. labels ,
199+ ( item ) =>
200+ item !== null &&
201+ item ?. key === 'ai.backend.customized-image.name' ,
202+ ) ?. value ;
203+ const fileBrowserFormValue : DeepPartial < SessionLauncherFormValue > =
204+ {
205+ sessionName : `filebrowser-${ vfolderNode ?. row_id . split ( '-' ) [ 0 ] } ` ,
206+ sessionType : 'interactive' ,
207+ // use systemSSHImage if configured and allowed
208+ ...( baiClient . _config ?. systemSSHImage &&
209+ baiClient . _config ?. allow_manual_image_name_for_session
210+ ? {
211+ environments : {
212+ environment : baiClient . _config . systemSSHImage ,
213+ } ,
214+ }
215+ : // otherwise use the first image found
216+ {
217+ environments : {
218+ customizedTag :
219+ customizedImageTag || undefined ,
220+ environment : `${ registry } /${ namespace } ` ,
221+ image : filebrowserImages ?. [ 0 ] ,
222+ version : getImageFullName (
223+ filebrowserImages ?. [ 0 ] ,
224+ ) ,
225+ } ,
226+ } ) ,
227+ allocationPreset : 'minimum-required' ,
228+ cluster_mode : 'single-node' ,
229+ cluster_size : 1 ,
230+ mount_ids : [
231+ vfolderNode ?. row_id ?. replaceAll ( '-' , '' ) || '' ,
232+ ] ,
233+ resource : {
234+ cpu : 1 ,
235+ mem : '0.5g' ,
236+ } ,
237+ } ;
238+ const formValuesForSessionLauncher = _ . merge (
239+ { } ,
240+ defaultFormValues ,
241+ fileBrowserFormValue ,
242+ ) as SessionLauncherFormValue ;
243+
244+ startSession ( formValuesForSessionLauncher )
245+ . then ( ( results ) => {
246+ if (
247+ results ?. fulfilled &&
248+ results . fulfilled . length > 0
249+ ) {
250+ upsertSessionNotification ( results . fulfilled ) ;
251+ }
252+ } )
253+ . catch ( ( error ) => {
254+ console . error (
255+ 'Unexpected error during session creation:' ,
256+ error ,
257+ ) ;
258+ message . error ( t ( 'error.UnexpectedError' ) ) ;
259+ } )
260+ . finally ( ( ) => {
261+ setIsLoadingToStartFileBrowser ( false ) ;
262+ } ) ;
263+ } ) ;
264+ } }
112265 >
113266 { lg && t ( 'data.explorer.ExecuteFileBrowser' ) }
114267 </ Button >
0 commit comments