Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: toggle sortable arrays and blocks #5962

Merged
merged 19 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/fields/array.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ properties:
| Option | Description |
|---------------------------|----------------------------------------------------------------------------------------------------------------------|
| **`initCollapsed`** | Set the initial collapsed state |
| **`isSortable`** | Disable order sorting by setting this value to `false` |
| **`components.RowLabel`** | Function or React component to be rendered as the label on the array row. Receives `({ data, index, path })` as args |

### Example
Expand Down
1 change: 1 addition & 0 deletions docs/fields/blocks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ properties:
| Option | Description |
|---------------------|---------------------------------|
| **`initCollapsed`** | Set the initial collapsed state |
| **`isSortable`** | Disable order sorting by setting this value to `false` |

### Block configs

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const ArrayAction: React.FC<Props> = ({
duplicateRow,
hasMaxRows,
index,
isSortable,
moveRow,
removeRow,
rowCount,
Expand All @@ -33,7 +34,7 @@ export const ArrayAction: React.FC<Props> = ({
render={({ close }) => {
return (
<PopupList.ButtonGroup buttonSize="small">
{index !== 0 && (
{isSortable && index !== 0 && (
<PopupList.Button
className={`${baseClass}__action ${baseClass}__move-up`}
onClick={() => {
Expand All @@ -47,7 +48,7 @@ export const ArrayAction: React.FC<Props> = ({
{t('moveUp')}
</PopupList.Button>
)}
{index < rowCount - 1 && (
{isSortable && index < rowCount - 1 && (
<PopupList.Button
className={`${baseClass}__action`}
onClick={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export type Props = {
duplicateRow: (current: number) => void
hasMaxRows: boolean
index: number
isSortable: boolean
moveRow: (from: number, to: number) => void
removeRow: (index: number) => void
rowCount: number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type ArrayRowProps = UseDraggableSortableReturn &
duplicateRow: (rowIndex: number) => void
forceRender?: boolean
hasMaxRows?: boolean
isSortable: boolean
moveRow: (fromIndex: number, toIndex: number) => void
readOnly?: boolean
removeRow: (rowIndex: number) => void
Expand All @@ -44,6 +45,7 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
forceRender = false,
hasMaxRows,
indexPath,
isSortable,
labels,
listeners,
moveRow,
Expand Down Expand Up @@ -94,6 +96,7 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
duplicateRow={duplicateRow}
hasMaxRows={hasMaxRows}
index={rowIndex}
isSortable={isSortable}
moveRow={moveRow}
removeRow={removeRow}
rowCount={rowCount}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const baseClass = 'array-field'
const ArrayFieldType: React.FC<Props> = (props) => {
const {
name,
admin: { className, components, condition, description, readOnly },
admin: { className, components, condition, description, isSortable = true, readOnly },
fieldTypes,
fields,
forceRender = false,
Expand Down Expand Up @@ -113,7 +113,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {

const duplicateRow = useCallback(
(rowIndex: number) => {
dispatchFields({ path, rowIndex, type: 'DUPLICATE_ROW' })
dispatchFields({ type: 'DUPLICATE_ROW', path, rowIndex })
setModified(true)

setTimeout(() => {
Expand All @@ -133,22 +133,22 @@ const ArrayFieldType: React.FC<Props> = (props) => {

const moveRow = useCallback(
(moveFromIndex: number, moveToIndex: number) => {
dispatchFields({ moveFromIndex, moveToIndex, path, type: 'MOVE_ROW' })
dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path })
setModified(true)
},
[dispatchFields, path, setModified],
)

const toggleCollapseAll = useCallback(
(collapsed: boolean) => {
dispatchFields({ collapsed, path, setDocFieldPreferences, type: 'SET_ALL_ROWS_COLLAPSED' })
dispatchFields({ type: 'SET_ALL_ROWS_COLLAPSED', collapsed, path, setDocFieldPreferences })
},
[dispatchFields, path, setDocFieldPreferences],
)

const setCollapse = useCallback(
(rowID: string, collapsed: boolean) => {
dispatchFields({ collapsed, path, rowID, setDocFieldPreferences, type: 'SET_ROW_COLLAPSED' })
dispatchFields({ type: 'SET_ROW_COLLAPSED', collapsed, path, rowID, setDocFieldPreferences })
},
[dispatchFields, path, setDocFieldPreferences],
)
Expand Down Expand Up @@ -227,7 +227,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
onDragEnd={({ moveFromIndex, moveToIndex }) => moveRow(moveFromIndex, moveToIndex)}
>
{rows.map((row, i) => (
<DraggableSortableItem disabled={readOnly} id={row.id} key={row.id}>
<DraggableSortableItem disabled={readOnly || !isSortable} id={row.id} key={row.id}>
{(draggableSortableItemProps) => (
<ArrayRow
{...draggableSortableItemProps}
Expand All @@ -239,6 +239,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
forceRender={forceRender}
hasMaxRows={hasMaxRows}
indexPath={indexPath}
isSortable={isSortable}
labels={labels}
moveRow={moveRow}
path={path}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type BlockFieldProps = UseDraggableSortableReturn &
duplicateRow: (rowIndex: number) => void
forceRender?: boolean
hasMaxRows?: boolean
isSortable?: boolean
moveRow: (fromIndex: number, toIndex: number) => void
readOnly: boolean
removeRow: (rowIndex: number) => void
Expand All @@ -44,6 +45,7 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
forceRender,
hasMaxRows,
indexPath,
isSortable,
labels,
listeners,
moveRow,
Expand Down Expand Up @@ -90,6 +92,7 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
blocks={blocks}
duplicateRow={duplicateRow}
hasMaxRows={hasMaxRows}
isSortable={isSortable}
labels={labels}
moveRow={moveRow}
removeRow={removeRow}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const RowActions: React.FC<{
blocks: Block[]
duplicateRow: (rowIndex: number, blockType: string) => void
hasMaxRows?: boolean
isSortable?: boolean
labels: Labels
moveRow: (fromIndex: number, toIndex: number) => void
removeRow: (rowIndex: number) => void
Expand All @@ -25,6 +26,7 @@ export const RowActions: React.FC<{
blocks,
duplicateRow,
hasMaxRows,
isSortable,
labels,
moveRow,
removeRow,
Expand Down Expand Up @@ -59,6 +61,7 @@ export const RowActions: React.FC<{
duplicateRow={() => duplicateRow(rowIndex, blockType)}
hasMaxRows={hasMaxRows}
index={rowIndex}
isSortable={isSortable}
moveRow={moveRow}
removeRow={removeRow}
rowCount={rowCount}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const BlocksField: React.FC<Props> = (props) => {

const {
name,
admin: { className, condition, description, readOnly },
admin: { className, condition, description, isSortable = true, readOnly },
blocks,
fieldTypes,
forceRender = false,
Expand Down Expand Up @@ -230,7 +230,7 @@ const BlocksField: React.FC<Props> = (props) => {

if (blockToRender) {
return (
<DraggableSortableItem disabled={readOnly} id={row.id} key={row.id}>
<DraggableSortableItem disabled={readOnly || !isSortable} id={row.id} key={row.id}>
{(draggableSortableItemProps) => (
<BlockRow
{...draggableSortableItemProps}
Expand All @@ -242,6 +242,7 @@ const BlocksField: React.FC<Props> = (props) => {
forceRender={forceRender}
hasMaxRows={hasMaxRows}
indexPath={indexPath}
isSortable={isSortable}
labels={labels}
moveRow={moveRow}
path={path}
Expand Down
6 changes: 6 additions & 0 deletions packages/payload/src/fields/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ export const array = baseField.keys({
RowLabel: componentSchema,
})
.default({}),
isSortable: joi.boolean(),
})
.default({}),
dbName: joi.alternatives().try(joi.string(), joi.func()),
Expand Down Expand Up @@ -408,6 +409,11 @@ export const relationship = baseField.keys({
export const blocks = baseField.keys({
name: joi.string().required(),
type: joi.string().valid('blocks').required(),
admin: baseAdminFields
.keys({
isSortable: joi.boolean(),
})
.default({}),
blocks: joi
.array()
.items(
Expand Down
8 changes: 8 additions & 0 deletions packages/payload/src/fields/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,10 @@ export type ArrayField = FieldBase & {
RowLabel?: RowLabel
} & Admin['components']
initCollapsed?: boolean | false
/**
* Disable drag and drop sorting
*/
isSortable?: boolean
}
/**
* Customize the SQL table name
Expand Down Expand Up @@ -631,6 +635,10 @@ export type Block = {
export type BlockField = FieldBase & {
admin?: Admin & {
initCollapsed?: boolean | false
/**
* Disable drag and drop sorting
*/
isSortable?: boolean
}
blocks: Block[]
defaultValue?: unknown
Expand Down
15 changes: 15 additions & 0 deletions test/fields/collections/Array/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,21 @@ const ArrayFields: CollectionConfig = {
minRows: 2,
type: 'array',
},
{
name: 'disableSortItems',
defaultValue: arrayDefaultValue,
admin: {
isSortable: false,
},
fields: [
{
name: 'text',
required: true,
type: 'text',
},
],
type: 'array',
},
],
slug: arrayFieldsSlug,
versions: true,
Expand Down
11 changes: 11 additions & 0 deletions test/fields/collections/Array/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,15 @@ export const anotherArrayDoc: Partial<ArrayField> = {
text: 'second row',
},
],
disableSortItems: [
{
text: 'un-sortable item 1',
},
{
text: 'un-sortable item 2',
},
{
text: 'un-sortable item 3',
},
],
}
1 change: 1 addition & 0 deletions test/fields/collections/Blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const BlockFields: CollectionConfig = {
name: 'collapsedByDefaultBlocks',
admin: {
initCollapsed: true,
isSortable: false,
},
localized: true,
},
Expand Down
12 changes: 12 additions & 0 deletions test/fields/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,12 @@ describe('fields', () => {
})
})
})

test('should have disabled admin sorting', async () => {
await page.goto(url.create)
const field = page.locator('#field-collapsedByDefaultBlocks .array-actions__action-chevron')
expect(await field.count()).toEqual(0)
})
})

describe('array', () => {
Expand All @@ -716,6 +722,12 @@ describe('fields', () => {
await expect(field).toHaveValue('defaultValue')
})

test('should have disabled admin sorting', async () => {
await page.goto(url.create)
const field = page.locator('#field-disableSortItems .array-actions__action-chevron')
expect(await field.count()).toEqual(0)
})

test('should render RowLabel using a function', async () => {
const label = 'custom row label as function'
await page.goto(url.create)
Expand Down
4 changes: 4 additions & 0 deletions test/fields/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ export interface ArrayField {
id?: string | null
}[]
| null
disableSortItems?: {
text: string
id?: string | null
}[]
updatedAt: string
createdAt: string
}
Expand Down