apostrophe 4.3.1 → 4.3.3
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 +17 -0
- package/modules/@apostrophecms/modal/ui/apos/components/AposWidgetModalTabs.vue +25 -14
- package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +1 -1
- package/modules/@apostrophecms/schema/ui/apos/logic/AposArrayEditor.js +2 -14
- package/modules/@apostrophecms/schema/ui/apos/logic/AposSchema.js +5 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuItem.vue +10 -0
- package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +14 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.3.3 (2024-06-04)
|
|
4
|
+
|
|
5
|
+
* Removes `$nextTick` use to re render schema in `AposArrayEditor` because it was triggering weird vue error in production.
|
|
6
|
+
Instead, makes the AposSchema for loop keys more unique using `modelValue.data._id`,
|
|
7
|
+
if document changes it re-renders schema fields.
|
|
8
|
+
|
|
9
|
+
## 4.3.2 (2024-05-18)
|
|
10
|
+
|
|
11
|
+
### Fixes
|
|
12
|
+
|
|
13
|
+
* Corrects a regression introduced in version 4.3.0 that broke the validation of widget modals, resulting in a confusing
|
|
14
|
+
error on the page. A "required" field in a widget, for instance, once again blocks the save operation properly.
|
|
15
|
+
|
|
16
|
+
### Changes
|
|
17
|
+
|
|
18
|
+
* Improves widget tab UI for the hidden entries, improves UX when validation errors are present in non-focused tabs.
|
|
19
|
+
|
|
3
20
|
## 4.3.1 (2024-05-17)
|
|
4
21
|
|
|
5
22
|
### Fixes
|
|
@@ -18,21 +18,22 @@
|
|
|
18
18
|
v-if="tabErrors[tab.name] && tabErrors[tab.name].length"
|
|
19
19
|
class="apos-modal-tabs__label apos-modal-tabs__label--error"
|
|
20
20
|
>
|
|
21
|
-
{{ tabErrors[tab.name].length }}
|
|
21
|
+
{{ tabErrors[tab.name].length }} {{ generateErrorLabel(tabErrors[tab.name].length) }}
|
|
22
22
|
</span>
|
|
23
23
|
</button>
|
|
24
24
|
</li>
|
|
25
25
|
<li
|
|
26
|
-
v-if="
|
|
26
|
+
v-if="menuTabs.length"
|
|
27
27
|
key="placeholder-for-hidden-tabs"
|
|
28
28
|
class="apos-modal-tabs__tab apos-modal-tabs__tab--small"
|
|
29
29
|
/>
|
|
30
30
|
</ul>
|
|
31
31
|
<AposContextMenu
|
|
32
|
-
v-if="
|
|
33
|
-
:menu="
|
|
32
|
+
v-if="menuTabs.length"
|
|
33
|
+
:menu="menuTabs"
|
|
34
34
|
menu-placement="bottom-end"
|
|
35
35
|
:button="moreMenuButton"
|
|
36
|
+
data-apos-test="context-menu-tabs"
|
|
36
37
|
@item-clicked="moreMenuHandler($event)"
|
|
37
38
|
/>
|
|
38
39
|
</div>
|
|
@@ -64,7 +65,6 @@ export default {
|
|
|
64
65
|
emits: [ 'select-tab' ],
|
|
65
66
|
data() {
|
|
66
67
|
const visibleTabs = [];
|
|
67
|
-
const hiddenTabs = [];
|
|
68
68
|
|
|
69
69
|
for (let i = 0; i < this.tabs.length; i++) {
|
|
70
70
|
// Shallow clone is sufficient to make mutating
|
|
@@ -73,14 +73,11 @@ export default {
|
|
|
73
73
|
tab.action = tab.name;
|
|
74
74
|
if (i < 5) {
|
|
75
75
|
visibleTabs.push(tab);
|
|
76
|
-
} else {
|
|
77
|
-
hiddenTabs.push(tab);
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
return {
|
|
82
80
|
visibleTabs,
|
|
83
|
-
hiddenTabs,
|
|
84
81
|
moreMenuButton: {
|
|
85
82
|
icon: 'dots-vertical-icon',
|
|
86
83
|
iconOnly: true,
|
|
@@ -100,6 +97,25 @@ export default {
|
|
|
100
97
|
}
|
|
101
98
|
}
|
|
102
99
|
return errors;
|
|
100
|
+
},
|
|
101
|
+
menuTabs() {
|
|
102
|
+
return this.tabs.map((tab) => {
|
|
103
|
+
const modifiers = [];
|
|
104
|
+
if (tab.name === this.current) {
|
|
105
|
+
modifiers.push('selected');
|
|
106
|
+
if (!this.tabErrors[tab.name] || !this.tabErrors[tab.name].length) {
|
|
107
|
+
modifiers.push('primary');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (this.tabErrors[tab.name] && this.tabErrors[tab.name].length) {
|
|
111
|
+
modifiers.push('danger');
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
...tab,
|
|
115
|
+
action: tab.name,
|
|
116
|
+
modifiers
|
|
117
|
+
};
|
|
118
|
+
});
|
|
103
119
|
}
|
|
104
120
|
},
|
|
105
121
|
methods: {
|
|
@@ -116,12 +132,6 @@ export default {
|
|
|
116
132
|
this.$emit('select-tab', id);
|
|
117
133
|
},
|
|
118
134
|
moreMenuHandler(item) {
|
|
119
|
-
const lastVisibleTab = this.visibleTabs[this.visibleTabs.length - 1];
|
|
120
|
-
const selectedItem = this.hiddenTabs.find((tab) => tab.name === item);
|
|
121
|
-
|
|
122
|
-
this.hiddenTabs.splice(this.hiddenTabs.indexOf(selectedItem), 1, lastVisibleTab);
|
|
123
|
-
this.visibleTabs.splice(this.visibleTabs.length - 1, 1, selectedItem);
|
|
124
|
-
|
|
125
135
|
this.$emit('select-tab', item);
|
|
126
136
|
}
|
|
127
137
|
}
|
|
@@ -219,6 +229,7 @@ export default {
|
|
|
219
229
|
|
|
220
230
|
.apos-modal-tabs__label--error {
|
|
221
231
|
border: 1px solid var(--a-danger);
|
|
232
|
+
margin-left: 5px;
|
|
222
233
|
}
|
|
223
234
|
|
|
224
235
|
.apos-modal-tabs__btn {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<component
|
|
33
33
|
:is="fieldStyle === 'table' ? 'td' : 'div'"
|
|
34
34
|
v-for="field in schema"
|
|
35
|
-
:key="
|
|
35
|
+
:key="generateItemUniqueKey(field)"
|
|
36
36
|
:data-apos-field="field.name"
|
|
37
37
|
:style="(fieldStyle === 'table' && field.columnStyle) || {}"
|
|
38
38
|
:class="{'apos-field--hidden': !displayComponent(field)}"
|
|
@@ -149,7 +149,7 @@ export default {
|
|
|
149
149
|
const [ _id, name ] = first.path.split('.');
|
|
150
150
|
await this.select(_id);
|
|
151
151
|
const aposSchema = this.$refs.schema;
|
|
152
|
-
await this
|
|
152
|
+
await this.$nextTick();
|
|
153
153
|
aposSchema.scrollFieldIntoView(name);
|
|
154
154
|
}
|
|
155
155
|
this.titleFieldChoices = await this.getTitleFieldChoices();
|
|
@@ -160,11 +160,7 @@ export default {
|
|
|
160
160
|
return;
|
|
161
161
|
}
|
|
162
162
|
if (await this.validate(true, false)) {
|
|
163
|
-
// Force the array editor to totally reset to avoid in-schema
|
|
164
|
-
// animations when switching (e.g., the relationship input).
|
|
165
163
|
this.currentDocToCurrentItem();
|
|
166
|
-
this.currentId = null;
|
|
167
|
-
await this.nextTick();
|
|
168
164
|
this.currentId = _id;
|
|
169
165
|
this.currentDoc = {
|
|
170
166
|
hasErrors: false,
|
|
@@ -261,7 +257,7 @@ export default {
|
|
|
261
257
|
if (validateItem) {
|
|
262
258
|
this.triggerValidation = true;
|
|
263
259
|
}
|
|
264
|
-
await this
|
|
260
|
+
await this.$nextTick();
|
|
265
261
|
if (validateLength) {
|
|
266
262
|
this.updateMinMax();
|
|
267
263
|
}
|
|
@@ -279,14 +275,6 @@ export default {
|
|
|
279
275
|
return true;
|
|
280
276
|
}
|
|
281
277
|
},
|
|
282
|
-
// Awaitable nextTick
|
|
283
|
-
nextTick() {
|
|
284
|
-
return new Promise((resolve, reject) => {
|
|
285
|
-
this.$nextTick(() => {
|
|
286
|
-
return resolve();
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
},
|
|
290
278
|
newInstance() {
|
|
291
279
|
const instance = {};
|
|
292
280
|
for (const field of this.schema) {
|
|
@@ -181,7 +181,7 @@ export default {
|
|
|
181
181
|
this.populateDocData();
|
|
182
182
|
}
|
|
183
183
|
},
|
|
184
|
-
generation() {
|
|
184
|
+
generation(generated) {
|
|
185
185
|
// repopulate the schema.
|
|
186
186
|
this.populateDocData();
|
|
187
187
|
},
|
|
@@ -331,6 +331,10 @@ export default {
|
|
|
331
331
|
},
|
|
332
332
|
highlight(fieldName) {
|
|
333
333
|
return this.meta[fieldName]?.['@apostrophecms/schema:highlight'];
|
|
334
|
+
},
|
|
335
|
+
generateItemUniqueKey(field) {
|
|
336
|
+
return `${field.name}:${field._id ?? ''}:${this.modelValue?.data?._id ?? ''}`;
|
|
337
|
+
|
|
334
338
|
}
|
|
335
339
|
}
|
|
336
340
|
};
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
class="apos-context-menu__button"
|
|
5
5
|
:class="modifiers"
|
|
6
6
|
:tabindex="tabindex"
|
|
7
|
+
data-apos-test="context-menu-item"
|
|
7
8
|
@click="click"
|
|
8
9
|
>
|
|
9
10
|
{{ $t(label) }}
|
|
@@ -91,6 +92,15 @@ export default {
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
&--primary {
|
|
96
|
+
color: var(--a-primary);
|
|
97
|
+
&:hover,
|
|
98
|
+
&:focus,
|
|
99
|
+
&:active {
|
|
100
|
+
color: var(--a-primary);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
94
104
|
&--disabled {
|
|
95
105
|
color: var(--a-base-5);
|
|
96
106
|
&:hover,
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
<AposButton
|
|
53
53
|
type="primary"
|
|
54
54
|
:label="saveLabel"
|
|
55
|
-
:disabled="
|
|
55
|
+
:disabled="errorCount > 0"
|
|
56
56
|
@click="save"
|
|
57
57
|
/>
|
|
58
58
|
</template>
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
<script>
|
|
63
63
|
import AposModifiedMixin from 'Modules/@apostrophecms/ui/mixins/AposModifiedMixin';
|
|
64
64
|
import AposEditorMixin from 'Modules/@apostrophecms/modal/mixins/AposEditorMixin';
|
|
65
|
+
import AposDocErrorsMixin from 'Modules/@apostrophecms/modal/mixins/AposDocErrorsMixin';
|
|
65
66
|
import AposModalTabsMixin from 'Modules/@apostrophecms/modal/mixins/AposModalTabsMixin';
|
|
66
67
|
import { detectDocChange } from 'Modules/@apostrophecms/schema/lib/detectChange';
|
|
67
68
|
import cuid from 'cuid';
|
|
@@ -69,7 +70,7 @@ import { klona } from 'klona';
|
|
|
69
70
|
|
|
70
71
|
export default {
|
|
71
72
|
name: 'AposWidgetEditor',
|
|
72
|
-
mixins: [ AposModifiedMixin, AposEditorMixin, AposModalTabsMixin ],
|
|
73
|
+
mixins: [ AposModifiedMixin, AposEditorMixin, AposDocErrorsMixin, AposModalTabsMixin ],
|
|
73
74
|
props: {
|
|
74
75
|
type: {
|
|
75
76
|
required: true,
|
|
@@ -193,6 +194,7 @@ export default {
|
|
|
193
194
|
},
|
|
194
195
|
methods: {
|
|
195
196
|
updateDocFields(value) {
|
|
197
|
+
this.updateFieldErrors(value.fieldState);
|
|
196
198
|
this.docFields.data = {
|
|
197
199
|
...this.docFields.data,
|
|
198
200
|
...value.data
|
|
@@ -203,8 +205,14 @@ export default {
|
|
|
203
205
|
this.triggerValidation = true;
|
|
204
206
|
this.$nextTick(async () => {
|
|
205
207
|
const widget = klona(this.docFields.data);
|
|
206
|
-
if (this.
|
|
208
|
+
if (this.errorCount > 0) {
|
|
207
209
|
this.triggerValidation = false;
|
|
210
|
+
await apos.notify('apostrophe:resolveErrorsBeforeSaving', {
|
|
211
|
+
type: 'warning',
|
|
212
|
+
icon: 'alert-circle-icon',
|
|
213
|
+
dismiss: true
|
|
214
|
+
});
|
|
215
|
+
this.focusNextError();
|
|
208
216
|
return;
|
|
209
217
|
}
|
|
210
218
|
try {
|
|
@@ -239,6 +247,9 @@ export default {
|
|
|
239
247
|
: null;
|
|
240
248
|
});
|
|
241
249
|
return widget;
|
|
250
|
+
},
|
|
251
|
+
getAposSchema(field) {
|
|
252
|
+
return this.$refs[field.group.name][0];
|
|
242
253
|
}
|
|
243
254
|
}
|
|
244
255
|
};
|