@processmaker/screen-builder 2.20.1 → 2.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@processmaker/screen-builder",
3
- "version": "2.20.1",
3
+ "version": "2.23.0",
4
4
  "scripts": {
5
5
  "serve": "vue-cli-service serve",
6
6
  "build": "vue-cli-service build",
@@ -44,7 +44,7 @@
44
44
  "@cypress/code-coverage": "^3.8.1",
45
45
  "@fortawesome/fontawesome-free": "^5.6.1",
46
46
  "@panter/vue-i18next": "^0.15.2",
47
- "@processmaker/vue-form-elements": "0.28.2",
47
+ "@processmaker/vue-form-elements": "0.28.6",
48
48
  "@processmaker/vue-multiselect": "^2.2.0",
49
49
  "@vue/cli-plugin-babel": "^3.6.0",
50
50
  "@vue/cli-plugin-e2e-cypress": "^4.0.3",
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "peerDependencies": {
87
87
  "@panter/vue-i18next": "^0.15.0",
88
- "@processmaker/vue-form-elements": "0.28.1",
88
+ "@processmaker/vue-form-elements": "0.28.6",
89
89
  "i18next": "^15.0.8",
90
90
  "vue": "^2.6.12",
91
91
  "vuex": "^3.1.1"
@@ -88,10 +88,14 @@ export default {
88
88
  }
89
89
  else {
90
90
  const endpoint = _.get(window, 'PM4ConfigOverrides.getScreenEndpoint', '/screens');
91
- const request = this.get(endpoint + `/${id}${query}`);
91
+
92
+ const screensCacheHit = this.screensCache.find(screen => screen.id == id);
93
+ if (screensCacheHit) {
94
+ return Promise.resolve({data: screensCacheHit});
95
+ }
92
96
 
93
97
  let screenPromise = new Promise((resolve, reject) => {
94
- request
98
+ this.get(endpoint + `/${id}${query}`)
95
99
  .then(response => {
96
100
  if (response.data.nested) {
97
101
  this.addNestedScreenCache(response.data.nested);
@@ -34,7 +34,7 @@ class Validations {
34
34
  isVisible() {
35
35
  // Disable validations if field is hidden
36
36
  let visible = true;
37
- if (this.element.config.conditionalHide) {
37
+ if (!this.data.noData && this.element.config.conditionalHide) {
38
38
  try {
39
39
  visible = !!Parser.evaluate(this.element.config.conditionalHide, this.data);
40
40
  } catch (error) {
@@ -51,7 +51,7 @@ class Validations {
51
51
  class ArrayOfFieldsValidations extends Validations {
52
52
  async addValidations(validations) {
53
53
  for (const item of this.element) {
54
- await ValidationsFactory(item, { screen: this.screen, data: this.data }).addValidations(validations);
54
+ await ValidationsFactory(item, { screen: this.screen, data: this.data, parentVisibilityRule: this.parentVisibilityRule }).addValidations(validations);
55
55
  }
56
56
  }
57
57
  }
@@ -81,8 +81,9 @@ class FormNestedScreenValidations extends Validations {
81
81
  return;
82
82
  }
83
83
  const definition = await this.loadScreen(this.element.config.screen);
84
+ let parentVisibilityRule = this.parentVisibilityRule ? this.parentVisibilityRule : this.element.config.conditionalHide;
84
85
  if (definition && definition[0] && definition[0].items) {
85
- await ValidationsFactory(definition[0].items, { screen: this.screen, data: this.data }).addValidations(validations);
86
+ await ValidationsFactory(definition[0].items, { screen: this.screen, data: this.data, parentVisibilityRule }).addValidations(validations);
86
87
  }
87
88
  }
88
89
 
@@ -112,8 +113,7 @@ class FormLoopValidations extends Validations {
112
113
  set(validations, this.element.config.name, {});
113
114
  const loopField = get(validations, this.element.config.name);
114
115
  loopField['$each'] = {};
115
- const firstRow = (get(this.data, this.element.config.name) || [{}])[0];
116
- await ValidationsFactory(this.element.items, { screen: this.screen, data: {_parent: this.data, ...firstRow } }).addValidations(loopField['$each']);
116
+ await ValidationsFactory(this.element.items, { screen: this.screen, data: {_parent: this.data, noData:true }, parentVisibilityRule: this.element.config.conditionalHide }).addValidations(loopField['$each']);
117
117
  }
118
118
  }
119
119
 
@@ -126,7 +126,7 @@ class FormMultiColumnValidations extends Validations {
126
126
  if (!this.isVisible()) {
127
127
  return;
128
128
  }
129
- await ValidationsFactory(this.element.items, { screen: this.screen, data: this.data }).addValidations(validations);
129
+ await ValidationsFactory(this.element.items, { screen: this.screen, data: this.data, parentVisibilityRule: this.element.config.conditionalHide }).addValidations(validations);
130
130
  }
131
131
  }
132
132
 
@@ -167,19 +167,8 @@ class FormElementValidations extends Validations {
167
167
  }
168
168
  const fieldName = this.element.config.name;
169
169
  const validationConfig = this.element.config.validation;
170
-
171
- // Disable validations if field is hidden
172
- if (this.element.config.conditionalHide) {
173
- let visible = true;
174
- try {
175
- visible = !!Parser.evaluate(this.element.config.conditionalHide, this.data);
176
- } catch (error) {
177
- visible = false;
178
- }
179
- if (!visible) {
180
- return;
181
- }
182
- }
170
+ const conditionalHide = this.element.config.conditionalHide;
171
+ const parentVisibilityRule = this.parentVisibilityRule;
183
172
 
184
173
  set(validations, fieldName, get(validations, fieldName, {}));
185
174
  const fieldValidation = get(validations, fieldName);
@@ -203,7 +192,40 @@ class FormElementValidations extends Validations {
203
192
  params.push(fieldName);
204
193
  validationFn = validationFn(...params);
205
194
  }
206
- fieldValidation[rule] = validationFn;
195
+ fieldValidation[rule] = function(...props) {
196
+ const data = props[1];
197
+ let dataWithParent = this.addReferenceToParents(data);
198
+ const nestedDataWithParent = this.addReferenceToParents(this.findParent(data));
199
+ if (nestedDataWithParent) {
200
+ dataWithParent = Object.assign(nestedDataWithParent, dataWithParent);
201
+ }
202
+ // Check Parent Visibility
203
+ if (parentVisibilityRule) {
204
+ let isParentVisible = true;
205
+ try {
206
+ isParentVisible = !!Parser.evaluate(parentVisibilityRule, dataWithParent);
207
+ } catch (error) {
208
+ isParentVisible = false;
209
+ }
210
+
211
+ if (!isParentVisible ) {
212
+ return true;
213
+ }
214
+ }
215
+ // Check Field Visibility
216
+ let visible = true;
217
+ if (conditionalHide) {
218
+ try {
219
+ visible = !!Parser.evaluate(conditionalHide, dataWithParent);
220
+ } catch (error) {
221
+ visible = false;
222
+ }
223
+ }
224
+ if (!visible) {
225
+ return true;
226
+ }
227
+ return validationFn.apply(this,props);
228
+ };
207
229
  });
208
230
  } else if (typeof validationConfig === 'string' && validationConfig) {
209
231
  let validationFn = validators[validationConfig];
@@ -212,7 +234,40 @@ class FormElementValidations extends Validations {
212
234
  console.error(`Undefined validation rule "${validationConfig}"`);
213
235
  return;
214
236
  }
215
- fieldValidation[validationConfig] = validationFn;
237
+ fieldValidation[validationConfig] = function(...props) {
238
+ const data = props[1];
239
+ let dataWithParent = this.addReferenceToParents(data);
240
+ const nestedDataWithParent = this.addReferenceToParents(this.findParent(data));
241
+ if (nestedDataWithParent) {
242
+ dataWithParent = Object.assign(nestedDataWithParent, dataWithParent);
243
+ }
244
+ // Check Parent Visibility
245
+ if (parentVisibilityRule) {
246
+ let isParentVisible = true;
247
+ try {
248
+ isParentVisible = !!Parser.evaluate(parentVisibilityRule, dataWithParent);
249
+ } catch (error) {
250
+ isParentVisible = false;
251
+ }
252
+
253
+ if (!isParentVisible) {
254
+ return true;
255
+ }
256
+ }
257
+ // Check Field Visibility
258
+ let visible = true;
259
+ if (conditionalHide) {
260
+ try {
261
+ visible = !!Parser.evaluate(conditionalHide, dataWithParent);
262
+ } catch (error) {
263
+ visible = false;
264
+ }
265
+ }
266
+ if (!visible) {
267
+ return true;
268
+ }
269
+ return validationFn.apply(this,props);
270
+ };
216
271
  }
217
272
  if (this.element.items) {
218
273
  ValidationsFactory(this.element.items, { screen: this.screen, data: this.data }).addValidations(validations);
Binary file
@@ -24,6 +24,8 @@
24
24
  :css="css"
25
25
  :empty-text="$t('No Data Available')"
26
26
  :current-page="currentPage"
27
+ @sort-changed="sortChanged"
28
+ @input="onInput"
27
29
  data-cy="table"
28
30
  >
29
31
  <template #cell()="{index,field,item}">
@@ -74,6 +76,7 @@
74
76
  :title="$t('Add')"
75
77
  header-close-content="&times;"
76
78
  data-cy="modal-add"
79
+ @shown="emitShownEvent"
77
80
  >
78
81
  <vue-form-renderer
79
82
  :page="0"
@@ -99,6 +102,7 @@
99
102
  :title="$t('Edit Record')"
100
103
  header-close-content="&times;"
101
104
  data-cy="modal-edit"
105
+ @shown="emitShownEvent"
102
106
  >
103
107
  <vue-form-renderer
104
108
  :page="0"
@@ -161,7 +165,7 @@ const jsonOptionsActionsColumn = {
161
165
 
162
166
  export default {
163
167
  mixins: [mustacheEvaluation],
164
- props: ['name', 'label', 'fields', 'value', 'editable', '_config', 'form', 'validationData', 'formConfig', 'formComputed', 'formWatchers'],
168
+ props: ['name', 'label', 'fields', 'value', 'editable', '_config', 'form', 'validationData', 'formConfig', 'formComputed', 'formWatchers', '_perPage'],
165
169
  data() {
166
170
  return {
167
171
  editFormVersion: 0,
@@ -192,6 +196,11 @@ export default {
192
196
  initFormValues: {},
193
197
  };
194
198
  },
199
+ mounted() {
200
+ if (this._perPage) {
201
+ this.perPage = this._perPage;
202
+ }
203
+ },
195
204
  computed: {
196
205
  popupConfig() {
197
206
  const config = [];
@@ -240,6 +249,7 @@ export default {
240
249
  from,
241
250
  to: value.length,
242
251
  data: value,
252
+ lastSortConfig: false,
243
253
  };
244
254
  return data;
245
255
  },
@@ -258,7 +268,28 @@ export default {
258
268
  return this.form && this.form === this.$parent.currentPage;
259
269
  },
260
270
  },
271
+ watch: {
272
+ 'tableData.total': {
273
+ deep: true,
274
+ handler(total) {
275
+ let totalPages = Math.ceil(total / this.perPage);
276
+ this.currentPage = (this.currentPage > totalPages ? totalPages : this.currentPage);
277
+ },
278
+ },
279
+ },
261
280
  methods: {
281
+ sortChanged(payload) {
282
+ this.lastSortConfig = payload;
283
+ this.tableData.data = _.orderBy(this.tableData.data, [payload.sortBy], [(payload.sortDesc ? 'desc' : 'asc')]);
284
+ },
285
+ onInput() {
286
+ if (this.lastSortConfig) {
287
+ this.tableData.data = _.orderBy(this.tableData.data, [this.lastSortConfig.sortBy], [(this.lastSortConfig.sortDesc ? 'desc' : 'asc')]);
288
+ }
289
+ },
290
+ emitShownEvent() {
291
+ window.ProcessMaker.EventBus.$emit('modal-shown');
292
+ },
262
293
  formatIfDate(string) {
263
294
  return dateUtils.formatIfDate(string);
264
295
  },
@@ -339,7 +370,7 @@ export default {
339
370
  showEditForm(index) {
340
371
  let pageIndex = ((this.paginatorPage-1) * this.perPage) + index;
341
372
  // Reset edit to be a copy of our data model item
342
- this.editItem = JSON.parse(JSON.stringify(this.value[pageIndex]));
373
+ this.editItem = JSON.parse(JSON.stringify(this.tableData.data[pageIndex]));
343
374
  this.editIndex = pageIndex;
344
375
  // rebuild the edit screen to avoid
345
376
  this.editFormVersion++;
@@ -349,13 +380,13 @@ export default {
349
380
  });
350
381
  },
351
382
  edit(event) {
352
- if (this.$refs.editRenderer.$refs.renderer.$refs.component.$v.$invalid) {
383
+ if (this.$refs.editRenderer.$refs.renderer.$refs.component.$v.vdata.$invalid) {
353
384
  event.preventDefault();
354
385
  return;
355
386
  }
356
387
 
357
388
  // Edit the item in our model and emit change
358
- let data = this.value ? JSON.parse(JSON.stringify(this.value)) : [];
389
+ let data = this.tableData.data ? JSON.parse(JSON.stringify(this.tableData.data)) : [];
359
390
  data[this.editIndex] = JSON.parse(JSON.stringify(this.editItem));
360
391
 
361
392
  // Remove the parent object
@@ -382,7 +413,7 @@ export default {
382
413
  handleOk(bvModalEvt) {
383
414
  bvModalEvt.preventDefault();
384
415
 
385
- if (this.$refs.addRenderer.$refs.renderer.$refs.component.$v.$invalid) {
416
+ if (this.$refs.addRenderer.$refs.renderer.$refs.component.$v.vdata.$invalid) {
386
417
  return;
387
418
  }
388
419
 
@@ -442,7 +473,7 @@ export default {
442
473
  remove() {
443
474
  // Add the item to our model and emit change
444
475
  // @todo Also check that value is an array type, if not, reset it to an array
445
- let data = this.value ? JSON.parse(JSON.stringify(this.value)) : [];
476
+ let data = this.tableData.data ? JSON.parse(JSON.stringify(this.tableData.data)) : [];
446
477
  let recordData = data[this.deleteIndex];
447
478
  // Remove item from data array
448
479
  data.splice(this.deleteIndex, 1);
@@ -459,3 +490,4 @@ export default {
459
490
  max-width: 300px;
460
491
  }
461
492
  </style>
493
+
@@ -26,7 +26,7 @@ import Json2Vue from '../mixins/Json2Vue';
26
26
  import CurrentPageProperty from '../mixins/CurrentPageProperty';
27
27
  import WatchersSynchronous from '@/components/watchers-synchronous';
28
28
  import ScreenRendererError from '../components/renderer/screen-renderer-error';
29
- import { cloneDeep, isEqual } from 'lodash';
29
+ import { cloneDeep, isEqual, debounce } from 'lodash';
30
30
 
31
31
  export default {
32
32
  name: 'screen-renderer',
@@ -43,19 +43,23 @@ export default {
43
43
  mounted() {
44
44
  this.currentDefinition = cloneDeep(this.definition);
45
45
  this.component = this.buildComponent(this.currentDefinition);
46
+ this.rebuildScreen = debounce(this.rebuildScreen, 25);
46
47
  },
47
48
  watch: {
48
49
  definition: {
49
50
  deep: true,
50
51
  handler(definition) {
51
- if (!isEqual(definition, this.currentDefinition)) {
52
- this.currentDefinition = cloneDeep(definition);
53
- this.component = this.buildComponent(this.currentDefinition);
54
- }
52
+ this.rebuildScreen(definition);
55
53
  },
56
54
  },
57
55
  },
58
56
  methods: {
57
+ rebuildScreen(definition) {
58
+ if (!isEqual(definition, this.currentDefinition)) {
59
+ this.currentDefinition = cloneDeep(definition);
60
+ this.component = this.buildComponent(this.currentDefinition);
61
+ }
62
+ },
59
63
  onAsyncWatcherOn() {
60
64
  this.displayAsyncLoading = typeof this._parent === 'undefined';
61
65
  },
@@ -242,6 +242,11 @@ export default {
242
242
  .then((response) => {
243
243
  this.task = response.data;
244
244
  this.checkTaskStatus();
245
+ if (window.PM4ConfigOverrides.getScreenEndpoint && window.PM4ConfigOverrides.getScreenEndpoint.includes('tasks/')) {
246
+ const screenPath = window.PM4ConfigOverrides.getScreenEndpoint.split('/');
247
+ screenPath[1] = this.task.id;
248
+ window.PM4ConfigOverrides.getScreenEndpoint = screenPath.join('/');
249
+ }
245
250
  })
246
251
  .catch(() => {
247
252
  this.hasErrors = true;
@@ -279,19 +284,19 @@ export default {
279
284
  }
280
285
  this.prepareTask();
281
286
  },
282
- closeTask() {
287
+ closeTask(parentRequestId = null) {
283
288
  if (this.hasErrors) {
284
289
  this.$emit('error', this.requestId);
285
290
  return;
286
291
  }
287
292
 
288
293
  if (this.task.process_request.status === 'COMPLETED') {
289
- this.processCompleted();
294
+ this.loadNextAssignedTask(parentRequestId);
290
295
 
291
296
  } else if (this.task.allow_interstitial) {
292
297
  this.task.interstitial_screen['_interstitial'] = true;
293
298
  this.screen = this.task.interstitial_screen;
294
- this.loadNextAssignedTask();
299
+ this.loadNextAssignedTask(parentRequestId);
295
300
 
296
301
  } else {
297
302
  this.$emit('closed', this.task.id);
@@ -313,11 +318,18 @@ export default {
313
318
  }
314
319
  this.unsubscribeSocketListeners();
315
320
  this.redirecting = task.process_request_id;
316
- this.$emit('redirect', task);
321
+ this.$emit('redirect', task.id, true);
317
322
  return;
323
+ } else {
324
+ // Only emit completed after getting the subprocess tasks and there are no tasks and process is completed
325
+ if (requestId == this.task.process_request_id && this.parentRequest && this.task.process_request.status === 'COMPLETED') {
326
+ this.$emit('completed', this.parentRequest);
327
+ }
318
328
  }
319
329
  this.taskId = task.id;
320
330
  this.nodeId = task.element_id;
331
+ } else {
332
+ this.$emit('completed', (this.parentRequest ? this.parentRequest : requestId));
321
333
  }
322
334
  });
323
335
  },
@@ -361,9 +373,8 @@ export default {
361
373
  // This may no longer be needed
362
374
  },
363
375
  processCompleted() {
364
- if (this.parentRequest && this.task.allow_interstitial) {
365
- // There could be another task in the parent, so don't emit completed
366
- return;
376
+ if (this.parentRequest) {
377
+ this.$emit('completed', this.parentRequest);
367
378
  }
368
379
  this.$emit('completed', this.requestId);
369
380
  },
@@ -412,8 +423,13 @@ export default {
412
423
  `ProcessMaker.Models.ProcessRequest.${this.parentRequest}`,
413
424
  '.ProcessUpdated',
414
425
  (data) => {
415
- if (['ACTIVITY_COMPLETED', 'ACTIVITY_ACTIVATED'].includes(data.event)) {
416
- this.loadNextAssignedTask(this.parentRequest);
426
+ if (['ACTIVITY_ACTIVATED'].includes(data.event)) {
427
+ this.closeTask(this.parentRequest);
428
+ }
429
+ if (['ACTIVITY_COMPLETED'].includes(data.event)) {
430
+ if (this.task.process_request.status === 'COMPLETED') {
431
+ this.processCompleted();
432
+ }
417
433
  }
418
434
  if (data.event === 'ACTIVITY_EXCEPTION') {
419
435
  this.$emit('error', this.requestId);
@@ -96,7 +96,8 @@ export const keyNameProperty = {
96
96
  config: {
97
97
  label: 'Variable Name',
98
98
  name: 'Variable Name',
99
- validation: 'regex:/^(?:[A-Za-z])(?:[0-9A-Z_.a-z])*[^.]$/|required|not_in:' + javascriptReservedKeywords,
99
+ // Update tests/e2e/specs/Builder.spec.js when changing this
100
+ validation: 'regex:/^([a-zA-Z]([a-zA-Z0-9_]?)+\\.?)+(?<!\\.)$/|required|not_in:' + javascriptReservedKeywords,
100
101
  helper: 'A variable name is a symbolic name to reference information.',
101
102
  },
102
103
  };
package/src/main.js CHANGED
@@ -152,7 +152,7 @@ window.ProcessMaker = {
152
152
  {value: 2, content: 'John'},
153
153
  {value: 3, content: 'Mary'},
154
154
  {value: 4, content: 'Patricia'},
155
- ],
155
+ ],
156
156
  }});
157
157
  break;
158
158
  default:
@@ -201,6 +201,16 @@ window.Echo = {
201
201
  }, 1000);
202
202
  });
203
203
  },
204
+ eventMocks(event, response) {
205
+ this.listeners.forEach((listener) => {
206
+ setTimeout(() => {
207
+ listener.callback({
208
+ type: event,
209
+ response,
210
+ });
211
+ }, 1000);
212
+ });
213
+ },
204
214
  private() {
205
215
  return {
206
216
  notification(callback) {
@@ -2,7 +2,7 @@ import extensions from './extensions';
2
2
  import ScreenBase from './ScreenBase';
3
3
  import CountElements from '../CountElements';
4
4
  import ValidationsFactory from '../ValidationsFactory';
5
- import _ from 'lodash';
5
+ import _, { debounce, isEqual } from 'lodash';
6
6
 
7
7
  let screenRenderer;
8
8
 
@@ -214,7 +214,12 @@ export default {
214
214
  return name && typeof name === 'string' && name.match(/^[a-zA-Z_][0-9a-zA-Z_.]*$/);
215
215
  },
216
216
  isComputedVariable(name, definition) {
217
- return definition.computed && definition.computed.find(c => c.property === name);
217
+ return definition.computed && definition.computed.some(computed => {
218
+ // Check if the first part of an element's name (up to the first `.`)
219
+ // matches the name of a computed property.
220
+ const regex = new RegExp(`^${computed.property}(\\.|$)`, 'i');
221
+ return regex.test(name);
222
+ });
218
223
  },
219
224
  registerVariable(name, element = {}) {
220
225
  if (!this.validVariableName(name)) {
@@ -336,19 +341,43 @@ export default {
336
341
  },
337
342
  addValidationRulesLoader(component, definition) {
338
343
  const firstPage = parseInt(this.currentPage) || 0;
344
+ function getKeys(input) {
345
+ if (input instanceof Array) {
346
+ const response = [];
347
+ input.forEach((item) => {
348
+ response.push(getKeys(item));
349
+ });
350
+ return response;
351
+ }
352
+ if (!(input instanceof Object)) {
353
+ return typeof input;
354
+ }
355
+ const keys = Object.keys(input);
356
+ const response = {};
357
+ keys.forEach((key) => {
358
+ response[key] = getKeys(input[key]);
359
+ });
360
+ return response;
361
+ }
362
+ let updateValidationRules = function(screenComponent, validations) {
363
+ const a = getKeys(screenComponent.ValidationRules__);
364
+ const b = getKeys(validations);
365
+ if (isEqual(a, b)) {
366
+ return;
367
+ }
368
+ screenComponent.ValidationRules__ = validations;
369
+ screenComponent.$nextTick(() => {
370
+ if (screenComponent.$v) {
371
+ screenComponent.$v.$touch();
372
+ }
373
+ });
374
+ };
375
+ updateValidationRules = debounce(updateValidationRules, 25);
339
376
  component.methods.loadValidationRules = function() {
340
377
  // Asynchronous loading of validations
341
378
  const validations = {};
342
379
  ValidationsFactory(definition, { screen: definition, firstPage, data: {_parent: this._parent, ...this.vdata} }).addValidations(validations).then(() => {
343
- if (_.isEqual(this.ValidationRules__, validations)) {
344
- return;
345
- }
346
- this.ValidationRules__ = validations;
347
- this.$nextTick(() => {
348
- if (this.$v) {
349
- this.$v.$touch();
350
- }
351
- });
380
+ updateValidationRules(this, validations);
352
381
  });
353
382
  };
354
383
  component.mounted.push('this.loadValidationRules()');
@@ -102,7 +102,15 @@ export default {
102
102
  },
103
103
  mustache(text) {
104
104
  try {
105
- const data = Object.assign({_parent: this._parent}, this.vdata);
105
+ const data = new Proxy(this, {
106
+ get(target, name) {
107
+ if (name === '_parent') {
108
+ return target._parent;
109
+ } else {
110
+ return target.vdata[name];
111
+ }
112
+ },
113
+ });
106
114
  return text && Mustache.render(text, data);
107
115
  } catch (e) {
108
116
  return 'MUSTACHE: ' + e.message;
@@ -23,6 +23,7 @@ import {
23
23
  and,
24
24
  maxItems,
25
25
  minItems,
26
+ type,
26
27
  } from 'vuelidate/lib/validators';
27
28
 
28
29
  export const ValidationMsg = {
@@ -59,6 +60,7 @@ export const ValidationMsg = {
59
60
  regex: 'Invalid value',
60
61
  maxItems: 'Should NOT have more than {max} items',
61
62
  minItems: 'Must have at least {min}',
63
+ type: 'Invalid type',
62
64
  };
63
65
 
64
66
  export const custom_date = (date) => {
@@ -231,4 +233,5 @@ export const validators = {
231
233
  afterOrEqual: after_or_equal,
232
234
  maxItems,
233
235
  minItems,
236
+ type,
234
237
  };
@@ -69,7 +69,7 @@ export default {
69
69
  properties[':form-computed'] = JSON.stringify(definition.computed);
70
70
  properties[':form-watchers'] = JSON.stringify(definition.watchers);
71
71
  // Check if control is assigned to a calculated property
72
- const isCalcProp = definition.computed && !!definition.computed.find(computed => computed.property == element.config.name);
72
+ const isCalcProp = this.isComputedVariable(element.config.name, definition);
73
73
  properties[':readonly'] = isCalcProp || element.config.readonly;
74
74
  properties[':disabled'] = isCalcProp || element.config.disabled;
75
75
  // Events