apostrophe 3.48.0 → 3.50.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +55 -2
  2. package/index.js +20 -2
  3. package/lib/locales.js +1 -1
  4. package/lib/moog-require.js +3 -0
  5. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +12 -2
  6. package/modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue +2 -0
  7. package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +7 -24
  8. package/modules/@apostrophecms/asset/index.js +27 -2
  9. package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.config.js +23 -2
  10. package/modules/@apostrophecms/asset/lib/webpack/src/webpack.config.js +26 -2
  11. package/modules/@apostrophecms/doc/index.js +149 -0
  12. package/modules/@apostrophecms/doc-type/index.js +9 -1
  13. package/modules/@apostrophecms/global/index.js +4 -15
  14. package/modules/@apostrophecms/i18n/i18n/en.json +3 -2
  15. package/modules/@apostrophecms/i18n/index.js +76 -61
  16. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerDisplay.vue +14 -1
  17. package/modules/@apostrophecms/login/ui/apos/components/AposForgotPasswordForm.vue +3 -60
  18. package/modules/@apostrophecms/login/ui/apos/components/AposLoginForm.vue +3 -231
  19. package/modules/@apostrophecms/login/ui/apos/components/AposResetPasswordForm.vue +3 -96
  20. package/modules/@apostrophecms/login/ui/apos/components/TheAposLogin.vue +2 -99
  21. package/modules/@apostrophecms/login/ui/apos/logic/AposForgotPasswordForm.js +68 -0
  22. package/modules/@apostrophecms/login/ui/apos/logic/AposLoginForm.js +239 -0
  23. package/modules/@apostrophecms/login/ui/apos/logic/AposResetPasswordForm.js +105 -0
  24. package/modules/@apostrophecms/login/ui/apos/logic/TheAposLogin.js +107 -0
  25. package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +9 -3
  26. package/modules/@apostrophecms/modal/ui/apos/components/AposModalToolbar.vue +1 -0
  27. package/modules/@apostrophecms/page/index.js +124 -1
  28. package/modules/@apostrophecms/piece-type/index.js +57 -9
  29. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposImageControlDialog.vue +11 -8
  30. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +226 -72
  31. package/modules/@apostrophecms/schema/index.js +0 -1
  32. package/modules/@apostrophecms/schema/lib/addFieldTypes.js +35 -7
  33. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +21 -1
  34. package/modules/@apostrophecms/schema/ui/apos/components/AposInputString.vue +12 -7
  35. package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +1 -0
  36. package/modules/@apostrophecms/ui/ui/apos/components/AposCombo.vue +178 -20
  37. package/modules/@apostrophecms/ui/ui/apos/components/AposFilterMenu.vue +1 -1
  38. package/modules/@apostrophecms/ui/ui/apos/components/AposPager.vue +4 -6
  39. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_theme_mixins.scss +1 -0
  40. package/modules/@apostrophecms/util/index.js +5 -6
  41. package/modules/@apostrophecms/util/ui/src/http.js +6 -3
  42. package/package.json +20 -3
  43. package/test/change-doc-ids.js +134 -0
  44. package/test/i18n.js +310 -0
  45. package/test/static-i18n.js +0 -105
@@ -58,108 +58,11 @@
58
58
  </template>
59
59
 
60
60
  <script>
61
- import AposThemeMixin from 'Modules/@apostrophecms/ui/mixins/AposThemeMixin';
62
-
63
- const STAGES = [
64
- 'login',
65
- 'forgotPassword',
66
- 'resetPassword'
67
- ];
61
+ import TheAposLoginLogic from 'Modules/@apostrophecms/login/logic/TheAposLogin';
68
62
 
69
63
  export default {
70
64
  name: 'TheAposLogin',
71
- mixins: [ AposThemeMixin ],
72
- data() {
73
- return {
74
- stage: STAGES[0],
75
- mounted: false,
76
- beforeCreateFinished: false,
77
- error: '',
78
- passwordResetData: {},
79
- context: {}
80
- };
81
- },
82
- computed: {
83
- loaded() {
84
- return this.mounted && this.beforeCreateFinished;
85
- },
86
- showNav() {
87
- return this.stage !== STAGES[0];
88
- },
89
- homeUrl() {
90
- return `${apos.prefix}/`;
91
- }
92
- },
93
- // We need it here and not in the login form because the version used in the footer.
94
- // The context will be passed to every form, might be a good thing in the future.
95
- async beforeCreate() {
96
- const stateChange = parseInt(window.sessionStorage.getItem('aposStateChange'));
97
- const seen = JSON.parse(window.sessionStorage.getItem('aposStateChangeSeen') || '{}');
98
- if (!seen[window.location.href]) {
99
- const lastModified = Date.parse(document.lastModified);
100
- if (stateChange && lastModified && (lastModified < stateChange)) {
101
- seen[window.location.href] = true;
102
- window.sessionStorage.setItem('aposStateChangeSeen', JSON.stringify(seen));
103
- location.reload();
104
- return;
105
- }
106
- }
107
- try {
108
- this.context = await apos.http.post(`${apos.login.action}/context`, {
109
- busy: true
110
- });
111
- } catch (e) {
112
- this.context = {};
113
- this.error = e.message || 'apostrophe:loginErrorGeneric';
114
- } finally {
115
- this.beforeCreateFinished = true;
116
- }
117
- },
118
- created() {
119
- const url = new URL(document.location);
120
- const data = {
121
- email: url.searchParams.get('email'),
122
- reset: url.searchParams.get('reset')
123
- };
124
- if (data.email && data.reset) {
125
- this.passwordResetData = data;
126
- this.setStage('resetPassword');
127
- }
128
- },
129
- mounted() {
130
- this.mounted = true;
131
- },
132
- methods: {
133
- setStage(name) {
134
- // 1. Enabled status per stage. A bit cryptic but effective.
135
- // Search for a method composed of the `name` + `Enabled`
136
- // (e.g. `forgotPasswordEnabled` and execute it (should return boolean).
137
- // If no method is found it is enabled. Fallback to the default stage.
138
- const enabled = this[`${name}Enabled`]?.() ?? true;
139
- if (!enabled) {
140
- this.stage = STAGES[0];
141
- return;
142
- }
143
- // 2. Set it only if it's a known stage
144
- if (STAGES.includes(name)) {
145
- this.stage = name;
146
- return;
147
- }
148
- // 3. Fallback to the default stage
149
- this.stage = STAGES[0];
150
- },
151
- forgotPasswordEnabled() {
152
- return apos.login.passwordResetEnabled;
153
- },
154
- resetPasswordEnabled() {
155
- return apos.login.passwordResetEnabled;
156
- },
157
- onRedirect(loc) {
158
- window.sessionStorage.setItem('aposStateChange', Date.now());
159
- window.sessionStorage.setItem('aposStateChangeSeen', '{}');
160
- location.assign(loc);
161
- }
162
- }
65
+ mixins: [ TheAposLoginLogic ]
163
66
  };
164
67
  </script>
165
68
 
