mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-26 21:39:43 +02:00
refactor: remove redundant document deletion logic and optimize cache updates
This commit is contained in:
parent
878e829bdc
commit
ab2896ec65
4 changed files with 9 additions and 64 deletions
|
|
@ -3,7 +3,6 @@
|
||||||
import { formatDistanceToNow } from "date-fns";
|
import { formatDistanceToNow } from "date-fns";
|
||||||
import { Calendar, ChevronDown, ChevronUp, FileText, FileX, Link2, Plus, User } from "lucide-react";
|
import { Calendar, ChevronDown, ChevronUp, FileText, FileX, Link2, Plus, User } from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import { useParams } from "next/navigation";
|
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import React, { useRef, useState, useEffect } from "react";
|
import React, { useRef, useState, useEffect } from "react";
|
||||||
import { useDocumentUploadDialog } from "@/components/assistant-ui/document-upload-popup";
|
import { useDocumentUploadDialog } from "@/components/assistant-ui/document-upload-popup";
|
||||||
|
|
@ -22,7 +21,6 @@ import {
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||||
import { DocumentTypeChip } from "./DocumentTypeIcon";
|
import { DocumentTypeChip } from "./DocumentTypeIcon";
|
||||||
import { RowActions } from "./RowActions";
|
|
||||||
import type { ColumnVisibility, Document } from "./types";
|
import type { ColumnVisibility, Document } from "./types";
|
||||||
|
|
||||||
export type SortKey = keyof Pick<Document, "title" | "document_type" | "created_at">;
|
export type SortKey = keyof Pick<Document, "title" | "document_type" | "created_at">;
|
||||||
|
|
@ -134,7 +132,6 @@ export function DocumentsTableShell({
|
||||||
selectedIds,
|
selectedIds,
|
||||||
setSelectedIds,
|
setSelectedIds,
|
||||||
columnVisibility,
|
columnVisibility,
|
||||||
deleteDocument,
|
|
||||||
sortKey,
|
sortKey,
|
||||||
sortDesc,
|
sortDesc,
|
||||||
onSortChange,
|
onSortChange,
|
||||||
|
|
@ -146,14 +143,11 @@ export function DocumentsTableShell({
|
||||||
selectedIds: Set<number>;
|
selectedIds: Set<number>;
|
||||||
setSelectedIds: (update: Set<number>) => void;
|
setSelectedIds: (update: Set<number>) => void;
|
||||||
columnVisibility: ColumnVisibility;
|
columnVisibility: ColumnVisibility;
|
||||||
deleteDocument: (id: number) => Promise<boolean>;
|
|
||||||
sortKey: SortKey;
|
sortKey: SortKey;
|
||||||
sortDesc: boolean;
|
sortDesc: boolean;
|
||||||
onSortChange: (key: SortKey) => void;
|
onSortChange: (key: SortKey) => void;
|
||||||
}) {
|
}) {
|
||||||
const t = useTranslations("documents");
|
const t = useTranslations("documents");
|
||||||
const params = useParams();
|
|
||||||
const searchSpaceId = params.search_space_id;
|
|
||||||
const { openDialog } = useDocumentUploadDialog();
|
const { openDialog } = useDocumentUploadDialog();
|
||||||
|
|
||||||
// State for metadata viewer (opened via Ctrl/Cmd+Click)
|
// State for metadata viewer (opened via Ctrl/Cmd+Click)
|
||||||
|
|
@ -222,13 +216,10 @@ export function DocumentsTableShell({
|
||||||
</TableHead>
|
</TableHead>
|
||||||
)}
|
)}
|
||||||
{columnVisibility.created_at && (
|
{columnVisibility.created_at && (
|
||||||
<TableHead className="w-32 border-r border-border/30">
|
<TableHead className="w-32">
|
||||||
<Skeleton className="h-3 w-16" />
|
<Skeleton className="h-3 w-16" />
|
||||||
</TableHead>
|
</TableHead>
|
||||||
)}
|
)}
|
||||||
<TableHead className="w-10 text-center">
|
|
||||||
<span className="sr-only">Actions</span>
|
|
||||||
</TableHead>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
@ -262,15 +253,10 @@ export function DocumentsTableShell({
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)}
|
)}
|
||||||
{columnVisibility.created_at && (
|
{columnVisibility.created_at && (
|
||||||
<TableCell className="w-32 py-2.5 border-r border-border/30">
|
<TableCell className="w-32 py-2.5">
|
||||||
<Skeleton className="h-4 w-20" />
|
<Skeleton className="h-4 w-20" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)}
|
)}
|
||||||
<TableCell className="w-10 py-2.5 px-0">
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<Skeleton className="h-7 w-7 rounded" />
|
|
||||||
</div>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
|
@ -387,7 +373,7 @@ export function DocumentsTableShell({
|
||||||
</TableHead>
|
</TableHead>
|
||||||
)}
|
)}
|
||||||
{columnVisibility.created_at && (
|
{columnVisibility.created_at && (
|
||||||
<TableHead className="w-32 border-r border-border/30">
|
<TableHead className="w-32">
|
||||||
<SortableHeader
|
<SortableHeader
|
||||||
sortKey="created_at"
|
sortKey="created_at"
|
||||||
currentSortKey={sortKey}
|
currentSortKey={sortKey}
|
||||||
|
|
@ -399,9 +385,6 @@ export function DocumentsTableShell({
|
||||||
</SortableHeader>
|
</SortableHeader>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
)}
|
)}
|
||||||
<TableHead className="w-10 text-center">
|
|
||||||
<span className="sr-only">Actions</span>
|
|
||||||
</TableHead>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
@ -479,7 +462,7 @@ export function DocumentsTableShell({
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)}
|
)}
|
||||||
{columnVisibility.created_at && (
|
{columnVisibility.created_at && (
|
||||||
<TableCell className="w-32 py-2.5 text-sm text-foreground border-r border-border/30">
|
<TableCell className="w-32 py-2.5 text-sm text-foreground">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<span className="cursor-default">{formatRelativeDate(doc.created_at)}</span>
|
<span className="cursor-default">{formatRelativeDate(doc.created_at)}</span>
|
||||||
|
|
@ -490,18 +473,6 @@ export function DocumentsTableShell({
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)}
|
)}
|
||||||
<TableCell className="w-10 py-2.5 px-0">
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<RowActions
|
|
||||||
document={doc}
|
|
||||||
deleteDocument={deleteDocument}
|
|
||||||
refreshDocuments={async () => {
|
|
||||||
await onRefresh();
|
|
||||||
}}
|
|
||||||
searchSpaceId={searchSpaceId as string}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</TableCell>
|
|
||||||
</motion.tr>
|
</motion.tr>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
@ -579,14 +550,6 @@ export function DocumentsTableShell({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<RowActions
|
|
||||||
document={doc}
|
|
||||||
deleteDocument={deleteDocument}
|
|
||||||
refreshDocuments={async () => {
|
|
||||||
await onRefresh();
|
|
||||||
}}
|
|
||||||
searchSpaceId={searchSpaceId as string}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,10 @@ const NON_DELETABLE_DOCUMENT_TYPES = ["SURFSENSE_DOCS"] as const;
|
||||||
export function RowActions({
|
export function RowActions({
|
||||||
document,
|
document,
|
||||||
deleteDocument,
|
deleteDocument,
|
||||||
refreshDocuments,
|
|
||||||
searchSpaceId,
|
searchSpaceId,
|
||||||
}: {
|
}: {
|
||||||
document: Document;
|
document: Document;
|
||||||
deleteDocument: (id: number) => Promise<boolean>;
|
deleteDocument: (id: number) => Promise<boolean>;
|
||||||
refreshDocuments: () => Promise<void>;
|
|
||||||
searchSpaceId: string;
|
searchSpaceId: string;
|
||||||
}) {
|
}) {
|
||||||
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
|
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
|
||||||
|
|
@ -55,9 +53,9 @@ export function RowActions({
|
||||||
setIsDeleting(true);
|
setIsDeleting(true);
|
||||||
try {
|
try {
|
||||||
const ok = await deleteDocument(document.id);
|
const ok = await deleteDocument(document.id);
|
||||||
if (ok) toast.success("Document deleted successfully");
|
if (!ok) toast.error("Failed to delete document");
|
||||||
else toast.error("Failed to delete document");
|
// Note: Success toast is handled by the mutation atom's onSuccess callback
|
||||||
await refreshDocuments();
|
// Cache is updated optimistically by the mutation, no need to refresh
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting document:", error);
|
console.error("Error deleting document:", error);
|
||||||
toast.error("Failed to delete document");
|
toast.error("Failed to delete document");
|
||||||
|
|
|
||||||
|
|
@ -187,20 +187,6 @@ export default function DocumentsTable() {
|
||||||
}
|
}
|
||||||
}, [debouncedSearch, refetchSearch, refetchDocuments, t, isRefreshing]);
|
}, [debouncedSearch, refetchSearch, refetchDocuments, t, isRefreshing]);
|
||||||
|
|
||||||
// Create a delete function for single document deletion
|
|
||||||
const deleteDocument = useCallback(
|
|
||||||
async (id: number) => {
|
|
||||||
try {
|
|
||||||
await deleteDocumentMutation({ id });
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to delete document:", error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[deleteDocumentMutation]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onBulkDelete = async () => {
|
const onBulkDelete = async () => {
|
||||||
if (selectedIds.size === 0) {
|
if (selectedIds.size === 0) {
|
||||||
toast.error(t("no_rows_selected"));
|
toast.error(t("no_rows_selected"));
|
||||||
|
|
@ -222,8 +208,7 @@ export default function DocumentsTable() {
|
||||||
if (okCount === selectedIds.size)
|
if (okCount === selectedIds.size)
|
||||||
toast.success(t("delete_success_count", { count: okCount }));
|
toast.success(t("delete_success_count", { count: okCount }));
|
||||||
else toast.error(t("delete_partial_failed"));
|
else toast.error(t("delete_partial_failed"));
|
||||||
// Refetch the current page with appropriate method
|
// Note: No need to call refreshCurrentView() - the mutation already updates the cache
|
||||||
await refreshCurrentView();
|
|
||||||
setSelectedIds(new Set());
|
setSelectedIds(new Set());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
@ -282,7 +267,6 @@ export default function DocumentsTable() {
|
||||||
selectedIds={selectedIds}
|
selectedIds={selectedIds}
|
||||||
setSelectedIds={setSelectedIds}
|
setSelectedIds={setSelectedIds}
|
||||||
columnVisibility={columnVisibility}
|
columnVisibility={columnVisibility}
|
||||||
deleteDocument={deleteDocument}
|
|
||||||
sortKey={sortKey}
|
sortKey={sortKey}
|
||||||
sortDesc={sortDesc}
|
sortDesc={sortDesc}
|
||||||
onSortChange={handleSortChange}
|
onSortChange={handleSortChange}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ export const deleteDocumentMutationAtom = atomWithMutation((get) => {
|
||||||
},
|
},
|
||||||
|
|
||||||
onSuccess: (_, request: DeleteDocumentRequest) => {
|
onSuccess: (_, request: DeleteDocumentRequest) => {
|
||||||
toast.success("Document deleted successfully");
|
// Note: Toast is handled by the caller (page.tsx onBulkDelete) to show count info
|
||||||
queryClient.setQueryData(
|
queryClient.setQueryData(
|
||||||
cacheKeys.documents.globalQueryParams(documentsQueryParams),
|
cacheKeys.documents.globalQueryParams(documentsQueryParams),
|
||||||
(oldData: GetDocumentsResponse | undefined) => {
|
(oldData: GetDocumentsResponse | undefined) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue