Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/mixins/extensions/LoopContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default {
items: element.items,
},
],
watchers: definition.watchers,
};

let loopContext = '';
Expand Down
13 changes: 10 additions & 3 deletions src/mixins/extensions/Watchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,24 @@ import watchersMixin from '../../mixins/watchers';

export default {
methods: {
filterWatchers(watcher) {
const inContext = !watcher.watching || this.variables.find(({name}) => name === watcher.watching);
return inContext;
},
addWatcherVariables(definition) {
if (definition.watchers) {
definition.watchers.forEach((watcher) => {
this.registerVariable(watcher.output_variable, {});
definition.watchers.filter(this.filterWatchers).forEach((watcher) => {
const inContext = !watcher.watching || this.variables.find(({name}) => name === watcher.watching);
if (inContext) {
this.registerVariable(watcher.output_variable, {});
}
});
}
},
watchers(screen, definition) {
if (definition.watchers) {
screen.mixins.push(watchersMixin);
definition.watchers.forEach((watcher) => {
definition.watchers.filter(this.filterWatchers).forEach((watcher) => {
this.addMounted(screen, `
this.$nextTick(() => this.$watch('${watcher.watching}', (newValue) => {
if (typeof newValue !== 'undefined') {
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/fixtures/watcher_inside_loop.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type":"screen_package","version":"2","screens":[{"id":5,"screen_category_id":"1","title":"Watcher in Loop","description":"Watcher in Loop","type":"FORM","config":[{"name":"Watcher in Loop","items":[{"items":[{"label":"Line Input","config":{"icon":"far fa-square","name":"form_input_1","type":"text","label":"New Input","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-Za-z])(?:[0-9A-Z_.a-z])*[^.]$\/|required|not_in:null,break,case,catch,continue,debugger,default,delete,do,else,finally,for,function,if,in,instanceof,new,return,switch,this,throw,try,typeof,var,void,while,with,class,const,enum,export,extends,import,super,true,false"}},{"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":{"type":null},"validationData":{"type":null},"validationField":{"type":null},"validationMessages":{"type":null}},"watch":{"validationData":{"deep":true}},"methods":[],"computed":[]}],"methods":[],"computed":[],"_compiled":true,"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","helper"],"watch":{"value":{"immediate":true}},"methods":[],"_scopeId":"data-v-172d71e1","computed":{"effectiveValue":[]},"_compiled":true,"components":{"MonacoEditor":{"name":"monaco-editor","_Ctor":[],"props":{"amdRequire":[]},"extends":{"name":"MonacoEditor","model":{"event":"change"},"props":{"theme":{"default":"vs"},"value":{"required":true},"options":[],"language":[],"original":[],"amdRequire":[],"diffEditor":{"default":false}},"watch":{"options":{"deep":true,"user":true}},"methods":[]},"methods":[]}},"staticRenderFns":[]},"field":"defaultValue","config":{"label":"Default Value","helper":"The default value is pre populated using the existing request data. This feature will allow you to modify the value displayed on screen load if needed."}},{"type":"FormInput","field":"conditionalHide","config":{"label":"Visibility Rule","helper":"This control is hidden until this expression is true"}},{"type":"FormInput","field":"customFormatter","config":{"label":"Custom Format String","helper":"Use the Mask Pattern format <br> Date ##\/##\/#### <br> SSN ###-##-#### <br> Phone (###) ###-####","validation":null}},{"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]*]"}},{"type":"FormInput","field":"ariaLabel","config":{"label":"Aria Label","helper":"Attribute designed to help assistive technology (e.g. screen readers) attach a label"}},{"type":"FormInput","field":"tabindex","config":{"label":"Tab Order","helper":"Order in which a user will move focus from one control to another by pressing the Tab key","validation":"regex: [0-9]*"}}],"editor-control":"FormInput","editor-component":"FormInput"}],"label":"Loop","config":{"icon":"fas fa-redo","name":"loop_1","label":null,"settings":{"add":false,"type":"new","times":"3","varname":"loop_1"}},"component":"FormLoop","container":true,"inspector":[{"type":"LoopInspector","field":"settings","config":[]},{"type":"FormInput","field":"conditionalHide","config":{"label":"Visibility Rule","helper":"This control is hidden until this expression is true"}},{"type":"FormInput","field":"customFormatter","config":{"label":"Custom Format String","helper":"Use the Mask Pattern format <br> Date ##\/##\/#### <br> SSN ###-##-#### <br> Phone (###) ###-####","validation":null}},{"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]*]"}},{"type":"FormInput","field":"ariaLabel","config":{"label":"Aria Label","helper":"Attribute designed to help assistive technology (e.g. screen readers) attach a label"}},{"type":"FormInput","field":"tabindex","config":{"label":"Tab Order","helper":"Order in which a user will move focus from one control to another by pressing the Tab key","validation":"regex: [0-9]*"}}],"editor-control":"Loop","editor-component":"Loop"}]}],"computed":[],"custom_css":null,"created_at":"2021-11-05T15:35:12-07:00","updated_at":"2021-11-05T15:37:47-07:00","status":"ACTIVE","key":null,"watchers":[{"input_data":"{}","script_configuration":"{}","synchronous":false,"show_async_loading":false,"run_onload":false,"name":"watcher inside loop","watching":"form_input_1","output_variable":"inside_loop","script":{"id":"script-6","key":null,"title":"simple","description":"simple","language":"php","code":"<?php \n\/* \n * Welcome to ProcessMaker 4 Script Editor \n * To access Environment Variables use getenv(\"ENV_VAR_NAME\") \n * To access Request Data use $data \n * To access Configuration Data use $config \n * To preview your script, click the Run button using the provided input and config data \n * Return an array and it will be merged with the processes data \n * Example API to retrieve user email by their ID $api->users()->getUserById(1)['email'] \n * API Documentation https:\/\/github.com\/ProcessMaker\/docker-executor-php\/tree\/master\/docs\/sdk \n *\/\n\nreturn [\"foo\"=>\"bar\"];","timeout":60,"run_as_user_id":2,"created_at":"2021-11-05T15:36:35-07:00","updated_at":"2021-11-05T15:36:52-07:00","status":"ACTIVE","script_category_id":"1","script_executor_id":3},"script_id":"6","script_key":null,"uid":"16361517695581"}],"categories":[{"id":1,"name":"Uncategorized","status":"ACTIVE","is_system":0,"created_at":"2021-11-01T11:16:52-07:00","updated_at":"2021-11-01T11:16:52-07:00","pivot":{"assignable_id":5,"category_id":1,"category_type":"ProcessMaker\\Models\\ScreenCategory"}}]}],"screen_categories":[],"scripts":[{"id":6,"key":null,"title":"simple","description":"simple","language":"php","code":"<?php \n\/* \n * Welcome to ProcessMaker 4 Script Editor \n * To access Environment Variables use getenv(\"ENV_VAR_NAME\") \n * To access Request Data use $data \n * To access Configuration Data use $config \n * To preview your script, click the Run button using the provided input and config data \n * Return an array and it will be merged with the processes data \n * Example API to retrieve user email by their ID $api->users()->getUserById(1)['email'] \n * API Documentation https:\/\/github.com\/ProcessMaker\/docker-executor-php\/tree\/master\/docs\/sdk \n *\/\n\nreturn [\"foo\"=>\"bar\"];","timeout":60,"run_as_user_id":2,"created_at":"2021-11-05T15:36:35-07:00","updated_at":"2021-11-05T15:36:52-07:00","status":"ACTIVE","script_category_id":"1","script_executor_id":3,"categories":[{"id":1,"name":"Uncategorized","status":"ACTIVE","is_system":0,"created_at":"2021-11-01T11:16:52-07:00","updated_at":"2021-11-01T11:16:52-07:00","pivot":{"assignable_id":6,"category_id":1,"category_type":"ProcessMaker\\Models\\ScriptCategory"}}]}]}
2 changes: 1 addition & 1 deletion tests/e2e/specs/LoadComplexData.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('Validation Rules (Advanced test)', () => {
cy.loadFromJson('FPP_PFP_CHAIRS_SCREEN.json', 0);
cy.get('[data-cy=mode-preview]').click();
// Open Tab 2
cy.get('[aria-label="Part Time"]:visible:first').click();
cy.get('button:contains("Part Time"):visible:first').click();
// Tab 2 contains the title '2. PART TIME PAGE'
cy.get('#preview').should('contain.html', '2. PART TIME PAGE');

Expand Down
114 changes: 114 additions & 0 deletions tests/e2e/specs/WatcherInsideLoop.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
describe('watcher inside loop', () => {
beforeEach(() => {
cy.server();
cy.visit('/');
cy.route(
'POST',
'/api/1.0/scripts/execute/6',
JSON.stringify({
output: {
foo: 'bar',
},
})
).as('executeScript');
});

it('Verify watcher is placed inside loop', () => {
cy.loadFromJson('watcher_inside_loop.json', 0);
cy.get('[data-cy=mode-preview]').click();

// Check the data of the screen
cy.assertPreviewData({
'loop_1': [
{
'form_input_1': '',
'inside_loop': null,
},
{
'form_input_1': '',
'inside_loop': null,
},
{
'form_input_1': '',
'inside_loop': null,
},
],
});

// Change form_input_1 to trigger watcher in the first loop
cy.get('[data-cy="screen-field-form_input_1"]').eq(0).type('foo');
cy.wait('@executeScript');
// Check the data of the screen
cy.assertPreviewData({
'loop_1': [
{
'form_input_1': 'foo',
'inside_loop': {
foo: 'bar',
},
},
{
'form_input_1': '',
'inside_loop': null,
},
{
'form_input_1': '',
'inside_loop': null,
},
],
});

// Change form_input_1 to trigger watcher in the second loop
cy.get('[data-cy="screen-field-form_input_1"]').eq(1).type('foo');
cy.wait('@executeScript');
// Check the data of the screen
cy.assertPreviewData({
'loop_1': [
{
'form_input_1': 'foo',
'inside_loop': {
foo: 'bar',
},
},
{
'form_input_1': 'foo',
'inside_loop': {
foo: 'bar',
},
},
{
'form_input_1': '',
'inside_loop': null,
},
],
});

// Change form_input_1 to trigger watcher in the third loop
cy.get('[data-cy="screen-field-form_input_1"]').eq(2).type('foo');
cy.wait('@executeScript');
// Check the data of the screen
cy.assertPreviewData({
'loop_1': [
{
'form_input_1': 'foo',
'inside_loop': {
foo: 'bar',
},
},
{
'form_input_1': 'foo',
'inside_loop': {
foo: 'bar',
},
},
{
'form_input_1': 'foo',
'inside_loop': {
foo: 'bar',
},
},
],
});

});
});