фикс задач
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,
|
refetchInterval: 5000,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const useTask = (id: string | undefined) =>
|
export const useTask = (id: string | undefined, options?: { refetchInterval?: number | false }) =>
|
||||||
useQuery({
|
useQuery({
|
||||||
queryKey: ['tasks', id],
|
queryKey: ['tasks', id],
|
||||||
queryFn: () => api.get<TaskDetail>(`/api/v1/tasks/${id}`).then((r) => r.data),
|
queryFn: () => api.get<TaskDetail>(`/api/v1/tasks/${id}`).then((r) => r.data),
|
||||||
enabled: !!id,
|
enabled: !!id,
|
||||||
|
refetchInterval: options?.refetchInterval,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Subscribe to SSE for a running task — merges results in cache, invalidates on completion.
|
// 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() {
|
export function TaskDetailPage() {
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams<{ id: string }>()
|
||||||
const navigate = useNavigate()
|
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 cancelTask = useCancelTask()
|
||||||
const createTask = useCreateTask()
|
const createTask = useCreateTask()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (task) {
|
||||||
|
setIsActive(task.status === 'pending' || task.status === 'running')
|
||||||
|
}
|
||||||
|
}, [task?.status])
|
||||||
|
|
||||||
const [log, setLog] = useState<LogLine[]>([])
|
const [log, setLog] = useState<LogLine[]>([])
|
||||||
const [liveResults, setLiveResults] = useState<Record<number, DeviceResultState>>({})
|
const [liveResults, setLiveResults] = useState<Record<number, DeviceResultState>>({})
|
||||||
const [totalDevices, setTotalDevices] = useState<number | null>(null)
|
const [totalDevices, setTotalDevices] = useState<number | null>(null)
|
||||||
|
|
@ -124,13 +131,40 @@ export function TaskDetailPage() {
|
||||||
|
|
||||||
// Merge DB results with live SSE updates
|
// Merge DB results with live SSE updates
|
||||||
const mergedResults = useMemo<(TaskResult & Partial<DeviceResultState>)[]>(() => {
|
const mergedResults = useMemo<(TaskResult & Partial<DeviceResultState>)[]>(() => {
|
||||||
if (!task?.device_results) return []
|
const dbResults = task?.device_results ?? []
|
||||||
return task.device_results.map((r) => {
|
const merged = dbResults.map((r) => {
|
||||||
const live = liveResults[r.device_id]
|
const live = liveResults[r.device_id]
|
||||||
return live ? { ...r, ...live } : r
|
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])
|
}, [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
|
// Determine if results span multiple objects
|
||||||
const multiObject = useMemo(() => {
|
const multiObject = useMemo(() => {
|
||||||
const objIds = new Set(mergedResults.map((r) => r.object_id).filter(Boolean))
|
const objIds = new Set(mergedResults.map((r) => r.object_id).filter(Boolean))
|
||||||
|
|
@ -186,7 +220,6 @@ export function TaskDetailPage() {
|
||||||
|
|
||||||
if (isLoading) return <Spin />
|
if (isLoading) return <Spin />
|
||||||
|
|
||||||
const isActive = task?.status === 'pending' || task?.status === 'running'
|
|
||||||
const canCancel = isActive && !task?.cancel_requested
|
const canCancel = isActive && !task?.cancel_requested
|
||||||
|
|
||||||
const resultColumns = [
|
const resultColumns = [
|
||||||
|
|
@ -347,13 +380,13 @@ export function TaskDetailPage() {
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{totalDevices != null && totalDevices > 0 && (
|
{effectiveTotal != null && effectiveTotal > 0 && (
|
||||||
<Row style={{ marginBottom: 16 }}>
|
<Row style={{ marginBottom: 16 }}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
{(() => {
|
{(() => {
|
||||||
const completed = mergedResults.filter((r) => r.status !== 'running').length
|
const completed = mergedResults.filter((r) => r.status !== 'running').length
|
||||||
const failed = mergedResults.filter((r) => r.status === 'failed').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 isDone = !isActive
|
||||||
const progressStatus = isDone
|
const progressStatus = isDone
|
||||||
? (failed > 0 ? 'exception' : 'success')
|
? (failed > 0 ? 'exception' : 'success')
|
||||||
|
|
@ -362,7 +395,7 @@ export function TaskDetailPage() {
|
||||||
<Progress
|
<Progress
|
||||||
percent={percent}
|
percent={percent}
|
||||||
status={progressStatus}
|
status={progressStatus}
|
||||||
format={() => `${completed} / ${totalDevices}`}
|
format={() => `${completed} / ${effectiveTotal}`}
|
||||||
strokeColor={failed > 0 ? undefined : '#52c41a'}
|
strokeColor={failed > 0 ? undefined : '#52c41a'}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue