refactor: replace imperative deleteDocument with mutation atom

- Replaced deleteDocument from useDocuments with deleteDocumentMutationAtom
- Removed unused useDocuments hook completely
- Updated DocumentsTable to use mutation atom for single and bulk deletes
- Maintains backward compatibility with existing delete functionality
This commit is contained in:
CREDO23 2025-12-08 10:03:17 +00:00
parent 8140a5fb6e
commit ede7020b61
2 changed files with 31 additions and 91 deletions

View file

@ -6,12 +6,11 @@ import { useTranslations } from "next-intl";
import { useCallback, useEffect, useId, useMemo, useState } from "react";
import { toast } from "sonner";
import { useQuery } from "@tanstack/react-query";
import { useAtomValue } from "jotai";
import { useAtomValue, useSetAtom } from "jotai";
import { documentsApiService } from "@/lib/apis/documents-api.service";
import { cacheKeys } from "@/lib/query-client/cache-keys";
import { documentTypeCountsAtom } from "@/atoms/documents/document-query.atoms";
import { useDocuments } from "@/hooks/use-documents";
import { deleteDocumentMutationAtom } from "@/atoms/documents/document-mutation.atoms";
import { DocumentsFilters } from "./components/DocumentsFilters";
import { DocumentsTableShell, type SortKey } from "./components/DocumentsTableShell";
@ -50,6 +49,9 @@ export default function DocumentsTable() {
const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set());
const {data: typeCounts} = useAtomValue(documentTypeCountsAtom) ;
// Set up the delete mutation
const deleteDocumentMutation = useSetAtom(deleteDocumentMutationAtom);
// Build query parameters for fetching documents
const queryParams = useMemo(
() => ({
@ -109,14 +111,6 @@ export default function DocumentsTable() {
const loading = debouncedSearch.trim() ? isSearchLoading : isDocumentsLoading;
const error = debouncedSearch.trim() ? searchError : documentsError
// Use server-side pagination, search, and filtering
const {
deleteDocument,
} = useDocuments(searchSpaceId, {
page: pageIndex,
pageSize: pageSize,
});
// Display server-filtered results directly
const displayDocs = documents || [];
const displayTotal = total;
@ -140,13 +134,37 @@ export default function DocumentsTable() {
}
}, [debouncedSearch, refetchSearch, refetchDocuments]);
// 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 () => {
if (selectedIds.size === 0) {
toast.error(t("no_rows_selected"));
return;
}
try {
const results = await Promise.all(Array.from(selectedIds).map((id) => deleteDocument?.(id)));
// Delete documents one by one using the mutation
const results = await Promise.all(
Array.from(selectedIds).map(async (id) => {
try {
await deleteDocumentMutation([{ id }]);
return true;
} catch {
return false;
}
})
);
const okCount = results.filter((r) => r === true).length;
if (okCount === selectedIds.size)
toast.success(t("delete_success_count", { count: okCount }));
@ -198,7 +216,7 @@ export default function DocumentsTable() {
selectedIds={selectedIds}
setSelectedIds={setSelectedIds}
columnVisibility={columnVisibility}
deleteDocument={(id) => deleteDocument?.(id) ?? Promise.resolve(false)}
deleteDocument={deleteDocument}
sortKey={sortKey}
sortDesc={sortDesc}
onSortChange={(key) => {

View file

@ -1,78 +0,0 @@
"use client";
import { useCallback, useEffect, useState } from "react";
import { toast } from "sonner";
import { authenticatedFetch } from "@/lib/auth-utils";
export interface Document {
id: number;
title: string;
document_type: DocumentType;
document_metadata: any;
content: string;
created_at: string;
search_space_id: number;
}
export type DocumentType =
| "EXTENSION"
| "CRAWLED_URL"
| "SLACK_CONNECTOR"
| "NOTION_CONNECTOR"
| "FILE"
| "YOUTUBE_VIDEO"
| "GITHUB_CONNECTOR"
| "LINEAR_CONNECTOR"
| "DISCORD_CONNECTOR"
| "JIRA_CONNECTOR"
| "CONFLUENCE_CONNECTOR"
| "CLICKUP_CONNECTOR"
| "GOOGLE_CALENDAR_CONNECTOR"
| "GOOGLE_GMAIL_CONNECTOR"
| "AIRTABLE_CONNECTOR"
| "LUMA_CONNECTOR"
| "ELASTICSEARCH_CONNECTOR";
export interface UseDocumentsOptions {
page?: number;
pageSize?: number;
lazy?: boolean;
documentTypes?: string[];
}
export function useDocuments(searchSpaceId: number, options?: UseDocumentsOptions | boolean) {
// Support both old boolean API and new options API for backward compatibility
const opts = typeof options === "boolean" ? { lazy: options } : options || {};
const [error, setError] = useState<string | null>(null);
// Function to delete a document
const deleteDocument = useCallback(
async (documentId: number) => {
try {
const response = await authenticatedFetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/documents/${documentId}`,
{ method: "DELETE" }
);
if (!response.ok) {
toast.error("Failed to delete document");
throw new Error("Failed to delete document");
}
toast.success("Document deleted successfully");
// Note: The caller should handle refetching the documents list
return true;
} catch (err: any) {
toast.error(err.message || "Failed to delete document");
console.error("Error deleting document:", err);
return false;
}
},
[]
);
return {
error,
deleteDocument,
};
}