@processmaker/screen-builder 2.99.2 → 3.0.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.
Files changed (48) hide show
  1. package/dist/vue-form-builder.css +1 -1
  2. package/dist/vue-form-builder.es.js +9092 -7133
  3. package/dist/vue-form-builder.es.js.map +1 -1
  4. package/dist/vue-form-builder.umd.js +53 -53
  5. package/dist/vue-form-builder.umd.js.map +1 -1
  6. package/package.json +2 -1
  7. package/src/App.vue +14 -2
  8. package/src/DataProvider.js +42 -1
  9. package/src/VariableDataTypeProperties.js +1 -1
  10. package/src/components/ClipboardButton.vue +77 -0
  11. package/src/components/CssIcon.vue +21 -0
  12. package/src/components/ScreenTemplateCard.vue +257 -0
  13. package/src/components/ScreenTemplates.vue +216 -0
  14. package/src/components/ScreenToolbar.vue +24 -2
  15. package/src/components/SelectUserGroup.vue +274 -0
  16. package/src/components/TabsBar.vue +47 -1
  17. package/src/components/accordions.js +7 -1
  18. package/src/components/editor/loop.vue +22 -1
  19. package/src/components/editor/multi-column.vue +22 -2
  20. package/src/components/editor/pagesDropdown.vue +20 -2
  21. package/src/components/index.js +7 -1
  22. package/src/components/inspector/collection-data-source.vue +200 -0
  23. package/src/components/inspector/collection-display-mode.vue +87 -0
  24. package/src/components/inspector/collection-records-list.vue +156 -0
  25. package/src/components/inspector/column-setup.vue +123 -7
  26. package/src/components/inspector/encrypted-config.vue +78 -0
  27. package/src/components/inspector/index.js +4 -0
  28. package/src/components/inspector/page-select.vue +1 -0
  29. package/src/components/renderer/file-upload.vue +136 -3
  30. package/src/components/renderer/form-collection-record-control.vue +248 -0
  31. package/src/components/renderer/form-collection-view-control.vue +236 -0
  32. package/src/components/renderer/form-masked-input.vue +194 -9
  33. package/src/components/renderer/form-record-list.vue +271 -69
  34. package/src/components/renderer/index.js +2 -0
  35. package/src/components/screen-renderer.vue +2 -0
  36. package/src/components/task.vue +3 -1
  37. package/src/components/vue-form-builder.vue +156 -22
  38. package/src/components/vue-form-renderer.vue +10 -2
  39. package/src/form-builder-controls.js +168 -21
  40. package/src/global-properties.js +8 -0
  41. package/src/main.js +60 -1
  42. package/src/mixins/Clipboard.js +153 -0
  43. package/src/mixins/ScreenBase.js +7 -1
  44. package/src/mixins/index.js +1 -0
  45. package/src/store/modules/ClipboardManager.js +79 -0
  46. package/src/store/modules/clipboardModule.js +210 -0
  47. package/src/stories/ClipboardButton.stories.js +66 -0
  48. package/src/stories/PagesDropdown.stories.js +11 -8
@@ -15,70 +15,98 @@
15
15
  </button>
16
16
  </div>
17
17
  </div>
18
- <div v-if="!value">
18
+ <div v-if="!value && !tableData.data">
19
19
  {{ $t("This record list is empty or contains no data.") }}
20
20
  </div>
21
21
  <template v-else>
