@processmaker/screen-builder 2.65.0 → 2.67.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.65.0",
3
+ "version": "2.67.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.43.5",
42
+ "@processmaker/vue-form-elements": "0.44.1",
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.43.5",
91
+ "@processmaker/vue-form-elements": "0.44.1",
92
92
  "i18next": "^15.0.8",
93
93
  "vue": "^2.6.12",
94
94
  "vuex": "^3.1.1"
@@ -3,6 +3,7 @@ import axios from "axios";
3
3
  import { has, get } from "lodash";
4
4
  import { cacheAdapterEnhancer } from "axios-extensions";
5
5
  import LRUCache from "lru-cache";
6
+ import i18next from 'i18next';
6
7
 
7
8
  const FIVE_MINUTES = 1000 * 60 * 5;
8
9
 
@@ -215,5 +216,41 @@ export default {
215
216
 
216
217
  download(url) {
217
218
  return this.apiInstance().get(url, { responseType: "blob" });
218
- }
219
+ },
220
+
221
+ getCollections() {
222
+ return this.get("/collections?per_page=1000").catch((error) => {
223
+ if (error.response && error.response.status === 404) {
224
+ throw new Error(i18next.t("Collections package not installed"));
225
+ }
226
+ throw error;
227
+ });
228
+ },
229
+
230
+ getCollectionFields(collectionId) {
231
+ return this.get(`/collections/${collectionId}/columns?per_page=1000`).catch((error) => {
232
+ if (error.response && error.response.status === 404) {
233
+ throw new Error(i18next.t("Collection id not found"));
234
+ }
235
+ throw error;
236
+ })
237
+ },
238
+
239
+ getCollectionRecords(collectionId, options, nonce = null) {
240
+ options.useCache = window.ProcessMaker.screen.cacheEnabled;
241
+
242
+ return this.get(`/collections/${collectionId}/records` + this.authQueryString(), options).then((response) => {
243
+ const data = response ? response.data : null;
244
+ if (!data) {
245
+ throw new Error(i18next.t("No data returned"));
246
+ }
247
+ return [data, nonce];
248
+ }).catch((error) => {
249
+ if (error.response && error.response.status === 404) {
250
+ const data = { data: [] };
251
+ return [data, nonce];
252
+ }
253
+ throw error;
254
+ });
255
+ },
219
256
  };
