Skip to content

🟡 [P0] Add real-time UI error notifications for background task failures #450

@manavgup

Description

@manavgup

Priority

🟡 P0 - Critical (Silent failures blocking production)

Problem

Users have zero visibility when background operations fail. Reindexing, ingestion, and exports fail silently, causing:

  • Users assume operations succeeded
  • Data inconsistency and confusion
  • No actionable error messages
  • Impossible to debug issues

Current User Experience

  1. User clicks "Reindex Collection" → 200 OK
  2. Modal closes → No feedback
  3. User waits... → Nothing happens
  4. User refreshes page → Same stale data
  5. User checks backend logs → Finds error

Solution - Phase 3 (6 hours)

1. Add Toast Notifications

// frontend/src/components/common/ErrorToast.tsx (NEW)
interface ErrorToastProps {
  title: string;
  message: string;
  details?: string;
  remediation?: string;
  onDismiss: () => void;
}

const ErrorToast: React.FC<ErrorToastProps> = ({
  title,
  message,
  details,
  remediation,
  onDismiss
}) => (
  <Toast kind="error" title={title} subtitle={message}>
    {details && (
      <Accordion>
        <AccordionItem title="Technical Details">
          <pre>{details}</pre>
        </AccordionItem>
      </Accordion>
    )}
    {remediation && (
      <div className="remediation">
        <strong>How to fix:</strong> {remediation}
      </div>
    )}
  </Toast>
);

2. Add Progress Modal

// frontend/src/components/collections/ReindexProgressModal.tsx (NEW)
const ReindexProgressModal: React.FC<{jobId: string}> = ({jobId}) => {
  const [status, setStatus] = useState<JobStatus>()
  const [ws, setWs] = useState<WebSocket>()
  
  useEffect(() => {
    // Connect to WebSocket for real-time updates
    const websocket = new WebSocket(`/ws/jobs/${jobId}`)
    
    websocket.onmessage = (event) => {
      const update = JSON.parse(event.data)
      setStatus(update)
      
      // Show error toast on failure
      if (update.status === 'failed') {
        showErrorToast({
          title: 'Reindexing Failed',
          message: update.error.message,
          details: update.error.details,
          remediation: update.error.remediation
        })
      }
      
      // Close modal on completion
      if (update.status === 'completed') {
        showSuccessToast('Reindexing completed successfully!')
        onClose()
      }
    }
    
    setWs(websocket)
    return () => websocket.close()
  }, [jobId])
  
  return (
    <Modal open>
      <h3>Reindexing Collection</h3>
      <ProgressBar value={status?.progress || 0} />
      <p>{status?.message || 'Starting...'}</p>
    </Modal>
  )
}

3. Update Collection Actions

// frontend/src/pages/CollectionDetailPage.tsx
const handleReindex = async () => {
  try {
    const {job_id} = await api.collections.reindex(collectionId)
    
    // Show progress modal
    setReindexJobId(job_id)
    setShowReindexModal(true)
    
  } catch (error) {
    showErrorToast({
      title: 'Failed to Start Reindexing',
      message: error.message,
      remediation: 'Check backend logs or contact support'
    })
  }
}

4. Error Message Catalog

// frontend/src/utils/errorMessages.ts (NEW)
export const ERROR_MESSAGES = {
  EMBEDDING_TOKEN_LIMIT: {
    title: 'Embedding Token Limit Exceeded',
    message: 'Some document chunks are too large for the embedding model',
    remediation: 'Reduce MAX_CHUNK_SIZE to 250 tokens in backend settings'
  },
  MILVUS_CONNECTION: {
    title: 'Vector Database Connection Failed',
    message: 'Cannot connect to Milvus vector database',
    remediation: 'Check that Milvus container is running: docker ps | grep milvus'
  },
  INSUFFICIENT_MEMORY: {
    title: 'Out of Memory',
    message: 'Not enough memory to process documents',
    remediation: 'Try processing smaller batches or increase Docker memory limit'
  }
}

User Experience Improvements

Before

User: [clicks Reindex]
UI: ✅ Request accepted
      ... 
      ... (nothing happens)
User: 🤔 Did it work?

After

User: [clicks Reindex]
UI: 📊 Modal: "Reindexing... 25%"
    ⚡ WebSocket: "Processing batch 2/8"
    ❌ Error Toast: "Embedding limit exceeded"
    💡 Suggestion: "Reduce MAX_CHUNK_SIZE to 250"
User: ✅ Knows exactly what failed and how to fix it

Acceptance Criteria

  • ErrorToast component created with Carbon Design
  • ReindexProgressModal shows real-time progress
  • WebSocket connection auto-reconnects on disconnect
  • Error messages include actionable remediation steps
  • Success notifications show on completion
  • Modal auto-closes on success
  • Toast auto-dismisses after 10 seconds (errors persist)
  • Error details expandable for debugging

Testing

# Unit tests
npm test src/components/common/ErrorToast.test.tsx

# Integration test - simulate failure
curl -X POST http://localhost:8000/api/collections/{id}/reindex
# WebSocket should receive failure update
# UI should show error toast with remediation

Effort

6 hours

Dependencies

Related Issues

Files to Create/Modify

  • frontend/src/components/common/ErrorToast.tsx (new)
  • frontend/src/components/collections/ReindexProgressModal.tsx (new)
  • frontend/src/utils/errorMessages.ts (new)
  • frontend/src/pages/CollectionDetailPage.tsx
  • frontend/src/hooks/useJobStatus.ts (new - WebSocket hook)

Metadata

Metadata

Assignees

No one assigned

    Labels

    chatChat and conversational interface featuresenhancementNew feature or requestfrontendFrontend/UI relatedpriority:criticalCritical priority - blocks production

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions