mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-29 19:35:20 +02:00
feat: enhance DocumentNode component with loading and error indicators
This commit is contained in:
parent
0204ed5363
commit
96549791e6
1 changed files with 60 additions and 28 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Eye, MoreHorizontal, Move, PenLine, Trash2 } from "lucide-react";
|
import { AlertCircle, Clock, Eye, MoreHorizontal, Move, PenLine, Trash2 } from "lucide-react";
|
||||||
import React, { useCallback } from "react";
|
import React, { useCallback, useRef } from "react";
|
||||||
import { useDrag } from "react-dnd";
|
import { useDrag } from "react-dnd";
|
||||||
import { getDocumentTypeIcon } from "@/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentTypeIcon";
|
import { getDocumentTypeIcon } from "@/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentTypeIcon";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
@ -18,6 +18,8 @@ import {
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||||
import type { DocumentTypeEnum } from "@/contracts/types/document.types";
|
import type { DocumentTypeEnum } from "@/contracts/types/document.types";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { DND_TYPES } from "./FolderNode";
|
import { DND_TYPES } from "./FolderNode";
|
||||||
|
|
@ -76,48 +78,78 @@ export const DocumentNode = React.memo(function DocumentNode({
|
||||||
);
|
);
|
||||||
|
|
||||||
const isProcessing = statusState === "pending" || statusState === "processing";
|
const isProcessing = statusState === "pending" || statusState === "processing";
|
||||||
|
const rowRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
|
const attachRef = useCallback(
|
||||||
|
(node: HTMLButtonElement | null) => {
|
||||||
|
(rowRef as React.MutableRefObject<HTMLButtonElement | null>).current = node;
|
||||||
|
drag(node);
|
||||||
|
},
|
||||||
|
[drag]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContextMenu onOpenChange={onContextMenuOpenChange}>
|
<ContextMenu onOpenChange={onContextMenuOpenChange}>
|
||||||
<ContextMenuTrigger asChild>
|
<ContextMenuTrigger asChild>
|
||||||
{/* biome-ignore lint/a11y/useSemanticElements: div required for drag ref */}
|
<button
|
||||||
<div
|
type="button"
|
||||||
ref={drag}
|
ref={attachRef}
|
||||||
role="button"
|
|
||||||
tabIndex={0}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"group flex h-8 items-center gap-2.5 rounded-md px-1 text-sm hover:bg-accent/50 cursor-pointer select-none",
|
"group flex h-8 w-full items-center gap-2.5 rounded-md px-1 text-sm hover:bg-accent/50 cursor-pointer select-none text-left",
|
||||||
isMentioned && "bg-accent/30",
|
isMentioned && "bg-accent/30",
|
||||||
isDragging && "opacity-40"
|
isDragging && "opacity-40"
|
||||||
)}
|
)}
|
||||||
style={{ paddingLeft: `${depth * 16 + 4}px` }}
|
style={{ paddingLeft: `${depth * 16 + 4}px` }}
|
||||||
onClick={handleCheckChange}
|
onClick={handleCheckChange}
|
||||||
onKeyDown={(e) => {
|
|
||||||
if (e.key === "Enter" || e.key === " ") {
|
|
||||||
e.preventDefault();
|
|
||||||
handleCheckChange();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{isSelectable ? (
|
{(() => {
|
||||||
|
if (statusState === "pending") {
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<span className="flex h-3.5 w-3.5 shrink-0 items-center justify-center">
|
||||||
|
<Clock className="h-3.5 w-3.5 text-muted-foreground/60" />
|
||||||
|
</span>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="top">Pending - waiting to be synced</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (statusState === "processing") {
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<span className="flex h-3.5 w-3.5 shrink-0 items-center justify-center">
|
||||||
|
<Spinner size="xs" className="text-primary" />
|
||||||
|
</span>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="top">Syncing</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (statusState === "failed") {
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<span className="flex h-3.5 w-3.5 shrink-0 items-center justify-center">
|
||||||
|
<AlertCircle className="h-3.5 w-3.5 text-destructive" />
|
||||||
|
</span>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="top" className="max-w-xs">
|
||||||
|
{doc.status?.reason || "Processing failed"}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={isMentioned}
|
checked={isMentioned}
|
||||||
onCheckedChange={handleCheckChange}
|
onCheckedChange={handleCheckChange}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
className="h-3.5 w-3.5 shrink-0"
|
className="h-3.5 w-3.5 shrink-0"
|
||||||
/>
|
/>
|
||||||
) : (
|
);
|
||||||
<span className="flex h-3.5 w-3.5 shrink-0 items-center justify-center">
|
})()}
|
||||||
<span
|
|
||||||
className={cn(
|
|
||||||
"h-2 w-2 rounded-full",
|
|
||||||
statusState === "processing" && "animate-pulse bg-amber-500",
|
|
||||||
statusState === "pending" && "bg-muted-foreground/40",
|
|
||||||
statusState === "failed" && "bg-destructive"
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<span className="flex-1 min-w-0 truncate">{doc.title}</span>
|
<span className="flex-1 min-w-0 truncate">{doc.title}</span>
|
||||||
|
|
||||||
|
|
@ -164,7 +196,7 @@ export const DocumentNode = React.memo(function DocumentNode({
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</button>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
|
|
||||||
{contextMenuOpen && (
|
{contextMenuOpen && (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue