diff --git a/surfsense_backend/app/routes/notes_routes.py b/surfsense_backend/app/routes/notes_routes.py index 928cd462a..47cf96d04 100644 --- a/surfsense_backend/app/routes/notes_routes.py +++ b/surfsense_backend/app/routes/notes_routes.py @@ -230,6 +230,14 @@ async def delete_note( if not document: raise HTTPException(status_code=404, detail="Note not found") + # Check if note is pending or currently being processed + doc_state = document.status.get("state") if document.status else None + if doc_state in ("pending", "processing"): + raise HTTPException( + status_code=409, + detail="Cannot delete note while it is pending or being processed. Please wait for processing to complete.", + ) + # Delete document (chunks will be cascade deleted) await session.delete(document) await session.commit() diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx index db77c6472..0bd8189b8 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx @@ -294,13 +294,22 @@ export function DocumentsTableShell({ [documents, sortKey, sortDesc] ); - const allSelectedOnPage = sorted.length > 0 && sorted.every((d) => selectedIds.has(d.id)); - const someSelectedOnPage = sorted.some((d) => selectedIds.has(d.id)) && !allSelectedOnPage; + // Helper: check if document can be selected (not processing/pending) + const isSelectable = (doc: Document) => { + const state = doc.status?.state; + return state !== "pending" && state !== "processing"; + }; + + // Only consider selectable documents for "select all" logic + const selectableDocs = sorted.filter(isSelectable); + const allSelectedOnPage = selectableDocs.length > 0 && selectableDocs.every((d) => selectedIds.has(d.id)); + const someSelectedOnPage = selectableDocs.some((d) => selectedIds.has(d.id)) && !allSelectedOnPage; const toggleAll = (checked: boolean) => { const next = new Set(selectedIds); if (checked) - sorted.forEach((d) => { + // Only select documents that are not processing/pending + selectableDocs.forEach((d) => { next.add(d.id); }); else @@ -547,6 +556,7 @@ export function DocumentsTableShell({ {sorted.map((doc, index) => { const title = doc.title; const isSelected = selectedIds.has(doc.id); + const canSelect = isSelectable(doc); return ( toggleOne(doc.id, !!v)} - aria-label="Select row" - className="border-foreground data-[state=checked]:bg-primary data-[state=checked]:border-primary" + onCheckedChange={(v) => canSelect && toggleOne(doc.id, !!v)} + disabled={!canSelect} + aria-label={canSelect ? "Select row" : "Cannot select while processing"} + className={`border-foreground data-[state=checked]:bg-primary data-[state=checked]:border-primary ${!canSelect ? "opacity-40 cursor-not-allowed" : ""}`} /> @@ -649,6 +660,7 @@ export function DocumentsTableShell({
{sorted.map((doc, index) => { const isSelected = selectedIds.has(doc.id); + const canSelect = isSelectable(doc); return ( toggleOne(doc.id, !!v)} - aria-label="Select row" - className="border-foreground data-[state=checked]:bg-primary data-[state=checked]:border-primary" + onCheckedChange={(v) => canSelect && toggleOne(doc.id, !!v)} + disabled={!canSelect} + aria-label={canSelect ? "Select row" : "Cannot select while processing"} + className={`border-foreground data-[state=checked]:bg-primary data-[state=checked]:border-primary ${!canSelect ? "opacity-40 cursor-not-allowed" : ""}`} />