diff --git a/lib/features/popup-menu/ReplaceMenuProvider.js b/lib/features/popup-menu/ReplaceMenuProvider.js index dd6897051f..fe0f147140 100644 --- a/lib/features/popup-menu/ReplaceMenuProvider.js +++ b/lib/features/popup-menu/ReplaceMenuProvider.js @@ -100,6 +100,9 @@ ReplaceMenuProvider.prototype.getPopupMenuEntries = function(target) { var rules = this._rules; + var sameTypeEventOptions = [], + eventDefinitionType; + var filteredReplaceOptions = []; if (isArray(target) || !rules.allowed('shape.replace', { element: target })) { @@ -116,10 +119,26 @@ ReplaceMenuProvider.prototype.getPopupMenuEntries = function(target) { return this._createEntries(target, replaceOptions.DATA_STORE_REFERENCE); } + // typed start, intermediate, and end events + if (is(businessObject, 'bpmn:Event') && !is(businessObject, 'bpmn:BoundaryEvent')) { + eventDefinitionType = businessObject.get('eventDefinitions')[0]?.$type; + + sameTypeEventOptions = replaceOptions.TYPED_EVENT[eventDefinitionType] || []; + + if (!isEventSubProcess(businessObject.$parent) && is(businessObject.$parent, 'bpmn:SubProcess')) { + sameTypeEventOptions = filter(sameTypeEventOptions, function(option) { + return option.target.type !== 'bpmn:StartEvent'; + }); + } + } + // start events outside sub processes if (is(businessObject, 'bpmn:StartEvent') && !is(businessObject.$parent, 'bpmn:SubProcess')) { - filteredReplaceOptions = filter(replaceOptions.START_EVENT, differentType); + filteredReplaceOptions = filter( + replaceOptions.START_EVENT.concat(sameTypeEventOptions), + differentType + ); return this._createEntries(target, filteredReplaceOptions); } @@ -136,18 +155,20 @@ ReplaceMenuProvider.prototype.getPopupMenuEntries = function(target) { // start events inside event sub processes if (is(businessObject, 'bpmn:StartEvent') && isEventSubProcess(businessObject.$parent)) { - filteredReplaceOptions = filter(replaceOptions.EVENT_SUB_PROCESS_START_EVENT, function(replaceOption) { + filteredReplaceOptions = filter( + replaceOptions.EVENT_SUB_PROCESS_START_EVENT.concat(sameTypeEventOptions), function(replaceOption) { - var target = replaceOption.target; + var target = replaceOption.target; - var isInterrupting = target.isInterrupting !== false; + var isInterrupting = target.isInterrupting !== false; - var isInterruptingEqual = businessObject.isInterrupting === isInterrupting; + var isInterruptingEqual = businessObject.isInterrupting === isInterrupting; - // filters elements which types and event definition are equal but have have different interrupting types - return differentType(replaceOption) || !differentType(replaceOption) && !isInterruptingEqual; + // filters elements which types and event definition are equal but have have different interrupting types + return differentType(replaceOption) || !differentType(replaceOption) && !isInterruptingEqual; - }); + } + ); return this._createEntries(target, filteredReplaceOptions); } @@ -155,7 +176,10 @@ ReplaceMenuProvider.prototype.getPopupMenuEntries = function(target) { // start events inside sub processes if (is(businessObject, 'bpmn:StartEvent') && !isEventSubProcess(businessObject.$parent) && is(businessObject.$parent, 'bpmn:SubProcess')) { - filteredReplaceOptions = filter(replaceOptions.START_EVENT_SUB_PROCESS, differentType); + filteredReplaceOptions = filter( + replaceOptions.START_EVENT_SUB_PROCESS.concat(sameTypeEventOptions), + differentType + ); return this._createEntries(target, filteredReplaceOptions); } @@ -163,7 +187,7 @@ ReplaceMenuProvider.prototype.getPopupMenuEntries = function(target) { // end events if (is(businessObject, 'bpmn:EndEvent')) { - filteredReplaceOptions = filter(replaceOptions.END_EVENT, function(replaceOption) { + filteredReplaceOptions = filter(replaceOptions.END_EVENT.concat(sameTypeEventOptions), function(replaceOption) { var target = replaceOption.target; // hide cancel end events outside transactions @@ -202,7 +226,10 @@ ReplaceMenuProvider.prototype.getPopupMenuEntries = function(target) { if (is(businessObject, 'bpmn:IntermediateCatchEvent') || is(businessObject, 'bpmn:IntermediateThrowEvent')) { - filteredReplaceOptions = filter(replaceOptions.INTERMEDIATE_EVENT, differentType); + filteredReplaceOptions = filter( + replaceOptions.INTERMEDIATE_EVENT.concat(sameTypeEventOptions), + differentType + ); return this._createEntries(target, filteredReplaceOptions); } diff --git a/lib/features/replace/ReplaceOptions.js b/lib/features/replace/ReplaceOptions.js index 278a3026e7..79e032a0f9 100644 --- a/lib/features/replace/ReplaceOptions.js +++ b/lib/features/replace/ReplaceOptions.js @@ -996,3 +996,203 @@ export var PARTICIPANT = [ } } ]; + +/** + * @type {{ [key: string]: ReplaceOption[]}} + */ +export var TYPED_EVENT = { + 'bpmn:MessageEventDefinition': [ + { + label: 'Message start event', + actionName: 'replace-with-message-start', + className: 'bpmn-icon-start-event-message', + target: { + type: 'bpmn:StartEvent', + eventDefinitionType: 'bpmn:MessageEventDefinition' + } + }, + { + label: 'Message intermediate catch event', + actionName: 'replace-with-message-intermediate-catch', + className: 'bpmn-icon-intermediate-event-catch-message', + target: { + type: 'bpmn:IntermediateCatchEvent', + eventDefinitionType: 'bpmn:MessageEventDefinition' + } + }, + { + label: 'Message intermediate throw event', + actionName: 'replace-with-message-intermediate-throw', + className: 'bpmn-icon-intermediate-event-throw-message', + target: { + type: 'bpmn:IntermediateThrowEvent', + eventDefinitionType: 'bpmn:MessageEventDefinition' + } + }, + { + label: 'Message end event', + actionName: 'replace-with-message-end', + className: 'bpmn-icon-end-event-message', + target: { + type: 'bpmn:EndEvent', + eventDefinitionType: 'bpmn:MessageEventDefinition' + } + } + ], + 'bpmn:TimerEventDefinition': [ + { + label: 'Timer start event', + actionName: 'replace-with-timer-start', + className: 'bpmn-icon-start-event-timer', + target: { + type: 'bpmn:StartEvent', + eventDefinitionType: 'bpmn:TimerEventDefinition' + } + }, + { + label: 'Timer intermediate catch event', + actionName: 'replace-with-timer-intermediate-catch', + className: 'bpmn-icon-intermediate-event-catch-timer', + target: { + type: 'bpmn:IntermediateCatchEvent', + eventDefinitionType: 'bpmn:TimerEventDefinition' + } + } + ], + 'bpmn:ConditionalEventDefinition': [ + { + label: 'Conditional start event', + actionName: 'replace-with-conditional-start', + className: 'bpmn-icon-start-event-condition', + target: { + type: 'bpmn:StartEvent', + eventDefinitionType: 'bpmn:ConditionalEventDefinition' + } + }, + { + label: 'Conditional intermediate catch event', + actionName: 'replace-with-conditional-intermediate-catch', + className: 'bpmn-icon-intermediate-event-catch-condition', + target: { + type: 'bpmn:IntermediateCatchEvent', + eventDefinitionType: 'bpmn:ConditionalEventDefinition' + } + } + ], + 'bpmn:SignalEventDefinition': [ + { + label: 'Signal start event', + actionName: 'replace-with-signal-start', + className: 'bpmn-icon-start-event-signal', + target: { + type: 'bpmn:StartEvent', + eventDefinitionType: 'bpmn:SignalEventDefinition' + } + }, + { + label: 'Signal intermediate catch event', + actionName: 'replace-with-signal-intermediate-catch', + className: 'bpmn-icon-intermediate-event-catch-signal', + target: { + type: 'bpmn:IntermediateCatchEvent', + eventDefinitionType: 'bpmn:SignalEventDefinition' + } + }, + { + label: 'Signal intermediate throw event', + actionName: 'replace-with-signal-intermediate-throw', + className: 'bpmn-icon-intermediate-event-throw-signal', + target: { + type: 'bpmn:IntermediateThrowEvent', + eventDefinitionType: 'bpmn:SignalEventDefinition' + } + }, + { + label: 'Signal end event', + actionName: 'replace-with-signal-end', + className: 'bpmn-icon-end-event-signal', + target: { + type: 'bpmn:EndEvent', + eventDefinitionType: 'bpmn:SignalEventDefinition' + } + } + ], + 'bpmn:ErrorEventDefinition': [ + { + label: 'Error start event', + actionName: 'replace-with-error-start', + className: 'bpmn-icon-start-event-error', + target: { + type: 'bpmn:StartEvent', + eventDefinitionType: 'bpmn:ErrorEventDefinition' + } + }, + { + label: 'Error end event', + actionName: 'replace-with-error-end', + className: 'bpmn-icon-end-event-error', + target: { + type: 'bpmn:EndEvent', + eventDefinitionType: 'bpmn:ErrorEventDefinition' + } + } + ], + 'bpmn:EscalationEventDefinition': [ + { + label: 'Escalation start event', + actionName: 'replace-with-escalation-start', + className: 'bpmn-icon-start-event-escalation', + target: { + type: 'bpmn:StartEvent', + eventDefinitionType: 'bpmn:EscalationEventDefinition' + } + }, + { + label: 'Escalation intermediate throw event', + actionName: 'replace-with-escalation-intermediate-throw', + className: 'bpmn-icon-intermediate-event-throw-escalation', + target: { + type: 'bpmn:IntermediateThrowEvent', + eventDefinitionType: 'bpmn:EscalationEventDefinition' + } + }, + { + label: 'Escalation end event', + actionName: 'replace-with-escalation-end', + className: 'bpmn-icon-end-event-escalation', + target: { + type: 'bpmn:EndEvent', + eventDefinitionType: 'bpmn:EscalationEventDefinition' + } + } + ], + 'bpmn:CompensateEventDefinition': [ + { + label: 'Compensation start event', + actionName: 'replace-with-compensation-start', + className: 'bpmn-icon-start-event-compensation', + target: { + type: 'bpmn:StartEvent', + eventDefinitionType: 'bpmn:CompensateEventDefinition' + } + }, + { + label: 'Compensation intermediate throw event', + actionName: 'replace-with-compensation-intermediate-throw', + className: 'bpmn-icon-intermediate-event-throw-compensation', + target: { + type: 'bpmn:IntermediateThrowEvent', + eventDefinitionType: 'bpmn:CompensateEventDefinition' + } + }, + { + label: 'Compensation end event', + actionName: 'replace-with-compensation-end', + className: 'bpmn-icon-end-event-compensation', + target: { + type: 'bpmn:EndEvent', + eventDefinitionType: 'bpmn:CompensateEventDefinition' + } + } + ] +}; diff --git a/test/fixtures/bpmn/features/replace/01_replace.bpmn b/test/fixtures/bpmn/features/replace/01_replace.bpmn index e757a4fb3b..6a158d327f 100644 --- a/test/fixtures/bpmn/features/replace/01_replace.bpmn +++ b/test/fixtures/bpmn/features/replace/01_replace.bpmn @@ -1,5 +1,5 @@ - + SequenceFlow_1 @@ -70,9 +70,25 @@ - - + + + + + + + + + + + + + + + + + + @@ -97,8 +113,8 @@ - - + + @@ -165,9 +181,21 @@ + + + + + + + + + + + + diff --git a/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js b/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js index b25048b210..b2bdda5fd5 100644 --- a/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js +++ b/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js @@ -1094,7 +1094,7 @@ describe('features/popup-menu - replace menu provider', function() { expect(queryEntry('replace-with-non-interrupting-message-start')).to.be.null; expect(queryEntry('replace-with-message-start')).to.exist; - expect(queryBodyEntries()).to.have.length(11); + expect(queryBodyEntries()).to.have.length(14); }) ); @@ -1118,7 +1118,7 @@ describe('features/popup-menu - replace menu provider', function() { expect(queryEntry('replace-with-conditional-start')).to.exist; expect(queryEntry('replace-with-non-interrupting-conditional-start')).to.be.null; - expect(queryBodyEntries()).to.have.length(11); + expect(queryBodyEntries()).to.have.length(12); }) ); @@ -1240,6 +1240,107 @@ describe('features/popup-menu - replace menu provider', function() { }) ); + + it('should show corresponding variants for a timer event', + inject(function(elementRegistry) { + + // given + var timerStartEvent = elementRegistry.get('StartEvent_4'); + + // when + openPopup(timerStartEvent); + + // then + expect(queryEntry('replace-with-timer-start')).to.be.null; + expect(queryEntry('replace-with-timer-intermediate-catch')).exist; + }) + ); + + + it('should show corresponding variants for a message event', + inject(function(elementRegistry) { + + // given + var messageStartEvent = elementRegistry.get('StartEvent_5'); + + // when + openPopup(messageStartEvent); + + // then + expect(queryEntry('replace-with-message-start')).to.be.null; + expect(queryEntry('replace-with-message-intermediate-catch')).exist; + expect(queryEntry('replace-with-message-intermediate-throw')).exist; + expect(queryEntry('replace-with-message-end')).exist; + }) + ); + + + it('should show corresponding variants for a compensation event', + inject(function(elementRegistry) { + + // given + var messageStartEvent = elementRegistry.get('CompensationEvent'); + + // when + openPopup(messageStartEvent); + + // then + expect(queryEntry('replace-with-compensation-start')).to.be.null; + expect(queryEntry('replace-with-compensation-intermediate-throw')).to.be.null; + expect(queryEntry('replace-with-compensation-end')).exist; + }) + ); + + + it('should show corresponding variants for a conditional event', + inject(function(elementRegistry) { + + // given + var messageStartEvent = elementRegistry.get('ConditionalEvent'); + + // when + openPopup(messageStartEvent); + + // then + expect(queryEntry('replace-with-conditional-start')).exist; + expect(queryEntry('replace-with-conditional-intermediate-catch')).to.be.null; + }) + ); + + + it('should show corresponding variants for an error event', + inject(function(elementRegistry) { + + // given + var messageStartEvent = elementRegistry.get('ErrorEvent'); + + // when + openPopup(messageStartEvent); + + // then + expect(queryEntry('replace-with-error-start')).exist; + expect(queryEntry('replace-with-error-end')).to.be.null; + }) + ); + + + it('should NOT show corresponding start event variants for a message event in subprocess', + inject(function(elementRegistry) { + + // given + var messageStartEvent = elementRegistry.get('IntermediateCatchMessageEvent'); + + // when + openPopup(messageStartEvent); + + // then + expect(queryEntry('replace-with-message-start')).to.be.null; + expect(queryEntry('replace-with-message-intermediate-catch')).to.be.null; + expect(queryEntry('replace-with-message-intermediate-throw')).exist; + expect(queryEntry('replace-with-message-end')).exist; + }) + ); + }); @@ -1262,7 +1363,7 @@ describe('features/popup-menu - replace menu provider', function() { openPopup(endEvent); // then - expect(queryBodyEntries()).to.have.length(9); + expect(queryBodyEntries()).to.have.length(11); expect(queryEntry('replace-with-cancel-end')).to.exist; })