diff --git a/mateclaw-ui/src/api/index.ts b/mateclaw-ui/src/api/index.ts index fae0e38d..e4db5ef2 100644 --- a/mateclaw-ui/src/api/index.ts +++ b/mateclaw-ui/src/api/index.ts @@ -825,6 +825,42 @@ export interface WorkflowRunStep { completedAt?: string } +/** Pause record carried inline on a paused run so the UI can resume + * without a second roundtrip. Mirrors mate_workflow_run_pause. */ +export interface WorkflowRunPause { + id: number + runId: number + stepId?: number + pauseKind: string + pauseToken: string + externalApprovalId?: number + pausedAt: string + resumeDeadline?: string + resumePayloadRef?: string + resumedAt?: string + resumeOutcome?: string +} + +export interface PausedRunSummary { + run: WorkflowRun + pause: WorkflowRunPause | null +} + +export interface RunDetail { + run: WorkflowRun + steps: WorkflowRunStep[] + /** Most recent unresolved pause record; null when the run is not paused. */ + activePause: WorkflowRunPause | null +} + +export type ResumeOutcome = 'approved' | 'rejected' | 'timeout' | 'cancelled' + +export interface ResumeResponse { + kind: string + runId?: number | null + errorMessage?: string | null +} + export const workflowApi = { list: (workspaceId: number) => http.get('/workflows', { params: { workspaceId } }), @@ -844,7 +880,17 @@ export const workflowApi = { runs: (id: number, limit = 50) => http.get(`/workflows/${id}/runs`, { params: { limit } }), runDetail: (runId: number) => - http.get<{ run: WorkflowRun; steps: WorkflowRunStep[] }>(`/workflows/runs/${runId}`), + http.get(`/workflows/runs/${runId}`), + /** List paused runs across the workspace so operators can resume them. */ + listPausedRuns: (limit = 50) => + http.get('/workflows/runs/paused', { params: { limit } }), + /** Resume a paused workflow run with one of the four documented outcomes. */ + resumeRun: (runId: number, pauseToken: string, outcome: ResumeOutcome, payload?: string) => + http.post(`/workflows/runs/${runId}/resume`, { + pauseToken, + outcome, + payload, + }), } // ==================== Trigger ==================== diff --git a/mateclaw-ui/src/i18n/locales/en-US.ts b/mateclaw-ui/src/i18n/locales/en-US.ts index ac5101b9..c278437a 100644 --- a/mateclaw-ui/src/i18n/locales/en-US.ts +++ b/mateclaw-ui/src/i18n/locales/en-US.ts @@ -2015,6 +2015,20 @@ export default { deleteContent: 'Delete workflow "{name}"? This is reversible via the audit log.', }, selectHint: 'Select a workflow on the left, or click "New Workflow" to start a fresh draft.', + paused: { + header: 'Paused runs ({count})', + empty: 'No paused runs.', + pauseTokenLabel: 'pause token', + deadlineLabel: 'deadline', + pausedAtLabel: 'paused at', + runHash: 'Run #{id}', + resumeApproved: 'Approve', + resumeRejected: 'Reject', + resumeTimeout: 'Time out', + resumeCancelled: 'Cancel', + resumeOk: 'Run resumed ({outcome}).', + resumeFailed: 'Resume failed: {msg}', + }, runs: { header: 'Recent runs ({count})', empty: 'No runs yet.', diff --git a/mateclaw-ui/src/i18n/locales/zh-CN.ts b/mateclaw-ui/src/i18n/locales/zh-CN.ts index f88b4204..b51067ea 100644 --- a/mateclaw-ui/src/i18n/locales/zh-CN.ts +++ b/mateclaw-ui/src/i18n/locales/zh-CN.ts @@ -2027,6 +2027,20 @@ export default { deleteContent: '将删除工作流「{name}」?此操作可通过审计日志撤销。', }, selectHint: '在左侧选择一个工作流,或点击「新建工作流」开始。', + paused: { + header: '待恢复运行 ({count})', + empty: '当前没有暂停中的运行。', + pauseTokenLabel: 'pause token', + deadlineLabel: '超时时间', + pausedAtLabel: '暂停于', + runHash: 'Run #{id}', + resumeApproved: '通过', + resumeRejected: '拒绝', + resumeTimeout: '标记超时', + resumeCancelled: '取消', + resumeOk: '运行已恢复 ({outcome})。', + resumeFailed: '恢复失败:{msg}', + }, runs: { header: '近期运行 ({count})', empty: '暂无运行记录。', diff --git a/mateclaw-ui/src/views/Workflows.vue b/mateclaw-ui/src/views/Workflows.vue index beba5510..b958cc89 100644 --- a/mateclaw-ui/src/views/Workflows.vue +++ b/mateclaw-ui/src/views/Workflows.vue @@ -122,6 +122,49 @@