diff --git a/public/locales/de-DE/translation.json b/public/locales/de-DE/translation.json index 5f7d6a9..20de05e 100644 --- a/public/locales/de-DE/translation.json +++ b/public/locales/de-DE/translation.json @@ -273,6 +273,8 @@ "definition-id": "Definitions-ID", "definition-details": "Definitionsdetails", "tenant-id": "Mandanten-ID", + "history-ttl": "Verlaufs-Aufbewahrungsdauer", + "history-ttl-updated": "Verlaufs-Aufbewahrungsdauer aktualisiert.", "click-to-copy": "Klicken zum Kopieren", "history-mode-active": "Verlaufsmodus aktiv", "enable-history-mode": "Verlaufsmodus aktivieren", diff --git a/public/locales/en-US/translation.json b/public/locales/en-US/translation.json index ac20fbe..d9f36e4 100644 --- a/public/locales/en-US/translation.json +++ b/public/locales/en-US/translation.json @@ -273,6 +273,8 @@ "definition-id": "Definition ID", "definition-details": "Definition details", "tenant-id": "Tenant ID", + "history-ttl": "History Time To Live", + "history-ttl-updated": "History time to live updated.", "click-to-copy": "Click to copy", "history-mode-active": "History Mode Active", "enable-history-mode": "Enable History Mode", diff --git a/public/locales/es-ES/translation.json b/public/locales/es-ES/translation.json index 121792c..43f3584 100644 --- a/public/locales/es-ES/translation.json +++ b/public/locales/es-ES/translation.json @@ -265,6 +265,8 @@ "change-definition": "Cambiar definición", "definition-id": "ID de definición", "tenant-id": "ID del inquilino", + "history-ttl": "Tiempo de vida del historial", + "history-ttl-updated": "Tiempo de vida del historial actualizado.", "click-to-copy": "Clic para copiar", "history-mode-active": "Modo historial activo", "enable-history-mode": "Activar modo historial", diff --git a/public/locales/fr-FR/translation.json b/public/locales/fr-FR/translation.json index 43e715f..24946b4 100644 --- a/public/locales/fr-FR/translation.json +++ b/public/locales/fr-FR/translation.json @@ -265,6 +265,8 @@ "change-definition": "Changer de définition", "definition-id": "ID de définition", "tenant-id": "ID du locataire", + "history-ttl": "Durée de conservation de l'historique", + "history-ttl-updated": "Durée de conservation de l'historique mise à jour.", "click-to-copy": "Cliquer pour copier", "history-mode-active": "Mode historique actif", "enable-history-mode": "Activer le mode historique", diff --git a/public/locales/nl-NL/translation.json b/public/locales/nl-NL/translation.json index a27f3a1..23b616d 100644 --- a/public/locales/nl-NL/translation.json +++ b/public/locales/nl-NL/translation.json @@ -265,6 +265,8 @@ "change-definition": "Definitie wijzigen", "definition-id": "Definitie-ID", "tenant-id": "Tenant-ID", + "history-ttl": "Bewaartermijn geschiedenis", + "history-ttl-updated": "Bewaartermijn geschiedenis bijgewerkt.", "click-to-copy": "Klik om te kopiëren", "history-mode-active": "Geschiedenismodus actief", "enable-history-mode": "Geschiedenismodus inschakelen", diff --git a/src/api/resources/process_definition.js b/src/api/resources/process_definition.js index 0ec18ac..b890a9c 100644 --- a/src/api/resources/process_definition.js +++ b/src/api/resources/process_definition.js @@ -106,6 +106,14 @@ const activate_process_definition = (state, id) => state.api.process.definition.suspend, ) +const update_history_ttl = (state, id, historyTimeToLive) => + PUT( + `/process-definition/${id}/history-time-to-live`, + { historyTimeToLive }, + state, + state.api.process.definition.update_history_ttl, + ) + const delete_process_definition = (state, id) => DELETE( `/process-definition/${id}?cascade=true`, @@ -129,6 +137,7 @@ const process_definition = { activity_instance_statistics: get_activity_instance_statistics, suspend: suspend_process_definition, activate: activate_process_definition, + update_history_ttl, remove: delete_process_definition, } diff --git a/src/api/resources/process_definition.test.js b/src/api/resources/process_definition.test.js index fec6547..31292e6 100644 --- a/src/api/resources/process_definition.test.js +++ b/src/api/resources/process_definition.test.js @@ -175,6 +175,16 @@ describe("api/resources/process_definition", () => { }); }); + it("update_history_ttl() PUTs the history time to live", () => { + process_definition.update_history_ttl(state, "def-1", 30); + expect_api_call(PUT, { + url: "/process-definition/def-1/history-time-to-live", + body: { historyTimeToLive: 30 }, + state, + signal: state.api.process.definition.update_history_ttl, + }); + }); + it("remove() DELETEs with cascade=true", () => { process_definition.remove(state, "def-1"); expect_api_call(DELETE, { diff --git a/src/pages/Processes.jsx b/src/pages/Processes.jsx index d6ac79e..ae899cc 100644 --- a/src/pages/Processes.jsx +++ b/src/pages/Processes.jsx @@ -1,4 +1,4 @@ -import { useSignal } from "@preact/signals"; +import { useSignal, useSignalEffect } from "@preact/signals"; import { useContext, useEffect } from "preact/hooks"; import { useLocation, useRoute } from "preact-iso"; import { useTranslation } from "react-i18next"; @@ -686,7 +686,7 @@ const DefinitionsEmpty = () => { {t("processes.empty.how-to")} @@ -716,14 +716,32 @@ const ProcessDefinitionDetails = () => { }; const DefinitionOverview = () => { - const { + const state = useContext(AppState), + { api: { process: { - definition: { one: process_definition, statistics }, + definition: { one: process_definition, statistics, update_history_ttl }, }, }, - } = useContext(AppState), - [t] = useTranslation(); + } = state, + [t] = useTranslation(), + history_ttl = useSignal(""); + + useSignalEffect(() => { + history_ttl.value = + process_definition.value?.data?.historyTimeToLive ?? ""; + }); + + const submit_history_ttl = async (e, id) => { + e.preventDefault(); + const raw = history_ttl.peek(); + await engine_rest.process_definition.update_history_ttl( + state, + id, + raw === "" ? null : Number(raw), + ); + void engine_rest.process_definition.one(state, id); + }; /** @namespace process_definition.value.data.tenantId **/ /** @namespace process_definition.value.data.deploymentId **/ @@ -771,6 +789,29 @@ const DefinitionOverview = () => {
{t("processes.tabs.incidents")}
{total_incidents}
+ <>} + on_success={() => ( +

{t("processes.history-ttl-updated")}

+ )} + /> +
submit_history_ttl(e, def.id)} + > + + (history_ttl.value = e.currentTarget.value)} + /> + +
); }} @@ -928,8 +969,7 @@ const InstanceDetails = () => { params: { selection_id, definition_id, panel }, query, } = useRoute(), - history_mode = query.history === "true", - [t] = useTranslation(); + history_mode = query.history === "true"; if (selection_id) { if ( @@ -1044,9 +1084,8 @@ const InstanceVariables = () => { ? Object.entries( state.api.process.instance.variables.value.data, ).map( - // eslint-disable-next-line react/jsx-key ([name, { type, value }]) => ( - + {name} {type} {value} @@ -1054,9 +1093,8 @@ const InstanceVariables = () => { ), ) : state.api.process.instance.variables.value.data.map( - // eslint-disable-next-line react/jsx-key ({ name, type, value }) => ( - + {name} {type} {value} @@ -1464,13 +1502,6 @@ const JobDefinitions = () => { ); }; -const BackToListBtn = ({ url, title, className }) => ( - - - - -); - const DefinitionsManage = () => { const state = useContext(AppState), { route } = useLocation(), diff --git a/src/pages/Processes.test.jsx b/src/pages/Processes.test.jsx index 60c4b48..ecec06d 100644 --- a/src/pages/Processes.test.jsx +++ b/src/pages/Processes.test.jsx @@ -245,6 +245,54 @@ describe("ProcessesPage — definition detail fetches", () => { // Heading shows the definition name. expect(getAllByText("Invoice").length).toBeGreaterThan(0); }); + + it("updates the process definition history time to live", async () => { + mockParams = { definition_id: "proc:1" }; + signal_response(state.api.process.definition.one, { + id: "proc:1", + name: "Invoice", + key: "invoice", + version: 2, + historyTimeToLive: 30, + }); + const { container, getByLabelText } = renderPage(state); + + fireEvent.input(getByLabelText("processes.history-ttl"), { + target: { value: "45" }, + }); + fireEvent.submit(container.querySelector("form.history-ttl-form")); + await Promise.resolve(); + + expect(engine_rest.process_definition.update_history_ttl).toHaveBeenCalled(); + const call = engine_rest.process_definition.update_history_ttl.mock.lastCall; + expect(call[0]).toBe(state); + expect(call[1]).toBe("proc:1"); + expect(call[2]).toBe(45); + }); + + it("clears the process definition history time to live with an empty value", async () => { + mockParams = { definition_id: "proc:1" }; + signal_response(state.api.process.definition.one, { + id: "proc:1", + name: "Invoice", + key: "invoice", + version: 2, + historyTimeToLive: 30, + }); + const { container, getByLabelText } = renderPage(state); + + fireEvent.input(getByLabelText("processes.history-ttl"), { + target: { value: "" }, + }); + fireEvent.submit(container.querySelector("form.history-ttl-form")); + await Promise.resolve(); + + expect(engine_rest.process_definition.update_history_ttl).toHaveBeenCalled(); + const call = engine_rest.process_definition.update_history_ttl.mock.lastCall; + expect(call[0]).toBe(state); + expect(call[1]).toBe("proc:1"); + expect(call[2]).toBeNull(); + }); }); describe("ProcessesPage — definition tabs", () => { diff --git a/src/state.js b/src/state.js index f63ad2e..c5c54dc 100644 --- a/src/state.js +++ b/src/state.js @@ -110,6 +110,7 @@ const createAppState = () => { rendered_form: signal(null), activity_instance_statistics: signal(null), suspend: signal(null), + update_history_ttl: signal(null), remove: signal(null), saved_filters: signal(null), },