фикс задач
This commit is contained in:
parent
de0a28ad62
commit
3440c45089
2 changed files with 42 additions and 8 deletions
|
|
@ -74,11 +74,12 @@ export const useTasks = (page = 1, pageSize = 50) =>
|
|||
refetchInterval: 5000,
|
||||
})
|
||||
|
||||
export const useTask = (id: string | undefined) =>
|
||||
export const useTask = (id: string | undefined, options?: { refetchInterval?: number | false }) =>
|
||||
useQuery({
|
||||
queryKey: ['tasks', id],
|
||||
queryFn: () => api.get<TaskDetail>(`/api/v1/tasks/${id}`).then((r) => r.data),
|
||||
enabled: !!id,
|
||||
refetchInterval: options?.refetchInterval,
|
||||
})
|
||||
|
||||
// Subscribe to SSE for a running task — merges results in cache, invalidates on completion.
|
||||
|
|
|
|||
|
|
@ -78,10 +78,17 @@ function groupBy<T>(items: T[], key: (item: T) => string): Record<string, T[]> {
|
|||
export function TaskDetailPage() {
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const navigate = useNavigate()
|
||||
const { data: task, isLoading } = useTask(id)
|
||||
const [isActive, setIsActive] = useState(true)
|
||||
const { data: task, isLoading } = useTask(id, { refetchInterval: isActive ? 3000 : false })
|
||||
const cancelTask = useCancelTask()
|
||||
const createTask = useCreateTask()
|
||||
|
||||
useEffect(() => {
|
||||
if (task) {
|
||||
setIsActive(task.status === 'pending' || task.status === 'running')
|
||||
}
|
||||
}, [task?.status])
|
||||
|
||||
const [log, setLog] = useState<LogLine[]>([])
|
||||
const [liveResults, setLiveResults] = useState<Record<number, DeviceResultState>>({})
|
||||
const [totalDevices, setTotalDevices] = useState<number | null>(null)
|
||||
|
|
@ -124,13 +131,40 @@ export function TaskDetailPage() {
|
|||
|
||||
// Merge DB results with live SSE updates
|
||||
const mergedResults = useMemo<(TaskResult & Partial<DeviceResultState>)[]>(() => {
|
||||
if (!task?.device_results) return []
|
||||
return task.device_results.map((r) => {
|
||||
const dbResults = task?.device_results ?? []
|
||||
const merged = dbResults.map((r) => {
|
||||
const live = liveResults[r.device_id]
|
||||
return live ? { ...r, ...live } : r
|
||||
})
|
||||
const dbDeviceIds = new Set(dbResults.map((r) => r.device_id))
|
||||
for (const [deviceId, live] of Object.entries(liveResults)) {
|
||||
const id = Number(deviceId)
|
||||
if (!dbDeviceIds.has(id)) {
|
||||
merged.push({
|
||||
id: 0,
|
||||
device_id: id,
|
||||
device_ip: live.device_ip,
|
||||
device_hostname: live.device_hostname,
|
||||
object_id: null,
|
||||
object_name: null,
|
||||
rack_id: null,
|
||||
rack_name: null,
|
||||
status: live.status,
|
||||
stdout: live.stdout,
|
||||
stderr: live.stderr,
|
||||
exit_code: null,
|
||||
data: null,
|
||||
duration_ms: live.duration_ms,
|
||||
executed_at: null,
|
||||
})
|
||||
}
|
||||
}
|
||||
return merged
|
||||
}, [task?.device_results, liveResults])
|
||||
|
||||
// Fallback: derive totalDevices from task.result or device_results count
|
||||
const effectiveTotal = totalDevices ?? task?.result?.total ?? (mergedResults.length > 0 ? mergedResults.length : null)
|
||||
|
||||
// Determine if results span multiple objects
|
||||
const multiObject = useMemo(() => {
|
||||
const objIds = new Set(mergedResults.map((r) => r.object_id).filter(Boolean))
|
||||
|
|
@ -186,7 +220,6 @@ export function TaskDetailPage() {
|
|||
|
||||
if (isLoading) return <Spin />
|
||||
|
||||
const isActive = task?.status === 'pending' || task?.status === 'running'
|
||||
const canCancel = isActive && !task?.cancel_requested
|
||||
|
||||
const resultColumns = [
|
||||
|
|
@ -347,13 +380,13 @@ export function TaskDetailPage() {
|
|||
</Col>
|
||||
</Row>
|
||||
|
||||
{totalDevices != null && totalDevices > 0 && (
|
||||
{effectiveTotal != null && effectiveTotal > 0 && (
|
||||
<Row style={{ marginBottom: 16 }}>
|
||||
<Col span={24}>
|
||||
{(() => {
|
||||
const completed = mergedResults.filter((r) => r.status !== 'running').length
|
||||
const failed = mergedResults.filter((r) => r.status === 'failed').length
|
||||
const percent = Math.round((completed / totalDevices) * 100)
|
||||
const percent = Math.round((completed / effectiveTotal) * 100)
|
||||
const isDone = !isActive
|
||||
const progressStatus = isDone
|
||||
? (failed > 0 ? 'exception' : 'success')
|
||||
|
|
@ -362,7 +395,7 @@ export function TaskDetailPage() {
|
|||
<Progress
|
||||
percent={percent}
|
||||
status={progressStatus}
|
||||
format={() => `${completed} / ${totalDevices}`}
|
||||
format={() => `${completed} / ${effectiveTotal}`}
|
||||
strokeColor={failed > 0 ? undefined : '#52c41a'}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue