diff --git a/packages/core/api/client.ts b/packages/core/api/client.ts index ec6ac4433..e09dd59da 100644 --- a/packages/core/api/client.ts +++ b/packages/core/api/client.ts @@ -869,6 +869,12 @@ export class ApiClient { ); } + async deleteCloudRuntimeNode(nodeId: string): Promise { + await this.fetch(`/api/cloud-runtime/nodes/${nodeId}`, { + method: "DELETE", + }); + } + async deleteRuntime(runtimeId: string): Promise { await this.fetch(`/api/runtimes/${runtimeId}`, { method: "DELETE" }); } diff --git a/packages/core/runtimes/cloud-runtime.ts b/packages/core/runtimes/cloud-runtime.ts index 7a8a1ec3e..986b6e824 100644 --- a/packages/core/runtimes/cloud-runtime.ts +++ b/packages/core/runtimes/cloud-runtime.ts @@ -79,3 +79,13 @@ export function useCreateCloudRuntimeNode(wsId: string) { }, }); } + +export function useDeleteCloudRuntimeNode(wsId: string) { + const qc = useQueryClient(); + return useMutation({ + mutationFn: (nodeId: string) => api.deleteCloudRuntimeNode(nodeId), + onSettled: () => { + qc.invalidateQueries({ queryKey: cloudRuntimeKeys.all(wsId) }); + }, + }); +} diff --git a/packages/views/locales/en/runtimes.json b/packages/views/locales/en/runtimes.json index 444a317b1..29dfb47bf 100644 --- a/packages/views/locales/en/runtimes.json +++ b/packages/views/locales/en/runtimes.json @@ -172,6 +172,10 @@ "cancel": "Cancel", "toast_created": "Cloud Runtime node created", "toast_create_failed": "Failed to create Cloud Runtime node", + "delete": "Delete node", + "delete_confirm": "Are you sure you want to delete this cloud node? This action cannot be undone.", + "toast_deleted": "Cloud node deleted", + "toast_delete_failed": "Failed to delete cloud node", "fields": { "name": "Name", "instance_type": "Instance type", diff --git a/packages/views/locales/zh-Hans/runtimes.json b/packages/views/locales/zh-Hans/runtimes.json index b27509533..d9266bc5a 100644 --- a/packages/views/locales/zh-Hans/runtimes.json +++ b/packages/views/locales/zh-Hans/runtimes.json @@ -163,6 +163,10 @@ "cancel": "取消", "toast_created": "Cloud Runtime 节点已创建", "toast_create_failed": "创建 Cloud Runtime 节点失败", + "delete": "删除节点", + "delete_confirm": "确定要删除此云节点吗?此操作无法撤销。", + "toast_deleted": "云节点已删除", + "toast_delete_failed": "删除云节点失败", "fields": { "name": "名称", "instance_type": "实例规格", diff --git a/packages/views/runtimes/components/cloud-runtime-dialog.tsx b/packages/views/runtimes/components/cloud-runtime-dialog.tsx index 39004fb91..006404939 100644 --- a/packages/views/runtimes/components/cloud-runtime-dialog.tsx +++ b/packages/views/runtimes/components/cloud-runtime-dialog.tsx @@ -3,12 +3,13 @@ import { useId, useMemo, useState } from "react"; import type { FormEvent, HTMLAttributes } from "react"; import { useQuery } from "@tanstack/react-query"; -import { Cloud, Loader2, RefreshCw, Rocket } from "lucide-react"; +import { Cloud, Loader2, RefreshCw, Rocket, Trash2 } from "lucide-react"; import { toast } from "sonner"; import type { CloudRuntimeNode } from "@multica/core/runtimes"; import { cloudRuntimeNodeListOptions, useCreateCloudRuntimeNode, + useDeleteCloudRuntimeNode, } from "@multica/core/runtimes"; import { useWorkspaceId } from "@multica/core/hooks"; import { Badge } from "@multica/ui/components/ui/badge"; @@ -192,7 +193,7 @@ export function CloudRuntimeDialog({ onClose }: { onClose: () => void }) {
{sortedNodes.map((node) => ( - + ))}
@@ -290,8 +291,9 @@ function LabeledInput({ ); } -function CloudRuntimeNodeRow({ node }: { node: CloudRuntimeNode }) { +function CloudRuntimeNodeRow({ node, wsId }: { node: CloudRuntimeNode; wsId: string }) { const { t } = useT("runtimes"); + const deleteNode = useDeleteCloudRuntimeNode(wsId); const title = node.name.trim() || node.instance_id.trim() || @@ -317,6 +319,32 @@ function CloudRuntimeNodeRow({ node }: { node: CloudRuntimeNode }) { )} + {node.instance_id && (