From aa264c77d44e42d818af98a9fd076aecb26f8853 Mon Sep 17 00:00:00 2001 From: Julian Haupt Date: Tue, 16 Jun 2026 23:50:00 +0200 Subject: [PATCH] decisions: show decision requirements diagrams --- public/locales/de-DE/translation.json | 1 + public/locales/en-US/translation.json | 1 + public/locales/es-ES/translation.json | 1 + public/locales/fr-FR/translation.json | 1 + public/locales/nl-NL/translation.json | 1 + src/api/resources/decision.js | 6 +++++- src/api/resources/decision.test.js | 9 ++++++++ src/components/DMNViewer.jsx | 7 +++--- src/components/DMNViewer.test.jsx | 5 +++++ src/pages/Decisions.jsx | 31 ++++++++++++++++++++++----- src/pages/Decisions.test.jsx | 29 +++++++++++++++++++++++++ src/state.js | 1 + 12 files changed, 83 insertions(+), 10 deletions(-) diff --git a/public/locales/de-DE/translation.json b/public/locales/de-DE/translation.json index 5f7d6a9..c287a38 100644 --- a/public/locales/de-DE/translation.json +++ b/public/locales/de-DE/translation.json @@ -404,6 +404,7 @@ "version-tag": "Versions-Tag", "deployment-id": "Deployment-ID", "decision-requirements-id": "Entscheidungsanforderungs-Definitions-ID", + "decision-requirements-diagram": "Entscheidungsanforderungsdiagramm", "history-ttl": "Verlaufs-Aufbewahrungsdauer", "sort": { "name": "Name", diff --git a/public/locales/en-US/translation.json b/public/locales/en-US/translation.json index ac20fbe..3bea2c5 100644 --- a/public/locales/en-US/translation.json +++ b/public/locales/en-US/translation.json @@ -404,6 +404,7 @@ "version-tag": "Version Tag", "deployment-id": "Deployment ID", "decision-requirements-id": "Decision Requirements Definition ID", + "decision-requirements-diagram": "Decision Requirements Diagram", "history-ttl": "History Time To Live", "sort": { "name": "Name", diff --git a/public/locales/es-ES/translation.json b/public/locales/es-ES/translation.json index 121792c..b9f85a6 100644 --- a/public/locales/es-ES/translation.json +++ b/public/locales/es-ES/translation.json @@ -371,6 +371,7 @@ "version-tag": "Etiqueta de versión", "deployment-id": "ID de despliegue", "decision-requirements-id": "ID de definición de requisitos de decisión", + "decision-requirements-diagram": "Diagrama de requisitos de decisión", "history-ttl": "Tiempo de vida del historial", "sort": { "name": "Nombre", diff --git a/public/locales/fr-FR/translation.json b/public/locales/fr-FR/translation.json index 43e715f..5c06186 100644 --- a/public/locales/fr-FR/translation.json +++ b/public/locales/fr-FR/translation.json @@ -371,6 +371,7 @@ "version-tag": "Tag de version", "deployment-id": "ID de déploiement", "decision-requirements-id": "ID de définition des exigences de décision", + "decision-requirements-diagram": "Diagramme des exigences de décision", "history-ttl": "Durée de conservation de l'historique", "sort": { "name": "Nom", diff --git a/public/locales/nl-NL/translation.json b/public/locales/nl-NL/translation.json index a27f3a1..5cbe7ac 100644 --- a/public/locales/nl-NL/translation.json +++ b/public/locales/nl-NL/translation.json @@ -371,6 +371,7 @@ "version-tag": "Versietag", "deployment-id": "Deployment-ID", "decision-requirements-id": "Beslissingsvereisten-definitie-ID", + "decision-requirements-diagram": "Beslissingsvereistendiagram", "history-ttl": "Bewaartermijn geschiedenis", "sort": { "name": "Naam", diff --git a/src/api/resources/decision.js b/src/api/resources/decision.js index a2c3857..6d44f5b 100644 --- a/src/api/resources/decision.js +++ b/src/api/resources/decision.js @@ -1,4 +1,4 @@ -import { GET, GET_TEXT } from '../helper.jsx' +import { GET } from '../helper.jsx' const get_decision_definition = (state, id) => @@ -13,11 +13,15 @@ const get_decision_definitions = (state, params = {}) => { const get_dmn_xml = (state, id) => GET(`/decision-definition/${id}/xml`, state, state.api.decision.dmn) +const get_decision_requirements_xml = (state, id) => + GET(`/decision-requirements-definition/${id}/xml`, state, state.api.decision.drd) + const decision = { get_decision_definition, get_decision_definitions, get_dmn_xml, + get_decision_requirements_xml, } export default decision diff --git a/src/api/resources/decision.test.js b/src/api/resources/decision.test.js index 2a7a0e7..131fea7 100644 --- a/src/api/resources/decision.test.js +++ b/src/api/resources/decision.test.js @@ -41,4 +41,13 @@ describe("api/resources/decision", () => { signal: state.api.decision.dmn, }); }); + + it("get_decision_requirements_xml() GETs /decision-requirements-definition/:id/xml", () => { + decision.get_decision_requirements_xml(state, "drd-1"); + expect_api_call(GET, { + url: "/decision-requirements-definition/drd-1/xml", + state, + signal: state.api.decision.drd, + }); + }); }); diff --git a/src/components/DMNViewer.jsx b/src/components/DMNViewer.jsx index bfe901c..b4e8494 100644 --- a/src/components/DMNViewer.jsx +++ b/src/components/DMNViewer.jsx @@ -1,9 +1,8 @@ import DmnJS from 'dmn-js' -import { useLayoutEffect } from 'preact/hooks' -export const DmnViewer = ({ xml, container }) => { +export const DmnViewer = ({ xml, container, table_view_only = true }) => { document.querySelector(container).innerText = '' @@ -13,7 +12,7 @@ export const DmnViewer = ({ xml, container }) => { viewer = new DmnJS({ container, height: 500, - tableViewOnly: true, + tableViewOnly: table_view_only, hideDetails: true, drd: { drillDown: { @@ -29,4 +28,4 @@ export const DmnViewer = ({ xml, container }) => { }) return <> -} \ No newline at end of file +} diff --git a/src/components/DMNViewer.test.jsx b/src/components/DMNViewer.test.jsx index 8064752..67b3d3a 100644 --- a/src/components/DMNViewer.test.jsx +++ b/src/components/DMNViewer.test.jsx @@ -30,6 +30,11 @@ describe("DmnViewer", () => { expect(DmnJS.mock.lastCall[0].container).toBe("#diagram"); }); + it("passes through the table view option", () => { + render(); + expect(DmnJS.mock.lastCall[0].tableViewOnly).toBe(false); + }); + it("imports the supplied xml into the viewer", () => { render(); expect(importXML).toHaveBeenCalled(); diff --git a/src/pages/Decisions.jsx b/src/pages/Decisions.jsx index 9a73c30..d29de94 100644 --- a/src/pages/Decisions.jsx +++ b/src/pages/Decisions.jsx @@ -63,7 +63,7 @@ const load_decisions = (state, query) => { const DecisionsPage = () => { const state = useContext(AppState), - { api: { decision: { definition, dmn } } } = state, + { api: { decision: { definition, dmn, drd } } } = state, { params: { decision_id }, query } = useRoute() useEffect(() => { @@ -86,10 +86,19 @@ const DecisionsPage = () => { return () => { definition.value = null dmn.value = null + drd.value = null } // eslint-disable-next-line react-hooks/exhaustive-deps }, [decision_id]) + useEffect(() => { + const drd_id = definition.value?.data?.decisionRequirementsDefinitionId + if (drd_id) { + void engine_rest.decision.get_decision_requirements_xml(state, drd_id) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [definition.value?.data?.decisionRequirementsDefinitionId]) + return (
@@ -170,8 +179,7 @@ const DecisionsList = () => { const DecisionDetails = () => { const state = useContext(AppState), - { api: { decision: { definition, dmn } } } = state, - { params: { decision_id } } = useRoute(), + { api: { decision: { definition, dmn, drd } } } = state, [t] = useTranslation() return
@@ -182,7 +190,6 @@ const DecisionDetails = () => { const { id, key, name, version, versionTag, tenantId, deploymentId, decisionRequirementsDefinitionId, historyTimeToLive, - resource } = definition.value.data return
@@ -203,7 +210,11 @@ const DecisionDetails = () => {
{t("decisions.deployment-id")}
{deploymentId}
{t("decisions.decision-requirements-id")}
-
{decisionRequirementsDefinitionId}
+
+ {decisionRequirementsDefinitionId + ? {decisionRequirementsDefinitionId} + : '-'} +
{t("decisions.history-ttl")}
{historyTimeToLive}
@@ -217,6 +228,16 @@ const DecisionDetails = () => { signal={dmn} on_nothing={() =>

{t("decisions.select-diagram")}

} on_success={() => } /> + + {definition.value?.data?.decisionRequirementsDefinitionId + ? <> +

{t("decisions.decision-requirements-diagram")}

+
+ } /> + + : null}
} diff --git a/src/pages/Decisions.test.jsx b/src/pages/Decisions.test.jsx index 9ac0a45..5a591f9 100644 --- a/src/pages/Decisions.test.jsx +++ b/src/pages/Decisions.test.jsx @@ -67,6 +67,20 @@ describe("DecisionsPage", () => { expect(engine_rest.decision.get_dmn_xml).toHaveBeenCalled(); }); + it("fetches the decision requirements xml when the selected decision belongs to a DRD", () => { + mockParams = { decision_id: "d1" }; + signal_response(state.api.decision.definition, { + id: "d1", + key: "risk", + name: "Risk", + version: 1, + decisionRequirementsDefinitionId: "drd-1", + }); + renderPage(state); + expect(engine_rest.decision.get_decision_requirements_xml).toHaveBeenCalled(); + expect(engine_rest.decision.get_decision_requirements_xml.mock.lastCall[1]).toBe("drd-1"); + }); + it("renders the DMN viewer with the fetched xml", () => { mockParams = { decision_id: "d1" }; signal_response(state.api.decision.definition, { @@ -79,4 +93,19 @@ describe("DecisionsPage", () => { const { getByTestId } = renderPage(state); expect(getByTestId("dmn-viewer").textContent).toBe("xml"); }); + + it("renders the DRD viewer with the fetched decision requirements xml", () => { + mockParams = { decision_id: "d1" }; + signal_response(state.api.decision.definition, { + id: "d1", + key: "risk", + name: "Risk", + version: 1, + decisionRequirementsDefinitionId: "drd-1", + }); + signal_response(state.api.decision.drd, { dmnXml: "xml" }); + const { getAllByTestId, getByText } = renderPage(state); + expect(getByText("decisions.decision-requirements-diagram")).toBeTruthy(); + expect(getAllByTestId("dmn-viewer").some((node) => node.textContent === "xml")).toBe(true); + }); }); diff --git a/src/state.js b/src/state.js index f63ad2e..03a2f22 100644 --- a/src/state.js +++ b/src/state.js @@ -164,6 +164,7 @@ const createAppState = () => { definitions: signal(null), definition: signal(null), dmn: signal(null), + drd: signal(null), saved_filters: signal(null), }, history: {