From 2d99591bdd3730b34127216b5db9b37dc75f8309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralf=20H=C3=BCller?= Date: Sat, 13 Jun 2026 14:15:56 +0200 Subject: [PATCH 1/2] feat(file-tree): upload to selected folder instead of project root Clicking a directory in the file tree now sets it as the upload target, so File Explorer uploads land in that folder instead of always going to the project root. An "Upload target" indicator shows the active folder and offers a clear (X) button to reset the target back to the project root. The server already accepts and validates a targetPath (validatePathInProject); this wires the frontend to pass the last-clicked directory through handleFileSelect, defaulting to '' (root). --- .../file-tree/hooks/useFileTreeUpload.ts | 4 ++-- src/components/file-tree/view/FileTree.tsx | 22 ++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/components/file-tree/hooks/useFileTreeUpload.ts b/src/components/file-tree/hooks/useFileTreeUpload.ts index 37cd936dcb..cd615b09c0 100644 --- a/src/components/file-tree/hooks/useFileTreeUpload.ts +++ b/src/components/file-tree/hooks/useFileTreeUpload.ts @@ -375,8 +375,8 @@ export const useFileTreeUpload = ({ ); 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..2f3dcafb09 100644 --- a/src/components/file-tree/view/FileTree.tsx +++ b/src/components/file-tree/view/FileTree.tsx @@ -92,10 +92,13 @@ export default function FileTree({ selectedProject, onFileOpen }: FileTreeProps) return ; }, []); + const [selectedUploadDir, setSelectedUploadDir] = useState(''); + // Centralized click behavior keeps file actions identical across all presentation modes. const handleItemClick = useCallback( (item: FileTreeNode) => { if (item.type === 'directory') { + setSelectedUploadDir(item.path); toggleDirectory(item.path); return; } @@ -150,7 +153,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 +164,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 && } From 4888ee202d115a09dcae1392954a88e3ba0d850b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralf=20H=C3=BCller?= Date: Mon, 15 Jun 2026 09:29:40 +0200 Subject: [PATCH 2/2] docs(file-tree): add JSDoc for upload-target handlers Document handleFileSelect's targetPath parameter and handleItemClick's upload-target side effect to satisfy the docstring-coverage pre-merge check. --- src/components/file-tree/hooks/useFileTreeUpload.ts | 8 ++++++++ src/components/file-tree/view/FileTree.tsx | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/components/file-tree/hooks/useFileTreeUpload.ts b/src/components/file-tree/hooks/useFileTreeUpload.ts index cd615b09c0..ac90f586c9 100644 --- a/src/components/file-tree/hooks/useFileTreeUpload.ts +++ b/src/components/file-tree/hooks/useFileTreeUpload.ts @@ -374,6 +374,14 @@ 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[], targetPath = '') => { await uploadFiles(Array.from(fileList), targetPath); diff --git a/src/components/file-tree/view/FileTree.tsx b/src/components/file-tree/view/FileTree.tsx index 2f3dcafb09..dba5f95bcf 100644 --- a/src/components/file-tree/view/FileTree.tsx +++ b/src/components/file-tree/view/FileTree.tsx @@ -94,7 +94,14 @@ export default function FileTree({ selectedProject, onFileOpen }: FileTreeProps) const [selectedUploadDir, setSelectedUploadDir] = useState(''); - // Centralized click behavior keeps file actions identical across all presentation modes. + /** + * 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') {