refactor: remove redundant document deletion logic and optimize cache updates

This commit is contained in:
Anish Sarkar 2026-02-04 17:27:40 +05:30
parent 878e829bdc
commit ab2896ec65
4 changed files with 9 additions and 64 deletions

View file

@ -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>
); );

View file

@ -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");

View file

@ -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}

View file

@ -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) => {