@processmaker/screen-builder 2.84.2 → 2.85.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.84.2",
3
+ "version": "2.85.0",
4
4
  "scripts": {
5
5
  "dev": "VITE_COVERAGE=true vite",
6
6
  "build": "vite build",
@@ -35,8 +35,8 @@
35
35
  "axios-extensions": "^3.1.6",
36
36
  "lodash": "^4.17.21",
37
37
  "lru-cache": "^10.0.1",
38
- "moment": "^2.29.1",
39
- "moment-timezone": "^0.5.27",
38
+ "moment": "^2.30.1",
39
+ "moment-timezone": "^0.5.45",
40
40
  "monaco-editor": "^0.34.0",
41
41
  "scrollparent": "^2.0.1",
42
42
  "vue-loader": "^15.9.2",
@@ -8,4 +8,7 @@
8
8
  }
9
9
  .page-dropdown-menu {
10
10
  min-width: 333px;
11
+ max-height: 26rem;
12
+ overflow-y: auto;
13
+ scrollbar-width: thin;
11
14
  }
@@ -10,10 +10,12 @@
10
10
  /* Override Bootstrap default tab styles */
11
11
  .nav-tabs {
12
12
  border-bottom: 1px solid var(--tabs-border) !important;
13
+ }
14
+ .nav-tabs-nowrap {
13
15
  flex-wrap: nowrap !important;
14
16
  overflow: hidden !important;
15
17
  }
16
-
18
+
17
19
  .nav-tabs .nav-item .nav-link {
18
20
  display: flex;
19
21
  align-items: center;
@@ -4,6 +4,7 @@
4
4
  v-model="activeTab"
5
5
  class="h-100 w-100 flat-tabs"
6
6
  content-class="h-tab"
7
+ nav-class="nav-tabs-nowrap"
7
8
  lazy
8
9
  @changed="tabsUpdated"
9
10
  @input="tabOpened"
@@ -196,9 +197,10 @@ export default {
196
197
  }, visualThreshold);
197
198
  });
198
199
  },
