diff --git a/src/components/extractions/ExtractionsRow.tsx b/src/components/extractions/ExtractionsRow.tsx
index 56e8ebd..191aa4e 100644
--- a/src/components/extractions/ExtractionsRow.tsx
+++ b/src/components/extractions/ExtractionsRow.tsx
@@ -1,7 +1,15 @@
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog'
import { TableCell, TableRow } from '@/components/ui/table'
-import type { ExtractionInfo } from '@/lib/api/services/extractions'
+import { extractionsService, type ExtractionInfo } from '@/lib/api/services/extractions'
import { formatDateDistanceToNow } from '@/utils/format-date'
import {
AlertCircle,
@@ -10,14 +18,44 @@ import {
Clock,
ExternalLink,
Loader2,
+ Trash2,
User
} from 'lucide-react'
+import { useState } from 'react'
+import { toast } from 'sonner'
interface ExtractionsRowProps {
extraction: ExtractionInfo
+ onExtractionDeleted?: (extractionId: number) => void
}
-export function ExtractionsRow({ extraction }: ExtractionsRowProps) {
+export function ExtractionsRow({ extraction, onExtractionDeleted }: ExtractionsRowProps) {
+ const [showDeleteDialog, setShowDeleteDialog] = useState(false)
+ const [deleteLoading, setDeleteLoading] = useState(false)
+
+ const handleDeleteExtraction = async () => {
+ if (!extraction.id) return
+
+ try {
+ setDeleteLoading(true)
+ const response = await extractionsService.deleteExtraction(extraction.id)
+ toast.success(response.message)
+
+ // Close dialog
+ setShowDeleteDialog(false)
+
+ // Notify parent component
+ if (onExtractionDeleted) {
+ onExtractionDeleted(extraction.id)
+ }
+ } catch (error) {
+ const errorMessage =
+ error instanceof Error ? error.message : 'Failed to delete extraction'
+ toast.error(errorMessage)
+ } finally {
+ setDeleteLoading(false)
+ }
+ }
const getStatusBadge = (status: ExtractionInfo['status']) => {
switch (status) {
case 'pending':
@@ -75,6 +113,7 @@ export function ExtractionsRow({ extraction }: ExtractionsRowProps) {
}
return (
+ <>
@@ -128,8 +167,64 @@ export function ExtractionsRow({ extraction }: ExtractionsRowProps) {
+
+
+
+ >
)
}
\ No newline at end of file
diff --git a/src/components/extractions/ExtractionsTable.tsx b/src/components/extractions/ExtractionsTable.tsx
index 3091430..8ce2bfa 100644
--- a/src/components/extractions/ExtractionsTable.tsx
+++ b/src/components/extractions/ExtractionsTable.tsx
@@ -10,9 +10,10 @@ import type { ExtractionInfo } from '@/lib/api/services/extractions'
interface ExtractionsTableProps {
extractions: ExtractionInfo[]
+ onExtractionDeleted?: (extractionId: number) => void
}
-export function ExtractionsTable({ extractions }: ExtractionsTableProps) {
+export function ExtractionsTable({ extractions, onExtractionDeleted }: ExtractionsTableProps) {
return (
@@ -31,6 +32,7 @@ export function ExtractionsTable({ extractions }: ExtractionsTableProps) {
))}
diff --git a/src/lib/api/services/extractions.ts b/src/lib/api/services/extractions.ts
index 30f3a27..447996f 100644
--- a/src/lib/api/services/extractions.ts
+++ b/src/lib/api/services/extractions.ts
@@ -41,6 +41,10 @@ export interface GetExtractionsParams {
limit?: number
}
+export interface DeleteExtractionResponse {
+ message: string
+}
+
export class ExtractionsService {
/**
* Create a new extraction job
@@ -135,6 +139,16 @@ export class ExtractionsService {
)
return response
}
+
+ /**
+ * Delete an extraction
+ */
+ async deleteExtraction(extractionId: number): Promise {
+ const response = await apiClient.delete(
+ `/api/v1/extractions/${extractionId}`
+ )
+ return response
+ }
}
export const extractionsService = new ExtractionsService()
diff --git a/src/pages/ExtractionsPage.tsx b/src/pages/ExtractionsPage.tsx
index 74216ca..c1c4ca8 100644
--- a/src/pages/ExtractionsPage.tsx
+++ b/src/pages/ExtractionsPage.tsx
@@ -159,6 +159,23 @@ export function ExtractionsPage() {
setShowCreateDialog(false)
}
+ const handleExtractionDeleted = (extractionId: number) => {
+ // Remove the deleted extraction from the current list
+ setExtractions(prev => prev.filter(extraction => extraction.id !== extractionId))
+
+ // Update total count
+ setTotalCount(prev => prev - 1)
+
+ // If current page is now empty and not the first page, go to previous page
+ const remainingOnCurrentPage = extractions.length - 1
+ if (remainingOnCurrentPage === 0 && currentPage > 1) {
+ setCurrentPage(currentPage - 1)
+ }
+
+ // Refresh the full list to ensure accuracy
+ fetchExtractions()
+ }
+
const renderContent = () => {
if (loading) {
return
@@ -174,7 +191,10 @@ export function ExtractionsPage() {
return (