62 lines
1.6 KiB
TypeScript
62 lines
1.6 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import { toast } from "sonner";
|
||
import { Square } from "lucide-react";
|
||
import { api, ApiError } from "@/components/api";
|
||
import { ConfirmDialog } from "@/components/confirm-dialog";
|
||
import { Button } from "@/components/ui/button";
|
||
|
||
interface StopRunButtonProps {
|
||
runId: number;
|
||
onStopped?: () => void;
|
||
}
|
||
|
||
export function StopRunButton({ runId, onStopped }: StopRunButtonProps) {
|
||
const [open, setOpen] = useState(false);
|
||
const [loading, setLoading] = useState(false);
|
||
|
||
async function stop() {
|
||
setLoading(true);
|
||
try {
|
||
await api(`/api/runs/${runId}/stop`, { method: "POST" });
|
||
toast.success("已发送停止请求");
|
||
setOpen(false);
|
||
onStopped?.();
|
||
} catch (e) {
|
||
if (e instanceof ApiError && e.status === 409) {
|
||
toast.info("运行已结束");
|
||
setOpen(false);
|
||
onStopped?.();
|
||
} else {
|
||
toast.error(e instanceof Error ? e.message : "停止失败");
|
||
}
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
className="border-red-500/40 text-red-600 hover:bg-red-500/10 hover:text-red-600 dark:text-red-400 dark:hover:text-red-400"
|
||
onClick={() => setOpen(true)}
|
||
>
|
||
<Square className="size-4" />
|
||
停止
|
||
</Button>
|
||
<ConfirmDialog
|
||
open={open}
|
||
onOpenChange={setOpen}
|
||
title={`停止运行 #${runId}?`}
|
||
description="停止后已迁移的部分数据会保留在目标库,确定停止?"
|
||
confirmText="停止"
|
||
loading={loading}
|
||
onConfirm={stop}
|
||
/>
|
||
</>
|
||
);
|
||
}
|