Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Don't display elements of a Collapsed Sub-Process #772

Merged
merged 10 commits into from
Oct 16, 2020
Merged
54 changes: 48 additions & 6 deletions src/component/mxgraph/MxGraphRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,34 @@
import Shape from '../../model/bpmn/internal/shape/Shape';
import Edge from '../../model/bpmn/internal/edge/Edge';
import BpmnModel from '../../model/bpmn/internal/BpmnModel';
import ShapeBpmnElement from '../../model/bpmn/internal/shape/ShapeBpmnElement';
import ShapeBpmnElement, { ShapeBpmnSubProcess } from '../../model/bpmn/internal/shape/ShapeBpmnElement';
import Waypoint from '../../model/bpmn/internal/edge/Waypoint';
import Bounds from '../../model/bpmn/internal/Bounds';
import ShapeUtil from '../../model/bpmn/internal/shape/ShapeUtil';
import CoordinatesTranslator from './renderer/CoordinatesTranslator';
import StyleConfigurator from './config/StyleConfigurator';
import { MessageFlow } from '../../model/bpmn/internal/edge/Flow';
import { MessageVisibleKind } from '../../model/bpmn/internal/edge/MessageVisibleKind';
import { ShapeBpmnMarkerKind } from '../../model/bpmn/internal/shape';

