From 660348abc3b2cdd2037bbef2ee38fbde801a4b12 Mon Sep 17 00:00:00 2001 From: Alexis Zeghers <42282939+AZeghers@users.noreply.github.com> Date: Wed, 18 Nov 2020 11:39:01 +0100 Subject: [PATCH] feat(replace): add switch between DataStore and DataObject in replace menu Closes #1372 --- .../popup-menu/ReplaceMenuProvider.js | 8 ++ lib/features/replace/BpmnReplace.js | 16 +++ lib/features/replace/ReplaceOptions.js | 22 +++ lib/util/DiUtil.js | 2 +- .../{data-object.bpmn => data-elements.bpmn} | 15 +- .../context-pad/ContextPadProviderSpec.js | 6 +- .../popup-menu/ReplaceMenuProviderSpec.js | 49 ++++++- test/spec/features/replace/BpmnReplaceSpec.js | 130 ++++++++++++++++++ 8 files changed, 234 insertions(+), 14 deletions(-) rename test/fixtures/bpmn/features/replace/{data-object.bpmn => data-elements.bpmn} (72%) diff --git a/lib/features/popup-menu/ReplaceMenuProvider.js b/lib/features/popup-menu/ReplaceMenuProvider.js index cba8c275f3..3c6ae5a8b7 100644 --- a/lib/features/popup-menu/ReplaceMenuProvider.js +++ b/lib/features/popup-menu/ReplaceMenuProvider.js @@ -77,6 +77,14 @@ ReplaceMenuProvider.prototype.getEntries = function(element) { var differentType = isDifferentType(element); + if (is(businessObject, 'bpmn:DataObjectReference')) { + return this._createEntries(element, replaceOptions.DATA_OBJECT_REFERENCE); + } + + if (is(businessObject, 'bpmn:DataStoreReference')) { + return this._createEntries(element, replaceOptions.DATA_STORE_REFERENCE); + } + // start events outside sub processes if (is(businessObject, 'bpmn:StartEvent') && !is(businessObject.$parent, 'bpmn:SubProcess')) { diff --git a/lib/features/replace/BpmnReplace.js b/lib/features/replace/BpmnReplace.js index 5547d46789..c51c823e9e 100644 --- a/lib/features/replace/BpmnReplace.js +++ b/lib/features/replace/BpmnReplace.js @@ -84,6 +84,7 @@ export default function BpmnReplace( moddleCopy, modeling, replace, + rules, selection ) { @@ -221,6 +222,11 @@ export default function BpmnReplace( newElement.height = elementFactory._getDefaultSize(newBusinessObject).height; } + if (!rules.allowed('shape.resize', { shape: newBusinessObject })) { + newElement.height = elementFactory._getDefaultSize(newBusinessObject).height; + newElement.width = elementFactory._getDefaultSize(newBusinessObject).width; + } + newBusinessObject.name = oldBusinessObject.name; // retain default flow's reference between inclusive <-> exclusive gateways and activities @@ -247,6 +253,15 @@ export default function BpmnReplace( newElement.host = target.host; } + // The DataStoreReference element is 14px wider than the DataObjectReference element + // This ensures that they stay centered on the x axis when replaced + if ( + newElement.type === 'bpmn:DataStoreReference' || + newElement.type === 'bpmn:DataObjectReference' + ) { + newElement.x = element.x + (element.width - newElement.width) / 2; + } + newElement.di = {}; // fill and stroke will be set to DI @@ -273,6 +288,7 @@ BpmnReplace.$inject = [ 'moddleCopy', 'modeling', 'replace', + 'rules', 'selection' ]; diff --git a/lib/features/replace/ReplaceOptions.js b/lib/features/replace/ReplaceOptions.js index b132368e46..d49e9b6900 100644 --- a/lib/features/replace/ReplaceOptions.js +++ b/lib/features/replace/ReplaceOptions.js @@ -537,6 +537,28 @@ export var TASK = [ } ]; +export var DATA_OBJECT_REFERENCE = [ + { + label: 'Data Store Reference', + actionName: 'replace-with-data-store-reference', + className: 'bpmn-icon-data-store', + target: { + type: 'bpmn:DataStoreReference' + } + } +]; + +export var DATA_STORE_REFERENCE = [ + { + label: 'Data Object Reference', + actionName: 'replace-with-data-object-reference', + className: 'bpmn-icon-data-object', + target: { + type: 'bpmn:DataObjectReference' + } + } +]; + export var BOUNDARY_EVENT = [ { label: 'Message Boundary Event', diff --git a/lib/util/DiUtil.js b/lib/util/DiUtil.js index 91c4e5a12a..119cb54dfa 100644 --- a/lib/util/DiUtil.js +++ b/lib/util/DiUtil.js @@ -15,7 +15,7 @@ export function isExpanded(element) { } if (is(element, 'bpmn:SubProcess')) { - return !!getBusinessObject(element).di.isExpanded; + return getBusinessObject(element).di && !!getBusinessObject(element).di.isExpanded; } if (is(element, 'bpmn:Participant')) { diff --git a/test/fixtures/bpmn/features/replace/data-object.bpmn b/test/fixtures/bpmn/features/replace/data-elements.bpmn similarity index 72% rename from test/fixtures/bpmn/features/replace/data-object.bpmn rename to test/fixtures/bpmn/features/replace/data-elements.bpmn index 1476dd7b48..d864deac4c 100644 --- a/test/fixtures/bpmn/features/replace/data-object.bpmn +++ b/test/fixtures/bpmn/features/replace/data-elements.bpmn @@ -4,20 +4,19 @@ + + - - - - + - - - - + + + + diff --git a/test/spec/features/context-pad/ContextPadProviderSpec.js b/test/spec/features/context-pad/ContextPadProviderSpec.js index bd6159fbbf..adfb580425 100644 --- a/test/spec/features/context-pad/ContextPadProviderSpec.js +++ b/test/spec/features/context-pad/ContextPadProviderSpec.js @@ -265,7 +265,7 @@ describe('features - context-pad', function() { expectContextPadEntries('DataStoreReference', [ 'connect', 'append.text-annotation', - '!replace', + 'replace', '!append.end-event' ]); })); @@ -489,11 +489,11 @@ describe('features - context-pad', function() { // given var rootShape = canvas.getRootElement(), - dataStore = elementFactory.createShape({ type: 'bpmn:DataStoreReference' }), + group = elementFactory.createShape({ type: 'bpmn:Group' }), replaceMenu; // when - create.start(canvasEvent({ x: 0, y: 0 }), dataStore); + create.start(canvasEvent({ x: 0, y: 0 }), group); dragging.move(canvasEvent({ x: 50, y: 50 })); dragging.hover({ element: rootShape }); diff --git a/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js b/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js index 26cad9c052..983bfeaae5 100644 --- a/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js +++ b/test/spec/features/popup-menu/ReplaceMenuProviderSpec.js @@ -29,7 +29,7 @@ describe('features/popup-menu - replace menu provider', function() { var diagramXMLMarkers = require('../../../fixtures/bpmn/draw/activity-markers-simple.bpmn'), diagramXMLReplace = require('../../../fixtures/bpmn/features/replace/01_replace.bpmn'), - diagramXMLDataObject = require('../../../fixtures/bpmn/features/replace/data-object.bpmn'); + diagramXMLDataElements = require('../../../fixtures/bpmn/features/replace/data-elements.bpmn'); var testModules = [ coreModule, @@ -50,9 +50,10 @@ describe('features/popup-menu - replace menu provider', function() { }); }; + describe('data object - collection marker', function() { - beforeEach(bootstrapModeler(diagramXMLDataObject, { modules: testModules })); + beforeEach(bootstrapModeler(diagramXMLDataElements, { modules: testModules })); it('should toggle on', inject(function(elementRegistry) { @@ -1202,6 +1203,50 @@ describe('features/popup-menu - replace menu provider', function() { }); + describe('data object', function() { + + beforeEach(bootstrapModeler(diagramXMLDataElements, { modules: testModules })); + + + it('should only contain data store reference', inject(function(elementRegistry) { + + // given + var dataObjectReference = elementRegistry.get('DataObjectReference_1'); + + // when + openPopup(dataObjectReference); + + // then + expect(queryEntries()).to.have.length(2); + expect(queryEntry('toggle-is-collection')).to.exist; + expect(queryEntry('replace-with-data-store-reference')).to.exist; + expect(queryEntry('replace-with-data-object-reference')).to.be.null; + })); + }); + + + describe('data store', function() { + + beforeEach(bootstrapModeler(diagramXMLDataElements, { modules: testModules })); + + + it('should only contain data object reference', inject(function(elementRegistry) { + + // given + var dataStoreReference = elementRegistry.get('DataStoreReference_1'); + + // when + openPopup(dataStoreReference); + + // then + expect(queryEntries()).to.have.length(1); + expect(queryEntry('toggle-is-collection')).to.be.null; + expect(queryEntry('replace-with-data-store-reference')).to.be.null; + expect(queryEntry('replace-with-data-object-reference')).to.exist; + })); + + }); + }); diff --git a/test/spec/features/replace/BpmnReplaceSpec.js b/test/spec/features/replace/BpmnReplaceSpec.js index f00ee2f3fc..b3bd02b46f 100644 --- a/test/spec/features/replace/BpmnReplaceSpec.js +++ b/test/spec/features/replace/BpmnReplaceSpec.js @@ -1648,6 +1648,136 @@ describe('features/replace - bpmn replace', function() { }); + + describe('center', function() { + + var diagramXML = require('../../../fixtures/bpmn/features/replace/data-elements.bpmn'); + + var testModules = [ + modelingModule, + coreModule + ]; + + beforeEach(bootstrapModeler(diagramXML, { + modules: testModules + })); + + + describe('data store reference to data object reference', function() { + + it('should center on replace', inject(function(bpmnReplace, elementRegistry) { + + // given + var dataStoreReference = elementRegistry.get('DataStoreReference_1'); + var positionX = dataStoreReference.x; + + // when + bpmnReplace.replaceElement(dataStoreReference, { type: 'bpmn:DataObjectReference' }); + + var dataObjectReference = elementRegistry.get('DataStoreReference_1'); + var newPositionX = positionX + (dataStoreReference.width - dataObjectReference.width) / 2; + + // then + expect(dataObjectReference.x).to.eql(newPositionX); + })); + + + it('should undo', inject(function(bpmnReplace, commandStack, elementRegistry) { + + // given + var dataStoreReference = elementRegistry.get('DataStoreReference_1'); + var positionX = dataStoreReference.x; + + bpmnReplace.replaceElement(dataStoreReference, { type: 'bpmn:DataObjectReference' }); + + // when + commandStack.undo(); + + // then + expect(elementRegistry.get('DataStoreReference_1').x).to.eql(positionX); + })); + + + it('should redo', inject(function(bpmnReplace, commandStack, elementRegistry) { + + // given + var dataStoreReference = elementRegistry.get('DataStoreReference_1'); + var positionX = dataStoreReference.x; + + bpmnReplace.replaceElement(dataStoreReference, { type: 'bpmn:DataObjectReference' }); + commandStack.undo(); + + // when + commandStack.redo(); + + var dataObjectReference = elementRegistry.get('DataStoreReference_1'); + var newPositionX = positionX + (dataStoreReference.width - dataObjectReference.width) / 2; + + // then + expect(dataObjectReference.x).to.eql(newPositionX); + })); + + }); + + + describe('data object reference to data store reference', function() { + + it('should center on replace', inject(function(bpmnReplace, elementRegistry) { + + // given + var dataObjectReference = elementRegistry.get('DataObjectReference_1'); + var positionX = dataObjectReference.x; + + // when + bpmnReplace.replaceElement(dataObjectReference, { type: 'bpmn:DataStoreReference' }); + + var dataStoreReference = elementRegistry.get('DataObjectReference_1'); + var newPositionX = positionX + (dataObjectReference.width - dataStoreReference.width) / 2; + + // then + expect(dataStoreReference.x).to.eql(newPositionX); + })); + + + it('should undo', inject(function(bpmnReplace, commandStack, elementRegistry) { + + // given + var dataObjectReference = elementRegistry.get('DataObjectReference_1'); + var positionX = dataObjectReference.x; + + bpmnReplace.replaceElement(dataObjectReference, { type: 'bpmn:DataStoreReference' }); + + // when + commandStack.undo(); + + // then + expect(elementRegistry.get('DataObjectReference_1').x).to.eql(positionX); + })); + + + it('should redo', inject(function(bpmnReplace, commandStack, elementRegistry) { + + // given + var dataObjectReference = elementRegistry.get('DataObjectReference_1'); + var positionX = dataObjectReference.x; + + bpmnReplace.replaceElement(dataObjectReference, { type: 'bpmn:DataStoreReference' }); + commandStack.undo(); + + // when + commandStack.redo(); + + var dataStoreReference = elementRegistry.get('DataObjectReference_1'); + var newPositionX = positionX + (dataObjectReference.width - dataStoreReference.width) / 2; + + // then + expect(dataStoreReference.x).to.eql(newPositionX); + })); + + }); + + }); + });