199
- closeTab(pageId) {
200
- this.localOpenedPages.splice(this.localOpenedPages.indexOf(pageId), 1);
201
- this.$emit("tab-closed", this.pages[pageId], this.localOpenedPages);
200
+ closeTab(tabIndex) {
201
+ const pageIndex = this.localOpenedPages[tabIndex];
202
+ this.localOpenedPages.splice(tabIndex, 1);
203
+ this.$emit("tab-closed", this.pages[pageIndex], this.localOpenedPages);
202
204
  },
203
205
  updateTabsReferences(pageDelete) {
204
206
  this.localOpenedPages = this.localOpenedPages.map((page) =>
@@ -24,15 +24,16 @@
24
24
  <div class="rounded sortable-item-name">
25
25
  <b-form-input
26
26
  v-if="editRowIndex === index"
27
- v-model="item.name"
27
+ v-model="newName"
28
28
  type="text"
29
29
  autofocus
30
30
  required
31
- :state="validateState(item.name, item)"
32
- :error="validateError(item.name, item)"
33
- @blur.stop="onBlur(item.name, item)"
34
- @keydown.enter.stop="onBlur(item.name, item)"
35
- @focus="onFocus(item.name, item)"
31
+ :state="validateState(newName, item)"
32
+ :error="validateError(newName, item)"
33
+ @blur.stop="onBlur(newName, item)"
34
+ @keydown.enter.stop="onBlur(newName, item)"
35
+ @keydown.esc.stop="onCancel(item)"
36
+ @focus="onFocus(item)"
36
37
  />
37
38
  <span v-else>{{ item.name }}</span>
38
39
  </div>
@@ -63,7 +64,7 @@ export default {
63
64
  },
64
65
  data() {
65
66
  return {
66
- originalName: '',
67
+ newName: '',
67
68
  draggedItem: 0,
68
69
  draggedOverItem: 0,
69
70
  editRowIndex: null,
@@ -79,14 +80,14 @@ export default {
79
80
  },
80
81
  methods: {
81
82
  validateState(name, item) {
82
- const isEmpty = !name;
83
+ const isEmpty = !name?.trim();
83
84
  const isDuplicated = this.items
84
85
  .filter((i) => i !== item)
85
86
  .find((i) => i.name === name);
86
87
  return isEmpty || isDuplicated ? false : null;
87
88
  },
88
89
  validateError(name, item) {
89
- const isEmpty = !name;
90
+ const isEmpty = !name?.trim();
90
91
  if (!isEmpty) {
91
92
  return this.$t("The Page Name field is required.");
92
93
  }
@@ -98,19 +99,25 @@ export default {
98
99
  }
99
100
  return '';
100
101
  },
101
- onFocus(name, item) {
102
- this.originalName = name;
102
+ onFocus(item) {
103
+ this.newName = item.name;
103
104
  },
104
105
  async onBlur(name, item) {
105
106
  if (this.validateState(name, item) === false) {
107
+ this.newName = item.name;
108
+ } else {
106
109
  // eslint-disable-next-line no-param-reassign
107
- item.name = this.originalName;
110
+ item.name = name;
108
111
  }
109
112
  await this.$nextTick();
110
113
  setTimeout(() => {
111
114
  this.editRowIndex = null;
112
115
  }, 250);
113
116
  },
117
+ async onCancel(item) {
118
+ this.newName = item.name;
119
+ this.editRowIndex = null;
120
+ },
114
121
  onClick(item, index) {
115
122
  this.editRowIndex = index;
116
123
  this.$emit("item-edit", item);
@@ -162,6 +169,14 @@ export default {
162
169
 
163
170
  itemsSortedClone[draggedItemIndex].order = tempOrder;
164
171
  }
172
+
173
+ // Update order of the items
174
+ const clone = [...itemsSortedClone];
175
+ clone.sort((a, b) => a.order - b.order);
176
+ clone.forEach((item, index) => {
177
+ // eslint-disable-next-line no-param-reassign
178
+ item.order = index + 1;
179
+ });
165
180
  }
166
181
 
167
182
  this.$emit('ordered', itemsSortedClone);
@@ -881,6 +881,7 @@ export default {
881
881
  config.forEach((page) => this.replaceFormText(page.items));
882
882
  config.forEach((page) => this.migrateFormSubmit(page.items));
883
883
  config.forEach((page) => this.updateFieldNameValidation(page.items));
884
+ this.updatePageOrder(config);
884
885
  config.forEach((page) =>
885
886
  this.removeDataVariableFromNestedScreens(page.items)
886
887
  );
@@ -889,6 +890,18 @@ export default {
889
890
  page.order = page.order || index + 1;
890
891
  });
891
892
  },
893
+ updatePageOrder(pages) {
894
+ const clone = [...pages];
895
+ clone.sort((a, b) => {
896
+ const aOrder = a.order || pages.indexOf(a) + 1;
897
+ const bOrder = b.order || pages.indexOf(b) + 1;
898
+ return aOrder - bOrder;
899
+ });
900
+ clone.forEach((item, index) => {
901
+ // eslint-disable-next-line no-param-reassign
902
+ item.order = index + 1;
903
+ });
904
+ },
892
905
  updateFieldNameValidation(items) {
893
906
  items.forEach((item) => {
894
907
  if (item.inspector) {
@@ -1148,9 +1161,9 @@ export default {
1148
1161
  this.updateState();
1149
1162
  },
1150
1163
  addPage(e) {
1151
- this.showAddPageValidations = true;
1152
1164
  const error = this.checkPageName(this.addPageName, true);
1153
1165
  if (error) {
1166
+ this.showAddPageValidations = true;
1154
1167
  e.preventDefault();
1155
1168
  return;
1156
1169
  }
@@ -1227,6 +1240,7 @@ export default {
1227
1240
  globalObject.ProcessMaker.alert(error.message, "danger");
1228
1241
  return;
1229
1242
  }
1243
+ this.updatePageOrder(this.config);
1230
1244
  this.$store.dispatch("undoRedoModule/pushState", {
1231
1245
  config: JSON.stringify(this.config),
1232
1246
  currentPage: this.currentPage,
@@ -80,7 +80,6 @@ export const OpenPageUsingDropdown = {
80
80
  "[data-test=page-dropdown] button"
81
81
  );
82
82
  let selectorAddPage = canvasElement.querySelector("[data-test=page-Page3]");
83
- console.log(selectorAddPage);
84
83
  await selector.click(selector);
85
84
  await selectorAddPage.click(selectorAddPage);
86
85
  // Open Page 3 (index=2)
@@ -111,3 +110,37 @@ export const OpenPageUsingDropdown = {
111
110
  });
112
111
  }
113
112
  };
113
+
114
+ // Open a page using the PageDropdown(index)
115
+ export const ScrollWithMoreThanTenPages = {
116
+ args: {
117
+ pages: [
118
+ { name: "Page1" },
119
+ { name: "Page2" },
120
+ { name: "Page3" },
121
+ { name: "Page4" },
122
+ { name: "Page5" },
123
+ { name: "Page6" },
124
+ { name: "Page7" },
125
+ { name: "Page8" },
126
+ { name: "Page9" },
127
+ { name: "Page10" },
128
+ { name: "Page11" },
129
+ { name: "Page12" }
130
+ ],
131
+ initialOpenedPages: [0]
132
+ },
133
+ play: async ({ canvasElement }) => {
134
+ const selector = canvasElement.querySelector(
135
+ "[data-test=page-dropdown] button"
136
+ );
137
+ await selector.click(selector);
138
+ // Test .page-dropdown-menu has scroll (scrollHeight > clientHeight)
139
+ await waitFor(() => {
140
+ const dropdownMenu = canvasElement.querySelector(".page-dropdown-menu");
141
+ expect(dropdownMenu.scrollHeight).toBeGreaterThan(
142
+ dropdownMenu.clientHeight
143
+ );
144
+ });
145
+ }
146
+ };
@@ -336,3 +336,60 @@ export const WithoutAnyPageOpened = {
336
336
  );
337
337
  }
338
338
  };
339
+
340
+ // User can close tabs
341
+ export const UserCanCloseTabs = {
342
+ args: {
343
+ pages: [
344
+ { name: "Page 1" },
345
+ { name: "Page 2" },
346
+ { name: "Page 3" },
347
+ { name: "Page 4" },
348
+ { name: "Page 5" }
349
+ ],
350
+ initialOpenedPages: [0, 1, 2, 3, 4]
351
+ },
352
+ play: async ({ canvasElement, step }) => {
353
+ const canvas = within(canvasElement);
354
+
355
+ // Close Tab #1 = Page 1 (tab index=0)
356
+ await step("Close Page 1 (tab index=0)", async () => {
357
+ canvas.getByTestId("close-tab-0").click();
358
+ await waitFor(
359
+ () => {
360
+ expect(canvas.getByTestId("tab-content")).toContainHTML(
361
+ "Here comes content of Page 2 (#1)"
362
+ );
363
+ },
364
+ { timeout: 1000 }
365
+ );
366
+ });
367
+
368
+ // Close Tab #1 = Page 2 (tab index=0)
369
+ await step("Close Page 2 (tab index=0)", async () => {
370
+ canvas.getByTestId("close-tab-0").click();
371
+ await waitFor(
372
+ () => {
373
+ expect(canvas.getByTestId("tab-content")).toContainHTML(
374
+ "Here comes content of Page 3 (#2)"
375
+ );
376
+ },
377
+ { timeout: 1000 }
378
+ );
379
+ });
380
+
381
+ // Close Tab #2 = Page 4 (tab index=1)
382
+ await step("Close Page 4 (tab index=1)", async () => {
383
+ canvas.getByTestId("close-tab-1").click();
384
+ await waitFor(
385
+ () => {
386
+ // keep focus in the tab #1
387
+ expect(canvas.getByTestId("tab-content")).toContainHTML(
388
+ "Here comes content of Page 3 (#2)"
389
+ );
390
+ },
391
+ { timeout: 1000 }
392
+ );
393
+ });
394
+ }
395
+ };