refactor: improve document processing error handling and UI state management

This commit is contained in:
Anish Sarkar 2026-04-13 22:22:50 +05:30
parent 635cdde0eb
commit ec27807644
3 changed files with 80 additions and 69 deletions

View file

@ -139,9 +139,19 @@ async def get_editor_content(
status_code=409,
detail="This document is still being processed. Please wait a moment and try again.",
)
if state == "failed":
reason = (
doc_status.get("reason", "Unknown error")
if isinstance(doc_status, dict)
else "Unknown error"
)
raise HTTPException(
status_code=422,
detail=f"Processing failed: {reason}. You can delete this document and re-upload it.",
)
raise HTTPException(
status_code=400,
detail="This document has no viewable content yet. It may still be syncing. Try again in a few seconds, or re-upload if the issue persists.",
detail="This document has no content. It may not have been processed correctly. Try deleting and re-uploading it.",
)
markdown_content = "\n\n".join(chunk_contents)

View file

@ -82,11 +82,12 @@ export const DocumentNode = React.memo(function DocumentNode({
onContextMenuOpenChange,
}: DocumentNodeProps) {
const statusState = doc.status?.state ?? "ready";
const isSelectable = statusState !== "pending" && statusState !== "processing";
const isFailed = statusState === "failed";
const isProcessing = statusState === "pending" || statusState === "processing";
const isUnavailable = isProcessing || isFailed;
const isSelectable = !isUnavailable;
const isEditable =
EDITABLE_DOCUMENT_TYPES.has(doc.document_type) &&
statusState !== "pending" &&
statusState !== "processing";
EDITABLE_DOCUMENT_TYPES.has(doc.document_type) && !isUnavailable;
const handleCheckChange = useCallback(() => {
if (isSelectable) {
@ -103,7 +104,6 @@ export const DocumentNode = React.memo(function DocumentNode({
[doc.id]
);
const isProcessing = statusState === "pending" || statusState === "processing";
const [dropdownOpen, setDropdownOpen] = useState(false);
const [exporting, setExporting] = useState<string | null>(null);
const [titleTooltipOpen, setTitleTooltipOpen] = useState(false);
@ -261,38 +261,38 @@ export const DocumentNode = React.memo(function DocumentNode({
className="w-40"
onClick={(e) => e.stopPropagation()}
>
<DropdownMenuItem onClick={() => onPreview(doc)} disabled={isProcessing}>
<Eye className="mr-2 h-4 w-4" />
Open
<DropdownMenuItem onClick={() => onPreview(doc)} disabled={isUnavailable}>
<Eye className="mr-2 h-4 w-4" />
Open
</DropdownMenuItem>
{isEditable && (
<DropdownMenuItem onClick={() => onEdit(doc)}>
<PenLine className="mr-2 h-4 w-4" />
Edit
</DropdownMenuItem>
{isEditable && (
<DropdownMenuItem onClick={() => onEdit(doc)}>
<PenLine className="mr-2 h-4 w-4" />
Edit
</DropdownMenuItem>
)}
<DropdownMenuItem onClick={() => onMove(doc)}>
<Move className="mr-2 h-4 w-4" />
Move to...
)}
<DropdownMenuItem onClick={() => onMove(doc)}>
<Move className="mr-2 h-4 w-4" />
Move to...
</DropdownMenuItem>
{onExport && (
<DropdownMenuSub>
<DropdownMenuSubTrigger disabled={isUnavailable}>
<Download className="mr-2 h-4 w-4" />
Export
</DropdownMenuSubTrigger>
<DropdownMenuSubContent className="min-w-[180px]">
<ExportDropdownItems onExport={handleExport} exporting={exporting} />
</DropdownMenuSubContent>
</DropdownMenuSub>
)}
{onVersionHistory && isVersionableType(doc.document_type) && (
<DropdownMenuItem disabled={isUnavailable} onClick={() => onVersionHistory(doc)}>
<History className="mr-2 h-4 w-4" />
Versions
</DropdownMenuItem>
{onExport && (
<DropdownMenuSub>
<DropdownMenuSubTrigger disabled={isProcessing}>
<Download className="mr-2 h-4 w-4" />
Export
</DropdownMenuSubTrigger>
<DropdownMenuSubContent className="min-w-[180px]">
<ExportDropdownItems onExport={handleExport} exporting={exporting} />
</DropdownMenuSubContent>
</DropdownMenuSub>
)}
{onVersionHistory && isVersionableType(doc.document_type) && (
<DropdownMenuItem disabled={isProcessing} onClick={() => onVersionHistory(doc)}>
<History className="mr-2 h-4 w-4" />
Versions
</DropdownMenuItem>
)}
<DropdownMenuItem disabled={isProcessing} onClick={() => onDelete(doc)}>
)}
<DropdownMenuItem disabled={isProcessing} onClick={() => onDelete(doc)}>
<Trash2 className="mr-2 h-4 w-4" />
Delete
</DropdownMenuItem>
@ -304,38 +304,38 @@ export const DocumentNode = React.memo(function DocumentNode({
{contextMenuOpen && (
<ContextMenuContent className="w-40" onClick={(e) => e.stopPropagation()}>
<ContextMenuItem onClick={() => onPreview(doc)} disabled={isProcessing}>
<Eye className="mr-2 h-4 w-4" />
Open
<ContextMenuItem onClick={() => onPreview(doc)} disabled={isUnavailable}>
<Eye className="mr-2 h-4 w-4" />
Open
</ContextMenuItem>
{isEditable && (
<ContextMenuItem onClick={() => onEdit(doc)}>
<PenLine className="mr-2 h-4 w-4" />
Edit
</ContextMenuItem>
{isEditable && (
<ContextMenuItem onClick={() => onEdit(doc)}>
<PenLine className="mr-2 h-4 w-4" />
Edit
</ContextMenuItem>
)}
<ContextMenuItem onClick={() => onMove(doc)}>
<Move className="mr-2 h-4 w-4" />
Move to...
)}
<ContextMenuItem onClick={() => onMove(doc)}>
<Move className="mr-2 h-4 w-4" />
Move to...
</ContextMenuItem>
{onExport && (
<ContextMenuSub>
<ContextMenuSubTrigger disabled={isUnavailable}>
<Download className="mr-2 h-4 w-4" />
Export
</ContextMenuSubTrigger>
<ContextMenuSubContent className="min-w-[180px]">
<ExportContextItems onExport={handleExport} exporting={exporting} />
</ContextMenuSubContent>
</ContextMenuSub>
)}
{onVersionHistory && isVersionableType(doc.document_type) && (
<ContextMenuItem disabled={isUnavailable} onClick={() => onVersionHistory(doc)}>
<History className="mr-2 h-4 w-4" />
Versions
</ContextMenuItem>
{onExport && (
<ContextMenuSub>
<ContextMenuSubTrigger disabled={isProcessing}>
<Download className="mr-2 h-4 w-4" />
Export
</ContextMenuSubTrigger>
<ContextMenuSubContent className="min-w-[180px]">
<ExportContextItems onExport={handleExport} exporting={exporting} />
</ContextMenuSubContent>
</ContextMenuSub>
)}
{onVersionHistory && isVersionableType(doc.document_type) && (
<ContextMenuItem disabled={isProcessing} onClick={() => onVersionHistory(doc)}>
<History className="mr-2 h-4 w-4" />
Versions
</ContextMenuItem>
)}
<ContextMenuItem disabled={isProcessing} onClick={() => onDelete(doc)}>
)}
<ContextMenuItem disabled={isProcessing} onClick={() => onDelete(doc)}>
<Trash2 className="mr-2 h-4 w-4" />
Delete
</ContextMenuItem>

View file

@ -627,9 +627,10 @@ export function DocumentsSidebar({
function collectSubtreeDocs(parentId: number): DocumentNodeDoc[] {
const directDocs = (treeDocuments ?? []).filter(
(d) =>
d.folderId === parentId &&
d.status?.state !== "pending" &&
d.status?.state !== "processing"
d.folderId === parentId &&
d.status?.state !== "pending" &&
d.status?.state !== "processing" &&
d.status?.state !== "failed"
);
const childFolders = foldersByParent[String(parentId)] ?? [];
const descendantDocs = childFolders.flatMap((cf) => collectSubtreeDocs(cf.id));