From bc0d2d325b6f55f8b910af33a30d72518e5ad105 Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Tue, 4 Jun 2024 11:11:48 -0400 Subject: [PATCH 1/7] Add task screen endpoint --- .../Http/Controllers/Api/V1_1/TaskController.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php index 47906da617..7ee2416fb6 100644 --- a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php +++ b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php @@ -6,6 +6,7 @@ use ProcessMaker\Http\Controllers\Controller; use ProcessMaker\Models\ProcessRequestToken; +use ProcessMaker\Http\Resources\Task as Resource; class TaskController extends Controller { @@ -30,4 +31,17 @@ public function show(ProcessRequestToken $task) { return $task; } + + public function showScreen($taskId) + { + $task = ProcessRequestToken::find($taskId); + $response = new Resource($task); + $response = response($response->toArray(request())['screen'], 200); + $now = time(); + // screen cache time + $cacheTime = config('screen_task_cache_time', 86400); + $response->headers->set('Cache-Control', 'max-age=' . $cacheTime . ', must-revalidate, public'); + $response->headers->set('Expires', gmdate('D, d M Y H:i:s', $now + $cacheTime) . ' GMT'); + return $response; + } } From d2b24aaec063a0191dfde07ebf70596af1a93004 Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Tue, 4 Jun 2024 16:12:16 -0400 Subject: [PATCH 2/7] Register endpoint --- routes/v1_1/api.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/routes/v1_1/api.php b/routes/v1_1/api.php index 08ef1fc0ea..d4580ae996 100644 --- a/routes/v1_1/api.php +++ b/routes/v1_1/api.php @@ -8,13 +8,18 @@ ->name('api.1.1.') ->group(function () { // Tasks Endpoints - Route::name('tasks.')->group(function () { + Route::name('tasks.')->prefix('tasks')->group(function () { // Route to list tasks - Route::get('tasks', [TaskController::class, 'index']) + Route::get('/', [TaskController::class, 'index']) ->name('index'); // Route to show a task - Route::get('tasks/{task}', [TaskController::class, 'show']) - ->name('show'); + Route::get('/{task}', [TaskController::class, 'show']) + ->name('show') + ->middleware(['bindings','can:view,task']); + + // Route to show the screen of a task + Route::get('/{taskId}/screen', [TaskController::class, 'showScreen']) + ->name('show.screen'); }); }); From 07c44e0e8a0994dd351e8b6cc65c9b0deed5f965 Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Wed, 5 Jun 2024 15:12:49 -0400 Subject: [PATCH 3/7] Add test for task screen endpoint --- .../V1_1/Fixtures/nested_screen_process.json | 2431 +++++++++++++++++ tests/Feature/Api/V1_1/TaskControllerTest.php | 57 + tests/Feature/Shared/RequestHelper.php | 4 +- 3 files changed, 2490 insertions(+), 2 deletions(-) create mode 100644 tests/Feature/Api/V1_1/Fixtures/nested_screen_process.json create mode 100644 tests/Feature/Api/V1_1/TaskControllerTest.php diff --git a/tests/Feature/Api/V1_1/Fixtures/nested_screen_process.json b/tests/Feature/Api/V1_1/Fixtures/nested_screen_process.json new file mode 100644 index 0000000000..7c8928ff60 --- /dev/null +++ b/tests/Feature/Api/V1_1/Fixtures/nested_screen_process.json @@ -0,0 +1,2431 @@ +{ + "type": "process_package", + "version": "1", + "process": { + "id": 3, + "process_category_id": "2", + "user_id": 2, + "description": "asdf", + "name": "nested screen test", + "cancel_screen_id": null, + "request_detail_screen_id": null, + "status": "ACTIVE", + "is_valid": 1, + "package_key": null, + "pause_timer_start": 0, + "deleted_at": null, + "created_at": "2020-09-10T17:55:30+00:00", + "updated_at": "2021-01-04T18:48:52+00:00", + "start_events": [{ + "id": "node_1", + "name": "Start Event", + "config": "{\"web_entry\":{\"require_valid_session\":false,\"mode\":\"DISABLED\",\"screen_id\":null,\"completed_action\":\"SCREEN\",\"completed_screen_id\":null,\"completed_url\":null,\"authenticatable_type\":\"ProcessMaker\\\\Models\\\\User\",\"authenticatable_id\":1,\"enable_query_params\":false,\"password\":null,\"enable_password_protect\":false,\"exclude_data\":[]}}", + "ownerProcessId": "ProcessId", + "eventDefinitions": [], + "ownerProcessName": "ProcessName", + "allowInterstitial": "false" + }], + "warnings": null, + "self_service_tasks": [], + "signal_events": [], + "conditional_events": [], + "properties": null, + "has_timer_start_events": false, + "notifications": { + "requester": { + "started": false, + "canceled": false, + "completed": false + }, + "assignee": { + "started": false, + "canceled": false, + "completed": false + }, + "participants": { + "started": false, + "canceled": false, + "completed": false + } + }, + "task_notifications": {}, + "bpmn": "\n\n \n \n node_4<\/bpmn:outgoing>\n <\/bpmn:startEvent>\n \n node_4<\/bpmn:incoming>\n node_5<\/bpmn:outgoing>\n <\/bpmn:task>\n \n node_5<\/bpmn:incoming>\n <\/bpmn:endEvent>\n \n \n <\/bpmn:process>\n \n \n \n \n <\/bpmndi:BPMNShape>\n \n \n <\/bpmndi:BPMNShape>\n \n \n <\/bpmndi:BPMNShape>\n \n \n \n <\/bpmndi:BPMNEdge>\n \n \n \n <\/bpmndi:BPMNEdge>\n <\/bpmndi:BPMNPlane>\n <\/bpmndi:BPMNDiagram>\n<\/bpmn:definitions>\n" + }, + "process_categories": [{ + "id": 2, + "name": "Uncategorized", + "status": "ACTIVE", + "is_system": 0, + "created_at": "2021-01-04T18:48:24+00:00", + "updated_at": "2021-01-04T18:48:24+00:00", + "pivot": { + "assignable_id": 3, + "category_id": 2, + "category_type": "ProcessMaker\\Models\\ProcessCategory" + } + }], + "screens": [{ + "id": 2, + "screen_category_id": "1", + "title": "child", + "description": "asdf", + "type": "FORM", + "config": [{ + "name": "child", + "items": [{ + "label": "Rich Text", + "config": { + "icon": "fas fa-pencil-ruler", + "label": null, + "content": "

Child<\/p>", + "interactive": true, + "renderVarHtml": null + }, + "component": "FormHtmlViewer", + "inspector": [{ + "type": "FormTextArea", + "field": "content", + "config": { + "rows": 5, + "label": "Content", + "value": null, + "helper": "The HTML text to display" + } + }, { + "type": "FormCheckbox", + "field": "renderVarHtml", + "config": { + "label": "Render HTML from a Variable", + "value": null, + "helper": null + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormHtmlEditor", + "editor-component": "FormHtmlEditor" + }, { + "label": "Line Input", + "config": { + "icon": "far fa-square", + "name": "child_input_1", + "type": "text", + "label": "child_input_1", + "helper": null, + "readonly": false, + "dataFormat": "string", + "validation": [], + "placeholder": null + }, + "component": "FormInput", + "inspector": [{ + "type": "FormInput", + "field": "name", + "config": { + "name": "Variable Name", + "label": "Variable Name", + "helper": "A variable name is a symbolic name to reference information.", + "validation": "regex:\/^(?:[A-Z_.a-z])(?:[0-9A-Z_.a-z])*$\/|required" + } + }, { + "type": "FormInput", + "field": "label", + "config": { + "label": "Label", + "helper": "The label describes the field's name" + } + }, { + "type": "FormMultiselect", + "field": "dataFormat", + "config": { + "name": "Data Type", + "label": "Data Type", + "helper": "The data type specifies what kind of data is stored in the variable.", + "options": [{ + "value": "string", + "content": "Text" + }, { + "value": "int", + "content": "Integer" + }, { + "value": "currency", + "content": "Currency" + }, { + "value": "percentage", + "content": "Percentage" + }, { + "value": "float", + "content": "Decimal" + }, { + "value": "datetime", + "content": "Datetime" + }, { + "value": "date", + "content": "Date" + }, { + "value": "password", + "content": "Password" + }], + "validation": "required" + } + }, { + "type": { + "extends": { + "props": ["label", "error", "options", "helper", "name", "value", "selectedControl"], + "mixins": [{ + "props": ["validation", "validationData", "validationField", "validationMessages"], + "watch": { + "validationData": { + "deep": true + } + }, + "methods": [] + }], + "methods": [], + "computed": [], + "_compiled": true, + "components": { + "Multiselect": { + "name": "vue-multiselect", + "props": { + "name": { + "default": null + }, + "limit": { + "default": 99999 + }, + "loading": { + "default": false + }, + "disabled": { + "default": false + }, + "tabindex": { + "default": 0 + }, + "limitText": [], + "maxHeight": { + "default": 300 + }, + "showLabels": { + "default": true + }, + "selectLabel": { + "default": "Press enter to select" + }, + "deselectLabel": { + "default": "Press enter to remove" + }, + "openDirection": { + "default": null + }, + "selectedLabel": { + "default": "Selected" + }, + "showNoOptions": { + "default": true + }, + "showNoResults": { + "default": true + }, + "selectGroupLabel": { + "default": "Press enter to select group" + }, + "deselectGroupLabel": { + "default": "Press enter to deselect group" + } + }, + "mixins": [{ + "props": { + "id": { + "default": null + }, + "max": { + "type": [null, null], + "default": false + }, + "label": [], + "value": { + "type": null + }, + "options": { + "required": true + }, + "trackBy": [], + "multiple": { + "default": false + }, + "taggable": { + "default": false + }, + "blockKeys": [], + "allowEmpty": { + "default": true + }, + "groupLabel": [], + "resetAfter": { + "default": false + }, + "searchable": { + "default": true + }, + "customLabel": [], + "groupSelect": { + "default": false + }, + "groupValues": [], + "placeholder": { + "default": "Select option" + }, + "tagPosition": { + "default": "top" + }, + "hideSelected": { + "default": false + }, + "optionsLimit": { + "default": 1000 + }, + "clearOnSelect": { + "default": true + }, + "closeOnSelect": { + "default": true + }, + "internalSearch": { + "default": true + }, + "preselectFirst": { + "default": false + }, + "preserveSearch": { + "default": false + }, + "tagPlaceholder": { + "default": "Press enter to create a tag" + } + }, + "watch": [], + "methods": [], + "computed": [] + }, { + "props": { + "showPointer": { + "default": true + }, + "optionHeight": { + "default": 40 + } + }, + "watch": [], + "methods": [], + "computed": [] + }], + "computed": [], + "_compiled": true, + "beforeCreate": [null], + "staticRenderFns": [] + } + }, + "inheritAttrs": false, + "staticRenderFns": [] + }, + "computed": [], + "_compiled": true, + "staticRenderFns": [] + }, + "field": "dataMask", + "config": { + "name": "Data Format", + "label": "Data Format", + "helper": "The data format for the selected type." + } + }, { + "type": "ValidationSelect", + "field": "validation", + "config": { + "label": "Validation Rules", + "helper": "The validation rules needed for this field" + } + }, { + "type": "FormInput", + "field": "placeholder", + "config": { + "label": "Placeholder Text", + "helper": "The placeholder is what is shown in the field when no value is provided yet" + } + }, { + "type": "FormInput", + "field": "helper", + "config": { + "label": "Helper Text", + "helper": "Help text is meant to provide additional guidance on the field's value" + } + }, { + "type": "FormCheckbox", + "field": "readonly", + "config": { + "label": "Read Only", + "helper": null + } + }, { + "type": "ColorSelect", + "field": "color", + "config": { + "label": "Text Color", + "helper": "Set the element's text color", + "options": [{ + "value": "text-primary", + "content": "primary" + }, { + "value": "text-secondary", + "content": "secondary" + }, { + "value": "text-success", + "content": "success" + }, { + "value": "text-danger", + "content": "danger" + }, { + "value": "text-warning", + "content": "warning" + }, { + "value": "text-info", + "content": "info" + }, { + "value": "text-light", + "content": "light" + }, { + "value": "text-dark", + "content": "dark" + }] + } + }, { + "type": "ColorSelect", + "field": "bgcolor", + "config": { + "label": "Background Color", + "helper": "Set the element's background color", + "options": [{ + "value": "alert alert-primary", + "content": "primary" + }, { + "value": "alert alert-secondary", + "content": "secondary" + }, { + "value": "alert alert-success", + "content": "success" + }, { + "value": "alert alert-danger", + "content": "danger" + }, { + "value": "alert alert-warning", + "content": "warning" + }, { + "value": "alert alert-info", + "content": "info" + }, { + "value": "alert alert-light", + "content": "light" + }, { + "value": "alert alert-dark", + "content": "dark" + }] + } + }, { + "type": { + "props": ["value"], + "watch": { + "value": { + "immediate": true + } + }, + "methods": [], + "_scopeId": "data-v-67152bf8", + "computed": { + "effectiveValue": [] + }, + "_compiled": true, + "components": { + "MonacoEditor": { + "name": "MonacoEditor", + "model": { + "event": "change" + }, + "props": { + "theme": { + "default": "vs" + }, + "amdRequire": [] + }, + "watch": { + "options": { + "deep": true + } + }, + "methods": [] + } + }, + "staticRenderFns": [] + }, + "field": "defaultValue", + "config": { + "label": "Default Value", + "helper": "Takes precedence over value set in data." + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormInput", + "editor-component": "FormInput" + }] + }, { + "name": "p2", + "items": [{ + "label": "Line Input", + "config": { + "icon": "far fa-square", + "name": "child_input_2", + "type": "text", + "label": "child_input_2", + "helper": null, + "readonly": false, + "dataFormat": "string", + "validation": [], + "placeholder": null + }, + "component": "FormInput", + "inspector": [{ + "type": "FormInput", + "field": "name", + "config": { + "name": "Variable Name", + "label": "Variable Name", + "helper": "A variable name is a symbolic name to reference information.", + "validation": "regex:\/^(?:[A-Z_.a-z])(?:[0-9A-Z_.a-z])*$\/|required" + } + }, { + "type": "FormInput", + "field": "label", + "config": { + "label": "Label", + "helper": "The label describes the field's name" + } + }, { + "type": "FormMultiselect", + "field": "dataFormat", + "config": { + "name": "Data Type", + "label": "Data Type", + "helper": "The data type specifies what kind of data is stored in the variable.", + "options": [{ + "value": "string", + "content": "Text" + }, { + "value": "int", + "content": "Integer" + }, { + "value": "currency", + "content": "Currency" + }, { + "value": "percentage", + "content": "Percentage" + }, { + "value": "float", + "content": "Decimal" + }, { + "value": "datetime", + "content": "Datetime" + }, { + "value": "date", + "content": "Date" + }, { + "value": "password", + "content": "Password" + }], + "validation": "required" + } + }, { + "type": { + "_Ctor": [], + "extends": { + "_Ctor": [], + "props": { + "name": { + "type": null + }, + "error": { + "type": null + }, + "label": { + "type": null + }, + "value": { + "type": null + }, + "helper": { + "type": null + }, + "options": { + "type": null + }, + "selectedControl": { + "type": null + } + }, + "mixins": [{ + "props": { + "validation": { + "type": null + }, + "validationData": { + "type": null + }, + "validationField": { + "type": null + }, + "validationMessages": { + "type": null + } + }, + "watch": { + "validationData": { + "deep": true, + "user": true + } + }, + "methods": [] + }], + "methods": [], + "computed": [], + "_compiled": true, + "components": { + "Multiselect": { + "name": "vue-multiselect", + "_Ctor": [], + "props": { + "name": { + "default": null + }, + "limit": { + "default": 99999 + }, + "loading": { + "default": false + }, + "disabled": { + "default": false + }, + "tabindex": { + "default": 0 + }, + "limitText": [], + "maxHeight": { + "default": 300 + }, + "showLabels": { + "default": true + }, + "selectLabel": { + "default": "Press enter to select" + }, + "deselectLabel": { + "default": "Press enter to remove" + }, + "openDirection": { + "default": null + }, + "selectedLabel": { + "default": "Selected" + }, + "showNoOptions": { + "default": true + }, + "showNoResults": { + "default": true + }, + "selectGroupLabel": { + "default": "Press enter to select group" + }, + "deselectGroupLabel": { + "default": "Press enter to deselect group" + } + }, + "mixins": [{ + "props": { + "id": { + "default": null + }, + "max": { + "type": [null, null], + "default": false + }, + "label": [], + "value": { + "type": null + }, + "options": { + "required": true + }, + "trackBy": [], + "multiple": { + "default": false + }, + "taggable": { + "default": false + }, + "blockKeys": [], + "allowEmpty": { + "default": true + }, + "groupLabel": [], + "resetAfter": { + "default": false + }, + "searchable": { + "default": true + }, + "customLabel": [], + "groupSelect": { + "default": false + }, + "groupValues": [], + "placeholder": { + "default": "Select option" + }, + "tagPosition": { + "default": "top" + }, + "hideSelected": { + "default": false + }, + "optionsLimit": { + "default": 1000 + }, + "clearOnSelect": { + "default": true + }, + "closeOnSelect": { + "default": true + }, + "internalSearch": { + "default": true + }, + "preselectFirst": { + "default": false + }, + "preserveSearch": { + "default": false + }, + "tagPlaceholder": { + "default": "Press enter to create a tag" + } + }, + "watch": [], + "methods": [], + "computed": [] + }, { + "props": { + "showPointer": { + "default": true + }, + "optionHeight": { + "default": 40 + } + }, + "watch": [], + "methods": [], + "computed": [] + }], + "computed": [], + "_compiled": true, + "beforeCreate": [null], + "staticRenderFns": [] + } + }, + "inheritAttrs": false, + "staticRenderFns": [] + }, + "computed": [], + "_compiled": true, + "staticRenderFns": [] + }, + "field": "dataMask", + "config": { + "name": "Data Format", + "label": "Data Format", + "helper": "The data format for the selected type." + } + }, { + "type": "ValidationSelect", + "field": "validation", + "config": { + "label": "Validation Rules", + "helper": "The validation rules needed for this field" + } + }, { + "type": "FormInput", + "field": "placeholder", + "config": { + "label": "Placeholder Text", + "helper": "The placeholder is what is shown in the field when no value is provided yet" + } + }, { + "type": "FormInput", + "field": "helper", + "config": { + "label": "Helper Text", + "helper": "Help text is meant to provide additional guidance on the field's value" + } + }, { + "type": "FormCheckbox", + "field": "readonly", + "config": { + "label": "Read Only", + "helper": null + } + }, { + "type": "ColorSelect", + "field": "color", + "config": { + "label": "Text Color", + "helper": "Set the element's text color", + "options": [{ + "value": "text-primary", + "content": "primary" + }, { + "value": "text-secondary", + "content": "secondary" + }, { + "value": "text-success", + "content": "success" + }, { + "value": "text-danger", + "content": "danger" + }, { + "value": "text-warning", + "content": "warning" + }, { + "value": "text-info", + "content": "info" + }, { + "value": "text-light", + "content": "light" + }, { + "value": "text-dark", + "content": "dark" + }] + } + }, { + "type": "ColorSelect", + "field": "bgcolor", + "config": { + "label": "Background Color", + "helper": "Set the element's background color", + "options": [{ + "value": "alert alert-primary", + "content": "primary" + }, { + "value": "alert alert-secondary", + "content": "secondary" + }, { + "value": "alert alert-success", + "content": "success" + }, { + "value": "alert alert-danger", + "content": "danger" + }, { + "value": "alert alert-warning", + "content": "warning" + }, { + "value": "alert alert-info", + "content": "info" + }, { + "value": "alert alert-light", + "content": "light" + }, { + "value": "alert alert-dark", + "content": "dark" + }] + } + }, { + "type": { + "_Ctor": [], + "props": { + "value": { + "type": null + } + }, + "watch": { + "value": { + "user": true, + "immediate": true + } + }, + "methods": [], + "_scopeId": "data-v-67152bf8", + "computed": { + "effectiveValue": [] + }, + "_compiled": true, + "components": { + "MonacoEditor": { + "name": "MonacoEditor", + "model": { + "event": "change" + }, + "props": { + "theme": { + "default": "vs" + }, + "amdRequire": [] + }, + "watch": { + "options": { + "deep": true + } + }, + "methods": [] + } + }, + "staticRenderFns": [] + }, + "field": "defaultValue", + "config": { + "label": "Default Value", + "helper": "Takes precedence over value set in data." + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormInput", + "editor-component": "FormInput" + }] + }], + "computed": [{ + "id": 1, + "name": "test", + "type": "javascript", + "formula": "return 'test calc!';", + "property": "child_input_1" + }], + "custom_css": "* { color: red }", + "created_at": "2020-09-10T17:34:07+00:00", + "updated_at": "2021-01-04T18:48:48+00:00", + "status": "ACTIVE", + "key": null, + "watchers": [{ + "input_data": "{}", + "script_configuration": "{}", + "synchronous": false, + "name": "child watcher", + "watching": "child_input_1", + "script": { + "id": "script-3", + "key": null, + "title": "child watcher script", + "description": "test", + "language": "php", + "code": " 'ok'];", + "timeout": 60, + "run_as_user_id": 1, + "created_at": "2020-09-11T19:06:28+00:00", + "updated_at": "2020-09-11T19:06:37+00:00", + "status": "ACTIVE", + "script_category_id": "1", + "script_executor_id": 3 + }, + "script_id": 3, + "script_key": null, + "output_variable": "watcher_result", + "uid": "15998512345162" + }], + "categories": [{ + "id": 1, + "name": "Uncategorized", + "status": "ACTIVE", + "is_system": 0, + "created_at": "2021-01-04T18:48:24+00:00", + "updated_at": "2021-01-04T18:48:24+00:00", + "pivot": { + "assignable_id": 2, + "category_id": 1, + "category_type": "ProcessMaker\\Models\\ScreenCategory" + } + }] + }, { + "id": 3, + "screen_category_id": "1", + "title": "parent", + "description": "asdf", + "type": "FORM", + "config": [{ + "name": "parent", + "items": [{ + "label": "Rich Text", + "config": { + "icon": "fas fa-pencil-ruler", + "label": null, + "content": "

Parent<\/p>", + "interactive": true, + "renderVarHtml": null + }, + "component": "FormHtmlViewer", + "inspector": [{ + "type": "FormTextArea", + "field": "content", + "config": { + "rows": 5, + "label": "Content", + "value": null, + "helper": "The HTML text to display" + } + }, { + "type": "FormCheckbox", + "field": "renderVarHtml", + "config": { + "label": "Render HTML from a Variable", + "value": null, + "helper": null + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormHtmlEditor", + "editor-component": "FormHtmlEditor" + }, { + "items": [ + [{ + "label": "Line Input", + "config": { + "icon": "far fa-square", + "name": "parent_input_1", + "type": "text", + "label": "parent_input_1", + "helper": null, + "readonly": false, + "dataFormat": "string", + "validation": [], + "placeholder": null + }, + "component": "FormInput", + "inspector": [{ + "type": "FormInput", + "field": "name", + "config": { + "name": "Variable Name", + "label": "Variable Name", + "helper": "A variable name is a symbolic name to reference information.", + "validation": "regex:\/^(?:[A-Z_.a-z])(?:[0-9A-Z_.a-z])*$\/|required" + } + }, { + "type": "FormInput", + "field": "label", + "config": { + "label": "Label", + "helper": "The label describes the field's name" + } + }, { + "type": "FormMultiselect", + "field": "dataFormat", + "config": { + "name": "Data Type", + "label": "Data Type", + "helper": "The data type specifies what kind of data is stored in the variable.", + "options": [{ + "value": "string", + "content": "Text" + }, { + "value": "int", + "content": "Integer" + }, { + "value": "currency", + "content": "Currency" + }, { + "value": "percentage", + "content": "Percentage" + }, { + "value": "float", + "content": "Decimal" + }, { + "value": "datetime", + "content": "Datetime" + }, { + "value": "date", + "content": "Date" + }, { + "value": "password", + "content": "Password" + }], + "validation": "required" + } + }, { + "type": { + "extends": { + "props": ["label", "error", "options", "helper", "name", "value", "selectedControl"], + "mixins": [{ + "props": ["validation", "validationData", "validationField", "validationMessages"], + "watch": { + "validationData": { + "deep": true + } + }, + "methods": [] + }], + "methods": [], + "computed": [], + "_compiled": true, + "components": { + "Multiselect": { + "name": "vue-multiselect", + "_Ctor": [], + "props": { + "name": { + "default": null + }, + "limit": { + "default": 99999 + }, + "loading": { + "default": false + }, + "disabled": { + "default": false + }, + "tabindex": { + "default": 0 + }, + "limitText": [], + "maxHeight": { + "default": 300 + }, + "showLabels": { + "default": true + }, + "selectLabel": { + "default": "Press enter to select" + }, + "deselectLabel": { + "default": "Press enter to remove" + }, + "openDirection": { + "default": null + }, + "selectedLabel": { + "default": "Selected" + }, + "showNoOptions": { + "default": true + }, + "showNoResults": { + "default": true + }, + "selectGroupLabel": { + "default": "Press enter to select group" + }, + "deselectGroupLabel": { + "default": "Press enter to deselect group" + } + }, + "mixins": [{ + "props": { + "id": { + "default": null + }, + "max": { + "type": [null, null], + "default": false + }, + "label": [], + "value": { + "type": null + }, + "options": { + "required": true + }, + "trackBy": [], + "multiple": { + "default": false + }, + "taggable": { + "default": false + }, + "blockKeys": [], + "allowEmpty": { + "default": true + }, + "groupLabel": [], + "resetAfter": { + "default": false + }, + "searchable": { + "default": true + }, + "customLabel": [], + "groupSelect": { + "default": false + }, + "groupValues": [], + "placeholder": { + "default": "Select option" + }, + "tagPosition": { + "default": "top" + }, + "hideSelected": { + "default": false + }, + "optionsLimit": { + "default": 1000 + }, + "clearOnSelect": { + "default": true + }, + "closeOnSelect": { + "default": true + }, + "internalSearch": { + "default": true + }, + "preselectFirst": { + "default": false + }, + "preserveSearch": { + "default": false + }, + "tagPlaceholder": { + "default": "Press enter to create a tag" + } + }, + "watch": [], + "methods": [], + "computed": [] + }, { + "props": { + "showPointer": { + "default": true + }, + "optionHeight": { + "default": 40 + } + }, + "watch": [], + "methods": [], + "computed": [] + }], + "computed": [], + "_compiled": true, + "beforeCreate": [null], + "staticRenderFns": [] + } + }, + "inheritAttrs": false, + "staticRenderFns": [] + }, + "computed": [], + "_compiled": true, + "staticRenderFns": [] + }, + "field": "dataMask", + "config": { + "name": "Data Format", + "label": "Data Format", + "helper": "The data format for the selected type." + } + }, { + "type": "ValidationSelect", + "field": "validation", + "config": { + "label": "Validation Rules", + "helper": "The validation rules needed for this field" + } + }, { + "type": "FormInput", + "field": "placeholder", + "config": { + "label": "Placeholder Text", + "helper": "The placeholder is what is shown in the field when no value is provided yet" + } + }, { + "type": "FormInput", + "field": "helper", + "config": { + "label": "Helper Text", + "helper": "Help text is meant to provide additional guidance on the field's value" + } + }, { + "type": "FormCheckbox", + "field": "readonly", + "config": { + "label": "Read Only", + "helper": null + } + }, { + "type": "ColorSelect", + "field": "color", + "config": { + "label": "Text Color", + "helper": "Set the element's text color", + "options": [{ + "value": "text-primary", + "content": "primary" + }, { + "value": "text-secondary", + "content": "secondary" + }, { + "value": "text-success", + "content": "success" + }, { + "value": "text-danger", + "content": "danger" + }, { + "value": "text-warning", + "content": "warning" + }, { + "value": "text-info", + "content": "info" + }, { + "value": "text-light", + "content": "light" + }, { + "value": "text-dark", + "content": "dark" + }] + } + }, { + "type": "ColorSelect", + "field": "bgcolor", + "config": { + "label": "Background Color", + "helper": "Set the element's background color", + "options": [{ + "value": "alert alert-primary", + "content": "primary" + }, { + "value": "alert alert-secondary", + "content": "secondary" + }, { + "value": "alert alert-success", + "content": "success" + }, { + "value": "alert alert-danger", + "content": "danger" + }, { + "value": "alert alert-warning", + "content": "warning" + }, { + "value": "alert alert-info", + "content": "info" + }, { + "value": "alert alert-light", + "content": "light" + }, { + "value": "alert alert-dark", + "content": "dark" + }] + } + }, { + "type": { + "props": ["value"], + "watch": { + "value": { + "immediate": true + } + }, + "methods": [], + "_scopeId": "data-v-67152bf8", + "computed": { + "effectiveValue": [] + }, + "_compiled": true, + "components": { + "MonacoEditor": { + "name": "MonacoEditor", + "model": { + "event": "change" + }, + "props": { + "theme": { + "default": "vs" + }, + "amdRequire": [] + }, + "watch": { + "options": { + "deep": true + } + }, + "methods": [] + } + }, + "staticRenderFns": [] + }, + "field": "defaultValue", + "config": { + "label": "Default Value", + "helper": "Takes precedence over value set in data." + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormInput", + "editor-component": "FormInput" + }], + [{ + "label": "Nested Screen", + "config": { + "icon": "fas fa-file-invoice", + "name": null, + "event": "submit", + "label": "Nested Screen", + "value": null, + "screen": 2, + "variant": "primary" + }, + "component": "FormNestedScreen", + "inspector": [{ + "type": "ScreenSelector", + "field": "screen", + "config": { + "name": "SelectScreen", + "label": "Screen", + "helper": "Select a screen" + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormSubmit", + "editor-component": "FormNestedScreen" + }] + ], + "label": "Multicolumn \/ Table", + "config": { + "icon": "fas fa-table", + "label": null, + "options": [{ + "value": "1", + "content": "6" + }, { + "value": "2", + "content": "6" + }] + }, + "component": "FormMultiColumn", + "container": true, + "inspector": [{ + "type": "ContainerColumns", + "field": "options", + "config": { + "label": "Column Width", + "validation": "columns-adds-to-12" + } + }, { + "type": "ColorSelect", + "field": "color", + "config": { + "label": "Text Color", + "helper": "Set the element's text color", + "options": [{ + "value": "text-primary", + "content": "primary" + }, { + "value": "text-secondary", + "content": "secondary" + }, { + "value": "text-success", + "content": "success" + }, { + "value": "text-danger", + "content": "danger" + }, { + "value": "text-warning", + "content": "warning" + }, { + "value": "text-info", + "content": "info" + }, { + "value": "text-light", + "content": "light" + }, { + "value": "text-dark", + "content": "dark" + }] + } + }, { + "type": "ColorSelect", + "field": "bgcolor", + "config": { + "label": "Background Color", + "helper": "Set the element's background color", + "options": [{ + "value": "alert alert-primary", + "content": "primary" + }, { + "value": "alert alert-secondary", + "content": "secondary" + }, { + "value": "alert alert-success", + "content": "success" + }, { + "value": "alert alert-danger", + "content": "danger" + }, { + "value": "alert alert-warning", + "content": "warning" + }, { + "value": "alert alert-info", + "content": "info" + }, { + "value": "alert alert-light", + "content": "light" + }, { + "value": "alert alert-dark", + "content": "dark" + }] + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "MultiColumn", + "editor-component": "MultiColumn" + }, { + "label": "Nested Screen", + "config": { + "icon": "fas fa-file-invoice", + "name": null, + "event": "submit", + "label": "Nested Screen", + "value": null, + "screen": 5, + "variant": "primary" + }, + "component": "FormNestedScreen", + "inspector": [{ + "type": "ScreenSelector", + "field": "screen", + "config": { + "name": "SelectScreen", + "label": "Screen", + "helper": "Select a screen" + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormSubmit", + "editor-component": "FormNestedScreen" + }, { + "label": "Submit Button", + "config": { + "icon": "fas fa-share-square", + "name": null, + "event": "submit", + "label": "New Submit", + "variant": "primary", + "fieldValue": null, + "defaultSubmit": true + }, + "component": "FormButton", + "inspector": [{ + "type": "FormInput", + "field": "label", + "config": { + "label": "Label", + "helper": "The label describes the button's text" + } + }, { + "type": "FormInput", + "field": "name", + "config": { + "name": "Variable Name", + "label": "Variable Name", + "helper": "A variable name is a symbolic name to reference information." + } + }, { + "type": "FormMultiselect", + "field": "event", + "config": { + "label": "Type", + "helper": "Choose whether the button should submit the form", + "options": [{ + "value": "submit", + "content": "Submit Button" + }, { + "value": "script", + "content": "Regular Button" + }] + } + }, { + "type": "FormInput", + "field": "fieldValue", + "config": { + "label": "Value", + "helper": "The value being submitted" + } + }, { + "type": "FormMultiselect", + "field": "variant", + "config": { + "label": "Button Variant Style", + "helper": "The variant determines the appearance of the button", + "options": [{ + "value": "primary", + "content": "Primary" + }, { + "value": "secondary", + "content": "Secondary" + }, { + "value": "success", + "content": "Success" + }, { + "value": "danger", + "content": "Danger" + }, { + "value": "warning", + "content": "Warning" + }, { + "value": "info", + "content": "Info" + }, { + "value": "light", + "content": "Light" + }, { + "value": "dark", + "content": "Dark" + }, { + "value": "link", + "content": "Link" + }] + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormSubmit", + "editor-component": "FormButton" + }] + }], + "computed": [{ + "id": 1, + "name": "test", + "type": "javascript", + "formula": "return 'test calc parent';", + "property": "parent_input_1" + }], + "custom_css": "* { color: blue }", + "created_at": "2020-09-10T17:34:26+00:00", + "updated_at": "2021-01-04T18:48:48+00:00", + "status": "ACTIVE", + "key": null, + "watchers": [{ + "input_data": "{}", + "script_configuration": "{}", + "synchronous": false, + "name": "parent watcher test", + "watching": "parent_input_1", + "output_variable": "parent_watcher_result", + "script": { + "id": "script-2", + "key": null, + "title": "parent watcher script", + "description": "test", + "language": "php", + "code": " 'ok'];", + "timeout": 60, + "run_as_user_id": 1, + "created_at": "2020-09-11T19:05:08+00:00", + "updated_at": "2020-09-11T19:05:41+00:00", + "status": "ACTIVE", + "script_category_id": "1", + "script_executor_id": 3 + }, + "script_id": 2, + "script_key": null, + "uid": "15998513965032" + }], + "categories": [{ + "id": 1, + "name": "Uncategorized", + "status": "ACTIVE", + "is_system": 0, + "created_at": "2021-01-04T18:48:24+00:00", + "updated_at": "2021-01-04T18:48:24+00:00", + "pivot": { + "assignable_id": 3, + "category_id": 1, + "category_type": "ProcessMaker\\Models\\ScreenCategory" + } + }] + }, { + "id": 4, + "screen_category_id": "1", + "title": "child3", + "description": "test", + "type": "FORM", + "config": [{ + "name": "child3", + "items": [{ + "label": "Rich Text", + "config": { + "icon": "fas fa-pencil-ruler", + "label": null, + "content": "

Child 3<\/p>", + "interactive": true, + "renderVarHtml": null + }, + "component": "FormHtmlViewer", + "inspector": [{ + "type": "FormTextArea", + "field": "content", + "config": { + "rows": 5, + "label": "Content", + "value": null, + "helper": "The HTML text to display" + } + }, { + "type": "FormCheckbox", + "field": "renderVarHtml", + "config": { + "label": "Render HTML from a Variable", + "value": null, + "helper": null + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormHtmlEditor", + "editor-component": "FormHtmlEditor" + }, { + "label": "Submit Button", + "config": { + "icon": "fas fa-share-square", + "name": null, + "event": "submit", + "label": "child 3 submit", + "variant": "primary", + "fieldValue": null, + "defaultSubmit": true + }, + "component": "FormButton", + "inspector": [{ + "type": "FormInput", + "field": "label", + "config": { + "label": "Label", + "helper": "The label describes the button's text" + } + }, { + "type": "FormInput", + "field": "name", + "config": { + "name": "Variable Name", + "label": "Variable Name", + "helper": "A variable name is a symbolic name to reference information." + } + }, { + "type": "FormMultiselect", + "field": "event", + "config": { + "label": "Type", + "helper": "Choose whether the button should submit the form", + "options": [{ + "value": "submit", + "content": "Submit Button" + }, { + "value": "script", + "content": "Regular Button" + }] + } + }, { + "type": "FormInput", + "field": "fieldValue", + "config": { + "label": "Value", + "helper": "The value being submitted" + } + }, { + "type": "FormMultiselect", + "field": "variant", + "config": { + "label": "Button Variant Style", + "helper": "The variant determines the appearance of the button", + "options": [{ + "value": "primary", + "content": "Primary" + }, { + "value": "secondary", + "content": "Secondary" + }, { + "value": "success", + "content": "Success" + }, { + "value": "danger", + "content": "Danger" + }, { + "value": "warning", + "content": "Warning" + }, { + "value": "info", + "content": "Info" + }, { + "value": "light", + "content": "Light" + }, { + "value": "dark", + "content": "Dark" + }, { + "value": "link", + "content": "Link" + }] + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormSubmit", + "editor-component": "FormButton" + }] + }], + "computed": [], + "custom_css": null, + "created_at": "2020-09-11T21:31:37+00:00", + "updated_at": "2021-01-04T18:50:04+00:00", + "status": "ACTIVE", + "key": null, + "watchers": [], + "categories": [{ + "id": 1, + "name": "Uncategorized", + "status": "ACTIVE", + "is_system": 0, + "created_at": "2021-01-04T18:48:24+00:00", + "updated_at": "2021-01-04T18:48:24+00:00", + "pivot": { + "assignable_id": 4, + "category_id": 1, + "category_type": "ProcessMaker\\Models\\ScreenCategory" + } + }] + }, { + "id": 5, + "screen_category_id": "1", + "title": "child2", + "description": "test", + "type": "FORM", + "config": [{ + "name": "child2", + "items": [{ + "label": "Rich Text", + "config": { + "icon": "fas fa-pencil-ruler", + "label": null, + "content": "

Child 2<\/p>", + "interactive": true, + "renderVarHtml": null + }, + "component": "FormHtmlViewer", + "inspector": [{ + "type": "FormTextArea", + "field": "content", + "config": { + "rows": 5, + "label": "Content", + "value": null, + "helper": "The HTML text to display" + } + }, { + "type": "FormCheckbox", + "field": "renderVarHtml", + "config": { + "label": "Render HTML from a Variable", + "value": null, + "helper": null + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormHtmlEditor", + "editor-component": "FormHtmlEditor" + }, { + "label": "Submit Button", + "config": { + "icon": "fas fa-share-square", + "name": null, + "event": "submit", + "label": "child 2 submit", + "variant": "primary", + "fieldValue": null, + "defaultSubmit": true + }, + "component": "FormButton", + "inspector": [{ + "type": "FormInput", + "field": "label", + "config": { + "label": "Label", + "helper": "The label describes the button's text" + } + }, { + "type": "FormInput", + "field": "name", + "config": { + "name": "Variable Name", + "label": "Variable Name", + "helper": "A variable name is a symbolic name to reference information." + } + }, { + "type": "FormMultiselect", + "field": "event", + "config": { + "label": "Type", + "helper": "Choose whether the button should submit the form", + "options": [{ + "value": "submit", + "content": "Submit Button" + }, { + "value": "script", + "content": "Regular Button" + }] + } + }, { + "type": "FormInput", + "field": "fieldValue", + "config": { + "label": "Value", + "helper": "The value being submitted" + } + }, { + "type": "FormMultiselect", + "field": "variant", + "config": { + "label": "Button Variant Style", + "helper": "The variant determines the appearance of the button", + "options": [{ + "value": "primary", + "content": "Primary" + }, { + "value": "secondary", + "content": "Secondary" + }, { + "value": "success", + "content": "Success" + }, { + "value": "danger", + "content": "Danger" + }, { + "value": "warning", + "content": "Warning" + }, { + "value": "info", + "content": "Info" + }, { + "value": "light", + "content": "Light" + }, { + "value": "dark", + "content": "Dark" + }, { + "value": "link", + "content": "Link" + }] + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormSubmit", + "editor-component": "FormButton" + }, { + "items": [ + [], + [{ + "label": "Submit Button", + "config": { + "icon": "fas fa-share-square", + "name": null, + "event": "submit", + "label": "child 2 submit in multicolumn", + "variant": "primary", + "fieldValue": null, + "defaultSubmit": true + }, + "component": "FormButton", + "inspector": [{ + "type": "FormInput", + "field": "label", + "config": { + "label": "Label", + "helper": "The label describes the button's text" + } + }, { + "type": "FormInput", + "field": "name", + "config": { + "name": "Variable Name", + "label": "Variable Name", + "helper": "A variable name is a symbolic name to reference information." + } + }, { + "type": "FormMultiselect", + "field": "event", + "config": { + "label": "Type", + "helper": "Choose whether the button should submit the form", + "options": [{ + "value": "submit", + "content": "Submit Button" + }, { + "value": "script", + "content": "Regular Button" + }] + } + }, { + "type": "FormInput", + "field": "fieldValue", + "config": { + "label": "Value", + "helper": "The value being submitted" + } + }, { + "type": "FormMultiselect", + "field": "variant", + "config": { + "label": "Button Variant Style", + "helper": "The variant determines the appearance of the button", + "options": [{ + "value": "primary", + "content": "Primary" + }, { + "value": "secondary", + "content": "Secondary" + }, { + "value": "success", + "content": "Success" + }, { + "value": "danger", + "content": "Danger" + }, { + "value": "warning", + "content": "Warning" + }, { + "value": "info", + "content": "Info" + }, { + "value": "light", + "content": "Light" + }, { + "value": "dark", + "content": "Dark" + }, { + "value": "link", + "content": "Link" + }] + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormSubmit", + "editor-component": "FormButton" + }] + ], + "label": "Multicolumn \/ Table", + "config": { + "icon": "fas fa-table", + "label": null, + "options": [{ + "value": "1", + "content": "6" + }, { + "value": "2", + "content": "6" + }] + }, + "component": "FormMultiColumn", + "container": true, + "inspector": [{ + "type": "ContainerColumns", + "field": "options", + "config": { + "label": "Column Width", + "validation": "columns-adds-to-12" + } + }, { + "type": "ColorSelect", + "field": "color", + "config": { + "label": "Text Color", + "helper": "Set the element's text color", + "options": [{ + "value": "text-primary", + "content": "primary" + }, { + "value": "text-secondary", + "content": "secondary" + }, { + "value": "text-success", + "content": "success" + }, { + "value": "text-danger", + "content": "danger" + }, { + "value": "text-warning", + "content": "warning" + }, { + "value": "text-info", + "content": "info" + }, { + "value": "text-light", + "content": "light" + }, { + "value": "text-dark", + "content": "dark" + }] + } + }, { + "type": "ColorSelect", + "field": "bgcolor", + "config": { + "label": "Background Color", + "helper": "Set the element's background color", + "options": [{ + "value": "alert alert-primary", + "content": "primary" + }, { + "value": "alert alert-secondary", + "content": "secondary" + }, { + "value": "alert alert-success", + "content": "success" + }, { + "value": "alert alert-danger", + "content": "danger" + }, { + "value": "alert alert-warning", + "content": "warning" + }, { + "value": "alert alert-info", + "content": "info" + }, { + "value": "alert alert-light", + "content": "light" + }, { + "value": "alert alert-dark", + "content": "dark" + }] + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "MultiColumn", + "editor-component": "MultiColumn" + }, { + "label": "Nested Screen", + "config": { + "icon": "fas fa-file-invoice", + "name": null, + "event": "submit", + "label": "Nested Screen", + "value": null, + "screen": 4, + "variant": "primary" + }, + "component": "FormNestedScreen", + "inspector": [{ + "type": "ScreenSelector", + "field": "screen", + "config": { + "name": "SelectScreen", + "label": "Screen", + "helper": "Select a screen" + } + }, { + "type": "FormInput", + "field": "conditionalHide", + "config": { + "label": "Visibility Rule", + "helper": "This control is hidden until this expression is true" + } + }, { + "type": "FormInput", + "field": "customCssSelector", + "config": { + "label": "CSS Selector Name", + "helper": "Use this in your custom css rules", + "validation": "regex: [-?[_a-zA-Z]+[_-a-zA-Z0-9]*]" + } + }], + "editor-control": "FormSubmit", + "editor-component": "FormNestedScreen" + }] + }], + "computed": [], + "custom_css": null, + "created_at": "2020-09-11T21:32:12+00:00", + "updated_at": "2021-01-04T18:49:50+00:00", + "status": "ACTIVE", + "key": null, + "watchers": [], + "categories": [{ + "id": 1, + "name": "Uncategorized", + "status": "ACTIVE", + "is_system": 0, + "created_at": "2021-01-04T18:48:24+00:00", + "updated_at": "2021-01-04T18:48:24+00:00", + "pivot": { + "assignable_id": 5, + "category_id": 1, + "category_type": "ProcessMaker\\Models\\ScreenCategory" + } + }] + }], + "screen_categories": [], + "scripts": [{ + "id": 2, + "key": null, + "title": "parent watcher script", + "description": "test", + "language": "php", + "code": " 'ok'];", + "timeout": 60, + "run_as_user_id": null, + "created_at": "2020-09-11T19:05:08+00:00", + "updated_at": "2021-01-04T18:48:48+00:00", + "status": "ACTIVE", + "script_category_id": "1", + "script_executor_id": 3, + "categories": [{ + "id": 1, + "name": "Uncategorized", + "status": "ACTIVE", + "is_system": 0, + "created_at": "2021-01-04T18:48:24+00:00", + "updated_at": "2021-01-04T18:48:24+00:00", + "pivot": { + "assignable_id": 2, + "category_id": 1, + "category_type": "ProcessMaker\\Models\\ScriptCategory" + } + }] + }, { + "id": 3, + "key": null, + "title": "child watcher script", + "description": "test", + "language": "php", + "code": " 'ok'];", + "timeout": 60, + "run_as_user_id": null, + "created_at": "2020-09-11T19:06:28+00:00", + "updated_at": "2021-01-04T18:48:48+00:00", + "status": "ACTIVE", + "script_category_id": "1", + "script_executor_id": 3, + "categories": [{ + "id": 1, + "name": "Uncategorized", + "status": "ACTIVE", + "is_system": 0, + "created_at": "2021-01-04T18:48:24+00:00", + "updated_at": "2021-01-04T18:48:24+00:00", + "pivot": { + "assignable_id": 3, + "category_id": 1, + "category_type": "ProcessMaker\\Models\\ScriptCategory" + } + }] + }], + "environment_variables": [] +} \ No newline at end of file diff --git a/tests/Feature/Api/V1_1/TaskControllerTest.php b/tests/Feature/Api/V1_1/TaskControllerTest.php new file mode 100644 index 0000000000..deeaa959a4 --- /dev/null +++ b/tests/Feature/Api/V1_1/TaskControllerTest.php @@ -0,0 +1,57 @@ +create(['element_type' => 'task']); + $response = $this->taskController->index(); + $this->assertContains($task->id, $response->data); + } + + public function testShow() + { + $task = ProcessRequestToken::factory()->create(); + // $response = $this->apiCall('GET', route('api.1.1.tasks.show', $task->id)); + $response = $this->apiCall('GET', route('api.tasks.show', $task->id) . '?include=screen,nested'); + $response->assertStatus(200) + ->assertJson(['id' => $task->id]); + } + + public function testShowScreen() + { + $content = file_get_contents( + __DIR__ . '/Fixtures/nested_screen_process.json' + ); + ImportProcess::dispatchSync($content); + $request = ProcessRequest::factory()->create([ + 'process_id' => Process::where('name', 'nested screen test')->first()->id, + ]); + $task = ProcessRequestToken::factory()->create([ + 'element_type' => 'task', + 'element_name' => 'Task 1', + 'element_id' => 'node_2', + 'process_id' => Process::where('name', 'nested screen test')->first()->id, + 'process_request_id' => $request->id, + ]); + $response = $this->apiCall('GET', route('api.1.1.tasks.show.screen', $task->id) . '?include=screen,nested'); + $this->assertNotNull($response->json()); + $this->assertIsArray($response->json()); + $this->assertNotNull($response->headers->get('Cache-Control')); + $this->assertNotNull($response->headers->get('Expires')); + } +} diff --git a/tests/Feature/Shared/RequestHelper.php b/tests/Feature/Shared/RequestHelper.php index 87dade97a3..e2a8000cc3 100644 --- a/tests/Feature/Shared/RequestHelper.php +++ b/tests/Feature/Shared/RequestHelper.php @@ -44,10 +44,10 @@ protected function apiCall($method, $url, $params = []) { // If the url was generated using the route() helper, // strip out the http://.../api/1.0 part of it; - $url = preg_replace('/^.*\/api\/1\.0/i', '', $url); + $url = preg_replace('/^.*\/api\//i', '', $url); $response = $this->actingAs($this->user, 'api') - ->json($method, '/api/1.0' . $url, $params); + ->json($method, '/api/' . $url, $params); $this->_debug_response = $response; return $response; From 4d7ec3fc0ed3513ff801f48d8c821958474adeb0 Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Thu, 6 Jun 2024 07:06:18 -0400 Subject: [PATCH 4/7] Reduce the size of response --- .../Controllers/Api/V1_1/TaskController.php | 6 +- .../Http/Resources/V1_1/TaskScreen.php | 96 +++++++++++++++++++ ProcessMaker/Traits/TaskResourceIncludes.php | 47 ++++++++- 3 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 ProcessMaker/Http/Resources/V1_1/TaskScreen.php diff --git a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php index 7ee2416fb6..f6e16a22dd 100644 --- a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php +++ b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php @@ -7,6 +7,8 @@ use ProcessMaker\Http\Controllers\Controller; use ProcessMaker\Models\ProcessRequestToken; use ProcessMaker\Http\Resources\Task as Resource; +use ProcessMaker\Http\Resources\V1_1\TaskScreen; +use ProcessMaker\Models\ProcessVersion; class TaskController extends Controller { @@ -34,8 +36,8 @@ public function show(ProcessRequestToken $task) public function showScreen($taskId) { - $task = ProcessRequestToken::find($taskId); - $response = new Resource($task); + $task = ProcessRequestToken::select('id', 'process_request_id', 'element_id', 'process_id')->findOrFail($taskId); + $response = new TaskScreen($task); $response = response($response->toArray(request())['screen'], 200); $now = time(); // screen cache time diff --git a/ProcessMaker/Http/Resources/V1_1/TaskScreen.php b/ProcessMaker/Http/Resources/V1_1/TaskScreen.php new file mode 100644 index 0000000000..e4374e9621 --- /dev/null +++ b/ProcessMaker/Http/Resources/V1_1/TaskScreen.php @@ -0,0 +1,96 @@ +includeScreen($request); + + return $array; + } + + private function includeScreen($request) + { + $array = ['screen' => null]; + + $screen = $this->getScreenVersion(); + + if ($screen) { + if ($screen->type === 'ADVANCED') { + $array['screen'] = $screen; + } else { + $resource = new ScreenVersionResource($screen); + $array['screen'] = $resource->toArray($request); + } + } else { + $array['screen'] = null; + } + + if ($array['screen']) { + // Apply translations to screen + $processTranslation = new ProcessTranslation($this->process); + $array['screen']['config'] = $processTranslation->applyTranslations($array['screen']); + $array['screen']['config'] = $this->removeInspectorMetadata($array['screen']['config']); + + // Apply translations to nested screens + if (array_key_exists('nested', $array['screen'])) { + foreach ($array['screen']['nested'] as &$nestedScreen) { + $nestedScreen['config'] = $processTranslation->applyTranslations($nestedScreen); + $nestedScreen['config'] = $this->removeInspectorMetadata($nestedScreen['config']); + } + } + } + + return $array; + } + + /** + * Removes the inspector metadata from the screen configuration + * + * @param array $config + * @return array + */ + private function removeInspectorMetadata(array $config) + { + foreach($config as $i => $page) { + $config[$i]['items'] = $this->removeInspectorMetadataItems($page['items']); + } + return $config; + } + + /** + * Removes the inspector metadata from the screen configuration items + * + * @param array $items + * @return array + */ + private function removeInspectorMetadataItems(array $items) + { + foreach($items as $i => $item) { + if (isset($item['inspector'])) { + unset($item['inspector']); + } + if (isset($item['component']) && $item['component'] === 'FormMultiColumn') { + foreach($item['items'] as $c => $col) { + $item['items'][$c] = $this->removeInspectorMetadataItems($col); + } + } elseif (isset($item['items']) && is_array($item['items'])) { + $item['items'] = $this->removeInspectorMetadataItems($item['items']); + } + $items[$i] = $item; + } + return $items; + } +} diff --git a/ProcessMaker/Traits/TaskResourceIncludes.php b/ProcessMaker/Traits/TaskResourceIncludes.php index 8b8db4a0f7..9f1127b615 100644 --- a/ProcessMaker/Traits/TaskResourceIncludes.php +++ b/ProcessMaker/Traits/TaskResourceIncludes.php @@ -29,7 +29,7 @@ private function includeRequestor() private function includeProcessRequest() { - return ['process_request' => new Users($this->processRequest)]; + return ['process_request' => $this->processRequest->attributesToArray()]; } private function includeDraft() @@ -72,11 +72,13 @@ private function includeScreen($request) // Apply translations to screen $processTranslation = new ProcessTranslation($this->process); $array['screen']['config'] = $processTranslation->applyTranslations($array['screen']); + $array['screen']['config'] = $this->removeInspectorMetadata($array['screen']['config']); // Apply translations to nested screens if (array_key_exists('nested', $array['screen'])) { foreach ($array['screen']['nested'] as &$nestedScreen) { $nestedScreen['config'] = $processTranslation->applyTranslations($nestedScreen); + $nestedScreen['config'] = $this->removeInspectorMetadata($nestedScreen['config']); } } } @@ -125,6 +127,11 @@ private function includeInterstitial() $translatedConf = $processTranslation->applyTranslations($interstitial['interstitial_screen']); $interstitial['interstitial_screen']['config'] = $translatedConf; + // Remove inspector metadata + $interstitial['interstitial_screen']['config'] = $this->removeInspectorMetadata( + $interstitial['interstitial_screen']['config'] + ); + return [ 'allow_interstitial' => $interstitial['allow_interstitial'], 'interstitial_screen' => $interstitial['interstitial_screen'], @@ -137,4 +144,42 @@ private function includeUserRequestPermission() return ['user_request_permission' => $userRequestPermission]; } + + /** + * Removes the inspector metadata from the screen configuration + * + * @param array $config + * @return array + */ + private function removeInspectorMetadata(array $config) + { + foreach($config as $i => $page) { + $config[$i]['items'] = $this->removeInspectorMetadataItems($page['items']); + } + return $config; + } + + /** + * Removes the inspector metadata from the screen configuration items + * + * @param array $items + * @return array + */ + private function removeInspectorMetadataItems(array $items) + { + foreach($items as $i => $item) { + if (isset($item['inspector'])) { + unset($item['inspector']); + } + if (isset($item['component']) && $item['component'] === 'FormMultiColumn') { + foreach($item['items'] as $c => $col) { + $item['items'][$c] = $this->removeInspectorMetadataItems($col); + } + } elseif (isset($item['items']) && is_array($item['items'])) { + $item['items'] = $this->removeInspectorMetadataItems($item['items']); + } + $items[$i] = $item; + } + return $items; + } } From 46add45532d74309817c04bf506dcbda4a103ea6 Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Thu, 6 Jun 2024 07:21:11 -0400 Subject: [PATCH 5/7] Move resource screen functions into a trait --- .../Http/Resources/V1_1/TaskScreen.php | 41 ++--------------- ProcessMaker/Traits/TaskResourceIncludes.php | 40 +---------------- .../Traits/TaskScreenResourceTrait.php | 45 +++++++++++++++++++ 3 files changed, 50 insertions(+), 76 deletions(-) create mode 100644 ProcessMaker/Traits/TaskScreenResourceTrait.php diff --git a/ProcessMaker/Http/Resources/V1_1/TaskScreen.php b/ProcessMaker/Http/Resources/V1_1/TaskScreen.php index e4374e9621..b4214b30cc 100644 --- a/ProcessMaker/Http/Resources/V1_1/TaskScreen.php +++ b/ProcessMaker/Http/Resources/V1_1/TaskScreen.php @@ -5,9 +5,12 @@ use ProcessMaker\Http\Resources\ApiResource; use ProcessMaker\Http\Resources\ScreenVersion as ScreenVersionResource; use ProcessMaker\ProcessTranslations\ProcessTranslation; +use ProcessMaker\Traits\TaskScreenResourceTrait; class TaskScreen extends ApiResource { + use TaskScreenResourceTrait; + /** * Transform the resource into an array. * @@ -55,42 +58,4 @@ private function includeScreen($request) return $array; } - - /** - * Removes the inspector metadata from the screen configuration - * - * @param array $config - * @return array - */ - private function removeInspectorMetadata(array $config) - { - foreach($config as $i => $page) { - $config[$i]['items'] = $this->removeInspectorMetadataItems($page['items']); - } - return $config; - } - - /** - * Removes the inspector metadata from the screen configuration items - * - * @param array $items - * @return array - */ - private function removeInspectorMetadataItems(array $items) - { - foreach($items as $i => $item) { - if (isset($item['inspector'])) { - unset($item['inspector']); - } - if (isset($item['component']) && $item['component'] === 'FormMultiColumn') { - foreach($item['items'] as $c => $col) { - $item['items'][$c] = $this->removeInspectorMetadataItems($col); - } - } elseif (isset($item['items']) && is_array($item['items'])) { - $item['items'] = $this->removeInspectorMetadataItems($item['items']); - } - $items[$i] = $item; - } - return $items; - } } diff --git a/ProcessMaker/Traits/TaskResourceIncludes.php b/ProcessMaker/Traits/TaskResourceIncludes.php index 9f1127b615..429e0c6603 100644 --- a/ProcessMaker/Traits/TaskResourceIncludes.php +++ b/ProcessMaker/Traits/TaskResourceIncludes.php @@ -12,6 +12,8 @@ trait TaskResourceIncludes { + use TaskScreenResourceTrait; + private function includeData() { return ['data' => $this->getData()]; @@ -144,42 +146,4 @@ private function includeUserRequestPermission() return ['user_request_permission' => $userRequestPermission]; } - - /** - * Removes the inspector metadata from the screen configuration - * - * @param array $config - * @return array - */ - private function removeInspectorMetadata(array $config) - { - foreach($config as $i => $page) { - $config[$i]['items'] = $this->removeInspectorMetadataItems($page['items']); - } - return $config; - } - - /** - * Removes the inspector metadata from the screen configuration items - * - * @param array $items - * @return array - */ - private function removeInspectorMetadataItems(array $items) - { - foreach($items as $i => $item) { - if (isset($item['inspector'])) { - unset($item['inspector']); - } - if (isset($item['component']) && $item['component'] === 'FormMultiColumn') { - foreach($item['items'] as $c => $col) { - $item['items'][$c] = $this->removeInspectorMetadataItems($col); - } - } elseif (isset($item['items']) && is_array($item['items'])) { - $item['items'] = $this->removeInspectorMetadataItems($item['items']); - } - $items[$i] = $item; - } - return $items; - } } diff --git a/ProcessMaker/Traits/TaskScreenResourceTrait.php b/ProcessMaker/Traits/TaskScreenResourceTrait.php new file mode 100644 index 0000000000..bf0d97774e --- /dev/null +++ b/ProcessMaker/Traits/TaskScreenResourceTrait.php @@ -0,0 +1,45 @@ + $page) { + $config[$i]['items'] = $this->removeInspectorMetadataItems($page['items']); + } + return $config; + } + + /** + * Removes the inspector metadata from the screen configuration items + * + * @param array $items + * @return array + */ + private function removeInspectorMetadataItems(array $items) + { + foreach ($items as $i => $item) { + if (isset($item['inspector'])) { + unset($item['inspector']); + } + if (isset($item['component']) && $item['component'] === 'FormMultiColumn') { + foreach ($item['items'] as $c => $col) { + $item['items'][$c] = $this->removeInspectorMetadataItems($col); + } + } elseif (isset($item['items']) && is_array($item['items'])) { + $item['items'] = $this->removeInspectorMetadataItems($item['items']); + } + $items[$i] = $item; + } + return $items; + } +} From 1ad9ba72a2e3db8c32c89e87256a7a3ea288f9f3 Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Thu, 6 Jun 2024 07:21:18 -0400 Subject: [PATCH 6/7] Update test --- tests/Feature/Api/V1_1/TaskControllerTest.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/Feature/Api/V1_1/TaskControllerTest.php b/tests/Feature/Api/V1_1/TaskControllerTest.php index deeaa959a4..c3fbf6533e 100644 --- a/tests/Feature/Api/V1_1/TaskControllerTest.php +++ b/tests/Feature/Api/V1_1/TaskControllerTest.php @@ -16,18 +16,10 @@ class TaskControllerTest extends TestCase protected $taskController; - public function testIndex() - { - $task = ProcessRequestToken::factory()->create(['element_type' => 'task']); - $response = $this->taskController->index(); - $this->assertContains($task->id, $response->data); - } - public function testShow() { $task = ProcessRequestToken::factory()->create(); - // $response = $this->apiCall('GET', route('api.1.1.tasks.show', $task->id)); - $response = $this->apiCall('GET', route('api.tasks.show', $task->id) . '?include=screen,nested'); + $response = $this->apiCall('GET', route('api.1.1.tasks.show', $task->id)); $response->assertStatus(200) ->assertJson(['id' => $task->id]); } From 0eb08d880a8ddc96438ea8a02bc2e0cdef24afd9 Mon Sep 17 00:00:00 2001 From: David Callizaya Date: Thu, 6 Jun 2024 07:32:52 -0400 Subject: [PATCH 7/7] Clean code --- ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php | 5 ++--- ProcessMaker/Http/Resources/V1_1/TaskScreen.php | 4 +--- tests/Feature/Api/V1_1/TaskControllerTest.php | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php index f6e16a22dd..047b24f1da 100644 --- a/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php +++ b/ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php @@ -6,9 +6,7 @@ use ProcessMaker\Http\Controllers\Controller; use ProcessMaker\Models\ProcessRequestToken; -use ProcessMaker\Http\Resources\Task as Resource; use ProcessMaker\Http\Resources\V1_1\TaskScreen; -use ProcessMaker\Models\ProcessVersion; class TaskController extends Controller { @@ -36,7 +34,8 @@ public function show(ProcessRequestToken $task) public function showScreen($taskId) { - $task = ProcessRequestToken::select('id', 'process_request_id', 'element_id', 'process_id')->findOrFail($taskId); + $task = ProcessRequestToken::select('id', 'process_request_id', 'element_id', 'process_id') + ->findOrFail($taskId); $response = new TaskScreen($task); $response = response($response->toArray(request())['screen'], 200); $now = time(); diff --git a/ProcessMaker/Http/Resources/V1_1/TaskScreen.php b/ProcessMaker/Http/Resources/V1_1/TaskScreen.php index b4214b30cc..51d4eb775f 100644 --- a/ProcessMaker/Http/Resources/V1_1/TaskScreen.php +++ b/ProcessMaker/Http/Resources/V1_1/TaskScreen.php @@ -19,9 +19,7 @@ class TaskScreen extends ApiResource */ public function toArray($request) { - $array = $this->includeScreen($request); - - return $array; + return $this->includeScreen($request); } private function includeScreen($request) diff --git a/tests/Feature/Api/V1_1/TaskControllerTest.php b/tests/Feature/Api/V1_1/TaskControllerTest.php index c3fbf6533e..3248ff4952 100644 --- a/tests/Feature/Api/V1_1/TaskControllerTest.php +++ b/tests/Feature/Api/V1_1/TaskControllerTest.php @@ -2,7 +2,6 @@ namespace Tests\Feature\Api\V1_1; -use ProcessMaker\Http\Controllers\Api\V1_1\TaskController; use ProcessMaker\Models\ProcessRequest; use ProcessMaker\Models\ProcessRequestToken; use Tests\Feature\Shared\RequestHelper;