-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(create-append-anything): create with templates
Closes #243
- Loading branch information
Showing
4 changed files
with
347 additions
and
2 deletions.
There are no files selected for viewing
115 changes: 115 additions & 0 deletions
115
lib/camunda-cloud/features/create-append-anything/ElementTemplatesCreateProvider.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { assign } from 'min-dash'; | ||
|
||
|
||
/** | ||
* A popup menu provider that allows to create elements with | ||
* element templates. | ||
*/ | ||
export default function ElementTemplatesCreateProvider( | ||
popupMenu, translate, elementTemplates, | ||
mouse, create) { | ||
|
||
this._popupMenu = popupMenu; | ||
this._translate = translate; | ||
this._elementTemplates = elementTemplates; | ||
this._mouse = mouse; | ||
this._create = create; | ||
|
||
this.register(); | ||
} | ||
|
||
ElementTemplatesCreateProvider.$inject = [ | ||
'popupMenu', | ||
'translate', | ||
'elementTemplates', | ||
'mouse', | ||
'create' | ||
]; | ||
|
||
/** | ||
* Register create menu provider in the popup menu | ||
*/ | ||
ElementTemplatesCreateProvider.prototype.register = function() { | ||
this._popupMenu.registerProvider('bpmn-create', this); | ||
}; | ||
|
||
/** | ||
* Adds the element templates to the create menu. | ||
* @param {djs.model.Base} element | ||
* | ||
* @returns {Object} | ||
*/ | ||
ElementTemplatesCreateProvider.prototype.getPopupMenuEntries = function(element) { | ||
return (entries) => { | ||
|
||
// add template entries | ||
assign(entries, this.getTemplateEntries(element)); | ||
|
||
return entries; | ||
}; | ||
}; | ||
|
||
/** | ||
* Get all element templates. | ||
* | ||
* @param {djs.model.Base} element | ||
* | ||
* @return {Array<Object>} a list of element templates as menu entries | ||
*/ | ||
ElementTemplatesCreateProvider.prototype.getTemplateEntries = function() { | ||
|
||
const templates = this._elementTemplates.getLatest(); | ||
const templateEntries = {}; | ||
|
||
templates.map(template => { | ||
|
||
const { | ||
icon = {}, | ||
category, | ||
} = template; | ||
|
||
const entryId = `create.template-${template.id}`; | ||
|
||
const defaultGroup = { | ||
id: 'templates', | ||
name: this._translate('Templates') | ||
}; | ||
|
||
templateEntries[entryId] = { | ||
label: template.name, | ||
description: template.description, | ||
documentationRef: template.documentationRef, | ||
imageUrl: icon.contents, | ||
group: category || defaultGroup, | ||
action: { | ||
click: this._getEntryAction(template), | ||
dragstart: this._getEntryAction(template) | ||
} | ||
}; | ||
}); | ||
|
||
return templateEntries; | ||
}; | ||
|
||
|
||
ElementTemplatesCreateProvider.prototype._getEntryAction = function(template) { | ||
const create = this._create; | ||
const popupMenu = this._popupMenu; | ||
const elementTemplates = this._elementTemplates; | ||
const mouse = this._mouse; | ||
|
||
return (event) => { | ||
|
||
popupMenu.close(); | ||
|
||
// create the new element | ||
let newElement = elementTemplates.createElement(template); | ||
|
||
// use last mouse event if triggered via keyboard | ||
if (event instanceof KeyboardEvent) { | ||
event = mouse.getLastMoveEvent(); | ||
} | ||
|
||
return create.start(event, newElement); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,11 @@ | ||
import ElementTemplatesAppendProvider from './ElementTemplatesAppendProvider'; | ||
import ElementTemplatesCreateProvider from './ElementTemplatesCreateProvider'; | ||
|
||
export default { | ||
__init__: [ 'elementTemplatesAppendProvider' ], | ||
elementTemplatesAppendProvider: [ 'type', ElementTemplatesAppendProvider ] | ||
__init__: [ | ||
'elementTemplatesAppendProvider', | ||
'elementTemplatesCreateProvider' | ||
], | ||
elementTemplatesAppendProvider: [ 'type', ElementTemplatesAppendProvider ], | ||
elementTemplatesCreateProvider: [ 'type', ElementTemplatesCreateProvider ] | ||
}; |
7 changes: 7 additions & 0 deletions
7
test/camunda-cloud/features/create-append-anything/ElementTemplatesCreateProvider.bpmn
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0su05ks" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.8.0-rc.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.1.0"> | ||
<bpmn:process id="Process_1uc9zgy" isExecutable="true" /> | ||
<bpmndi:BPMNDiagram id="BPMNDiagram_1"> | ||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1uc9zgy" /> | ||
</bpmndi:BPMNDiagram> | ||
</bpmn:definitions> |
218 changes: 218 additions & 0 deletions
218
test/camunda-cloud/features/create-append-anything/ElementTemplatesCreateProviderSpec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
import { | ||
inject, | ||
getBpmnJS, | ||
bootstrapCamundaCloudModeler, | ||
} from 'test/TestHelper'; | ||
|
||
import { | ||
query as domQuery | ||
} from 'min-dom'; | ||
|
||
import diagramXML from './ElementTemplatesCreateProvider.bpmn'; | ||
import templates from './ElementTemplatesAppendProvider.json'; | ||
|
||
import { | ||
getBusinessObject, | ||
is | ||
} from 'bpmn-js/lib/util/ModelUtil'; | ||
|
||
|
||
describe('<ElementTemplatesCreateProviderSpec>', function() { | ||
|
||
beforeEach(bootstrapCamundaCloudModeler(diagramXML)); | ||
|
||
beforeEach(inject(function(elementTemplates) { | ||
elementTemplates.set(templates); | ||
})); | ||
|
||
|
||
describe('display', function() { | ||
|
||
it('should display template options', inject(function(canvas) { | ||
|
||
// given | ||
const rootElement = canvas.getRootElement(); | ||
|
||
// when | ||
openPopup(rootElement); | ||
|
||
// then | ||
const entries = Object.keys(getEntries()); | ||
const templateEntries = entries.filter((entry) => entry.startsWith('create.template-')); | ||
|
||
expect(templateEntries.length).to.eql(templates.length); | ||
})); | ||
|
||
}); | ||
|
||
|
||
describe('create', function() { | ||
|
||
it('should create template', inject(function(elementRegistry, selection) { | ||
|
||
// given | ||
const template = templates[0]; | ||
|
||
// when | ||
triggerEntry(`create.template-${template.id}`); | ||
|
||
// then | ||
expectElementWithTemplate(elementRegistry, 'bpmn:Task', template, true); | ||
expectSelected(selection, 'bpmn:Task'); | ||
})); | ||
|
||
|
||
it('should undo', inject(function(elementRegistry, commandStack, selection) { | ||
|
||
// given | ||
const template = templates[0]; | ||
|
||
// when | ||
triggerEntry(`create.template-${template.id}`); | ||
|
||
// then | ||
expectElementWithTemplate(elementRegistry, 'bpmn:Task', template); | ||
expectSelected(selection, 'bpmn:Task'); | ||
|
||
// when | ||
commandStack.undo(); | ||
|
||
// then | ||
expectElementWithTemplate(elementRegistry, 'bpmn:Task', template, false); | ||
expectSelected(selection, 'bpmn:Task', false); | ||
})); | ||
|
||
|
||
it('should redo', inject(function(elementRegistry, commandStack, selection) { | ||
|
||
// given | ||
const template = templates[0]; | ||
|
||
// when | ||
triggerEntry(`create.template-${template.id}`); | ||
commandStack.undo(); | ||
|
||
// then | ||
expectElementWithTemplate(elementRegistry, 'bpmn:Task', template, false); | ||
expectSelected(selection, 'bpmn:Task', false); | ||
|
||
// when | ||
commandStack.redo(); | ||
|
||
// then | ||
expectElementWithTemplate(elementRegistry, 'bpmn:Task', template); | ||
})); | ||
|
||
}); | ||
|
||
}); | ||
|
||
|
||
// helpers //////////// | ||
|
||
function openPopup(element, offset) { | ||
offset = offset || 100; | ||
|
||
getBpmnJS().invoke(function(popupMenu) { | ||
popupMenu.open(element, 'bpmn-create', { | ||
x: element.x, y: element.y | ||
}); | ||
|
||
}); | ||
} | ||
|
||
function queryEntry(id) { | ||
var container = getMenuContainer(); | ||
|
||
return domQuery('.djs-popup [data-id="' + id + '"]', container); | ||
} | ||
|
||
function getMenuContainer() { | ||
const popup = getBpmnJS().get('popupMenu'); | ||
return popup._current.container; | ||
} | ||
|
||
function triggerAction(id, position = { x: 0, y: 0 }) { | ||
const entry = queryEntry(id); | ||
|
||
if (!entry) { | ||
throw new Error('entry "' + id + '" not found in append menu'); | ||
} | ||
|
||
const popupMenu = getBpmnJS().get('popupMenu'); | ||
const eventBus = getBpmnJS().get('eventBus'); | ||
|
||
return popupMenu.trigger( | ||
eventBus.createEvent({ | ||
target: entry, | ||
clientX: position.x, | ||
clientY: position.y | ||
},) | ||
); | ||
} | ||
|
||
function getEntries() { | ||
const popupMenu = getBpmnJS().get('popupMenu'); | ||
return popupMenu._current.entries; | ||
} | ||
|
||
function isTemaplateApplied(element, template) { | ||
const businessObject = getBusinessObject(element); | ||
|
||
return businessObject.get('modelerTemplate') === template.id; | ||
} | ||
|
||
function expectElementWithTemplate(elementRegistry, type, template, result = true) { | ||
const element = elementRegistry.find((element) => is(element, type)); | ||
|
||
if (!result) { | ||
expect(element).to.not.exist; | ||
} else { | ||
expect(element).to.exist; | ||
expect(isTemaplateApplied(element, template)).to.be.true; | ||
} | ||
} | ||
|
||
function expectSelected(selection, type, result = true) { | ||
const selected = selection.get(); | ||
|
||
if (!result) { | ||
expect(selected).to.have.length(0); | ||
} else { | ||
expect(selected).to.have.length(1); | ||
expect(is(selected[0], type)).to.be.true; | ||
} | ||
} | ||
|
||
function triggerEntry(id) { | ||
|
||
return getBpmnJS().invoke(function(canvas, dragging) { | ||
|
||
var rootElement = canvas.getRootElement(), | ||
rootGfx = canvas.getGraphics(rootElement); | ||
|
||
openPopup(rootElement); | ||
triggerAction(id); | ||
|
||
dragging.hover({ element: rootElement, gfx: rootGfx }); | ||
dragging.move(createCanvasEvent({ x: 200, y: 300 })); | ||
|
||
// when | ||
dragging.end(); | ||
|
||
}); | ||
} | ||
|
||
function createCanvasEvent(position) { | ||
|
||
return getBpmnJS().invoke(function(canvas, eventBus) { | ||
|
||
var target = canvas._svg; | ||
|
||
return eventBus.createEvent({ | ||
target: target, | ||
clientX: position.x, | ||
clientY: position.y | ||
}); | ||
}); | ||
} |