From 6f240f20e2e149091a52208be2709c5a677b9d16 Mon Sep 17 00:00:00 2001 From: Philipp Date: Wed, 1 Nov 2023 15:34:02 +0100 Subject: [PATCH] fix(delete-participant-behavior): ignore empty participants Related to https://github.com/camunda/camunda-modeler/issues/3941 --- lib/shared/DeleteParticipantBehaviour.js | 17 ++- .../DeleteParticipantBehaviorSpec.js | 114 +++++++++++++----- .../process-empty-participant.bpmn | 13 ++ .../DeleteParticipantBehaviorSpec.js | 114 +++++++++++++----- .../camunda-empty-participant.bpmn | 13 ++ 5 files changed, 205 insertions(+), 66 deletions(-) create mode 100644 test/camunda-cloud/process-empty-participant.bpmn create mode 100644 test/camunda-platform/camunda-empty-participant.bpmn diff --git a/lib/shared/DeleteParticipantBehaviour.js b/lib/shared/DeleteParticipantBehaviour.js index 8e0b3d6..a6953f2 100644 --- a/lib/shared/DeleteParticipantBehaviour.js +++ b/lib/shared/DeleteParticipantBehaviour.js @@ -1,11 +1,12 @@ -import { is } from 'bpmn-js/lib/util/ModelUtil'; import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor'; +import { is } from 'bpmn-js/lib/util/ModelUtil'; + const LOW_PRIORITY = 250; /** - * Camunda specific behavior ensuring process.isExecutable is kept after deleting - * the last Participant. + * Camunda-specific behavior ensuring `isExecutable` is kept after deleting + * the last participant. */ export default class DeleteParticipantBehaviour extends CommandInterceptor { constructor(eventBus, canvas, modeling) { @@ -21,12 +22,16 @@ export default class DeleteParticipantBehaviour extends CommandInterceptor { if (is(shape, 'bpmn:Participant') && collaborationRoot && - !collaborationRoot.businessObject.participants.length && + !collaborationRoot.businessObject.get('participants').length && is(newRoot, 'bpmn:Process')) { - const oldProcessBo = shape.businessObject.processRef; + const oldProcessBusinessObject = shape.businessObject.get('processRef'); + + if (!oldProcessBusinessObject) { + return; + } - modeling.updateProperties(newRoot, { isExecutable: oldProcessBo.isExecutable }); + modeling.updateProperties(newRoot, { isExecutable: oldProcessBusinessObject.get('isExecutable') }); } }, true); diff --git a/test/camunda-cloud/DeleteParticipantBehaviorSpec.js b/test/camunda-cloud/DeleteParticipantBehaviorSpec.js index 2ebaf02..9611074 100644 --- a/test/camunda-cloud/DeleteParticipantBehaviorSpec.js +++ b/test/camunda-cloud/DeleteParticipantBehaviorSpec.js @@ -5,56 +5,110 @@ import { import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil'; -import diagramXML from './process-executable-participant.bpmn'; +import participantXML from './process-executable-participant.bpmn'; +import emptyParticipantXML from './process-empty-participant.bpmn'; describe('camunda-platform/features/modeling - DeleteParticipantBehaviour', function() { - beforeEach(bootstrapCamundaCloudModeler(diagramXML)); + describe('set isExecuteable on new process after deleting last participant', function() { - describe('remove set isExecuteable on new Process', function() { + describe('non-empty participant', function() { - beforeEach(inject(function(elementRegistry, modeling) { + beforeEach(bootstrapCamundaCloudModeler(participantXML)); - // given - const shape = elementRegistry.get('Participant_1'); + beforeEach(inject(function(elementRegistry, modeling) { - // when - modeling.removeShape(shape); - })); + // given + const shape = elementRegistry.get('Participant_1'); + // when + modeling.removeShape(shape); + })); - it('should execute', inject(function(canvas) { - // then - const newRoot = getBusinessObject(canvas.getRootElement()); - expect(newRoot.isExecutable).to.be.true; - })); + it('should execute', inject(function(canvas) { + // then + const newRoot = getBusinessObject(canvas.getRootElement()); + expect(newRoot.isExecutable).to.be.true; + })); - it('should undo', inject(function(canvas, commandStack) { - // given - const newRoot = getBusinessObject(canvas.getRootElement()); + it('should undo', inject(function(canvas, commandStack) { - // when - commandStack.undo(); + // given + const newRoot = getBusinessObject(canvas.getRootElement()); - // then - expect(newRoot.isExecutable).not.to.exist; - })); + // when + commandStack.undo(); + // then + expect(newRoot.isExecutable).not.to.exist; + })); - it('should redo', inject(function(canvas, commandStack) { - // when - commandStack.undo(); - commandStack.redo(); + it('should redo', inject(function(canvas, commandStack) { - // then - const newRoot = getBusinessObject(canvas.getRootElement()); - expect(newRoot.isExecutable).to.be.true; - })); + // when + commandStack.undo(); + commandStack.redo(); + + // then + const newRoot = getBusinessObject(canvas.getRootElement()); + expect(newRoot.isExecutable).to.be.true; + })); + + }); + + + describe('empty participant', function() { + + beforeEach(bootstrapCamundaCloudModeler(emptyParticipantXML)); + + beforeEach(inject(function(elementRegistry, modeling) { + + // given + const shape = elementRegistry.get('Participant_1'); + + // when + modeling.removeShape(shape); + })); + + + it('should execute', inject(function(canvas) { + + // then + const newRoot = getBusinessObject(canvas.getRootElement()); + expect(newRoot.isExecutable).not.to.exist; + })); + + + it('should undo', inject(function(canvas, commandStack) { + + // given + const newRoot = getBusinessObject(canvas.getRootElement()); + + // when + commandStack.undo(); + + // then + expect(newRoot.isExecutable).not.to.exist; + })); + + + it('should redo', inject(function(canvas, commandStack) { + + // when + commandStack.undo(); + commandStack.redo(); + + // then + const newRoot = getBusinessObject(canvas.getRootElement()); + expect(newRoot.isExecutable).not.to.exist; + })); + + }); }); diff --git a/test/camunda-cloud/process-empty-participant.bpmn b/test/camunda-cloud/process-empty-participant.bpmn new file mode 100644 index 0000000..9eeea17 --- /dev/null +++ b/test/camunda-cloud/process-empty-participant.bpmn @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/test/camunda-platform/DeleteParticipantBehaviorSpec.js b/test/camunda-platform/DeleteParticipantBehaviorSpec.js index 1422dcf..5271175 100644 --- a/test/camunda-platform/DeleteParticipantBehaviorSpec.js +++ b/test/camunda-platform/DeleteParticipantBehaviorSpec.js @@ -5,56 +5,110 @@ import { import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil'; -import diagramXML from './camunda-executable-participant.bpmn'; +import participantXML from './camunda-executable-participant.bpmn'; +import emptyParticipantXML from './camunda-empty-participant.bpmn'; describe('camunda-platform/features/modeling - DeleteParticipantBehaviour', function() { - beforeEach(bootstrapCamundaPlatformModeler(diagramXML)); + describe('set isExecuteable on new process after deleting last participant', function() { - describe('remove set isExecuteable on new Process', function() { + describe('non-empty participant', function() { - beforeEach(inject(function(elementRegistry, modeling) { + beforeEach(bootstrapCamundaPlatformModeler(participantXML)); - // given - const shape = elementRegistry.get('Participant_1'); + beforeEach(inject(function(elementRegistry, modeling) { - // when - modeling.removeShape(shape); - })); + // given + const shape = elementRegistry.get('Participant_1'); + // when + modeling.removeShape(shape); + })); - it('should execute', inject(function(canvas) { - // then - const newRoot = getBusinessObject(canvas.getRootElement()); - expect(newRoot.isExecutable).to.be.true; - })); + it('should execute', inject(function(canvas) { + // then + const newRoot = getBusinessObject(canvas.getRootElement()); + expect(newRoot.isExecutable).to.be.true; + })); - it('should undo', inject(function(canvas, commandStack) { - // given - const newRoot = getBusinessObject(canvas.getRootElement()); + it('should undo', inject(function(canvas, commandStack) { - // when - commandStack.undo(); + // given + const newRoot = getBusinessObject(canvas.getRootElement()); - // then - expect(newRoot.isExecutable).not.to.exist; - })); + // when + commandStack.undo(); + // then + expect(newRoot.isExecutable).not.to.exist; + })); - it('should redo', inject(function(canvas, commandStack) { - // when - commandStack.undo(); - commandStack.redo(); + it('should redo', inject(function(canvas, commandStack) { - // then - const newRoot = getBusinessObject(canvas.getRootElement()); - expect(newRoot.isExecutable).to.be.true; - })); + // when + commandStack.undo(); + commandStack.redo(); + + // then + const newRoot = getBusinessObject(canvas.getRootElement()); + expect(newRoot.isExecutable).to.be.true; + })); + + }); + + + describe('empty participant', function() { + + beforeEach(bootstrapCamundaPlatformModeler(emptyParticipantXML)); + + beforeEach(inject(function(elementRegistry, modeling) { + + // given + const shape = elementRegistry.get('Participant_1'); + + // when + modeling.removeShape(shape); + })); + + + it('should execute', inject(function(canvas) { + + // then + const newRoot = getBusinessObject(canvas.getRootElement()); + expect(newRoot.isExecutable).not.to.exist; + })); + + + it('should undo', inject(function(canvas, commandStack) { + + // given + const newRoot = getBusinessObject(canvas.getRootElement()); + + // when + commandStack.undo(); + + // then + expect(newRoot.isExecutable).not.to.exist; + })); + + + it('should redo', inject(function(canvas, commandStack) { + + // when + commandStack.undo(); + commandStack.redo(); + + // then + const newRoot = getBusinessObject(canvas.getRootElement()); + expect(newRoot.isExecutable).not.to.exist; + })); + + }); }); diff --git a/test/camunda-platform/camunda-empty-participant.bpmn b/test/camunda-platform/camunda-empty-participant.bpmn new file mode 100644 index 0000000..b291244 --- /dev/null +++ b/test/camunda-platform/camunda-empty-participant.bpmn @@ -0,0 +1,13 @@ + + + + + + + + + + + + +