@@ -0,0 +1,68 @@
1
+ // This is the business logic of the AposForgotPasswordForm Vue component.
2
+ // It is in a separate file so that you can override the component's templates
3
+ // and styles just by copying the .vue file to your project, and leave the business logic
4
+ // unchanged.
5
+
6
+ import AposLoginFormMixin from 'Modules/@apostrophecms/login/mixins/AposLoginFormMixin';
7
+
8
+ export default {
9
+ mixins: [ AposLoginFormMixin ],
10
+ emits: [ 'set-stage' ],
11
+ data() {
12
+ return {
13
+ busy: false,
14
+ done: false,
15
+ schema: [
16
+ {
17
+ name: 'email',
18
+ label: 'apostrophe:email',
19
+ placeholder: 'apostrophe:loginEnterEmail',
20
+ type: 'string',
21
+ required: true
22
+ }
23
+ ]
24
+ };
25
+ },
26
+ computed: {
27
+ disabled() {
28
+ return this.doc.hasErrors;
29
+ },
30
+ help() {
31
+ if (this.done) {
32
+ return this.$t('apostrophe:loginResetRequestDone', {
33
+ email: this.doc.data.email
34
+ });
35
+ }
36
+ return this.$t('apostrophe:loginResetPasswordRequest');
37
+ }
38
+ },
39
+ created() {
40
+ if (!this.passwordResetEnabled) {
41
+ this.$emit('set-stage', 'login');
42
+ }
43
+ },
44
+ methods: {
45
+ async submit() {
46
+ if (this.busy) {
47
+ return;
48
+ }
49
+ this.busy = true;
50
+ this.error = '';
51
+
52
+ await this.requestReset();
53
+ },
54
+ async requestReset() {
55
+ try {
56
+ await apos.http.post(`${apos.login.action}/reset-request`, {
57
+ busy: true,
58
+ body: { ...this.doc.data }
59
+ });
60
+ this.done = true;
61
+ } catch (e) {
62
+ this.error = e.message || 'apostrophe:loginErrorGeneric';
63
+ } finally {
64
+ this.busy = false;
65
+ }
66
+ }
67
+ }
68
+ };
@@ -0,0 +1,239 @@
1
+ // This is the business logic of the AposLoginForm Vue component.
2
+ // It is in a separate file so that you can override the component's templates
3
+ // and styles just by copying the .vue file to your project, and leave the business logic
4
+ // unchanged.
5
+
6
+ import AposLoginFormMixin from 'Modules/@apostrophecms/login/mixins/AposLoginFormMixin';
7
+
8
+ export default {
9
+ mixins: [ AposLoginFormMixin ],
10
+ emits: [ 'redirect', 'set-stage' ],
11
+ data() {
12
+ return {
13
+ phase: 'beforeSubmit',
14
+ busy: false,
15
+ schema: [
16
+ {
17
+ name: 'username',
18
+ label: 'Username',
19
+ placeholder: 'Enter username',
20
+ type: 'string',
21
+ required: true
22
+ },
23
+ {
24
+ name: 'password',
25
+ label: 'Password',
26
+ placeholder: 'Enter password',
27
+ type: 'password',
28
+ required: true
29
+ }
30
+ ],
31
+ requirements: getRequirements(),
32
+ requirementProps: {},
33
+ fetchingRequirementProps: false
34
+ };
35
+ },
36
+ computed: {
37
+ disabled() {
38
+ return this.doc.hasErrors ||
39
+ !!this.beforeSubmitRequirements.find(requirement => !requirement.done);
40
+ },
41
+ beforeSubmitRequirements() {
42
+ return this.requirements.filter(requirement => requirement.phase === 'beforeSubmit');
43
+ },
44
+ // The currently active requirement expecting a solo presentation.
45
+ // Currently it only concerns `afterPasswordVerified` requirements.
46
+ // beforeSubmit requirements are not presented solo.
47
+ activeSoloRequirement() {
48
+ return (this.phase === 'afterPasswordVerified') &&
49
+ this.requirements.find(requirement =>
50
+ (requirement.phase === 'afterPasswordVerified') && !requirement.done
51
+ );
52
+ }
53
+ },
54
+ watch: {
55
+ context(newVal) {
56
+ this.requirementProps = newVal.requirementProps;
57
+ },
58
+ async activeSoloRequirement(newVal) {
59
+ if (
60
+ (this.phase === 'afterPasswordVerified') &&
61
+ (newVal?.phase === 'afterPasswordVerified') &&
62
+ newVal.propsRequired &&
63
+ !(newVal.success || newVal.error)
64
+ ) {
65
+ try {
66
+ this.fetchingRequirementProps = true;
67
+ const data = await apos.http.post(`${apos.login.action}/requirement-props`, {
68
+ busy: true,
69
+ body: {
70
+ name: newVal.name,
71
+ incompleteToken: this.incompleteToken
72
+ }
73
+ });
74
+ this.requirementProps = {
75
+ ...this.requirementProps,
76
+ [newVal.name]: data
77
+ };
78
+ } catch (e) {
79
+ this.error = e.message || 'apostrophe:loginErrorGeneric';
80
+ } finally {
81
+ this.fetchingRequirementProps = false;
82
+ }
83
+ } else {
84
+ return null;
85
+ }
86
+ }
87
+ },
88
+ created() {
89
+ this.requirementProps = this.context.requirementProps;
90
+ },
91
+ methods: {
92
+ async submit() {
93
+ if (this.busy) {
94
+ return;
95
+ }
96
+ this.busy = true;
97
+ this.error = '';
98
+
99
+ await this.invokeInitialLoginApi();
100
+ },
101
+ async invokeInitialLoginApi() {
102
+ try {
103
+ const response = await apos.http.post(`${apos.login.action}/login`, {
104
+ busy: true,
105
+ body: {
106
+ ...this.doc.data,
107
+ requirements: this.getInitialSubmitRequirementsData(),
108
+ session: true
109
+ }
110
+ });
111
+ if (response && response.incompleteToken) {
112
+ this.incompleteToken = response.incompleteToken;
113
+ this.phase = 'afterPasswordVerified';
114
+ } else {
115
+ this.redirectAfterLogin();
116
+ }
117
+ } catch (e) {
118
+ this.error = e.message || 'An error occurred. Please try again.';
119
+ this.phase = 'beforeSubmit';
120
+ } finally {
121
+ this.busy = false;
122
+ }
123
+ },
124
+ getInitialSubmitRequirementsData() {
125
+ return Object.fromEntries(this.requirements
126
+ .filter(r => r.phase !== 'afterPasswordVerified' || !r.done)
127
+ .map(r => ([
128
+ r.name,
129
+ r.value
130
+ ])));
131
+ },
132
+ async invokeFinalLoginApi() {
133
+ try {
134
+ await apos.http.post(`${apos.login.action}/login`, {
135
+ busy: true,
136
+ body: {
137
+ ...this.doc.data,
138
+ incompleteToken: this.incompleteToken,
139
+ requirements: this.getFinalSubmitRequirementsData(),
140
+ session: true
141
+ }
142
+ });
143
+ this.redirectAfterLogin();
144
+ } catch (e) {
145
+ this.error = e.message || 'An error occurred. Please try again.';
146
+ this.phase = 'beforeSubmit';
147
+ } finally {
148
+ this.busy = false;
149
+ }
150
+ },
151
+ getFinalSubmitRequirementsData() {
152
+ return Object.fromEntries(this.requirements.filter(r => r.phase === 'afterPasswordVerified').map(r => ([
153
+ r.name,
154
+ r.value
155
+ ])));
156
+ },
157
+ redirectAfterLogin() {
158
+ // TODO handle situation where user should be sent somewhere other than homepage.
159
+ // Redisplay homepage with editing interface
160
+ this.$emit('redirect', `${apos.prefix}/`);
161
+ },
162
+ async requirementBlock(requirementBlock) {
163
+ const requirement = this.requirements
164
+ .find(requirement => requirement.name === requirementBlock.name);
165
+ requirement.done = false;
166
+ requirement.value = undefined;
167
+ },
168
+ async requirementDone(requirementDone, value) {
169
+ const requirement = this.requirements
170
+ .find(requirement => requirement.name === requirementDone.name);
171
+
172
+ if (requirement.phase === 'beforeSubmit') {
173
+ requirement.done = true;
174
+ requirement.value = value;
175
+ return;
176
+ }
177
+
178
+ requirement.error = null;
179
+
180
+ try {
181
+ await apos.http.post(`${apos.login.action}/requirement-verify`, {
182
+ busy: true,
183
+ body: {
184
+ name: requirement.name,
185
+ value,
186
+ incompleteToken: this.incompleteToken
187
+ }
188
+ });
189
+
190
+ requirement.success = true;
191
+ } catch (err) {
192
+ requirement.error = err;
193
+ }
194
+
195
+ // Avoids the need for a deep watch
196
+ this.requirements = [ ...this.requirements ];
197
+
198
+ if (requirement.success && !requirement.askForConfirmation) {
199
+ requirement.done = true;
200
+
201
+ if (!this.activeSoloRequirement) {
202
+ await this.invokeFinalLoginApi();
203
+ }
204
+ }
205
+ },
206
+
207
+ async requirementConfirmed (requirementConfirmed) {
208
+ const requirement = this.requirements
209
+ .find(requirement => requirement.name === requirementConfirmed.name);
210
+
211
+ requirement.done = true;
212
+
213
+ if (!this.activeSoloRequirement) {
214
+ await this.invokeFinalLoginApi();
215
+ }
216
+ },
217
+ getRequirementProps(name) {
218
+ return this.requirementProps[name] || {};
219
+ }
220
+ }
221
+ };
222
+
223
+ function getRequirements() {
224
+ const requirements = Object.entries(apos.login.requirements).map(([ name, requirement ]) => {
225
+ return {
226
+ name,
227
+ component: requirement.component || name,
228
+ ...requirement,
229
+ done: false,
230
+ value: null,
231
+ success: null,
232
+ error: null
233
+ };
234
+ });
235
+ return [
236
+ ...requirements.filter(r => r.phase === 'beforeSubmit'),
237
+ ...requirements.filter(r => r.phase === 'afterPasswordVerified')
238
+ ];
239
+ }
@@ -0,0 +1,105 @@
1
+ // This is the business logic of the AposResetPasswordForm Vue component.
2
+ // It is in a separate file so that you can override the component's templates
3
+ // and styles just by copying the .vue file to your project, and leave the business logic
4
+ // unchanged.
5
+
6
+ import AposLoginFormMixin from 'Modules/@apostrophecms/login/mixins/AposLoginFormMixin';
7
+
8
+ export default {
9
+ name: 'AposResetPasswordForm',
10
+ mixins: [ AposLoginFormMixin ],
11
+ props: {
12
+ data: {
13
+ type: Object,
14
+ default: function() {
15
+ return {};
16
+ }
17
+ }
18
+ },
19
+ emits: [ 'set-stage' ],
20
+ data() {
21
+ return {
22
+ ready: false,
23
+ busy: false,
24
+ valid: true,
25
+ done: false,
26
+ contextErrorReceived: false,
27
+ schema: [
28
+ {
29
+ name: 'password',
30
+ label: 'apostrophe:newPassword',
31
+ type: 'password',
32
+ required: true
33
+ }
34
+ ]
35
+ };
36
+ },
37
+ computed: {
38
+ disabled() {
39
+ return this.doc.hasErrors;
40
+ },
41
+ help() {
42
+ if (!this.valid) {
43
+ return '';
44
+ }
45
+ if (this.done) {
46
+ return this.error ? '' : this.$t('apostrophe:loginResetDone');
47
+ }
48
+ return this.$t('apostrophe:loginResetInfo', {
49
+ email: this.data.email
50
+ });
51
+ }
52
+ },
53
+ async created() {
54
+ if (!this.passwordResetEnabled) {
55
+ this.$emit('set-stage', 'login');
56
+ return;
57
+ }
58
+ this.busy = true;
59
+ await this.verify();
60
+ this.ready = true;
61
+ },
62
+
63
+ methods: {
64
+ async submit() {
65
+ if (this.busy) {
66
+ return;
67
+ }
68
+ this.busy = true;
69
+ this.error = '';
70
+
71
+ await this.reset();
72
+ },
73
+ async verify() {
74
+ try {
75
+ await apos.http.get(`${apos.login.action}/reset`, {
76
+ busy: true,
77
+ qs: { ...this.data }
78
+ });
79
+ this.valid = true;
80
+ } catch (e) {
81
+ this.valid = false;
82
+ this.done = true;
83
+ this.error = e.message || 'apostrophe:loginErrorGeneric';
84
+ } finally {
85
+ this.busy = false;
86
+ }
87
+ },
88
+ async reset() {
89
+ try {
90
+ await apos.http.post(`${apos.login.action}/reset`, {
91
+ busy: true,
92
+ body: {
93
+ ...this.data,
94
+ ...this.doc.data
95
+ }
96
+ });
97
+ this.done = true;
98
+ } catch (e) {
99
+ this.error = e.message || 'apostrophe:loginErrorGeneric';
100
+ } finally {
101
+ this.busy = false;
102
+ }
103
+ }
104
+ }
105
+ };
@@ -0,0 +1,107 @@
1
+ // This is the business logic of the TheAposLogin Vue component.
2
+ // It is in a separate file so that you can override the component's templates
3
+ // and styles just by copying the .vue file to your project, and leave the business logic
4
+ // unchanged.
5
+
6
+ import AposThemeMixin from 'Modules/@apostrophecms/ui/mixins/AposThemeMixin';
7
+
8
+ const STAGES = [
9
+ 'login',
10
+ 'forgotPassword',
11
+ 'resetPassword'
12
+ ];
13
+
14
+ export default {
15
+ mixins: [ AposThemeMixin ],
16
+ data() {
17
+ return {
18
+ stage: STAGES[0],
19
+ mounted: false,
20
+ beforeCreateFinished: false,
21
+ error: '',
22
+ passwordResetData: {},
23
+ context: {}
24
+ };
25
+ },
26
+ computed: {
27
+ loaded() {
28
+ return this.mounted && this.beforeCreateFinished;
29
+ },
30
+ showNav() {
31
+ return this.stage !== STAGES[0];
32
+ },
33
+ homeUrl() {
34
+ return `${apos.prefix}/`;
35
+ }
36
+ },
37
+ // We need it here and not in the login form because the version used in the footer.
38
+ // The context will be passed to every form, might be a good thing in the future.
39
+ async beforeCreate() {
40
+ const stateChange = parseInt(window.sessionStorage.getItem('aposStateChange'));
41
+ const seen = JSON.parse(window.sessionStorage.getItem('aposStateChangeSeen') || '{}');
42
+ if (!seen[window.location.href]) {
43
+ const lastModified = Date.parse(document.lastModified);
44
+ if (stateChange && lastModified && (lastModified < stateChange)) {
45
+ seen[window.location.href] = true;
46
+ window.sessionStorage.setItem('aposStateChangeSeen', JSON.stringify(seen));
47
+ location.reload();
48
+ return;
49
+ }
50
+ }
51
+ try {
52
+ this.context = await apos.http.post(`${apos.login.action}/context`, {
53
+ busy: true
54
+ });
55
+ } catch (e) {
56
+ this.context = {};
57
+ this.error = e.message || 'apostrophe:loginErrorGeneric';
58
+ } finally {
59
+ this.beforeCreateFinished = true;
60
+ }
61
+ },
62
+ created() {
63
+ const url = new URL(document.location);
64
+ const data = {
65
+ email: url.searchParams.get('email'),
66
+ reset: url.searchParams.get('reset')
67
+ };
68
+ if (data.email && data.reset) {
69
+ this.passwordResetData = data;
70
+ this.setStage('resetPassword');
71
+ }
72
+ },
73
+ mounted() {
74
+ this.mounted = true;
75
+ },
76
+ methods: {
77
+ setStage(name) {
78
+ // 1. Enabled status per stage. A bit cryptic but effective.
79
+ // Search for a method composed of the `name` + `Enabled`
80
+ // (e.g. `forgotPasswordEnabled` and execute it (should return boolean).
81
+ // If no method is found it is enabled. Fallback to the default stage.
82
+ const enabled = this[`${name}Enabled`]?.() ?? true;
83
+ if (!enabled) {
84
+ this.stage = STAGES[0];
85
+ return;
86
+ }
87
+ // 2. Set it only if it's a known stage
88
+ if (STAGES.includes(name)) {
89
+ this.stage = name;
90
+ return;
91
+ }
92
+ // 3. Fallback to the default stage
93
+ this.stage = STAGES[0];
94
+ },
95
+ forgotPasswordEnabled() {
96
+ return apos.login.passwordResetEnabled;
97
+ },
98
+ resetPasswordEnabled() {
99
+ return apos.login.passwordResetEnabled;
100
+ },
101
+ onRedirect(loc) {
102
+ window.sessionStorage.setItem('aposStateChange', Date.now());
103
+ window.sessionStorage.setItem('aposStateChangeSeen', '{}');
104
+ location.assign(loc);
105
+ }
106
+ }
107
+ };
@@ -5,6 +5,7 @@
5
5
  v-if="canSelectAll"
