@processmaker/screen-builder 2.94.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.94.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">
@@ -124,6 +125,7 @@ export default {
124
125
  loadingButton: false,
125
126
  loadingTask: false,
126
127
  loadingListeners: this.waitLoadingListeners,
128
+ isSelfService: false,
127
129
  };
128
130
  },
129
131
  watch: {
@@ -359,12 +361,12 @@ export default {
359
361
  }
360
362
  this.prepareTask();
361
363
  },
362
- disableForSelfService() {
364
+ setSelfService() {
363
365
  this.$nextTick(() => {
364
366
  if (window.ProcessMaker.isSelfService) {
365
- this.disabled = true;
367
+ this.isSelfService = true;
366
368
  } else {
367
- this.disabled = false;
369
+ this.isSelfService = false;
368
370
  }
369
371
  });
370
372
  },
@@ -455,6 +457,8 @@ export default {
455
457
 
456
458
  const elementDestinationUrl = elementDestination.value;
457
459
  if (elementDestinationUrl) {
460
+ // Save the referring URL to sessionStorage for future verification
461
+ sessionStorage.setItem('sessionUrlActionBlocker', document.referrer);
458
462
  return elementDestinationUrl;
459
463
  }
460
464
 
@@ -488,8 +492,8 @@ export default {
488
492
  this.emitIfTaskCompleted(requestId);
489
493
  }
490
494
  this.taskId = task.id;
491
- this.loadTask();
492
495
  this.nodeId = task.element_id;
496
+ this.loadTask();
493
497
  } else if (this.parentRequest && ['COMPLETED', 'CLOSED'].includes(this.task.process_request.status)) {
494
498
  this.$emit('completed', this.getAllowedRequestId());
495
499
  } else if (!this.taskPreview) {
@@ -543,10 +547,14 @@ export default {
543
547
  this.task.interstitial_screen['_interstitial'] = true;
544
548
  this.screen = this.task.interstitial_screen;
545
549
  }
550
+ if (this.task.bpmn_tag_name === 'manualTask') {
551
+ this.checkTaskStatus();
552
+ this.reload();
553
+ }
546
554
  },
547
555
  onUpdate(data) {
548
556
  this.$emit('input', data);
549
- this.disableForSelfService();
557
+ this.setSelfService();
550
558
  },
551
559
  activityAssigned() {
552
560
  // This may no longer be needed
@@ -688,10 +696,10 @@ export default {
688
696
  },
689
697
  processUpdated: _.debounce(function(data) {
690
698
  if (
691
- data.event === "ACTIVITY_ACTIVATED"
699
+ ['ACTIVITY_ACTIVATED', 'ACTIVITY_COMPLETED'].includes(data.event)
692
700
  && data.elementType === 'task'
693
701
  ) {
694
- if (!this.task.elementDestination?.type) {
702
+ if (!this.task?.elementDestination?.type) {
695
703
  this.taskId = data.taskId;
696
704
  }
697
705
 
@@ -797,6 +805,30 @@ export default {
797
805
  requestIdNode.setAttribute('content', this.requestId);
798
806
  }
799
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
+ },
800
832
 
801
833
  },
802
834
  mounted() {
@@ -807,7 +839,9 @@ export default {
807
839
  this.nodeId = this.initialNodeId;
808
840
  this.requestData = this.value;
809
841
  this.loopContext = this.initialLoopContext;
810
- this.loadTask();
842
+ if (!this.hasUrlActionBlocker()) {
843
+ this.loadTask();
844
+ }
811
845
  },
812
846
  destroyed() {
813
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,