From 0536ce97559fd482268e3976c8cc77987d481575 Mon Sep 17 00:00:00 2001 From: loveuer Date: Thu, 13 Nov 2025 15:27:54 +0800 Subject: [PATCH] feat: add delete functionality for namespace resources --- frontend/src/pages/K8sResourceList.tsx | 28 ++++++++++++++++++----- internal/api/api.go | 1 + internal/module/k8s/handler.resource.go | 30 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/frontend/src/pages/K8sResourceList.tsx b/frontend/src/pages/K8sResourceList.tsx index e201ddb..c635edd 100644 --- a/frontend/src/pages/K8sResourceList.tsx +++ b/frontend/src/pages/K8sResourceList.tsx @@ -198,6 +198,10 @@ export default function K8sResourceList() { try { let endpoint = ''; let kind = ''; + let requestBody = { + name: deleteTarget.name, + namespace: deleteTarget.namespace + }; // Determine the correct endpoint based on the selected resource kind switch (selectedKind.key) { @@ -221,6 +225,12 @@ export default function K8sResourceList() { endpoint = '/api/v1/k8s/configmap/delete' kind = 'ConfigMap' break + case 'namespace': + endpoint = '/api/v1/k8s/namespace/delete' + kind = 'Namespace' + // Namespace doesn't need namespace field + requestBody = { name: deleteTarget.name } + break default: throw new Error(`Unsupported resource kind: ${selectedKind.key}`) } @@ -228,10 +238,7 @@ export default function K8sResourceList() { const res = await fetch(endpoint, { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - name: deleteTarget.name, - namespace: deleteTarget.namespace - }), + body: JSON.stringify(requestBody), }) const result = await res.json() @@ -381,7 +388,7 @@ export default function K8sResourceList() { const getResourceColumns = () => { switch (selectedKind.key) { case 'namespace': - return ['Name', 'Status', 'Age'] + return ['Name', 'Status', 'Age', 'Actions'] case 'deployment': case 'statefulset': return ['Name', 'Namespace', 'Replicas', 'Age', 'Actions'] @@ -421,6 +428,17 @@ export default function K8sResourceList() { {metadata.name || '-'} {status.phase || '-'} {getAge(metadata.creationTimestamp)} + + + openDeleteDialog(metadata.name, metadata.namespace)} + > + + + + ) case 'deployment': diff --git a/internal/api/api.go b/internal/api/api.go index 8271afe..9ac6ce2 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -71,6 +71,7 @@ func Init(ctx context.Context, address string, db *gorm.DB, store store.Store) ( k8sAPI.Post("/resource/update", k8s.K8sResourceUpdate(ctx, db, store)) // resource list k8sAPI.Get("/namespace/list", k8s.K8sNamespaceList(ctx, db, store)) + k8sAPI.Delete("/namespace/delete", k8s.K8sNamespaceDelete(ctx, db, store)) k8sAPI.Get("/deployment/list", k8s.K8sDeploymentList(ctx, db, store)) k8sAPI.Delete("/deployment/delete", k8s.K8sDeploymentDelete(ctx, db, store)) k8sAPI.Get("/statefulset/list", k8s.K8sStatefulSetList(ctx, db, store)) diff --git a/internal/module/k8s/handler.resource.go b/internal/module/k8s/handler.resource.go index 2ecc8b1..8fcb4a1 100644 --- a/internal/module/k8s/handler.resource.go +++ b/internal/module/k8s/handler.resource.go @@ -927,3 +927,33 @@ func K8sConfigMapDelete(ctx context.Context, db *gorm.DB, store store.Store) fib }) } } + +func K8sNamespaceDelete(ctx context.Context, db *gorm.DB, store store.Store) fiber.Handler { + return func(c fiber.Ctx) error { + var req struct { + Name string `json:"name"` + } + + if err := json.Unmarshal(c.Body(), &req); err != nil { + return resp.R400(c, "", nil, err) + } + + if req.Name == "" { + return resp.R400(c, "", nil, fmt.Errorf("name is required")) + } + + clientset, err := getK8sClient(db) + if err != nil { + return resp.R500(c, "", nil, err) + } + + err = clientset.CoreV1().Namespaces().Delete(c.Context(), req.Name, metav1.DeleteOptions{}) + if err != nil { + return resp.R500(c, "", nil, fmt.Errorf("failed to delete namespace: %w", err)) + } + + return resp.R200(c, map[string]any{ + "name": req.Name, + }) + } +}