22
- <b-table
23
- ref="vuetable"
24
- :per-page="perPage"
25
- :data-manager="dataManager"
26
- :fields="tableFields"
27
- :items="tableData.data"
28
- :sort-compare-options="{ numeric: false }"
29
- :sort-null-last="true"
30
- sort-icon-left
31
- :css="css"
32
- :empty-text="$t('No Data Available')"
33
- :current-page="currentPage"
34
- data-cy="table"
35
- >
36
- <template #cell()="{ index, field, item }">
37
- <template v-if="isFiledownload(field, item)">
38
- <span href="#" @click="downloadFile(item, field.key, index)">{{
39
- mustache(field.key, item)
40
- }}</span>
41
- </template>
42
- <template v-else-if="isImage(field, item)">
43
- <img :src="mustache(field.key, item)" style="record-list-image" />
22
+ <b-table
23
+ ref="vuetable"
24
+ :per-page="perPage"
25
+ :data-manager="dataManager"
26
+ :fields="tableFields"
27
+ :items="tableData.data"
28
+ :sort-compare-options="{ numeric: false }"
29
+ :sort-null-last="true"
30
+ sort-icon-left
31
+ :css="css"
32
+ :empty-text="$t('No Data Available')"
33
+ :current-page="currentPage"
34
+ data-cy="table"
35
+ >
36
+ <!-- Slot header for checkbox (Select All) -->
37
+ <template #head(checkbox)="data">
38
+ <b-form-checkbox
39
+ v-model="allRowsSelected"
40
+ @change="selectAllRows"
41
+ :indeterminate="indeterminate"
42
+ aria-label="Select All"
43
+ />
44
44
  </template>
45
- <template v-else-if="isWebEntryFile(field, item)">
46
- {{ formatIfWebEntryFile(field, item) }}
45
+
46
+ <template #cell(checkbox)="{ index, item }">
47
+ <b-form-checkbox
48
+ v-model="selectedRows"
49
+ :value="item"
50
+ @change="onMultipleSelectionChange(index)"
51
+ />
47
52
  </template>
48
- <template v-else>
49
- {{ formatIfDate(mustache(field.key, item)) }}
53
+
54
+ <template #cell(radio)="{ index, item }">
55
+ <b-form-radio
56
+ v-model="selectedRow"
57
+ :value="item"
58
+ @change="onRadioChange(item, index)"
59
+
60
+ />
50
61
  </template>
51
62
 
52
- </template>
53
- <template #cell(__actions)="{ index, item }">
54
- <div class="actions">
55
- <div
56
- class="btn-group btn-group-sm"
57
- role="group"
58
- aria-label="Actions"
59
- >
60
- <button
61
- class="btn btn-primary"
62
- :title="$t('Edit')"
63
- data-cy="edit-row"
64
- @click="showEditForm(index, item.row_id)"
65
- >
66
- <i class="fas fa-edit" />
67
- </button>
68
- <button
69
- class="btn btn-danger"
70
- :title="$t('Delete')"
71
- data-cy="remove-row"
72
- @click="showDeleteConfirmation(index, item.row_id)"
63
+ <template #cell()="{ index, field, item }">
64
+
65
+ <template v-if="isFiledownload(field, item)">
66
+ <span href="#" @click="downloadFile(item, field.key, index)">{{
67
+ mustache(field.key, item)
68
+ }}</span>
69
+ </template>
70
+ <template v-else-if="isImage(field, item)">
71
+ <img :src="mustache(field.key, item)" style="record-list-image" />
72
+ </template>
73
+ <template v-else-if="isWebEntryFile(field, item)">
74
+ {{ formatIfWebEntryFile(field, item) }}
75
+ </template>
76
+ <template v-else>
77
+ {{ formatIfDate(mustache(field.key, item)) }}
78
+ </template>
79
+
80
+ </template>
81
+ <template #cell(__actions)="{ index, item }">
82
+ <div class="actions">
83
+ <div
84
+ class="btn-group btn-group-sm"
85
+ role="group"
86
+ aria-label="Actions"
73
87
  >
74
- <i class="fas fa-trash-alt" />
75
- </button>
88
+ <button
89
+ class="btn btn-primary"
90
+ :title="$t('Edit')"
91
+ data-cy="edit-row"
92
+ @click="showEditForm(index, item.row_id)"
93
+ >
94
+ <i class="fas fa-edit" />
95
+ </button>
96
+ <button
97
+ class="btn btn-danger"
98
+ :title="$t('Delete')"
99
+ data-cy="remove-row"
100
+ @click="showDeleteConfirmation(index, item.row_id)"
101
+ >
102
+ <i class="fas fa-trash-alt" />
103
+ </button>
104
+ </div>
76
105
  </div>
77
- </div>
78
- </template>
79
- </b-table>
106
+ </template>
107
+ </b-table>
80
108
  <b-pagination
