|
1 | 1 | import { useState } from 'react' |
2 | 2 | import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' |
3 | | -import { Trash2, CheckCircle2, XCircle, CheckSquare, Square, Terminal } from 'lucide-react' |
| 3 | +import { Trash2, CheckCircle2, XCircle, CheckSquare, Square, Terminal, RotateCcw } from 'lucide-react' |
4 | 4 | import { api } from '@/lib/api' |
5 | 5 | import { useApp } from '@/contexts/AppContext' |
6 | 6 | import { Button } from '@/components/ui/button' |
@@ -76,6 +76,31 @@ export default function HistoryPage() { |
76 | 76 | }, |
77 | 77 | }) |
78 | 78 |
|
| 79 | + const retryMutation = useMutation({ |
| 80 | + mutationFn: (id: string) => api.retryTask(id), |
| 81 | + onSuccess: () => { |
| 82 | + queryClient.invalidateQueries({ queryKey: ['tasks'] }) |
| 83 | + showToast(t.history.retrySuccess, 'success') |
| 84 | + }, |
| 85 | + onError: () => { |
| 86 | + showToast(t.history.retryFailed, 'error') |
| 87 | + }, |
| 88 | + }) |
| 89 | + |
| 90 | + const retryMultipleMutation = useMutation({ |
| 91 | + mutationFn: async (ids: string[]) => { |
| 92 | + await Promise.all(ids.map(id => api.retryTask(id))) |
| 93 | + }, |
| 94 | + onSuccess: () => { |
| 95 | + queryClient.invalidateQueries({ queryKey: ['tasks'] }) |
| 96 | + showToast(t.history.retryMultipleSuccess, 'success') |
| 97 | + setSelectedTasks([]) |
| 98 | + }, |
| 99 | + onError: () => { |
| 100 | + showToast(t.history.retryFailed, 'error') |
| 101 | + }, |
| 102 | + }) |
| 103 | + |
79 | 104 | const handleDelete = (id: string) => { |
80 | 105 | setTaskToDelete(id) |
81 | 106 | setDeleteConfirmOpen(true) |
@@ -152,14 +177,25 @@ export default function HistoryPage() { |
152 | 177 | </div> |
153 | 178 | <div className="flex gap-2"> |
154 | 179 | {selectedTasks.length > 0 && ( |
155 | | - <Button |
156 | | - variant="destructive" |
157 | | - size="sm" |
158 | | - onClick={handleDeleteSelected} |
159 | | - > |
160 | | - <Trash2 className="h-4 w-4 mr-1" /> |
161 | | - {t.history.deleteSelected} ({selectedTasks.length}) |
162 | | - </Button> |
| 180 | + <> |
| 181 | + <Button |
| 182 | + variant="default" |
| 183 | + size="sm" |
| 184 | + onClick={() => retryMultipleMutation.mutate(selectedTasks)} |
| 185 | + disabled={retryMultipleMutation.isPending} |
| 186 | + > |
| 187 | + <RotateCcw className={cn("h-4 w-4 mr-1", retryMultipleMutation.isPending && "animate-spin")} /> |
| 188 | + {t.history.retrySelected} ({selectedTasks.length}) |
| 189 | + </Button> |
| 190 | + <Button |
| 191 | + variant="destructive" |
| 192 | + size="sm" |
| 193 | + onClick={handleDeleteSelected} |
| 194 | + > |
| 195 | + <Trash2 className="h-4 w-4 mr-1" /> |
| 196 | + {t.history.deleteSelected} ({selectedTasks.length}) |
| 197 | + </Button> |
| 198 | + </> |
163 | 199 | )} |
164 | 200 | {completedTasks.length > 0 && ( |
165 | 201 | <Button |
@@ -474,6 +510,16 @@ export default function HistoryPage() { |
474 | 510 |
|
475 | 511 | {/* Actions */} |
476 | 512 | <div className="pt-3 border-t space-y-2"> |
| 513 | + <Button |
| 514 | + variant="default" |
| 515 | + size="sm" |
| 516 | + onClick={() => retryMutation.mutate(selectedTask.id)} |
| 517 | + disabled={retryMutation.isPending} |
| 518 | + className="w-full" |
| 519 | + > |
| 520 | + <RotateCcw className={cn("h-4 w-4 mr-1", retryMutation.isPending && "animate-spin")} /> |
| 521 | + {t.history.retryTask} |
| 522 | + </Button> |
477 | 523 | <Button |
478 | 524 | variant="outline" |
479 | 525 | size="sm" |
|
0 commit comments