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

[FEAT] Render Non-instantiating Receive task #512

Merged
merged 7 commits into from
Aug 12, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/bpmn-support.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ The default rendering uses `white` as fill color and `black` as stroke color.
*icon*: the task icon is derived from the https://www.flaticon.com/free-icon/employees_554768[flaticon 'employees' icon] "Icons made by https://www.flaticon.com/authors/freepik[freepik] from https://www.flaticon.com"

|Receive Task
|
|
|icon:check-circle-o[]
|Icon may be subject to change +
⚠️ The render for the instantiating receive task is NOT done

|Send Task
|icon:check-circle-o[]
Expand Down
5 changes: 5 additions & 0 deletions src/component/mxgraph/StyleUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export enum StyleIdentifier {
BPMN_STYLE_SUB_PROCESS_KIND = 'bpmn.subProcessKind',
BPMN_STYLE_IS_INTERRUPTING = 'bpmn.isInterrupting',
BPMN_STYLE_MARKERS = 'bpmn.markers',
BPMN_STYLE_INSTANTIATING = 'bpmn.isInstantiating',
}

/* eslint-disable @typescript-eslint/no-explicit-any */
Expand Down Expand Up @@ -90,4 +91,8 @@ export default class StyleUtils {
public static getBpmnMarkers(style: any): string {
return mxUtils.getValue(style, StyleIdentifier.BPMN_STYLE_MARKERS, undefined);
}

public static getBpmnIsInstantiating(style: any): boolean {
return JSON.parse(mxUtils.getValue(style, StyleIdentifier.BPMN_STYLE_INSTANTIATING, false));
}
}
2 changes: 2 additions & 0 deletions src/component/mxgraph/config/StyleConfigurator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ export default class StyleConfigurator {
} else if (bpmnElement instanceof ShapeBpmnActivity) {
if (bpmnElement instanceof ShapeBpmnSubProcess) {
styleValues.set(StyleIdentifier.BPMN_STYLE_SUB_PROCESS_KIND, bpmnElement.subProcessKind);
} else if (bpmnElement.kind === ShapeBpmnElementKind.TASK_RECEIVE) {
styleValues.set(StyleIdentifier.BPMN_STYLE_INSTANTIATING, bpmnElement.instantiate.toString());
}

const markers: ShapeBpmnMarkerKind[] = bpmnElement.markers;
Expand Down
36 changes: 27 additions & 9 deletions src/component/mxgraph/shape/activity-shapes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ import { buildPaintParameter, IconPainterProvider, PaintParameter } from './rend
import { ShapeBpmnSubProcessKind } from '../../../model/bpmn/shape/ShapeBpmnSubProcessKind';
import { ShapeBpmnMarkerKind } from '../../../model/bpmn/shape/ShapeBpmnMarkerKind';
import BpmnCanvas from './render/BpmnCanvas';
function paintEnvelopeIcon(paintParameter: PaintParameter, isFilled: boolean): void {
csouchet marked this conversation as resolved.
Show resolved Hide resolved
IconPainterProvider.get().paintEnvelopeIcon({
...paintParameter,
setIconOrigin: (canvas: BpmnCanvas) => canvas.setIconOriginToShapeTopLeft(),
ratioFromParent: 0.2,
icon: { ...paintParameter.icon, isFilled: isFilled },
});
}

export abstract class BaseActivityShape extends mxRectangleShape {
protected iconPainter = IconPainterProvider.get();
Expand Down Expand Up @@ -116,11 +124,26 @@ export class UserTaskShape extends BaseTaskShape {
export class ReceiveTaskShape extends BaseTaskShape {
public constructor(bounds: mxRectangle, fill: string, stroke: string, strokewidth: number) {
super(bounds, fill, stroke, strokewidth);
this.gradient = 'Salmon';
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
protected paintTaskIcon(paintParameter: PaintParameter): void {}
// TODO To remove when the instantiating receive task render is implemented
public paintVertexShape(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void {
const isInstantiating = StyleUtils.getBpmnIsInstantiating(this.style);

if (isInstantiating) {
c.setFillColor('Salmon');
}

super.paintVertexShape(c, x, y, w, h);
}

protected paintTaskIcon(paintParameter: PaintParameter): void {
const isInstantiating = StyleUtils.getBpmnIsInstantiating(this.style);

if (!isInstantiating) {
paintEnvelopeIcon(paintParameter, false);
}
}
}

export class SendTaskShape extends BaseTaskShape {
Expand All @@ -129,12 +152,7 @@ export class SendTaskShape extends BaseTaskShape {
}

protected paintTaskIcon(paintParameter: PaintParameter): void {
this.iconPainter.paintEnvelopeIcon({
...paintParameter,
setIconOrigin: (canvas: BpmnCanvas) => canvas.setIconOriginToShapeTopLeft(),
ratioFromParent: 0.2,
icon: { ...paintParameter.icon, isFilled: true },
});
paintEnvelopeIcon(paintParameter, true);
}
}

Expand Down
43 changes: 27 additions & 16 deletions test/e2e/mxGraph.model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface ExpectedShapeModelElement {
/** Only needed when the BPMN shape doesn't exist yet (use an arbitrary shape until the final render is implemented) */
styleShape?: string;
markers?: ShapeBpmnMarkerKind[];
isInstantiating?: boolean;
}

export interface ExpectedEventModelElement extends ExpectedShapeModelElement {
Expand Down Expand Up @@ -123,6 +124,10 @@ describe('mxGraph model', () => {
expect(cell.style).toContain(`bpmn.markers=${modelElement.markers.join(',')}`);
}

if (modelElement.isInstantiating !== undefined) {
expect(cell.style).toContain(`bpmn.isInstantiating=${modelElement.isInstantiating}`);
}

const state = bpmnVisualization.graph.getView().getState(cell);
const styleShape = !modelElement.styleShape ? modelElement.kind : modelElement.styleShape;
expect(state.style[mxConstants.STYLE_SHAPE]).toEqual(styleShape);
Expand Down Expand Up @@ -657,39 +662,45 @@ describe('mxGraph model', () => {
markers: [ShapeBpmnMarkerKind.MULTI_INSTANCE_PARALLEL],
});

// Receive Task: Not instantiated
expectModelContainsShape('receiveTask_not_instantiated', { kind: ShapeBpmnElementKind.TASK_RECEIVE, label: 'Not instantiated Receive Task' });
expectModelContainsShape('receiveTask_not_instantiated_with_loop', {
// Receive Task: Non instantiating
expectModelContainsShape('receiveTask_non_instantiating', { kind: ShapeBpmnElementKind.TASK_RECEIVE, label: 'Non-instantiating Receive Task', isInstantiating: false });
expectModelContainsShape('receiveTask_non_instantiating_with_loop', {
kind: ShapeBpmnElementKind.TASK_RECEIVE,
label: 'Not instantiated Receive Task With Loop',
label: 'Non-instantiating Receive Task With Loop',
isInstantiating: false,
markers: [ShapeBpmnMarkerKind.LOOP],
});
expectModelContainsShape('receiveTask_not_instantiated_with_sequential_multi_instance', {
expectModelContainsShape('receiveTask_non_instantiating_with_sequential_multi_instance', {
kind: ShapeBpmnElementKind.TASK_RECEIVE,
label: 'Not instantiated Receive Task With Sequential Multi-instance',
label: 'Non-instantiating Receive Task With Sequential Multi-instance',
isInstantiating: false,
markers: [ShapeBpmnMarkerKind.MULTI_INSTANCE_SEQUENTIAL],
});
expectModelContainsShape('receiveTask_not_instantiated_with_parallel_multi_instance', {
expectModelContainsShape('receiveTask_non_instantiating_with_parallel_multi_instance', {
kind: ShapeBpmnElementKind.TASK_RECEIVE,
label: 'Not instantiated Receive Task With Parallel Multi-instance',
label: 'Non-instantiating Receive Task With Parallel Multi-instance',
isInstantiating: false,
markers: [ShapeBpmnMarkerKind.MULTI_INSTANCE_PARALLEL],
});

// Receive Task: Instantiated
expectModelContainsShape('receiveTask_instantiated', { kind: ShapeBpmnElementKind.TASK_RECEIVE, label: 'Instantiated Receive Task' });
expectModelContainsShape('receiveTask_instantiated_with_loop', {
// Receive Task: Instantiating
expectModelContainsShape('receiveTask_instantiating', { kind: ShapeBpmnElementKind.TASK_RECEIVE, label: 'Instantiating Receive Task', isInstantiating: true });
expectModelContainsShape('receiveTask_instantiating_with_loop', {
kind: ShapeBpmnElementKind.TASK_RECEIVE,
label: 'Instantiated Receive Task With Loop',
label: 'Instantiating Receive Task With Loop',
isInstantiating: true,
markers: [ShapeBpmnMarkerKind.LOOP],
});
expectModelContainsShape('receiveTask_instantiated_with_sequential_multi_instance', {
expectModelContainsShape('receiveTask_instantiating_with_sequential_multi_instance', {
kind: ShapeBpmnElementKind.TASK_RECEIVE,
label: 'Instantiated Receive Task With Sequential Multi-instance',
label: 'Instantiating Receive Task With Sequential Multi-instance',
isInstantiating: true,
markers: [ShapeBpmnMarkerKind.MULTI_INSTANCE_SEQUENTIAL],
});
expectModelContainsShape('receiveTask_instantiated_with_parallel_multi_instance', {
expectModelContainsShape('receiveTask_instantiating_with_parallel_multi_instance', {
kind: ShapeBpmnElementKind.TASK_RECEIVE,
label: 'Instantiated Receive Task With Parallel Multi-instance',
label: 'Instantiating Receive Task With Parallel Multi-instance',
isInstantiating: true,
markers: [ShapeBpmnMarkerKind.MULTI_INSTANCE_PARALLEL],
});

Expand Down
40 changes: 20 additions & 20 deletions test/fixtures/bpmn/model-complete-semantic.bpmn
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,27 @@
<semantic:multiInstanceLoopCharacteristics isSequential="false"/>
</semantic:userTask>

<!-- Receive Task: Not instantiated -->
<semantic:receiveTask id="receiveTask_not_instantiated" name="Not instantiated Receive Task"/>
<semantic:receiveTask id="receiveTask_not_instantiated_with_loop" name="Not instantiated Receive Task With Loop" >
<!-- Receive Task: Non-instantiating -->
<semantic:receiveTask id="receiveTask_non_instantiating" name="Non-instantiating Receive Task"/>
<semantic:receiveTask id="receiveTask_non_instantiating_with_loop" name="Non-instantiating Receive Task With Loop" >
<semantic:standardLoopCharacteristics id="1"/>
</semantic:receiveTask>
<semantic:receiveTask id="receiveTask_not_instantiated_with_sequential_multi_instance" name="Not instantiated Receive Task With Sequential Multi-instance" >
<semantic:receiveTask id="receiveTask_non_instantiating_with_sequential_multi_instance" name="Non-instantiating Receive Task With Sequential Multi-instance" >
<semantic:multiInstanceLoopCharacteristics isSequential="true"/>
</semantic:receiveTask>
<semantic:receiveTask id="receiveTask_not_instantiated_with_parallel_multi_instance" name="Not instantiated Receive Task With Parallel Multi-instance" >
<semantic:receiveTask id="receiveTask_non_instantiating_with_parallel_multi_instance" name="Non-instantiating Receive Task With Parallel Multi-instance" >
<semantic:multiInstanceLoopCharacteristics isSequential="false"/>
</semantic:receiveTask>

<!-- Receive Task: Instantiated -->
<semantic:receiveTask id="receiveTask_instantiated" name="Instantiated Receive Task" instantiate="true"/>
<semantic:receiveTask id="receiveTask_instantiated_with_loop" name="Instantiated Receive Task With Loop" instantiate="true">
<!-- Receive Task: Instantiating -->
<semantic:receiveTask id="receiveTask_instantiating" name="Instantiating Receive Task" instantiate="true"/>
<semantic:receiveTask id="receiveTask_instantiating_with_loop" name="Instantiating Receive Task With Loop" instantiate="true">
<semantic:standardLoopCharacteristics />
</semantic:receiveTask>
<semantic:receiveTask id="receiveTask_instantiated_with_sequential_multi_instance" name="Instantiated Receive Task With Sequential Multi-instance" instantiate="true">
<semantic:receiveTask id="receiveTask_instantiating_with_sequential_multi_instance" name="Instantiating Receive Task With Sequential Multi-instance" instantiate="true">
<semantic:multiInstanceLoopCharacteristics isSequential="true"/>
</semantic:receiveTask>
<semantic:receiveTask id="receiveTask_instantiated_with_parallel_multi_instance" name="Instantiated Receive Task With Parallel Multi-instance" instantiate="true">
<semantic:receiveTask id="receiveTask_instantiating_with_parallel_multi_instance" name="Instantiating Receive Task With Parallel Multi-instance" instantiate="true">
<semantic:multiInstanceLoopCharacteristics/>
</semantic:receiveTask>

Expand Down Expand Up @@ -503,31 +503,31 @@
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>

<!-- Receive Task: Not instantiated -->
<bpmndi:BPMNShape bpmnElement="receiveTask_not_instantiated" id="S1373649849862_receiveTask_not_instantiated">
<!-- Receive Task: Non-instantiating -->
<bpmndi:BPMNShape bpmnElement="receiveTask_non_instantiating" id="S1373649849862_receiveTask_non_instantiating">
<dc:Bounds height="32.0" width="32.0" x="87.0" y="335.0" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="receiveTask_not_instantiated_with_loop" id="S1373649849862_receiveTask_not_instantiated_with_loop">
<bpmndi:BPMNShape bpmnElement="receiveTask_non_instantiating_with_loop" id="S1373649849862_receiveTask_non_instantiating_with_loop">
<dc:Bounds height="32.0" width="32.0" x="87.0" y="335.0" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="receiveTask_not_instantiated_with_sequential_multi_instance" id="S1373649849862_receiveTask_not_instantiated_with_sequential_multi_instance">
<bpmndi:BPMNShape bpmnElement="receiveTask_non_instantiating_with_sequential_multi_instance" id="S1373649849862_receiveTask_non_instantiating_with_sequential_multi_instance">
<dc:Bounds height="32.0" width="32.0" x="87.0" y="335.0" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="receiveTask_not_instantiated_with_parallel_multi_instance" id="S1373649849862_receiveTask_not_instantiated_with_parallel_multi_instance">
<bpmndi:BPMNShape bpmnElement="receiveTask_non_instantiating_with_parallel_multi_instance" id="S1373649849862_receiveTask_non_instantiating_with_parallel_multi_instance">
<dc:Bounds height="32.0" width="32.0" x="87.0" y="335.0" />
</bpmndi:BPMNShape>

<!-- Receive Task: Instantiated -->
<bpmndi:BPMNShape bpmnElement="receiveTask_instantiated" id="S1373649849862_receiveTask_instantiated">
<!-- Receive Task: Instantiating -->
<bpmndi:BPMNShape bpmnElement="receiveTask_instantiating" id="S1373649849862_receiveTask_instantiating">
<dc:Bounds height="32.0" width="32.0" x="87.0" y="335.0" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="receiveTask_instantiated_with_loop" id="S1373649849862_receiveTask_instantiated_with_loop">
<bpmndi:BPMNShape bpmnElement="receiveTask_instantiating_with_loop" id="S1373649849862_receiveTask_instantiating_with_loop">
<dc:Bounds height="32.0" width="32.0" x="87.0" y="335.0" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="receiveTask_instantiated_with_sequential_multi_instance" id="S1373649849862_receiveTask_instantiated_with_sequential_multi_instance">
<bpmndi:BPMNShape bpmnElement="receiveTask_instantiating_with_sequential_multi_instance" id="S1373649849862_receiveTask_instantiating_with_sequential_multi_instance">
<dc:Bounds height="32.0" width="32.0" x="87.0" y="335.0" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="receiveTask_instantiated_with_parallel_multi_instance" id="S1373649849862_receiveTask_instantiated_with_parallel_multi_instance">
<bpmndi:BPMNShape bpmnElement="receiveTask_instantiating_with_parallel_multi_instance" id="S1373649849862_receiveTask_instantiating_with_parallel_multi_instance">
<dc:Bounds height="32.0" width="32.0" x="87.0" y="335.0" />
</bpmndi:BPMNShape>

Expand Down
17 changes: 14 additions & 3 deletions test/unit/component/mxgraph/config/StyleConfigurator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ function newShapeBpmnElement(kind: ShapeBpmnElementKind): ShapeBpmnElement {
return new ShapeBpmnElement('id', 'name', kind);
}

function newShapeBpmnActivity(kind: ShapeBpmnElementKind, markers?: ShapeBpmnMarkerKind[]): ShapeBpmnElement {
return new ShapeBpmnActivity('id', 'name', kind, undefined, undefined, markers);
function newShapeBpmnActivity(kind: ShapeBpmnElementKind, markers?: ShapeBpmnMarkerKind[], instantiate?: boolean): ShapeBpmnElement {
return new ShapeBpmnActivity('id', 'name', kind, undefined, instantiate, markers);
}

function newShapeBpmnCallActivity(markers?: ShapeBpmnMarkerKind[]): ShapeBpmnElement {
Expand Down Expand Up @@ -280,6 +280,16 @@ describe('mxgraph renderer', () => {
});
});

describe('compute style - receive tasks', () => {
it.each([
['non-instantiating', false],
['instantiating', true],
])('%s receive task', (instantiatingKind: string, instantiate: boolean) => {
const shape = newShape(newShapeBpmnActivity(ShapeBpmnElementKind.TASK_RECEIVE, undefined, instantiate), newLabel({ name: 'Arial' }));
expect(computeStyle(shape)).toEqual(`receiveTask;bpmn.isInstantiating=${instantiate};fontFamily=Arial`);
});
});

describe('compute style - text annotation', () => {
it('without label', () => {
const shape = newShape(newShapeBpmnElement(ShapeBpmnElementKind.TEXT_ANNOTATION));
Expand Down Expand Up @@ -312,7 +322,8 @@ describe('mxgraph renderer', () => {
(markerKind: ShapeBpmnMarkerKind) => {
it(`${bpmnKind} with ${markerKind} marker`, () => {
const shape = newShape(newShapeBpmnActivity(bpmnKind, [markerKind]), newLabel({ name: 'Arial' }));
expect(computeStyle(shape)).toEqual(`${bpmnKind};bpmn.markers=${markerKind};fontFamily=Arial`);
const additionalReceiveTaskStyle = bpmnKind === ShapeBpmnElementKind.TASK_RECEIVE ? ';bpmn.isInstantiating=false' : '';
expect(computeStyle(shape)).toEqual(`${bpmnKind}${additionalReceiveTaskStyle};bpmn.markers=${markerKind};fontFamily=Arial`);
});

if (bpmnKind == ShapeBpmnElementKind.SUB_PROCESS) {
Expand Down