diff --git a/app/src/components/files/FileActions.tsx b/app/src/components/files/FileActions.tsx index 8ef048e..83bf7ae 100644 --- a/app/src/components/files/FileActions.tsx +++ b/app/src/components/files/FileActions.tsx @@ -9,17 +9,18 @@ import { } from '@tabler/icons-react'; import { useModalContext } from '../../contexts/ModalContext'; import { useWorkspace } from '../../hooks/useWorkspace'; +import { useFileOperations } from '../../hooks/useFileOperations'; interface FileActionsProps { handlePullChanges: () => Promise; selectedFile: string | null; - onFileUpload?: (files: FileList) => Promise; + loadFileList: () => Promise; } const FileActions: React.FC = ({ handlePullChanges, selectedFile, - onFileUpload, + loadFileList, }) => { const { currentWorkspace } = useWorkspace(); const { @@ -28,6 +29,8 @@ const FileActions: React.FC = ({ setCommitMessageModalVisible, } = useModalContext(); + const { handleUpload } = useFileOperations(); + // Hidden file input for upload const fileInputRef = useRef(null); @@ -43,10 +46,20 @@ const FileActions: React.FC = ({ event: React.ChangeEvent ): void => { const files = event.target.files; - if (files && files.length > 0 && onFileUpload) { - onFileUpload(files).catch((error) => { - console.error('Error uploading files:', error); - }); + if (files && files.length > 0) { + const uploadFiles = async () => { + try { + const success = await handleUpload(files); + if (success) { + await loadFileList(); + } + } catch (error) { + console.error('Error uploading files:', error); + } + }; + + void uploadFiles(); + // Reset the input so the same file can be selected again event.target.value = ''; } diff --git a/app/src/components/files/FileTree.tsx b/app/src/components/files/FileTree.tsx index cc69954..67f0c9e 100644 --- a/app/src/components/files/FileTree.tsx +++ b/app/src/components/files/FileTree.tsx @@ -8,6 +8,7 @@ import { } from '@tabler/icons-react'; import { Tooltip, Text, Box } from '@mantine/core'; import useResizeObserver from '@react-hook/resize-observer'; +import { useFileOperations } from '../../hooks/useFileOperations'; import type { FileNode } from '@/types/models'; interface Size { @@ -19,12 +20,7 @@ interface FileTreeProps { files: FileNode[]; handleFileSelect: (filePath: string | null) => Promise; showHiddenFiles: boolean; - onFileMove?: ( - dragIds: string[], - parentId: string | null, - index: number - ) => Promise; - onFileUpload?: (files: FileList, targetPath?: string) => Promise; + loadFileList: () => Promise; } const useSize = (target: React.RefObject): Size | undefined => { @@ -111,11 +107,11 @@ const FileTree: React.FC = ({ files, handleFileSelect, showHiddenFiles, - onFileMove, - onFileUpload, + loadFileList, }) => { const target = useRef(null); const size = useSize(target); + const { handleMove, handleUpload } = useFileOperations(); // State for drag and drop overlay const [isDragOver, setIsDragOver] = useState(false); @@ -136,7 +132,7 @@ const FileTree: React.FC = ({ }; // Handle file movement within the tree - const handleMove = useCallback( + const handleTreeMove = useCallback( async ({ dragIds, parentId, @@ -146,11 +142,16 @@ const FileTree: React.FC = ({ parentId: string | null; index: number; }) => { - if (onFileMove) { - await onFileMove(dragIds, parentId, index); + try { + const success = await handleMove(dragIds, parentId, index); + if (success) { + await loadFileList(); + } + } catch (error) { + console.error('Error moving files:', error); } }, - [onFileMove] + [handleMove, loadFileList] ); // External file drag and drop handlers @@ -189,14 +190,22 @@ const FileTree: React.FC = ({ setIsDragOver(false); const { files } = e.dataTransfer; - if (files && files.length > 0 && onFileUpload) { - // Handle the upload without awaiting to avoid the eslint warning - onFileUpload(files).catch((error) => { - console.error('Error uploading files:', error); - }); + if (files && files.length > 0) { + const uploadFiles = async () => { + try { + const success = await handleUpload(files); + if (success) { + await loadFileList(); + } + } catch (error) { + console.error('Error uploading files:', error); + } + }; + + void uploadFiles(); } }, - [onFileUpload] + [handleUpload, loadFileList] ); return ( @@ -247,7 +256,8 @@ const FileTree: React.FC = ({ height={size.height} indent={24} rowHeight={28} - onMove={handleMove} + // Enable drag and drop for moving files + onMove={handleTreeMove} onActivate={(node) => { const fileNode = node.data; if (!node.isInternal) { diff --git a/app/src/components/layout/Sidebar.tsx b/app/src/components/layout/Sidebar.tsx index 135dbf0..f108838 100644 --- a/app/src/components/layout/Sidebar.tsx +++ b/app/src/components/layout/Sidebar.tsx @@ -37,11 +37,16 @@ const Sidebar: React.FC = ({ overflow: 'hidden', }} > - + ); diff --git a/app/src/hooks/useFileOperations.ts b/app/src/hooks/useFileOperations.ts index f34e32c..64fc7d7 100644 --- a/app/src/hooks/useFileOperations.ts +++ b/app/src/hooks/useFileOperations.ts @@ -9,6 +9,12 @@ interface UseFileOperationsResult { handleSave: (filePath: string, content: string) => Promise; handleDelete: (filePath: string) => Promise; handleCreate: (fileName: string, initialContent?: string) => Promise; + handleUpload: (files: FileList, targetPath?: string) => Promise; + handleMove: ( + dragIds: string[], + parentId: string | null, + index: number + ) => Promise; } export const useFileOperations = (): UseFileOperationsResult => { @@ -109,5 +115,83 @@ export const useFileOperations = (): UseFileOperationsResult => { [currentWorkspace, autoCommit] ); - return { handleSave, handleDelete, handleCreate }; + // Add these to your hook implementation: + const handleUpload = useCallback( + async (files: FileList, targetPath?: string): Promise => { + if (!currentWorkspace) return false; + + try { + // TODO: Implement your file upload API call + // Example: + // const formData = new FormData(); + // Array.from(files).forEach((file, index) => { + // formData.append(`file${index}`, file); + // }); + // if (targetPath) { + // formData.append('targetPath', targetPath); + // } + // await uploadFiles(currentWorkspace.name, formData); + + notifications.show({ + title: 'Success', + message: `Successfully uploaded ${files.length} file(s)`, + color: 'green', + }); + + // Auto-commit if enabled + await autoCommit('multiple files', FileAction.Create); + return true; + } catch (error) { + console.error('Error uploading files:', error); + notifications.show({ + title: 'Error', + message: 'Failed to upload files', + color: 'red', + }); + return false; + } + }, + [currentWorkspace, autoCommit] + ); + + const handleMove = useCallback( + async ( + dragIds: string[], + parentId: string | null, + index: number + ): Promise => { + if (!currentWorkspace) return false; + + try { + // TODO: Implement your file move API call + // Example: + // await moveFiles(currentWorkspace.name, { + // sourceIds: dragIds, + // targetParentId: parentId, + // targetIndex: index + // }); + + notifications.show({ + title: 'Success', + message: `Successfully moved ${dragIds.length} file(s)`, + color: 'green', + }); + + // Auto-commit if enabled + await autoCommit('multiple files', FileAction.Update); + return true; + } catch (error) { + console.error('Error moving files:', error); + notifications.show({ + title: 'Error', + message: 'Failed to move files', + color: 'red', + }); + return false; + } + }, + [currentWorkspace, autoCommit] + ); + + return { handleSave, handleDelete, handleCreate, handleUpload, handleMove }; };