@processmaker/screen-builder 2.93.0 → 2.95.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.93.0",
3
+ "version": "2.95.0",
4
4
  "scripts": {
5
5
  "dev": "VITE_COVERAGE=true vite",
6
6
  "build": "vite build",
@@ -56,7 +56,7 @@
56
56
  "@fortawesome/fontawesome-free": "^5.6.1",
57
57
  "@originjs/vite-plugin-commonjs": "^1.0.3",
58
58
  "@panter/vue-i18next": "^0.15.2",
59
- "@processmaker/vue-form-elements": "0.58.0",
59
+ "@processmaker/vue-form-elements": "0.59.0",
60
60
  "@processmaker/vue-multiselect": "2.3.0",
61
61
  "@storybook/addon-essentials": "^7.6.13",
62
62
  "@storybook/addon-interactions": "^7.6.13",
@@ -115,7 +115,7 @@
115
115
  },
116
116
  "peerDependencies": {
117
117
  "@panter/vue-i18next": "^0.15.0",
118
- "@processmaker/vue-form-elements": "0.58.0",
118
+ "@processmaker/vue-form-elements": "0.59.0",
119
119
  "i18next": "^15.0.8",
120
120
  "vue": "^2.6.12",
121
121
  "vuex": "^3.1.1"
@@ -199,7 +199,7 @@ export default {
199
199
  !window.ProcessMaker.screen.cacheEnabled &&
200
200
  !window.ProcessMaker.screen.cacheTimeout
201
201
  ) {
202
- return this.postDataSource(dataSourceId, null, params);
202
+ return this.postDataSource(dataSourceId, null, params).then(r => [r, nonce]);
203
203
  }
204
204
  let url = `/requests/data_sources/${dataSourceId}/resources/${params.config.endpoint}/data`;
205
205
  url += this.authQueryString();
@@ -240,6 +240,10 @@ class PageNavigateValidations extends Validations {
240
240
  */
241
241
  class FormElementValidations extends Validations {
242
242
  async addValidations(validations) {
243
+ // Disable validations if field is hidden
244
+ if (!this.isVisible()) {
245
+ return;
246
+ }
243
247
  if (this.element.config && this.element.config.readonly) {
244
248
  //readonly elements do not need validation
245
249
  return;
@@ -10,11 +10,7 @@
10
10
  {{ $t(title) }}
11
11
  </p>
12
12
  <template v-if="dataControl.dropdownShow === 'requests'">
13
- <b-dropdown
14
- variant="outline-secondary"
15
- offset="-70"
16
- no-caret
17
- >
13
+ <b-dropdown variant="outline-secondary" offset="-70" no-caret>
18
14
  <template #button-content>
19
15
  <i class="fas fa-caret-down" />
20
16
  </template>
@@ -26,7 +22,9 @@
26
22
  </span>
27
23
  </b-dropdown-item>
28
24
  <b-dropdown-item
29
- @click="handleDropdownSelection('requests_filter', 'as_participant')"
25
+ @click="
26
+ handleDropdownSelection('requests_filter', 'as_participant')
27
+ "
30
28
  >
31
29
  <span class="item-text">
32
30
  {{ $t("As Participant") }}
@@ -42,11 +40,7 @@
42
40
  <div class="ml-auto d-flex align-items-center">
43
41
  <template v-if="dataControl.dropdownShow === 'requests'">
44
42
  <div class="mr-4">
45
- <b-dropdown
46
- variant="outline-secondary"
47
- offset="-50"
48
- size="sm"
49
- >
43
+ <b-dropdown variant="outline-secondary" offset="-50" size="sm">
50
44
  <template #button-content>
51
45
  <span class="text-capitalize">
52
46
  {{ $t(titleDropdown) }}
@@ -66,11 +60,7 @@
66
60
  </template>
67
61
  <template v-if="dataControl.dropdownShow === 'tasks'">
68
62
  <div class="mr-4">
69
- <b-dropdown
70
- variant="outline-secondary"
71
- offset="-50"
72
- size="sm"
73
- >
63
+ <b-dropdown variant="outline-secondary" offset="-50" size="sm">
74
64
  <template #button-content>
75
65
  <span class="text-capitalize">
76
66
  {{ $t(titleDropdown) }}
@@ -82,7 +72,7 @@
82
72
  @click="handleDropdownSelection('tasks', option)"
83
73
  >
84
74
  <span class="item-text">
85
- {{ $t(option) }}
75
+ {{ $t(option) }}
86
76
  </span>
87
77
  </b-dropdown-item>
88
78
  </b-dropdown>
@@ -122,7 +112,6 @@
122
112
  </div>
123
113
  <div class="card-body list-table">
124
114
  <template v-if="listOption === 'My Tasks'">
125
- <Recommendations :dashboard="true" />
126
115
  <FormTasks @tasksCount="getData"></FormTasks>
127
116
  </template>
128
117
  <template v-if="verifyListCase()">
@@ -140,12 +129,8 @@ import FormTasks from "./form-tasks.vue";
140
129
  import FormRequests from "./form-requests.vue";
141
130
  import FormNewRequest from "./form-new-request.vue";
142
131
 
143
- const Recommendations = (resolve) => {
144
- resolve(window.SharedComponents?.Recommendations || { template: "<span></span>" });
145
- };
146
-
147
132
  export default {
148
- components: { FormTasks, FormRequests, FormNewRequest, Recommendations },
133
+ components: { FormTasks, FormRequests, FormNewRequest },
149
134
  mixins: [],
150
135
  props: ["listOption"],
151
136
  data() {
@@ -170,11 +155,7 @@ export default {
170
155
  "Overdue",
171
156
  "View All"
172
157
  ],
173
- requestFilterDropdown: [
174
- "View All",
175
- "Completed",
176
- "In Progress",
177
- ]
158
+ requestFilterDropdown: ["View All", "Completed", "In Progress"]
178
159
  };
179
160
  },
180
161
  watch: {
@@ -331,8 +312,8 @@ export default {
331
312
  }
332
313
 
333
314
  .item-text {
334
- color: #42526E;
335
- font-family: 'Open Sans', sans-serif;
315
+ color: #42526e;
316
+ font-family: "Open Sans", sans-serif;
336
317
  font-size: 14px;
337
318
  font-weight: 400;
338
319
  line-height: 21px;
@@ -343,13 +324,13 @@ export default {
343
324
  .dropdown-menu {
344
325
  padding: 0px;
345
326
  width: 180px;
346
- box-shadow: 0px 4px 8px 0px #0000001A;
327
+ box-shadow: 0px 4px 8px 0px #0000001a;
347
328
  border-radius: 4px;
348
329
  }
349
330
 
350
331
  .dropdown-item {
351
332
  padding: 13px 12px;
352
- font-family: 'Open Sans', sans-serif;
333
+ font-family: "Open Sans", sans-serif;
353
334
  font-size: 16px;
354
335
  font-weight: 400;
355
336
  line-height: 21.79px;
@@ -361,10 +342,10 @@ export default {
361
342
  .btn-outline-secondary:not(:disabled):not(.disabled):active,
362
343
  .btn-outline-secondary:not(:disabled):not(.disabled).active,
363
344
  .show > .btn-outline-secondary.dropdown-toggle {
364
- background: none;
365
- color: #228fed;
366
- border: none;
367
- box-shadow: none;
345
+ background: none;
346
+ color: #228fed;
347
+ border: none;
348
+ box-shadow: none;
368
349
  }
369
350
 
370
351
  .head-filter {
@@ -11,6 +11,9 @@
11
11
  <td
12
12
  v-for="(header, colIndex) in tableHeaders"
13
13
  :key="`${rowIndex}-${colIndex}`"
14
+ :class="{
15
+ 'pm-table-filter-applied-tbody': header.sortAsc || header.sortDesc
16
+ }"
14
17
  >
15
18
  <template v-if="containsHTML(getNestedPropertyValue(row, header))">
16
19
  <div
@@ -24,6 +27,10 @@
24
27
  v-if="header.truncate"
25
28
  :target="`element-${rowIndex}-${colIndex}`"
26
29
  custom-class="pm-table-tooltip"
30
+ placement="topright"
31
+ trigger="hover"
32
+ boundary="viewport"
33
+ :delay="{ show: 0, hide: 0 }"
27
34
  @show="checkIfTooltipIsNeeded"
28
35
  >
29
36
  {{ sanitizeTooltip(getNestedPropertyValue(row, header)) }}
@@ -47,6 +54,10 @@
47
54
  v-if="header.truncate"
48
55
  :target="`element-${rowIndex}-${colIndex}`"
49
56
  custom-class="pm-table-tooltip"
57
+ placement="topright"
58
+ trigger="hover"
59
+ boundary="viewport"
60
+ :delay="{ show: 0, hide: 0 }"
50
61
  @show="checkIfTooltipIsNeeded"
51
62
  >
52
63
  {{ getNestedPropertyValue(row, header) }}
@@ -91,7 +102,7 @@ export default {
91
102
  direction: "desc"
92
103
  }
93
104
  ],
94
- tableHeaders: [],
105
+ tableHeaders: []
95
106
  };
96
107
  },
97
108
  computed: {
@@ -210,8 +221,9 @@ export default {
210
221
  if (option === "case_title") {
211
222
  attr[option] = value.case_title_formatted || value.case_title || "";
212
223
  }
213
- return `<a href="${this.openRequest(value)}" class="text-nowrap"
214
- target="_blank">${attr[option]}</a>`;
224
+ return `
225
+ <a href="${this.openRequest(value)}" class="text-nowrap custom-wrap"
226
+ target="_blank">${attr[option]}</a>`;
215
227
  },
216
228
  openRequest(data) {
217
229
  return `/requests/${data.id}`;
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <div v-if="showTable">
3
+ <Recommendations :dashboard="true" />
3
4
  <filter-table
4
5
  table-name="form-tasks"
5
6
  :headers="tableHeaders"
@@ -137,8 +138,15 @@ import datatableMixin from "../../mixins/datatable";
137
138
  import formEmpty from "./form-empty-table.vue";
138
139
 
139
140
  const uniqIdsMixin = createUniqIdsMixin();
141
+
142
+ const Recommendations = (resolve) => {
143
+ resolve(
144
+ window.SharedComponents?.Recommendations || { template: "<span></span>" }
145
+ );
146
+ };
147
+
140
148
  export default {
141
- components: { formEmpty },
149
+ components: { formEmpty, Recommendations },
142
150
  mixins: [uniqIdsMixin, datatableMixin],
143
151
  data() {
144
152
  return {
@@ -162,10 +170,8 @@ export default {
162
170
  }
163
171
  ],
164
172
  advancedFilter: "",
165
- tasksPreview:
166
- (window.SharedComponents && window.SharedComponents.TasksHome) || {},
167
- taskTooltip:
168
- (window.SharedComponents && window.SharedComponents.TaskTooltip) || {},
173
+ tasksPreview: window.SharedComponents?.TasksHome || {},
174
+ taskTooltip: window.SharedComponents?.TaskTooltip || {},
169
175
  rowPosition: {},
170
176
  ellipsisShow: false,
171
177
  isTooltipVisible: false,
@@ -568,7 +574,11 @@ export default {
568
574
 
569
575
  const rightBorderX = rect.right;
570
576
 
571
- const bottomBorderY = yPosition - topAdjust - elementHeight + 100;
577
+ let bottomBorderY = yPosition - topAdjust - elementHeight + 100;
578
+
579
+ if (document.getElementsByClassName("recommendation").length > 0) {
580
+ bottomBorderY += 60;
581
+ }
572
582
 
573
583
  this.rowPosition = {
574
584
  x: rightBorderX,
@@ -37,7 +37,7 @@
37
37
  :is="component"
38
38
  ref="component"
39
39
  :vdata="value"
40
- :_parent="_parent"
40
+ :_parent="_parent || value._parent"
41
41
  :_initial-page="currentPage"
42
42
  @after-submit="afterSubmit"
43
43
  @submit="submit"
@@ -7,15 +7,16 @@
7
7
  >
8
8
  <template v-if="screen">
9
9
  <b-overlay
10
- :show="disabled"
10
+ :show="disabled || isSelfService"
11
11
  id="overlay-background"
12
- variant="white"
12
+ :variant="isSelfService ? 'white' : 'transparent'"
13
+ :blur="null"
13
14
  cardStyles="pointer-events: none;pointer-events: none;inset: 1px"
14
15
  rounded="sm"
15
16
  >
16
17
  <template #overlay>
17
18
  <div class="text-center">
18
- <p>Please claim this task to continue.</p>
19
+ <p v-if="isSelfService">Please claim this task to continue.</p>
19
20
  </div>
20
21
  </template>
21
22
  <div class="card card-body border-top-0 h-100" :class="screenTypeClass">
@@ -102,6 +103,7 @@ export default {
102
103
  loading: { type: Number, default: null },
103
104
  alwaysAllowEditing: { type: Boolean, default: false },
104
105
  disableInterstitial: { type: Boolean, default: false },
106
+ waitLoadingListeners: { type: Boolean, default: false },
105
107
  },
106
108
  data() {
107
109
  return {
@@ -122,7 +124,8 @@ export default {
122
124
  redirecting: null,
123
125
  loadingButton: false,
124
126
  loadingTask: false,
125
- loadingListeners: true,
127
+ loadingListeners: this.waitLoadingListeners,
128
+ isSelfService: false,
126
129
  };
127
130
  },
128
131
  watch: {
@@ -258,6 +261,10 @@ export default {
258
261
  }
259
262
  },
260
263
  loadTask() {
264
+ if (!this.taskId) {
265
+ return;
266
+ }
267
+
261
268
  const url = `/${this.taskId}?include=data,user,draft,requestor,processRequest,component,screen,requestData,loopContext,bpmnTagName,interstitial,definition,nested,userRequestPermission,elementDestination`;
262
269
  // For Vocabularies
263
270
  if (window.ProcessMaker && window.ProcessMaker.packages && window.ProcessMaker.packages.includes('package-vocabularies')) {
@@ -354,12 +361,12 @@ export default {
354
361
  }
355
362
  this.prepareTask();
356
363
  },
357
- disableForSelfService() {
364
+ setSelfService() {
358
365
  this.$nextTick(() => {
359
366
  if (window.ProcessMaker.isSelfService) {
360
- this.disabled = true;
367
+ this.isSelfService = true;
361
368
  } else {
362
- this.disabled = false;
369
+ this.isSelfService = false;
363
370
  }
364
371
  });
365
372
  },
@@ -412,7 +419,7 @@ export default {
412
419
  * Emits a closed event.
413
420
  */
414
421
  async emitClosedEvent() {
415
- this.$emit("closed", this.task.id, await this.getDestinationUrl());
422
+ this.$emit("closed", this.task?.id, await this.getDestinationUrl());
416
423
  },
417
424
  /**
418
425
  * Retrieves the destination URL for the closed event.
@@ -450,6 +457,8 @@ export default {
450
457
 
451
458
  const elementDestinationUrl = elementDestination.value;
452
459
  if (elementDestinationUrl) {
460
+ // Save the referring URL to sessionStorage for future verification
461
+ sessionStorage.setItem('sessionUrlActionBlocker', document.referrer);
453
462
  return elementDestinationUrl;
454
463
  }
455
464
 
@@ -483,8 +492,8 @@ export default {
483
492
  this.emitIfTaskCompleted(requestId);
484
493
  }
485
494
  this.taskId = task.id;
486
- this.loadTask();
487
495
  this.nodeId = task.element_id;
496
+ this.loadTask();
488
497
  } else if (this.parentRequest && ['COMPLETED', 'CLOSED'].includes(this.task.process_request.status)) {
489
498
  this.$emit('completed', this.getAllowedRequestId());
490
499
  } else if (!this.taskPreview) {
@@ -538,10 +547,14 @@ export default {
538
547
  this.task.interstitial_screen['_interstitial'] = true;
539
548
  this.screen = this.task.interstitial_screen;
540
549
  }
550
+ if (this.task.bpmn_tag_name === 'manualTask') {
551
+ this.checkTaskStatus();
552
+ this.reload();
553
+ }
541
554
  },
542
555
  onUpdate(data) {
543
556
  this.$emit('input', data);
544
- this.disableForSelfService();
557
+ this.setSelfService();
545
558
  },
546
559
  activityAssigned() {
547
560
  // This may no longer be needed
@@ -683,10 +696,10 @@ export default {
683
696
  },
684
697
  processUpdated: _.debounce(function(data) {
685
698
  if (
686
- data.event === "ACTIVITY_ACTIVATED"
699
+ ['ACTIVITY_ACTIVATED', 'ACTIVITY_COMPLETED'].includes(data.event)
687
700
  && data.elementType === 'task'
688
701
  ) {
689
- if (!this.task.elementDestination?.type) {
702
+ if (!this.task?.elementDestination?.type) {
690
703
  this.taskId = data.taskId;
691
704
  }
692
705
 
@@ -792,6 +805,30 @@ export default {
792
805
  requestIdNode.setAttribute('content', this.requestId);
793
806
  }
794
807
  },
808
+ /**
809
+ * Checks for the presence of a URL action blocker in sessionStorage and handles it.
810
+ *
811
+ * This method retrieves the 'sessionUrlActionBlocker' value from sessionStorage,
812
+ * and if present, removes it and emits a 'closed' event with the task id and
813
+ * the source of the redirection. It returns false if the blocker was handled,
814
+ * and true otherwise.
815
+ *
816
+ * @returns {boolean} Returns false if the 'sessionUrlActionBlocker' was found and handled, true otherwise.
817
+ */
818
+ hasUrlActionBlocker() {
819
+ // Retrieve the 'sessionUrlActionBlocker' value from sessionStorage
820
+ const redirectedFrom = sessionStorage.getItem("sessionUrlActionBlocker");
821
+
822
+ if (redirectedFrom) {
823
+ // Remove 'sessionUrlActionBlocker' from sessionStorage after retrieving its value
824
+ sessionStorage.removeItem("sessionUrlActionBlocker");
825
+
826
+ // Emit a 'closed' event with the task id and the source of the redirection
827
+ this.$emit("closed", this.task?.id, redirectedFrom);
828
+ return true;
829
+ }
830
+ return false;
831
+ },
795
832
 
796
833
  },
797
834
  mounted() {
@@ -802,7 +839,9 @@ export default {
802
839
  this.nodeId = this.initialNodeId;
803
840
  this.requestData = this.value;
804
841
  this.loopContext = this.initialLoopContext;
805
- this.loadTask();
842
+ if (!this.hasUrlActionBlocker()) {
843
+ this.loadTask();
844
+ }
806
845
  },
807
846
  destroyed() {
808
847
  this.unsubscribeSocketListeners();
@@ -647,10 +647,13 @@ export default {
647
647
 
648
648
  const excludedLabels = [""];
649
649
 
650
+ let filter = this.filterQuery.toLowerCase();
650
651
  const filtered = this.controls.filter((control) => {
651
- return control.label
652
- .toLowerCase()
653
- .includes(this.filterQuery.toLowerCase());
652
+ let result = control.label.toLowerCase().includes(filter);
653
+ if (control.group.toLowerCase().includes(filter)) {
654
+ result = true;
655
+ }
656
+ return result;
654
657
  });
655
658
 
656
659
  return filtered;
@@ -10,7 +10,7 @@
10
10
  <screen-renderer
11
11
  ref="renderer"
12
12
  :value="data"
13
- :_parent="_parent"
13
+ :_parent="_parent || data._parent"
14
14
  :definition="definition"
15
15
  :current-page="currentPage"
16
16
  data-cy="screen-renderer"
package/src/main.js CHANGED
@@ -38,6 +38,17 @@ Vue.component("Required", {
38
38
  template: '<div class="text-right"><small>* = Required</small></div>'
39
39
  });
40
40
 
41
+ // Mock PmqlInput for test/standalone
42
+ Vue.component("PmqlInput", {
43
+ props: {
44
+ value: {
45
+ type: String,
46
+ default: ""
47
+ }
48
+ },
49
+ template: '<div>PMQL: {{ value }}</div>'
50
+ });
51
+
41
52
  const store = new Vuex.Store({
42
53
  modules: {
43
54
  globalErrorsModule,