feat: Rework sidebar with dedicated components for menu, folders, tags, correspondents, and search, including tenant switching and theme controls.
This commit is contained in:
@@ -350,6 +350,7 @@ const useDocumentsWorkspace = ({
|
||||
searchResultIds,
|
||||
setSearchResultIds,
|
||||
searchLoading,
|
||||
activeTagFilters,
|
||||
setActiveTagFilters,
|
||||
activeCorrespondentFilters,
|
||||
setActiveCorrespondentFilters,
|
||||
@@ -966,7 +967,7 @@ const useDocumentsWorkspace = ({
|
||||
|
||||
|
||||
|
||||
const handlePromptCreateFolder = useCallback(async () => {
|
||||
const handlePromptCreateFolder = useCallback(async (parentId?: Identifier | null) => {
|
||||
if (creatingFolder) {
|
||||
return;
|
||||
}
|
||||
@@ -981,7 +982,7 @@ const useDocumentsWorkspace = ({
|
||||
}
|
||||
setCreatingFolder(true);
|
||||
try {
|
||||
const success = await handleFolderCreate(trimmed);
|
||||
const success = await handleFolderCreate(trimmed, parentId);
|
||||
if (!success) {
|
||||
setStatusMessage('Unable to create folder. Check the status message for details.', 'error');
|
||||
}
|
||||
@@ -1198,8 +1199,10 @@ const useDocumentsWorkspace = ({
|
||||
refreshCurrentFolder,
|
||||
currentSubfolders,
|
||||
documents: viewDocuments,
|
||||
searchQuery,
|
||||
searchResultIds,
|
||||
folderClickHandlers,
|
||||
selectedFolder,
|
||||
handleFolderDragStart,
|
||||
handleFolderDragEnd,
|
||||
draggedFolderId,
|
||||
@@ -1211,6 +1214,7 @@ const useDocumentsWorkspace = ({
|
||||
handleDocumentDragEnd,
|
||||
searchLoading,
|
||||
tagLookupById,
|
||||
activeTagFilters,
|
||||
activeCorrespondentFilters,
|
||||
ensureAssetUrl,
|
||||
getDocumentAsset,
|
||||
|
||||
@@ -170,7 +170,8 @@ const useFolderTree = ({
|
||||
],
|
||||
);
|
||||
|
||||
const expandFolderAncestors = useCallback((targetId: FolderId | null) => {
|
||||
const expandFolderAncestors = useCallback((targetId: FolderId | null, options: { includeSelf?: boolean } = {}) => {
|
||||
const { includeSelf = true } = options;
|
||||
if (!targetId || targetId === 'root') {
|
||||
setFolderNodes((prev: Map<FolderId, FolderTreeNode>) => {
|
||||
const root = prev.get('root');
|
||||
@@ -186,6 +187,13 @@ const useFolderTree = ({
|
||||
const next = new Map<FolderId, FolderTreeNode>(prev);
|
||||
let currentId = targetId;
|
||||
let guard = 0;
|
||||
|
||||
// If not including self, start from parent
|
||||
if (!includeSelf) {
|
||||
const node = next.get(currentId);
|
||||
currentId = node?.parentId ?? 'root';
|
||||
}
|
||||
|
||||
while (currentId && guard < 32) {
|
||||
guard += 1;
|
||||
const node = next.get(currentId);
|
||||
|
||||
@@ -59,7 +59,7 @@ interface UseFolderTreeActionsOptions {
|
||||
setSelectedFolder: (folderId: FolderKey) => void;
|
||||
ensureFolderData: (folderId: FolderKey, options?: EnsureFolderOptions) => Promise<any>;
|
||||
ensureFolderAncestorsLoaded: (folderId: FolderKey) => Promise<void>;
|
||||
expandFolderAncestors: (folderId: FolderKey) => void;
|
||||
expandFolderAncestors: (folderId: FolderKey, options?: { includeSelf?: boolean }) => void;
|
||||
applySelectedFolder: (folderId: FolderKey, contents: any) => void;
|
||||
notifyApiError: (error: unknown, message?: string) => void;
|
||||
setStatusMessage: (message: string, level?: string) => void;
|
||||
@@ -250,7 +250,7 @@ const useFolderTreeActions = ({
|
||||
const targetId = folderId && folderId !== 'root' ? folderId : 'root';
|
||||
|
||||
await ensureFolderAncestorsLoaded(targetId);
|
||||
expandFolderAncestors(targetId);
|
||||
expandFolderAncestors(targetId, { includeSelf: false });
|
||||
|
||||
if (!navigate || immediate) {
|
||||
await loadFolder(targetId, { preserveSearch: isFilterActive });
|
||||
@@ -327,7 +327,7 @@ const useFolderTreeActions = ({
|
||||
);
|
||||
|
||||
const handleFolderCreate = useCallback(
|
||||
async (name: string) => {
|
||||
async (name: string, parentId?: FolderKey | null) => {
|
||||
if (!token) {
|
||||
setStatusMessage('Log in to create folders.', 'error');
|
||||
return false;
|
||||
@@ -336,9 +336,14 @@ const useFolderTreeActions = ({
|
||||
setStatusMessage('Folder name cannot be empty.', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
const targetParentId = parentId !== undefined
|
||||
? (parentId === 'root' ? null : parentId)
|
||||
: (selectedFolder === 'root' ? null : selectedFolder);
|
||||
|
||||
const payload = {
|
||||
name: name.trim(),
|
||||
parent_id: selectedFolder === 'root' ? null : selectedFolder,
|
||||
parent_id: targetParentId,
|
||||
};
|
||||
setCreatingFolder(true);
|
||||
let succeeded = false;
|
||||
@@ -372,7 +377,11 @@ const useFolderTreeActions = ({
|
||||
});
|
||||
return next;
|
||||
});
|
||||
await ensureFolderData(selectedFolder, { force: true, prefetchDepth: 1 });
|
||||
|
||||
// Refresh the parent folder to ensure consistency
|
||||
const refreshTarget = targetParentId || 'root';
|
||||
await ensureFolderData(refreshTarget, { force: true, prefetchDepth: 1 });
|
||||
|
||||
await selectFolder(folderData.id, { immediate: true });
|
||||
succeeded = true;
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user