81
- v-if="tableData.total > perPage"
109
+ v-if="tableData.total > perPage && (perPage !== 0)"
82
110
  v-model="currentPage"
83
111
  data-cy="table-pagination"
84
112
  :total-rows="tableData.total"
@@ -211,7 +239,9 @@ export default {
211
239
  "formConfig",
212
240
  "formComputed",
213
241
  "formWatchers",
214
- "_perPage"
242
+ "_perPage",
243
+ "source",
244
+ "paginationOption"
215
245
  ],
216
246
  data() {
217
247
  return {
@@ -242,10 +272,19 @@ export default {
242
272
  }
243
273
  },
244
274
  initFormValues: {},
245
- currentRowIndex: null
275
+ currentRowIndex: null,
276
+ collectionData: {},
277
+ selectedRow: null,
278
+ selectedRows: [],
279
+ selectedIndex: null,
280
+ rows: [],
281
+ selectAll: false
246
282
  };
247
283
  },
248
284
  computed: {
285
+ indeterminate() {
286
+ return this.selectedRows.length > 0 && this.selectedRows.length < this.tableData.data.length;
287
+ },
249
288
  popupConfig() {
250
289
  const config = [];
251
290
  config[this.form] = this.formConfig[this.form];
@@ -279,7 +318,14 @@ export default {
279
318
  console.log("refs vuetable not exists");
280
319
  },
281
320
  tableData() {
282
- const value = this.value || [];
321
+ const value = Array.isArray(this.collectionData) && this.collectionData.length
322
+ ? this.collectionData
323
+ : (Array.isArray(this.value) ? this.value : []);
324
+
325
+ if(this.value) {
326
+ this.selectedIndex = this.value.selectedRowIndex;
327
+ }
328
+
283
329
  const from = this.paginatorPage - 1;
284
330
  // eslint-disable-next-line vue/no-side-effects-in-computed-properties
285
331
  this.lastPage = Math.ceil(value.length / this.perPage);
@@ -296,7 +342,23 @@ export default {
296
342
  data: value,
297
343
  lastSortConfig: false
298
344
  };
299
- return data;
345
+
346
+ // Enable Radio button selected when process finishes
347
+ if (this.selectedIndex !== null && this.selectedIndex < data.data.length) {
348
+ this.selectedRow = data.data[this.selectedIndex];
349
+ }
350
+
351
+ //Enable Checkbox selected when process finishes
352
+ if (Array.isArray(this.value) && this.value.length > 0) {
353
+ if(this.rows.length === 0) {
354
+ this.value.forEach(item => {
355
+ if (item.hasOwnProperty('selectedRowsIndex')) {
356
+ this.selectedRows.push(data.data[item.selectedRowsIndex]);
357
+ }
358
+ });
359
+ }
360
+ }
361
+ return data;
300
362
  },
301
363
  // The fields used for our vue table
302
364
  tableFields() {
@@ -306,6 +368,23 @@ export default {
306
368
  fields.push(jsonOptionsActionsColumn);
307
369
  }
308
370
 
371
+ // Adds radio buttons or checkbox to the table depending selected option
372
+ if (['single-field', 'single-record'].includes(this.source?.dataSelectionOptions)) {
373
+ fields.unshift({
374
+ key: 'radio',
375
+ label: '',
376
+ sortable: false,
377
+ });
378
+ }
379
+
380
+ if (this.source?.dataSelectionOptions === 'multiple-records') {
381
+ fields.unshift({
382
+ key: 'checkbox',
383
+ label: '',
384
+ sortable: false
385
+ });
386
+ }
387
+
309
388
  return fields;
310
389
  },
311
390
  // Determines if the form used for add/edit is self referencing. If so, we should not show it
@@ -322,7 +401,7 @@ export default {
322
401
  this.currentPage > totalPages ? totalPages : this.currentPage;
323
402
  this.currentPage = this.currentPage == 0 ? 1 : this.currentPage;
324
403
  }
325
- }
404
+ },
326
405
  },