@@ -0,0 +1,163 @@
1
+ <template>
2
+ <div>
3
+ <div>
4
+ <label for="collection">{{ $t("Collection") }}</label>
5
+ <b-form-select
6
+ id="collection"
7
+ v-model="collectionId"
8
+ @change="resetFields"
9
+ :options="collections"
10
+ data-cy="inspector-collection"
11
+ />
12
+ </div>
13
+
14
+ <div class="mt-3" v-if="fields.length > 1">
15
+ <label for="label">{{ $t("Label") }}</label>
16
+ <b-form-select
17
+ id="label"
18
+ v-model="labelField"
19
+ :options="fields"
20
+ data-cy="inspector-collection-label"
21
+ />
22
+ </div>
23
+
24
+ <div class="mt-3" v-if="fields.length > 1">
25
+ <label for="value">{{ $t("Value") }}</label>
26
+ <b-form-select
27
+ id="value"
28
+ v-model="valueField"
29
+ :options="fields"
30
+ data-cy="inspector-collection-value"
31
+ />
32
+ </div>
33
+
34
+ <div class="mt-3" v-if="fields.length > 1">
35
+ <label for="pmql">{{ $t("PMQL") }}</label>
36
+ <mustache-helper />
37
+ <b-form-textarea
38
+ id="pmql"
39
+ rows="4"
40
+ v-model="pmql"
41
+ data-cy="inspector-collection-pmql"
42
+ />
43
+ <small class="form-text text-muted">{{
44
+ $t("Add a PMQL query to filter the result list. Use `data` as prefix")
45
+ }}</small>
46
+ </div>
47
+
48
+ <div class="mt-3" v-if="fields.length > 1">
49
+ <form-checkbox
50
+ :label="$t('Ignore duplicates in list')"
51
+ v-model="unique"
52
+ :helper="$t('Select to show only distinct list entries if labels are repeated. Only the first value will be used if duplicate labels have different values.')"
53
+ data-cy="inspector-collection-isDependent"
54
+ />
55
+ </div>
56
+
57
+ </div>
58
+ </template>
59
+
60
+ <script>
61
+ import _ from "lodash";
62
+ import MustacheHelper from "./mustache-helper";
63
+ import ScreenVariableSelector from '../screen-variable-selector.vue';
64
+
65
+ const CONFIG_FIELDS = [
66
+ "collectionId",
67
+ "labelField",
68
+ "valueField",
69
+ "pmql",
70
+ "unique",
71
+ ];
72
+
73
+ export default {
74
+ props: ["value"],
75
+ components: {
76
+ MustacheHelper,
77
+ ScreenVariableSelector,
78
+ },
79
+ data() {
80
+ return {
81
+ collections: [],
82
+ fields: [],
83
+ collectionId: null,
84
+ labelField: null,
85
+ valueField: null,
86
+ pmql: "",
87
+ unique: false,
88
+ };
89
+ },
90
+ watch: {
91
+ value: {
92
+ handler(value) {
93
+ if (!value) {
94
+ return;
95
+ }
96
+ CONFIG_FIELDS.forEach(field => this[field] = value[field]);
97
+ },
98
+ immediate: true
99
+ },
100
+ collectionId: {
101
+ handler() {
102
+ this.getFields();
103
+ }
104
+ },
105
+ options: {
106
+ handler() {
107
+ this.$emit("input", this.options);
108
+ },
109
+ deep: true
110
+ }
111
+ },
112
+ computed: {
113
+ options() {
114
+ return Object.fromEntries(CONFIG_FIELDS.map(field => [field, this[field]]));
115
+ }
116
+ },
117
+ methods: {
118
+ resetFields() {
119
+ this.labelField = null;
120
+ this.valueField = null;
121
+ },
122
+ getCollections() {
123
+ this.$dataProvider.getCollections().then((response) => {
124
+ this.collections = [
125
+ { value: null, text: this.$t("Select a collection") },
126
+ ...response.data.data.map((collection) => {
127
+ return {
128
+ text: collection.name,
129
+ value: collection.id
130
+ };
131
+ })
132
+ ];
133
+ });
134
+ },
135
+ getFields() {
136
+ if (!this.collectionId) {
137
+ return;
138
+ }
139
+
140
+ this.$dataProvider
141
+ .getCollectionFields(this.collectionId)
142
+ .then((response) => {
143
+ this.fields = [
144
+ { value: null, text: this.$t("Select a field") },
145
+ { value: "id", text: this.$t("Collection Record ID") },
146
+ ...response.data.data.map((field) => {
147
+ return {
148
+ text: field.label,
149
+ value: field.field
150
+ };
151
+ })
152
+ ];
153
+ });
154
+ }
155
+ },
156
+ mounted() {
157
+ this.getCollections();
158
+ if (this.collectionId) {
159
+ this.getFields();
160
+ }
161
+ }
162
+ };
163
+ </script>
@@ -2,6 +2,7 @@ export const dataSources = [
2
2
  { value: 'provideData', text: 'Provide Values' },
3
3
  { value: 'dataObject', text: 'Request Data' },
4
4
  { value: 'dataConnector', text: 'Data Connector' },
5
+ { value: 'collection', text: 'Collection' },
5
6
  ];
6
7
 
