From 846be505aac544bd3e4b66020b7b6ef1c6cdd3c0 Mon Sep 17 00:00:00 2001 From: Julian Haupt Date: Tue, 16 Jun 2026 23:39:57 +0200 Subject: [PATCH] deployments: delete deployments from details --- public/locales/de-DE/translation.json | 2 ++ public/locales/en-US/translation.json | 2 ++ public/locales/es-ES/translation.json | 2 ++ public/locales/fr-FR/translation.json | 2 ++ public/locales/nl-NL/translation.json | 2 ++ src/pages/Deployments.jsx | 31 ++++++++++++++++++++++++++- src/pages/Deployments.test.jsx | 20 ++++++++++++++++- 7 files changed, 59 insertions(+), 2 deletions(-) diff --git a/public/locales/de-DE/translation.json b/public/locales/de-DE/translation.json index 5f7d6a9..34b33b8 100644 --- a/public/locales/de-DE/translation.json +++ b/public/locales/de-DE/translation.json @@ -440,6 +440,8 @@ "empty-response": "Leere Antwort", "form-preview": "Formularvorschau", "raw-data-json": "Rohdaten (JSON)", + "delete": "Deployment löschen", + "confirm-delete": "Dieses Deployment und alle zugehörigen Prozessinstanzen, historischen Prozessinstanzen und Jobs löschen?", "sort": { "deploymentTime": "Deployment-Zeit", "name": "Name", diff --git a/public/locales/en-US/translation.json b/public/locales/en-US/translation.json index ac20fbe..42b31a5 100644 --- a/public/locales/en-US/translation.json +++ b/public/locales/en-US/translation.json @@ -440,6 +440,8 @@ "empty-response": "Empty response", "form-preview": "Form preview", "raw-data-json": "Raw data (JSON)", + "delete": "Delete deployment", + "confirm-delete": "Delete this deployment and all process instances, historic process instances, and jobs for it?", "sort": { "deploymentTime": "Deployment time", "name": "Name", diff --git a/public/locales/es-ES/translation.json b/public/locales/es-ES/translation.json index 121792c..5ce84b0 100644 --- a/public/locales/es-ES/translation.json +++ b/public/locales/es-ES/translation.json @@ -405,6 +405,8 @@ "no-process-name": "N/A – El nombre del proceso no está definido", "instance-count": "Cantidad de instancias", "empty-response": "Respuesta vacía", + "delete": "Eliminar despliegue", + "confirm-delete": "¿Eliminar este despliegue y todas sus instancias de proceso, instancias históricas y jobs?", "sort": { "deploymentTime": "Hora de despliegue", "name": "Nombre", diff --git a/public/locales/fr-FR/translation.json b/public/locales/fr-FR/translation.json index 43e715f..3b4034e 100644 --- a/public/locales/fr-FR/translation.json +++ b/public/locales/fr-FR/translation.json @@ -405,6 +405,8 @@ "no-process-name": "N/A – Le nom du processus n'est pas défini", "instance-count": "Nombre d'instances", "empty-response": "Réponse vide", + "delete": "Supprimer le déploiement", + "confirm-delete": "Supprimer ce déploiement ainsi que toutes ses instances de processus, instances historiques et jobs ?", "sort": { "deploymentTime": "Heure de déploiement", "name": "Nom", diff --git a/public/locales/nl-NL/translation.json b/public/locales/nl-NL/translation.json index a27f3a1..0ab1c5d 100644 --- a/public/locales/nl-NL/translation.json +++ b/public/locales/nl-NL/translation.json @@ -405,6 +405,8 @@ "no-process-name": "N.v.t. – Procesnaam is niet gedefinieerd", "instance-count": "Aantal instanties", "empty-response": "Leeg antwoord", + "delete": "Deployment verwijderen", + "confirm-delete": "Deze deployment en alle bijbehorende procesinstanties, historische instanties en jobs verwijderen?", "sort": { "deploymentTime": "Deployment-tijd", "name": "Naam", diff --git a/src/pages/Deployments.jsx b/src/pages/Deployments.jsx index 6ed1b25..a2fd477 100644 --- a/src/pages/Deployments.jsx +++ b/src/pages/Deployments.jsx @@ -1,3 +1,4 @@ +import { useSignal } from "@preact/signals"; import { useContext, useEffect } from "preact/hooks"; import { useTranslation } from "react-i18next"; import { AppState } from "../state.js"; @@ -5,6 +6,7 @@ import { useLocation, useRoute } from "preact-iso"; import engine_rest, { RequestState } from "../api/engine_rest.jsx"; import { BPMNViewer } from "../components/BPMNViewer.jsx"; import { CamundaForm } from "../components/CamundaForm.jsx"; +import { ConfirmDialog } from "../components/Dialog.jsx"; import { DmnViewer } from "../components/DMNViewer.jsx"; import { formatRelativeDate } from "../helper/date_formatter.js"; import { ListFilter } from "../components/ListFilter.jsx"; @@ -217,7 +219,19 @@ const DeploymentsList = () => { const ResourcesList = () => { const state = useContext(AppState), { params } = useRoute(), - [t] = useTranslation(); + { route } = useLocation(), + [t] = useTranslation(), + confirm_delete = useSignal(false); + + const remove = async () => { + await engine_rest.deployment.delete(state, params.deployment_id, { + cascade: true, + }); + state.api.deployment.resources.value = null; + state.api.deployment.resource.value = null; + route("/deployments", true); + void engine_rest.deployment.all(state); + }; if (!params.deployment_id) { return ( @@ -227,6 +241,21 @@ const ResourcesList = () => { return (
+
+ +
+ diff --git a/src/pages/Deployments.test.jsx b/src/pages/Deployments.test.jsx index f8d536e..cca122d 100644 --- a/src/pages/Deployments.test.jsx +++ b/src/pages/Deployments.test.jsx @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { h } from "preact"; -import { render, cleanup } from "@testing-library/preact"; +import { render, cleanup, fireEvent } from "@testing-library/preact"; // Spy all engine_rest API functions but keep RequestState/RESPONSE_STATE real. vi.mock("../api/engine_rest.jsx", async (importOriginal) => { @@ -88,6 +88,24 @@ describe("DeploymentsPage", () => { expect(engine_rest.deployment.resources.mock.lastCall[1]).toBe("dep1"); }); + it("deletes the selected deployment after confirmation", async () => { + mockParams = { deployment_id: "dep1" }; + signal_response(state.api.deployment.resources, []); + const { getAllByText } = renderPage(state); + + const deleteButtons = getAllByText("deployments.delete"); + fireEvent.click(deleteButtons[0]); + fireEvent.click(deleteButtons[deleteButtons.length - 1]); + await Promise.resolve(); + + expect(engine_rest.deployment.delete).toHaveBeenCalled(); + const call = engine_rest.deployment.delete.mock.lastCall; + expect(call[0]).toBe(state); + expect(call[1]).toBe("dep1"); + expect(call[2]).toEqual({ cascade: true }); + expect(routeFn).toHaveBeenCalledWith("/deployments", true); + }); + it("renders the resource list for the active deployment", () => { mockParams = { deployment_id: "dep1" }; signal_response(state.api.deployment.all, [