diff --git a/public/locales/de-DE/translation.json b/public/locales/de-DE/translation.json index 5f7d6a9..2454b32 100644 --- a/public/locales/de-DE/translation.json +++ b/public/locales/de-DE/translation.json @@ -425,6 +425,15 @@ "latestVersion": "latestVersion", "decisionRequirementsDefinitionKey": "decisionRequirementsDefinitionKey" }, + "instances": { + "title": "Decision-Instanzen", + "refresh": "Aktualisieren", + "empty": "Keine Decision-Instanzen gefunden.", + "id": "Decision-Instanz-ID", + "evaluation-time": "Auswertungszeit", + "process-instance": "Prozessinstanz", + "activity": "Aktivität" + }, "filter": { "manage_title": "Decision-Filter verwalten" } diff --git a/public/locales/en-US/translation.json b/public/locales/en-US/translation.json index ac20fbe..750c3e1 100644 --- a/public/locales/en-US/translation.json +++ b/public/locales/en-US/translation.json @@ -425,6 +425,15 @@ "latestVersion": "latestVersion", "decisionRequirementsDefinitionKey": "decisionRequirementsDefinitionKey" }, + "instances": { + "title": "Decision Instances", + "refresh": "Refresh", + "empty": "No decision instances found.", + "id": "Decision Instance ID", + "evaluation-time": "Evaluation Time", + "process-instance": "Process Instance", + "activity": "Activity" + }, "filter": { "manage_title": "Manage decision-definition filters" } diff --git a/src/api/resources/history.js b/src/api/resources/history.js index 6bc1013..199bc17 100644 --- a/src/api/resources/history.js +++ b/src/api/resources/history.js @@ -1,6 +1,7 @@ import { GET, PAGINATED_GET } from '../helper.jsx' const INSTANCE_PAGE_SIZE = 20 +const DECISION_INSTANCE_PAGE_SIZE = 20 const instance_url = (definition_id, params = {}, { unfinished = false } = {}) => { const merged = { @@ -49,6 +50,19 @@ const get_historic_tasks_by_instance = (state, instance_id) => const get_historic_called_instances = (state, instance_id) => GET(`/history/process-instance?superProcessInstanceId=${instance_id}`, state, state.api.history.process_instance.called) +const get_decision_instances_by_definition = (state, definition_id, firstResult = 0) => + PAGINATED_GET( + `/history/decision-instance?${new URLSearchParams({ + decisionDefinitionId: definition_id, + sortBy: 'evaluationTime', + sortOrder: 'desc', + }).toString()}`, + state, + state.api.history.decision_instance.list, + firstResult, + DECISION_INSTANCE_PAGE_SIZE, + ) + /** * Task History */ @@ -72,7 +86,10 @@ const history = { task: { by_process_instance: get_historic_tasks_by_instance, }, + decision_instance: { + by_decision_definition: get_decision_instances_by_definition, + }, get_user_operation } -export default history \ No newline at end of file +export default history diff --git a/src/api/resources/history.test.js b/src/api/resources/history.test.js index 12970fd..bea8a7a 100644 --- a/src/api/resources/history.test.js +++ b/src/api/resources/history.test.js @@ -118,4 +118,15 @@ describe("api/resources/history", () => { signal: state.api.history.process_instance.called, }); }); + + it("decision_instance.by_decision_definition() PAGINATED_GETs historic decision instances", () => { + history.decision_instance.by_decision_definition(state, "decision-1", 20); + expect_api_call(PAGINATED_GET, { + url: "/history/decision-instance?decisionDefinitionId=decision-1&sortBy=evaluationTime&sortOrder=desc", + state, + signal: state.api.history.decision_instance.list, + }); + expect(PAGINATED_GET.mock.lastCall[3]).toBe(20); + expect(PAGINATED_GET.mock.lastCall[4]).toBe(20); + }); }); diff --git a/src/pages/Decisions.jsx b/src/pages/Decisions.jsx index 9a73c30..f0f5b2a 100644 --- a/src/pages/Decisions.jsx +++ b/src/pages/Decisions.jsx @@ -61,9 +61,18 @@ const load_decisions = (state, query) => { void engine_rest.decision.get_decision_definitions(state, params) } +const load_decision_instances = (state, decision_id, firstResult = 0) => { + if (!decision_id) return + void engine_rest.history.decision_instance.by_decision_definition( + state, + decision_id, + firstResult, + ) +} + const DecisionsPage = () => { const state = useContext(AppState), - { api: { decision: { definition, dmn } } } = state, + { api: { decision: { definition, dmn }, history: { decision_instance } } } = state, { params: { decision_id }, query } = useRoute() useEffect(() => { @@ -80,12 +89,14 @@ const DecisionsPage = () => { if (decision_id) { void engine_rest.decision.get_decision_definition(state, decision_id) void engine_rest.decision.get_dmn_xml(state, decision_id) + load_decision_instances(state, decision_id) } // Clear stale per-decision data so navigating between decisions doesn't - // render the previous decision's metadata or DMN diagram briefly. + // render the previous decision's metadata, DMN diagram or instances briefly. return () => { definition.value = null dmn.value = null + decision_instance.list.value = null } // eslint-disable-next-line react-hooks/exhaustive-deps }, [decision_id]) @@ -182,7 +193,6 @@ const DecisionDetails = () => { const { id, key, name, version, versionTag, tenantId, deploymentId, decisionRequirementsDefinitionId, historyTimeToLive, - resource } = definition.value.data return
{t("decisions.select-diagram")}
} on_success={() =>{t("decisions.instances.empty")}
+ } + return ( + <> +| {t("decisions.instances.id")} | +{t("decisions.instances.evaluation-time")} | +{t("decisions.instances.process-instance")} | +{t("decisions.instances.activity")} | +{t("processes.tenant-id")} | +
|---|---|---|---|---|
| {instance.id?.substring(0, 8)} | ++ + | ++ {process_link ? ( + + {instance.processInstanceId.substring(0, 8)} + + ) : ( + instance.processInstanceId ?? '—' + )} + | +{instance.activityId ?? '—'} | +{instance.tenantId ?? '—'} | +