Skip to content

Commit e4ee8b2

Browse files
authored
moves widget operations to backend (#5111)
* moves widget operations to backend * removes logs * remove frontent operations, adds disabledIf * uses native operations from backend in widget controls (only remove left) * removes skipOperations * uses cascades to remove edit widget operation in layout-widget, updates skipEdit computed * adds remove to backend config, keep it standalone in frontend * fixes widgets tests * emit operation from widget control with name instead of each individual name * disable and tooltip props for breadcrumb switch * rework controls / breadcrumb * breadcrumb switch must have a value even if no def (radio input) * in area editor get index from payload object (more generic way to use an object) * uses nativeAction * action for switch layout * listen to bus events directly in layout editor * disabledIdData for layout switch * renames disabledIfData, makes disable and tooltip "work" for switch choices * removes breadcrumb switch general tooltip * removes choiceTooltip * remove control broken * breadcrumb switch has null had default value * uses same table / mobile values than in brekpoint preview * adds disabled logic in normal widget operations, fix remove button, clean code * removes useless labels from backend primary widget operations (only tooltip needed) * removes logs * moves breakpoint preview mode value into its own store (easy to retrieve, watch, compute etc) * renames tinyWidgetContainer into tinyScreen * in breadcrumb switch remove useless div, adds missing classes, reorganizes css * adds translation key for disabled switch on tiny screen * missing store update when switching layout mode * readability * if switch choice becomes disabled switch to another one or unset it * styles when entire breadcrumb switch is disabled * adds style for disabled breadcrumb switch choice * global disabled for breadcrumb switch * compare current mobile preview screen with layout-widget mobile and tablet breakpoint * clean * be sure table and/or mobile breakpoints are ok * share operation disable and tooltip in lib file, support disable and disable tooltip on entire switch * supports only two choices in breadcrumb operations * passes tooltip for breadcrumb menu * fixes widget operations native before separator * removes unsused import * gets back old tablet and mobile defaults * fix move breadcrumb operation * fixes widgets tests * adds changelog
1 parent a4cce8b commit e4ee8b2

File tree

18 files changed

+511
-312
lines changed

18 files changed

+511
-312
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
* `widgetOperations` support for `placement: 'breadcrumb'` to add operations to the breadcrumb menu of widgets. Extend the widget operations configuration to support various features when in the breadcrumb menu.
1212
* Area template (Nunjucks) support for `aposStyle`, `aposClassName`, `aposParentOptions` and `aposAttrs` contextual named variables (`with {}` syntax).
1313
* New login option `caseInsensitive` to force login usernames and emails to be case insensitive. New task `login-case-insensitive` updating all login names / email to lowercase, used by a new migration when switching to `caseInsensitive`.
14+
* Adds `disableIfProps` and `disableTooltip` to widget operations and breadcrumb operations.
1415

1516
### Changes
1617

1718
* Enable `/api/v1/@apostrophecms/login/logout` and `/api/v1/@apostrophecms/login/whoami` routes when `localLogin` is `false`.
1819
* Refactored complex logic regarding data updates in `AposSchema`.
1920
* Cleaned up `annotateAreaForExternalFront` logic and added context so developers understand the reason if it fails due to a widget type with no matching module in the project.
2021
* Color fields now display their preset color swatches in the field UI rather than just the color picker popup
22+
* Moves widget operations to backend with new `action` and `nativeAction` properties.
23+
* Moves `mode` from breakpoint preview to it's own store (to be used by layout).
2124

2225
### Fixes
2326

modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBreakpointPreviewMode.vue

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@
5656
</div>
5757
</template>
5858
<script>
59+
import { mapState, mapActions } from 'pinia';
60+
import { useBreakpointPreviewStore } from 'Modules/@apostrophecms/ui/stores/breakpointPreview.js';
61+
5962
export default {
6063
name: 'TheAposContextBreakpointPreviewMode',
6164
props: {
@@ -83,7 +86,6 @@ export default {
8386
emits: [ 'switch-breakpoint-preview-mode', 'reset-breakpoint-preview-mode' ],
8487
data() {
8588
return {
86-
mode: null,
8789
originalBodyBackground: null,
8890
shortcuts: this.getShortcuts(),
8991
breakpoints: this.getBreakpointItems(),
@@ -94,6 +96,7 @@ export default {
9496
};
9597
},
9698
computed: {
99+
...mapState(useBreakpointPreviewStore, [ 'mode' ]),
97100
activeScreen() {
98101
return this.mode && this.screens[this.mode];
99102
},
@@ -154,6 +157,7 @@ export default {
154157
);
155158
},
156159
methods: {
160+
...mapActions(useBreakpointPreviewStore, [ 'setMode' ]),
157161
observerCallback(mutationList, observer) {
158162
for (const mutation of mutationList) {
159163
if (
@@ -205,7 +209,7 @@ export default {
205209
refreshableEl.style.width = width;
206210
refreshableEl.style.height = height;
207211
208-
this.mode = mode;
212+
this.setMode(mode);
209213
this.$emit('switch-breakpoint-preview-mode', {
210214
mode,
211215
label,
@@ -249,7 +253,7 @@ export default {
249253
refreshableEl.style.removeProperty('width');
250254
refreshableEl.style.removeProperty('height');
251255
252-
this.mode = null;
256+
this.setMode(null);
253257
this.$emit('reset-breakpoint-preview-mode');
254258
this.saveState({ mode: this.mode });
255259
},

modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,14 @@
8080
<AposBreadcrumbOperations
8181
v-if="widgetBreadcrumbOperations.length > 0"
8282
:i="i"
83+
:tiny-screen="tinyScreen"
8384
:widget="widget"
8485
:options="options"
8586
:disabled="disabled"
8687
:is-focused="isFocused"
8788
@widget-focus="getFocus"
8889
@update="$emit('update', $event)"
89-
@operation="onBreadcrumbOperation"
90+
@operation="onOperation"
9091
/>
9192
</div>
9293
<div
@@ -128,6 +129,7 @@
128129
>
129130
<AposWidgetControls
130131
v-if="!foreign"
132+
:index="i"
131133
:first="i === 0"
132134
:last="i === next.length - 1"
133135
:options="{ contextual: isContextual }"
@@ -136,14 +138,8 @@
136138
:tabbable="isFocused"
137139
:model-value="widget"
138140
:widget-options="widgetOptions"
139-
@up="$emit('up', i);"
140-
@remove="$emit('remove', i);"
141-
@edit="$emit('edit', i);"
142-
@cut="$emit('cut', i);"
143-
@copy="$emit('copy', i);"
144-
@clone="$emit('clone', i);"
145-
@down="$emit('down', i);"
146141
@update="$emit('update', $event)"
142+
@operation="onOperation"
147143
/>
148144
</div>
149145

@@ -211,7 +207,7 @@
211207
<script>
212208
import { mapState, mapActions } from 'pinia';
213209
import { useWidgetStore } from 'Modules/@apostrophecms/ui/stores/widget';
214-
210+
import { useBreakpointPreviewStore } from 'Modules/@apostrophecms/ui/stores/breakpointPreview.js';
215211
export default {
216212
name: 'AposAreaWidget',
217213
props: {
@@ -357,6 +353,7 @@ export default {
357353
'hoveredNonForeignWidget',
358354
'emphasizedWidgets'
359355
]),
356+
...mapState(useBreakpointPreviewStore, { breakpointPreviewMode: 'mode' }),
360357
// Passed only to the preview layer (custom preview components).
361358
followingValuesWithParent() {
362359
return Object.entries(this.followingValues || {})
@@ -402,7 +399,8 @@ export default {
402399
return (this.widgetModuleOptions.widgetBreadcrumbOperations || []);
403400
},
404401
shouldSkipEdit() {
405-
return this.widgetModuleOptions.skipOperations?.includes('edit') ?? false;
402+
return !this.widgetModuleOptions.widgetOperations
403+
.some((op) => op.action === 'edit');
406404
},
407405
isFocused() {
408406
return this.focusedWidget === this.widget._id;
@@ -451,7 +449,29 @@ export default {
451449
},
452450
foreign() {
453451
// Cast to boolean is necessary to satisfy prop typing
454-
return !!(this.docId && (window.apos.adminBar.contextId !== this.docId));
452+
return !!(this.docId && (apos.adminBar.contextId !== this.docId));
453+
},
454+
tinyScreen() {
455+
if (!this.breakpointPreviewMode) {
456+
return false;
457+
}
458+
// How to detect mobile if users have their own screen names..
459+
// Should we consider the tinier the mobile, or should we degine an abstract value?
460+
const [ _, curScreen ] = Object.entries(apos.adminBar.breakpointPreviewMode.screens)
461+
.find(([ screen, _ ]) => screen === this.breakpointPreviewMode) || [ null, null ];
462+
if (!curScreen) {
463+
return false;
464+
}
465+
const screenWidth = parseInt(curScreen.width);
466+
const layoutWidgetGrid = apos.modules['@apostrophecms/layout-widget'].grid;
467+
if (!layoutWidgetGrid) {
468+
return false;
469+
}
470+
const tinyScreenStart = Math.max(
471+
layoutWidgetGrid.tablet?.breakpoint,
472+
layoutWidgetGrid.mobile?.breakpoint
473+
);
474+
return screenWidth <= tinyScreenStart;
455475
}
456476
},
457477
watch: {
@@ -503,7 +523,7 @@ export default {
503523
}
504524
505525
this.$nextTick(() => {
506-
this.adminBarHeight = window.apos.adminBar.height;
526+
this.adminBarHeight = apos.adminBar.height;
507527
this.controlsHeight = this.$refs.modifyControls.getBoundingClientRect().height;
508528
509529
// The height of elements we need to account for when re-attaching the controls
@@ -524,9 +544,9 @@ export default {
524544
},
525545
methods: {
526546
...mapActions(useWidgetStore, [ 'setFocusedWidget', 'setHoveredWidget' ]),
527-
// Emits same actions as the Standard operations,
528-
// e.g ('edit', i), ('remove', i), etc.
529-
onBreadcrumbOperation({ name, payload }) {
547+
// Emits same actions as the native operations,
548+
// e.g ('edit', { index }), ('remove', { index }), etc.
549+
onOperation({ name, payload }) {
530550
this.$emit(name, payload);
531551
},
532552
updateStickyStyles(newStyles) {

modules/@apostrophecms/area/ui/apos/components/AposBreadcrumbOperations.vue

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@
4848
</template>
4949

5050
<script>
51-
import { useWidgetStore } from 'Modules/@apostrophecms/ui/stores/widget';
5251
import { mapActions } from 'pinia';
52+
import { useWidgetStore } from 'Modules/@apostrophecms/ui/stores/widget';
53+
import { isOperationDisabled, getOperationTooltip } from '../lib/operations.js';
5354
5455
export default {
5556
name: 'AposBreadcrumbOperations',
@@ -58,6 +59,10 @@ export default {
5859
type: Number,
5960
required: true
6061
},
62+
tinyScreen: {
63+
type: Boolean,
64+
default: false
65+
},
6166
options: {
6267
type: Object,
6368
default() {
@@ -159,21 +164,42 @@ export default {
159164
return 'AposButton';
160165
},
161166
getOperationProps(operation) {
167+
const disabled = this.disabled || isOperationDisabled(operation, this.$props);
168+
const tooltip = getOperationTooltip(operation, {
169+
disabled,
170+
placement: 'bottom'
171+
});
172+
162173
if (operation.type === 'info') {
163174
return {
164175
fillColor: 'var(--a-primary)',
165176
icon: operation.icon,
166-
tooltip: operation.tooltip
177+
tooltip: operation.tooltip,
178+
disabled
167179
};
168180
}
169181
170182
if (operation.type === 'switch') {
183+
const choices = operation.choices.map((choice) => {
184+
const disabled = isOperationDisabled(choice, this.$props);
185+
const tooltip = getOperationTooltip(choice, {
186+
disabled,
187+
placement: 'bottom'
188+
});
189+
return {
190+
...choice,
191+
disabled,
192+
tooltip
193+
};
194+
});
171195
return {
172196
widgetId: this.widget._id,
173197
name: operation.name,
174-
choices: operation.choices,
198+
choices,
175199
value: operation.def,
176-
class: 'apos-area-widget--switch'
200+
class: 'apos-area-widget--switch',
201+
disabled,
202+
tooltip
177203
};
178204
}
179205
@@ -183,8 +209,9 @@ export default {
183209
...this.operationButtonDefault,
184210
icon: operation.icon
185211
},
186-
tooltip: operation.tooltip || null,
187-
teleportContent: this.teleportModals
212+
teleportContent: this.teleportModals,
213+
disabled,
214+
tooltip
188215
};
189216
}
190217
@@ -255,23 +282,23 @@ export default {
255282
256283
this.emitOperation(operation);
257284
},
258-
emitOperation(operation, payload = {}) {
259-
if (operation.action || operation.rawEvents?.length) {
285+
emitOperation(operation, data = {}) {
286+
const payload = {
287+
widgetId: this.widget._id,
288+
index: this.i,
289+
data
290+
};
291+
292+
if (operation.nativeAction) {
260293
this.$emit('operation', {
261-
name: operation.action,
262-
payload: this.i,
263-
data: {
264-
...payload,
265-
...operation,
266-
_id: this.widget._id
267-
}
268-
});
269-
} else {
270-
apos.bus.$emit('widget-breadcrumb-operation', {
271-
...payload,
272-
...operation,
273-
_id: this.widget._id
294+
name: operation.nativeAction,
295+
payload
274296
});
297+
return;
298+
}
299+
300+
if (operation.action) {
301+
apos.bus.$emit(operation.action, payload);
275302
}
276303
},
277304

0 commit comments

Comments
 (0)