This is an automated email from the ASF dual-hosted git repository.
thiagoelg pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new 9131b10d272 kie-issues#3634: BPMN Editor: Add processDuration field to
the Global Properties (#3635)
9131b10d272 is described below
commit 9131b10d27288b79c8c2ae77f286b1979d5b1bbd
Author: Kusuma04-dev <[email protected]>
AuthorDate: Thu Jul 9 20:49:17 2026 +0530
kie-issues#3634: BPMN Editor: Add processDuration field to the Global
Properties (#3635)
Co-authored-by: Kusuma <[email protected]>
---
packages/bpmn-editor/src/i18n/BpmnEditorI18n.ts | 2 +
packages/bpmn-editor/src/i18n/locales/en.ts | 2 +
.../src/propertiesPanel/GlobalProperties.tsx | 3 +
.../processDuration/ProcessDurationInput.tsx | 106 +++++++++++++++++++++
.../propertiesPanel/changeGlobalProperties.spec.ts | 82 ++++++++++++++++
.../src/drools-extension-metaData.ts | 1 +
6 files changed, 196 insertions(+)
diff --git a/packages/bpmn-editor/src/i18n/BpmnEditorI18n.ts
b/packages/bpmn-editor/src/i18n/BpmnEditorI18n.ts
index ee82d89c0ea..8a619836988 100644
--- a/packages/bpmn-editor/src/i18n/BpmnEditorI18n.ts
+++ b/packages/bpmn-editor/src/i18n/BpmnEditorI18n.ts
@@ -203,6 +203,8 @@ interface BpmnEditorDictionary
priorityPlaceholder: string;
slaDuedate: string;
datePlaceholder: string;
+ processDuration: string;
+ processDurationPlaceholder: string;
timerOptions: string;
fireOnceAfterDuration: string;
durationPlaceholder: string;
diff --git a/packages/bpmn-editor/src/i18n/locales/en.ts
b/packages/bpmn-editor/src/i18n/locales/en.ts
index 4b4ae8c07df..25c322a7c62 100644
--- a/packages/bpmn-editor/src/i18n/locales/en.ts
+++ b/packages/bpmn-editor/src/i18n/locales/en.ts
@@ -208,6 +208,8 @@ export const en: BpmnEditorI18n = {
priorityPlaceholder: "Enter priority...",
slaDuedate: "SLA Due Date",
datePlaceholder: "Enter a date...",
+ processDuration: "Process Duration",
+ processDurationPlaceholder: "E.g., PT1M (1 minute), PT1H (1 hour), P1D (1
day)",
timerOptions: "Timer options",
fireOnceAfterDuration: "Fire once after duration",
durationPlaceholder: "Enter duration or expression #{expression}",
diff --git a/packages/bpmn-editor/src/propertiesPanel/GlobalProperties.tsx
b/packages/bpmn-editor/src/propertiesPanel/GlobalProperties.tsx
index 7c5b273d50a..c4d31d85187 100644
--- a/packages/bpmn-editor/src/propertiesPanel/GlobalProperties.tsx
+++ b/packages/bpmn-editor/src/propertiesPanel/GlobalProperties.tsx
@@ -52,6 +52,7 @@ import { isProcessIdValid, getProcessIdErrorMessage } from
"../validation/proces
import { Imports } from "./imports/Imports";
import { Metadata } from "./metadata/Metadata";
import { SlaDueDateInput } from "./slaDueDate/SlaDueDateInput";
+import { ProcessDurationInput } from "./processDuration/ProcessDurationInput";
import { useBpmnEditorI18n } from "../i18n";
export function GlobalProperties() {
@@ -185,6 +186,8 @@ export function GlobalProperties() {
</FormGroup>
<SlaDueDateInput element={process} />
+
+ <ProcessDurationInput element={process} />
</FormSection>
</>
)}
diff --git
a/packages/bpmn-editor/src/propertiesPanel/processDuration/ProcessDurationInput.tsx
b/packages/bpmn-editor/src/propertiesPanel/processDuration/ProcessDurationInput.tsx
new file mode 100644
index 00000000000..9e2e1cd19db
--- /dev/null
+++
b/packages/bpmn-editor/src/propertiesPanel/processDuration/ProcessDurationInput.tsx
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as React from "react";
+import {
+ deleteBpmn20Drools10MetaDataEntry,
+ parseBpmn20Drools10MetaData,
+ setBpmn20Drools10MetaData,
+} from "@kie-tools/bpmn-marshaller/dist/drools-extension-metaData";
+import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
+import { TextInput } from
"@patternfly/react-core/dist/js/components/TextInput";
+import { addOrGetProcessAndDiagramElements } from
"../../mutations/addOrGetProcessAndDiagramElements";
+import { useBpmnEditorStore, useBpmnEditorStoreApi } from
"../../store/StoreContext";
+import {
+ BPMN20__tDefinitions,
+ BPMN20__tProcess,
+ WithMetaData,
+} from "@kie-tools/bpmn-marshaller/dist/schemas/bpmn-2_0/ts-gen/types";
+import { ElementFilter } from "@kie-tools/xml-parser-ts/dist/elementFilter";
+import { Unpacked } from
"@kie-tools/xyflow-react-kie-diagram/dist/tsExt/tsExt";
+import { Normalized } from "../../normalization/normalize";
+import { visitFlowElementsAndArtifacts } from
"../../mutations/_elementVisitor";
+import { useBpmnEditorI18n } from "../../i18n";
+
+export type WithProcessDuration =
+ | undefined
+ | Normalized<
+ |
ElementFilter<Unpacked<NonNullable<BPMN20__tDefinitions["rootElement"]>>,
"process">
+ | ElementFilter<
+ Unpacked<NonNullable<BPMN20__tProcess["flowElement"]>>,
+ | "startEvent"
+ | "intermediateCatchEvent"
+ | "boundaryEvent"
+ | "callActivity"
+ | "subProcess"
+ | "adHocSubProcess"
+ | "transaction"
+ | "userTask"
+ | "task"
+ | "serviceTask"
+ | "businessRuleTask"
+ >
+ >;
+
+export function ProcessDurationInput({ element }: { element:
WithProcessDuration }) {
+ const { i18n } = useBpmnEditorI18n();
+ const bpmnEditorStoreApi = useBpmnEditorStoreApi();
+
+ const isReadOnly = useBpmnEditorStore((s) => s.settings.isReadOnly);
+
+ return (
+ <FormGroup label={i18n.propertiesPanel.processDuration}>
+ <TextInput
+ aria-label={"Process Duration"}
+ type={"text"}
+ isDisabled={isReadOnly}
+ placeholder={i18n.propertiesPanel.processDurationPlaceholder}
+ value={parseBpmn20Drools10MetaData(element).get("processDuration") ||
""}
+ onChange={(_e, newProcessDuration) =>
+ bpmnEditorStoreApi.setState((s) => {
+ const { process } = addOrGetProcessAndDiagramElements({
+ definitions: s.bpmn.model.definitions,
+ });
+ if (!element || element["@_id"] === process["@_id"]) {
+ if (newProcessDuration) {
+ setBpmn20Drools10MetaData(process, "processDuration",
newProcessDuration);
+ } else {
+ deleteBpmn20Drools10MetaDataEntry(process, "processDuration");
+ }
+ } else {
+ visitFlowElementsAndArtifacts(process, ({ element: e }) => {
+ if (e["@_id"] === element["@_id"]) {
+ if (newProcessDuration) {
+ setBpmn20Drools10MetaData(
+ e as { extensionElements?: WithMetaData },
+ "processDuration",
+ newProcessDuration
+ );
+ } else {
+ deleteBpmn20Drools10MetaDataEntry(e as {
extensionElements?: WithMetaData }, "processDuration");
+ }
+ }
+ });
+ }
+ })
+ }
+ />
+ </FormGroup>
+ );
+}
diff --git
a/packages/bpmn-editor/tests-e2e/propertiesPanel/changeGlobalProperties.spec.ts
b/packages/bpmn-editor/tests-e2e/propertiesPanel/changeGlobalProperties.spec.ts
new file mode 100644
index 00000000000..4859de96c11
--- /dev/null
+++
b/packages/bpmn-editor/tests-e2e/propertiesPanel/changeGlobalProperties.spec.ts
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { test, expect } from "../__fixtures__/base";
+
+test.beforeEach(async ({ editor, page }) => {
+ await page.setViewportSize({ width: 1920, height: 1080 });
+ await editor.open();
+ await editor.setInitialProcessId();
+});
+
+test.describe("Change Global Properties - Process Duration", () => {
+ test.beforeEach(async ({ page }) => {
+ await page.getByRole("button", { name: "Properties Management" }).click();
+ await expect(page.getByText("Process", { exact: true })).toBeVisible();
+ });
+
+ test("should set processDuration value", async ({ page }) => {
+ const processDurationInput = page.getByPlaceholder(/E.g., PT1M \(1
minute\), PT1H \(1 hour\), P1D \(1 day\)/i);
+ await processDurationInput.fill("PT30M");
+
+ await expect(processDurationInput).toHaveValue("PT30M");
+ });
+
+ test("should update processDuration value", async ({ page }) => {
+ const processDurationInput = page.getByPlaceholder(/E.g., PT1M \(1
minute\), PT1H \(1 hour\), P1D \(1 day\)/i);
+
+ await processDurationInput.fill("PT1H");
+ await expect(processDurationInput).toHaveValue("PT1H");
+
+ await processDurationInput.fill("P1D");
+ await expect(processDurationInput).toHaveValue("P1D");
+ });
+
+ test("should clear processDuration value", async ({ page }) => {
+ const processDurationInput = page.getByPlaceholder(/E.g., PT1M \(1
minute\), PT1H \(1 hour\), P1D \(1 day\)/i);
+
+ await processDurationInput.fill("PT2H");
+ await expect(processDurationInput).toHaveValue("PT2H");
+
+ await processDurationInput.clear();
+ await expect(processDurationInput).toHaveValue("");
+ });
+
+ test("should accept various ISO 8601 duration formats", async ({ page }) => {
+ const processDurationInput = page.getByPlaceholder(/E.g., PT1M \(1
minute\), PT1H \(1 hour\), P1D \(1 day\)/i);
+
+ const testValues = ["PT1M", "PT30M", "PT1H", "PT2H30M", "P1D", "P1DT12H",
"P7D"];
+
+ for (const duration of testValues) {
+ await processDurationInput.fill(duration);
+ await expect(processDurationInput).toHaveValue(duration);
+ }
+ });
+
+ test("should persist processDuration with other process properties", async
({ page }) => {
+ const nameInput = page.getByPlaceholder(/Enter a name.../i);
+ await nameInput.fill("Order Processing");
+
+ const processDurationInput = page.getByPlaceholder(/E.g., PT1M \(1
minute\), PT1H \(1 hour\), P1D \(1 day\)/i);
+ await processDurationInput.fill("PT45M");
+
+ await expect(nameInput).toHaveValue("Order Processing");
+ await expect(processDurationInput).toHaveValue("PT45M");
+ });
+});
diff --git a/packages/bpmn-marshaller/src/drools-extension-metaData.ts
b/packages/bpmn-marshaller/src/drools-extension-metaData.ts
index c2f84083c1a..a9769be4900 100644
--- a/packages/bpmn-marshaller/src/drools-extension-metaData.ts
+++ b/packages/bpmn-marshaller/src/drools-extension-metaData.ts
@@ -25,6 +25,7 @@ export type Bpmn20KnownMetaDataKey =
| "customTags" // Used for Process Variables.
| "customDescription" // Used for "Process Instance Description" as a global
property.
| "customSLADueDate" // Used for "SLA Due date" as a global property.
+ | "processDuration" // Used for "Process Duration" as a global property.
| "customAbortParent" // Used for "Abort parent" flag on Call Activities.
| "customAsync" // Used for "Async" flag on Call Activities.
| "customActivationCondition" // Used for "Activation condition" expression
on Ad-hoc sub-processes.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]