@processmaker/screen-builder 2.60.3 → 2.61.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.60.3",
3
+ "version": "2.61.0",
4
4
  "scripts": {
5
5
  "serve": "vue-cli-service serve",
6
6
  "build": "vue-cli-service build",
@@ -39,7 +39,7 @@
39
39
  "@cypress/code-coverage": "^3.8.1",
40
40
  "@fortawesome/fontawesome-free": "^5.6.1",
41
41
  "@panter/vue-i18next": "^0.15.2",
42
- "@processmaker/vue-form-elements": "0.41.4",
42
+ "@processmaker/vue-form-elements": "0.42.0",
43
43
  "@processmaker/vue-multiselect": "^2.2.0",
44
44
  "@vue/cli-plugin-babel": "^3.6.0",
45
45
  "@vue/cli-plugin-e2e-cypress": "^4.0.3",
@@ -88,7 +88,7 @@
88
88
  },
89
89
  "peerDependencies": {
90
90
  "@panter/vue-i18next": "^0.15.0",
91
- "@processmaker/vue-form-elements": "0.41.4",
91
+ "@processmaker/vue-form-elements": "0.42.0",
92
92
  "i18next": "^15.0.8",
93
93
  "vue": "^2.6.12",
94
94
  "vuex": "^3.1.1"
package/src/.DS_Store CHANGED
Binary file
package/src/App.vue CHANGED
@@ -218,6 +218,7 @@ import VueFormRenderer from './components/vue-form-renderer.vue';
218
218
  import MonacoEditor from 'vue-monaco';
219
219
  import canOpenJsonFile from './mixins/canOpenJsonFile';
220
220
  import { cloneDeep, debounce } from 'lodash';
221
+ import { mapMutations } from 'vuex';
221
222
 
222
223
  // Bring in our initial set of controls
223
224
  import controlConfig from './form-builder-controls';
@@ -420,6 +421,7 @@ export default {
420
421
  this.loadFromLocalStorage();
421
422
  },
422
423
  methods: {
424
+ ...mapMutations("globalErrorsModule", { setStoreMode: "setMode" }),
423
425
  // eslint-disable-next-line func-names
424
426
  updateDataInput: debounce(function () {
425
427
  this.updateDataInputNow();
@@ -456,6 +458,7 @@ export default {
456
458
  } else {
457
459
  this.$refs.builder.refreshContent();
458
460
  }
461
+ this.setStoreMode(this.mode);
459
462
  this.mode = mode;
460
463
  },
461
464
  loadFromLocalStorage() {
@@ -43,6 +43,22 @@ export {
43
43
  Task,
44
44
  };
45
45
 
46
+ /**
47
+ * Gets the screen parent or null if don't have
48
+ * @returns {object|null}
49
+ */
50
+ function findScreenOwner(control) {
51
+ let owner = control.$parent;
52
+ while (owner) {
53
+ const isScreen = owner.$options.name === "ScreenContent";
54
+ if (isScreen) {
55
+ return owner;
56
+ }
57
+ owner = owner.$parent;
58
+ }
59
+ return null;
60
+ }
61
+
46
62
  // Export our Vue plugin as our default
47
63
  export default {
48
64
  install(Vue) {
@@ -87,6 +103,13 @@ export default {
87
103
  }
88
104
  });
89
105
  Vue.mixin({ store });
106
+
107
+ //Helper to access data reference.
108
+ Vue.mixin({ methods:{ getScreenDataReference(customProperties = null, setter = null) {
109
+ const control = this;
110
+ const screen = findScreenOwner(control);
111
+ return screen.getDataReference(customProperties, setter);
112
+ }}});
90
113
  }
91
114
  };
92
115
 
@@ -20,6 +20,8 @@
20
20
  </template>
21
21
 
22
22
  <script>
23
+ import { mapActions } from "vuex";
24
+
23
25
  export default {
24
26
  props: {
25
27
  value: Array,
@@ -27,7 +29,7 @@ export default {
27
29
  error: String,
28
30
  },
29
31
  methods: {
30
- add() {
32
+ async add() {
31
33
  this.value.push({});
32
34
  },
33
35
  remove() {
@@ -8,17 +8,13 @@
8
8
 
9
9
  <script>
10
10
  import Mustache from 'mustache';
11
+ import { mapActions, mapState } from "vuex";
11
12
  import { getValidPath } from '@/mixins';
12
- import { mapState } from 'vuex';
13
+
13
14
 
14
15
  export default {
15
16
  mixins: [getValidPath],
16
17
  props: ['variant', 'label', 'event', 'eventData', 'name', 'fieldValue', 'value', 'tooltip', 'transientData'],
17
- watch: {
18
- valid(valid) {
19
- this.isInvalid = !valid;
20
- }
21
- },
22
18
  computed: {
23
19
  ...mapState('globalErrorsModule', ['valid']),
24
20
  classList() {
@@ -26,7 +22,7 @@ export default {
26
22
  return {
27
23
  btn: true,
28
24
  ['btn-' + variant]: true,
29
- disabled: this.event === 'submit' && this.isInvalid,
25
+ disabled: this.event === 'submit' && !this.valid
30
26
  };
31
27
  },
32
28
  options() {
@@ -49,11 +45,6 @@ export default {
49
45
  };
50
46
  },
51
47
  },
52
- data() {
53
- return {
54
- isInvalid: false,
55
- };
56
- },
57
48
  methods: {
58
49
  setValue(parent, name, value) {
59
50
  if (parent) {
@@ -64,7 +55,7 @@ export default {
64
55
  }
65
56
  }
66
57
  },
67
- click() {
58
+ async click() {
68
59
  if (this.event === 'script') {
69
60
  const trueValue = this.fieldValue || '1';
70
61
  const value = (this.value == trueValue) ? null : trueValue;
@@ -18,7 +18,9 @@ export default {
18
18
  },
19
19
  computed: {
20
20
  imageUrl() {
21
- return get(this.validationData, this.variableName || this.imageName);
21
+ if (this.mode !== 'editor') {
22
+ return get(this.getScreenDataReference(), this.variableName || this.imageName);
23
+ }
22
24
  },
23
25
  },
24
26
  };
@@ -11,6 +11,7 @@
11
11
  class="form-control"
12
12
  :class="classList"
13
13
  type="text"
14
+ @change="onChange"
14
15
  />
15
16
  <input v-else
16
17
  v-model="localValue"
@@ -21,6 +22,7 @@
21
22
  :class="classList"
22
23
  :type="dataType"
23
24
  :maxlength="maxlength"
25
+ @change="onChange"
24
26
  >
25
27
  <template v-if="validator && validator.errorCount">
26
28
  <div class="invalid-feedback" v-for="(errors, index) in validator.errors.all()" :key="index">
@@ -41,6 +43,7 @@ import { TheMask } from 'vue-the-mask';
41
43
  import { getUserDateFormat, getUserDateTimeFormat } from '@processmaker/vue-form-elements/src/dateUtils';
42
44
  import ValidationMixin from '@processmaker/vue-form-elements/src/components/mixins/validation';
43
45
  import moment from 'moment';
46
+ import debounce from "lodash/debounce";
44
47
 
45
48
  const uniqIdsMixin = createUniqIdsMixin();
46
49
  const componentTypes = {
@@ -210,6 +213,9 @@ export default {
210
213
  }
211
214
  },
212
215
  methods: {
216
+ onChange() {
217
+ this.$emit("change", this.convertToData(this.localValue));
218
+ },
213
219
  getUserConfig() {
214
220
  return (window.ProcessMaker && window.ProcessMaker.user) || {};
215
221
  },
@@ -156,7 +156,7 @@
156
156
  import mustacheEvaluation from '../../mixins/mustacheEvaluation';
157
157
  import _ from 'lodash';
158
158
  import { dateUtils } from '@processmaker/vue-form-elements';
159
- //import ScreenRenderer from '../screen-renderer.vue';
159
+ import { mapActions, mapState } from "vuex";
160
160
 
161
161
  const jsonOptionsActionsColumn = {
162
162
  key: '__actions',
@@ -411,7 +411,7 @@ export default {
411
411
  let {_parent, ...result} = this.addItem;
412
412
  this.initFormValues = _.cloneDeep(result);
413
413
  },
414
- handleOk(bvModalEvt) {
414
+ async handleOk(bvModalEvt) {
415
415
  bvModalEvt.preventDefault();
416
416
 
417
417
  if (this.$refs.addRenderer.$refs.renderer.$refs.component.$v.vdata.$invalid) {
@@ -2,13 +2,15 @@
2
2
  * Gets the screen parent or null if don't have
3
3
  * @returns {object|null}
4
4
  */
5
- function findScreenOwner(control) {
5
+ function findScreenOwner(control, lastScreenContentIfNull = false) {
6
6
  let owner = control;
7
7
  let level = 1;
8
+ let lastScreenContent = null;
8
9
  while (owner) {
9
10
  const isScreen = owner.$options.name === "ScreenContent";
10
11
  const isNested = owner.$options.name === "FormNestedScreen";
11
12
  if (isScreen) {
13
+ lastScreenContent = owner;
12
14
  level--;
13
15
  }
14
16
  if (isNested) {
@@ -19,7 +21,7 @@ function findScreenOwner(control) {
19
21
  }
20
22
  owner = owner.$parent;
21
23
  }
22
- return null;
24
+ return lastScreenContentIfNull ? lastScreenContent : null;
23
25
  }
24
26
  /**
25
27
  * Wrap the data of a control using a Proxy
@@ -83,3 +85,11 @@ export default {
83
85
  }
84
86
  }
85
87
  };
88
+
89
+ /**
90
+ * Gets the root screen or same element if couldn't find
91
+ * @returns {object|null}
92
+ */
93
+ export function findRootScreen(element) {
94
+ return findScreenOwner(element, true) || element;
95
+ }
@@ -1,8 +1,8 @@
1
+ import _ from "lodash";
1
2
  import extensions from './extensions';
2
3
  import ScreenBase from './ScreenBase';
3
4
  import CountElements from '../CountElements';
4
5
  import ValidationsFactory from '../ValidationsFactory';
5
- import _, { isEqual } from 'lodash';
6
6
 
7
7
  let screenRenderer;
8
8
 
@@ -184,12 +184,26 @@ export default {
184
184
  return reference;
185
185
  },
186
186
  loadItems(items, component, screen, definition, formIndex) {
187
- items.forEach(element => {
187
+ items.forEach((element) => {
188
188
  const componentName = element[this.nodeNameProperty];
189
189
  const nodeName = this.alias[componentName] || componentName;
190
190
  const properties = { ...element.config };
191
191
  // Extensions.onloadproperties
192
- this.extensions.forEach((ext) => ext.onloadproperties instanceof Function && ext.onloadproperties.bind(this)({ properties, element, component, items, nodeName, componentName, screen, definition , formIndex}));
192
+ this.extensions.forEach(
193
+ (ext) =>
194
+ ext.onloadproperties instanceof Function &&
195
+ ext.onloadproperties.bind(this)({
196
+ properties,
197
+ element,
198
+ component,
199
+ items,
200
+ nodeName,
201
+ componentName,
202
+ screen,
203
+ definition,
204
+ formIndex
205
+ })
206
+ );
193
207
  // Create component
194
208
  const node = this.createComponent(nodeName, properties);
195
209
  // Create wrapper
@@ -291,6 +305,7 @@ export default {
291
305
  props: {},
292
306
  computed: {},
293
307
  methods: {},
308
+ created: [],
294
309
  data: {},
295
310
  watch: {},
296
311
  mounted: [],
@@ -306,7 +321,27 @@ export default {
306
321
  ext.onbuild instanceof Function ? ext.onbuild.bind(this)({ screen: component, definition }) : null;
307
322
  });
308
323
  // Build data
309
- component.data = new Function('const data = {};' + Object.keys(component.data).map(key => `this.setValue(${JSON.stringify(key)}, ${component.data[key]}, data);`).join('\n') + 'return data;');
324
+ const hiddenVars = ["currentPage__"];
325
+ const dataCode = `let value;const data = {};
326
+ ${Object.keys(component.data)
327
+ .map((key) => {
328
+ const { code, variable } = component.data[key];
329
+ return `value = ${code};
330
+ data.${this.safeDotName(key)} = value;
331
+ ${
332
+ !variable ||
333
+ hiddenVars.includes(variable) ||
334
+ variable.endsWith("__")
335
+ ? ""
336
+ : `this.setValue(${JSON.stringify(
337
+ variable
338
+ )}, value, this.vdata);`
339
+ }`;
340
+ })
341
+ .join("\n")};
342
+ return data;`;
343
+ // eslint-disable-next-line no-new-func
344
+ component.data = new Function(dataCode);
310
345
  // Build watchers
311
346
  Object.keys(component.watch).forEach((key) => {
312
347
  const watch = { deep: true };
@@ -317,6 +352,8 @@ export default {
317
352
  // Add validation rules
318
353
  this.addValidationRulesLoader(component, definition);
319
354
  // Build mounted
355
+ component.created = new Function(component.created.join('\n'));
356
+ // Build mounted
320
357
  component.mounted = new Function(component.mounted.join('\n'));
321
358
  return component;
322
359
  } catch (error) {
@@ -331,8 +368,19 @@ export default {
331
368
  };
332
369
  }
333
370
  },
334
- addData(screen, name, code) {
335
- screen.data[name] = code;
371
+ addProp(screen, name, value) {
372
+ screen.props[name] = value;
373
+ },
374
+ addData(screen, name, code, variable = null) {
375
+ screen.data[name] = { code, variable };
376
+ },
377
+ addComputed(screen, name, getterCode, setterCode) {
378
+ screen.computed[name] = {
379
+ // eslint-disable-next-line no-new-func
380
+ get: new Function(getterCode),
381
+ // eslint-disable-next-line no-new-func
382
+ set: new Function("value", setterCode)
383
+ };
336
384
  },
337
385
  addWatch(screen, name, code, options = {}) {
338
386
  if (screen.watch[name]) {
@@ -344,6 +392,9 @@ export default {
344
392
  addMounted(screen, code) {
345
393
  screen.mounted.push(code);
346
394
  },
395
+ addCreated(screen, code) {
396
+ screen.created.push(code);
397
+ },
347
398
  addEvent(properties, event, code) {
348
399
  properties[`@${event}`] = code;
349
400
  },
@@ -367,13 +418,19 @@ export default {
367
418
  });
368
419
  return response;
369
420
  }
370
- const updateValidationRules = function (screenComponent, validations) {
421
+ const updateValidationRules = (screenComponent, validations) => {
371
422
  return new Promise((resolve) => {
372
423
  screenComponent.ValidationRules__ = validations;
373
424
  screenComponent.$nextTick(() => {
374
- if (screenComponent.$v) {
375
- screenComponent.$v.$touch();
376
- resolve();
425
+ try {
426
+ if (screenComponent.$v) {
427
+ screenComponent.$v.$touch();
428
+ resolve();
429
+ }
430
+ } catch (error) {
431
+ if (this.getMode() === "preview") {
432
+ console.warn("There was a problem rendering the screen", error);
433
+ }
377
434
  }
378
435
  });
379
436
  });
@@ -1,15 +1,17 @@
1
- import { get, isEqual, set } from 'lodash';
1
+ import { get, isEqual, set, debounce } from 'lodash';
2
2
  import Mustache from 'mustache';
3
3
  import { mapActions, mapState } from 'vuex';
4
4
  import { ValidationMsg } from './ValidationRules';
5
5
  import DataReference from "./DataReference";
6
+ import computedFields from "./computedFields";
7
+ import { findRootScreen } from "./DataReference";
6
8
 
7
9
  const stringFormats = ['string', 'datetime', 'date', 'password'];
8
10
  const parentReference = [];
9
11
 
10
12
  export default {
11
13
  name: "ScreenContent",
12
- mixins: [DataReference],
14
+ mixins: [DataReference, computedFields],
13
15
  schema: [
14
16
  function() {
15
17
  if (window.ProcessMaker && window.ProcessMaker.packages && window.ProcessMaker.packages.includes('package-vocabularies')) {
@@ -45,7 +47,8 @@ export default {
45
47
  computed: {
46
48
  ...mapState("globalErrorsModule", {
47
49
  valid__: "valid",
48
- message__: "message"
50
+ message__: "message",
51
+ locked__: "locked",
49
52
  }),
50
53
  references__() {
51
54
  return this.$parent && this.$parent.references__;
@@ -134,14 +137,15 @@ export default {
134
137
  },
135
138
  mustache(text) {
136
139
  try {
137
- const data = Object.assign({_parent: this._parent}, this.vdata);
140
+ const data = this.getDataReference();
138
141
  return text && Mustache.render(text, data);
139
142
  } catch (e) {
140
143
  return 'MUSTACHE: ' + e.message;
141
144
  }
142
145
  },
143
146
  async submitForm() {
144
- await this.validateNow(this);
147
+ await this.validateNow(findRootScreen(this));
148
+ console.log(this.valid__, this.message__);
145
149
  if (!this.valid__) {
146
150
  window.ProcessMaker.alert(this.message__, "danger");
147
151
  // if the form is not valid the data is not emitted
@@ -149,6 +153,10 @@ export default {
149
153
  }
150
154
  this.$emit('submit', this.vdata);
151
155
  },
156
+ resetValue(safeDotName, variableName) {
157
+ this.setValue(safeDotName, null);
158
+ this.updateScreenDataNow(safeDotName, variableName);
159
+ },
152
160
  getValidationData() {
153
161
  return this.vdata;
154
162
  },
@@ -166,9 +174,44 @@ export default {
166
174
  value = [];
167
175
  } else if (component === 'FormSelectList' && !config.options.allowMultiSelect) {
168
176
  value = null;
177
+ } else if (component === "FormLoop") {
178
+ value = this.emptyLoopValue(config);
169
179
  }
170
180
  return value;
171
181
  },
182
+ emptyLoopValue(config) {
183
+ if (config.settings.type === "existing") {
184
+ return [];
185
+ }
186
+ const times = Number(config.settings.times);
187
+ const loopVariable = [];
188
+ for (let i = 0; i < times; i++) {
189
+ loopVariable.push({});
190
+ }
191
+ return loopVariable;
192
+ },
193
+ updateScreenData(safeDotName, variable) {
194
+ this[`${safeDotName}_was_filled__`] = true;
195
+ this.blockUpdate(safeDotName, 210);
196
+ this.setValueDebounced(variable, this[safeDotName], this.vdata);
197
+ },
198
+ updateScreenDataNow(safeDotName, variable) {
199
+ this[`${safeDotName}_was_filled__`] = true;
200
+ this.setValue(variable, this[safeDotName], this.vdata);
201
+ this.unblockUpdate(safeDotName);
202
+ },
203
+ blockUpdate(safeDotName, time) {
204
+ this.blockedUpdates[safeDotName] = new Date().getTime() + time;
205
+ },
206
+ unblockUpdate(safeDotName) {
207
+ this.blockUpdate(safeDotName, 0);
208
+ },
209
+ canUpdate(safeDotName) {
210
+ return (
211
+ !this.blockedUpdates[safeDotName] ||
212
+ this.blockedUpdates[safeDotName] < new Date().getTime()
213
+ );
214
+ },
172
215
  getValue(name, object = this) {
173
216
  return object ? get(object, name) : undefined;
174
217
  },
@@ -214,6 +257,32 @@ export default {
214
257
  }
215
258
  }
216
259
  },
260
+ addNonDefinedComputedAttributes(value, key, owner = null) {
261
+ if (value instanceof Array) {
262
+ value.forEach((item, index) => {
263
+ this.addNonDefinedComputedAttributes(item, index, value);
264
+ });
265
+ } else if (value instanceof Object) {
266
+ Object.keys(value).forEach((k) => {
267
+ this.addNonDefinedComputedAttributes(value[k], k, value);
268
+ });
269
+ } else if (
270
+ owner &&
271
+ owner instanceof Object &&
272
+ !(value instanceof Array)
273
+ ) {
274
+ // check if value is reactive using getOwnPropertyDescriptor
275
+ const descriptor = Object.getOwnPropertyDescriptor(owner, key);
276
+ const isReactive = descriptor && descriptor.get;
277
+ if (!isReactive) {
278
+ // remove static value
279
+ delete owner[key];
280
+ // add reactive value
281
+ this.$set(owner, key, value);
282
+ }
283
+ }
284
+ return value;
285
+ },
217
286
  validationMessage(validation) {
218
287
  const message = [];
219
288
  Object.keys(ValidationMsg).forEach(key => {
@@ -234,8 +303,26 @@ export default {
234
303
  setCurrentPage(page) {
235
304
  this.currentPage__ = page;
236
305
  },
306
+ setValueAsync(name, value, object = this, defaults = object) {}
237
307
  },
238
308
  validations() {
239
309
  return { vdata: this.ValidationRules__ };
240
310
  },
311
+ created() {
312
+ this.blockedUpdates = {};
313
+ const debouncedValuesQueue = [];
314
+ const setDebouncedValues = debounce(() => {
315
+ debouncedValuesQueue.forEach((args) => {
316
+ this.setValue(...args);
317
+ });
318
+ }, 210);
319
+ this.setValueDebounced = (...args) => {
320
+ debouncedValuesQueue.push(args);
321
+ setDebouncedValues();
322
+ };
323
+ this.setValueAsync = (name, value, object = this, defaults = object) =>
324
+ Promise.resolve().then(() => {
325
+ this.setValue(name, value, object, defaults);
326
+ });
327
+ }
241
328
  };
@@ -1,32 +1,15 @@
1
- import { Parser } from 'expr-eval';
1
+ import { Parser } from "expr-eval";
2
2
 
3
3
  export default {
4
4
  methods: {
5
5
  visibilityRuleIsVisible(rule) {
6
6
  try {
7
- const that = this;
8
- const dataWithParent = new Proxy(
9
- {},
10
- {
11
- get: (target, name) => {
12
- if (name === "_parent") {
13
- return that._parent;
14
- }
15
- return that.vdata[name];
16
- },
17
- has: (target, name) => {
18
- if (name === "_parent") {
19
- return that._parent !== undefined;
20
- }
21
- return that.vdata[name] !== undefined;
22
- }
23
- }
24
- );
7
+ const dataWithParent = this.getDataReference();
25
8
  const isVisible = Boolean(Parser.evaluate(rule, dataWithParent));
26
9
  return isVisible;
27
10
  } catch (e) {
28
11
  return false;
29
12
  }
30
- },
31
- },
13
+ }
14
+ }
32
15
  };
@@ -1,35 +1,31 @@
1
- import computedFields from '../computedFields';
2
-
3
1
  export default {
4
2
  methods: {
3
+ /**
4
+ * Implements computed fields like this:
5
+ *
6
+ * calcProperty() {
7
+ * let value = this.evaluateExpression('return formula();', 'javascript');
8
+ * value = this.addNonDefinedComputedAttributes(value);
9
+ * this.setValueAsync("calcProperty", value, this.vdata);
10
+ * }
11
+ */
5
12
  computedFields(screen, definition) {
6
- // Add computed fields
7
- screen.mixins.push(computedFields);
8
-
9
- for (const computed of definition.computed) {
10
- screen.computed[computed.property] = {
11
- get: (() => {
12
- const formula = JSON.stringify(computed.formula);
13
- const type = JSON.stringify(computed.type);
14
-
15
- return new Function(`return this.evaluateExpression(${formula}, ${type});`);
16
- })(),
17
- set() {
18
- // Do nothing (as it's not allowed)
19
- },
20
- };
21
-
22
- this.addWatch(
23
- screen,
24
- computed.property,
25
- `this.setValue(${JSON.stringify(computed.property)}, value, this.vdata);`
26
- );
27
-
28
- this.addMounted(screen, `
29
- this.setValue(${JSON.stringify(computed.property)}, this.getValue(${JSON.stringify(computed.property)}), this.vdata, this);
30
- `);
31
- }
32
- },
13
+ // For each computed field defined
14
+ definition.computed.forEach((computed) => {
15
+ const formula = JSON.stringify(computed.formula);
16
+ const type = JSON.stringify(computed.type);
17
+ const name = JSON.stringify(computed.property);
18
+ const safeDotName = this.safeDotName(computed.property);
19
+ const code = `
20
+ let value = this.evaluateExpression(${formula}, ${type});
21
+ value = this.addNonDefinedComputedAttributes(value);
22
+ this.setValue(${name}, value, this.vdata);
23
+ return value;`;
24
+ this.addComputed(screen, safeDotName, code, "");
25
+ // required to enable reactivity of computed field
26
+ this.addWatch(screen, safeDotName, "");
27
+ });
28
+ }
33
29
  },
34
30
  mounted() {
35
31
  this.extensions.push({
@@ -37,7 +33,7 @@ export default {
37
33
  if (definition.computed) {
38
34
  this.computedFields(screen, definition);
39
35
  }
40
- },
36
+ }
41
37
  });
42
- },
38
+ }
43
39
  };