mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 08:46:22 +02:00
feat: enhance document upload and folder synchronization UI with improved processing state indicators and responsive design adjustments
This commit is contained in:
parent
530db10539
commit
bd21c2842d
7 changed files with 359 additions and 283 deletions
|
|
@ -195,12 +195,14 @@ export const DocumentNode = React.memo(function DocumentNode({
|
|||
|
||||
<span className="flex-1 min-w-0 truncate">{doc.title}</span>
|
||||
|
||||
<span className="shrink-0">
|
||||
{getDocumentTypeIcon(
|
||||
doc.document_type as DocumentTypeEnum,
|
||||
"h-3.5 w-3.5 text-muted-foreground"
|
||||
)}
|
||||
</span>
|
||||
{getDocumentTypeIcon(doc.document_type as DocumentTypeEnum, "h-3.5 w-3.5 text-muted-foreground") && (
|
||||
<span className="shrink-0">
|
||||
{getDocumentTypeIcon(
|
||||
doc.document_type as DocumentTypeEnum,
|
||||
"h-3.5 w-3.5 text-muted-foreground"
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<DropdownMenu open={dropdownOpen} onOpenChange={setDropdownOpen}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import {
|
||||
AlertCircle,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
|
|
@ -30,6 +31,8 @@ import {
|
|||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { FolderSelectionState } from "./FolderTreeView";
|
||||
|
||||
|
|
@ -55,6 +58,7 @@ interface FolderNodeProps {
|
|||
isRenaming: boolean;
|
||||
childCount: number;
|
||||
selectionState: FolderSelectionState;
|
||||
processingState: "idle" | "processing" | "failed";
|
||||
onToggleSelect: (folderId: number, selectAll: boolean) => void;
|
||||
onToggleExpand: (folderId: number) => void;
|
||||
onRename: (folder: FolderDisplay, newName: string) => void;
|
||||
|
|
@ -100,6 +104,7 @@ export const FolderNode = React.memo(function FolderNode({
|
|||
isRenaming,
|
||||
childCount,
|
||||
selectionState,
|
||||
processingState,
|
||||
onToggleSelect,
|
||||
onToggleExpand,
|
||||
onRename,
|
||||
|
|
@ -281,14 +286,41 @@ export const FolderNode = React.memo(function FolderNode({
|
|||
)}
|
||||
</span>
|
||||
|
||||
<Checkbox
|
||||
checked={
|
||||
selectionState === "all" ? true : selectionState === "some" ? "indeterminate" : false
|
||||
}
|
||||
onCheckedChange={handleCheckChange}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="h-3.5 w-3.5 shrink-0"
|
||||
/>
|
||||
{processingState !== "idle" && selectionState === "none" ? (
|
||||
<>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="flex h-3.5 w-3.5 shrink-0 items-center justify-center group-hover:hidden">
|
||||
{processingState === "processing" ? (
|
||||
<Spinner size="xs" className="text-primary" />
|
||||
) : (
|
||||
<AlertCircle className="h-3.5 w-3.5 text-destructive" />
|
||||
)}
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top">
|
||||
{processingState === "processing"
|
||||
? "Syncing folder contents"
|
||||
: "Some files failed to process"}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Checkbox
|
||||
checked={false}
|
||||
onCheckedChange={handleCheckChange}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="h-3.5 w-3.5 shrink-0 hidden group-hover:flex"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Checkbox
|
||||
checked={
|
||||
selectionState === "all" ? true : selectionState === "some" ? "indeterminate" : false
|
||||
}
|
||||
onCheckedChange={handleCheckChange}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="h-3.5 w-3.5 shrink-0"
|
||||
/>
|
||||
)}
|
||||
|
||||
<FolderIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
|
||||
|
|
|
|||
|
|
@ -166,6 +166,35 @@ export function FolderTreeView({
|
|||
return states;
|
||||
}, [folders, docsByFolder, foldersByParent, mentionedDocIds]);
|
||||
|
||||
const folderProcessingStates = useMemo(() => {
|
||||
const states: Record<number, "idle" | "processing" | "failed"> = {};
|
||||
|
||||
function compute(folderId: number): { hasProcessing: boolean; hasFailed: boolean } {
|
||||
const directDocs = docsByFolder[folderId] ?? [];
|
||||
let hasProcessing = directDocs.some(
|
||||
(d) => d.status?.state === "pending" || d.status?.state === "processing"
|
||||
);
|
||||
let hasFailed = directDocs.some((d) => d.status?.state === "failed");
|
||||
|
||||
for (const child of foldersByParent[folderId] ?? []) {
|
||||
const sub = compute(child.id);
|
||||
hasProcessing = hasProcessing || sub.hasProcessing;
|
||||
hasFailed = hasFailed || sub.hasFailed;
|
||||
}
|
||||
|
||||
if (hasProcessing) states[folderId] = "processing";
|
||||
else if (hasFailed) states[folderId] = "failed";
|
||||
else states[folderId] = "idle";
|
||||
|
||||
return { hasProcessing, hasFailed };
|
||||
}
|
||||
|
||||
for (const f of folders) {
|
||||
if (states[f.id] === undefined) compute(f.id);
|
||||
}
|
||||
return states;
|
||||
}, [folders, docsByFolder, foldersByParent]);
|
||||
|
||||
function renderLevel(parentId: number | null, depth: number): React.ReactNode[] {
|
||||
const key = parentId ?? "root";
|
||||
const childFolders = (foldersByParent[key] ?? [])
|
||||
|
|
@ -199,6 +228,7 @@ export function FolderTreeView({
|
|||
isRenaming={renamingFolderId === f.id}
|
||||
childCount={folderChildCounts[f.id] ?? 0}
|
||||
selectionState={folderSelectionStates[f.id] ?? "none"}
|
||||
processingState={folderProcessingStates[f.id] ?? "idle"}
|
||||
onToggleSelect={onToggleFolderSelect}
|
||||
onToggleExpand={onToggleExpand}
|
||||
onRename={onRenameFolder}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue