From a94795f9577916864b6af08b83199df1d4ad185d Mon Sep 17 00:00:00 2001 From: Martin Stamm Date: Wed, 1 Sep 2021 08:48:11 +0200 Subject: [PATCH] feat(import): support importing multiple diagrams at once --- .../auto-resize/BpmnAutoResizeProvider.js | 9 ++-- lib/import/BpmnImporter.js | 17 ++++--- lib/import/BpmnTreeWalker.js | 6 +-- lib/import/Importer.js | 23 +++++++--- lib/util/DiUtil.js | 4 ++ test/spec/draw/BpmnRendererSpec.js | 2 +- .../features/copy-paste/BpmnCopyPasteSpec.js | 10 ++-- test/spec/import/ImporterSpec.js | 46 +++++++++++++++++++ 8 files changed, 95 insertions(+), 22 deletions(-) diff --git a/lib/features/auto-resize/BpmnAutoResizeProvider.js b/lib/features/auto-resize/BpmnAutoResizeProvider.js index d44e9aa6..9dff6083 100644 --- a/lib/features/auto-resize/BpmnAutoResizeProvider.js +++ b/lib/features/auto-resize/BpmnAutoResizeProvider.js @@ -1,4 +1,4 @@ -import { is } from '../../util/ModelUtil'; +import { getDi, is } from '../../util/ModelUtil'; import inherits from 'inherits'; @@ -32,8 +32,11 @@ BpmnAutoResizeProvider.$inject = [ * @return {boolean} */ BpmnAutoResizeProvider.prototype.canResize = function(elements, target) { - - if (!is(target, 'bpmn:Participant') && !is(target, 'bpmn:Lane') && !(is(target, 'bpmn:SubProcess'))) { + if ( + !is(target, 'bpmn:Participant') && + !is(target, 'bpmn:Lane') && + (!is(target, 'bpmn:SubProcess') || is(getDi(target), 'bpmndi:BPMNPlane')) + ) { return false; } diff --git a/lib/import/BpmnImporter.js b/lib/import/BpmnImporter.js index db0d86ce..84259914 100644 --- a/lib/import/BpmnImporter.js +++ b/lib/import/BpmnImporter.js @@ -93,10 +93,12 @@ BpmnImporter.$inject = [ * Add bpmn element (semantic) to the canvas onto the * specified parent shape. */ -BpmnImporter.prototype.add = function(semantic, di, parentElement) { +BpmnImporter.prototype.add = function(context, parentElement) { var element, translate = this._translate, - hidden; + hidden, + semantic = context.element, + di = context.di; var parentIndex; @@ -108,7 +110,11 @@ BpmnImporter.prototype.add = function(semantic, di, parentElement) { // add a virtual element (not being drawn) element = this._elementFactory.createRoot(elementData(semantic, di)); - this._canvas.setRootElement(element); + if (this._elementRegistry.get(element.id)) { + element.id = element.id + '_layer'; + } + + this._canvas.setRootElementForPlane(element, semantic.id); } // SHAPE @@ -116,7 +122,6 @@ BpmnImporter.prototype.add = function(semantic, di, parentElement) { var collapsed = !isExpanded(semantic, di), isFrame = isFrameElement(semantic); - hidden = parentElement && (parentElement.hidden || parentElement.collapsed); var bounds = di.bounds; @@ -144,7 +149,7 @@ BpmnImporter.prototype.add = function(semantic, di, parentElement) { // check whether data store is inside our outside of its semantic parent if (!isPointInsideBBox(parentElement, getMid(bounds))) { - parentElement = this._canvas.getRootElement(); + parentElement = this._canvas.findPlane(parentElement).rootElement; } } @@ -172,7 +177,7 @@ BpmnImporter.prototype.add = function(semantic, di, parentElement) { // are rendered correctly across different "hacks" people // love to model such as cross participant / sub process // associations - parentElement = null; + parentElement = this._canvas.findPlane(parentElement).rootElement; } // insert sequence flows behind other flow nodes (cf. #727) diff --git a/lib/import/BpmnTreeWalker.js b/lib/import/BpmnTreeWalker.js index 214d5191..a1e62541 100644 --- a/lib/import/BpmnTreeWalker.js +++ b/lib/import/BpmnTreeWalker.js @@ -76,11 +76,11 @@ export default function BpmnTreeWalker(handler, translate) { } // call handler - return handler.element(element, diMap[element.id], ctx); + return handler.element({ element: element, di: diMap[element.id] }, ctx); } function visitRoot(element, diagram) { - return handler.root(element, diMap[element.id], diagram); + return handler.root({ element: element, di: diMap[element.id] }, diagram); } function visitIfDi(element, ctx) { @@ -216,7 +216,7 @@ export default function BpmnTreeWalker(handler, translate) { var ctx = visitRoot(rootElement, plane); - if (is(rootElement, 'bpmn:Process')) { + if (is(rootElement, 'bpmn:Process') || is(rootElement, 'bpmn:SubProcess')) { handleProcess(rootElement, ctx); } else if (is(rootElement, 'bpmn:Collaboration')) { handleCollaboration(rootElement, ctx); diff --git a/lib/import/Importer.js b/lib/import/Importer.js index 7434f220..41eaeb54 100644 --- a/lib/import/Importer.js +++ b/lib/import/Importer.js @@ -33,7 +33,8 @@ export function importBpmnDiagram(diagram, definitions, bpmnDiagram) { var importer, eventBus, - translate; + translate, + canvas; var error, warnings = []; @@ -49,12 +50,12 @@ export function importBpmnDiagram(diagram, definitions, bpmnDiagram) { var visitor = { - root: function(element, di) { - return importer.add(element, di); + root: function(element) { + return importer.add(element); }, - element: function(element, di, parentShape) { - return importer.add(element, di, parentShape); + element: function(element, parentShape) { + return importer.add(element, parentShape); }, error: function(message, context) { @@ -66,7 +67,16 @@ export function importBpmnDiagram(diagram, definitions, bpmnDiagram) { // traverse BPMN 2.0 document model, // starting at definitions - walker.handleDefinitions(definitions, bpmnDiagram); + if (!bpmnDiagram && definitions.diagrams) { + for (var i = 0; i < definitions.diagrams.length; i++) { + walker.handleDefinitions(definitions, definitions.diagrams[i]); + } + } else { + walker.handleDefinitions(definitions, bpmnDiagram); + } + + var mainDiagram = bpmnDiagram || definitions.diagrams[0]; + canvas.setActivePlane(mainDiagram.plane.bpmnElement.id); } return new Promise(function(resolve, reject) { @@ -74,6 +84,7 @@ export function importBpmnDiagram(diagram, definitions, bpmnDiagram) { importer = diagram.get('bpmnImporter'); eventBus = diagram.get('eventBus'); translate = diagram.get('translate'); + canvas = diagram.get('canvas'); eventBus.fire('import.render.start', { definitions: definitions }); diff --git a/lib/util/DiUtil.js b/lib/util/DiUtil.js index 0bde14d7..56bc591c 100644 --- a/lib/util/DiUtil.js +++ b/lib/util/DiUtil.js @@ -11,6 +11,10 @@ import { export function isExpanded(element, di) { + if (di && is(di, 'bpmndi:BPMNPlane')) { + return true; + } + if (is(element, 'bpmn:CallActivity')) { return false; } diff --git a/test/spec/draw/BpmnRendererSpec.js b/test/spec/draw/BpmnRendererSpec.js index 36872c38..3bef2e6f 100644 --- a/test/spec/draw/BpmnRendererSpec.js +++ b/test/spec/draw/BpmnRendererSpec.js @@ -569,7 +569,7 @@ describe('draw - bpmn renderer', function() { var rootElement = canvas.getRootElement(); elementRegistry.forEach(function(element) { - if (element === rootElement) { + if (element === rootElement || element.isImplicit) { return; } diff --git a/test/spec/features/copy-paste/BpmnCopyPasteSpec.js b/test/spec/features/copy-paste/BpmnCopyPasteSpec.js index b09925b7..dca0638a 100644 --- a/test/spec/features/copy-paste/BpmnCopyPasteSpec.js +++ b/test/spec/features/copy-paste/BpmnCopyPasteSpec.js @@ -895,7 +895,7 @@ function integrationTest(elementIds) { getBpmnJS().invoke(function(canvas, commandStack, copyPaste, elementRegistry, modeling) { // given - var allElements = elementRegistry.getAll(); + var allElements = elementRegistry.filter(isImplicit); var initialContext = { length: allElements.length, @@ -934,7 +934,7 @@ function integrationTest(elementIds) { commandStack.undo(); commandStack.undo(); - elements = elementRegistry.getAll(); + elements = elementRegistry.filter(isImplicit); currentContext = { length: elements.length, @@ -951,7 +951,7 @@ function integrationTest(elementIds) { commandStack.redo(); commandStack.redo(); - elements = elementRegistry.getAll(); + elements = elementRegistry.filter(isImplicit); currentContext = { length: elements.length, @@ -972,6 +972,10 @@ function isRoot(element) { return !!element.parent; } +function isImplicit(element) { + return !element.isImplicit; +} + function getPropertyForElements(elements, property) { return map(elements, function(element) { return element[ property ]; diff --git a/test/spec/import/ImporterSpec.js b/test/spec/import/ImporterSpec.js index aef20379..f1d20493 100644 --- a/test/spec/import/ImporterSpec.js +++ b/test/spec/import/ImporterSpec.js @@ -665,6 +665,52 @@ describe('import - Importer', function() { }); + + describe('Multiple Planes', function() { + + it('should import multiple diagrams', function() { + + // given + var xml = require('../../fixtures/bpmn/multiple-diagrams.bpmn'); + + // when + return runImport(diagram, xml).then(function(result) { + + var warnings = result.warnings; + + // then + expect(warnings).to.have.length(0); + + expect(diagram.get('elementRegistry').get('Task_A')).to.exist; + expect(diagram.get('elementRegistry').get('Task_B')).to.exist; + }); + }); + + + it('should render Tasks on different layers', function() { + + // given + var xml = require('../../fixtures/bpmn/multiple-diagrams.bpmn'); + + // when + return runImport(diagram, xml).then(function() { + + var elementRegistry = diagram.get('elementRegistry'), + canvas = diagram.get('canvas'), + taskA = elementRegistry.get('Task_A'), + taskB = elementRegistry.get('Task_B'); + + var activePlane = canvas.getActivePlane(), + planeA = canvas.findPlane(taskA), + planeB = canvas.findPlane(taskB); + + // then + expect(activePlane).to.eql(planeA); + expect(planeA).to.not.eql(planeB); + }); + }); + + }); });