export default class MxGraphRenderer {
constructor(readonly graph: mxGraph, readonly coordinatesTranslator: CoordinatesTranslator, readonly styleConfigurator: StyleConfigurator) {}

public render(bpmnModel: BpmnModel): void {
const displayedModel = toDisplayedModel(bpmnModel);

const model = this.graph.getModel();
model.clear(); // ensure to remove manual changes or already loaded graphs
model.beginUpdate();
try {
this.insertShapes(bpmnModel.pools);
this.insertShapes(bpmnModel.lanes);
this.insertShapes(bpmnModel.flowNodes.filter(shape => !ShapeUtil.isBoundaryEvent(shape.bpmnElement?.kind)));
this.insertShapes(bpmnModel.flowNodes.filter(shape => ShapeUtil.isBoundaryEvent(shape.bpmnElement?.kind)));
this.insertEdges(bpmnModel.edges);
this.insertShapes(displayedModel.pools);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 It's easier to read, but instead of adding a new class, I will have rather modify the BPMNModel, since we already distinguish between Lane / Pool / Flownode in the shapes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not but this means removing from the model children of the collapsed subprocess.
I don't see any impacts for now for the rendering but I haven't think about future features that could be impacted by such a change.

Copy link
Member

@tbouffard tbouffard Oct 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do such a refactoring in another PR. With the current changes, everything occur only in the Render file?
Changes directly in the model will have more impacts, so to keep this PR foccused on the fix, this is probably better to limit changes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem 😄

this.insertShapes(displayedModel.lanes);
this.insertShapes(displayedModel.subprocesses);
this.insertShapes(displayedModel.otherFlowNodes);
// last shape as the boundary event parent must be in the model (subprocess or activity)
this.insertShapes(displayedModel.boundaryEvents);
// at last as edge source and target must be present in the model prior insertion, otherwise they are not rendered
this.insertEdges(displayedModel.edges);
} finally {
model.endUpdate();
}
Expand Down Expand Up @@ -148,3 +154,39 @@ export default class MxGraphRenderer {
export function defaultMxGraphRenderer(graph: mxGraph): MxGraphRenderer {
return new MxGraphRenderer(graph, new CoordinatesTranslator(graph), new StyleConfigurator(graph));
}

function toDisplayedModel(bpmnModel: BpmnModel): DisplayedModel {
const collapsedSubProcessIds: string[] = bpmnModel.flowNodes
.filter(shape => {
const bpmnElement = shape.bpmnElement;
return ShapeUtil.isSubProcess(bpmnElement?.kind) && (bpmnElement as ShapeBpmnSubProcess)?.markers.includes(ShapeBpmnMarkerKind.EXPAND);
})
.map(shape => shape.bpmnElement?.id);

const subprocesses: Shape[] = [];
const boundaryEvents: Shape[] = [];
const otherFlowNodes: Shape[] = [];
bpmnModel.flowNodes.forEach(shape => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

ℹ️ If we change BPMNModel, no need this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what do we do for this code. Do we revert the last commit to restore the 3 array filters or do we keep it like this?
cc @aibcmars

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's ok for me :)

const kind = shape.bpmnElement?.kind;
if (ShapeUtil.isSubProcess(kind)) {
subprocesses.push(shape);
} else if (!collapsedSubProcessIds.includes(shape.bpmnElement?.parentId)) {
if (ShapeUtil.isBoundaryEvent(kind)) {
boundaryEvents.push(shape);
} else {
otherFlowNodes.push(shape);
}
}
});

return { boundaryEvents: boundaryEvents, edges: bpmnModel.edges, lanes: bpmnModel.lanes, otherFlowNodes: otherFlowNodes, pools: bpmnModel.pools, subprocesses: subprocesses };
}

interface DisplayedModel {
edges: Edge[];
boundaryEvents: Shape[];
otherFlowNodes: Shape[];
lanes: Shape[];
pools: Shape[];
subprocesses: Shape[];
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions test/e2e/mxGraph.model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,8 @@ describe('mxGraph model', () => {
verticalAlign: 'bottom',
});

expect('task_in_collapsed_sub_process_id').not.toBeCell();

// Start Event in Event Sub Process
// Interrupting Start Event
expect('start_event_interrupting_message_id').toBeStartEvent({
Expand Down
10 changes: 9 additions & 1 deletion test/fixtures/bpmn/model-complete-semantic.bpmn
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@
</semantic:subProcess>

<!-- Collapsed -->
<semantic:subProcess id="collapsed_embedded_sub_process_id" name="Collapsed Embedded Sub-Process" />
<semantic:subProcess id="collapsed_embedded_sub_process_id" name="Collapsed Embedded Sub-Process" >
<semantic:task id="task_in_collapsed_sub_process_id" name="Task In Collapsed Sub-Process"/>
</semantic:subProcess>
<semantic:subProcess id="collapsed_embedded_sub_process_with_loop_id" name="Collapsed Embedded Sub-Process With Loop">
<semantic:standardLoopCharacteristics />
</semantic:subProcess>
Expand Down Expand Up @@ -741,9 +743,15 @@
</bpmndi:BPMNShape>

<!-- Collapsed -->
<!-- Expanded with elements -->
<bpmndi:BPMNShape id="shape_collapsed_embedded_sub_process_id" bpmnElement="collapsed_embedded_sub_process_id" isExpanded="false">
<dc:Bounds x="3415" y="2175" width="140" height="90" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape_task_in_collapsed_sub_process_id" bpmnElement="task_in_collapsed_sub_process_id">
<dc:Bounds x="3435" y="2180" width="100" height="80" />
</bpmndi:BPMNShape>
<!-- END OF "Expanded with elements" -->

<bpmndi:BPMNShape id="shape_collapsed_embedded_sub_process_with_loop_id" bpmnElement="collapsed_embedded_sub_process_with_loop_id" isExpanded="false">
<dc:Bounds x="3415" y="2035" width="140" height="90" />
</bpmndi:BPMNShape>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_08ie96i" targetNamespace="http://bpmn.io/schema/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="7.3.0">
<bpmn:globalTask id="Activity_0xpd4f7" name="Called Global Task" implementation="##WebService" />
<bpmn:process id="Process_083f5uf" isExecutable="false">
<bpmn:subProcess id="Expanded_event_sub_process" triggeredByEvent="true">
<bpmn:task id="Activity_0x447u4">
<bpmn:incoming>Flow_0cjf31m</bpmn:incoming>
<bpmn:outgoing>Flow_06jg95n</bpmn:outgoing>
</bpmn:task>
<bpmn:startEvent id="Event_12w0lsa">
<bpmn:outgoing>Flow_0cjf31m</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:endEvent id="Event_1g31fpy">
<bpmn:incoming>Flow_06jg95n</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_06jg95n" sourceRef="Activity_0x447u4" targetRef="Event_1g31fpy" />
<bpmn:sequenceFlow id="Flow_0cjf31m" sourceRef="Event_12w0lsa" targetRef="Activity_0x447u4" />
</bpmn:subProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_083f5uf">
<bpmndi:BPMNShape id="Expanded_event_sub_process_di" bpmnElement="Expanded_event_sub_process" isExpanded="false">
<dc:Bounds x="160" y="80" width="345" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0cjf31m_di" bpmnElement="Flow_0cjf31m">
<di:waypoint x="228" y="180" />
<di:waypoint x="290" y="180" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_06jg95n_di" bpmnElement="Flow_06jg95n">
<di:waypoint x="390" y="180" />
<di:waypoint x="442" y="180" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Activity_0x447u4_di" bpmnElement="Activity_0x447u4">
<dc:Bounds x="290" y="140" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_12w0lsa_di" bpmnElement="Event_12w0lsa">
<dc:Bounds x="192" y="162" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1g31fpy_di" bpmnElement="Event_1g31fpy">
<dc:Bounds x="442" y="162" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>