Enhance uploadFile to support multiple files and update handleMove to process file paths for moving files

This commit is contained in:
2025-07-12 13:59:30 +02:00
parent 1a7c97fb08
commit 51c6f62c44
3 changed files with 88 additions and 22 deletions

View File

@@ -199,20 +199,24 @@ export const moveFile = async (
}; };
/** /**
* uploadFile uploads a file to a workspace * uploadFile uploads multiple files to a workspace
* @param workspaceName - The name of the workspace * @param workspaceName - The name of the workspace
* @param directoryPath - The directory path where the file should be uploaded * @param directoryPath - The directory path where files should be uploaded
* @param file - The file to upload * @param files - Multiple files to upload
* @returns {Promise<SaveFileResponse>} A promise that resolves to the upload file response * @returns {Promise<SaveFileResponse>} A promise that resolves to the upload file response
* @throws {Error} If the API call fails or returns an invalid response * @throws {Error} If the API call fails or returns an invalid response
*/ */
export const uploadFile = async ( export const uploadFile = async (
workspaceName: string, workspaceName: string,
directoryPath: string, directoryPath: string,
file: File files: FileList
): Promise<SaveFileResponse> => { ): Promise<SaveFileResponse> => {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file);
// Add all files to the form data
Array.from(files).forEach((file) => {
formData.append('file', file);
});
const response = await apiCall( const response = await apiCall(
`${API_BASE_URL}/workspaces/${encodeURIComponent( `${API_BASE_URL}/workspaces/${encodeURIComponent(

View File

@@ -103,7 +103,49 @@ function Node({
); );
} }
const FileTree: React.FC<FileTreeProps> = ({ // Utility function to recursively find file paths by IDs
const findFilePathsById = (files: FileNode[], ids: string[]): string[] => {
const paths: string[] = [];
const searchFiles = (nodes: FileNode[]) => {
for (const node of nodes) {
if (ids.includes(node.id)) {
paths.push(node.path);
}
if (node.children) {
searchFiles(node.children);
}
}
};
searchFiles(files);
return paths;
};
// Utility function to find parent path by ID
const findParentPathById = (
files: FileNode[],
parentId: string | null
): string => {
if (!parentId) return '';
const searchFiles = (nodes: FileNode[]): string | null => {
for (const node of nodes) {
if (node.id === parentId) {
return node.path;
}
if (node.children) {
const result = searchFiles(node.children);
if (result) return result;
}
}
return null;
};
return searchFiles(files) || '';
};
export const FileTree: React.FC<FileTreeProps> = ({
files, files,
handleFileSelect, handleFileSelect,
showHiddenFiles, showHiddenFiles,
@@ -143,7 +185,14 @@ const FileTree: React.FC<FileTreeProps> = ({
index: number; index: number;
}) => { }) => {
try { try {
const success = await handleMove(dragIds, parentId, index); // Map dragged file IDs to their corresponding paths
const dragPaths = findFilePathsById(filteredFiles, dragIds);
// Find the parent path where files will be moved
const targetParentPath = findParentPathById(filteredFiles, parentId);
// Move files to the new location
const success = await handleMove(dragPaths, targetParentPath, index);
if (success) { if (success) {
await loadFileList(); await loadFileList();
} }
@@ -151,7 +200,7 @@ const FileTree: React.FC<FileTreeProps> = ({
console.error('Error moving files:', error); console.error('Error moving files:', error);
} }
}, },
[handleMove, loadFileList] [handleMove, loadFileList, filteredFiles]
); );
// External file drag and drop handlers // External file drag and drop handlers
@@ -256,7 +305,6 @@ const FileTree: React.FC<FileTreeProps> = ({
height={size.height} height={size.height}
indent={24} indent={24}
rowHeight={28} rowHeight={28}
// Enable drag and drop for moving files
onMove={handleTreeMove} onMove={handleTreeMove}
onActivate={(node) => { onActivate={(node) => {
const fileNode = node.data; const fileNode = node.data;

View File

@@ -1,6 +1,6 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { notifications } from '@mantine/notifications'; import { notifications } from '@mantine/notifications';
import { saveFile, deleteFile } from '../api/file'; import { saveFile, deleteFile, uploadFile, moveFile } from '../api/file';
import { useWorkspaceData } from '../contexts/WorkspaceDataContext'; import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
import { useGitOperations } from './useGitOperations'; import { useGitOperations } from './useGitOperations';
import { FileAction } from '@/types/models'; import { FileAction } from '@/types/models';
@@ -11,9 +11,9 @@ interface UseFileOperationsResult {
handleCreate: (fileName: string, initialContent?: string) => Promise<boolean>; handleCreate: (fileName: string, initialContent?: string) => Promise<boolean>;
handleUpload: (files: FileList, targetPath?: string) => Promise<boolean>; handleUpload: (files: FileList, targetPath?: string) => Promise<boolean>;
handleMove: ( handleMove: (
dragIds: string[], filePaths: string[],
parentId: string | null, destinationParentPath: string,
index: number index?: number
) => Promise<boolean>; ) => Promise<boolean>;
handleRename: (oldPath: string, newPath: string) => Promise<boolean>; handleRename: (oldPath: string, newPath: string) => Promise<boolean>;
} }
@@ -117,13 +117,13 @@ export const useFileOperations = (): UseFileOperationsResult => {
[currentWorkspace, autoCommit] [currentWorkspace, autoCommit]
); );
// Add these to your hook implementation:
const handleUpload = useCallback( const handleUpload = useCallback(
async (files: FileList, targetPath?: string): Promise<boolean> => { async (files: FileList, targetPath?: string): Promise<boolean> => {
if (!currentWorkspace) return false; if (!currentWorkspace) return false;
try { try {
// TODO: Implement your file upload API call // Use unified upload API that handles both single and multiple files
await uploadFile(currentWorkspace.name, targetPath || '', files);
notifications.show({ notifications.show({
title: 'Success', title: 'Success',
@@ -149,18 +149,32 @@ export const useFileOperations = (): UseFileOperationsResult => {
const handleMove = useCallback( const handleMove = useCallback(
async ( async (
dragIds: string[], filePaths: string[],
parentId: string | null, destinationParentPath: string,
index: number _index?: number
): Promise<boolean> => { ): Promise<boolean> => {
if (!currentWorkspace) return false; if (!currentWorkspace) return false;
try { try {
// TODO: Implement your file move API call // Move each file to the destination directory
const movePromises = filePaths.map(async (filePath) => {
// Extract the filename from the path
const fileName = filePath.split('/').pop() || '';
// Construct the destination path
const destinationPath = destinationParentPath
? `${destinationParentPath}/${fileName}`
: fileName;
// Call the API to move the file
await moveFile(currentWorkspace.name, filePath, destinationPath);
});
await Promise.all(movePromises);
notifications.show({ notifications.show({
title: 'Success', title: 'Success',
message: `Successfully moved ${dragIds.length} file(s)`, message: `Successfully moved ${filePaths.length} file(s)`,
color: 'green', color: 'green',
}); });
@@ -185,8 +199,8 @@ export const useFileOperations = (): UseFileOperationsResult => {
if (!currentWorkspace) return false; if (!currentWorkspace) return false;
try { try {
// TODO: Replace with your actual rename API call // Use moveFile API for renaming (rename is essentially a move operation)
// await renameFile(currentWorkspace.name, oldPath, newPath); await moveFile(currentWorkspace.name, oldPath, newPath);
notifications.show({ notifications.show({
title: 'Success', title: 'Success',