diff --git a/service/index.html b/service/index.html
index 2990eb5..a5d70fd 100644
--- a/service/index.html
+++ b/service/index.html
@@ -2359,6 +2359,9 @@ A+B
history_empty: "还没有历史任务。",
history_load: "载入",
history_delete: "删除",
+ history_cancel: "终止",
+ history_cancel_confirm: "确定要终止这个正在运行的任务吗?终止后不可恢复。",
+ history_cancel_success: "任务终止请求已发送",
history_mode_tube: "Tube",
history_mode_complex: "Complex",
count_complexes: "个复合物",
@@ -2711,6 +2714,9 @@ A+B
history_empty: "No saved jobs yet.",
history_load: "Load",
history_delete: "Delete",
+ history_cancel: "Terminate",
+ history_cancel_confirm: "Terminate this running job? This cannot be undone.",
+ history_cancel_success: "Job termination requested",
history_mode_tube: "Tube",
history_mode_complex: "Complex",
count_complexes: "complexes",
@@ -3967,6 +3973,17 @@ A+B
await refreshAccountWorkspace();
}
+ async function cancelHistoryJob(id) {
+ if (!window.confirm(t("history_cancel_confirm"))) return;
+ const { response, data } = await fetchJsonOrThrow(`/api/jobs/${encodeURIComponent(id)}/cancel`, { method: "POST" });
+ if (!response.ok || data.status !== "success") {
+ throw new Error(data?.error || `Cancel failed with HTTP ${response.status}`);
+ }
+ setStatus(formatStatus(t("history_cancel_success")));
+ await refreshAccountWorkspace();
+ refreshHealth();
+ }
+
async function fetchAllHistory() {
const items = [];
let offset = 0;
@@ -4180,6 +4197,7 @@ A+B
+ ${["queued", "running"].includes(item.status) ? `` : ""}
${["queued", "running", "cancel_requested"].includes(item.status) ? "" : ``}
@@ -4196,6 +4214,9 @@ A+B
historyList.querySelectorAll("[data-history-delete]").forEach((button) => {
button.addEventListener("click", () => deleteHistory(button.dataset.historyDelete).catch((error) => setStatus(error.message, true)));
});
+ historyList.querySelectorAll("[data-history-cancel]").forEach((button) => {
+ button.addEventListener("click", () => cancelHistoryJob(button.dataset.historyCancel).catch((error) => setStatus(`${t("cancel_job_failed")}: ${error.message}`, true)));
+ });
historyList.querySelectorAll("[data-history-export]").forEach((button) => {
button.addEventListener("click", () => exportHistoryItem(button.dataset.historyExport).catch((error) => setStatus(error.message, true)));
});