diff --git a/flowset-ui-kit/src/main/java/io/flowset/uikit/fragment/bpmnviewer/BpmnViewerFragment.java b/flowset-ui-kit/src/main/java/io/flowset/uikit/fragment/bpmnviewer/BpmnViewerFragment.java index e544621..23ca4a4 100644 --- a/flowset-ui-kit/src/main/java/io/flowset/uikit/fragment/bpmnviewer/BpmnViewerFragment.java +++ b/flowset-ui-kit/src/main/java/io/flowset/uikit/fragment/bpmnviewer/BpmnViewerFragment.java @@ -59,6 +59,11 @@ public class BpmnViewerFragment extends Fragment
{ protected ViewerMode mode; protected BpmnViewer bpmnViewer; + @Subscribe(target = Target.HOST_CONTROLLER) + public void onHostInit(final View.InitEvent event) { + onInit(); + } + @Subscribe(target = Target.HOST_CONTROLLER) public void onHostBeforeShow(final View.BeforeShowEvent event) { if (!noBorders) { @@ -103,7 +108,7 @@ public ViewerMode getMode() { } public void initViewer(String bpmnXml) { - this.bpmnViewer = uiComponents.create(BpmnViewer.class); + this.bpmnViewer = createBpmnViewer(); this.bpmnViewer.setBpmnXml(bpmnXml); this.bpmnViewer.setMode(mode); @@ -274,4 +279,12 @@ public void showCalledProcessOverlays() { }); } } + + protected void onInit() { + + } + + protected BpmnViewer createBpmnViewer() { + return uiComponents.create(BpmnViewer.class); + } } diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/flowset-bpmn-viewer.ts b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/flowset-bpmn-viewer.ts index 2c32225..031c497 100644 --- a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/flowset-bpmn-viewer.ts +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/flowset-bpmn-viewer.ts @@ -165,6 +165,18 @@ class FlowsetBpmnViewer extends LitElement { }); } + public addTransactionBoundaries() { + this.awaitRun(() => { + this.overlayManager.addTransactionBoundaryOverlays(); + }); + } + + public setTransactionBoundariesVisible(visible: boolean) { + this.awaitRun(() => { + this.overlayManager.updateOverlaysVisibility(OverlayType.TRANSACTION_BOUNDARY, visible); + }); + } + public addMarker(cmdJson: string) { const cmd: AddMarkerCmd = JSON.parse(cmdJson); this.awaitRun(() => this.canvas.addMarker(cmd.elementId, cmd.marker)); diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/OverlayManager.ts b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/OverlayManager.ts index ec96e22..0144f09 100644 --- a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/OverlayManager.ts +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/OverlayManager.ts @@ -23,12 +23,18 @@ import BpmnViewer from "../bpm/js/BpmnViewer"; import ElementRegistry from 'diagram-js/lib/core/ElementRegistry'; import Canvas from 'diagram-js/lib/core/Canvas'; import {createNavigationOverlay} from "./createNavigationOverlay"; -import {getMessage, isMessageSupported} from "../utils/bpmnEventUtils"; +import {getMessage, isMessageSupported} from "../utils/eventDefinitionUtils"; import {createSendMessageOverlay} from "./createSendMessageOverlay"; import {getBinding, getCalledElement, getVersion, getVersionTag} from "../utils/callActivityUtils"; -import {ElementLike} from "diagram-js/lib/model/Types"; +import {ElementLike, Shape} from "diagram-js/lib/model/Types"; import {findElementDocumentation} from "../utils/documentationUtils"; import {createActivityStatisticsOverlay} from "./createActivityStatisticsOverlay"; +import {getElementTransactionBoundary} from "../utils/transactionBoundaryUtils"; +import {forEach} from 'min-dash'; +import {createTransactionBoundaryOverlay} from "./createTransactionBoundaryOverlay"; +import {BeforeElementTransactionType, ElementTransactionBoundary} from "../types"; +import {DEFAULT_LABEL_SIZE} from "bpmn-js/lib/util/LabelUtil"; +import {Point, Rect} from "diagram-js/lib/util/Types"; /** * OverlayManager class manages various overlays associated with BPMN diagram elements, @@ -51,7 +57,10 @@ export class OverlayManager { * @param data overlay data */ public showIncidentOverlay(data: IncidentOverlayData) { - const incidentOverlay = createIncidentOverlay({tooltipMessage : data.tooltipMessage, incidentCount : data.incidentCount}); + const incidentOverlay = createIncidentOverlay({ + tooltipMessage: data.tooltipMessage, + incidentCount: data.incidentCount + }); this.overlays.add(data.elementId, OverlayType.INCIDENT_COUNT, incidentOverlay); } @@ -117,7 +126,10 @@ export class OverlayManager { const handleOverlayClick = () => { handleClick(data.decisionInstanceId); } - const decisionInstanceOverlay = createNavigationOverlay({title : data.tooltipMessage, handleClick : handleOverlayClick}); + const decisionInstanceOverlay = createNavigationOverlay({ + title: data.tooltipMessage, + handleClick: handleOverlayClick + }); this.overlays.add(element.id, OverlayType.DECISION_INSTANCE, decisionInstanceOverlay); } @@ -148,7 +160,10 @@ export class OverlayManager { } const overlayTooltip = `${data.tooltipMessage}: ${message.get("name")}`; - const sendMessageOverlay: OverlayAttrs = createSendMessageOverlay({title : overlayTooltip, handleClick : handleOverlayClick}); + const sendMessageOverlay: OverlayAttrs = createSendMessageOverlay({ + title: overlayTooltip, + handleClick: handleOverlayClick + }); this.overlays.add(element.id, OverlayType.SEND_MESSAGE, sendMessageOverlay); } }); @@ -167,7 +182,10 @@ export class OverlayManager { handleClick(details); } - const calledInstancesOverlay = createNavigationOverlay({title : data.tooltipMessage, handleClick : handleOverlayClick}); + const calledInstancesOverlay = createNavigationOverlay({ + title: data.tooltipMessage, + handleClick: handleOverlayClick + }); this.overlays.add(data.elementId, OverlayType.CALLED_PROCESS_INSTANCE, calledInstancesOverlay); } @@ -197,7 +215,10 @@ export class OverlayManager { } const tooltipMessage = `${data.tooltipMessage} (${calledElement})`; - const calledProcessOverlay = createNavigationOverlay({title : tooltipMessage, handleClick : handleOverlayClick}); + const calledProcessOverlay = createNavigationOverlay({ + title: tooltipMessage, + handleClick: handleOverlayClick + }); this.overlays.add(element.id, OverlayType.CALLED_PROCESS, calledProcessOverlay); } @@ -227,6 +248,111 @@ export class OverlayManager { this.overlays.add(data.elementId, OverlayType.ACTIVITY_STATISTICS, createActivityStatisticsOverlay(data)); } + /** + * Adds overlays for the transaction boundary (before/after) for all elements. + */ + public addTransactionBoundaryOverlays() { + this.overlays.remove({type: OverlayType.TRANSACTION_BOUNDARY}); + + const elements: ElementLike[] = this.elementRegistry.filter(element => { + return element.type !== 'label'; + }); + + elements.forEach((shape: ElementLike) => { + const transactionBoundary: ElementTransactionBoundary = getElementTransactionBoundary(shape); + + if (!transactionBoundary) { + return; + } + + const addIncomingTransactionBoundaryOverlay = (type: BeforeElementTransactionType) => { + const incoming = shape.incoming || []; + const hasIncoming = incoming.length > 0; + + if (hasIncoming) { + this.addOverlayForConnections(shape, transactionBoundary, incoming, true, type); + } else { + // no incoming connection, calculate position in the front + this.addTransactionBoundaryOverlay(shape, { + x: shape.x, + y: shape.y + shape.height / 2 + }, transactionBoundary, type); + } + }; + + if (transactionBoundary.engineWaitState) { + addIncomingTransactionBoundaryOverlay(BeforeElementTransactionType.ENGINE_WAIT_STATE) + } + + if (transactionBoundary.asyncBefore) { + addIncomingTransactionBoundaryOverlay(BeforeElementTransactionType.ASYNC_BEFORE); + } + + if (transactionBoundary.asyncAfter) { + const outgoing = shape.outgoing || []; + const hasOutgoing = outgoing.length > 0; + + if (hasOutgoing) { + this.addOverlayForConnections(shape, transactionBoundary, outgoing, false); + } else { + // no outgoing connection, calculate position after the element + this.addTransactionBoundaryOverlay(shape, { + x: shape.x + shape.width, + y: shape.y + shape.height / 2 + }, transactionBoundary); + } + } + + }); + } + + /** + * Adds a transaction boundary overlay to a shape element at a specified waypoint. + * + * @param {ElementLike} shape - The shape element to which the transaction boundary overlay will be added. + * @param {Point} waypoint - The waypoint indicating the location of the transaction boundary. + * @param {ElementTransactionBoundary} [transactionBoundary] - Optional parameter representing the transaction boundary element. + * @param {BeforeElementTransactionType} [type] - Required for the transactions before the element. + */ + private addTransactionBoundaryOverlay = (shape: ElementLike, waypoint: Point, + transactionBoundary?: ElementTransactionBoundary, type?: BeforeElementTransactionType): void => { + const rect = {...waypoint}; + const overlay = createTransactionBoundaryOverlay({ + shape, + waypoint: rect, + transactionBoundary, + beforeType: type + }); + this.overlays.add(shape.id, OverlayType.TRANSACTION_BOUNDARY, overlay); + }; + + /** + * Adds overlays to the provided connections based on transaction boundaries. + * + * @param {ElementLike} shape - The visual object to which the overlays will be added. + * @param {ElementTransactionBoundary} transactionBoundary - The transaction boundary linked to the overlay. + * @param {any[]} connections - An array of connections to process for adding overlays. + * @param {boolean} isIncoming - Specifies whether the connections are incoming or outgoing. + * @return {void} This method does not return a value. + */ + private addOverlayForConnections(shape: ElementLike, transactionBoundary: ElementTransactionBoundary, + connections: any[], isIncoming: boolean, type?: BeforeElementTransactionType): void { + forEach(connections, (connection: any) => { + if (connection.type !== 'bpmn:SequenceFlow') { + return; + } + + let waypoint: Rect; + if(isIncoming) { + const lastWaypointIndex = connection.waypoints.length - 1; + waypoint = connection.waypoints[lastWaypointIndex]; + } else { + waypoint = connection.waypoints[0]; + } + this.addTransactionBoundaryOverlay(shape, waypoint, transactionBoundary, type); + }); + } + private shouldRenderSendMessageOverlay(element: ElementLike, data: SendMessageOverlaysData): boolean { if (data.useActiveEvents) { const isRunningActivity = this.canvas.hasMarker(element.id, 'running-activity'); diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/createTransactionBoundaryOverlay.ts b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/createTransactionBoundaryOverlay.ts new file mode 100644 index 0000000..9f80c07 --- /dev/null +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/createTransactionBoundaryOverlay.ts @@ -0,0 +1,128 @@ +/* + * Copyright (c) Haulmont 2025. All Rights Reserved. + * Use is subject to license terms. + */ + +import {OverlayPosition} from "./types"; + +import {OverlayAttrs} from "diagram-js/lib/features/overlays/Overlays"; +import {BeforeElementTransactionType, ElementTransactionBoundary} from "../types"; +import {getOrientation} from "diagram-js/lib/layout/LayoutUtil"; +import {ShapeLike} from "bpmn-js/lib/draw/BpmnRenderUtil"; + +export type TransactionBoundaryOverlayData = { + shape: ShapeLike; + waypoint: any; + beforeType?: BeforeElementTransactionType; + transactionBoundary?: ElementTransactionBoundary; +} + +type Orientation = + 'left' + | 'right' + | 'top' + | 'bottom' + | 'top-left' + | 'top-right' + | 'bottom-left' + | 'bottom-right' + | 'intersect'; + +/** + * Creates an overlay representing a transaction boundary at a given position on a shape. + * + * The function calculates the overlay position based on the relative position of the point and the element. + * For example, in the case of an overlay for a gateway with 3 incoming elements (top/bottom and right): + * 1. For the left connection, there will be a vertical overlay on the left of element + * 2. For the top and bottom connections, there will be a horizontal overlay on the top and bottom of element + * + * @param {TransactionBoundaryOverlayData} config - the configuration object for creating the overlay + * @param {Shape} config.shape - the diagram shape for which the overlay is created. + * @param {Waypoint} config.waypoint - a waypoint used for alignment and orientation. + * @param {string} config.beforeType - the type of transaction if transaction is done before the element. + * @param {TransactionBoundary} config.transactionBoundary - transaction boundary details. + * @returns {OverlayAttrs} The calculated attributes for the overlay, such as HTML structure and position. + */ +export const createTransactionBoundaryOverlay = ({ + + shape, + waypoint, + beforeType, + transactionBoundary + }: TransactionBoundaryOverlayData): OverlayAttrs => { + + let orientation: Orientation = getOrientation(waypoint, shape, -7); + + if (orientation === 'intersect') { + // Try again using a bigger padding to get an orientation which is not 'intersect'. + // Otherwise the boundary would not be visible if the connection is attached on the + // diagonal edge of a gateway. Not perfect, but much better than showing no overlay at all. + orientation = getOrientation(waypoint, shape, -20); + } + + let strokeWidth = 7; //width of overlay dot line + const offset = 5; //overlay offset from top/right + + let margin = 2; + + let position: OverlayPosition = {}; + let height: number; + let width: number; + + if (beforeType === BeforeElementTransactionType.ENGINE_WAIT_STATE && transactionBoundary && transactionBoundary.asyncBefore) { + margin = margin + strokeWidth + 5; //the "waiting state" overlay is always added to the left of the "async before" overlay + } + + // if orientation is either 'left', 'top-left' or 'bottom-left' + if (/left/.test(orientation)) { + width = strokeWidth; + height = shape.height + 2 * offset; + + // horizontal position: at the left border respecting margin + // vertical position: slightly above the diagram element + position.left = -width - margin; + position.top = -offset; + + console.log("left position: ", beforeType, width, margin) + + // if orientation is either 'right', 'top-right' or 'bottom-right' + } else if (/right/.test(orientation)) { + + width = strokeWidth; + height = shape.height + 2 * offset; + + // horizontal position: at the right border respecting margin + // vertical position: slightly above the diagram element + position.right = -margin; + position.top = -offset; + + } else if (orientation === 'top') { + width = shape.width; + height = strokeWidth; + + // horizontal position: slightly right to the diagram element start + // vertical position: at the top border respecting margin + position.left = -offset; + position.top = -offset - margin; + + } else if (orientation === 'bottom') { + width = shape.width; + height = strokeWidth; + + // horizontal position: slightly right to the diagram element start + // vertical position: at the bottom border respecting margin + position.bottom = -margin; + position.left = -offset; + } + + const isHorizontalOverlay = orientation === 'top' || orientation === 'bottom'; + const className = isHorizontalOverlay ? 'transaction-boundary-horizontal-overlay' : + 'transaction-boundary-vertical-overlay'; + + const additionalClassName = beforeType === BeforeElementTransactionType.ENGINE_WAIT_STATE ? 'engine-wait-state' : ''; + + return { + html: `
`, + position: position + } +}; \ No newline at end of file diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/types.ts b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/types.ts index 4233972..e9bc05a 100644 --- a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/types.ts +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/overlay/types.ts @@ -13,6 +13,7 @@ export enum OverlayType { ACTIVITY_STATISTICS = 'activity-statistics', INCIDENT_COUNT = 'incident-count', SEND_MESSAGE = 'send-message', + TRANSACTION_BOUNDARY = 'transaction-boundary' } export interface IncidentOverlayData { diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/styles/bpmnViewerStyles.ts b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/styles/bpmnViewerStyles.ts index 97a51ef..9768db3 100644 --- a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/styles/bpmnViewerStyles.ts +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/styles/bpmnViewerStyles.ts @@ -134,4 +134,20 @@ export const bpmnViewerStyles = css` border-radius: var(--lumo-border-radius-m); border: var(--bpmn-group-overlay-border); } + + .transaction-boundary-vertical-overlay { + background: var(--bpmn-async-transaction-overlay-vertical-background); + } + + .transaction-boundary-horizontal-overlay { + background: var(--bpmn-async-transaction-boundary-overlay-horizontal-background); + } + + .transaction-boundary-vertical-overlay.engine-wait-state { + background: var(--bpmn-engine-transaction-overlay-vertical-background); + } + + .transaction-boundary-horizontal-overlay.engine-wait-state { + background: var(--bpmn-engine-transaction-boundary-overlay-horizontal-background); + } `; \ No newline at end of file diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/types.ts b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/types.ts index 15bb85b..b189232 100644 --- a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/types.ts +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/types.ts @@ -39,4 +39,15 @@ export interface ActivityData { id: string; name?: string; type: string; +} + +export interface ElementTransactionBoundary { + asyncBefore: boolean; + asyncAfter: boolean; + engineWaitState: boolean; +} + +export enum BeforeElementTransactionType { + ENGINE_WAIT_STATE = 'ENGINE_WAIT_STATE', + ASYNC_BEFORE = 'ASYNC_BEFORE' } \ No newline at end of file diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/bpmnEventUtils.ts b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/eventDefinitionUtils.ts similarity index 88% rename from flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/bpmnEventUtils.ts rename to flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/eventDefinitionUtils.ts index 1c905e8..a3f6ae9 100644 --- a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/bpmnEventUtils.ts +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/eventDefinitionUtils.ts @@ -27,7 +27,7 @@ export const getMessageEventDefinition = (element: ElementLike) => { return getEventDefinition(element, 'bpmn:MessageEventDefinition'); }; -export const getEventDefinition = (element: ElementLike, eventType: string)=> { +export const getEventDefinition = (element: ElementLike, eventType: string) => { const businessObject = getBusinessObject(element); const eventDefinitions = businessObject.get('eventDefinitions') || []; @@ -37,6 +37,12 @@ export const getEventDefinition = (element: ElementLike, eventType: string)=> { }); } +export const getEventDefinitions = (element: ElementLike) => { + const businessObject = getBusinessObject(element); + + return businessObject.get('eventDefinitions') || []; +} + export const getMessage = (element: ElementLike) => { const messageEventDefinition = getMessageEventDefinition(element); diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/transactionBoundaryUtils.ts b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/transactionBoundaryUtils.ts new file mode 100644 index 0000000..0141499 --- /dev/null +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/src/bpmn-viewer/utils/transactionBoundaryUtils.ts @@ -0,0 +1,116 @@ +/* + * Copyright (c) Haulmont 2025. All Rights Reserved. + * Use is subject to license terms. + */ + +import {ElementTransactionBoundary} from "../types"; +import {ElementLike} from "diagram-js/lib/model/Types"; +import {getBusinessObject, is, isAny} from 'bpmn-js/lib/util/ModelUtil'; +import {getEventDefinitions} from "./eventDefinitionUtils"; + +/** + * Determines the transaction boundary information for a given element. + * + * This function analyzes a specified element to determine its transaction boundaries + * based on its asynchronous continuations properties and default engine wait states. + * + * @param {ElementLike} element - a diagram element. + * @returns {ElementTransactionBoundary | undefined} an object containing transaction boundary details or undefined if element does not have transaction boundary + */ +export const getElementTransactionBoundary = (element: ElementLike): ElementTransactionBoundary | undefined => { + const businessObject = getBusinessObject(element); + const loopCharacteristics = businessObject.loopCharacteristics; + + const waitStateTask = isWaitStateTask(element); + const waitStateGateway = isWaitStateGateway(element); + const waitStateEvent = isWaitStateEvent(element); + + const asyncAfter = isAsyncAfter(businessObject) || (loopCharacteristics && isAsyncAfter(loopCharacteristics)); + const asyncBefore = isAsyncBefore(businessObject) || (loopCharacteristics && isAsyncBefore(loopCharacteristics)); + + const isWaitState = waitStateTask || waitStateEvent || waitStateGateway; + + if (isWaitState || asyncBefore || asyncAfter) { + return { + asyncBefore, + asyncAfter, + engineWaitState: isWaitState + }; + } + + return undefined; +} + +const isAsyncAfter = bo => { + const camundaAsyncAfter = !!bo.get('camunda:asyncAfter'); + if (camundaAsyncAfter) { + return true; + } + return !!bo.get('operaton:asyncAfter'); +}; + +const isAsyncBefore = bo => { + const camundaAsyncBefore = !!(bo.get('camunda:asyncBefore') || bo.get('camunda:async')); + if (camundaAsyncBefore) { + return true; + } + + return !!(bo.get('operaton:asyncBefore') || bo.get('operaton:async')); +}; + + +const isWaitStateEvent = (element: ElementLike) => { + const eventDefinitions = getEventDefinitions(element); + if (!eventDefinitions || eventDefinitions.length === 0) { + return false; + } + const eventDefinition = eventDefinitions[0]; + const eventDefinitionType = eventDefinition.$type; + + const isCatchEvent = is(element, 'bpmn:IntermediateCatchEvent'); + + const isMessageEvent = eventDefinitionType === 'bpmn:MessageEventDefinition'; + const isTimerEvent = eventDefinitionType === 'bpmn:TimerEventDefinition'; + const isSignalEvent = eventDefinitionType === 'bpmn:SignalEventDefinition'; + const isConditionalEvent = eventDefinitionType === 'bpmn:ConditionalEventDefinition'; + + if (isCatchEvent && (isMessageEvent || isTimerEvent || isSignalEvent || isConditionalEvent)) { + return true; + } + + const isThrowEvent = is(element, 'bpmn:IntermediateThrowEvent'); + const isEndEvent = is(element, 'bpmn:IntermediateEndEvent'); + + if (isMessageEvent && (isThrowEvent || isEndEvent)) { + const businessObject = getBusinessObject(eventDefinition); + + return hasExternalImplementation(businessObject); + } + + return false; +} + +const isWaitStateTask = (element) => { + if (isAny(element, ['bpmn:ReceiveTask', 'bpmn:UserTask'])) { + return true; + } + if (isAny(element, ['bpmn:ServiceTask', 'bpmn:SendTask', 'bpmn:BusinessRuleTask'])) { + const businessObject = getBusinessObject(element); + + return hasExternalImplementation(businessObject); + } + + return false; +} + +const hasExternalImplementation = businessObject => { + const camundaTaskType = businessObject.get('camunda:type'); + const operatonTaskType = businessObject.get('operaton:type'); + + return camundaTaskType === 'external' || operatonTaskType === 'external'; +} + +const isWaitStateGateway = (element) => { + return is(element, 'bpmn:EventBasedGateway'); +} + diff --git a/flowset-ui-kit/src/main/resources/META-INF/frontend/styles/bpmn-viewer.css b/flowset-ui-kit/src/main/resources/META-INF/frontend/styles/bpmn-viewer.css index 8765b77..623a108 100644 --- a/flowset-ui-kit/src/main/resources/META-INF/frontend/styles/bpmn-viewer.css +++ b/flowset-ui-kit/src/main/resources/META-INF/frontend/styles/bpmn-viewer.css @@ -28,4 +28,24 @@ --default-bpmn-element-overlay-size: 1.2em; --default-bpmn-element-overlay-font-size: var(--lumo-font-size-xxs); + + --bpmn-async-transaction-overlay-vertical-background: repeating-linear-gradient(to bottom, + var(--bpmn-async-transaction-boundary-overlay-color) 0px, + var(--bpmn-async-transaction-boundary-overlay-color) 15px, + transparent 10px, transparent 20px); + + --bpmn-engine-transaction-overlay-vertical-background: repeating-linear-gradient(to bottom, + var(--bpmn-engine-transaction-boundary-overlay-color) 0px, + var(--bpmn-engine-transaction-boundary-overlay-color) 15px, + transparent 10px, transparent 20px); + + --bpmn-async-transaction-boundary-overlay-horizontal-background: repeating-linear-gradient(to right, + var(--bpmn-async-transaction-boundary-overlay-color) 0px, + var(--bpmn-async-transaction-boundary-overlay-color) 15px, + transparent 10px, transparent 20px); + + --bpmn-engine-transaction-boundary-overlay-horizontal-background: repeating-linear-gradient(to right, + var(--bpmn-engine-transaction-boundary-overlay-color) 0px, + var(--bpmn-engine-transaction-boundary-overlay-color) 15px, + transparent 10px, transparent 20px); } \ No newline at end of file diff --git a/flowset-ui-kit/src/main/resources/io/flowset/uikit/fragment/bpmnviewer/bpmn-viewer-fragment.xml b/flowset-ui-kit/src/main/resources/io/flowset/uikit/fragment/bpmnviewer/bpmn-viewer-fragment.xml index 5c26c27..dcf558f 100644 --- a/flowset-ui-kit/src/main/resources/io/flowset/uikit/fragment/bpmnviewer/bpmn-viewer-fragment.xml +++ b/flowset-ui-kit/src/main/resources/io/flowset/uikit/fragment/bpmnviewer/bpmn-viewer-fragment.xml @@ -8,7 +8,7 @@