merge: maestro/tsk_PbcHccuPmwxV [任务取消/删除的 UI 入口]
# Conflicts: # web/style.css
This commit is contained in:
@@ -226,6 +226,18 @@ export function buildServer(opts: ApiOptions): FastifyInstance {
|
||||
return store.transition(id, b.to as TaskStatus, b.meta ?? {});
|
||||
});
|
||||
|
||||
// 取消任务(transition → cancelled;状态机已守卫合法流转)
|
||||
app.post('/api/tasks/:id/cancel', (req) => {
|
||||
const { id } = req.params as { id: string };
|
||||
return store.transition(id, 'cancelled', { by: 'user' });
|
||||
});
|
||||
|
||||
// 彻底删除任务及其子孙(不可恢复,cascade)
|
||||
app.delete('/api/tasks/:id', (req) => {
|
||||
const { id } = req.params as { id: string };
|
||||
return store.deleteTask(id);
|
||||
});
|
||||
|
||||
// 审批闸:accept / reject(reject 必带 reason)
|
||||
// exec 闸的 accept = 通过并合并(PR 闭环):先 merge 再 decide;merge 失败 → 400,任务保留在审核闸。
|
||||
app.post('/api/tasks/:id/decide', async (req) => {
|
||||
|
||||
@@ -613,6 +613,43 @@ export class Store {
|
||||
return rows.map(rowToEvent).reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 彻底删除任务及其全部子孙(runs/approvals 由 FK CASCADE 自动清除,events 手动清理)。
|
||||
* 不可恢复——调用方须在上层做二次确认。
|
||||
*/
|
||||
deleteTask(taskId: string): { deleted: number } {
|
||||
const root = this.getTaskRow(taskId);
|
||||
if (!root) throw new StoreError(`任务不存在: ${taskId}`);
|
||||
|
||||
// BFS 收集所有子孙 id(用于清理 events,其他表有 FK ON DELETE CASCADE)
|
||||
const toDelete: string[] = [];
|
||||
const queue: string[] = [taskId];
|
||||
while (queue.length) {
|
||||
const tid = queue.shift()!;
|
||||
toDelete.push(tid);
|
||||
const kids = this.db.prepare(
|
||||
`SELECT id FROM tasks WHERE parent_id = ?`,
|
||||
).all(tid) as Array<{ id: string }>;
|
||||
for (const k of kids) queue.push(k.id);
|
||||
}
|
||||
|
||||
const projectId = root.project_id;
|
||||
const txn = this.db.transaction(() => {
|
||||
// events 没有 FK,逐条清理
|
||||
for (const tid of toDelete) {
|
||||
this.db.prepare(`DELETE FROM events WHERE task_id = ?`).run(tid);
|
||||
}
|
||||
// 删根节点:子孙、runs、approvals 均 ON DELETE CASCADE
|
||||
this.db.prepare(`DELETE FROM tasks WHERE id = ?`).run(taskId);
|
||||
});
|
||||
txn();
|
||||
|
||||
this.emit(projectId, null, 'task.updated', {
|
||||
kind: 'delete', taskId, count: toDelete.length,
|
||||
});
|
||||
return { deleted: toDelete.length };
|
||||
}
|
||||
|
||||
/**
|
||||
* 取下一个可执行任务(叶子、ready、依赖全部 done)。供编排器领取。
|
||||
* 被拆解的 Hard 容器任务不会是 ready(停在 decomposed),天然排除。
|
||||
|
||||
Reference in New Issue
Block a user