327
406
  mounted() {
328
407
  if (this._perPage) {
@@ -332,8 +411,121 @@ export default {
332
411
  this.updateRowDataNamePrefix,
333
412
  100
334
413
  );
414
+
415
+ if (this.paginationOption != null) {
416
+ this.perPage = this.paginationOption;
417
+ }
418
+
419
+ if(this.source?.sourceOptions === "Collection") {
420
+ this.onCollectionChange(this.source?.collectionFields?.collectionId, this.source?.collectionFields?.pmql);
421
+ }
422
+
423
+ this.$root.$emit("record-list-option", this.source?.sourceOptions);
335
424
  },
336
425
  methods: {
426
+ selectAllRows() {
427
+ if (this.allRowsSelected) {
428
+ const updatedRows = this.tableData.data.map((item, index) => {
429
+ return {
430
+ ...item,
431
+ selectedRowsIndex: index
432
+ };
433
+ });
434
+
435
+ this.selectedRows = updatedRows;
436
+ this.collectionData = updatedRows;
437
+ this.onMultipleSelectionChange();
438
+ } else {
439
+ this.selectedRows = [];
440
+ this.onMultipleSelectionChange();
441
+ }
442
+ },
443
+ componentOutput(data) {
444
+ this.$emit('input', data);
445
+ },
446
+ onRadioChange(selectedItem, index) {
447
+ const globalIndex = (this.currentPage - 1) * this.perPage + index;
448
+ if(this.source?.singleField) {
449
+ let valueOfColumn = selectedItem[this.source.singleField];
450
+ this.componentOutput(valueOfColumn);
451
+ } else {
452
+ selectedItem = { ...selectedItem, selectedRowIndex: globalIndex};
453
+ this.componentOutput(selectedItem);
454
+ }
455
+ },
456
+ onMultipleSelectionChange(selIndex) {
457
+ this.collectionData.forEach((item, index) => {
458
+ this.selectedRows.forEach((selectedItem) => {
459
+ // Compares both objects all keys and values
460
+ if (this.areObjectsEqual(selectedItem, item)) {
461
+ // Adds`selectedRowIndex` with index iteration
462
+ selectedItem.selectedRowsIndex = index;
463
+ }
464
+ });
465
+ });
466
+ this.componentOutput(this.selectedRows);
467
+ this.rows.push(selIndex);
468
+ },
469
+ areObjectsEqual(obj1, obj2) {
470
+ const keys1 = Object.keys(obj1);
471
+ const keys2 = Object.keys(obj2);
472
+
473
+ if (keys1.length !== keys2.length) return false;
474
+
475
+ return keys1.every(key => obj1[key] === obj2[key]);
476
+ },
477
+ onCollectionChange(collectionId,pmql) {
478
+ let param = {params:{pmql:pmql}};
479
+ let rowsCollection = [];
480
+ this.$dataProvider
481
+ .getCollectionRecordsList(collectionId, param)
482
+ .then((response) => {
483
+ rowsCollection = response.data;
484
+
485
+ this.changeCollectionColumns(rowsCollection,this.fields);
486
+ });
487
+
488
+ this.$emit('change', this.field);
489
+ },
490
+ changeCollectionColumns(collectionFieldsColumns,columnsSelected) {
491
+
492
+ const optionsList = columnsSelected.optionsList;
493
+
494
+ collectionFieldsColumns.forEach(column => {
495
+ let dataObject = column.data;
496
+ let newDataObject = {};
497
+
498
+ Object.keys(dataObject).forEach(dataKey => {
499
+ const matchingOption = optionsList.find(option => option.content === dataKey);
500
+
501
+ if (matchingOption) {
502
+ newDataObject[matchingOption.key] = dataObject[dataKey];
503
+ }
504
+ });
505
+
506
+ column.data = newDataObject;
507
+ });
508
+
509
+ this.setCollectionIntoList(collectionFieldsColumns);
510
+
511
+ },
512
+ setCollectionIntoList(arrayCollection) {
513
+ const result = [];
514
+ arrayCollection.forEach((row) => {
515
+ if (row.hasOwnProperty('data')) {
516
+ const dataObject = row.data;
517
+ const extracted = {};
518
+
519
+ for (const [key, value] of Object.entries(dataObject)) {
520
+ extracted[key] = value;
521
+ }
522
+
523
+ result.push(extracted);
524
+ }
525
+ });
526
+ //sets Collection result(columns and rows) into this.collectionData
527
+ this.collectionData = result;
528
+ },
337
529
  updateRowDataNamePrefix() {
338
530
  this.setUploadDataNamePrefix(this.currentRowIndex);
339
531
  },
@@ -377,21 +569,31 @@ export default {
377
569
  } else if (this.addItem) {
378
570
  rowId = this.addItem.row_id;
379
571
  }
380
-
381
572
  this.$root.$emit("set-upload-data-name", this, index, rowId);
382
573
  },
383
574
  getTableFieldsFromDataSource() {
384
575
  const { jsonData, key, value, dataName } = this.fields;
385
-
386
- const convertToVuetableFormat = (option) => {
387
- // let slot = '__filedownload';
388
- return {
389
- key: option[key || "value"],
390
- sortable: true,
391
- label: option[value || "content"],
392
- tdClass: "table-column"
576
+
577
+ let convertToVuetableFormat = {};
578
+ if(this.source?.sourceOptions === "Collection") {
579
+ convertToVuetableFormat = (option) => {
580
+ return {
581
+ key: option[key || "key"],
582
+ sortable: true,
583
+ label: option[key || "key"],
584
+ tdClass: "table-column"
585
+ };
393
586
  };
394
- };
587
+ } else {
588
+ convertToVuetableFormat = (option) => {
589
+ return {
590
+ key: option[key || "value"],
591
+ sortable: true,
592
+ label: option[value || "content"],
593
+ tdClass: "table-column"
594
+ };
595
+ };
596
+ }
395
597
 
396
598
  return this.getValidFieldData(jsonData, dataName).map(
397
599
  convertToVuetableFormat
@@ -19,3 +19,5 @@ export { default as FormAnalyticsChart } from "./form-analytics-chart.vue";
19
19
  export { default as FormRequests } from "./form-requests.vue";
20
20
  export { default as FormTasks } from "./form-tasks.vue";
21
21
  export { default as LinkButton } from "./link-button.vue";
22
+ export { default as FormCollectionRecordControl } from "./form-collection-record-control.vue";
23
+ export { default as FormCollectionViewControl } from "./form-collection-view-control.vue";
@@ -39,6 +39,7 @@
39
39
  :vdata="value"
40
40
  :_parent="_parent || value._parent"
41
41
  :_initial-page="currentPage"
42
+ :taskdraft="taskdraft"
42
43
  @after-submit="afterSubmit"
43
44
  @submit="submit"
44
45
  @asyncWatcherTriggered="onAsyncWatcherOn"
@@ -70,6 +71,7 @@ export default {
70
71
  type: String,
71
72
  default: ""
72
73
  },
74
+ taskdraft: Object
73
75
  },
74
76
  data() {
75
77
  return {
@@ -31,6 +31,7 @@
31
31
  :watchers="screen.watchers"
32
32
  :key="refreshScreen"
33
33
  :loop-context="loopContext"
34
+ :taskdraft="this.task"
34
35
  @update="onUpdate"
35
36
  @after-submit="afterSubmit"
36
37
  @submit="submit"
@@ -49,6 +50,7 @@
49
50
  :watchers="screen.watchers"
50
51
  :data="requestData"
51
52
  :type="screen.type"
53
+ @update="onUpdate"
52
54
  @after-submit="afterSubmit"
53
55
  @submit="submit"
54
56
  />
@@ -471,7 +473,6 @@ export default {
471
473
 
472
474
  return this.getSessionRedirectUrl();
473
475
  } catch (error) {
474
- console.error("Error in getDestinationUrl:", error);
475
476
  return null;
476
477
  }
477
478
  }
@@ -1001,6 +1002,7 @@ export default {
1001
1002
  this.requestData = this.value;
1002
1003
  this.loopContext = this.initialLoopContext;
1003
1004
  this.loadTask(true);
1005
+ this.setSelfService();
1004
1006
  },
1005
1007
  destroyed() {
1006
1008
  this.unsubscribeSocketListeners();