Add force rerun recovery and polish CLI startup
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
Table, Tag, Space, Button, Form, Input, Select, Progress, Checkbox, message,
|
||||
Table, Tag, Space, Button, Form, Input, Select, Progress, Checkbox, message, Modal,
|
||||
Drawer, Tabs, Empty, Tooltip, Popconfirm, Collapse, InputNumber, Row, Col, Card
|
||||
} from 'antd'
|
||||
import {
|
||||
@@ -382,30 +382,92 @@ function DataSources() {
|
||||
return () => clearInterval(interval)
|
||||
}, [builtInSources, taskProgress, taskSocketConnected, fetchData])
|
||||
|
||||
const triggerDatasource = async (id: number, options?: { force?: boolean }) => {
|
||||
const force = options?.force ?? false
|
||||
const res = await axios.post(`/api/v1/datasources/${id}/trigger`, null, {
|
||||
params: { force },
|
||||
})
|
||||
|
||||
if (res.data.task_id) {
|
||||
setTaskProgress(prev => ({
|
||||
...prev,
|
||||
[id]: {
|
||||
task_id: res.data.task_id,
|
||||
progress: 0,
|
||||
is_running: true,
|
||||
phase: 'queued',
|
||||
status: 'running',
|
||||
},
|
||||
}))
|
||||
} else {
|
||||
window.setTimeout(() => {
|
||||
fetchData()
|
||||
}, 800)
|
||||
}
|
||||
|
||||
fetchData()
|
||||
return res
|
||||
}
|
||||
|
||||
const confirmForceTrigger = (id: number, taskInfo?: {
|
||||
progress?: number | null
|
||||
phase?: string | null
|
||||
records_processed?: number | null
|
||||
total_records?: number | null
|
||||
message?: string
|
||||
}) => {
|
||||
const progressText = typeof taskInfo?.progress === 'number' ? `${Math.round(taskInfo.progress)}%` : '未知'
|
||||
const phaseText = taskInfo?.phase || 'running'
|
||||
const processedText = typeof taskInfo?.records_processed === 'number'
|
||||
? `${taskInfo.records_processed}${typeof taskInfo?.total_records === 'number' && taskInfo.total_records > 0 ? ` / ${taskInfo.total_records}` : ''}`
|
||||
: '未知'
|
||||
|
||||
Modal.confirm({
|
||||
title: '当前任务未完成',
|
||||
content: (
|
||||
<div>
|
||||
<p>{taskInfo?.message || '当前采集任务仍在运行,重新触发会丢失本次未完成进度。'}</p>
|
||||
<p>当前阶段: {phaseText}</p>
|
||||
<p>当前进度: {progressText}</p>
|
||||
<p>已处理记录: {processedText}</p>
|
||||
<p>确认后会强制取消当前采集,并回滚未完成写入,然后重新开始采集。</p>
|
||||
</div>
|
||||
),
|
||||
okText: '强制重新采集',
|
||||
cancelText: '取消',
|
||||
okButtonProps: { danger: true },
|
||||
onOk: async () => {
|
||||
try {
|
||||
await triggerDatasource(id, { force: true })
|
||||
messageApi.success('已强制重新触发,未完成采集将回滚')
|
||||
} catch (error: unknown) {
|
||||
const err = error as { response?: { data?: { detail?: string | { message?: string } } } }
|
||||
const detail = err.response?.data?.detail
|
||||
messageApi.error(typeof detail === 'string' ? detail : detail?.message || '强制重新采集失败')
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const handleTrigger = async (id: number) => {
|
||||
try {
|
||||
const res = await axios.post(`/api/v1/datasources/${id}/trigger`)
|
||||
await triggerDatasource(id)
|
||||
messageApi.success('任务已触发')
|
||||
if (res.data.task_id) {
|
||||
setTaskProgress(prev => ({
|
||||
...prev,
|
||||
[id]: {
|
||||
task_id: res.data.task_id,
|
||||
progress: 0,
|
||||
is_running: true,
|
||||
phase: 'queued',
|
||||
status: 'running',
|
||||
},
|
||||
}))
|
||||
} else {
|
||||
window.setTimeout(() => {
|
||||
fetchData()
|
||||
}, 800)
|
||||
}
|
||||
fetchData()
|
||||
} catch (error: unknown) {
|
||||
const err = error as { response?: { data?: { detail?: string } } }
|
||||
messageApi.error(err.response?.data?.detail || '触发失败')
|
||||
const err = error as { response?: { status?: number; data?: { detail?: string | {
|
||||
reason?: string
|
||||
message?: string
|
||||
progress?: number | null
|
||||
phase?: string | null
|
||||
records_processed?: number | null
|
||||
total_records?: number | null
|
||||
} } } }
|
||||
const detail = err.response?.data?.detail
|
||||
if (err.response?.status === 409 && typeof detail === 'object' && detail?.reason === 'running_task_in_progress') {
|
||||
confirmForceTrigger(id, detail)
|
||||
return
|
||||
}
|
||||
messageApi.error(typeof detail === 'string' ? detail : detail?.message || '触发失败')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,12 +589,24 @@ function DataSources() {
|
||||
const handleUpdateSource = async () => {
|
||||
if (!viewingSource) return
|
||||
try {
|
||||
await axios.post(`/api/v1/datasources/${viewingSource.id}/trigger`)
|
||||
await triggerDatasource(viewingSource.id)
|
||||
messageApi.success('已触发更新')
|
||||
setViewDrawerVisible(false)
|
||||
} catch (error: unknown) {
|
||||
const err = error as { response?: { data?: { detail?: string } } }
|
||||
messageApi.error(err.response?.data?.detail || '更新失败')
|
||||
const err = error as { response?: { status?: number; data?: { detail?: string | {
|
||||
reason?: string
|
||||
message?: string
|
||||
progress?: number | null
|
||||
phase?: string | null
|
||||
records_processed?: number | null
|
||||
total_records?: number | null
|
||||
} } } }
|
||||
const detail = err.response?.data?.detail
|
||||
if (err.response?.status === 409 && typeof detail === 'object' && detail?.reason === 'running_task_in_progress') {
|
||||
confirmForceTrigger(viewingSource.id, detail)
|
||||
return
|
||||
}
|
||||
messageApi.error(typeof detail === 'string' ? detail : detail?.message || '更新失败')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user