diff --git a/src/components/file-tree/hooks/useFileTreeUpload.ts b/src/components/file-tree/hooks/useFileTreeUpload.ts index 37cd936dcb..ac90f586c9 100644 --- a/src/components/file-tree/hooks/useFileTreeUpload.ts +++ b/src/components/file-tree/hooks/useFileTreeUpload.ts @@ -374,9 +374,17 @@ export const useFileTreeUpload = ({ ], ); + /** + * Upload the picked files into the given target folder. + * + * @param fileList Files chosen via the File Explorer input or drop. + * @param targetPath Project-relative folder to upload into; defaults to '' + * (the project root). Validated server-side via + * validatePathInProject. + */ const handleFileSelect = useCallback( - async (fileList: FileList | File[]) => { - await uploadFiles(Array.from(fileList), ''); + async (fileList: FileList | File[], targetPath = '') => { + await uploadFiles(Array.from(fileList), targetPath); }, [uploadFiles], ); diff --git a/src/components/file-tree/view/FileTree.tsx b/src/components/file-tree/view/FileTree.tsx index bd90c36b33..dba5f95bcf 100644 --- a/src/components/file-tree/view/FileTree.tsx +++ b/src/components/file-tree/view/FileTree.tsx @@ -92,10 +92,20 @@ export default function FileTree({ selectedProject, onFileOpen }: FileTreeProps) return ; }, []); - // Centralized click behavior keeps file actions identical across all presentation modes. + const [selectedUploadDir, setSelectedUploadDir] = useState(''); + + /** + * Centralized click behavior keeps file actions identical across all + * presentation modes. Clicking a directory also marks it as the upload + * target, so subsequent File Explorer uploads land in that folder instead + * of the project root. + * + * @param item The file-tree node that was clicked. + */ const handleItemClick = useCallback( (item: FileTreeNode) => { if (item.type === 'directory') { + setSelectedUploadDir(item.path); toggleDirectory(item.path); return; } @@ -150,7 +160,7 @@ export default function FileTree({ selectedProject, onFileOpen }: FileTreeProps) onViewModeChange={changeViewMode} searchQuery={searchQuery} onSearchQueryChange={setSearchQuery} - onUploadFiles={upload.handleFileSelect} + onUploadFiles={(files) => upload.handleFileSelect(files, selectedUploadDir)} onNewFile={() => operations.handleStartCreate('', 'file')} onNewFolder={() => operations.handleStartCreate('', 'directory')} onRefresh={refreshFiles} @@ -161,6 +171,23 @@ export default function FileTree({ selectedProject, onFileOpen }: FileTreeProps) uploadProgress={upload.uploadProgress?.progress ?? null} /> + {selectedUploadDir && ( +
+ + {t('fileTree.uploadTarget', 'Upload target')}: {selectedUploadDir} + + +
+ )} + {viewMode === 'detailed' && filteredFiles.length > 0 && }