@strapi/admin 5.27.0 → 5.28.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/dist/admin/admin/src/components/DragLayer.js +67 -0
- package/dist/admin/admin/src/components/DragLayer.js.map +1 -0
- package/dist/admin/admin/src/components/DragLayer.mjs +64 -0
- package/dist/admin/admin/src/components/DragLayer.mjs.map +1 -0
- package/dist/admin/admin/src/components/GapDropZone.js +292 -0
- package/dist/admin/admin/src/components/GapDropZone.js.map +1 -0
- package/dist/admin/admin/src/components/GapDropZone.mjs +268 -0
- package/dist/admin/admin/src/components/GapDropZone.mjs.map +1 -0
- package/dist/admin/admin/src/components/ResizeIndicator.js +353 -0
- package/dist/admin/admin/src/components/ResizeIndicator.js.map +1 -0
- package/dist/admin/admin/src/components/ResizeIndicator.mjs +332 -0
- package/dist/admin/admin/src/components/ResizeIndicator.mjs.map +1 -0
- package/dist/admin/admin/src/components/WidgetRoot.js +216 -0
- package/dist/admin/admin/src/components/WidgetRoot.js.map +1 -0
- package/dist/admin/admin/src/components/WidgetRoot.mjs +195 -0
- package/dist/admin/admin/src/components/WidgetRoot.mjs.map +1 -0
- package/dist/admin/admin/src/features/Tracking.js.map +1 -1
- package/dist/admin/admin/src/features/Tracking.mjs.map +1 -1
- package/dist/admin/admin/src/features/Widgets.js +276 -0
- package/dist/admin/admin/src/features/Widgets.js.map +1 -0
- package/dist/admin/admin/src/features/Widgets.mjs +255 -0
- package/dist/admin/admin/src/features/Widgets.mjs.map +1 -0
- package/dist/admin/admin/src/hooks/useAPIErrorHandler.js +1 -1
- package/dist/admin/admin/src/hooks/useAPIErrorHandler.js.map +1 -1
- package/dist/admin/admin/src/hooks/useAPIErrorHandler.mjs +1 -1
- package/dist/admin/admin/src/hooks/useAPIErrorHandler.mjs.map +1 -1
- package/dist/admin/admin/src/pages/Home/HomePage.js +160 -91
- package/dist/admin/admin/src/pages/Home/HomePage.js.map +1 -1
- package/dist/admin/admin/src/pages/Home/HomePage.mjs +162 -93
- package/dist/admin/admin/src/pages/Home/HomePage.mjs.map +1 -1
- package/dist/admin/admin/src/pages/Home/components/AddWidgetModal.js +189 -0
- package/dist/admin/admin/src/pages/Home/components/AddWidgetModal.js.map +1 -0
- package/dist/admin/admin/src/pages/Home/components/AddWidgetModal.mjs +168 -0
- package/dist/admin/admin/src/pages/Home/components/AddWidgetModal.mjs.map +1 -0
- package/dist/admin/admin/src/services/homepage.js +11 -4
- package/dist/admin/admin/src/services/homepage.js.map +1 -1
- package/dist/admin/admin/src/services/homepage.mjs +11 -4
- package/dist/admin/admin/src/services/homepage.mjs.map +1 -1
- package/dist/admin/admin/src/translations/en.json.js +6 -1
- package/dist/admin/admin/src/translations/en.json.js.map +1 -1
- package/dist/admin/admin/src/translations/en.json.mjs +6 -1
- package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
- package/dist/admin/admin/src/translations/uk.json.js +9 -9
- package/dist/admin/admin/src/translations/uk.json.mjs +9 -9
- package/dist/admin/admin/src/utils/resizeHandlers.js +109 -0
- package/dist/admin/admin/src/utils/resizeHandlers.js.map +1 -0
- package/dist/admin/admin/src/utils/resizeHandlers.mjs +100 -0
- package/dist/admin/admin/src/utils/resizeHandlers.mjs.map +1 -0
- package/dist/admin/admin/src/utils/widgetLayout.js +293 -0
- package/dist/admin/admin/src/utils/widgetLayout.js.map +1 -0
- package/dist/admin/admin/src/utils/widgetLayout.mjs +273 -0
- package/dist/admin/admin/src/utils/widgetLayout.mjs.map +1 -0
- package/dist/admin/src/components/DragLayer.d.ts +8 -4
- package/dist/admin/src/components/GapDropZone.d.ts +36 -0
- package/dist/admin/src/components/ResizeIndicator.d.ts +12 -0
- package/dist/admin/src/components/WidgetRoot.d.ts +14 -0
- package/dist/admin/src/features/Tracking.d.ts +1 -1
- package/dist/admin/src/features/Widgets.d.ts +29 -0
- package/dist/admin/src/pages/Home/HomePage.d.ts +4 -5
- package/dist/admin/src/pages/Home/components/AddWidgetModal.d.ts +10 -0
- package/dist/admin/src/services/homepage.d.ts +3 -3
- package/dist/admin/src/utils/resizeHandlers.d.ts +58 -0
- package/dist/admin/src/utils/widgetLayout.d.ts +78 -0
- package/dist/ee/server/src/controllers/authentication-utils/middlewares.d.ts.map +1 -1
- package/dist/server/ee/server/src/controllers/authentication-utils/middlewares.js +4 -2
- package/dist/server/ee/server/src/controllers/authentication-utils/middlewares.js.map +1 -1
- package/dist/server/ee/server/src/controllers/authentication-utils/middlewares.mjs +4 -2
- package/dist/server/ee/server/src/controllers/authentication-utils/middlewares.mjs.map +1 -1
- package/dist/server/server/src/bootstrap.js +5 -0
- package/dist/server/server/src/bootstrap.js.map +1 -1
- package/dist/server/server/src/bootstrap.mjs +5 -0
- package/dist/server/server/src/bootstrap.mjs.map +1 -1
- package/dist/server/shared/utils/session-auth.js +4 -2
- package/dist/server/shared/utils/session-auth.js.map +1 -1
- package/dist/server/shared/utils/session-auth.mjs +4 -2
- package/dist/server/shared/utils/session-auth.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/shared/contracts/homepage.d.ts +8 -4
- package/dist/shared/contracts/homepage.d.ts.map +1 -1
- package/dist/shared/utils/session-auth.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var reactIntl = require('react-intl');
|
|
5
|
+
var useAPIErrorHandler = require('../hooks/useAPIErrorHandler.js');
|
|
6
|
+
var homepage = require('../services/homepage.js');
|
|
7
|
+
var widgetLayout = require('../utils/widgetLayout.js');
|
|
8
|
+
var Notifications = require('./Notifications.js');
|
|
9
|
+
|
|
10
|
+
function _interopNamespaceDefault(e) {
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
28
|
+
|
|
29
|
+
/* -------------------------------------------------------------------------------------------------
|
|
30
|
+
* Widget Management
|
|
31
|
+
* -----------------------------------------------------------------------------------------------*/ const findWidget = (filteredWidgets, widgetId)=>{
|
|
32
|
+
const widget = filteredWidgets.find((c)=>`${c.uid}` === widgetId);
|
|
33
|
+
if (!widget) {
|
|
34
|
+
return {
|
|
35
|
+
widget: undefined,
|
|
36
|
+
index: -1
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
widget,
|
|
41
|
+
index: filteredWidgets.indexOf(widget)
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const saveLayout = async ({ widgets, widths, updateHomepageLayout, toggleNotification, formatAPIError, formatMessage })=>{
|
|
45
|
+
try {
|
|
46
|
+
const layoutData = {
|
|
47
|
+
widgets: widgets.map((widget)=>({
|
|
48
|
+
uid: widget.uid,
|
|
49
|
+
width: widths[widget.uid] || widgetLayout.WIDGET_SIZING.TOTAL_COLUMNS
|
|
50
|
+
}))
|
|
51
|
+
};
|
|
52
|
+
const res = await updateHomepageLayout(layoutData);
|
|
53
|
+
if ('error' in res) {
|
|
54
|
+
toggleNotification({
|
|
55
|
+
type: 'danger',
|
|
56
|
+
message: formatAPIError(res.error)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
toggleNotification({
|
|
61
|
+
type: 'danger',
|
|
62
|
+
message: formatMessage({
|
|
63
|
+
id: 'notification.error',
|
|
64
|
+
defaultMessage: 'An error occured'
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const moveWidget = ({ filteredWidgets, columnWidths, widgetId, insertIndex, targetRowIndex, isHorizontalDrop })=>{
|
|
70
|
+
const widget = filteredWidgets.find((w)=>w.uid === widgetId);
|
|
71
|
+
if (!widget) return {
|
|
72
|
+
newWidgets: filteredWidgets,
|
|
73
|
+
newWidths: columnWidths
|
|
74
|
+
};
|
|
75
|
+
const widgetRows = widgetLayout.calculateWidgetRows(filteredWidgets, columnWidths);
|
|
76
|
+
// Move widget in the array
|
|
77
|
+
const newWidgets = widgetLayout.moveWidgetInArray(filteredWidgets, widgetId, insertIndex);
|
|
78
|
+
// Calculate optimal widths for both source and target rows
|
|
79
|
+
const newWidths = {
|
|
80
|
+
...columnWidths
|
|
81
|
+
};
|
|
82
|
+
// Find the source row (where the widget was removed from)
|
|
83
|
+
const sourceRow = widgetLayout.findRowContainingWidget(widgetRows, widgetId, filteredWidgets);
|
|
84
|
+
if (isHorizontalDrop) {
|
|
85
|
+
// This is a horizontal drop zone - widget gets full width in its own row
|
|
86
|
+
newWidths[widgetId] = widgetLayout.WIDGET_SIZING.TOTAL_COLUMNS;
|
|
87
|
+
// Resize source row (after widget removal)
|
|
88
|
+
const sourceRowResize = widgetLayout.resizeRowAfterRemoval(sourceRow, widgetId, newWidths);
|
|
89
|
+
Object.assign(newWidths, sourceRowResize);
|
|
90
|
+
} else {
|
|
91
|
+
// This is a vertical drop zone within a row
|
|
92
|
+
const targetRow = widgetRows[targetRowIndex];
|
|
93
|
+
// Check if we're reordering within the same row
|
|
94
|
+
const isSameRowReorder = sourceRow && targetRow && sourceRow.startIndex === targetRow.startIndex;
|
|
95
|
+
if (isSameRowReorder) {
|
|
96
|
+
// For same-row reordering, just preserve the existing widths
|
|
97
|
+
return {
|
|
98
|
+
newWidgets,
|
|
99
|
+
newWidths
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// Different rows - resize both source and target rows
|
|
103
|
+
// Resize source row (after widget removal)
|
|
104
|
+
const sourceRowResize = widgetLayout.resizeRowAfterRemoval(sourceRow, widgetId, newWidths);
|
|
105
|
+
Object.assign(newWidths, sourceRowResize);
|
|
106
|
+
// Resize target row (after widget addition)
|
|
107
|
+
const targetRowResize = widgetLayout.resizeRowAfterAddition(targetRow, widget, insertIndex, newWidths);
|
|
108
|
+
Object.assign(newWidths, targetRowResize);
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
newWidgets,
|
|
112
|
+
newWidths
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
const deleteWidget = (filteredWidgets, columnWidths)=>{
|
|
116
|
+
const widgetRows = widgetLayout.calculateWidgetRows(filteredWidgets, columnWidths);
|
|
117
|
+
return (widgetId)=>{
|
|
118
|
+
const { [widgetId]: _removed, ...newWidths } = columnWidths;
|
|
119
|
+
// Find the row containing the deleted widget
|
|
120
|
+
const deletedWidgetIndex = filteredWidgets.findIndex((w)=>w.uid === widgetId);
|
|
121
|
+
if (deletedWidgetIndex === -1) return {
|
|
122
|
+
newWidgets: filteredWidgets,
|
|
123
|
+
newWidths
|
|
124
|
+
};
|
|
125
|
+
const affectedRow = widgetRows.find((row)=>deletedWidgetIndex >= row.startIndex && deletedWidgetIndex <= row.endIndex);
|
|
126
|
+
// Use resizeRowAfterRemoval to resize the affected row
|
|
127
|
+
const finalWidths = widgetLayout.resizeRowAfterRemoval(affectedRow, widgetId, newWidths);
|
|
128
|
+
const newWidgets = filteredWidgets.filter((w)=>w.uid !== widgetId);
|
|
129
|
+
return {
|
|
130
|
+
newWidgets,
|
|
131
|
+
newWidths: finalWidths
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
const addWidget = (filteredWidgets, columnWidths)=>{
|
|
136
|
+
return (widget)=>{
|
|
137
|
+
// Check if widget is already added
|
|
138
|
+
const index = filteredWidgets.findIndex((w)=>w.uid === widget.uid);
|
|
139
|
+
if (index !== -1) return {
|
|
140
|
+
newWidgets: filteredWidgets,
|
|
141
|
+
newWidths: columnWidths
|
|
142
|
+
};
|
|
143
|
+
const newWidgets = [
|
|
144
|
+
...filteredWidgets,
|
|
145
|
+
widget
|
|
146
|
+
];
|
|
147
|
+
const newWidths = {
|
|
148
|
+
...columnWidths
|
|
149
|
+
};
|
|
150
|
+
// New widget always takes full width in its own row
|
|
151
|
+
newWidths[widget.uid] = widgetLayout.WIDGET_SIZING.TOTAL_COLUMNS;
|
|
152
|
+
return {
|
|
153
|
+
newWidgets,
|
|
154
|
+
newWidths
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
const handleWidgetResize = ({ filteredWidgets, columnWidths, leftWidgetId, rightWidgetId, newLeftWidth, newRightWidth })=>{
|
|
159
|
+
// Check if widgets can be resized (adjacent, same row, valid sizes)
|
|
160
|
+
if (!widgetLayout.canResizeBetweenWidgets(leftWidgetId, rightWidgetId, columnWidths, filteredWidgets)) {
|
|
161
|
+
return columnWidths;
|
|
162
|
+
}
|
|
163
|
+
if (!widgetLayout.isValidResizeOperation(newLeftWidth, newRightWidth)) {
|
|
164
|
+
// Resize would violate constraints, don't allow it
|
|
165
|
+
return columnWidths;
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
...columnWidths,
|
|
169
|
+
[leftWidgetId]: newLeftWidth,
|
|
170
|
+
[rightWidgetId]: newRightWidth
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
const useWidgets = ({ filteredWidgets, setFilteredWidgets })=>{
|
|
174
|
+
const [columnWidths, setColumnWidths] = React__namespace.useState({});
|
|
175
|
+
const [isDraggingWidget, setIsDraggingWidget] = React__namespace.useState(false);
|
|
176
|
+
const [draggedWidgetId, setDraggedWidgetId] = React__namespace.useState();
|
|
177
|
+
const [updateHomepageLayout] = homepage.useUpdateHomepageLayoutMutation();
|
|
178
|
+
const { toggleNotification } = Notifications.useNotification();
|
|
179
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler.useAPIErrorHandler();
|
|
180
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
181
|
+
const findWidgetFn = (widgetId)=>findWidget(filteredWidgets, widgetId);
|
|
182
|
+
const moveWidgetFn = (widgetId, insertIndex, targetRowIndex, isHorizontalDrop)=>{
|
|
183
|
+
const result = moveWidget({
|
|
184
|
+
filteredWidgets,
|
|
185
|
+
columnWidths,
|
|
186
|
+
widgetId,
|
|
187
|
+
insertIndex,
|
|
188
|
+
targetRowIndex,
|
|
189
|
+
isHorizontalDrop
|
|
190
|
+
});
|
|
191
|
+
setFilteredWidgets(result.newWidgets);
|
|
192
|
+
setColumnWidths(result.newWidths);
|
|
193
|
+
saveLayout({
|
|
194
|
+
widgets: result.newWidgets,
|
|
195
|
+
widths: result.newWidths,
|
|
196
|
+
updateHomepageLayout,
|
|
197
|
+
toggleNotification,
|
|
198
|
+
formatAPIError,
|
|
199
|
+
formatMessage
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
const deleteWidgetFn = (widgetId)=>{
|
|
203
|
+
const deleteWidgetOperation = deleteWidget(filteredWidgets, columnWidths);
|
|
204
|
+
const result = deleteWidgetOperation(widgetId);
|
|
205
|
+
setFilteredWidgets(result.newWidgets);
|
|
206
|
+
setColumnWidths(result.newWidths);
|
|
207
|
+
saveLayout({
|
|
208
|
+
widgets: result.newWidgets,
|
|
209
|
+
widths: result.newWidths,
|
|
210
|
+
updateHomepageLayout,
|
|
211
|
+
toggleNotification,
|
|
212
|
+
formatAPIError,
|
|
213
|
+
formatMessage
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
const addWidgetFn = (widget)=>{
|
|
217
|
+
const addWidgetOperation = addWidget(filteredWidgets, columnWidths);
|
|
218
|
+
const result = addWidgetOperation(widget);
|
|
219
|
+
setFilteredWidgets(result.newWidgets);
|
|
220
|
+
setColumnWidths(result.newWidths);
|
|
221
|
+
saveLayout({
|
|
222
|
+
widgets: result.newWidgets,
|
|
223
|
+
widths: result.newWidths,
|
|
224
|
+
updateHomepageLayout,
|
|
225
|
+
toggleNotification,
|
|
226
|
+
formatAPIError,
|
|
227
|
+
formatMessage
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
const handleWidgetResizeFn = (leftWidgetId, rightWidgetId, newLeftWidth, newRightWidth)=>{
|
|
231
|
+
const newWidths = handleWidgetResize({
|
|
232
|
+
filteredWidgets,
|
|
233
|
+
columnWidths,
|
|
234
|
+
leftWidgetId,
|
|
235
|
+
rightWidgetId,
|
|
236
|
+
newLeftWidth,
|
|
237
|
+
newRightWidth
|
|
238
|
+
});
|
|
239
|
+
setColumnWidths(newWidths);
|
|
240
|
+
};
|
|
241
|
+
const handleDragStart = React__namespace.useCallback((widgetId)=>{
|
|
242
|
+
setIsDraggingWidget(true);
|
|
243
|
+
setDraggedWidgetId(widgetId);
|
|
244
|
+
}, []);
|
|
245
|
+
const handleDragEnd = React__namespace.useCallback(()=>{
|
|
246
|
+
setIsDraggingWidget(false);
|
|
247
|
+
setDraggedWidgetId(undefined);
|
|
248
|
+
}, []);
|
|
249
|
+
const saveLayoutFn = ()=>{
|
|
250
|
+
saveLayout({
|
|
251
|
+
widgets: filteredWidgets,
|
|
252
|
+
widths: columnWidths,
|
|
253
|
+
updateHomepageLayout,
|
|
254
|
+
toggleNotification,
|
|
255
|
+
formatAPIError,
|
|
256
|
+
formatMessage
|
|
257
|
+
});
|
|
258
|
+
};
|
|
259
|
+
return {
|
|
260
|
+
findWidget: findWidgetFn,
|
|
261
|
+
deleteWidget: deleteWidgetFn,
|
|
262
|
+
addWidget: addWidgetFn,
|
|
263
|
+
moveWidget: moveWidgetFn,
|
|
264
|
+
columnWidths,
|
|
265
|
+
setColumnWidths,
|
|
266
|
+
handleWidgetResize: handleWidgetResizeFn,
|
|
267
|
+
saveLayout: saveLayoutFn,
|
|
268
|
+
isDraggingWidget,
|
|
269
|
+
draggedWidgetId,
|
|
270
|
+
handleDragStart,
|
|
271
|
+
handleDragEnd
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
exports.useWidgets = useWidgets;
|
|
276
|
+
//# sourceMappingURL=Widgets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Widgets.js","sources":["../../../../../admin/src/features/Widgets.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useIntl } from 'react-intl';\n\nimport { useAPIErrorHandler } from '../hooks/useAPIErrorHandler';\nimport { useUpdateHomepageLayoutMutation } from '../services/homepage';\nimport {\n calculateWidgetRows,\n moveWidgetInArray,\n findRowContainingWidget,\n resizeRowAfterRemoval,\n resizeRowAfterAddition,\n isValidResizeOperation,\n canResizeBetweenWidgets,\n WIDGET_SIZING,\n} from '../utils/widgetLayout';\n\nimport { useNotification } from './Notifications';\n\nimport type { WidgetWithUID } from '../core/apis/Widgets';\nimport type { WidgetType } from '@strapi/admin/strapi-admin';\n\nexport interface WidgetInfo {\n widget: WidgetType | undefined;\n index: number;\n}\n\nexport type FindWidgetFunction = (id: string) => WidgetInfo;\nexport type WidgetIdFunction = (id: string) => void;\nexport type DragEndFunction = () => void;\n\ninterface BaseWidgetContext {\n filteredWidgets: WidgetWithUID[];\n columnWidths: Record<string, number>;\n}\n\ninterface MoveWidgetOptions extends BaseWidgetContext {\n widgetId: string;\n insertIndex: number;\n targetRowIndex?: number;\n isHorizontalDrop?: boolean;\n}\n\ninterface SaveLayoutOptions {\n widgets: WidgetWithUID[];\n widths: Record<string, number>;\n updateHomepageLayout: (data: {\n widgets: Array<{ uid: string; width: (typeof WIDGET_SIZING.DISCRETE_SIZES)[number] }>;\n }) => Promise<any>;\n toggleNotification: (config: { type: 'danger'; message: string }) => void;\n formatAPIError: (error: any) => string;\n formatMessage: (descriptor: { id: string; defaultMessage: string }) => string;\n}\n\ninterface HandleWidgetResizeOptions extends BaseWidgetContext {\n leftWidgetId: string;\n rightWidgetId: string;\n newLeftWidth: number;\n newRightWidth: number;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Widget Management\n * -----------------------------------------------------------------------------------------------*/\n\nconst findWidget = (filteredWidgets: WidgetWithUID[], widgetId: string): WidgetInfo => {\n const widget = filteredWidgets.find((c) => `${c.uid}` === widgetId);\n if (!widget) {\n return {\n widget: undefined,\n index: -1,\n };\n }\n return {\n widget,\n index: filteredWidgets.indexOf(widget),\n };\n};\n\nconst saveLayout = async ({\n widgets,\n widths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n}: SaveLayoutOptions) => {\n try {\n const layoutData = {\n widgets: widgets.map((widget) => ({\n uid: widget.uid,\n width: (widths[widget.uid] ||\n WIDGET_SIZING.TOTAL_COLUMNS) as (typeof WIDGET_SIZING.DISCRETE_SIZES)[number],\n })),\n };\n\n const res = await updateHomepageLayout(layoutData);\n\n if ('error' in res) {\n toggleNotification({\n type: 'danger',\n message: formatAPIError(res.error),\n });\n }\n } catch {\n toggleNotification({\n type: 'danger',\n message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occured' }),\n });\n }\n};\n\nconst moveWidget = ({\n filteredWidgets,\n columnWidths,\n widgetId,\n insertIndex,\n targetRowIndex,\n isHorizontalDrop,\n}: MoveWidgetOptions) => {\n const widget = filteredWidgets.find((w) => w.uid === widgetId);\n if (!widget) return { newWidgets: filteredWidgets, newWidths: columnWidths };\n\n const widgetRows = calculateWidgetRows(filteredWidgets, columnWidths);\n\n // Move widget in the array\n const newWidgets = moveWidgetInArray(filteredWidgets, widgetId, insertIndex);\n\n // Calculate optimal widths for both source and target rows\n const newWidths = { ...columnWidths };\n\n // Find the source row (where the widget was removed from)\n const sourceRow = findRowContainingWidget(widgetRows, widgetId, filteredWidgets);\n\n if (isHorizontalDrop) {\n // This is a horizontal drop zone - widget gets full width in its own row\n newWidths[widgetId] = WIDGET_SIZING.TOTAL_COLUMNS;\n\n // Resize source row (after widget removal)\n const sourceRowResize = resizeRowAfterRemoval(sourceRow, widgetId, newWidths);\n Object.assign(newWidths, sourceRowResize);\n } else {\n // This is a vertical drop zone within a row\n const targetRow = widgetRows[targetRowIndex!];\n\n // Check if we're reordering within the same row\n const isSameRowReorder =\n sourceRow && targetRow && sourceRow.startIndex === targetRow.startIndex;\n\n if (isSameRowReorder) {\n // For same-row reordering, just preserve the existing widths\n return { newWidgets, newWidths };\n }\n\n // Different rows - resize both source and target rows\n // Resize source row (after widget removal)\n const sourceRowResize = resizeRowAfterRemoval(sourceRow, widgetId, newWidths);\n Object.assign(newWidths, sourceRowResize);\n\n // Resize target row (after widget addition)\n const targetRowResize = resizeRowAfterAddition(targetRow, widget, insertIndex, newWidths);\n Object.assign(newWidths, targetRowResize);\n }\n\n return { newWidgets, newWidths };\n};\n\nconst deleteWidget = (filteredWidgets: WidgetWithUID[], columnWidths: Record<string, number>) => {\n const widgetRows = calculateWidgetRows(filteredWidgets, columnWidths);\n\n return (widgetId: string) => {\n const { [widgetId]: _removed, ...newWidths } = columnWidths;\n\n // Find the row containing the deleted widget\n const deletedWidgetIndex = filteredWidgets.findIndex((w) => w.uid === widgetId);\n if (deletedWidgetIndex === -1) return { newWidgets: filteredWidgets, newWidths };\n const affectedRow = widgetRows.find(\n (row) => deletedWidgetIndex >= row.startIndex && deletedWidgetIndex <= row.endIndex\n );\n\n // Use resizeRowAfterRemoval to resize the affected row\n const finalWidths = resizeRowAfterRemoval(affectedRow, widgetId, newWidths);\n const newWidgets = filteredWidgets.filter((w) => w.uid !== widgetId);\n\n return { newWidgets, newWidths: finalWidths };\n };\n};\n\nconst addWidget = (filteredWidgets: WidgetWithUID[], columnWidths: Record<string, number>) => {\n return (widget: WidgetWithUID) => {\n // Check if widget is already added\n const index = filteredWidgets.findIndex((w) => w.uid === widget.uid);\n if (index !== -1) return { newWidgets: filteredWidgets, newWidths: columnWidths };\n\n const newWidgets = [...filteredWidgets, widget];\n const newWidths = { ...columnWidths };\n // New widget always takes full width in its own row\n newWidths[widget.uid] = WIDGET_SIZING.TOTAL_COLUMNS;\n\n return { newWidgets, newWidths };\n };\n};\n\nconst handleWidgetResize = ({\n filteredWidgets,\n columnWidths,\n leftWidgetId,\n rightWidgetId,\n newLeftWidth,\n newRightWidth,\n}: HandleWidgetResizeOptions) => {\n // Check if widgets can be resized (adjacent, same row, valid sizes)\n if (!canResizeBetweenWidgets(leftWidgetId, rightWidgetId, columnWidths, filteredWidgets)) {\n return columnWidths;\n }\n\n if (!isValidResizeOperation(newLeftWidth, newRightWidth)) {\n // Resize would violate constraints, don't allow it\n return columnWidths;\n }\n\n return {\n ...columnWidths,\n [leftWidgetId]: newLeftWidth,\n [rightWidgetId]: newRightWidth,\n };\n};\n\ninterface UseWidgetsOptions {\n filteredWidgets: WidgetWithUID[];\n setFilteredWidgets: (\n widgets: WidgetWithUID[] | ((prev: WidgetWithUID[]) => WidgetWithUID[])\n ) => void;\n}\n\nexport const useWidgets = ({ filteredWidgets, setFilteredWidgets }: UseWidgetsOptions) => {\n const [columnWidths, setColumnWidths] = React.useState<Record<string, number>>({});\n const [isDraggingWidget, setIsDraggingWidget] = React.useState(false);\n const [draggedWidgetId, setDraggedWidgetId] = React.useState<string | undefined>();\n\n const [updateHomepageLayout] = useUpdateHomepageLayoutMutation();\n const { toggleNotification } = useNotification();\n const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();\n const { formatMessage } = useIntl();\n\n const findWidgetFn: FindWidgetFunction = (widgetId: string) =>\n findWidget(filteredWidgets, widgetId);\n\n const moveWidgetFn = (\n widgetId: string,\n insertIndex: number,\n targetRowIndex?: number,\n isHorizontalDrop?: boolean\n ) => {\n const result = moveWidget({\n filteredWidgets,\n columnWidths,\n widgetId,\n insertIndex,\n targetRowIndex,\n isHorizontalDrop,\n });\n\n setFilteredWidgets(result.newWidgets);\n setColumnWidths(result.newWidths);\n\n saveLayout({\n widgets: result.newWidgets,\n widths: result.newWidths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n });\n };\n\n const deleteWidgetFn: WidgetIdFunction = (widgetId: string) => {\n const deleteWidgetOperation = deleteWidget(filteredWidgets, columnWidths);\n const result = deleteWidgetOperation(widgetId);\n\n setFilteredWidgets(result.newWidgets);\n setColumnWidths(result.newWidths);\n\n saveLayout({\n widgets: result.newWidgets,\n widths: result.newWidths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n });\n };\n\n const addWidgetFn = (widget: WidgetWithUID) => {\n const addWidgetOperation = addWidget(filteredWidgets, columnWidths);\n const result = addWidgetOperation(widget);\n\n setFilteredWidgets(result.newWidgets);\n setColumnWidths(result.newWidths);\n\n saveLayout({\n widgets: result.newWidgets,\n widths: result.newWidths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n });\n };\n\n const handleWidgetResizeFn = (\n leftWidgetId: string,\n rightWidgetId: string,\n newLeftWidth: number,\n newRightWidth: number\n ) => {\n const newWidths = handleWidgetResize({\n filteredWidgets,\n columnWidths,\n leftWidgetId,\n rightWidgetId,\n newLeftWidth,\n newRightWidth,\n });\n\n setColumnWidths(newWidths);\n };\n\n const handleDragStart: WidgetIdFunction = React.useCallback((widgetId: string) => {\n setIsDraggingWidget(true);\n setDraggedWidgetId(widgetId);\n }, []);\n\n const handleDragEnd: DragEndFunction = React.useCallback(() => {\n setIsDraggingWidget(false);\n setDraggedWidgetId(undefined);\n }, []);\n\n const saveLayoutFn = () => {\n saveLayout({\n widgets: filteredWidgets,\n widths: columnWidths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n });\n };\n\n return {\n findWidget: findWidgetFn,\n deleteWidget: deleteWidgetFn,\n addWidget: addWidgetFn,\n moveWidget: moveWidgetFn,\n columnWidths,\n setColumnWidths,\n handleWidgetResize: handleWidgetResizeFn,\n saveLayout: saveLayoutFn,\n isDraggingWidget,\n draggedWidgetId,\n handleDragStart,\n handleDragEnd,\n };\n};\n"],"names":["findWidget","filteredWidgets","widgetId","widget","find","c","uid","undefined","index","indexOf","saveLayout","widgets","widths","updateHomepageLayout","toggleNotification","formatAPIError","formatMessage","layoutData","map","width","WIDGET_SIZING","TOTAL_COLUMNS","res","type","message","error","id","defaultMessage","moveWidget","columnWidths","insertIndex","targetRowIndex","isHorizontalDrop","w","newWidgets","newWidths","widgetRows","calculateWidgetRows","moveWidgetInArray","sourceRow","findRowContainingWidget","sourceRowResize","resizeRowAfterRemoval","Object","assign","targetRow","isSameRowReorder","startIndex","targetRowResize","resizeRowAfterAddition","deleteWidget","_removed","deletedWidgetIndex","findIndex","affectedRow","row","endIndex","finalWidths","filter","addWidget","handleWidgetResize","leftWidgetId","rightWidgetId","newLeftWidth","newRightWidth","canResizeBetweenWidgets","isValidResizeOperation","useWidgets","setFilteredWidgets","setColumnWidths","React","useState","isDraggingWidget","setIsDraggingWidget","draggedWidgetId","setDraggedWidgetId","useUpdateHomepageLayoutMutation","useNotification","_unstableFormatAPIError","useAPIErrorHandler","useIntl","findWidgetFn","moveWidgetFn","result","deleteWidgetFn","deleteWidgetOperation","addWidgetFn","addWidgetOperation","handleWidgetResizeFn","handleDragStart","useCallback","handleDragEnd","saveLayoutFn"],"mappings":"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"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import { useAPIErrorHandler } from '../hooks/useAPIErrorHandler.mjs';
|
|
4
|
+
import { useUpdateHomepageLayoutMutation } from '../services/homepage.mjs';
|
|
5
|
+
import { WIDGET_SIZING, calculateWidgetRows, moveWidgetInArray, findRowContainingWidget, resizeRowAfterRemoval, resizeRowAfterAddition, canResizeBetweenWidgets, isValidResizeOperation } from '../utils/widgetLayout.mjs';
|
|
6
|
+
import { useNotification } from './Notifications.mjs';
|
|
7
|
+
|
|
8
|
+
/* -------------------------------------------------------------------------------------------------
|
|
9
|
+
* Widget Management
|
|
10
|
+
* -----------------------------------------------------------------------------------------------*/ const findWidget = (filteredWidgets, widgetId)=>{
|
|
11
|
+
const widget = filteredWidgets.find((c)=>`${c.uid}` === widgetId);
|
|
12
|
+
if (!widget) {
|
|
13
|
+
return {
|
|
14
|
+
widget: undefined,
|
|
15
|
+
index: -1
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
widget,
|
|
20
|
+
index: filteredWidgets.indexOf(widget)
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
const saveLayout = async ({ widgets, widths, updateHomepageLayout, toggleNotification, formatAPIError, formatMessage })=>{
|
|
24
|
+
try {
|
|
25
|
+
const layoutData = {
|
|
26
|
+
widgets: widgets.map((widget)=>({
|
|
27
|
+
uid: widget.uid,
|
|
28
|
+
width: widths[widget.uid] || WIDGET_SIZING.TOTAL_COLUMNS
|
|
29
|
+
}))
|
|
30
|
+
};
|
|
31
|
+
const res = await updateHomepageLayout(layoutData);
|
|
32
|
+
if ('error' in res) {
|
|
33
|
+
toggleNotification({
|
|
34
|
+
type: 'danger',
|
|
35
|
+
message: formatAPIError(res.error)
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
toggleNotification({
|
|
40
|
+
type: 'danger',
|
|
41
|
+
message: formatMessage({
|
|
42
|
+
id: 'notification.error',
|
|
43
|
+
defaultMessage: 'An error occured'
|
|
44
|
+
})
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const moveWidget = ({ filteredWidgets, columnWidths, widgetId, insertIndex, targetRowIndex, isHorizontalDrop })=>{
|
|
49
|
+
const widget = filteredWidgets.find((w)=>w.uid === widgetId);
|
|
50
|
+
if (!widget) return {
|
|
51
|
+
newWidgets: filteredWidgets,
|
|
52
|
+
newWidths: columnWidths
|
|
53
|
+
};
|
|
54
|
+
const widgetRows = calculateWidgetRows(filteredWidgets, columnWidths);
|
|
55
|
+
// Move widget in the array
|
|
56
|
+
const newWidgets = moveWidgetInArray(filteredWidgets, widgetId, insertIndex);
|
|
57
|
+
// Calculate optimal widths for both source and target rows
|
|
58
|
+
const newWidths = {
|
|
59
|
+
...columnWidths
|
|
60
|
+
};
|
|
61
|
+
// Find the source row (where the widget was removed from)
|
|
62
|
+
const sourceRow = findRowContainingWidget(widgetRows, widgetId, filteredWidgets);
|
|
63
|
+
if (isHorizontalDrop) {
|
|
64
|
+
// This is a horizontal drop zone - widget gets full width in its own row
|
|
65
|
+
newWidths[widgetId] = WIDGET_SIZING.TOTAL_COLUMNS;
|
|
66
|
+
// Resize source row (after widget removal)
|
|
67
|
+
const sourceRowResize = resizeRowAfterRemoval(sourceRow, widgetId, newWidths);
|
|
68
|
+
Object.assign(newWidths, sourceRowResize);
|
|
69
|
+
} else {
|
|
70
|
+
// This is a vertical drop zone within a row
|
|
71
|
+
const targetRow = widgetRows[targetRowIndex];
|
|
72
|
+
// Check if we're reordering within the same row
|
|
73
|
+
const isSameRowReorder = sourceRow && targetRow && sourceRow.startIndex === targetRow.startIndex;
|
|
74
|
+
if (isSameRowReorder) {
|
|
75
|
+
// For same-row reordering, just preserve the existing widths
|
|
76
|
+
return {
|
|
77
|
+
newWidgets,
|
|
78
|
+
newWidths
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// Different rows - resize both source and target rows
|
|
82
|
+
// Resize source row (after widget removal)
|
|
83
|
+
const sourceRowResize = resizeRowAfterRemoval(sourceRow, widgetId, newWidths);
|
|
84
|
+
Object.assign(newWidths, sourceRowResize);
|
|
85
|
+
// Resize target row (after widget addition)
|
|
86
|
+
const targetRowResize = resizeRowAfterAddition(targetRow, widget, insertIndex, newWidths);
|
|
87
|
+
Object.assign(newWidths, targetRowResize);
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
newWidgets,
|
|
91
|
+
newWidths
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
const deleteWidget = (filteredWidgets, columnWidths)=>{
|
|
95
|
+
const widgetRows = calculateWidgetRows(filteredWidgets, columnWidths);
|
|
96
|
+
return (widgetId)=>{
|
|
97
|
+
const { [widgetId]: _removed, ...newWidths } = columnWidths;
|
|
98
|
+
// Find the row containing the deleted widget
|
|
99
|
+
const deletedWidgetIndex = filteredWidgets.findIndex((w)=>w.uid === widgetId);
|
|
100
|
+
if (deletedWidgetIndex === -1) return {
|
|
101
|
+
newWidgets: filteredWidgets,
|
|
102
|
+
newWidths
|
|
103
|
+
};
|
|
104
|
+
const affectedRow = widgetRows.find((row)=>deletedWidgetIndex >= row.startIndex && deletedWidgetIndex <= row.endIndex);
|
|
105
|
+
// Use resizeRowAfterRemoval to resize the affected row
|
|
106
|
+
const finalWidths = resizeRowAfterRemoval(affectedRow, widgetId, newWidths);
|
|
107
|
+
const newWidgets = filteredWidgets.filter((w)=>w.uid !== widgetId);
|
|
108
|
+
return {
|
|
109
|
+
newWidgets,
|
|
110
|
+
newWidths: finalWidths
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
const addWidget = (filteredWidgets, columnWidths)=>{
|
|
115
|
+
return (widget)=>{
|
|
116
|
+
// Check if widget is already added
|
|
117
|
+
const index = filteredWidgets.findIndex((w)=>w.uid === widget.uid);
|
|
118
|
+
if (index !== -1) return {
|
|
119
|
+
newWidgets: filteredWidgets,
|
|
120
|
+
newWidths: columnWidths
|
|
121
|
+
};
|
|
122
|
+
const newWidgets = [
|
|
123
|
+
...filteredWidgets,
|
|
124
|
+
widget
|
|
125
|
+
];
|
|
126
|
+
const newWidths = {
|
|
127
|
+
...columnWidths
|
|
128
|
+
};
|
|
129
|
+
// New widget always takes full width in its own row
|
|
130
|
+
newWidths[widget.uid] = WIDGET_SIZING.TOTAL_COLUMNS;
|
|
131
|
+
return {
|
|
132
|
+
newWidgets,
|
|
133
|
+
newWidths
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
const handleWidgetResize = ({ filteredWidgets, columnWidths, leftWidgetId, rightWidgetId, newLeftWidth, newRightWidth })=>{
|
|
138
|
+
// Check if widgets can be resized (adjacent, same row, valid sizes)
|
|
139
|
+
if (!canResizeBetweenWidgets(leftWidgetId, rightWidgetId, columnWidths, filteredWidgets)) {
|
|
140
|
+
return columnWidths;
|
|
141
|
+
}
|
|
142
|
+
if (!isValidResizeOperation(newLeftWidth, newRightWidth)) {
|
|
143
|
+
// Resize would violate constraints, don't allow it
|
|
144
|
+
return columnWidths;
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
...columnWidths,
|
|
148
|
+
[leftWidgetId]: newLeftWidth,
|
|
149
|
+
[rightWidgetId]: newRightWidth
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
const useWidgets = ({ filteredWidgets, setFilteredWidgets })=>{
|
|
153
|
+
const [columnWidths, setColumnWidths] = React.useState({});
|
|
154
|
+
const [isDraggingWidget, setIsDraggingWidget] = React.useState(false);
|
|
155
|
+
const [draggedWidgetId, setDraggedWidgetId] = React.useState();
|
|
156
|
+
const [updateHomepageLayout] = useUpdateHomepageLayoutMutation();
|
|
157
|
+
const { toggleNotification } = useNotification();
|
|
158
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
|
159
|
+
const { formatMessage } = useIntl();
|
|
160
|
+
const findWidgetFn = (widgetId)=>findWidget(filteredWidgets, widgetId);
|
|
161
|
+
const moveWidgetFn = (widgetId, insertIndex, targetRowIndex, isHorizontalDrop)=>{
|
|
162
|
+
const result = moveWidget({
|
|
163
|
+
filteredWidgets,
|
|
164
|
+
columnWidths,
|
|
165
|
+
widgetId,
|
|
166
|
+
insertIndex,
|
|
167
|
+
targetRowIndex,
|
|
168
|
+
isHorizontalDrop
|
|
169
|
+
});
|
|
170
|
+
setFilteredWidgets(result.newWidgets);
|
|
171
|
+
setColumnWidths(result.newWidths);
|
|
172
|
+
saveLayout({
|
|
173
|
+
widgets: result.newWidgets,
|
|
174
|
+
widths: result.newWidths,
|
|
175
|
+
updateHomepageLayout,
|
|
176
|
+
toggleNotification,
|
|
177
|
+
formatAPIError,
|
|
178
|
+
formatMessage
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
const deleteWidgetFn = (widgetId)=>{
|
|
182
|
+
const deleteWidgetOperation = deleteWidget(filteredWidgets, columnWidths);
|
|
183
|
+
const result = deleteWidgetOperation(widgetId);
|
|
184
|
+
setFilteredWidgets(result.newWidgets);
|
|
185
|
+
setColumnWidths(result.newWidths);
|
|
186
|
+
saveLayout({
|
|
187
|
+
widgets: result.newWidgets,
|
|
188
|
+
widths: result.newWidths,
|
|
189
|
+
updateHomepageLayout,
|
|
190
|
+
toggleNotification,
|
|
191
|
+
formatAPIError,
|
|
192
|
+
formatMessage
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
const addWidgetFn = (widget)=>{
|
|
196
|
+
const addWidgetOperation = addWidget(filteredWidgets, columnWidths);
|
|
197
|
+
const result = addWidgetOperation(widget);
|
|
198
|
+
setFilteredWidgets(result.newWidgets);
|
|
199
|
+
setColumnWidths(result.newWidths);
|
|
200
|
+
saveLayout({
|
|
201
|
+
widgets: result.newWidgets,
|
|
202
|
+
widths: result.newWidths,
|
|
203
|
+
updateHomepageLayout,
|
|
204
|
+
toggleNotification,
|
|
205
|
+
formatAPIError,
|
|
206
|
+
formatMessage
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
const handleWidgetResizeFn = (leftWidgetId, rightWidgetId, newLeftWidth, newRightWidth)=>{
|
|
210
|
+
const newWidths = handleWidgetResize({
|
|
211
|
+
filteredWidgets,
|
|
212
|
+
columnWidths,
|
|
213
|
+
leftWidgetId,
|
|
214
|
+
rightWidgetId,
|
|
215
|
+
newLeftWidth,
|
|
216
|
+
newRightWidth
|
|
217
|
+
});
|
|
218
|
+
setColumnWidths(newWidths);
|
|
219
|
+
};
|
|
220
|
+
const handleDragStart = React.useCallback((widgetId)=>{
|
|
221
|
+
setIsDraggingWidget(true);
|
|
222
|
+
setDraggedWidgetId(widgetId);
|
|
223
|
+
}, []);
|
|
224
|
+
const handleDragEnd = React.useCallback(()=>{
|
|
225
|
+
setIsDraggingWidget(false);
|
|
226
|
+
setDraggedWidgetId(undefined);
|
|
227
|
+
}, []);
|
|
228
|
+
const saveLayoutFn = ()=>{
|
|
229
|
+
saveLayout({
|
|
230
|
+
widgets: filteredWidgets,
|
|
231
|
+
widths: columnWidths,
|
|
232
|
+
updateHomepageLayout,
|
|
233
|
+
toggleNotification,
|
|
234
|
+
formatAPIError,
|
|
235
|
+
formatMessage
|
|
236
|
+
});
|
|
237
|
+
};
|
|
238
|
+
return {
|
|
239
|
+
findWidget: findWidgetFn,
|
|
240
|
+
deleteWidget: deleteWidgetFn,
|
|
241
|
+
addWidget: addWidgetFn,
|
|
242
|
+
moveWidget: moveWidgetFn,
|
|
243
|
+
columnWidths,
|
|
244
|
+
setColumnWidths,
|
|
245
|
+
handleWidgetResize: handleWidgetResizeFn,
|
|
246
|
+
saveLayout: saveLayoutFn,
|
|
247
|
+
isDraggingWidget,
|
|
248
|
+
draggedWidgetId,
|
|
249
|
+
handleDragStart,
|
|
250
|
+
handleDragEnd
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
export { useWidgets };
|
|
255
|
+
//# sourceMappingURL=Widgets.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Widgets.mjs","sources":["../../../../../admin/src/features/Widgets.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useIntl } from 'react-intl';\n\nimport { useAPIErrorHandler } from '../hooks/useAPIErrorHandler';\nimport { useUpdateHomepageLayoutMutation } from '../services/homepage';\nimport {\n calculateWidgetRows,\n moveWidgetInArray,\n findRowContainingWidget,\n resizeRowAfterRemoval,\n resizeRowAfterAddition,\n isValidResizeOperation,\n canResizeBetweenWidgets,\n WIDGET_SIZING,\n} from '../utils/widgetLayout';\n\nimport { useNotification } from './Notifications';\n\nimport type { WidgetWithUID } from '../core/apis/Widgets';\nimport type { WidgetType } from '@strapi/admin/strapi-admin';\n\nexport interface WidgetInfo {\n widget: WidgetType | undefined;\n index: number;\n}\n\nexport type FindWidgetFunction = (id: string) => WidgetInfo;\nexport type WidgetIdFunction = (id: string) => void;\nexport type DragEndFunction = () => void;\n\ninterface BaseWidgetContext {\n filteredWidgets: WidgetWithUID[];\n columnWidths: Record<string, number>;\n}\n\ninterface MoveWidgetOptions extends BaseWidgetContext {\n widgetId: string;\n insertIndex: number;\n targetRowIndex?: number;\n isHorizontalDrop?: boolean;\n}\n\ninterface SaveLayoutOptions {\n widgets: WidgetWithUID[];\n widths: Record<string, number>;\n updateHomepageLayout: (data: {\n widgets: Array<{ uid: string; width: (typeof WIDGET_SIZING.DISCRETE_SIZES)[number] }>;\n }) => Promise<any>;\n toggleNotification: (config: { type: 'danger'; message: string }) => void;\n formatAPIError: (error: any) => string;\n formatMessage: (descriptor: { id: string; defaultMessage: string }) => string;\n}\n\ninterface HandleWidgetResizeOptions extends BaseWidgetContext {\n leftWidgetId: string;\n rightWidgetId: string;\n newLeftWidth: number;\n newRightWidth: number;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Widget Management\n * -----------------------------------------------------------------------------------------------*/\n\nconst findWidget = (filteredWidgets: WidgetWithUID[], widgetId: string): WidgetInfo => {\n const widget = filteredWidgets.find((c) => `${c.uid}` === widgetId);\n if (!widget) {\n return {\n widget: undefined,\n index: -1,\n };\n }\n return {\n widget,\n index: filteredWidgets.indexOf(widget),\n };\n};\n\nconst saveLayout = async ({\n widgets,\n widths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n}: SaveLayoutOptions) => {\n try {\n const layoutData = {\n widgets: widgets.map((widget) => ({\n uid: widget.uid,\n width: (widths[widget.uid] ||\n WIDGET_SIZING.TOTAL_COLUMNS) as (typeof WIDGET_SIZING.DISCRETE_SIZES)[number],\n })),\n };\n\n const res = await updateHomepageLayout(layoutData);\n\n if ('error' in res) {\n toggleNotification({\n type: 'danger',\n message: formatAPIError(res.error),\n });\n }\n } catch {\n toggleNotification({\n type: 'danger',\n message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occured' }),\n });\n }\n};\n\nconst moveWidget = ({\n filteredWidgets,\n columnWidths,\n widgetId,\n insertIndex,\n targetRowIndex,\n isHorizontalDrop,\n}: MoveWidgetOptions) => {\n const widget = filteredWidgets.find((w) => w.uid === widgetId);\n if (!widget) return { newWidgets: filteredWidgets, newWidths: columnWidths };\n\n const widgetRows = calculateWidgetRows(filteredWidgets, columnWidths);\n\n // Move widget in the array\n const newWidgets = moveWidgetInArray(filteredWidgets, widgetId, insertIndex);\n\n // Calculate optimal widths for both source and target rows\n const newWidths = { ...columnWidths };\n\n // Find the source row (where the widget was removed from)\n const sourceRow = findRowContainingWidget(widgetRows, widgetId, filteredWidgets);\n\n if (isHorizontalDrop) {\n // This is a horizontal drop zone - widget gets full width in its own row\n newWidths[widgetId] = WIDGET_SIZING.TOTAL_COLUMNS;\n\n // Resize source row (after widget removal)\n const sourceRowResize = resizeRowAfterRemoval(sourceRow, widgetId, newWidths);\n Object.assign(newWidths, sourceRowResize);\n } else {\n // This is a vertical drop zone within a row\n const targetRow = widgetRows[targetRowIndex!];\n\n // Check if we're reordering within the same row\n const isSameRowReorder =\n sourceRow && targetRow && sourceRow.startIndex === targetRow.startIndex;\n\n if (isSameRowReorder) {\n // For same-row reordering, just preserve the existing widths\n return { newWidgets, newWidths };\n }\n\n // Different rows - resize both source and target rows\n // Resize source row (after widget removal)\n const sourceRowResize = resizeRowAfterRemoval(sourceRow, widgetId, newWidths);\n Object.assign(newWidths, sourceRowResize);\n\n // Resize target row (after widget addition)\n const targetRowResize = resizeRowAfterAddition(targetRow, widget, insertIndex, newWidths);\n Object.assign(newWidths, targetRowResize);\n }\n\n return { newWidgets, newWidths };\n};\n\nconst deleteWidget = (filteredWidgets: WidgetWithUID[], columnWidths: Record<string, number>) => {\n const widgetRows = calculateWidgetRows(filteredWidgets, columnWidths);\n\n return (widgetId: string) => {\n const { [widgetId]: _removed, ...newWidths } = columnWidths;\n\n // Find the row containing the deleted widget\n const deletedWidgetIndex = filteredWidgets.findIndex((w) => w.uid === widgetId);\n if (deletedWidgetIndex === -1) return { newWidgets: filteredWidgets, newWidths };\n const affectedRow = widgetRows.find(\n (row) => deletedWidgetIndex >= row.startIndex && deletedWidgetIndex <= row.endIndex\n );\n\n // Use resizeRowAfterRemoval to resize the affected row\n const finalWidths = resizeRowAfterRemoval(affectedRow, widgetId, newWidths);\n const newWidgets = filteredWidgets.filter((w) => w.uid !== widgetId);\n\n return { newWidgets, newWidths: finalWidths };\n };\n};\n\nconst addWidget = (filteredWidgets: WidgetWithUID[], columnWidths: Record<string, number>) => {\n return (widget: WidgetWithUID) => {\n // Check if widget is already added\n const index = filteredWidgets.findIndex((w) => w.uid === widget.uid);\n if (index !== -1) return { newWidgets: filteredWidgets, newWidths: columnWidths };\n\n const newWidgets = [...filteredWidgets, widget];\n const newWidths = { ...columnWidths };\n // New widget always takes full width in its own row\n newWidths[widget.uid] = WIDGET_SIZING.TOTAL_COLUMNS;\n\n return { newWidgets, newWidths };\n };\n};\n\nconst handleWidgetResize = ({\n filteredWidgets,\n columnWidths,\n leftWidgetId,\n rightWidgetId,\n newLeftWidth,\n newRightWidth,\n}: HandleWidgetResizeOptions) => {\n // Check if widgets can be resized (adjacent, same row, valid sizes)\n if (!canResizeBetweenWidgets(leftWidgetId, rightWidgetId, columnWidths, filteredWidgets)) {\n return columnWidths;\n }\n\n if (!isValidResizeOperation(newLeftWidth, newRightWidth)) {\n // Resize would violate constraints, don't allow it\n return columnWidths;\n }\n\n return {\n ...columnWidths,\n [leftWidgetId]: newLeftWidth,\n [rightWidgetId]: newRightWidth,\n };\n};\n\ninterface UseWidgetsOptions {\n filteredWidgets: WidgetWithUID[];\n setFilteredWidgets: (\n widgets: WidgetWithUID[] | ((prev: WidgetWithUID[]) => WidgetWithUID[])\n ) => void;\n}\n\nexport const useWidgets = ({ filteredWidgets, setFilteredWidgets }: UseWidgetsOptions) => {\n const [columnWidths, setColumnWidths] = React.useState<Record<string, number>>({});\n const [isDraggingWidget, setIsDraggingWidget] = React.useState(false);\n const [draggedWidgetId, setDraggedWidgetId] = React.useState<string | undefined>();\n\n const [updateHomepageLayout] = useUpdateHomepageLayoutMutation();\n const { toggleNotification } = useNotification();\n const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();\n const { formatMessage } = useIntl();\n\n const findWidgetFn: FindWidgetFunction = (widgetId: string) =>\n findWidget(filteredWidgets, widgetId);\n\n const moveWidgetFn = (\n widgetId: string,\n insertIndex: number,\n targetRowIndex?: number,\n isHorizontalDrop?: boolean\n ) => {\n const result = moveWidget({\n filteredWidgets,\n columnWidths,\n widgetId,\n insertIndex,\n targetRowIndex,\n isHorizontalDrop,\n });\n\n setFilteredWidgets(result.newWidgets);\n setColumnWidths(result.newWidths);\n\n saveLayout({\n widgets: result.newWidgets,\n widths: result.newWidths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n });\n };\n\n const deleteWidgetFn: WidgetIdFunction = (widgetId: string) => {\n const deleteWidgetOperation = deleteWidget(filteredWidgets, columnWidths);\n const result = deleteWidgetOperation(widgetId);\n\n setFilteredWidgets(result.newWidgets);\n setColumnWidths(result.newWidths);\n\n saveLayout({\n widgets: result.newWidgets,\n widths: result.newWidths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n });\n };\n\n const addWidgetFn = (widget: WidgetWithUID) => {\n const addWidgetOperation = addWidget(filteredWidgets, columnWidths);\n const result = addWidgetOperation(widget);\n\n setFilteredWidgets(result.newWidgets);\n setColumnWidths(result.newWidths);\n\n saveLayout({\n widgets: result.newWidgets,\n widths: result.newWidths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n });\n };\n\n const handleWidgetResizeFn = (\n leftWidgetId: string,\n rightWidgetId: string,\n newLeftWidth: number,\n newRightWidth: number\n ) => {\n const newWidths = handleWidgetResize({\n filteredWidgets,\n columnWidths,\n leftWidgetId,\n rightWidgetId,\n newLeftWidth,\n newRightWidth,\n });\n\n setColumnWidths(newWidths);\n };\n\n const handleDragStart: WidgetIdFunction = React.useCallback((widgetId: string) => {\n setIsDraggingWidget(true);\n setDraggedWidgetId(widgetId);\n }, []);\n\n const handleDragEnd: DragEndFunction = React.useCallback(() => {\n setIsDraggingWidget(false);\n setDraggedWidgetId(undefined);\n }, []);\n\n const saveLayoutFn = () => {\n saveLayout({\n widgets: filteredWidgets,\n widths: columnWidths,\n updateHomepageLayout,\n toggleNotification,\n formatAPIError,\n formatMessage,\n });\n };\n\n return {\n findWidget: findWidgetFn,\n deleteWidget: deleteWidgetFn,\n addWidget: addWidgetFn,\n moveWidget: moveWidgetFn,\n columnWidths,\n setColumnWidths,\n handleWidgetResize: handleWidgetResizeFn,\n saveLayout: saveLayoutFn,\n isDraggingWidget,\n draggedWidgetId,\n handleDragStart,\n handleDragEnd,\n };\n};\n"],"names":["findWidget","filteredWidgets","widgetId","widget","find","c","uid","undefined","index","indexOf","saveLayout","widgets","widths","updateHomepageLayout","toggleNotification","formatAPIError","formatMessage","layoutData","map","width","WIDGET_SIZING","TOTAL_COLUMNS","res","type","message","error","id","defaultMessage","moveWidget","columnWidths","insertIndex","targetRowIndex","isHorizontalDrop","w","newWidgets","newWidths","widgetRows","calculateWidgetRows","moveWidgetInArray","sourceRow","findRowContainingWidget","sourceRowResize","resizeRowAfterRemoval","Object","assign","targetRow","isSameRowReorder","startIndex","targetRowResize","resizeRowAfterAddition","deleteWidget","_removed","deletedWidgetIndex","findIndex","affectedRow","row","endIndex","finalWidths","filter","addWidget","handleWidgetResize","leftWidgetId","rightWidgetId","newLeftWidth","newRightWidth","canResizeBetweenWidgets","isValidResizeOperation","useWidgets","setFilteredWidgets","setColumnWidths","React","useState","isDraggingWidget","setIsDraggingWidget","draggedWidgetId","setDraggedWidgetId","useUpdateHomepageLayoutMutation","useNotification","_unstableFormatAPIError","useAPIErrorHandler","useIntl","findWidgetFn","moveWidgetFn","result","deleteWidgetFn","deleteWidgetOperation","addWidgetFn","addWidgetOperation","handleWidgetResizeFn","handleDragStart","useCallback","handleDragEnd","saveLayoutFn"],"mappings":"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"}
|
|
@@ -122,7 +122,7 @@ that has been thrown.
|
|
|
122
122
|
* There's a chance with SerializedErrors that the message is not set.
|
|
123
123
|
* In that case we return a generic error message.
|
|
124
124
|
*/ if (!error.message) {
|
|
125
|
-
return 'Unknown error
|
|
125
|
+
return 'Unknown error occurred.';
|
|
126
126
|
}
|
|
127
127
|
return formatError(err);
|
|
128
128
|
}, [
|