From 23052c5c3216d40d0000e637ed7325b67fb98652 Mon Sep 17 00:00:00 2001 From: Martin Stamm Date: Mon, 14 Mar 2022 13:41:32 +0100 Subject: [PATCH] feat(cloud-element-templates): add feel guidance closes #606 --- .../properties/CustomProperties.js | 8 +- .../cloud-element-templates/Validator.spec.js | 17 ++++ .../fixtures/complex.bpmn | 6 +- .../fixtures/complex.json | 74 +++++++++++++++ .../fixtures/error-feel-invalid-type.json | 20 ++++ .../properties/CustomProperties.feel.bpmn | 19 ++++ .../properties/CustomProperties.feel.json | 82 ++++++++++++++++ .../properties/CustomProperties.spec.js | 95 +++++++++++++++++++ 8 files changed, 318 insertions(+), 3 deletions(-) create mode 100644 test/spec/provider/cloud-element-templates/fixtures/error-feel-invalid-type.json create mode 100644 test/spec/provider/cloud-element-templates/properties/CustomProperties.feel.bpmn create mode 100644 test/spec/provider/cloud-element-templates/properties/CustomProperties.feel.json diff --git a/src/provider/cloud-element-templates/properties/CustomProperties.js b/src/provider/cloud-element-templates/properties/CustomProperties.js index b0cd714f5..47b41f767 100644 --- a/src/provider/cloud-element-templates/properties/CustomProperties.js +++ b/src/provider/cloud-element-templates/properties/CustomProperties.js @@ -274,7 +274,8 @@ function StringProperty(props) { const { description, editable, - label + label, + feel } = property; const bpmnFactory = useService('bpmnFactory'), @@ -288,6 +289,7 @@ function StringProperty(props) { getValue: propertyGetter(element, property), id, label, + feel, description: PropertyDescription({ description }), setValue: propertySetter(bpmnFactory, commandStack, element, property), validate: propertyValidator(translate, property), @@ -305,7 +307,8 @@ function TextAreaProperty(props) { const { description, editable, - label + label, + feel } = property; const bpmnFactory = useService('bpmnFactory'), @@ -317,6 +320,7 @@ function TextAreaProperty(props) { element, id, label, + feel, description: PropertyDescription({ description }), getValue: propertyGetter(element, property), setValue: propertySetter(bpmnFactory, commandStack, element, property), diff --git a/test/spec/provider/cloud-element-templates/Validator.spec.js b/test/spec/provider/cloud-element-templates/Validator.spec.js index 7b75fc704..9b49d1383 100644 --- a/test/spec/provider/cloud-element-templates/Validator.spec.js +++ b/test/spec/provider/cloud-element-templates/Validator.spec.js @@ -393,6 +393,23 @@ describe('provider/cloud-element-templates - Validator', function() { }); + it('should reject feel on invalid type', function() { + + // given + const templates = new Validator(); + + const templateDescriptor = require('./fixtures/error-feel-invalid-type'); + + // when + templates.addAll(templateDescriptor); + + // then + expect(errors(templates)).to.contain('template(id: , name: ): feel is only supported for "String" and "Text" type'); + + expect(valid(templates)).to.be.empty; + }); + + describe('grouping', function() { it('should accept groups', function() { diff --git a/test/spec/provider/cloud-element-templates/fixtures/complex.bpmn b/test/spec/provider/cloud-element-templates/fixtures/complex.bpmn index 35bf48af8..205c4419f 100644 --- a/test/spec/provider/cloud-element-templates/fixtures/complex.bpmn +++ b/test/spec/provider/cloud-element-templates/fixtures/complex.bpmn @@ -1,5 +1,5 @@ - + Flow_0gw5hlt @@ -53,6 +53,7 @@ + @@ -88,6 +89,9 @@ + + + diff --git a/test/spec/provider/cloud-element-templates/fixtures/complex.json b/test/spec/provider/cloud-element-templates/fixtures/complex.json index 9ebbf5b2a..bb06d7b4d 100644 --- a/test/spec/provider/cloud-element-templates/fixtures/complex.json +++ b/test/spec/provider/cloud-element-templates/fixtures/complex.json @@ -451,5 +451,79 @@ } } ] + }, + { + "$schema": "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json", + "name": "REST Connector (FEEL enabled)", + "id": "io.camunda.connectors.RestConnector-feel", + "description": "A generic REST service.", + "appliesTo": [ + "bpmn:ServiceTask" + ], + "properties": [ + { + "type": "Hidden", + "value": "http", + "binding": { + "type": "zeebe:taskDefinition:type" + } + }, + { + "label": "REST Endpoint URL", + "description": "Specify the url of the REST API to talk to.", + "type": "String", + "binding": { + "type": "zeebe:taskHeader", + "key": "url" + }, + "constraints": { + "notEmpty": true, + "pattern": { + "value": "^https?://.*", + "message": "Must be http(s) URL." + } + } + }, + { + "label": "REST Method", + "description": "Specify the HTTP method to use.", + "type": "Dropdown", + "value": "get", + "choices": [ + { "name": "GET", "value": "get" }, + { "name": "POST", "value": "post" }, + { "name": "PATCH", "value": "patch" }, + { "name": "DELETE", "value": "delete" } + ], + "binding": { + "type": "zeebe:taskHeader", + "key": "method" + } + }, + { + "label": "Request Body", + "description": "Data to send to the endpoint.", + "value": "", + "optional": true, + "type": "Text", + "binding": { + "type": "zeebe:input", + "name": "body" + }, + "feel": "optional" + }, + { + "label": "Result Variable", + "description": "Name of variable to store the response data in.", + "value": "response", + "optional": true, + "type": "String", + "binding": { + "type": "zeebe:output", + "source": "= body" + }, + "feel": "required" + } + ] } ] \ No newline at end of file diff --git a/test/spec/provider/cloud-element-templates/fixtures/error-feel-invalid-type.json b/test/spec/provider/cloud-element-templates/fixtures/error-feel-invalid-type.json new file mode 100644 index 000000000..7782a37e5 --- /dev/null +++ b/test/spec/provider/cloud-element-templates/fixtures/error-feel-invalid-type.json @@ -0,0 +1,20 @@ +[ + { + "$schema": "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json", + "name": "Invalid", + "id": "invalid", + "appliesTo": [ + "bpmn:ServiceTask" + ], + "properties": [ + { + "type": "Hidden", + "binding": { + "type": "zeebe:input", + "name": "input1" + }, + "feel": "required" + } + ] + } +] \ No newline at end of file diff --git a/test/spec/provider/cloud-element-templates/properties/CustomProperties.feel.bpmn b/test/spec/provider/cloud-element-templates/properties/CustomProperties.feel.bpmn new file mode 100644 index 000000000..6d0ea3588 --- /dev/null +++ b/test/spec/provider/cloud-element-templates/properties/CustomProperties.feel.bpmn @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/spec/provider/cloud-element-templates/properties/CustomProperties.feel.json b/test/spec/provider/cloud-element-templates/properties/CustomProperties.feel.json new file mode 100644 index 000000000..bf23ebd00 --- /dev/null +++ b/test/spec/provider/cloud-element-templates/properties/CustomProperties.feel.json @@ -0,0 +1,82 @@ +[ + { + "name": "Custom FeelTask with Strings", + "$schema": "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json", + "id": "my.custom.FeelTask.String", + "appliesTo": [ + "bpmn:ServiceTask" + ], + "properties": [ + { + "label": "A FEEL expression", + "type": "String", + "feel": "optional", + "editable": true, + "binding": { + "type": "property", + "name": "optionalFeelProp" + } + }, + { + "label": "A required FEEL expression", + "type": "String", + "feel": "required", + "editable": true, + "binding": { + "type": "property", + "name": "feelProp" + } + }, + { + "label": "A Normal Input", + "type": "String", + "editable": true, + "binding": { + "type": "property", + "name": "myCustomProp" + } + } + ], + "entriesVisible": false + }, + { + "name": "Custom FeelTask with TextFields", + "$schema": "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json", + "id": "my.custom.FeelTask.Text", + "appliesTo": [ + "bpmn:ServiceTask" + ], + "properties": [ + { + "label": "A FEEL expression", + "type": "Text", + "feel": "optional", + "editable": true, + "binding": { + "type": "property", + "name": "optionalFeelProp" + } + }, + { + "label": "A required FEEL expression", + "type": "Text", + "feel": "required", + "editable": true, + "binding": { + "type": "property", + "name": "feelProp" + } + }, + { + "label": "A Normal Input", + "type": "Text", + "editable": true, + "binding": { + "type": "property", + "name": "myCustomProp" + } + } + ], + "entriesVisible": false + } +] \ No newline at end of file diff --git a/test/spec/provider/cloud-element-templates/properties/CustomProperties.spec.js b/test/spec/provider/cloud-element-templates/properties/CustomProperties.spec.js index edac274eb..06e15071b 100644 --- a/test/spec/provider/cloud-element-templates/properties/CustomProperties.spec.js +++ b/test/spec/provider/cloud-element-templates/properties/CustomProperties.spec.js @@ -45,6 +45,9 @@ import descriptionElementTemplates from './CustomProperties.description.json'; import editableDiagramXML from './CustomProperties.editable.bpmn'; import editableElementTemplates from './CustomProperties.editable.json'; +import feelDiagramXML from './CustomProperties.feel.bpmn'; +import feelElementTemplates from './CustomProperties.feel.json'; + import defaultTypesDiagramXML from './CustomProperties.default-types.bpmn'; import defaultTypesElementTemplates from './CustomProperties.default-types.json'; @@ -1145,6 +1148,98 @@ describe('provider/cloud-element-templates - CustomProperties', function() { }); + + describe('feel', function() { + + beforeEach(bootstrapPropertiesPanel(feelDiagramXML, { + container, + debounceInput: false, + elementTemplates: feelElementTemplates, + moddleExtensions: { + zeebe: zeebeModdlePackage + }, + modules: [ + BpmnPropertiesPanel, + coreModule, + elementTemplatesModule, + modelingModule + ] + })); + + + describe('TextField', function() { + + it('should not display icon by default', async function() { + + // when + await expectSelected('stringTask'); + + // then + const entry = findEntry('custom-entry-my.custom.FeelTask.String-2', container); + + const feelIcon = domQuery('.bio-properties-panel-feel-icon', entry); + + expect(feelIcon).not.to.exist; + + }); + + + it('should display icons', async function() { + + // when + await expectSelected('stringTask'); + + // then + const requiredEntry = findEntry('custom-entry-my.custom.FeelTask.String-0', container); + const optionalEntry = findEntry('custom-entry-my.custom.FeelTask.String-1', container); + + const requiredIcon = domQuery('.bio-properties-panel-feel-icon', requiredEntry); + const optionalIcon = domQuery('.bio-properties-panel-feel-icon', optionalEntry); + + expect(requiredIcon).to.exist; + expect(optionalIcon).to.exist; + }); + + }); + + + describe('TextArea', function() { + + it('should not display icon by default', async function() { + + // when + await expectSelected('textTask'); + + // then + const entry = findEntry('custom-entry-my.custom.FeelTask.Text-2', container); + + const feelIcon = domQuery('.bio-properties-panel-feel-icon', entry); + + expect(feelIcon).not.to.exist; + + }); + + + it('should display icons on TextArea', async function() { + + // when + await expectSelected('textTask'); + + // then + const requiredEntry = findEntry('custom-entry-my.custom.FeelTask.Text-0', container); + const optionalEntry = findEntry('custom-entry-my.custom.FeelTask.Text-1', container); + + const requiredIcon = domQuery('.bio-properties-panel-feel-icon', requiredEntry); + const optionalIcon = domQuery('.bio-properties-panel-feel-icon', optionalEntry); + + expect(requiredIcon).to.exist; + expect(optionalIcon).to.exist; + }); + + }); + + }); + });