diff --git a/public/locales/de-DE/translation.json b/public/locales/de-DE/translation.json
index 5f7d6a9..f186714 100644
--- a/public/locales/de-DE/translation.json
+++ b/public/locales/de-DE/translation.json
@@ -284,6 +284,7 @@
"instances": "Instanzen",
"incidents": "Inzidente",
"called-definitions": "Aufgerufene Definitionen",
+ "restart": "Restart",
"jobs": "Jobs",
"variables": "Variablen",
"instance-incidents": "Instanz-Inzidente",
@@ -296,6 +297,7 @@
"instances": "Instanzen",
"incidents": "Inzidente",
"called-definitions": "Aufgerufene Definitionen",
+ "restart": "Restart",
"jobs": "Jobs"
},
"diagram-maximize": "Diagramm maximieren",
@@ -347,6 +349,28 @@
"suspend": "Anhalten",
"change-priority": "Job-Priorität ändern"
},
+ "restart": {
+ "start-point": "Startpunkt",
+ "instruction": "Instruktion",
+ "default-start": "Standard-Start-Event",
+ "start-before": "Vor Aktivität starten",
+ "start-after": "Nach Aktivität starten",
+ "start-transition": "Transition starten",
+ "activity-id": "Aktivitäts-ID",
+ "transition-id": "Transition-ID",
+ "options": "Optionen",
+ "async": "Asynchroner Batch",
+ "initial-variables": "Initiale Variablen",
+ "without-business-key": "Ohne Geschäftsschlüssel",
+ "skip-custom-listeners": "Custom Listener überspringen",
+ "skip-io-mappings": "IO-Mappings überspringen",
+ "execute": "Neu starten",
+ "execute-async": "Asynchron neu starten",
+ "batch-created": "Restart-Batch erstellt:",
+ "success": "Prozessinstanzen neu gestartet.",
+ "no-instances": "Keine abgeschlossenen Prozessinstanzen gefunden.",
+ "end-time": "Endzeit"
+ },
"sort": {
"name": "Name",
"key": "Schlüssel",
diff --git a/public/locales/en-US/translation.json b/public/locales/en-US/translation.json
index ac20fbe..90cb331 100644
--- a/public/locales/en-US/translation.json
+++ b/public/locales/en-US/translation.json
@@ -284,6 +284,7 @@
"instances": "Instances",
"incidents": "Incidents",
"called-definitions": "Called Definitions",
+ "restart": "Restart",
"jobs": "Jobs",
"variables": "Variables",
"instance-incidents": "Instance Incidents",
@@ -296,6 +297,7 @@
"instances": "Instances",
"incidents": "Incidents",
"called-definitions": "Called Definitions",
+ "restart": "Restart",
"jobs": "Jobs"
},
"diagram-maximize": "Maximize diagram",
@@ -347,6 +349,28 @@
"suspend": "Suspend",
"change-priority": "Change Overriding Job Priority"
},
+ "restart": {
+ "start-point": "Start point",
+ "instruction": "Instruction",
+ "default-start": "Default start event",
+ "start-before": "Start before activity",
+ "start-after": "Start after activity",
+ "start-transition": "Start transition",
+ "activity-id": "Activity ID",
+ "transition-id": "Transition ID",
+ "options": "Options",
+ "async": "Async batch",
+ "initial-variables": "Initial variables",
+ "without-business-key": "Without business key",
+ "skip-custom-listeners": "Skip custom listeners",
+ "skip-io-mappings": "Skip IO mappings",
+ "execute": "Restart",
+ "execute-async": "Restart async",
+ "batch-created": "Restart batch created:",
+ "success": "Process instances restarted.",
+ "no-instances": "No completed process instances found.",
+ "end-time": "End Time"
+ },
"sort": {
"name": "Name",
"key": "Key",
diff --git a/src/api/resources/process_definition.js b/src/api/resources/process_definition.js
index 0ec18ac..29f4f07 100644
--- a/src/api/resources/process_definition.js
+++ b/src/api/resources/process_definition.js
@@ -90,6 +90,22 @@ export const start_process_submit_form = (state, id, body = {}) =>
export const get_activity_instance_statistics = (state, id) =>
GET(`/process-definition/${id}/statistics`, state, state.api.process.definition.activity_instance_statistics)
+const restart_process_instances = (state, id, body) =>
+ POST(
+ `/process-definition/${id}/restart`,
+ body,
+ state,
+ state.api.process.definition.restart,
+ )
+
+const restart_process_instances_async = (state, id, body) =>
+ POST(
+ `/process-definition/${id}/restart-async`,
+ body,
+ state,
+ state.api.process.definition.restart,
+ )
+
const suspend_process_definition = (state, id) =>
PUT(
`/process-definition/${id}/suspended`,
@@ -127,6 +143,8 @@ const process_definition = {
rendered_start_form: get_rendered_start_form,
submit_form: start_process_submit_form,
activity_instance_statistics: get_activity_instance_statistics,
+ restart: restart_process_instances,
+ restart_async: restart_process_instances_async,
suspend: suspend_process_definition,
activate: activate_process_definition,
remove: delete_process_definition,
diff --git a/src/api/resources/process_definition.test.js b/src/api/resources/process_definition.test.js
index fec6547..ede635c 100644
--- a/src/api/resources/process_definition.test.js
+++ b/src/api/resources/process_definition.test.js
@@ -155,6 +155,34 @@ describe("api/resources/process_definition", () => {
});
});
+ it("restart() POSTs the restart payload", () => {
+ const body = {
+ instructions: [{ type: "startBeforeActivity", activityId: "task" }],
+ processInstanceIds: ["inst-1"],
+ };
+ process_definition.restart(state, "def-1", body);
+ expect_api_call(POST, {
+ url: "/process-definition/def-1/restart",
+ body,
+ state,
+ signal: state.api.process.definition.restart,
+ });
+ });
+
+ it("restart_async() POSTs the async restart payload", () => {
+ const body = {
+ processInstanceIds: ["inst-1", "inst-2"],
+ initialVariables: true,
+ };
+ process_definition.restart_async(state, "def-1", body);
+ expect_api_call(POST, {
+ url: "/process-definition/def-1/restart-async",
+ body,
+ state,
+ signal: state.api.process.definition.restart,
+ });
+ });
+
it("suspend() PUTs suspended=true", () => {
process_definition.suspend(state, "def-1");
expect_api_call(PUT, {
diff --git a/src/css/components.css b/src/css/components.css
index 5bed3e4..a213568 100644
--- a/src/css/components.css
+++ b/src/css/components.css
@@ -570,6 +570,43 @@ main#processes {
color: var(--text);
}
+#processes .restart {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-2);
+}
+
+#processes .restart form {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: end;
+ gap: var(--spacing-2);
+}
+
+#processes .restart fieldset {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: var(--spacing-1);
+ margin: 0;
+}
+
+#processes .restart label {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+}
+
+#processes .restart label:has(> select),
+#processes .restart label:has(> input[type="text"]) {
+ flex-direction: column;
+ align-items: start;
+}
+
+#processes .restart button {
+ margin: 0;
+}
+
/* bpmn-js's brand badge defaults to inline-flow at the canvas root, which
can push sibling columns sideways. Pin it to the viewport's bottom-right. */
.bjs-powered-by {
diff --git a/src/pages/Processes.jsx b/src/pages/Processes.jsx
index d6ac79e..9b463a2 100644
--- a/src/pages/Processes.jsx
+++ b/src/pages/Processes.jsx
@@ -277,6 +277,7 @@ const ProcessSubNav = () => {
panel="called_definitions"
label={t("processes.subnav.called-definitions")}
/>
+
+ {t("processes.restart.batch-created")}{" "}
+ {result.id}
+ {t("processes.restart.success")} {t("processes.restart.no-instances")}
+
+
+
+
+
+
+ {rows.map((instance) => (
+
+ 0 && selected.value.size === rows.length
+ }
+ onChange={toggle_all}
+ />
+
+ {t("common.id")}
+ {t("processes.start-time")}
+ {t("processes.restart.end-time")}
+ {t("common.state")}
+ {t("processes.business-key")}
+
+
+ ))}
+
+
+ toggle_one(instance.id)}
+ />
+
+ {instance.id.substring(0, 8)}
+
+ {instance.startTime ? (
+
+ ) : (
+ "—"
+ )}
+
+
+ {instance.endTime ? (
+
+ ) : (
+ "—"
+ )}
+
+ {instance.state}
+ {instance.businessKey}
+