feat: refine frontend folder management and display by merging folder tree data.
This commit is contained in:
@@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import type { DragEvent } from 'react';
|
||||
import { useStatusToast } from '../../../lib/context/StatusToastContext';
|
||||
import { DEFAULT_FOLDER_NAME, hasFiles } from '../../../app/workspaceUtils';
|
||||
import { hasFiles } from '../../../app/workspaceUtils';
|
||||
import {
|
||||
createFolder,
|
||||
deleteFolder,
|
||||
@@ -35,11 +35,12 @@ import useNotifyApiError from '../../../hooks/useNotifyApiError';
|
||||
import type {
|
||||
FolderState,
|
||||
DragState,
|
||||
FolderNode,
|
||||
} from '../../types/workspaceTypes';
|
||||
|
||||
import type FoldersManager from '../../FoldersManager';
|
||||
|
||||
interface UseFolderTreeActionsOptions {
|
||||
folderState: Pick<FolderState, 'folderNodes' | 'setFolderNodes' | 'selectedFolder' | 'setSelectedFolder' | 'setCreatingFolder'>;
|
||||
folderState: Pick<FolderState, 'folderNodes' | 'selectedFolder' | 'setSelectedFolder' | 'setCreatingFolder'> & { foldersManager?: FoldersManager };
|
||||
dragState: DragState;
|
||||
actions: {
|
||||
handleFileDrop: (dataTransfer: DataTransfer, folderId: FolderKey) => Promise<void> | void;
|
||||
@@ -58,10 +59,10 @@ const useFolderTreeActions = ({
|
||||
}: UseFolderTreeActionsOptions) => {
|
||||
const {
|
||||
folderNodes,
|
||||
setFolderNodes,
|
||||
selectedFolder,
|
||||
setSelectedFolder,
|
||||
setCreatingFolder,
|
||||
foldersManager,
|
||||
} = folderState;
|
||||
|
||||
const {
|
||||
@@ -101,50 +102,9 @@ const useFolderTreeActions = ({
|
||||
try {
|
||||
await moveFolderRequest(folderId, parent_id);
|
||||
|
||||
setFolderNodes((prev: Map<FolderKey, FolderNode>) => {
|
||||
const next = new Map(prev);
|
||||
const currentNode = next.get(folderId);
|
||||
if (!currentNode) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
next.set(folderId, { ...currentNode, parentId: parent_id ?? null });
|
||||
|
||||
const previousParent = next.get(previousParentKey);
|
||||
if (previousParent) {
|
||||
const remainingChildren = (previousParent.children || []).filter(
|
||||
(childId) => childId !== folderId,
|
||||
);
|
||||
next.set(previousParentKey, {
|
||||
...previousParent,
|
||||
children: remainingChildren,
|
||||
hasChildren: remainingChildren.length > 0,
|
||||
});
|
||||
}
|
||||
|
||||
if (!next.has(targetKey)) {
|
||||
next.set(targetKey, {
|
||||
id: targetKey,
|
||||
name: targetKey === 'root' ? DEFAULT_FOLDER_NAME : 'Folder',
|
||||
parentId: targetKey === 'root' ? null : null,
|
||||
children: [],
|
||||
expanded: targetKey === 'root',
|
||||
loaded: false,
|
||||
hasChildren: false,
|
||||
});
|
||||
}
|
||||
|
||||
const targetNode = next.get(targetKey);
|
||||
if (targetNode && !targetNode.children.includes(folderId)) {
|
||||
next.set(targetKey, {
|
||||
...targetNode,
|
||||
children: [...targetNode.children, folderId],
|
||||
hasChildren: true,
|
||||
});
|
||||
}
|
||||
|
||||
return next;
|
||||
});
|
||||
if (foldersManager) {
|
||||
foldersManager.invalidateTree();
|
||||
}
|
||||
|
||||
if (selectedFolder === folderId) {
|
||||
setSelectedFolder(folderId);
|
||||
@@ -160,7 +120,7 @@ const useFolderTreeActions = ({
|
||||
folderNodes,
|
||||
notifyApiError,
|
||||
selectedFolder,
|
||||
setFolderNodes,
|
||||
foldersManager,
|
||||
setSelectedFolder,
|
||||
showToast,
|
||||
],
|
||||
@@ -202,14 +162,9 @@ const useFolderTreeActions = ({
|
||||
try {
|
||||
await renameFolderRequest(folderId, trimmed);
|
||||
|
||||
setFolderNodes((prev: Map<FolderKey, FolderNode>) => {
|
||||
const next = new Map(prev);
|
||||
const node = next.get(folderId);
|
||||
if (node) {
|
||||
next.set(folderId, { ...node, name: trimmed });
|
||||
}
|
||||
return next;
|
||||
});
|
||||
if (foldersManager) {
|
||||
foldersManager.ingest([{ id: folderId, name: trimmed }]);
|
||||
}
|
||||
|
||||
showToast('Folder renamed.', 'success');
|
||||
return true;
|
||||
@@ -221,7 +176,7 @@ const useFolderTreeActions = ({
|
||||
},
|
||||
[
|
||||
notifyApiError,
|
||||
setFolderNodes,
|
||||
foldersManager,
|
||||
showToast,
|
||||
],
|
||||
);
|
||||
@@ -250,29 +205,13 @@ const useFolderTreeActions = ({
|
||||
throw new Error('Folder creation failed.');
|
||||
}
|
||||
showToast('Folder created.', 'success');
|
||||
setFolderNodes((prev: Map<FolderKey, FolderNode>) => {
|
||||
const next = new Map(prev);
|
||||
const parentId = folderData.parent_id ?? payload.parent_id ?? 'root';
|
||||
const parentNode = next.get(parentId);
|
||||
if (parentNode) {
|
||||
next.set(parentId, {
|
||||
...parentNode,
|
||||
children: parentNode.children.concat([folderData.id]),
|
||||
loaded: true,
|
||||
hasChildren: true,
|
||||
});
|
||||
}
|
||||
next.set(folderData.id, {
|
||||
id: folderData.id,
|
||||
name: folderData.name ?? payload.name,
|
||||
parentId: parentId,
|
||||
children: folderData.children || [],
|
||||
expanded: false,
|
||||
loaded: false,
|
||||
hasChildren: Array.isArray(folderData.children) ? folderData.children.length > 0 : false,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
|
||||
if (foldersManager) {
|
||||
// Ingest the new folder data immediately so it's available
|
||||
foldersManager.ingest([folderData]);
|
||||
// Force tree refresh to update structure
|
||||
foldersManager.invalidateTree();
|
||||
}
|
||||
|
||||
await selectFolder(folderData.id, { immediate: true });
|
||||
succeeded = true;
|
||||
@@ -293,7 +232,7 @@ const useFolderTreeActions = ({
|
||||
selectFolder,
|
||||
selectedFolder,
|
||||
setCreatingFolder,
|
||||
setFolderNodes,
|
||||
foldersManager,
|
||||
showToast,
|
||||
],
|
||||
);
|
||||
@@ -310,26 +249,13 @@ const useFolderTreeActions = ({
|
||||
try {
|
||||
await deleteFolder(folderId);
|
||||
|
||||
setFolderNodes((prev: Map<FolderKey, FolderNode>) => {
|
||||
const next = new Map(prev);
|
||||
const node = next.get(folderId);
|
||||
next.delete(folderId);
|
||||
if (node) {
|
||||
const parentId = node.parentId || 'root';
|
||||
const parentNode = next.get(parentId);
|
||||
if (parentNode) {
|
||||
const remaining = parentNode.children.filter((id) => id !== folderId);
|
||||
next.set(parentId, {
|
||||
...parentNode,
|
||||
children: remaining,
|
||||
hasChildren: remaining.length > 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
return next;
|
||||
});
|
||||
if (foldersManager) {
|
||||
foldersManager.remove([folderId]);
|
||||
foldersManager.invalidateTree();
|
||||
}
|
||||
|
||||
if (selectedFolder === folderId) {
|
||||
// Fallback selection logic
|
||||
const node = folderNodes.get(folderId);
|
||||
const parentId = node?.parentId || 'root';
|
||||
setSelectedFolder(parentId);
|
||||
@@ -352,7 +278,7 @@ const useFolderTreeActions = ({
|
||||
folderNodes,
|
||||
notifyApiError,
|
||||
selectedFolder,
|
||||
setFolderNodes,
|
||||
foldersManager,
|
||||
setSelectedFolder,
|
||||
showToast,
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user