apostrophe 4.27.0 → 4.27.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.27.1 (2026-03-03)
4
+
5
+ ### Fixes
6
+
7
+ - Fixes two conditions where slow internet speed could cause relationship field inputs to lose focus before a selection can be registered.
8
+ - Fixes a subtle bug in AposPermissionGrid that caused unrelated clicks to be "swallowed" due to a race condition at low network speeds.
9
+
3
10
  ## 4.27.0 (2026-02-18)
4
11
 
5
12
  ### Adds
@@ -91,9 +91,21 @@ export default {
91
91
  },
92
92
  watch: {
93
93
  apiParams: {
94
- async handler() {
94
+ async handler(newValue, oldValue) {
95
+ // The way we pass the props to this component as an object every
96
+ // means that everything gets flagged as a change every time the
97
+ // component is included in a render.
98
+ //
99
+ // So we need to compare the actual data, and this is a simple way
100
+ // to do that deeply for both regular and advanced permission.
101
+ if (JSON.stringify(newValue) === JSON.stringify(oldValue)) {
102
+ return;
103
+ }
95
104
  this.permissionSets = await this.getPermissionSets();
96
105
  },
106
+ // Still in place in case we stop passing a new object
107
+ // every time, in which case this wouldn't fire
108
+ // without it. -Tom
97
109
  deep: true
98
110
  }
99
111
  },
@@ -28,7 +28,7 @@
28
28
  v-apos-tooltip="getTooltip(item)"
29
29
  aria-selected="false"
30
30
  :class="getClasses(item, index)"
31
- @click="select(item)"
31
+ @pointerdown.prevent="select(item)"
32
32
  >
33
33
  <div
34
34
  v-if="item?.attachment?._urls?.['one-sixth']"
@@ -43,7 +43,10 @@
43
43
  class="apos-button__icon"
44
44
  fill-color="currentColor"
45
45
  />
46
- <div class="apos-search__item__title">
46
+ <div
47
+ class="apos-search__item__title"
48
+ data-apos-test="searchItemTitle"
49
+ >
47
50
  {{ item.title }}
48
51
  </div>
49
52
  <div
@@ -188,6 +191,9 @@ export default {
188
191
 
189
192
  & {
190
193
  color: var(--a-text-primary);
194
+ max-width: 40ch;
195
+ overflow-wrap: break-word;
196
+ word-break: break-all;
191
197
  }
192
198
  }
193
199
 
@@ -37,6 +37,7 @@ export default {
37
37
  subfields,
38
38
  disabled: false,
39
39
  searching: false,
40
+ searchRequestId: 0,
40
41
  choosing: false,
41
42
  relationshipSchema: null
42
43
  };
@@ -176,6 +177,7 @@ export default {
176
177
  );
177
178
  },
178
179
  async search(qs) {
180
+ const requestId = ++this.searchRequestId;
179
181
  const action = apos.modules[this.field.withType].action;
180
182
  const isPage = apos.modules['@apostrophecms/page'].validPageTypes
181
183
  .includes(this.field.withType);
@@ -200,6 +202,10 @@ export default {
200
202
  qs
201
203
  });
202
204
 
205
+ if (requestId !== this.searchRequestId) {
206
+ return;
207
+ }
208
+
203
209
  const removeSelectedItem = item => !this.next.map(i => i._id).includes(item._id);
204
210
  const formatItems = item => ({
205
211
  ...item,
@@ -216,10 +222,6 @@ export default {
216
222
  this.searching = false;
217
223
  },
218
224
  async input () {
219
- if (this.searching) {
220
- return;
221
- }
222
-
223
225
  const trimmed = this.searchTerm.trim();
224
226
  const qs = trimmed.length
225
227
  ? {
@@ -69,6 +69,9 @@ export default {
69
69
  emits: [ 'select' ],
70
70
  methods: {
71
71
  select(item) {
72
+ if (item.disabled) {
73
+ return;
74
+ }
72
75
  const selectedItems = this.selectedItems;
73
76
  if (!selectedItems.some(selectedItem => selectedItem._id === item._id)) {
74
77
  // Never modify a prop
@@ -21,7 +21,8 @@
21
21
  v-for="checked in selectedItems"
22
22
  :key="objectValues ? checked.value : checked"
23
23
  class="apos-combo__selected"
24
- @click.stop="selectOption(getSelectedOption(checked))"
24
+ @pointerdown.stop.prevent="selectOption(getSelectedOption(checked))"
25
+ @click.stop
25
26
  >
26
27
  {{ getSelectedOption(checked)?.label }}
27
28
  <AposIndicator
@@ -74,7 +75,8 @@
74
75
  class="apos-combo__list-item"
75
76
  role="menuitemcheckbox"
76
77
  :class="{focused: focusedItemIndex === i}"
77
- @click.stop="selectOption(choice)"
78
+ @pointerdown.stop.prevent="selectOption(choice)"
79
+ @click.stop
78
80
  @mouseover="focusedItemIndex = i"
79
81
  >
80
82
  <AposIndicator
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apostrophe",
3
- "version": "4.27.0",
3
+ "version": "4.27.1",
4
4
  "description": "The Apostrophe Content Management System.",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -120,10 +120,10 @@
120
120
  "webpack-merge": "^5.7.3",
121
121
  "xregexp": "^2.0.0",
122
122
  "@apostrophecms/emulate-mongo-3-driver": "^1.0.6",
123
- "broadband": "^1.1.0",
124
- "boring": "^1.1.1",
125
123
  "express-cache-on-demand": "^1.0.4",
126
124
  "postcss-viewport-to-container-toggle": "^2.2.0",
125
+ "boring": "^1.1.1",
126
+ "broadband": "^1.1.0",
127
127
  "sanitize-html": "^2.17.0"
128
128
  },
129
129
  "devDependencies": {