mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 23:44:22 +00:00
Implement file upload functionality in FileActions and FileTree components
This commit is contained in:
@@ -9,17 +9,18 @@ import {
|
|||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useModalContext } from '../../contexts/ModalContext';
|
import { useModalContext } from '../../contexts/ModalContext';
|
||||||
import { useWorkspace } from '../../hooks/useWorkspace';
|
import { useWorkspace } from '../../hooks/useWorkspace';
|
||||||
|
import { useFileOperations } from '../../hooks/useFileOperations';
|
||||||
|
|
||||||
interface FileActionsProps {
|
interface FileActionsProps {
|
||||||
handlePullChanges: () => Promise<boolean>;
|
handlePullChanges: () => Promise<boolean>;
|
||||||
selectedFile: string | null;
|
selectedFile: string | null;
|
||||||
onFileUpload?: (files: FileList) => Promise<void>;
|
loadFileList: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileActions: React.FC<FileActionsProps> = ({
|
const FileActions: React.FC<FileActionsProps> = ({
|
||||||
handlePullChanges,
|
handlePullChanges,
|
||||||
selectedFile,
|
selectedFile,
|
||||||
onFileUpload,
|
loadFileList,
|
||||||
}) => {
|
}) => {
|
||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const {
|
const {
|
||||||
@@ -28,6 +29,8 @@ const FileActions: React.FC<FileActionsProps> = ({
|
|||||||
setCommitMessageModalVisible,
|
setCommitMessageModalVisible,
|
||||||
} = useModalContext();
|
} = useModalContext();
|
||||||
|
|
||||||
|
const { handleUpload } = useFileOperations();
|
||||||
|
|
||||||
// Hidden file input for upload
|
// Hidden file input for upload
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
@@ -43,10 +46,20 @@ const FileActions: React.FC<FileActionsProps> = ({
|
|||||||
event: React.ChangeEvent<HTMLInputElement>
|
event: React.ChangeEvent<HTMLInputElement>
|
||||||
): void => {
|
): void => {
|
||||||
const files = event.target.files;
|
const files = event.target.files;
|
||||||
if (files && files.length > 0 && onFileUpload) {
|
if (files && files.length > 0) {
|
||||||
onFileUpload(files).catch((error) => {
|
const uploadFiles = async () => {
|
||||||
console.error('Error uploading files:', error);
|
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
|
// Reset the input so the same file can be selected again
|
||||||
event.target.value = '';
|
event.target.value = '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { Tooltip, Text, Box } from '@mantine/core';
|
import { Tooltip, Text, Box } from '@mantine/core';
|
||||||
import useResizeObserver from '@react-hook/resize-observer';
|
import useResizeObserver from '@react-hook/resize-observer';
|
||||||
|
import { useFileOperations } from '../../hooks/useFileOperations';
|
||||||
import type { FileNode } from '@/types/models';
|
import type { FileNode } from '@/types/models';
|
||||||
|
|
||||||
interface Size {
|
interface Size {
|
||||||
@@ -19,12 +20,7 @@ interface FileTreeProps {
|
|||||||
files: FileNode[];
|
files: FileNode[];
|
||||||
handleFileSelect: (filePath: string | null) => Promise<void>;
|
handleFileSelect: (filePath: string | null) => Promise<void>;
|
||||||
showHiddenFiles: boolean;
|
showHiddenFiles: boolean;
|
||||||
onFileMove?: (
|
loadFileList: () => Promise<void>;
|
||||||
dragIds: string[],
|
|
||||||
parentId: string | null,
|
|
||||||
index: number
|
|
||||||
) => Promise<void>;
|
|
||||||
onFileUpload?: (files: FileList, targetPath?: string) => Promise<void>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const useSize = (target: React.RefObject<HTMLElement>): Size | undefined => {
|
const useSize = (target: React.RefObject<HTMLElement>): Size | undefined => {
|
||||||
@@ -111,11 +107,11 @@ const FileTree: React.FC<FileTreeProps> = ({
|
|||||||
files,
|
files,
|
||||||
handleFileSelect,
|
handleFileSelect,
|
||||||
showHiddenFiles,
|
showHiddenFiles,
|
||||||
onFileMove,
|
loadFileList,
|
||||||
onFileUpload,
|
|
||||||
}) => {
|
}) => {
|
||||||
const target = useRef<HTMLDivElement>(null);
|
const target = useRef<HTMLDivElement>(null);
|
||||||
const size = useSize(target);
|
const size = useSize(target);
|
||||||
|
const { handleMove, handleUpload } = useFileOperations();
|
||||||
|
|
||||||
// State for drag and drop overlay
|
// State for drag and drop overlay
|
||||||
const [isDragOver, setIsDragOver] = useState(false);
|
const [isDragOver, setIsDragOver] = useState(false);
|
||||||
@@ -136,7 +132,7 @@ const FileTree: React.FC<FileTreeProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handle file movement within the tree
|
// Handle file movement within the tree
|
||||||
const handleMove = useCallback(
|
const handleTreeMove = useCallback(
|
||||||
async ({
|
async ({
|
||||||
dragIds,
|
dragIds,
|
||||||
parentId,
|
parentId,
|
||||||
@@ -146,11 +142,16 @@ const FileTree: React.FC<FileTreeProps> = ({
|
|||||||
parentId: string | null;
|
parentId: string | null;
|
||||||
index: number;
|
index: number;
|
||||||
}) => {
|
}) => {
|
||||||
if (onFileMove) {
|
try {
|
||||||
await onFileMove(dragIds, parentId, index);
|
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
|
// External file drag and drop handlers
|
||||||
@@ -189,14 +190,22 @@ const FileTree: React.FC<FileTreeProps> = ({
|
|||||||
setIsDragOver(false);
|
setIsDragOver(false);
|
||||||
|
|
||||||
const { files } = e.dataTransfer;
|
const { files } = e.dataTransfer;
|
||||||
if (files && files.length > 0 && onFileUpload) {
|
if (files && files.length > 0) {
|
||||||
// Handle the upload without awaiting to avoid the eslint warning
|
const uploadFiles = async () => {
|
||||||
onFileUpload(files).catch((error) => {
|
try {
|
||||||
console.error('Error uploading files:', error);
|
const success = await handleUpload(files);
|
||||||
});
|
if (success) {
|
||||||
|
await loadFileList();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error uploading files:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void uploadFiles();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onFileUpload]
|
[handleUpload, loadFileList]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -247,7 +256,8 @@ const FileTree: React.FC<FileTreeProps> = ({
|
|||||||
height={size.height}
|
height={size.height}
|
||||||
indent={24}
|
indent={24}
|
||||||
rowHeight={28}
|
rowHeight={28}
|
||||||
onMove={handleMove}
|
// Enable drag and drop for moving files
|
||||||
|
onMove={handleTreeMove}
|
||||||
onActivate={(node) => {
|
onActivate={(node) => {
|
||||||
const fileNode = node.data;
|
const fileNode = node.data;
|
||||||
if (!node.isInternal) {
|
if (!node.isInternal) {
|
||||||
|
|||||||
@@ -37,11 +37,16 @@ const Sidebar: React.FC<SidebarProps> = ({
|
|||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FileActions handlePullChanges={handlePull} selectedFile={selectedFile} />
|
<FileActions
|
||||||
|
handlePullChanges={handlePull}
|
||||||
|
selectedFile={selectedFile}
|
||||||
|
loadFileList={loadFileList}
|
||||||
|
/>
|
||||||
<FileTree
|
<FileTree
|
||||||
files={files}
|
files={files}
|
||||||
handleFileSelect={handleFileSelect}
|
handleFileSelect={handleFileSelect}
|
||||||
showHiddenFiles={currentWorkspace?.showHiddenFiles || false}
|
showHiddenFiles={currentWorkspace?.showHiddenFiles || false}
|
||||||
|
loadFileList={loadFileList}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ interface UseFileOperationsResult {
|
|||||||
handleSave: (filePath: string, content: string) => Promise<boolean>;
|
handleSave: (filePath: string, content: string) => Promise<boolean>;
|
||||||
handleDelete: (filePath: string) => Promise<boolean>;
|
handleDelete: (filePath: string) => Promise<boolean>;
|
||||||
handleCreate: (fileName: string, initialContent?: string) => Promise<boolean>;
|
handleCreate: (fileName: string, initialContent?: string) => Promise<boolean>;
|
||||||
|
handleUpload: (files: FileList, targetPath?: string) => Promise<boolean>;
|
||||||
|
handleMove: (
|
||||||
|
dragIds: string[],
|
||||||
|
parentId: string | null,
|
||||||
|
index: number
|
||||||
|
) => Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useFileOperations = (): UseFileOperationsResult => {
|
export const useFileOperations = (): UseFileOperationsResult => {
|
||||||
@@ -109,5 +115,83 @@ export const useFileOperations = (): UseFileOperationsResult => {
|
|||||||
[currentWorkspace, autoCommit]
|
[currentWorkspace, autoCommit]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { handleSave, handleDelete, handleCreate };
|
// Add these to your hook implementation:
|
||||||
|
const handleUpload = useCallback(
|
||||||
|
async (files: FileList, targetPath?: string): Promise<boolean> => {
|
||||||
|
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<boolean> => {
|
||||||
|
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 };
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user