@@ -689,7 +689,7 @@ export function Files() {
689689 )
690690
691691 async function uploadFiles ( filesToUpload : File [ ] , targetFolderId = currentFolderId ) {
692- if ( ! workspaceId || filesToUpload . length === 0 ) return
692+ if ( ! workspaceId || filesToUpload . length === 0 || ! canEdit ) return
693693
694694 const oversized : string [ ] = [ ]
695695 const sizeFiltered = filesToUpload . filter ( ( f ) => {
@@ -904,14 +904,19 @@ export function Files() {
904904 } , [ selectedFileIds , selectedFolderIds , currentFolderId ] )
905905
906906 const handleMoveSelected = useCallback ( async ( ) => {
907- await moveItems . mutateAsync ( {
908- workspaceId,
909- fileIds : selectedFileIds ,
910- folderIds : selectedFolderIds ,
911- targetFolderId : moveTargetFolderId ,
912- } )
913- setSelectedRowIds ( new Set ( ) )
914- setShowMoveModal ( false )
907+ try {
908+ await moveItems . mutateAsync ( {
909+ workspaceId,
910+ fileIds : selectedFileIds ,
911+ folderIds : selectedFolderIds ,
912+ targetFolderId : moveTargetFolderId ,
913+ } )
914+ setSelectedRowIds ( new Set ( ) )
915+ setShowMoveModal ( false )
916+ } catch ( error ) {
917+ logger . error ( 'Failed to move selected items:' , error )
918+ toast . error ( error instanceof Error ? error . message : 'Failed to move selected items' )
919+ }
915920 } , [ workspaceId , selectedFileIds , selectedFolderIds , moveTargetFolderId , moveItems ] )
916921
917922 const fileDetailBreadcrumbs = useMemo (
@@ -1075,10 +1080,21 @@ export function Files() {
10751080
10761081 const handleContextMenuDownload = useCallback ( ( ) => {
10771082 const item = contextMenuItemRef . current
1078- if ( ! item || item . kind !== 'file' ) return
1083+ if ( ! item ) return
1084+ const rowId = item . kind === 'file' ? fileRowId ( item . file . id ) : folderRowId ( item . folder . id )
1085+ if ( selectedRowIds . has ( rowId ) && selectedRowIds . size > 1 ) {
1086+ handleBulkDownload ( )
1087+ closeContextMenu ( )
1088+ return
1089+ }
1090+ if ( item . kind === 'folder' ) {
1091+ window . location . href = `/api/workspaces/${ workspaceId } /files/download?folderIds=${ encodeURIComponent ( item . folder . id ) } `
1092+ closeContextMenu ( )
1093+ return
1094+ }
10791095 handleDownload ( item . file )
10801096 closeContextMenu ( )
1081- } , [ handleDownload , closeContextMenu ] )
1097+ } , [ selectedRowIds , handleBulkDownload , closeContextMenu , workspaceId , handleDownload ] )
10821098
10831099 const handleContextMenuRename = useCallback ( ( ) => {
10841100 const item = contextMenuItemRef . current
@@ -1091,14 +1107,20 @@ export function Files() {
10911107 const handleContextMenuDelete = useCallback ( ( ) => {
10921108 const item = contextMenuItemRef . current
10931109 if ( ! item ) return
1110+ const rowId = item . kind === 'file' ? fileRowId ( item . file . id ) : folderRowId ( item . folder . id )
1111+ if ( selectedRowIds . has ( rowId ) && selectedRowIds . size > 1 ) {
1112+ handleBulkDelete ( )
1113+ closeContextMenu ( )
1114+ return
1115+ }
10941116 setDeleteTarget (
10951117 item . kind === 'file'
10961118 ? { fileIds : [ item . file . id ] , folderIds : [ ] , name : item . file . name }
10971119 : { fileIds : [ ] , folderIds : [ item . folder . id ] , name : item . folder . name , isFolder : true }
10981120 )
10991121 setShowDeleteConfirm ( true )
11001122 closeContextMenu ( )
1101- } , [ closeContextMenu ] )
1123+ } , [ selectedRowIds , handleBulkDelete , closeContextMenu ] )
11021124
11031125 const handleContentContextMenu = useCallback (
11041126 ( e : React . MouseEvent ) => {
@@ -1115,9 +1137,10 @@ export function Files() {
11151137 )
11161138
11171139 const handleListUploadFile = useCallback ( ( ) => {
1140+ if ( ! canEdit || uploading ) return
11181141 fileInputRef . current ?. click ( )
11191142 closeListContextMenu ( )
1120- } , [ closeListContextMenu ] )
1143+ } , [ canEdit , uploading , closeListContextMenu ] )
11211144
11221145 const prevFileIdRef = useRef ( fileIdFromRoute )
11231146 if ( fileIdFromRoute !== prevFileIdRef . current ) {
@@ -1279,8 +1302,9 @@ export function Files() {
12791302 )
12801303
12811304 const handleUploadClick = useCallback ( ( ) => {
1305+ if ( ! canEdit || uploading ) return
12821306 fileInputRef . current ?. click ( )
1283- } , [ ] )
1307+ } , [ canEdit , uploading ] )
12841308
12851309 const searchConfig : SearchConfig = {
12861310 value : inputValue ,
@@ -1310,6 +1334,7 @@ export function Files() {
13101334 label : uploadButtonLabel ,
13111335 icon : Upload ,
13121336 onClick : handleUploadClick ,
1337+ disabled : uploading || ! canEdit ,
13131338 } ,
13141339 {
13151340 label : 'New folder' ,
@@ -1372,14 +1397,20 @@ export function Files() {
13721397 ( ) => [
13731398 { value : '__root__' , label : 'Files' } ,
13741399 ...folders
1375- . filter ( ( folder ) => ! selectedFolderIds . includes ( folder . id ) )
1400+ . filter ( ( folder ) => {
1401+ if ( selectedFolderIds . includes ( folder . id ) ) return false
1402+ return selectedFolderIds . every (
1403+ ( selectedFolderId ) =>
1404+ ! descendantFolderIdsByFolderId . get ( selectedFolderId ) ?. has ( folder . id )
1405+ )
1406+ } )
13761407 . map ( ( folder ) => ( {
13771408 value : folder . id ,
13781409 label : folder . path ,
13791410 icon : Folder ,
13801411 } ) ) ,
13811412 ] ,
1382- [ folders , selectedFolderIds ]
1413+ [ folders , selectedFolderIds , descendantFolderIdsByFolderId ]
13831414 )
13841415
13851416 const sortConfig : SortConfig = useMemo (
@@ -1734,7 +1765,7 @@ export function Files() {
17341765 type = 'file'
17351766 className = 'hidden'
17361767 onChange = { handleFileChange }
1737- disabled = { uploading }
1768+ disabled = { uploading || ! canEdit }
17381769 accept = { ACCEPT_ATTR }
17391770 multiple
17401771 />
0 commit comments