diff --git a/src/provider/zeebe/properties/FormProps.js b/src/provider/zeebe/properties/FormProps.js index dd0f77af2..958e627d9 100644 --- a/src/provider/zeebe/properties/FormProps.js +++ b/src/provider/zeebe/properties/FormProps.js @@ -3,10 +3,18 @@ import { is } from 'bpmn-js/lib/util/ModelUtil'; -import { TextAreaEntry, isTextAreaEntryEdited } from '@bpmn-io/properties-panel'; +import { + SelectEntry, + TextFieldEntry, + TextAreaEntry, + isSelectEntryEdited, + isTextFieldEntryEdited, + isTextAreaEntryEdited +} from '@bpmn-io/properties-panel'; import { - createElement + createElement, + nextId } from '../../../utils/ElementUtil'; import { @@ -14,11 +22,9 @@ import { } from '../../../utils/ExtensionElementsUtil'; import { - nextId -} from '../../../utils/ElementUtil'; - -import { - find, without + find, + isUndefined, + without } from 'min-dash'; import { @@ -35,47 +41,164 @@ export function FormProps(props) { return []; } - return [ + const entries = []; + + entries.push( + { + id: 'formType', + component: , + isEdited: isSelectEntryEdited + }, { id: 'formConfiguration', - component: , + component: , isEdited: isTextAreaEntryEdited - } - ]; + }, + { + id: 'customFormKey', + component: , + isEdited: isTextFieldEntryEdited + }, + ); + + return entries; } -function FormProperty(props) { + +function FormType(props) { + const { element } = props; + const translate = useService('translate'); const injector = useService('injector'); + const formHelper = injector.invoke(FormHelper); - const debounce = useService('debounceInput'); - const translate = useService('translate'); + const getValue = () => { + const formDefinition = formHelper.getFormDefinition(element); + const userTaskForm = formHelper.getUserTaskForm(element); - const formHelper = injector.invoke(FormHelper); + if (formDefinition) { + + if (userTaskForm) { + return 'formKey'; + } + + return 'customFormKey'; + } + + return ''; + }; - const getValue = () => formHelper.get(element); + const setValue = (value) => { - const setValue = (value) => formHelper.set(element, value); + formHelper.resetForm(element); - return TextAreaEntry({ + if (value === 'formKey') { + formHelper.setUserTaskForm(element, ''); + + } else if (value === 'customFormKey') { + formHelper.setFormDefinition(element, ''); + } + }; + + const getOptions = () => { + return [ + { value: '', label: translate('') }, + { value: 'formKey', label: translate('Camunda Forms') }, + { value: 'customFormKey', label: translate('Custom Key') }, + ]; + }; + + return SelectEntry({ element, - id: 'formConfiguration', - label: translate('Form JSON configuration'), - rows: 4, + id: 'formType', + label: translate('Type'), getValue, setValue, - debounce + getOptions }); } +function FormConfiguration(props) { + const { + element + } = props; + + const injector = useService('injector'); + const debounce = useService('debounceInput'); + const translate = useService('translate'); + const formHelper = injector.invoke(FormHelper); + + const getValue = () => { + const userTaskForm = formHelper.getUserTaskForm(element); + return userTaskForm.get('body'); + }; + + const setValue = (value) => { + formHelper.setUserTaskForm(element, value); + }; + + if (isCamundaForm(element, formHelper)) { + return TextAreaEntry({ + element, + id: 'formConfiguration', + label: translate('Form JSON configuration'), + rows: 4, + getValue, + setValue, + debounce + }); + } +} + + +function CustomFormKey(props) { + const { + element + } = props; + + const injector = useService('injector'); + const debounce = useService('debounceInput'); + const translate = useService('translate'); + const formHelper = injector.invoke(FormHelper); + + const getValue = () => { + const formDefinition = formHelper.getFormDefinition(element); + return formDefinition.get('formKey'); + }; + + const setValue = (value) => { + formHelper.setFormDefinition(element, value); + }; + + if (isCustomKey(element, formHelper)) { + return TextFieldEntry({ + element, + id: 'customFormKey', + label: translate('Form Key'), + getValue, + setValue, + debounce + }); + } + +} + const USER_TASK_FORM_PREFIX = 'userTaskForm_'; function FormHelper(bpmnFactory, commandStack) { + function getFormDefinition(element) { + const businessObject = getBusinessObject(element); + + const formDefinitions = getExtensionElementsList(businessObject, 'zeebe:FormDefinition'); + + return formDefinitions[0]; + } + function getUserTaskForm(element, parent) { const rootElement = parent || getRootElement(element); @@ -83,7 +206,7 @@ function FormHelper(bpmnFactory, commandStack) { // (1) get form definition from user task const formDefinition = getFormDefinition(element); - if (!formDefinition) { + if (isUndefined(formDefinition)) { return; } @@ -95,131 +218,147 @@ function FormHelper(bpmnFactory, commandStack) { return userTaskForm; } - function getFormDefinition(element) { - const businessObject = getBusinessObject(element); + function ensureTaskForm(element, values) { - const formDefinitions = getExtensionElementsList(businessObject, 'zeebe:FormDefinition'); + let commands = []; - return formDefinitions[0]; - } + const rootElement = getRootElement(element); - function setUserTaskForm(element, body) { + // (1) ensure root element extension elements + let rootExtensionElements = rootElement.get('extensionElements'); - const businessObject = getBusinessObject(element), - rootElement = getRootElement(element); + if (!rootExtensionElements) { + rootExtensionElements = createElement( + 'bpmn:ExtensionElements', + { values: [] }, + rootElement, + bpmnFactory + ); - let commands = [], - userTaskForm, - formId; + commands.push( + UpdateModdlePropertiesCmd(element, rootElement, { + extensionElements: rootExtensionElements, + }) + ); + } - // (1) ensure extension elements - let extensionElements = businessObject.get('extensionElements'); + // (2) ensure user task form + let userTaskForm = getUserTaskForm(element); - if (!extensionElements) { - extensionElements = createElement( - 'bpmn:ExtensionElements', - { values: [] }, - businessObject, + // (2.1) create user task form if doesn't exist + if (!userTaskForm) { + userTaskForm = createUserTaskForm( + values, + rootExtensionElements, bpmnFactory ); commands.push( - UpdateModdlePropertiesCmd(element, businessObject, { - extensionElements: extensionElements, + UpdateModdlePropertiesCmd(element, rootExtensionElements,{ + values: [ ...rootExtensionElements.get('values'), userTaskForm ] }) ); } - // (2) ensure root element extension elements - let rootExtensionElements = rootElement.get('extensionElements'); + commands.push(UpdateModdlePropertiesCmd(element, userTaskForm, values)); - if (!rootExtensionElements) { - rootExtensionElements = createElement( + return commands; + } + + function ensureFormDefinition(element, customFormKey) { + const businessObject = getBusinessObject(element); + + let commands = []; + + // (1) ensure extension elements + let extensionElements = businessObject.get('extensionElements'); + + if (isUndefined(extensionElements)) { + extensionElements = createElement( 'bpmn:ExtensionElements', { values: [] }, - rootElement, + businessObject, bpmnFactory ); commands.push( - UpdateModdlePropertiesCmd(element, rootElement, { - extensionElements: rootExtensionElements, + UpdateModdlePropertiesCmd(element, businessObject, { + extensionElements: extensionElements, }) ); } - // (3) ensure form definition + // (2) ensure form definition let formDefinition = getFormDefinition(element); + // (2.1) create if doesn't exist if (!formDefinition) { - formId = createFormId(); + let formKey = customFormKey; + + if (isUndefined(formKey)) { + const formId = createFormId(); + formKey = createFormKey(formId); + } formDefinition = createFormDefinition( { - formKey: createFormKey(formId) + formKey }, extensionElements, bpmnFactory ); - commands.push({ - cmd: 'element.updateModdleProperties', - context: { - element, - moddleElement: extensionElements, - properties: { - values: [ ...extensionElements.get('values'), formDefinition ] - } - } - }); + commands.push( + UpdateModdlePropertiesCmd(element, extensionElements, { + values: [ ...extensionElements.get('values'), formDefinition ] + }) + ); } - formId = resolveFormId(formDefinition.get('formKey')); + // (2.2) update existing form definition with custom key + else if (customFormKey) { + commands.push( + UpdateModdlePropertiesCmd(element, formDefinition, { + formKey: customFormKey + }) + ); + } - // (4) ensure user task form - userTaskForm = getUserTaskForm(element); + return { + formId: resolveFormId(formDefinition.get('formKey')), + commands + }; + } - if (!userTaskForm) { - userTaskForm = createUserTaskForm( - { - id: formId, - body: body - }, - rootExtensionElements, - bpmnFactory - ); + function setFormDefinition(element, customFormKey) { - commands.push({ - cmd: 'element.updateModdleProperties', - context: { - element, - moddleElement: rootExtensionElements, - properties: { - values: [ ...rootExtensionElements.get('values'), userTaskForm ] - } - } - }); - } + const { + commands + } = ensureFormDefinition(element, customFormKey); + + commandStack.execute('properties-panel.multi-command-executor', commands); + } - // (5) update user task form - commands.push(UpdateModdlePropertiesCmd(element, userTaskForm, { - body - })); + function setUserTaskForm(element, value) { - return commands; + const { + formId, + commands: formDefCommands + } = ensureFormDefinition(element); + + const userTaskCommands = ensureTaskForm(element, { id:formId, body:value }); + const commands = formDefCommands.concat(userTaskCommands); + commandStack.execute('properties-panel.multi-command-executor', commands); } - function unsetUserTaskForm(element) { + function unsetFormDefinition(element) { const businessObject = getBusinessObject(element), - rootElement = getRootElement(element), - extensionElements = businessObject.get('extensionElements'), - rootExtensionElements = rootElement.get('extensionElements'); + extensionElements = businessObject.get('extensionElements'); let commands = []; - // (1) remove form definition const formDefinition = getFormDefinition(element); if (!formDefinition) { @@ -228,38 +367,37 @@ function FormHelper(bpmnFactory, commandStack) { let values = without(extensionElements.get('values'), formDefinition); - commands.push({ - cmd: 'element.updateModdleProperties', - context: { - element, - moddleElement: extensionElements, - properties: { - values - } - } - }); + commands.push( + UpdateModdlePropertiesCmd(element, extensionElements, { values }) + ); + + return commands; + } + + function resetForm(element) { + + const rootElement = getRootElement(element), + rootExtensionElements = rootElement.get('extensionElements'); + + // (1) remove form definition + const commands = unsetFormDefinition(element); // (2) remove referenced user task form const userTaskForm = getUserTaskForm(element); if (!userTaskForm) { - return commands; + commandStack.execute('properties-panel.multi-command-executor', commands); + return; } - values = without(rootExtensionElements.get('values'), userTaskForm); + const values = without(rootExtensionElements.get('values'), userTaskForm); - commands.push({ - cmd: 'element.updateModdleProperties', - context: { - element, - moddleElement: rootExtensionElements, - properties: { - values - } - } - }); + commands.push( + UpdateModdlePropertiesCmd(element, rootExtensionElements, { values }) + ); + + commandStack.execute('properties-panel.multi-command-executor', commands); - return commands; } function createFormKey(formId) { @@ -312,28 +450,12 @@ function FormHelper(bpmnFactory, commandStack) { return parent; } - function get(element) { - const value = getUserTaskForm(element); - - return value && value.body || ''; - } - - function set(element, body) { - - body = body && body.trim(); - - const commands = ( - body - ? setUserTaskForm(element, body) - : unsetUserTaskForm(element) - ); - - commandStack.execute('properties-panel.multi-command-executor', commands); - } - return { - get, - set + getFormDefinition, + getUserTaskForm, + setFormDefinition, + setUserTaskForm, + resetForm }; } @@ -352,4 +474,18 @@ function UpdateModdlePropertiesCmd(element, businessObject, newProperties) { properties: newProperties } }; +} + +function isCamundaForm(element, formHelper) { + const formDefinition = formHelper.getFormDefinition(element); + const userTaskForm = formHelper.getUserTaskForm(element); + + return formDefinition && userTaskForm; +} + +function isCustomKey(element, formHelper) { + const formDefinition = formHelper.getFormDefinition(element); + const userTaskForm = formHelper.getUserTaskForm(element); + + return formDefinition && !userTaskForm; } \ No newline at end of file diff --git a/test/spec/provider/zeebe/Forms.bpmn b/test/spec/provider/zeebe/Forms.bpmn index e9afb64fb..800241ab5 100644 --- a/test/spec/provider/zeebe/Forms.bpmn +++ b/test/spec/provider/zeebe/Forms.bpmn @@ -1,24 +1,32 @@ - + {} - + + + + + + - + + + + diff --git a/test/spec/provider/zeebe/Forms.spec.js b/test/spec/provider/zeebe/Forms.spec.js index 8e586ec4c..c87ee9d82 100644 --- a/test/spec/provider/zeebe/Forms.spec.js +++ b/test/spec/provider/zeebe/Forms.spec.js @@ -67,99 +67,211 @@ describe('provider/zeebe - Forms', function() { describe('zeebe:userTaskForm', function() { - it('should display', inject(async function(elementRegistry, selection) { + describe('form type', function() { - // given - const userTask = elementRegistry.get('WITH_FORM'); + it('should display - custom key', inject(async function(elementRegistry, selection) { - // when - await act(() => { - selection.select(userTask); - }); + // given + const userTask = elementRegistry.get('WITH_CAMUNDA_FORM'); - const formInput = getFormInput(container); + // when + await act(() => { + selection.select(userTask); + }); - // then - expect(formInput).to.exist; + const formInput = getFormInput(container); - expect(formInput.value).to.equal('{}'); - })); + // then + expect(formInput).to.exist; + expect(formInput.value).to.equal('formKey'); + })); - it('should display empty', inject(async function(elementRegistry, selection) { - // given - const userTask = elementRegistry.get('NO_FORM'); + it('should display - camunda form', inject(async function(elementRegistry, selection) { - // when - await act(() => { - selection.select(userTask); - }); + // given + const userTask = elementRegistry.get('WITH_CUSTOM_KEY'); - const formInput = getFormInput(container); + // when + await act(() => { + selection.select(userTask); + }); - // then - expect(formInput).to.exist; + const formInput = getFormInput(container); - expect(formInput.value).to.equal(''); - })); + // then + expect(formInput).to.exist; + expect(formInput.value).to.equal('customFormKey'); + })); - it('should update', inject(async function(elementRegistry, selection) { - // given - const userTask = elementRegistry.get('WITH_FORM'); + it('should display - empty', inject(async function(elementRegistry, selection) { - await act(() => { - selection.select(userTask); - }); + // given + const userTask = elementRegistry.get('NO_FORM'); - const formInput = getFormInput(container); + // when + await act(() => { + selection.select(userTask); + }); - // when - changeInput(formInput, '{ "a": 1 }'); + const formInput = getFormInput(container); - // then - expectForm(userTask, '{ "a": 1 }'); - })); + // then + expect(formInput).to.exist; + expect(formInput.value).to.equal(''); + })); - it('should remove', inject(async function(elementRegistry, selection) { - // given - const userTask = elementRegistry.get('WITH_FORM'); + it('should update - empty', inject(async function(elementRegistry, selection) { - await act(() => { - selection.select(userTask); - }); + // given + const userTask = elementRegistry.get('WITH_CAMUNDA_FORM'); - const formInput = getFormInput(container); + await act(() => { + selection.select(userTask); + }); - // when - changeInput(formInput, ''); + const formInput = getFormInput(container); - // then - expectForm(userTask, null); - })); + // when + changeInput(formInput, ''); + // then - it('should add', inject(async function(elementRegistry, selection) { + // expect user task form not to exist + const formDefinition = getFormDefinition(userTask); + expect(formDefinition).to.not.exist; - // given - const userTask = elementRegistry.get('NO_FORM'); + // expect form definnition not to exist + const rootElement = getRootElement(userTask); + const forms = getExtensionElementsList(rootElement, 'zeebe:UserTaskForm'); + expect(forms).to.have.lengthOf(0); + })); - await act(() => { - selection.select(userTask); - }); - const formInput = getFormInput(container); + it('should update - camunda form', inject(async function(elementRegistry, selection) { - // when - changeInput(formInput, '{}'); + // given + const userTask = elementRegistry.get('NO_FORM'); + + await act(() => { + selection.select(userTask); + }); + + const formInput = getFormInput(container); + + // when + changeInput(formInput, 'formKey'); + + // then + expectForm(userTask, ''); + })); + + + it('should update - custom key', inject(async function(elementRegistry, selection) { + + // given + const userTask = elementRegistry.get('NO_FORM'); + + await act(() => { + selection.select(userTask); + }); + + const formInput = getFormInput(container); + + // when + changeInput(formInput, 'customFormKey'); + + // then + expectFormKey(userTask, ''); + })); + + }); + + + describe('camunda form', function() { + + it('should display', inject(async function(elementRegistry, selection) { + + // given + const userTask = elementRegistry.get('WITH_CAMUNDA_FORM'); + + // when + await act(() => { + selection.select(userTask); + }); + + const formConfig = getFormConfig(container); + + // then + expect(formConfig).to.exist; + })); + + + it('should update', inject(async function(elementRegistry, selection) { + + // given + const userTask = elementRegistry.get('WITH_CAMUNDA_FORM'); + + await act(() => { + selection.select(userTask); + }); + + const formConfig = getFormConfig(container); + + // when + changeInput(formConfig, '{ "a": 1 }'); + + // then + expectForm(userTask, '{ "a": 1 }'); + })); + + }); + + + describe('custom key', function() { + + it('should display', inject(async function(elementRegistry, selection) { + + // given + const userTask = elementRegistry.get('WITH_CUSTOM_KEY'); + + // when + await act(() => { + selection.select(userTask); + }); + + const formKey = getCustomKey(container); + + // then + expect(formKey).to.exist; + })); + + + it('should update', inject(async function(elementRegistry, selection) { + + // given + const userTask = elementRegistry.get('WITH_CUSTOM_KEY'); + + await act(() => { + selection.select(userTask); + }); + + const formKey = getCustomKey(container); + + // when + changeInput(formKey, 'customKey'); + + // then + expectFormKey(userTask, 'customKey'); + })); + + }); - // then - expectForm(userTask, '{}'); - })); }); @@ -169,27 +281,35 @@ describe('provider/zeebe - Forms', function() { // helpers ///////////////////// function getFormInput(container) { + return domQuery('select[name=formType]', container); +} + +function getFormConfig(container) { return domQuery('textarea[name=formConfiguration]', container); } -function expectForm(element, body) { +function getCustomKey(container) { + return domQuery('input[name=customFormKey]', container); +} - // (1) get form definition from user task +function expectFormKey(element, key) { const formDefinition = getFormDefinition(element); - // (2.1) assume removed, if no body - if (!body) { - expect(formDefinition).not.to.exist; + expect(formDefinition).to.exist; + expect(formDefinition.formKey).to.eql(key); +} - return; - } +function expectForm(element, body) { + + // (1) get form definition from user task + const formDefinition = getFormDefinition(element); - // (2.2) assume existing + // (1.2) assume existing expect(formDefinition).to.exist; const rootElement = getRootElement(element); - // (3) assume corresponding task form on root element + // (2) assume corresponding task form on root element const formKey = formDefinition.get('formKey'); const form = findUserTaskForm(formKey, rootElement);