payload-nested-docs-page-tree 1.1.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/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/components/PageTreeContext.d.ts +15 -0
- package/dist/components/PageTreeContext.js +26 -0
- package/dist/components/PageTreeContext.js.map +1 -0
- package/dist/components/PageTreeListView.client.d.ts +17 -0
- package/dist/components/PageTreeListView.client.js +960 -0
- package/dist/components/PageTreeListView.client.js.map +1 -0
- package/dist/components/PageTreeListView.module.css +358 -0
- package/dist/components/PageTreeListView.server.d.ts +3 -0
- package/dist/components/PageTreeListView.server.js +390 -0
- package/dist/components/PageTreeListView.server.js.map +1 -0
- package/dist/components/PageTreeTitleCell.d.ts +6 -0
- package/dist/components/PageTreeTitleCell.js +80 -0
- package/dist/components/PageTreeTitleCell.js.map +1 -0
- package/dist/endpoints/createMovePageEndpoint.d.ts +5 -0
- package/dist/endpoints/createMovePageEndpoint.js +265 -0
- package/dist/endpoints/createMovePageEndpoint.js.map +1 -0
- package/dist/exports/client.d.ts +1 -0
- package/dist/exports/client.js +3 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/exports/rsc.js +3 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +142 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utilities/badgeConfig.d.ts +2 -0
- package/dist/utilities/badgeConfig.js +30 -0
- package/dist/utilities/badgeConfig.js.map +1 -0
- package/dist/utilities/dropTargets.d.ts +31 -0
- package/dist/utilities/dropTargets.js +73 -0
- package/dist/utilities/dropTargets.js.map +1 -0
- package/dist/utilities/moveValidation.d.ts +11 -0
- package/dist/utilities/moveValidation.js +44 -0
- package/dist/utilities/moveValidation.js.map +1 -0
- package/dist/utilities/pageTree.d.ts +37 -0
- package/dist/utilities/pageTree.js +300 -0
- package/dist/utilities/pageTree.js.map +1 -0
- package/dist/utilities/pageTreeCollision.d.ts +16 -0
- package/dist/utilities/pageTreeCollision.js +70 -0
- package/dist/utilities/pageTreeCollision.js.map +1 -0
- package/dist/utilities/pageTreeConfig.d.ts +3 -0
- package/dist/utilities/pageTreeConfig.js +21 -0
- package/dist/utilities/pageTreeConfig.js.map +1 -0
- package/dist/utilities/status.d.ts +17 -0
- package/dist/utilities/status.js +72 -0
- package/dist/utilities/status.js.map +1 -0
- package/package.json +115 -0
|
@@ -0,0 +1,960 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { DndContext, DragOverlay, PointerSensor, useDroppable, useSensor, useSensors } from '@dnd-kit/core';
|
|
4
|
+
import { DefaultListView, ListQueryProvider, SelectAll, SelectRow, SortHeader, toast, useConfig, useLocale, useTranslation } from '@payloadcms/ui';
|
|
5
|
+
import { useRouter, useSearchParams } from 'next/navigation';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { buildInsertDropTargets, getDropTargetParentDoc, getOrderPlacementFromDropTarget } from '../utilities/dropTargets.js';
|
|
8
|
+
import { CANCEL_DRAG_MESSAGE, getDropValidation } from '../utilities/moveValidation.js';
|
|
9
|
+
import { buildDocSlugPath, buildPageTreeDocs, buildProspectiveDocSlugPath, getDocDisplayLabel, getVisibleTreeDocs } from '../utilities/pageTree.js';
|
|
10
|
+
import { pageTreeCollisionDetectionStrategy } from '../utilities/pageTreeCollision.js';
|
|
11
|
+
import { getPageTreeBadgeColor, getPageTreeBadgeLabel, getPageTreeDisplayStatus } from '../utilities/status.js';
|
|
12
|
+
import { PageTreeProvider } from './PageTreeContext.js';
|
|
13
|
+
import styles from './PageTreeListView.module.css';
|
|
14
|
+
import { PageTreeTitleCell } from './PageTreeTitleCell.js';
|
|
15
|
+
const MANUAL_ORDER_COLUMN_ACCESSOR = '_dragHandle';
|
|
16
|
+
const SILENT_MOVE_MESSAGES = new Set([
|
|
17
|
+
CANCEL_DRAG_MESSAGE
|
|
18
|
+
]);
|
|
19
|
+
function getRowDropID(rowID) {
|
|
20
|
+
return `page-drop:${rowID}`;
|
|
21
|
+
}
|
|
22
|
+
function getPageTreeDragData(value) {
|
|
23
|
+
return value && typeof value === 'object' ? value : {};
|
|
24
|
+
}
|
|
25
|
+
function getPayloadDocID(doc) {
|
|
26
|
+
return typeof doc.id === 'number' || typeof doc.id === 'string' ? doc.id : undefined;
|
|
27
|
+
}
|
|
28
|
+
function getManualOrderDropValidation(args) {
|
|
29
|
+
const { activeDoc, targetDoc } = args;
|
|
30
|
+
if (!targetDoc) {
|
|
31
|
+
return {
|
|
32
|
+
isValid: true,
|
|
33
|
+
parentID: null
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (targetDoc.__pageTreeID === activeDoc.__pageTreeID) {
|
|
37
|
+
return {
|
|
38
|
+
isValid: false,
|
|
39
|
+
message: CANCEL_DRAG_MESSAGE,
|
|
40
|
+
parentID: targetDoc.__pageTreeID
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (targetDoc.__pageTreeAncestorIDs.includes(activeDoc.__pageTreeID)) {
|
|
44
|
+
return {
|
|
45
|
+
isValid: false,
|
|
46
|
+
message: 'A document cannot be moved under one of its descendants.',
|
|
47
|
+
parentID: targetDoc.__pageTreeID
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
isValid: true,
|
|
52
|
+
parentID: targetDoc.__pageTreeID
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function getDropValidationForMode(args) {
|
|
56
|
+
const { activeDoc, allowSameParent, targetDoc } = args;
|
|
57
|
+
if (allowSameParent) {
|
|
58
|
+
return getManualOrderDropValidation({
|
|
59
|
+
activeDoc,
|
|
60
|
+
targetDoc
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return getDropValidation({
|
|
64
|
+
activeDoc,
|
|
65
|
+
targetDoc
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function getCurrentOrderPlacement(args) {
|
|
69
|
+
const { activeDoc, docs } = args;
|
|
70
|
+
const activeIndex = docs.findIndex((doc)=>doc.__pageTreeID === activeDoc.__pageTreeID);
|
|
71
|
+
const movingSubtreeIDs = new Set(docs.filter((doc)=>doc.__pageTreeID === activeDoc.__pageTreeID || doc.__pageTreeAncestorIDs.includes(activeDoc.__pageTreeID)).map((doc)=>doc.__pageTreeID));
|
|
72
|
+
const siblingIsNotMoving = (doc)=>doc.__pageTreeParentID === activeDoc.__pageTreeParentID && !movingSubtreeIDs.has(doc.__pageTreeID);
|
|
73
|
+
if (activeIndex < 0) {
|
|
74
|
+
return {
|
|
75
|
+
nextSiblingID: null,
|
|
76
|
+
parentID: activeDoc.__pageTreeParentID,
|
|
77
|
+
previousSiblingID: null
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
nextSiblingID: docs.slice(activeIndex + 1).find(siblingIsNotMoving)?.__pageTreeID ?? null,
|
|
82
|
+
parentID: activeDoc.__pageTreeParentID,
|
|
83
|
+
previousSiblingID: docs.slice(0, activeIndex).filter(siblingIsNotMoving).at(-1)?.__pageTreeID ?? null
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function orderPlacementHasChanged(currentPlacement, nextPlacement) {
|
|
87
|
+
return currentPlacement.parentID !== nextPlacement.parentID || currentPlacement.previousSiblingID !== nextPlacement.previousSiblingID || currentPlacement.nextSiblingID !== nextPlacement.nextSiblingID;
|
|
88
|
+
}
|
|
89
|
+
function getReorderTargetFromPlacement(args) {
|
|
90
|
+
const { currentSort, docsByID, orderableFieldName, placement } = args;
|
|
91
|
+
const targetDocID = placement.previousSiblingID ?? placement.nextSiblingID;
|
|
92
|
+
if (!targetDocID) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const targetDoc = docsByID.get(targetDocID);
|
|
96
|
+
if (!targetDoc) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
newKeyWillBe: placement.previousSiblingID !== null && currentSort === orderableFieldName || placement.previousSiblingID === null && currentSort === `-${orderableFieldName}` ? 'greater' : 'less',
|
|
101
|
+
targetDoc
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function buildPaginatedData(docs, limit, requestedPage) {
|
|
105
|
+
const totalDocs = docs.length;
|
|
106
|
+
const totalPages = totalDocs > 0 ? Math.max(1, Math.ceil(totalDocs / limit)) : 1;
|
|
107
|
+
const page = Math.min(Math.max(requestedPage, 1), totalPages);
|
|
108
|
+
const startIndex = (page - 1) * limit;
|
|
109
|
+
const pageDocs = docs.slice(startIndex, startIndex + limit);
|
|
110
|
+
return {
|
|
111
|
+
docs: pageDocs,
|
|
112
|
+
hasNextPage: page < totalPages,
|
|
113
|
+
hasPrevPage: page > 1,
|
|
114
|
+
limit,
|
|
115
|
+
nextPage: page < totalPages ? page + 1 : null,
|
|
116
|
+
page,
|
|
117
|
+
pagingCounter: totalDocs === 0 ? 0 : startIndex + 1,
|
|
118
|
+
prevPage: page > 1 ? page - 1 : null,
|
|
119
|
+
totalDocs,
|
|
120
|
+
totalPages
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function normalizeSort(value) {
|
|
124
|
+
if (Array.isArray(value)) {
|
|
125
|
+
const sortValues = value.filter((entry)=>typeof entry === 'string' && entry.length > 0);
|
|
126
|
+
return sortValues.length > 0 ? sortValues.join(',') : undefined;
|
|
127
|
+
}
|
|
128
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
129
|
+
}
|
|
130
|
+
function normalizePositiveInt(value, fallback) {
|
|
131
|
+
if (typeof value !== 'string') {
|
|
132
|
+
return fallback;
|
|
133
|
+
}
|
|
134
|
+
const parsedValue = Number.parseInt(value, 10);
|
|
135
|
+
return Number.isNaN(parsedValue) || parsedValue <= 0 ? fallback : parsedValue;
|
|
136
|
+
}
|
|
137
|
+
function normalizePageTreeColumnState(columnState, useAsTitle) {
|
|
138
|
+
return columnState.filter((column)=>column.accessor !== MANUAL_ORDER_COLUMN_ACCESSOR).map((column)=>column.accessor === useAsTitle ? {
|
|
139
|
+
...column,
|
|
140
|
+
active: true
|
|
141
|
+
} : column);
|
|
142
|
+
}
|
|
143
|
+
function sliceColumnState(columnState, docs, renderedCellIndexByDocID) {
|
|
144
|
+
return columnState.map((column)=>({
|
|
145
|
+
...column,
|
|
146
|
+
renderedCells: docs.map((doc)=>{
|
|
147
|
+
const renderedCellIndex = renderedCellIndexByDocID.get(doc.__pageTreeID) ?? doc.__pageTreeOrderIndex;
|
|
148
|
+
return column.renderedCells?.[renderedCellIndex] ?? null;
|
|
149
|
+
})
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
function getSelectableRowData(doc) {
|
|
153
|
+
const record = doc;
|
|
154
|
+
return {
|
|
155
|
+
id: String(doc.id ?? doc.__pageTreeID),
|
|
156
|
+
_isLocked: Boolean(record._isLocked),
|
|
157
|
+
_userEditing: record._userEditing
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function shouldSilenceMoveMessage(message) {
|
|
161
|
+
return typeof message === 'string' && SILENT_MOVE_MESSAGES.has(message);
|
|
162
|
+
}
|
|
163
|
+
function getStatusClassName(status) {
|
|
164
|
+
if (status === 'changed' || status === 'draft' || status === 'published') {
|
|
165
|
+
return status;
|
|
166
|
+
}
|
|
167
|
+
return 'unknown';
|
|
168
|
+
}
|
|
169
|
+
function renderStatusBadge(args) {
|
|
170
|
+
const { badgeConfig, doc, index, t } = args;
|
|
171
|
+
const status = getPageTreeDisplayStatus(doc);
|
|
172
|
+
const customColor = getPageTreeBadgeColor({
|
|
173
|
+
badgeColors: badgeConfig.colors,
|
|
174
|
+
status
|
|
175
|
+
});
|
|
176
|
+
const statusClass = getStatusClassName(status);
|
|
177
|
+
const style = customColor ? {
|
|
178
|
+
'--page-tree-badge-base': customColor
|
|
179
|
+
} : undefined;
|
|
180
|
+
return /*#__PURE__*/ _jsx("span", {
|
|
181
|
+
className: [
|
|
182
|
+
'pages-hierarchy-status-badge',
|
|
183
|
+
`pages-hierarchy-status-badge--${statusClass}`
|
|
184
|
+
].join(' '),
|
|
185
|
+
"data-custom-color": customColor ? 'true' : undefined,
|
|
186
|
+
style: style,
|
|
187
|
+
children: getPageTreeBadgeLabel({
|
|
188
|
+
badgeLabels: badgeConfig.labels,
|
|
189
|
+
status,
|
|
190
|
+
t
|
|
191
|
+
})
|
|
192
|
+
}, doc.__pageTreeID ?? index);
|
|
193
|
+
}
|
|
194
|
+
function createManualOrderColumn(docs) {
|
|
195
|
+
return {
|
|
196
|
+
accessor: MANUAL_ORDER_COLUMN_ACCESSOR,
|
|
197
|
+
active: true,
|
|
198
|
+
field: {
|
|
199
|
+
hidden: true
|
|
200
|
+
},
|
|
201
|
+
Heading: /*#__PURE__*/ _jsx(SortHeader, {}),
|
|
202
|
+
renderedCells: docs.map(()=>null)
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function insertManualOrderColumn(columns, orderColumn) {
|
|
206
|
+
const selectColumnIndex = columns.findIndex((column)=>column.accessor === '_select');
|
|
207
|
+
const insertIndex = selectColumnIndex >= 0 ? selectColumnIndex + 1 : 0;
|
|
208
|
+
return [
|
|
209
|
+
...columns.slice(0, insertIndex),
|
|
210
|
+
orderColumn,
|
|
211
|
+
...columns.slice(insertIndex)
|
|
212
|
+
];
|
|
213
|
+
}
|
|
214
|
+
function buildTableColumns(args) {
|
|
215
|
+
const { badgeConfig, columnState, docs, enableRowSelections, orderableFieldName, parentFieldSlug, t, useAsTitle } = args;
|
|
216
|
+
const columnsToUse = columnState.map((column)=>{
|
|
217
|
+
if (column.accessor === useAsTitle) {
|
|
218
|
+
return {
|
|
219
|
+
...column,
|
|
220
|
+
active: true,
|
|
221
|
+
renderedCells: docs.map((doc, index)=>/*#__PURE__*/ _jsx(PageTreeTitleCell, {
|
|
222
|
+
doc: doc,
|
|
223
|
+
children: column.renderedCells?.[index] ?? getDocDisplayLabel(doc)
|
|
224
|
+
}, doc.__pageTreeID ?? index))
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
if (column.accessor === '_status') {
|
|
228
|
+
return {
|
|
229
|
+
...column,
|
|
230
|
+
renderedCells: docs.map((doc, index)=>renderStatusBadge({
|
|
231
|
+
badgeConfig,
|
|
232
|
+
doc,
|
|
233
|
+
index,
|
|
234
|
+
t
|
|
235
|
+
}))
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (column.accessor === parentFieldSlug) {
|
|
239
|
+
return {
|
|
240
|
+
...column,
|
|
241
|
+
renderedCells: docs.map((doc, index)=>doc.__pageTreeParentID !== null ? column.renderedCells?.[index] ?? null : /*#__PURE__*/ _jsx("span", {
|
|
242
|
+
className: "pages-hierarchy-empty-cell",
|
|
243
|
+
children: "-"
|
|
244
|
+
}, doc.__pageTreeID ?? index))
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return column;
|
|
248
|
+
});
|
|
249
|
+
if (enableRowSelections) {
|
|
250
|
+
columnsToUse.unshift({
|
|
251
|
+
accessor: '_select',
|
|
252
|
+
active: true,
|
|
253
|
+
field: {
|
|
254
|
+
hidden: true
|
|
255
|
+
},
|
|
256
|
+
Heading: /*#__PURE__*/ _jsx(SelectAll, {}),
|
|
257
|
+
renderedCells: docs.map((doc, index)=>/*#__PURE__*/ _jsx(SelectRow, {
|
|
258
|
+
rowData: getSelectableRowData(doc)
|
|
259
|
+
}, doc.__pageTreeID ?? index))
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if (orderableFieldName && !columnsToUse.some((column)=>column.accessor === MANUAL_ORDER_COLUMN_ACCESSOR)) {
|
|
263
|
+
return insertManualOrderColumn(columnsToUse, createManualOrderColumn(docs));
|
|
264
|
+
}
|
|
265
|
+
return columnsToUse;
|
|
266
|
+
}
|
|
267
|
+
function HierarchyInsertRow({ activeColumnsCount, activeDragRowID, dropTarget, dropValidation, isMovePending }) {
|
|
268
|
+
const { isOver, setNodeRef } = useDroppable({
|
|
269
|
+
id: dropTarget.dropID,
|
|
270
|
+
data: dropTarget,
|
|
271
|
+
disabled: isMovePending
|
|
272
|
+
});
|
|
273
|
+
const hasActiveDrag = Boolean(activeDragRowID);
|
|
274
|
+
return /*#__PURE__*/ _jsx("tr", {
|
|
275
|
+
className: "pages-hierarchy-insert-row",
|
|
276
|
+
"data-drag-over": isOver ? 'true' : 'false',
|
|
277
|
+
"data-drop-valid": hasActiveDrag ? dropValidation?.isValid ? 'true' : 'false' : undefined,
|
|
278
|
+
"data-page-tree-insert": "true",
|
|
279
|
+
children: /*#__PURE__*/ _jsx("td", {
|
|
280
|
+
colSpan: activeColumnsCount,
|
|
281
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
282
|
+
className: "pages-hierarchy-insert-row__target",
|
|
283
|
+
"data-insert-depth": dropTarget.depth,
|
|
284
|
+
ref: setNodeRef
|
|
285
|
+
})
|
|
286
|
+
})
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function HierarchyTableRow({ activeColumns, activeDragRowID, doc, dropValidation, insertAfterDropID, insertBeforeDropID, isMovePending, rowIndex, titleCellAccessor }) {
|
|
290
|
+
const { isOver, setNodeRef } = useDroppable({
|
|
291
|
+
id: getRowDropID(doc.__pageTreeID),
|
|
292
|
+
data: {
|
|
293
|
+
dropType: 'row',
|
|
294
|
+
insertAfterDropID,
|
|
295
|
+
insertBeforeDropID,
|
|
296
|
+
rowID: doc.__pageTreeID
|
|
297
|
+
},
|
|
298
|
+
disabled: isMovePending
|
|
299
|
+
});
|
|
300
|
+
const hasActiveDrag = Boolean(activeDragRowID);
|
|
301
|
+
const isActiveDragRow = activeDragRowID === doc.__pageTreeID;
|
|
302
|
+
return /*#__PURE__*/ _jsx("tr", {
|
|
303
|
+
className: `row-${rowIndex + 1}`,
|
|
304
|
+
"data-drag-over": isOver ? 'true' : 'false',
|
|
305
|
+
"data-drop-valid": hasActiveDrag ? dropValidation?.isValid ? 'true' : 'false' : undefined,
|
|
306
|
+
"data-id": doc.id,
|
|
307
|
+
"data-is-drag-source": isActiveDragRow ? 'true' : 'false',
|
|
308
|
+
"data-page-tree-row": "true",
|
|
309
|
+
ref: setNodeRef,
|
|
310
|
+
children: activeColumns.map((column, columnIndex)=>{
|
|
311
|
+
const { accessor } = column;
|
|
312
|
+
return /*#__PURE__*/ _jsx("td", {
|
|
313
|
+
className: `cell-${accessor.replace(/\./g, '__')}`,
|
|
314
|
+
"data-page-tree-manual-order-cell": accessor === MANUAL_ORDER_COLUMN_ACCESSOR ? 'true' : undefined,
|
|
315
|
+
"data-page-tree-title-cell": accessor === titleCellAccessor ? 'true' : undefined,
|
|
316
|
+
children: column.renderedCells?.[rowIndex] ?? null
|
|
317
|
+
}, columnIndex);
|
|
318
|
+
})
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
function HierarchyTable({ activeDragRowID, allDocsByID, allowSameParentDrops, columns, data, isMovePending, titleCellAccessor }) {
|
|
322
|
+
const activeColumns = React.useMemo(()=>columns.filter((column)=>column?.active), [
|
|
323
|
+
columns
|
|
324
|
+
]);
|
|
325
|
+
const hasManualOrderColumn = React.useMemo(()=>activeColumns.some((column)=>column.accessor === MANUAL_ORDER_COLUMN_ACCESSOR), [
|
|
326
|
+
activeColumns
|
|
327
|
+
]);
|
|
328
|
+
const insertDropTargets = React.useMemo(()=>buildInsertDropTargets(data), [
|
|
329
|
+
data
|
|
330
|
+
]);
|
|
331
|
+
const activeDoc = activeDragRowID ? allDocsByID.get(activeDragRowID) ?? null : null;
|
|
332
|
+
const rowDropValidationByID = React.useMemo(()=>{
|
|
333
|
+
if (!activeDoc) {
|
|
334
|
+
return new Map();
|
|
335
|
+
}
|
|
336
|
+
return new Map(data.map((doc)=>[
|
|
337
|
+
doc.__pageTreeID,
|
|
338
|
+
getDropValidationForMode({
|
|
339
|
+
activeDoc,
|
|
340
|
+
allowSameParent: allowSameParentDrops,
|
|
341
|
+
targetDoc: doc
|
|
342
|
+
})
|
|
343
|
+
]));
|
|
344
|
+
}, [
|
|
345
|
+
activeDoc,
|
|
346
|
+
allowSameParentDrops,
|
|
347
|
+
data
|
|
348
|
+
]);
|
|
349
|
+
const insertDropValidationByID = React.useMemo(()=>{
|
|
350
|
+
if (!activeDoc) {
|
|
351
|
+
return new Map();
|
|
352
|
+
}
|
|
353
|
+
return new Map(insertDropTargets.map((dropTarget)=>[
|
|
354
|
+
dropTarget.dropID,
|
|
355
|
+
getDropValidationForMode({
|
|
356
|
+
activeDoc,
|
|
357
|
+
allowSameParent: allowSameParentDrops,
|
|
358
|
+
targetDoc: dropTarget.parentID === null ? undefined : allDocsByID.get(dropTarget.parentID) ?? undefined
|
|
359
|
+
})
|
|
360
|
+
]));
|
|
361
|
+
}, [
|
|
362
|
+
activeDoc,
|
|
363
|
+
allowSameParentDrops,
|
|
364
|
+
allDocsByID,
|
|
365
|
+
insertDropTargets
|
|
366
|
+
]);
|
|
367
|
+
if (activeColumns.length === 0) {
|
|
368
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
369
|
+
children: "No columns selected"
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
373
|
+
className: [
|
|
374
|
+
'table-wrap pages-hierarchy-table',
|
|
375
|
+
activeDoc ? 'pages-hierarchy-table--dragging' : ''
|
|
376
|
+
].filter(Boolean).join(' '),
|
|
377
|
+
"data-page-tree-orderable": hasManualOrderColumn ? 'true' : undefined,
|
|
378
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
379
|
+
className: "table table--appearance-default",
|
|
380
|
+
children: /*#__PURE__*/ _jsxs("table", {
|
|
381
|
+
cellPadding: "0",
|
|
382
|
+
cellSpacing: "0",
|
|
383
|
+
children: [
|
|
384
|
+
/*#__PURE__*/ _jsx("thead", {
|
|
385
|
+
children: /*#__PURE__*/ _jsx("tr", {
|
|
386
|
+
children: activeColumns.map((column, index)=>/*#__PURE__*/ _jsx("th", {
|
|
387
|
+
"data-page-tree-manual-order-cell": column.accessor === MANUAL_ORDER_COLUMN_ACCESSOR ? 'true' : undefined,
|
|
388
|
+
"data-page-tree-title-cell": column.accessor === titleCellAccessor ? 'true' : undefined,
|
|
389
|
+
id: `heading-${column.accessor.replace(/\./g, '__')}`,
|
|
390
|
+
children: column.Heading
|
|
391
|
+
}, index))
|
|
392
|
+
})
|
|
393
|
+
}),
|
|
394
|
+
/*#__PURE__*/ _jsxs("tbody", {
|
|
395
|
+
children: [
|
|
396
|
+
insertDropTargets[0] ? /*#__PURE__*/ _jsx(HierarchyInsertRow, {
|
|
397
|
+
activeColumnsCount: activeColumns.length,
|
|
398
|
+
activeDragRowID: activeDragRowID,
|
|
399
|
+
dropTarget: insertDropTargets[0],
|
|
400
|
+
dropValidation: insertDropValidationByID.get(insertDropTargets[0].dropID),
|
|
401
|
+
isMovePending: isMovePending
|
|
402
|
+
}, insertDropTargets[0].dropID) : null,
|
|
403
|
+
data.map((doc, rowIndex)=>/*#__PURE__*/ _jsxs(React.Fragment, {
|
|
404
|
+
children: [
|
|
405
|
+
/*#__PURE__*/ _jsx(HierarchyTableRow, {
|
|
406
|
+
activeColumns: activeColumns,
|
|
407
|
+
activeDragRowID: activeDragRowID,
|
|
408
|
+
doc: doc,
|
|
409
|
+
dropValidation: rowDropValidationByID.get(doc.__pageTreeID),
|
|
410
|
+
insertAfterDropID: insertDropTargets[rowIndex + 1].dropID,
|
|
411
|
+
insertBeforeDropID: insertDropTargets[rowIndex].dropID,
|
|
412
|
+
isMovePending: isMovePending,
|
|
413
|
+
rowIndex: rowIndex,
|
|
414
|
+
titleCellAccessor: titleCellAccessor
|
|
415
|
+
}),
|
|
416
|
+
insertDropTargets[rowIndex + 1] ? /*#__PURE__*/ _jsx(HierarchyInsertRow, {
|
|
417
|
+
activeColumnsCount: activeColumns.length,
|
|
418
|
+
activeDragRowID: activeDragRowID,
|
|
419
|
+
dropTarget: insertDropTargets[rowIndex + 1],
|
|
420
|
+
dropValidation: insertDropValidationByID.get(insertDropTargets[rowIndex + 1].dropID),
|
|
421
|
+
isMovePending: isMovePending
|
|
422
|
+
}, insertDropTargets[rowIndex + 1].dropID) : null
|
|
423
|
+
]
|
|
424
|
+
}, doc.__pageTreeID))
|
|
425
|
+
]
|
|
426
|
+
})
|
|
427
|
+
]
|
|
428
|
+
})
|
|
429
|
+
})
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
export default function PageTreeListViewClient({ allDocs, badgeConfig, canMoveDocs, columnState, orderableFieldName, parentFieldSlug, query, sourceDocs, useAsTitle, ...props }) {
|
|
433
|
+
const router = useRouter();
|
|
434
|
+
const searchParams = useSearchParams();
|
|
435
|
+
const { config } = useConfig();
|
|
436
|
+
const locale = useLocale();
|
|
437
|
+
const { i18n } = useTranslation();
|
|
438
|
+
const [activeDragRowID, setActiveDragRowID] = React.useState(null);
|
|
439
|
+
const [activeDropTarget, setActiveDropTarget] = React.useState(null);
|
|
440
|
+
const [collapsedIDs, setCollapsedIDs] = React.useState(()=>new Set());
|
|
441
|
+
const [localSourceDocs, setLocalSourceDocs] = React.useState(sourceDocs);
|
|
442
|
+
const [pendingMoveRowID, setPendingMoveRowID] = React.useState(null);
|
|
443
|
+
React.useEffect(()=>{
|
|
444
|
+
setLocalSourceDocs(sourceDocs);
|
|
445
|
+
}, [
|
|
446
|
+
sourceDocs
|
|
447
|
+
]);
|
|
448
|
+
const toggleRow = React.useCallback((rowID)=>{
|
|
449
|
+
setCollapsedIDs((currentState)=>{
|
|
450
|
+
const nextState = new Set(currentState);
|
|
451
|
+
if (nextState.has(rowID)) {
|
|
452
|
+
nextState.delete(rowID);
|
|
453
|
+
} else {
|
|
454
|
+
nextState.add(rowID);
|
|
455
|
+
}
|
|
456
|
+
return nextState;
|
|
457
|
+
});
|
|
458
|
+
}, []);
|
|
459
|
+
const currentSort = React.useMemo(()=>{
|
|
460
|
+
const searchParamSort = searchParams.getAll('sort');
|
|
461
|
+
if (searchParamSort.length > 0) {
|
|
462
|
+
return normalizeSort(searchParamSort);
|
|
463
|
+
}
|
|
464
|
+
return normalizeSort(query.sort);
|
|
465
|
+
}, [
|
|
466
|
+
query.sort,
|
|
467
|
+
searchParams
|
|
468
|
+
]);
|
|
469
|
+
const manualOrderIsActive = Boolean(orderableFieldName && (currentSort === orderableFieldName || currentSort === `-${orderableFieldName}`));
|
|
470
|
+
const currentLimit = React.useMemo(()=>normalizePositiveInt(searchParams.get('limit'), typeof query.limit === 'number' && query.limit > 0 ? query.limit : 10), [
|
|
471
|
+
query.limit,
|
|
472
|
+
searchParams
|
|
473
|
+
]);
|
|
474
|
+
const currentRequestedPage = React.useMemo(()=>normalizePositiveInt(searchParams.get('page'), typeof query.page === 'number' && query.page > 0 ? query.page : 1), [
|
|
475
|
+
query.page,
|
|
476
|
+
searchParams
|
|
477
|
+
]);
|
|
478
|
+
const liveAllDocs = React.useMemo(()=>buildPageTreeDocs(localSourceDocs, {
|
|
479
|
+
parentFieldSlug,
|
|
480
|
+
sort: currentSort
|
|
481
|
+
}), [
|
|
482
|
+
currentSort,
|
|
483
|
+
localSourceDocs,
|
|
484
|
+
parentFieldSlug
|
|
485
|
+
]);
|
|
486
|
+
const collapseResetKey = React.useMemo(()=>JSON.stringify([
|
|
487
|
+
props.collectionSlug,
|
|
488
|
+
props.viewType,
|
|
489
|
+
searchParams.toString()
|
|
490
|
+
]), [
|
|
491
|
+
props.collectionSlug,
|
|
492
|
+
props.viewType,
|
|
493
|
+
searchParams
|
|
494
|
+
]);
|
|
495
|
+
const hierarchyValue = React.useMemo(()=>({
|
|
496
|
+
activeDragRowID,
|
|
497
|
+
canMoveDocs,
|
|
498
|
+
collapsedIDs,
|
|
499
|
+
pendingMoveRowID,
|
|
500
|
+
toggleRow
|
|
501
|
+
}), [
|
|
502
|
+
activeDragRowID,
|
|
503
|
+
canMoveDocs,
|
|
504
|
+
collapsedIDs,
|
|
505
|
+
pendingMoveRowID,
|
|
506
|
+
toggleRow
|
|
507
|
+
]);
|
|
508
|
+
React.useEffect(()=>{
|
|
509
|
+
setActiveDragRowID(null);
|
|
510
|
+
setActiveDropTarget(null);
|
|
511
|
+
setCollapsedIDs(new Set());
|
|
512
|
+
}, [
|
|
513
|
+
collapseResetKey
|
|
514
|
+
]);
|
|
515
|
+
const visibleDocs = React.useMemo(()=>getVisibleTreeDocs(liveAllDocs, collapsedIDs), [
|
|
516
|
+
liveAllDocs,
|
|
517
|
+
collapsedIDs
|
|
518
|
+
]);
|
|
519
|
+
const paginatedData = React.useMemo(()=>buildPaginatedData(visibleDocs, currentLimit, currentRequestedPage), [
|
|
520
|
+
currentLimit,
|
|
521
|
+
currentRequestedPage,
|
|
522
|
+
visibleDocs
|
|
523
|
+
]);
|
|
524
|
+
const paginatedDocs = paginatedData.docs;
|
|
525
|
+
const allDocsByID = React.useMemo(()=>new Map(liveAllDocs.map((doc)=>[
|
|
526
|
+
doc.__pageTreeID,
|
|
527
|
+
doc
|
|
528
|
+
])), [
|
|
529
|
+
liveAllDocs
|
|
530
|
+
]);
|
|
531
|
+
const paginatedDocsByID = React.useMemo(()=>new Map(paginatedDocs.map((doc)=>[
|
|
532
|
+
doc.__pageTreeID,
|
|
533
|
+
doc
|
|
534
|
+
])), [
|
|
535
|
+
paginatedDocs
|
|
536
|
+
]);
|
|
537
|
+
const renderedCellIndexByDocID = React.useMemo(()=>new Map(allDocs.map((doc, index)=>[
|
|
538
|
+
doc.__pageTreeID,
|
|
539
|
+
index
|
|
540
|
+
])), [
|
|
541
|
+
allDocs
|
|
542
|
+
]);
|
|
543
|
+
const normalizedColumnState = React.useMemo(()=>normalizePageTreeColumnState(columnState, useAsTitle), [
|
|
544
|
+
columnState,
|
|
545
|
+
useAsTitle
|
|
546
|
+
]);
|
|
547
|
+
const paginatedColumnState = React.useMemo(()=>sliceColumnState(normalizedColumnState, paginatedDocs, renderedCellIndexByDocID), [
|
|
548
|
+
normalizedColumnState,
|
|
549
|
+
paginatedDocs,
|
|
550
|
+
renderedCellIndexByDocID
|
|
551
|
+
]);
|
|
552
|
+
const tableColumns = React.useMemo(()=>buildTableColumns({
|
|
553
|
+
badgeConfig,
|
|
554
|
+
columnState: paginatedColumnState,
|
|
555
|
+
docs: paginatedDocs,
|
|
556
|
+
enableRowSelections: props.enableRowSelections,
|
|
557
|
+
orderableFieldName,
|
|
558
|
+
parentFieldSlug,
|
|
559
|
+
t: i18n.t,
|
|
560
|
+
useAsTitle
|
|
561
|
+
}), [
|
|
562
|
+
paginatedColumnState,
|
|
563
|
+
paginatedDocs,
|
|
564
|
+
badgeConfig,
|
|
565
|
+
orderableFieldName,
|
|
566
|
+
parentFieldSlug,
|
|
567
|
+
props.enableRowSelections,
|
|
568
|
+
i18n.t,
|
|
569
|
+
useAsTitle
|
|
570
|
+
]);
|
|
571
|
+
const activeDragDoc = activeDragRowID ? paginatedDocsByID.get(activeDragRowID) ?? null : null;
|
|
572
|
+
const activeDragPreviewPath = React.useMemo(()=>{
|
|
573
|
+
if (!activeDragDoc) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
if (!activeDropTarget) {
|
|
577
|
+
return buildDocSlugPath({
|
|
578
|
+
doc: activeDragDoc,
|
|
579
|
+
docsByID: allDocsByID
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
const targetDoc = getDropTargetParentDoc({
|
|
583
|
+
docsByID: allDocsByID,
|
|
584
|
+
dropTarget: activeDropTarget
|
|
585
|
+
});
|
|
586
|
+
const dropValidation = getDropValidationForMode({
|
|
587
|
+
activeDoc: activeDragDoc,
|
|
588
|
+
allowSameParent: manualOrderIsActive,
|
|
589
|
+
targetDoc: targetDoc ?? undefined
|
|
590
|
+
});
|
|
591
|
+
if (!dropValidation.isValid) {
|
|
592
|
+
return buildDocSlugPath({
|
|
593
|
+
doc: activeDragDoc,
|
|
594
|
+
docsByID: allDocsByID
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
return buildProspectiveDocSlugPath({
|
|
598
|
+
activeDoc: activeDragDoc,
|
|
599
|
+
docsByID: allDocsByID,
|
|
600
|
+
targetDoc: targetDoc ?? undefined
|
|
601
|
+
});
|
|
602
|
+
}, [
|
|
603
|
+
activeDragDoc,
|
|
604
|
+
activeDropTarget,
|
|
605
|
+
allDocsByID,
|
|
606
|
+
manualOrderIsActive
|
|
607
|
+
]);
|
|
608
|
+
const isMovePending = pendingMoveRowID !== null;
|
|
609
|
+
const sensors = useSensors(useSensor(PointerSensor, {
|
|
610
|
+
activationConstraint: {
|
|
611
|
+
distance: 4
|
|
612
|
+
}
|
|
613
|
+
}));
|
|
614
|
+
const moveDocument = React.useCallback(async (args)=>{
|
|
615
|
+
const { parentID, rowID } = args;
|
|
616
|
+
const params = new URLSearchParams();
|
|
617
|
+
if (locale?.code) {
|
|
618
|
+
params.set('locale', locale.code);
|
|
619
|
+
}
|
|
620
|
+
const response = await fetch(`${config.routes.api}/${props.collectionSlug}/${encodeURIComponent(rowID)}/move${params.size > 0 ? `?${params.toString()}` : ''}`, {
|
|
621
|
+
body: JSON.stringify({
|
|
622
|
+
parentID
|
|
623
|
+
}),
|
|
624
|
+
credentials: 'include',
|
|
625
|
+
headers: {
|
|
626
|
+
'Accept-Language': i18n.language,
|
|
627
|
+
'Content-Type': 'application/json'
|
|
628
|
+
},
|
|
629
|
+
method: 'POST'
|
|
630
|
+
});
|
|
631
|
+
const result = await response.json().catch(()=>null);
|
|
632
|
+
if (!response.ok) {
|
|
633
|
+
throw new Error(result?.message ?? 'Could not move document.');
|
|
634
|
+
}
|
|
635
|
+
return result;
|
|
636
|
+
}, [
|
|
637
|
+
config.routes.api,
|
|
638
|
+
i18n.language,
|
|
639
|
+
locale?.code,
|
|
640
|
+
props.collectionSlug
|
|
641
|
+
]);
|
|
642
|
+
const reorderDocument = React.useCallback(async (args)=>{
|
|
643
|
+
const { movedDocID, newKeyWillBe, targetDoc } = args;
|
|
644
|
+
const targetID = getPayloadDocID(targetDoc);
|
|
645
|
+
if (!orderableFieldName || targetID === undefined) {
|
|
646
|
+
return undefined;
|
|
647
|
+
}
|
|
648
|
+
const params = new URLSearchParams();
|
|
649
|
+
if (locale?.code) {
|
|
650
|
+
params.set('locale', locale.code);
|
|
651
|
+
}
|
|
652
|
+
const response = await fetch(`${config.routes.api}/reorder${params.size > 0 ? `?${params.toString()}` : ''}`, {
|
|
653
|
+
body: JSON.stringify({
|
|
654
|
+
collectionSlug: props.collectionSlug,
|
|
655
|
+
docsToMove: [
|
|
656
|
+
movedDocID
|
|
657
|
+
],
|
|
658
|
+
newKeyWillBe,
|
|
659
|
+
orderableFieldName,
|
|
660
|
+
target: {
|
|
661
|
+
id: targetID,
|
|
662
|
+
key: targetDoc[orderableFieldName]
|
|
663
|
+
}
|
|
664
|
+
}),
|
|
665
|
+
credentials: 'include',
|
|
666
|
+
headers: {
|
|
667
|
+
'Accept-Language': i18n.language,
|
|
668
|
+
'Content-Type': 'application/json'
|
|
669
|
+
},
|
|
670
|
+
method: 'POST'
|
|
671
|
+
});
|
|
672
|
+
const result = await response.json().catch(()=>null);
|
|
673
|
+
if (response.status === 403) {
|
|
674
|
+
throw new Error('You do not have permission to reorder these rows');
|
|
675
|
+
}
|
|
676
|
+
if (!response.ok) {
|
|
677
|
+
throw new Error('Failed to reorder. This can happen if you reorder several rows too quickly. Please try again.');
|
|
678
|
+
}
|
|
679
|
+
if (result?.message === 'initial migration') {
|
|
680
|
+
throw new Error('You have enabled "orderable" on a collection with existing documents and this is the first time you have sorted documents. We have run an automatic migration to add an initial order to the documents. Please refresh the page and try again.');
|
|
681
|
+
}
|
|
682
|
+
return result?.orderValues?.[0];
|
|
683
|
+
}, [
|
|
684
|
+
config.routes.api,
|
|
685
|
+
i18n.language,
|
|
686
|
+
locale?.code,
|
|
687
|
+
orderableFieldName,
|
|
688
|
+
props.collectionSlug
|
|
689
|
+
]);
|
|
690
|
+
const handleManualOrderMoveEnd = React.useCallback(async (args)=>{
|
|
691
|
+
const { activeDoc, dropTarget, rowID } = args;
|
|
692
|
+
if (!orderableFieldName) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
const targetDoc = getDropTargetParentDoc({
|
|
696
|
+
docsByID: allDocsByID,
|
|
697
|
+
dropTarget
|
|
698
|
+
});
|
|
699
|
+
const dropValidation = getManualOrderDropValidation({
|
|
700
|
+
activeDoc,
|
|
701
|
+
targetDoc: targetDoc ?? undefined
|
|
702
|
+
});
|
|
703
|
+
if (!dropValidation.isValid) {
|
|
704
|
+
if (!shouldSilenceMoveMessage(dropValidation.message)) {
|
|
705
|
+
toast.error(dropValidation.message ?? 'Could not move document.');
|
|
706
|
+
}
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
const placement = getOrderPlacementFromDropTarget({
|
|
710
|
+
activeDoc,
|
|
711
|
+
docs: paginatedDocs,
|
|
712
|
+
docsByID: allDocsByID,
|
|
713
|
+
dropTarget
|
|
714
|
+
});
|
|
715
|
+
if (!placement) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
const currentPlacement = getCurrentOrderPlacement({
|
|
719
|
+
activeDoc,
|
|
720
|
+
docs: paginatedDocs
|
|
721
|
+
});
|
|
722
|
+
const parentChanged = activeDoc.__pageTreeParentID !== placement.parentID;
|
|
723
|
+
const orderChanged = orderPlacementHasChanged(currentPlacement, placement);
|
|
724
|
+
const reorderTarget = orderChanged ? getReorderTargetFromPlacement({
|
|
725
|
+
currentSort,
|
|
726
|
+
docsByID: allDocsByID,
|
|
727
|
+
orderableFieldName,
|
|
728
|
+
placement
|
|
729
|
+
}) : null;
|
|
730
|
+
if (!parentChanged && !reorderTarget) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const movedDocID = getPayloadDocID(activeDoc);
|
|
734
|
+
if (movedDocID === undefined) {
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
const parentDoc = placement.parentID ? allDocsByID.get(placement.parentID) : undefined;
|
|
738
|
+
const nextParentValue = placement.parentID === null ? null : parentDoc ? getPayloadDocID(parentDoc) ?? placement.parentID : placement.parentID;
|
|
739
|
+
let parentMoveSucceeded = false;
|
|
740
|
+
setPendingMoveRowID(rowID);
|
|
741
|
+
try {
|
|
742
|
+
if (parentChanged) {
|
|
743
|
+
await moveDocument({
|
|
744
|
+
parentID: placement.parentID,
|
|
745
|
+
rowID
|
|
746
|
+
});
|
|
747
|
+
parentMoveSucceeded = true;
|
|
748
|
+
}
|
|
749
|
+
const nextOrderValue = reorderTarget ? await reorderDocument({
|
|
750
|
+
movedDocID,
|
|
751
|
+
newKeyWillBe: reorderTarget.newKeyWillBe,
|
|
752
|
+
targetDoc: reorderTarget.targetDoc
|
|
753
|
+
}) : undefined;
|
|
754
|
+
if (parentChanged || typeof nextOrderValue === 'string') {
|
|
755
|
+
setLocalSourceDocs((currentDocs)=>currentDocs.map((doc)=>String(doc.id ?? '') === String(movedDocID) ? {
|
|
756
|
+
...doc,
|
|
757
|
+
...parentChanged ? {
|
|
758
|
+
[parentFieldSlug]: nextParentValue
|
|
759
|
+
} : {},
|
|
760
|
+
...typeof nextOrderValue === 'string' ? {
|
|
761
|
+
[orderableFieldName]: nextOrderValue
|
|
762
|
+
} : {}
|
|
763
|
+
} : doc));
|
|
764
|
+
}
|
|
765
|
+
if (parentChanged) {
|
|
766
|
+
toast.success(`Moved "${getDocDisplayLabel(activeDoc)}".`);
|
|
767
|
+
}
|
|
768
|
+
React.startTransition(()=>{
|
|
769
|
+
router.refresh();
|
|
770
|
+
});
|
|
771
|
+
} catch (error) {
|
|
772
|
+
const message = error instanceof Error && error.message ? error.message : 'Could not move document.';
|
|
773
|
+
toast.error(parentMoveSucceeded ? `Moved "${getDocDisplayLabel(activeDoc)}", but could not update its manual order. ${message}` : message);
|
|
774
|
+
if (parentMoveSucceeded) {
|
|
775
|
+
React.startTransition(()=>{
|
|
776
|
+
router.refresh();
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
} finally{
|
|
780
|
+
setPendingMoveRowID(null);
|
|
781
|
+
}
|
|
782
|
+
}, [
|
|
783
|
+
allDocsByID,
|
|
784
|
+
currentSort,
|
|
785
|
+
moveDocument,
|
|
786
|
+
orderableFieldName,
|
|
787
|
+
paginatedDocs,
|
|
788
|
+
parentFieldSlug,
|
|
789
|
+
reorderDocument,
|
|
790
|
+
router
|
|
791
|
+
]);
|
|
792
|
+
const handleDragCancel = React.useCallback(()=>{
|
|
793
|
+
setActiveDragRowID(null);
|
|
794
|
+
setActiveDropTarget(null);
|
|
795
|
+
}, []);
|
|
796
|
+
const handleDragStart = React.useCallback((event)=>{
|
|
797
|
+
const dragData = getPageTreeDragData(event.active.data.current);
|
|
798
|
+
if (!canMoveDocs || isMovePending) {
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
const rowID = dragData.rowID;
|
|
802
|
+
if (typeof rowID === 'string' && paginatedDocsByID.has(rowID)) {
|
|
803
|
+
setActiveDragRowID(rowID);
|
|
804
|
+
setActiveDropTarget(null);
|
|
805
|
+
}
|
|
806
|
+
}, [
|
|
807
|
+
canMoveDocs,
|
|
808
|
+
isMovePending,
|
|
809
|
+
paginatedDocsByID
|
|
810
|
+
]);
|
|
811
|
+
const handleDragOver = React.useCallback((event)=>{
|
|
812
|
+
const overData = event.over?.data.current;
|
|
813
|
+
if (!overData) {
|
|
814
|
+
setActiveDropTarget(null);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
if (overData.dropType === 'insert') {
|
|
818
|
+
setActiveDropTarget(overData);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
if (overData.dropType === 'row') {
|
|
822
|
+
setActiveDropTarget(overData);
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
setActiveDropTarget(null);
|
|
826
|
+
}, []);
|
|
827
|
+
const handleDragEnd = React.useCallback(async (event)=>{
|
|
828
|
+
const dragData = getPageTreeDragData(event.active.data.current);
|
|
829
|
+
const rowID = dragData.rowID;
|
|
830
|
+
const activeDoc = typeof rowID === 'string' ? paginatedDocsByID.get(rowID) ?? null : null;
|
|
831
|
+
const overData = event.over?.data.current;
|
|
832
|
+
setActiveDragRowID(null);
|
|
833
|
+
setActiveDropTarget(null);
|
|
834
|
+
if (!rowID || !activeDoc || !overData) {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
if (manualOrderIsActive && orderableFieldName) {
|
|
838
|
+
await handleManualOrderMoveEnd({
|
|
839
|
+
activeDoc,
|
|
840
|
+
dropTarget: overData,
|
|
841
|
+
rowID
|
|
842
|
+
});
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
const targetDoc = getDropTargetParentDoc({
|
|
846
|
+
docsByID: allDocsByID,
|
|
847
|
+
dropTarget: overData
|
|
848
|
+
});
|
|
849
|
+
const dropValidation = getDropValidation({
|
|
850
|
+
activeDoc,
|
|
851
|
+
targetDoc: targetDoc ?? undefined
|
|
852
|
+
});
|
|
853
|
+
if (!dropValidation.isValid) {
|
|
854
|
+
if (!shouldSilenceMoveMessage(dropValidation.message)) {
|
|
855
|
+
toast.error(dropValidation.message ?? 'Could not move document.');
|
|
856
|
+
}
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
setPendingMoveRowID(rowID);
|
|
860
|
+
try {
|
|
861
|
+
await moveDocument({
|
|
862
|
+
parentID: dropValidation.parentID,
|
|
863
|
+
rowID
|
|
864
|
+
});
|
|
865
|
+
toast.success(`Moved "${getDocDisplayLabel(activeDoc)}".`);
|
|
866
|
+
React.startTransition(()=>{
|
|
867
|
+
router.refresh();
|
|
868
|
+
});
|
|
869
|
+
} catch (error) {
|
|
870
|
+
const message = error instanceof Error && error.message ? error.message : 'Could not move document.';
|
|
871
|
+
if (shouldSilenceMoveMessage(message)) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
toast.error(message);
|
|
875
|
+
} finally{
|
|
876
|
+
setPendingMoveRowID(null);
|
|
877
|
+
}
|
|
878
|
+
}, [
|
|
879
|
+
allDocsByID,
|
|
880
|
+
handleManualOrderMoveEnd,
|
|
881
|
+
manualOrderIsActive,
|
|
882
|
+
moveDocument,
|
|
883
|
+
orderableFieldName,
|
|
884
|
+
paginatedDocsByID,
|
|
885
|
+
router
|
|
886
|
+
]);
|
|
887
|
+
const handleDragEndSync = React.useCallback((event)=>{
|
|
888
|
+
void handleDragEnd(event);
|
|
889
|
+
}, [
|
|
890
|
+
handleDragEnd
|
|
891
|
+
]);
|
|
892
|
+
const tableNode = React.useMemo(()=>/*#__PURE__*/ _jsxs(DndContext, {
|
|
893
|
+
collisionDetection: pageTreeCollisionDetectionStrategy,
|
|
894
|
+
onDragCancel: handleDragCancel,
|
|
895
|
+
onDragEnd: handleDragEndSync,
|
|
896
|
+
onDragOver: handleDragOver,
|
|
897
|
+
onDragStart: handleDragStart,
|
|
898
|
+
sensors: sensors,
|
|
899
|
+
children: [
|
|
900
|
+
/*#__PURE__*/ _jsx(HierarchyTable, {
|
|
901
|
+
activeDragRowID: activeDragRowID,
|
|
902
|
+
allDocsByID: allDocsByID,
|
|
903
|
+
allowSameParentDrops: manualOrderIsActive,
|
|
904
|
+
columns: tableColumns,
|
|
905
|
+
data: paginatedDocs,
|
|
906
|
+
isMovePending: isMovePending,
|
|
907
|
+
titleCellAccessor: useAsTitle
|
|
908
|
+
}),
|
|
909
|
+
/*#__PURE__*/ _jsx(DragOverlay, {
|
|
910
|
+
dropAnimation: null,
|
|
911
|
+
style: {
|
|
912
|
+
cursor: 'grabbing'
|
|
913
|
+
},
|
|
914
|
+
children: activeDragPreviewPath ? /*#__PURE__*/ _jsx("div", {
|
|
915
|
+
className: "pages-hierarchy-drag-overlay",
|
|
916
|
+
children: activeDragPreviewPath
|
|
917
|
+
}) : null
|
|
918
|
+
})
|
|
919
|
+
]
|
|
920
|
+
}), [
|
|
921
|
+
activeDragPreviewPath,
|
|
922
|
+
activeDragRowID,
|
|
923
|
+
handleDragCancel,
|
|
924
|
+
handleDragEndSync,
|
|
925
|
+
handleDragOver,
|
|
926
|
+
handleDragStart,
|
|
927
|
+
isMovePending,
|
|
928
|
+
allDocsByID,
|
|
929
|
+
manualOrderIsActive,
|
|
930
|
+
paginatedDocs,
|
|
931
|
+
sensors,
|
|
932
|
+
tableColumns,
|
|
933
|
+
useAsTitle
|
|
934
|
+
]);
|
|
935
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
936
|
+
className: styles.root,
|
|
937
|
+
children: /*#__PURE__*/ _jsx(PageTreeProvider, {
|
|
938
|
+
value: hierarchyValue,
|
|
939
|
+
children: /*#__PURE__*/ _jsx(ListQueryProvider, {
|
|
940
|
+
collectionSlug: props.collectionSlug,
|
|
941
|
+
data: paginatedData,
|
|
942
|
+
modifySearchParams: true,
|
|
943
|
+
orderableFieldName: orderableFieldName,
|
|
944
|
+
query: {
|
|
945
|
+
...query,
|
|
946
|
+
limit: currentLimit,
|
|
947
|
+
page: paginatedData.page,
|
|
948
|
+
sort: currentSort
|
|
949
|
+
},
|
|
950
|
+
children: /*#__PURE__*/ _jsx(DefaultListView, {
|
|
951
|
+
...props,
|
|
952
|
+
columnState: paginatedColumnState,
|
|
953
|
+
Table: tableNode
|
|
954
|
+
})
|
|
955
|
+
})
|
|
956
|
+
})
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
//# sourceMappingURL=PageTreeListView.client.js.map
|