Adding a Launch Button for Call Activity
Json files are now a selection list, not a text field -- see app.json for usage. New SpiffExtensionSelect can be used to add select boxes anywhere you want.
This commit is contained in:
parent
fbcda3f672
commit
6467e967b8
38
app/app.js
38
app/app.js
|
@ -126,6 +126,44 @@ saveMarkdownBtn.addEventListener('click', (_event) => {
|
|||
document.getElementById('markdown_overlay').style.display = 'none';
|
||||
});
|
||||
|
||||
/**
|
||||
* Also can be good to launch an editor for a call activity.
|
||||
* Not implemented here but imagine opening up a new browser tab
|
||||
* and showing a different process.
|
||||
*/
|
||||
bpmnModeler.on('callactivity.editor.launch', (newEvent) => {
|
||||
console.log(
|
||||
'Open new window with editor for call activity: ',
|
||||
newEvent.processId
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Also handy to get a list of available files that can be used in a given
|
||||
* context, say json files for a form, or a DMN file for a BusinessRuleTask
|
||||
*/
|
||||
bpmnModeler.on('spiff.options.requested', (event) => {
|
||||
console.log('Requested!', event);
|
||||
if (event.optionType === 'json') {
|
||||
console.log("Firing the json")
|
||||
event.eventBus.fire('spiff.options.returned.json', {
|
||||
options: [
|
||||
{ label: 'pizza_form.json', value: 'pizza_form.json' },
|
||||
{ label: 'credit_card_form.json', value: 'credit_card_form.json' },
|
||||
],
|
||||
});
|
||||
} else if (event.optionType === 'dmn') {
|
||||
console.log("Firing the dmn")
|
||||
event.eventBus.fire('spiff.options.returned.dmn', {
|
||||
options: [
|
||||
{ label: 'Pizza Special Prices', value: 'pizza_prices' },
|
||||
{ label: 'Topping Prices', value: 'topping_prices' },
|
||||
],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// This handles the download and upload buttons - it isn't specific to
|
||||
// the BPMN modeler or these extensions, just a quick way to allow you to
|
||||
// create and save files, so keeping it outside the example.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import { TextFieldEntry } from '@bpmn-io/properties-panel';
|
||||
import { HeaderButton, TextFieldEntry } from '@bpmn-io/properties-panel';
|
||||
import { useService } from 'bpmn-js-properties-panel';
|
||||
|
||||
const LOW_PRIORITY = 500;
|
||||
|
@ -45,21 +45,33 @@ function createCalledElementGroup(element, translate, moddle, commandStack) {
|
|||
commandStack,
|
||||
translate,
|
||||
},
|
||||
{
|
||||
id: `called_element_launch_button`,
|
||||
element,
|
||||
component: LaunchEditorButton,
|
||||
moddle,
|
||||
commandStack,
|
||||
translate,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function getCalledElementValue(element) {
|
||||
const { calledElement } = element.businessObject;
|
||||
if (calledElement) {
|
||||
return calledElement;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function CalledElementTextField(props) {
|
||||
const { element } = props;
|
||||
const { translate } = props;
|
||||
|
||||
const debounce = useService('debounceInput');
|
||||
const getValue = () => {
|
||||
const { calledElement } = element.businessObject;
|
||||
if (calledElement) {
|
||||
return calledElement;
|
||||
}
|
||||
return '';
|
||||
return getCalledElementValue(element);
|
||||
};
|
||||
|
||||
const setValue = (value) => {
|
||||
|
@ -75,3 +87,20 @@ function CalledElementTextField(props) {
|
|||
debounce,
|
||||
});
|
||||
}
|
||||
|
||||
function LaunchEditorButton(props) {
|
||||
const { element } = props;
|
||||
const eventBus = useService('eventBus');
|
||||
return HeaderButton({
|
||||
id: 'spiffworkflow-open-call-activity-button',
|
||||
class: 'spiffworkflow-properties-panel-button',
|
||||
onClick: () => {
|
||||
const processId = getCalledElementValue(element);
|
||||
eventBus.fire('callactivity.editor.launch', {
|
||||
element,
|
||||
processId,
|
||||
});
|
||||
},
|
||||
children: 'Launch Editor',
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
const SPIFF_PARENT_PROP = 'spiffworkflow:properties';
|
||||
const SPIFF_PROP = 'spiffworkflow:property';
|
||||
|
||||
export function getExtensionProperties(element) {
|
||||
const bizObj = element.businessObject;
|
||||
if (!bizObj.extensionElements) {
|
||||
return null;
|
||||
}
|
||||
const extensionElements = bizObj.extensionElements.get('values');
|
||||
return extensionElements.filter(function (extensionElement) {
|
||||
if (extensionElement.$instanceOf(SPIFF_PARENT_PROP)) {
|
||||
return extensionElement;
|
||||
}
|
||||
return null;
|
||||
})[0];
|
||||
}
|
||||
|
||||
export function getExtensionProperty(element, name) {
|
||||
const parentElement = getExtensionProperties(element);
|
||||
if (parentElement) {
|
||||
return parentElement.get('properties').filter(function (propertyElement) {
|
||||
return (
|
||||
propertyElement.$instanceOf(SPIFF_PROP) && propertyElement.name === name
|
||||
);
|
||||
})[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function setExtensionProperty(element, name, value, moddle, commandStack) {
|
||||
let properties = getExtensionProperties(element);
|
||||
let property = getExtensionProperty(element, name);
|
||||
const { businessObject } = element;
|
||||
let extensions = businessObject.extensionElements;
|
||||
|
||||
if (!extensions) {
|
||||
extensions = moddle.create('bpmn:ExtensionElements');
|
||||
}
|
||||
if (!properties) {
|
||||
properties = moddle.create(SPIFF_PARENT_PROP);
|
||||
extensions.get('values').push(properties);
|
||||
}
|
||||
if (!property) {
|
||||
property = moddle.create(SPIFF_PROP);
|
||||
properties.get('properties').push(property);
|
||||
}
|
||||
property.value = value;
|
||||
property.name = name;
|
||||
|
||||
commandStack.execute('element.updateModdleProperties', {
|
||||
element,
|
||||
moddleElement: businessObject,
|
||||
properties: {
|
||||
extensionElements: extensions,
|
||||
},
|
||||
});
|
||||
}
|
|
@ -8,6 +8,7 @@ import {
|
|||
ServiceTaskParameterArray,
|
||||
ServiceTaskOperatorSelect, ServiceTaskResultTextInput,
|
||||
} from './SpiffExtensionServiceProperties';
|
||||
import {OPTION_TYPE, SpiffExtensionSelect} from './SpiffExtensionSelect';
|
||||
|
||||
const LOW_PRIORITY = 500;
|
||||
|
||||
|
@ -140,7 +141,8 @@ function createUserGroup(element, translate, moddle, commandStack) {
|
|||
element,
|
||||
moddle,
|
||||
commandStack,
|
||||
component: SpiffExtensionTextInput,
|
||||
component: SpiffExtensionSelect,
|
||||
optionType: OPTION_TYPE.json,
|
||||
label: translate('JSON Schema Filename'),
|
||||
description: translate('RJSF Json Data Structure Filename'),
|
||||
name: 'formJsonSchemaFilename',
|
||||
|
@ -149,7 +151,8 @@ function createUserGroup(element, translate, moddle, commandStack) {
|
|||
element,
|
||||
moddle,
|
||||
commandStack,
|
||||
component: SpiffExtensionTextInput,
|
||||
component: SpiffExtensionSelect,
|
||||
optionType: OPTION_TYPE.json,
|
||||
label: translate('UI Schema Filename'),
|
||||
description: translate('RJSF User Interface Filename'),
|
||||
name: 'formUiSchemaFilename',
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
import { SelectEntry } from '@bpmn-io/properties-panel';
|
||||
import { useService } from 'bpmn-js-properties-panel';
|
||||
import {
|
||||
getExtensionProperty,
|
||||
setExtensionProperty,
|
||||
} from '../extensionHelpers';
|
||||
|
||||
const spiffExtensionOptions = {};
|
||||
|
||||
export const OPTION_TYPE = {
|
||||
json: 'json',
|
||||
dmn: 'dmn',
|
||||
};
|
||||
|
||||
/**
|
||||
* Allow selecting an option from a list of available options, and setting
|
||||
* the name and value of a SpiffWorkflow Property to the one selected in the
|
||||
* dropdown list.
|
||||
* The list of options must be provided by the containing library - by responding
|
||||
* to a request passed to the eventBus.
|
||||
* When needed, the event "spiff.options.requested" will be fired. The event will include
|
||||
* a 'type' attribute that will be one of the following:
|
||||
* * jsonFiles
|
||||
* * dmnFiles
|
||||
* The response should be sent to "spiff.options.returned.___" where the final
|
||||
* section is the name requested, ie "spiff.options.returned.jsonFiles" The response
|
||||
* event should include an 'options' attribute that is list of labels and values:
|
||||
* [ { label: 'Product Prices DMN', value: 'Process_16xfaqc' } ]
|
||||
*/
|
||||
export function SpiffExtensionSelect(props) {
|
||||
const { element } = props;
|
||||
const { commandStack } = props;
|
||||
const { moddle } = props;
|
||||
const { label, description } = props;
|
||||
|
||||
const { name } = props;
|
||||
const { optionType } = props;
|
||||
|
||||
const debounce = useService('debounceInput');
|
||||
const eventBus = useService('eventBus');
|
||||
|
||||
const getValue = () => {
|
||||
const property = getExtensionProperty(element, name);
|
||||
if (property) {
|
||||
return property.value;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const setValue = (value) => {
|
||||
console.log(`Set Value called with ${ value}`);
|
||||
setExtensionProperty(element, name, value, moddle, commandStack);
|
||||
};
|
||||
|
||||
if (
|
||||
!(optionType in spiffExtensionOptions) ||
|
||||
spiffExtensionOptions[optionType].length === 0
|
||||
) {
|
||||
spiffExtensionOptions[optionType] = [];
|
||||
requestOptions(eventBus, element, commandStack, optionType);
|
||||
} else {
|
||||
console.log("Getting here.", spiffExtensionOptions)
|
||||
}
|
||||
const getOptions = () => {
|
||||
const optionList = [];
|
||||
if (optionType in spiffExtensionOptions) {
|
||||
spiffExtensionOptions[optionType].forEach((opt) => {
|
||||
optionList.push({
|
||||
label: opt.label,
|
||||
value: opt.value,
|
||||
});
|
||||
});
|
||||
}
|
||||
return optionList;
|
||||
};
|
||||
|
||||
return SelectEntry({
|
||||
id: `extension_${name}`,
|
||||
element,
|
||||
label,
|
||||
description,
|
||||
getValue,
|
||||
setValue,
|
||||
getOptions,
|
||||
debounce,
|
||||
});
|
||||
}
|
||||
|
||||
function requestOptions(eventBus, element, commandStack, optionType) {
|
||||
// Little backwards, but you want to assure you are ready to catch, before you throw
|
||||
// or you risk a race condition.
|
||||
eventBus.once('spiff.options.returned.json', (event) => {
|
||||
spiffExtensionOptions[optionType] = event.options;
|
||||
commandStack.execute('element.updateProperties', {
|
||||
element,
|
||||
properties: {},
|
||||
});
|
||||
});
|
||||
eventBus.fire('spiff.options.requested', { eventBus, optionType });
|
||||
}
|
|
@ -1,8 +1,12 @@
|
|||
import {useService } from 'bpmn-js-properties-panel';
|
||||
import { TextFieldEntry } from '@bpmn-io/properties-panel';
|
||||
import {
|
||||
addOrUpdateExtensionProperty,
|
||||
getExtensionProperties,
|
||||
getExtensionPropertiesObject,
|
||||
getExtensionProperty, setExtensionProperty
|
||||
} from '../extensionHelpers';
|
||||
|
||||
const SPIFF_PARENT_PROP = "spiffworkflow:properties"
|
||||
const SPIFF_PROP = "spiffworkflow:property"
|
||||
|
||||
/**
|
||||
* A generic properties' editor for text input.
|
||||
|
@ -25,32 +29,8 @@ export function SpiffExtensionTextInput(props) {
|
|||
const name = props.name, label = props.label, description = props.description;
|
||||
const debounce = useService('debounceInput');
|
||||
|
||||
const getPropertiesObject = () => {
|
||||
const bizObj = element.businessObject;
|
||||
if (!bizObj.extensionElements) {
|
||||
return null;
|
||||
} else {
|
||||
const extensionElements = bizObj.extensionElements.get("values");
|
||||
return extensionElements.filter(function (extensionElement) {
|
||||
if (extensionElement.$instanceOf(SPIFF_PARENT_PROP)) {
|
||||
return extensionElement;
|
||||
}
|
||||
})[0];
|
||||
}
|
||||
}
|
||||
|
||||
const getPropertyObject = () => {
|
||||
const parentElement = getPropertiesObject();
|
||||
if (parentElement) {
|
||||
return parentElement.get("properties").filter(function (propertyElement) {
|
||||
return propertyElement.$instanceOf(SPIFF_PROP) && propertyElement.name === name;
|
||||
})[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const getValue = () => {
|
||||
const property = getPropertyObject()
|
||||
const property = getExtensionProperty(element, name)
|
||||
if (property) {
|
||||
return property.value;
|
||||
}
|
||||
|
@ -58,32 +38,7 @@ export function SpiffExtensionTextInput(props) {
|
|||
}
|
||||
|
||||
const setValue = value => {
|
||||
let properties = getPropertiesObject()
|
||||
let property = getPropertyObject()
|
||||
let businessObject = element.businessObject;
|
||||
let extensions = businessObject.extensionElements;
|
||||
|
||||
if (!extensions) {
|
||||
extensions = moddle.create('bpmn:ExtensionElements');
|
||||
}
|
||||
if (!properties) {
|
||||
properties = moddle.create(SPIFF_PARENT_PROP);
|
||||
extensions.get('values').push(properties);
|
||||
}
|
||||
if (!property) {
|
||||
property = moddle.create(SPIFF_PROP);
|
||||
properties.get('properties').push(property);
|
||||
}
|
||||
property.value = value;
|
||||
property.name = name;
|
||||
|
||||
commandStack.execute('element.updateModdleProperties', {
|
||||
element,
|
||||
moddleElement: businessObject,
|
||||
properties: {
|
||||
"extensionElements": extensions
|
||||
}
|
||||
});
|
||||
setExtensionProperty(element, name, value, moddle, commandStack)
|
||||
};
|
||||
|
||||
return <TextFieldEntry
|
||||
|
|
|
@ -5,15 +5,17 @@ import {
|
|||
} from 'bpmn-js-properties-panel';
|
||||
import { query as domQuery } from 'min-dom';
|
||||
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import { inject } from 'bpmn-js/test/helper';
|
||||
import {
|
||||
bootstrapPropertiesPanel,
|
||||
changeInput,
|
||||
expectSelected,
|
||||
findGroupEntry,
|
||||
expectSelected, findButton,
|
||||
findGroupEntry, pressButton,
|
||||
} from './helpers';
|
||||
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
|
||||
import callActivity from '../../app/spiffworkflow/callActivity';
|
||||
|
||||
|
||||
describe('Call Activities should work', function () {
|
||||
const xml = require('./bpmn/call_activity.bpmn').default;
|
||||
let container;
|
||||
|
@ -57,4 +59,23 @@ describe('Call Activities should work', function () {
|
|||
changeInput(textInput, 'newProcessId');
|
||||
expect(businessObject.get('calledElement')).to.equal('newProcessId');
|
||||
});
|
||||
|
||||
it('should issue an event to the event bus if user clicks the edit button', inject(
|
||||
async function(eventBus) {
|
||||
const shapeElement = await expectSelected('the_call_activity');
|
||||
expect(shapeElement, "Can't find Call Activity").to.exist;
|
||||
const businessObject = getBusinessObject(shapeElement);
|
||||
expect(businessObject.get('calledElement')).to.equal('ProcessIdTBD1');
|
||||
|
||||
const entry = findGroupEntry('called_element', container);
|
||||
const button = findButton('spiffworkflow-open-call-activity-button', entry);
|
||||
expect(button).to.exist;
|
||||
|
||||
let launchEvent;
|
||||
eventBus.on('callactivity.editor.launch', function (event) {
|
||||
launchEvent = event;
|
||||
});
|
||||
await pressButton(button);
|
||||
expect(launchEvent.processId).to.exist;
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -1,24 +1,47 @@
|
|||
import {
|
||||
bootstrapPropertiesPanel, changeInput,
|
||||
expectSelected,
|
||||
findEntry, findGroupEntry, findInput
|
||||
} from './helpers';
|
||||
|
||||
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
|
||||
import { BpmnPropertiesPanelModule, BpmnPropertiesProviderModule } from 'bpmn-js-properties-panel';
|
||||
BpmnPropertiesPanelModule,
|
||||
BpmnPropertiesProviderModule,
|
||||
} from 'bpmn-js-properties-panel';
|
||||
import { getBpmnJS } from 'bpmn-js/test/helper';
|
||||
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import TestContainer from 'mocha-test-container-support';
|
||||
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
|
||||
import {
|
||||
bootstrapPropertiesPanel,
|
||||
changeInput,
|
||||
expectSelected,
|
||||
findEntry,
|
||||
findGroupEntry,
|
||||
findInput,
|
||||
findSelect,
|
||||
} from './helpers';
|
||||
import extensions from '../../app/spiffworkflow/extensions';
|
||||
|
||||
describe('Properties Panel for User Tasks', function() {
|
||||
describe('Properties Panel for User Tasks', function () {
|
||||
const user_form_xml = require('./bpmn/user_form.bpmn').default;
|
||||
const diagram_xml = require('./bpmn/diagram.bpmn').default;
|
||||
let container;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
container = TestContainer.get(this);
|
||||
});
|
||||
|
||||
function addOptionsToEventBus(bpmnModeler) {
|
||||
bpmnModeler.on('spiff.options.requested', (event) => {
|
||||
if (event.optionType === 'json') {
|
||||
event.eventBus.fire('spiff.options.returned.json', {
|
||||
options: [
|
||||
{ label: 'pizza_form.json', value: 'pizza_form.json' },
|
||||
{ label: 'credit_card_form.json', value: 'credit_card_form.json' },
|
||||
{ label: 'give_me_a_number_form.json', value: 'give_me_a_number_form.json' },
|
||||
{ label: 'number_form_schema.json', value: 'number_form_schema.json' },
|
||||
|
||||
],
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function preparePropertiesPanelWithXml(xml) {
|
||||
return bootstrapPropertiesPanel(xml, {
|
||||
container,
|
||||
|
@ -29,12 +52,12 @@ describe('Properties Panel for User Tasks', function() {
|
|||
BpmnPropertiesProviderModule,
|
||||
],
|
||||
moddleExtensions: {
|
||||
spiffworkflow: spiffModdleExtension
|
||||
spiffworkflow: spiffModdleExtension,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
it('should display a panel for setting the web form properties', async function() {
|
||||
it('should display a panel for setting the web form properties', async function () {
|
||||
await preparePropertiesPanelWithXml(user_form_xml)();
|
||||
|
||||
// IF - you select a user task
|
||||
|
@ -42,44 +65,49 @@ describe('Properties Panel for User Tasks', function() {
|
|||
expect(userTask).to.exist;
|
||||
|
||||
// THEN - a property panel exists with a section for editing web forms
|
||||
let group = findGroupEntry('user_task_properties', container);
|
||||
const group = findGroupEntry('user_task_properties', container);
|
||||
expect(group).to.exist;
|
||||
});
|
||||
|
||||
it('should allow you to edit a web form property.', async function() {
|
||||
it('should allow you to select a json file.', async function () {
|
||||
await preparePropertiesPanelWithXml(user_form_xml)();
|
||||
|
||||
const modeler = getBpmnJS();
|
||||
addOptionsToEventBus(modeler);
|
||||
// IF - you select a user task and change the formJsonSchemaFilename text field
|
||||
const userTask = await expectSelected('my_user_task');
|
||||
let group = findGroupEntry('user_task_properties', container);
|
||||
let entry = findEntry('extension_formJsonSchemaFilename', group);
|
||||
let input = findInput('text', entry);
|
||||
expect(input).to.exist;
|
||||
changeInput(input, 'my_filename.json');
|
||||
const group = findGroupEntry('user_task_properties', container);
|
||||
const entry = findEntry('extension_formJsonSchemaFilename', group);
|
||||
const selectList = findSelect(entry);
|
||||
expect(selectList).to.exist;
|
||||
expect(selectList.options.length).to.equal(4);
|
||||
expect(selectList.options[0].label).to.equal('pizza_form.json');
|
||||
expect(selectList.options[1].label).to.equal('credit_card_form.json');
|
||||
|
||||
changeInput(selectList, 'pizza_form.json');
|
||||
|
||||
// THEN - the input is updated.
|
||||
let businessObject = getBusinessObject(userTask);
|
||||
const businessObject = getBusinessObject(userTask);
|
||||
expect(businessObject.extensionElements).to.exist;
|
||||
let properties = businessObject.extensionElements.values[1];
|
||||
const properties = businessObject.extensionElements.values[1];
|
||||
expect(properties.properties).to.exist;
|
||||
const property = properties.properties[0];
|
||||
expect(property.value).to.equal('my_filename.json');
|
||||
expect(property.value).to.equal('pizza_form.json');
|
||||
expect(property.name).to.equal('formJsonSchemaFilename');
|
||||
});
|
||||
|
||||
it('should parse the spiffworkflow:properties tag when you open an existing file', async function() {
|
||||
it('should parse the spiffworkflow:properties tag when you open an existing file', async function () {
|
||||
await preparePropertiesPanelWithXml(diagram_xml)();
|
||||
const modeler = getBpmnJS();
|
||||
addOptionsToEventBus(modeler);
|
||||
|
||||
// IF - a script tag is selected, and you change the script in the properties panel
|
||||
await expectSelected('task_confirm');
|
||||
let group = findGroupEntry('user_task_properties', container);
|
||||
let formJsonSchemaFilenameEntry = findEntry('extension_formJsonSchemaFilename', group);
|
||||
let formJsonSchemaFilenameInput = findInput('text', formJsonSchemaFilenameEntry);
|
||||
const group = findGroupEntry('user_task_properties', container);
|
||||
const formJsonSchemaFilenameEntry = findEntry('extension_formJsonSchemaFilename', group);
|
||||
const formJsonSchemaFilenameInput = findSelect(formJsonSchemaFilenameEntry);
|
||||
expect(formJsonSchemaFilenameInput.value).to.equal('give_me_a_number_form.json');
|
||||
|
||||
let formUiSchemaFilenameEntry = findEntry('extension_formUiSchemaFilename', group);
|
||||
let formUiSchemaFilenameInput = findInput('text', formUiSchemaFilenameEntry);
|
||||
const formUiSchemaFilenameEntry = findEntry('extension_formUiSchemaFilename', group);
|
||||
const formUiSchemaFilenameInput = findSelect(formUiSchemaFilenameEntry);
|
||||
expect(formUiSchemaFilenameInput.value).to.equal('number_form_schema.json');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue