cleanup
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { DEFAULT_FOLDER_NAME } from '../../app/appLayoutUtils';
|
||||
|
||||
type Identifier = string | number;
|
||||
type FolderId = Identifier | 'root';
|
||||
|
||||
interface UseWorkspaceBreadcrumbsArgs {
|
||||
selectedFolder: FolderId | null;
|
||||
folderNodes: Map<FolderId, { id?: FolderId; name?: string | null; parentId?: FolderId | null; parent_id?: FolderId | null }>;
|
||||
currentFolder: { id?: FolderId; name?: string | null; parentId?: FolderId | null; parent_id?: FolderId | null } | null;
|
||||
breadcrumbFetchRef: React.MutableRefObject<Set<FolderId>>;
|
||||
ensureFolderData: (folderId: FolderId, options?: Record<string, unknown>) => Promise<unknown>;
|
||||
}
|
||||
|
||||
const useWorkspaceBreadcrumbs = ({
|
||||
selectedFolder,
|
||||
folderNodes,
|
||||
currentFolder,
|
||||
breadcrumbFetchRef,
|
||||
ensureFolderData,
|
||||
}: UseWorkspaceBreadcrumbsArgs) => {
|
||||
const { breadcrumbs, missingBreadcrumbAncestors } = useMemo(() => {
|
||||
const chain: Array<{ id: FolderId; name?: string | null }> = [];
|
||||
const seen = new Set<FolderId>();
|
||||
const pending = new Set<FolderId>();
|
||||
let currentId: FolderId | null = (selectedFolder || 'root') as FolderId;
|
||||
let guard = 0;
|
||||
|
||||
while (currentId && !seen.has(currentId) && guard < 32) {
|
||||
guard += 1;
|
||||
seen.add(currentId);
|
||||
|
||||
if (currentId === 'root') {
|
||||
chain.push({ id: 'root', name: DEFAULT_FOLDER_NAME });
|
||||
currentId = null;
|
||||
break;
|
||||
}
|
||||
|
||||
const node = folderNodes.get(currentId as FolderId);
|
||||
if (node) {
|
||||
chain.push({ id: currentId, name: node.name || 'Folder' });
|
||||
currentId = (node.parentId ?? node.parent_id ?? 'root') as FolderId;
|
||||
continue;
|
||||
}
|
||||
|
||||
let fallbackName: string | null | undefined = '…';
|
||||
let parentId: FolderId | null | undefined = null;
|
||||
|
||||
if (currentFolder && currentFolder.id === currentId) {
|
||||
fallbackName = currentFolder.name;
|
||||
parentId = (currentFolder.parent_id ?? currentFolder.parentId ?? 'root') as FolderId;
|
||||
}
|
||||
|
||||
chain.push({ id: currentId, name: fallbackName });
|
||||
pending.add(currentId);
|
||||
currentId = parentId as FolderId | null;
|
||||
}
|
||||
|
||||
if (!chain.some((crumb) => crumb.id === 'root')) {
|
||||
chain.push({ id: 'root', name: DEFAULT_FOLDER_NAME });
|
||||
}
|
||||
|
||||
const ordered: Array<{ id: FolderId; name?: string | null }> = [];
|
||||
const seenOrdered = new Set<FolderId>();
|
||||
chain
|
||||
.slice()
|
||||
.reverse()
|
||||
.forEach((crumb) => {
|
||||
if (!seenOrdered.has(crumb.id)) {
|
||||
seenOrdered.add(crumb.id);
|
||||
ordered.push(crumb);
|
||||
}
|
||||
});
|
||||
|
||||
return { breadcrumbs: ordered, missingBreadcrumbAncestors: Array.from(pending) };
|
||||
}, [selectedFolder, folderNodes, currentFolder]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!missingBreadcrumbAncestors.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
missingBreadcrumbAncestors.forEach((folderId) => {
|
||||
if (!folderId || folderId === 'root') {
|
||||
return;
|
||||
}
|
||||
if (breadcrumbFetchRef.current.has(folderId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
breadcrumbFetchRef.current.add(folderId);
|
||||
ensureFolderData(folderId, { force: false })
|
||||
.catch((error) => {
|
||||
console.warn('Failed to preload breadcrumb ancestor', folderId, error);
|
||||
})
|
||||
.finally(() => {
|
||||
breadcrumbFetchRef.current.delete(folderId);
|
||||
});
|
||||
});
|
||||
}, [missingBreadcrumbAncestors, ensureFolderData, breadcrumbFetchRef]);
|
||||
|
||||
return breadcrumbs;
|
||||
};
|
||||
|
||||
export default useWorkspaceBreadcrumbs;
|
||||
Reference in New Issue
Block a user