6
6
  label="apostrophe:select"
7
7
  type="outline"
8
+ :modifiers="['small']"
8
9
  text-color="var(--a-base-1)"
9
10
  :icon-only="true"
10
11
  :icon="checkboxIcon"
@@ -24,9 +25,9 @@
24
25
  <AposButton
25
26
  v-if="!operations"
26
27
  :label="label"
27
- :icon-only="true"
28
28
  :icon="icon"
29
29
  :disabled="!checkedCount"
30
+ :modifiers="['small']"
30
31
  type="outline"
31
32
  @click="confirmOperation({ action, label, ...rest })"
32
33
  />
@@ -302,7 +303,12 @@ export default {
302
303
  </script>
303
304
 
304
305
  <style lang="scss" scoped>
305
- .apos-manager-toolbar ::v-deep .apos-field--search {
306
- width: 250px;
306
+ .apos-manager-toolbar ::v-deep {
307
+ .apos-field--search {
308
+ width: 250px;
309
+ }
310
+ .apos-input {
311
+ height: 32px;
312
+ }
307
313
  }
308
314
  </style>
@@ -45,5 +45,6 @@ export default {
45
45
 
46
46
  .apos-toolbar__group {
47
47
  display: flex;
48
+ align-items: center;
48
49
  }
49
50
  </style>