7
8
  export const dataSourceValues = dataSources.reduce((values, source) => {
@@ -129,6 +129,10 @@
129
129
  <b-form-input id="value" v-model="value" placeholder="Request Variable Property" @change="valueChanged" data-cy="inspector-options-label" />
130
130
  <small class="form-text text-muted mb-3">{{ $t('Enter the property name from the Request data variable that displays to the user on the screen.') }}</small>
131
131
  </div>
132
+
133
+ <div v-if="dataSource === dataSourceValues.collection">
134
+ <collection-select-list v-model="collectionOptions"></collection-select-list>
135
+ </div>
132
136
 
133
137
  <div v-if="showRenderAs">
134
138
  <div class="row mb-3">
@@ -181,9 +185,11 @@
181
185
  </button>
182
186
  </div>
183
187
 
184
- <label for="value-type-returned">{{ $t('Type of Value Returned') }}</label>
185
- <b-form-select id="value-type-returded" v-model="valueTypeReturned" :options="returnValueOptions" data-cy="inspector-value-returned" />
186
- <small class="form-text text-muted mb-3">{{ $t("Select 'Single Value' to use parts of the selected object. Select 'Object' to use the entire selected value.") }}</small>
188
+ <div v-if="showTypeOfValueReturned">
189
+ <label for="value-type-returned">{{ $t('Type of Value Returned') }}</label>
190
+ <b-form-select id="value-type-returded" v-model="valueTypeReturned" :options="returnValueOptions" data-cy="inspector-value-returned" />
191
+ <small class="form-text text-muted mb-3">{{ $t("Select 'Single Value' to use parts of the selected object. Select 'Object' to use the entire selected value.") }}</small>
192
+ </div>
187
193
 
188
194
  <div v-if="dataSource === dataSourceValues.dataConnector">
189
195
  <div v-if="valueTypeReturned === 'single'">
@@ -243,12 +249,14 @@ import { dataSources, dataSourceValues } from './data-source-types';
243
249
  import MonacoEditor from 'vue-monaco';
244
250
  import MustacheHelper from './mustache-helper';
245
251
  import _ from 'lodash';
252
+ import CollectionSelectList from './collection-select-list';
246
253
 
247
254
  export default {
248
255
  components: {
249
256
  draggable,
250
257
  MonacoEditor,
251
- MustacheHelper
258
+ MustacheHelper,
259
+ CollectionSelectList,
252
260
  },
253
261
  props: ['options', 'selectedControl'],
254
262
  model: {
@@ -266,6 +274,7 @@ export default {
266
274
  key: null,
267
275
  value: null,
268
276
  dataName: '',
277
+ collectionOptions: null,
269
278
  selectedDataSource: '',
270
279
  dataSourcesList: [],
271
280
  selectedEndPoint: '',
@@ -336,13 +345,22 @@ export default {
336
345
  case 'dataConnector':
337
346
  this.jsonData = '';
338
347
  this.dataName = '';
348
+ this.collectionOptions = null;
339
349
  this.getDataSourceList();
340
350
  break;
341
351
  case 'dataObject':
342
352
  this.jsonData = '';
343
353
  this.selectedDataSource = '';
354
+ this.collectionOptions = null;
344
355
  break;
345
356
  case 'provideData':
357
+ this.dataName = '';
358
+ this.selectedDataSource = '';
359
+ this.collectionOptions = null;
360
+ break;
361
+ case 'collection':
362
+ this.showRenderAs = false;
363
+ this.jsonData = '';
346
364
  this.dataName = '';
347
365
  this.selectedDataSource = '';
348
366
  break;
@@ -371,6 +389,9 @@ export default {
371
389
  },
372
390
  },
373
391
  computed: {
392
+ showTypeOfValueReturned() {
393
+ return this.dataSource !== dataSourceValues.collection
394
+ },
374
395
  endPointList() {
375
396
  return _.get(this.endpoints, this.selectedDataSource, []);
376
397
  },
@@ -413,6 +434,7 @@ export default {
413
434
  dataSource: this.dataSource,
414
435
  jsonData: this.jsonData,
415
436
  dataName: this.dataName,
437
+ collectionOptions: this.collectionOptions,
416
438
  selectedDataSource: this.selectedDataSource,
417
439
  selectedEndPoint: this.selectedEndPoint,
418
440
  key: this.key,
@@ -442,6 +464,7 @@ export default {
442
464
  this.dataSource = this.options.dataSource;
443
465
  this.jsonData = this.options.jsonData;
444
466
  this.dataName = this.options.dataName;
467
+ this.collectionOptions = this.options.collectionOptions;
445
468
  this.selectedDataSource = this.options.selectedDataSource,
446
469
  this.selectedEndPoint = this.options.selectedEndPoint,
447
470
  this.key = this.options.key;
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <form-multi-select
3
+ :name="$t('Variable to Watch')"
4
+ :label="$t('Variable to Watch') + ' *'"
5
+ :options="variables"
6
+ :taggable="true"
7
+ v-model="selectedVariable"
8
+ :placeholder="$t('None')"
9
+ :multiple="false"
10
+ :show-labels="false"
11
+ :internal-search="true"
12
+ :validation="validation"
13
+ :helper="helper"
14
+ @open="loadVariables"
15
+ @tag="addTag"
16
+ :tag-placeholder="$t('Press enter to use this variable')"
17
+ :data-cy="dataCy"
18
+ />
19
+ </template>
20
+
21
+
22
+ <script>
23
+
24
+ import {
25
+ FormMultiSelect,
26
+ } from '@processmaker/vue-form-elements';
27
+
28
+ export default {
29
+ props: ["name", "label", "value", "helper", "validation", "dataCy"],
30
+ components: { FormMultiSelect },
31
+ data() {
32
+ return {
33
+ variables:[],
34
+ newTags:[],
35
+ };
36
+ },
37
+ computed: {
38
+ selectedVariable: {
39
+ get() {
40
+ return this.value;
41
+ },
42
+ set(value) {
43
+ this.$emit('input', value);
44
+ }
45
+ }
46
+ },
47
+ methods: {
48
+ addTag(tag) {
49
+ this.newTags.push(tag);
50
+ this.selectedVariable = tag;
51
+ this.variables = this.newTags.concat(this.variables);
52
+ },
53
+ loadVariables() {
54
+ this.variables = [];
55
+ //Search in all config screen
56
+ this.findElements(this.$root.$children[0].config);
57
+ this.variables = this.newTags.concat(this.variables);
58
+ if (this.selectedVariable && !this.variables.includes(this.selectedVariable)) {
59
+ this.variables.unshift(this.selectedVariable);
60
+ }
61
+ },
62
+ findElements(items, screens=[]) {
63
+ items.forEach(item => {
64
+ //If the element has containers (Multi-columns)
65
+ if (Array.isArray(item)) {
66
+ this.findElements(item);
67
+ }
68
+
69
+ //If the element has items
70
+ if (item.items) {
71
+ this.findElements(item.items);
72
+ }
73
+
74
+ //If the element has configuration only
75
+ if (item.config && item.config.name) {
76
+ this.variables.push(item.config.name);
77
+ }
78
+
79
+ // Variables from Nested screens
80
+ if (item.component === 'FormNestedScreen') {
81
+ this.loadVariablesFromScreen(item.config.screen, screens);
82
+ }
83
+ });
84
+ },
85
+ loadVariablesFromScreen(id, screens) {
86
+ if (screens.indexOf(id) === -1) {
87
+ screens.push(id);
88
+ if (id) {
89
+ this.$dataProvider.getScreen(id)
90
+ .then(response => {
91
+ this.findElements(response.data.config);
92
+ });
93
+ }
94
+ }
95
+ },
96
+ }
97
+ };
98
+ </script>
@@ -702,6 +702,7 @@ export default {
702
702
  },
703
703
  updateState() {
704
704
  this.$store.dispatch('undoRedoModule/pushState', {'config': JSON.stringify(this.config), 'currentPage': this.currentPage});
705
+ window.ProcessMaker.EventBus.$emit('screen-change');
705
706
  },
706
707
  undo() {
707
708
  this.inspect();
@@ -24,21 +24,12 @@
24
24
  aria-required="true"
25
25
  />
26
26
 
27
- <form-multi-select
27
+ <screen-variable-selector
28
28
  :name="$t('Variable to Watch')"
29
29
  :label="$t('Variable to Watch') + ' *'"
30
- :options="variables"
31
- :taggable="true"
32
30
  v-model="config.watching"
33
- :placeholder="$t('None')"
34
- :multiple="false"
35
- :show-labels="false"
36
- :internal-search="true"
37
31
  :validation="ruleWatcherVariable"
38
32
  :helper="$t('Select the variable to watch on this screen or type any request variable name')"
39
- @open="loadVariables"
40
- @tag="addTag"
41
- :tag-placeholder="$t('Press enter to use this variable')"
42
33
  data-cy="watchers-watcher-variable"
43
34
  ref="watching"
44
35
  />
@@ -267,6 +258,7 @@ import MonacoEditor from 'vue-monaco';
267
258
  import DataMapping from './inspector/data-mapping';
268
259
  import OutboundConfig from './inspector/outbound-config';
269
260
  import FocusErrors from '../mixins/focusErrors';
261
+ import ScreenVariableSelector from './screen-variable-selector'
270
262
 
271
263
  import _ from 'lodash';
272
264
 
@@ -284,6 +276,7 @@ export default {
284
276
  MonacoEditor,
285
277
  DataMapping,
286
278
  OutboundConfig,
279
+ ScreenVariableSelector,
287
280
  },
288
281
  props: {
289
282
  config: {
@@ -318,8 +311,6 @@ export default {
318
311
  required: true,
319
312
  inputDataInvalid: false,
320
313
  scriptConfigurationInvalid: false,
321
- variables:[],
322
- newTags:[],
323
314
  scripts:[],
324
315
  script: null,
325
316
  monacoOptions: {
@@ -502,54 +493,6 @@ export default {
502
493
  });
503
494
  }
504
495
  },
505
- addTag(tag) {
506
- this.newTags.push(tag);
507
- this.config.watching = tag;
508
- this.variables = this.newTags.concat(this.variables);
509
- },
510
- loadVariables() {
511
- this.variables = [];
512
- //Search in all config screen
513
- this.findElements(this.$root.$children[0].config);
514
- this.variables = this.newTags.concat(this.variables);
515
- if (this.config.watching && !this.variables.includes(this.config.watching)) {
516
- this.variables.unshift(this.config.watching);
517
- }
518
- },
519
- findElements(items, screens=[]) {
520
- items.forEach(item => {
521
- //If the element has containers (Multi-columns)
522
- if (Array.isArray(item)) {
523
- this.findElements(item);
524
- }
525
-
526
- //If the element has items
527
- if (item.items) {
528
- this.findElements(item.items);
529
- }
530
-
531
- //If the element has configuration only
532
- if (item.config && item.config.name) {
533
- this.variables.push(item.config.name);
534
- }
535
-
536
- // Variables from Nested screens
537
- if (item.component === 'FormNestedScreen') {
538
- this.loadVariablesFromScreen(item.config.screen, screens);
539
- }
540
- });
541
- },
542
- loadVariablesFromScreen(id, screens) {
543
- if (screens.indexOf(id) === -1) {
544
- screens.push(id);
545
- if (id) {
546
- this.$dataProvider.getScreen(id)
547
- .then(response => {
548
- this.findElements(response.data.config);
549
- });
550
- }
551
- }
552
- },
553
496
  loadSources() {
554
497
  this.scripts = [];
555
498
  //call load data