Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
187 lines
7.0 KiB
Plaintext
187 lines
7.0 KiB
Plaintext
'use client';
|
|
|
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
import './index.scss';
|
|
import { DragOverlay } from '@dnd-kit/core';
|
|
import { formatAdminURL } from 'payload/shared';
|
|
import React, { useEffect, useState } from 'react';
|
|
import { toast } from 'sonner';
|
|
import { useConfig } from '../../providers/Config/index.js';
|
|
import { useListQuery } from '../../providers/ListQuery/index.js';
|
|
import { useLocale } from '../../providers/Locale/index.js';
|
|
import { DraggableSortableItem } from '../DraggableSortable/DraggableSortableItem/index.js';
|
|
import { DraggableSortable } from '../DraggableSortable/index.js';
|
|
import { OrderableRow } from './OrderableRow.js';
|
|
import { OrderableRowDragPreview } from './OrderableRowDragPreview.js';
|
|
const baseClass = 'table';
|
|
export const OrderableTable = ({
|
|
appearance = 'default',
|
|
BeforeTable,
|
|
collection,
|
|
columns,
|
|
data: initialData
|
|
}) => {
|
|
const {
|
|
config
|
|
} = useConfig();
|
|
const {
|
|
data: listQueryData,
|
|
orderableFieldName,
|
|
query
|
|
} = useListQuery();
|
|
const {
|
|
code: localeCode
|
|
} = useLocale();
|
|
// Use the data from ListQueryProvider if available, otherwise use the props
|
|
const serverData = listQueryData?.docs || initialData;
|
|
// Local state to track the current order of rows
|
|
const [localData, setLocalData] = useState(serverData);
|
|
// id -> index for each column
|
|
const [cellMap, setCellMap] = useState({});
|
|
const [dragActiveRowId, setDragActiveRowId] = useState();
|
|
// Update local data when server data changes
|
|
useEffect(() => {
|
|
setLocalData(serverData);
|
|
setCellMap(Object.fromEntries(serverData.map((item, index) => [String(item.id ?? item._id), index])));
|
|
}, [serverData]);
|
|
const activeColumns = columns?.filter(col => col?.active);
|
|
if (!activeColumns || activeColumns.filter(col_0 => !['_dragHandle', '_select'].includes(col_0.accessor)).length === 0) {
|
|
return /*#__PURE__*/_jsx("div", {
|
|
children: "No columns selected"
|
|
});
|
|
}
|
|
const handleDragEnd = async ({
|
|
moveFromIndex,
|
|
moveToIndex
|
|
}) => {
|
|
if (query.sort !== orderableFieldName && query.sort !== `-${orderableFieldName}`) {
|
|
toast.warning('To reorder the rows you must first sort them by the "Order" column');
|
|
setDragActiveRowId(undefined);
|
|
return;
|
|
}
|
|
if (moveFromIndex === moveToIndex) {
|
|
setDragActiveRowId(undefined);
|
|
return;
|
|
}
|
|
const movedId = localData[moveFromIndex].id ?? localData[moveFromIndex]._id;
|
|
const newBeforeRow = moveToIndex > moveFromIndex ? localData[moveToIndex] : localData[moveToIndex - 1];
|
|
const newAfterRow = moveToIndex > moveFromIndex ? localData[moveToIndex + 1] : localData[moveToIndex];
|
|
// Store the original data for rollback
|
|
const previousData = [...localData];
|
|
// Optimisitc update of local state to reorder the rows
|
|
setLocalData(currentData => {
|
|
const newData = [...currentData];
|
|
// Update the rendered cell for the moved row to show "pending"
|
|
newData[moveFromIndex][orderableFieldName] = `pending`;
|
|
// Move the item in the array
|
|
newData.splice(moveToIndex, 0, newData.splice(moveFromIndex, 1)[0]);
|
|
return newData;
|
|
});
|
|
try {
|
|
const target = newBeforeRow ? {
|
|
id: newBeforeRow.id ?? newBeforeRow._id,
|
|
key: newBeforeRow[orderableFieldName]
|
|
} : {
|
|
id: newAfterRow.id ?? newAfterRow._id,
|
|
key: newAfterRow[orderableFieldName]
|
|
};
|
|
const newKeyWillBe = newBeforeRow && query.sort === orderableFieldName || !newBeforeRow && query.sort === `-${orderableFieldName}` ? 'greater' : 'less';
|
|
const jsonBody = {
|
|
collectionSlug: collection.slug,
|
|
docsToMove: [movedId],
|
|
newKeyWillBe,
|
|
orderableFieldName,
|
|
target
|
|
};
|
|
const response = await fetch(formatAdminURL({
|
|
apiRoute: config.routes.api,
|
|
path: `/reorder?locale=${localeCode}`
|
|
}), {
|
|
body: JSON.stringify(jsonBody),
|
|
credentials: 'include',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
method: 'POST'
|
|
});
|
|
if (response.status === 403) {
|
|
throw new Error('You do not have permission to reorder these rows');
|
|
}
|
|
if (!response.ok) {
|
|
throw new Error('Failed to reorder. This can happen if you reorder several rows too quickly. Please try again.');
|
|
}
|
|
if (response.status === 200 && (await response.json())['message'] === 'initial migration') {
|
|
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.');
|
|
}
|
|
} catch (err) {
|
|
const error = err instanceof Error ? err.message : String(err);
|
|
// Rollback to previous state if the request fails
|
|
setLocalData(previousData);
|
|
toast.error(error);
|
|
} finally {
|
|
setDragActiveRowId(undefined);
|
|
}
|
|
};
|
|
const handleDragStart = ({
|
|
id
|
|
}) => {
|
|
setDragActiveRowId(id);
|
|
};
|
|
const rowIds = localData.map(row => row.id ?? row._id);
|
|
return /*#__PURE__*/_jsxs("div", {
|
|
className: [baseClass, appearance && `${baseClass}--appearance-${appearance}`].filter(Boolean).join(' '),
|
|
children: [BeforeTable, /*#__PURE__*/_jsxs(DraggableSortable, {
|
|
ids: rowIds,
|
|
onDragEnd: handleDragEnd,
|
|
onDragStart: handleDragStart,
|
|
children: [/*#__PURE__*/_jsxs("table", {
|
|
cellPadding: "0",
|
|
cellSpacing: "0",
|
|
children: [/*#__PURE__*/_jsx("thead", {
|
|
children: /*#__PURE__*/_jsx("tr", {
|
|
children: activeColumns.map((col_1, i) => /*#__PURE__*/_jsx("th", {
|
|
id: `heading-${col_1.accessor}`,
|
|
children: col_1.Heading
|
|
}, i))
|
|
})
|
|
}), /*#__PURE__*/_jsx("tbody", {
|
|
children: localData.map((row_0, rowIndex) => /*#__PURE__*/_jsx(DraggableSortableItem, {
|
|
id: rowIds[rowIndex],
|
|
children: ({
|
|
attributes,
|
|
isDragging,
|
|
listeners,
|
|
setNodeRef,
|
|
transform,
|
|
transition
|
|
}) => /*#__PURE__*/_jsx(OrderableRow, {
|
|
cellMap: cellMap,
|
|
className: `row-${rowIndex + 1}`,
|
|
columns: activeColumns,
|
|
dragAttributes: attributes,
|
|
dragListeners: listeners,
|
|
ref: setNodeRef,
|
|
rowId: row_0.id ?? row_0._id,
|
|
style: {
|
|
opacity: isDragging ? 0 : 1,
|
|
transform,
|
|
transition
|
|
}
|
|
})
|
|
}, rowIds[rowIndex]))
|
|
})]
|
|
}), /*#__PURE__*/_jsx(DragOverlay, {
|
|
children: /*#__PURE__*/_jsx(OrderableRowDragPreview, {
|
|
className: [baseClass, `${baseClass}--drag-preview`].join(' '),
|
|
rowId: dragActiveRowId,
|
|
children: /*#__PURE__*/_jsx(OrderableRow, {
|
|
cellMap: cellMap,
|
|
columns: activeColumns,
|
|
rowId: dragActiveRowId
|
|
})
|
|
})
|
|
})]
|
|
})]
|
|
});
|
|
};
|
|
//# sourceMappingURL=OrderableTable.js.map |