This reverts commit 69c0d09 in #11390.
In order to future proof column prefs, it probably is best to continue
to use the current shape. This change was intended to ensure that as
little transformation to URL params was made as possible for #11387, but
we will likely transform them after all.
This will ensure that we can add support for additional properties over
time, as needed. For example, if we hypothetically wanted to add a
custom `label` or similar feature to columns prefs, it would make more
sense to use explicit properties to identity `accessor` and `active`.
For example:
```ts
[
{
accessor: "title",
active: true,
label: 'Custom Label' // hypothetical
}
]
```
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import type { ImportMap } from '../../bin/generateImportMap/index.js'
|
||||
import type { SanitizedConfig } from '../../config/types.js'
|
||||
import type { PaginatedDocs } from '../../database/types.js'
|
||||
import type { CollectionSlug, ColumnPreference } from '../../index.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { PayloadRequest, Sort, Where } from '../../types/index.js'
|
||||
|
||||
export type DefaultServerFunctionArgs = {
|
||||
@@ -50,7 +50,7 @@ export type ListQuery = {
|
||||
|
||||
export type BuildTableStateArgs = {
|
||||
collectionSlug: string | string[]
|
||||
columns?: ColumnPreference[]
|
||||
columns?: { accessor: string; active: boolean }[]
|
||||
docs?: PaginatedDocs['docs']
|
||||
enableRowSelections?: boolean
|
||||
parent?: {
|
||||
|
||||
@@ -1374,7 +1374,6 @@ export { restoreVersionOperation as restoreVersionOperationGlobal } from './glob
|
||||
export { updateOperation as updateOperationGlobal } from './globals/operations/update.js'
|
||||
export type {
|
||||
CollapsedPreferences,
|
||||
ColumnPreference,
|
||||
DocumentPreferences,
|
||||
FieldsPreferences,
|
||||
InsideFieldsPreferences,
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @todo remove this function and subsequent hooks in v4
|
||||
* They are used to transform the old shape of `columnPreferences` to new shape
|
||||
* i.e. ({ accessor: string, active: boolean })[] to ({ [accessor: string]: boolean })[]
|
||||
* In v4 can we use the new shape directly
|
||||
*/
|
||||
export const migrateColumns = (value: Record<string, any>) => {
|
||||
if (value && typeof value === 'object' && 'columns' in value && Array.isArray(value.columns)) {
|
||||
value.columns = value.columns.map((col) => {
|
||||
if ('accessor' in col) {
|
||||
return { [col.accessor]: col.active }
|
||||
}
|
||||
|
||||
return col
|
||||
})
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
import type { CollectionConfig } from '../collections/config/types.js'
|
||||
import type { Access, Config } from '../config/types.js'
|
||||
|
||||
import { migrateColumns } from './migrateColumns.js'
|
||||
import { deleteHandler } from './requestHandlers/delete.js'
|
||||
import { findByIDHandler } from './requestHandlers/findOne.js'
|
||||
import { updateHandler } from './requestHandlers/update.js'
|
||||
@@ -77,14 +76,6 @@ const getPreferencesCollection = (config: Config): CollectionConfig => ({
|
||||
{
|
||||
name: 'value',
|
||||
type: 'json',
|
||||
/**
|
||||
* @todo remove these hooks in v4
|
||||
* See `migrateColumns` for more information
|
||||
*/
|
||||
hooks: {
|
||||
afterRead: [({ value }) => migrateColumns(value)],
|
||||
beforeValidate: [({ value }) => migrateColumns(value)],
|
||||
},
|
||||
validate: (value) => {
|
||||
if (value) {
|
||||
try {
|
||||
|
||||
@@ -28,12 +28,8 @@ export type DocumentPreferences = {
|
||||
fields: FieldsPreferences
|
||||
}
|
||||
|
||||
export type ColumnPreference = {
|
||||
[key: string]: boolean
|
||||
}
|
||||
|
||||
export type ListPreferences = {
|
||||
columns?: ColumnPreference[]
|
||||
columns?: { accessor: string; active: boolean }[]
|
||||
limit?: number
|
||||
sort?: string
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import type {
|
||||
CollectionSlug,
|
||||
Column,
|
||||
ColumnPreference,
|
||||
JoinFieldClient,
|
||||
ListQuery,
|
||||
PaginatedDocs,
|
||||
@@ -26,6 +25,7 @@ import { useServerFunctions } from '../../providers/ServerFunctions/index.js'
|
||||
import { useTranslation } from '../../providers/Translation/index.js'
|
||||
import { hoistQueryParamsToAnd } from '../../utilities/mergeListSearchAndWhere.js'
|
||||
import { AnimateHeight } from '../AnimateHeight/index.js'
|
||||
import './index.scss'
|
||||
import { ColumnSelector } from '../ColumnSelector/index.js'
|
||||
import { useDocumentDrawer } from '../DocumentDrawer/index.js'
|
||||
import { Popup, PopupList } from '../Popup/index.js'
|
||||
@@ -33,7 +33,6 @@ import { RelationshipProvider } from '../Table/RelationshipProvider/index.js'
|
||||
import { TableColumnsProvider } from '../TableColumns/index.js'
|
||||
import { DrawerLink } from './cells/DrawerLink/index.js'
|
||||
import { RelationshipTablePagination } from './Pagination.js'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'relationship-table'
|
||||
|
||||
@@ -124,10 +123,11 @@ export const RelationshipTable: React.FC<RelationshipTableComponentProps> = (pro
|
||||
newQuery.where = hoistQueryParamsToAnd(newQuery.where, filterOptions)
|
||||
}
|
||||
|
||||
// map columns from string[] to ColumnPreference[]
|
||||
const defaultColumns: ColumnPreference[] = field.admin.defaultColumns
|
||||
// map columns from string[] to ListPreferences['columns']
|
||||
const defaultColumns = field.admin.defaultColumns
|
||||
? field.admin.defaultColumns.map((accessor) => ({
|
||||
[accessor]: true,
|
||||
accessor,
|
||||
active: true,
|
||||
}))
|
||||
: undefined
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import type {
|
||||
ClientComponentProps,
|
||||
ClientField,
|
||||
Column,
|
||||
ColumnPreference,
|
||||
DefaultCellComponentProps,
|
||||
DefaultServerCellComponentProps,
|
||||
Field,
|
||||
ListPreferences,
|
||||
PaginatedDocs,
|
||||
Payload,
|
||||
SanitizedCollectionConfig,
|
||||
@@ -39,8 +39,8 @@ type Args = {
|
||||
beforeRows?: Column[]
|
||||
clientCollectionConfig: ClientCollectionConfig
|
||||
collectionConfig: SanitizedCollectionConfig
|
||||
columnPreferences: ColumnPreference[]
|
||||
columns?: ColumnPreference[]
|
||||
columnPreferences: ListPreferences['columns']
|
||||
columns?: ListPreferences['columns']
|
||||
customCellProps: DefaultCellComponentProps['customCellProps']
|
||||
docs: PaginatedDocs['docs']
|
||||
enableRowSelections: boolean
|
||||
@@ -99,10 +99,10 @@ export const buildColumnState = (args: Args): Column[] => {
|
||||
|
||||
const sortTo = columnPreferences || columns
|
||||
|
||||
const sortFieldMap = (fieldMap, sortTo: ColumnPreference[]) =>
|
||||
const sortFieldMap = (fieldMap, sortTo) =>
|
||||
fieldMap?.sort((a, b) => {
|
||||
const aIndex = sortTo.findIndex((column) => 'name' in a && a.name in column)
|
||||
const bIndex = sortTo.findIndex((column) => 'name' in b && b.name in column)
|
||||
const aIndex = sortTo.findIndex((column) => 'name' in a && column.accessor === a.name)
|
||||
const bIndex = sortTo.findIndex((column) => 'name' in b && column.accessor === b.name)
|
||||
|
||||
if (aIndex === -1 && bIndex === -1) {
|
||||
return 0
|
||||
@@ -136,12 +136,18 @@ export const buildColumnState = (args: Args): Column[] => {
|
||||
(f) => 'name' in field && 'name' in f && f.name === field.name,
|
||||
)
|
||||
|
||||
const columnPreference = columnPreferences?.find(
|
||||
(preference) => field && 'name' in field && preference.accessor === field.name,
|
||||
)
|
||||
|
||||
let active = false
|
||||
|
||||
if (columnPreferences) {
|
||||
active = 'name' in field && columnPreferences?.some((col) => col?.[field.name])
|
||||
if (columnPreference) {
|
||||
active = columnPreference.active
|
||||
} else if (columns && Array.isArray(columns) && columns.length > 0) {
|
||||
active = 'name' in field && columns.some((col) => col?.[field.name])
|
||||
active = columns.find(
|
||||
(column) => field && 'name' in field && column.accessor === field.name,
|
||||
)?.active
|
||||
} else if (activeColumnsIndices.length < 4) {
|
||||
active = true
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import type { I18nClient } from '@payloadcms/translations'
|
||||
import type {
|
||||
ClientField,
|
||||
Column,
|
||||
ColumnPreference,
|
||||
DefaultCellComponentProps,
|
||||
DefaultServerCellComponentProps,
|
||||
Field,
|
||||
ListPreferences,
|
||||
PaginatedDocs,
|
||||
Payload,
|
||||
SanitizedCollectionConfig,
|
||||
@@ -36,8 +36,8 @@ import { filterFields } from './filterFields.js'
|
||||
|
||||
type Args = {
|
||||
beforeRows?: Column[]
|
||||
columnPreferences: ColumnPreference[]
|
||||
columns?: ColumnPreference[]
|
||||
columnPreferences: ListPreferences['columns']
|
||||
columns?: ListPreferences['columns']
|
||||
customCellProps: DefaultCellComponentProps['customCellProps']
|
||||
docs: PaginatedDocs['docs']
|
||||
enableRowSelections: boolean
|
||||
@@ -92,8 +92,8 @@ export const buildPolymorphicColumnState = (args: Args): Column[] => {
|
||||
|
||||
const sortFieldMap = (fieldMap, sortTo) =>
|
||||
fieldMap?.sort((a, b) => {
|
||||
const aIndex = sortTo.findIndex((column) => 'name' in a && a.name in column)
|
||||
const bIndex = sortTo.findIndex((column) => 'name' in b && b.name in column)
|
||||
const aIndex = sortTo.findIndex((column) => 'name' in a && column.accessor === a.name)
|
||||
const bIndex = sortTo.findIndex((column) => 'name' in b && column.accessor === b.name)
|
||||
|
||||
if (aIndex === -1 && bIndex === -1) {
|
||||
return 0
|
||||
@@ -127,12 +127,18 @@ export const buildPolymorphicColumnState = (args: Args): Column[] => {
|
||||
(f) => 'name' in field && 'name' in f && f.name === field.name,
|
||||
)
|
||||
|
||||
const columnPreference = columnPreferences?.find(
|
||||
(preference) => field && 'name' in field && preference.accessor === field.name,
|
||||
)
|
||||
|
||||
let active = false
|
||||
|
||||
if (columnPreferences) {
|
||||
active = 'name' in field && columnPreferences?.some((col) => col?.[field.name])
|
||||
if (columnPreference) {
|
||||
active = columnPreference.active
|
||||
} else if (columns && Array.isArray(columns) && columns.length > 0) {
|
||||
active = 'name' in field && columns.some((col) => col?.[field.name])
|
||||
active = columns.find(
|
||||
(column) => field && 'name' in field && column.accessor === field.name,
|
||||
)?.active
|
||||
} else if (activeColumnsIndices.length < 4) {
|
||||
active = true
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { ClientField, CollectionConfig, ColumnPreference, Field } from 'payload'
|
||||
import type { ClientField, CollectionConfig, Field, ListPreferences } from 'payload'
|
||||
|
||||
import { fieldAffectsData } from 'payload/shared'
|
||||
|
||||
const getRemainingColumns = <T extends ClientField[] | Field[]>(
|
||||
fields: T,
|
||||
useAsTitle: string,
|
||||
): ColumnPreference[] =>
|
||||
): ListPreferences['columns'] =>
|
||||
fields?.reduce((remaining, field) => {
|
||||
if (fieldAffectsData(field) && field.name === useAsTitle) {
|
||||
return remaining
|
||||
@@ -40,7 +40,7 @@ export const getInitialColumns = <T extends ClientField[] | Field[]>(
|
||||
fields: T,
|
||||
useAsTitle: CollectionConfig['admin']['useAsTitle'],
|
||||
defaultColumns: CollectionConfig['admin']['defaultColumns'],
|
||||
): ColumnPreference[] => {
|
||||
): ListPreferences['columns'] => {
|
||||
let initialColumns = []
|
||||
|
||||
if (Array.isArray(defaultColumns) && defaultColumns.length >= 1) {
|
||||
@@ -57,6 +57,7 @@ export const getInitialColumns = <T extends ClientField[] | Field[]>(
|
||||
}
|
||||
|
||||
return initialColumns.map((column) => ({
|
||||
[column]: true,
|
||||
accessor: column,
|
||||
active: true,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import type { Column, ColumnPreference, ListPreferences, SanitizedCollectionConfig } from 'payload'
|
||||
import type { Column, ListPreferences, SanitizedCollectionConfig } from 'payload'
|
||||
|
||||
import React, { createContext, useCallback, useContext, useEffect } from 'react'
|
||||
|
||||
@@ -39,10 +39,12 @@ type Props = {
|
||||
}
|
||||
|
||||
// strip out Heading, Label, and renderedCells properties, they cannot be sent to the server
|
||||
const formatColumnPreferences = (columns: Column[]): ColumnPreference[] =>
|
||||
columns.map(({ accessor, active }) => ({
|
||||
[accessor]: active,
|
||||
const sanitizeColumns = (columns: Column[]) => {
|
||||
return columns.map(({ accessor, active }) => ({
|
||||
accessor,
|
||||
active,
|
||||
}))
|
||||
}
|
||||
|
||||
export const TableColumnsProvider: React.FC<Props> = ({
|
||||
children,
|
||||
@@ -88,7 +90,7 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
|
||||
const result = await getTableState({
|
||||
collectionSlug,
|
||||
columns: formatColumnPreferences(withMovedColumn),
|
||||
columns: sanitizeColumns(withMovedColumn),
|
||||
docs,
|
||||
enableRowSelections,
|
||||
renderRowTypes,
|
||||
@@ -121,7 +123,7 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
|
||||
const { newColumnState, toggledColumns } = tableColumns.reduce<{
|
||||
newColumnState: Column[]
|
||||
toggledColumns: ColumnPreference[]
|
||||
toggledColumns: Pick<Column, 'accessor' | 'active'>[]
|
||||
}>(
|
||||
(acc, col) => {
|
||||
if (col.accessor === column) {
|
||||
@@ -131,12 +133,14 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
active: !col.active,
|
||||
})
|
||||
acc.toggledColumns.push({
|
||||
[col.accessor]: !col.active,
|
||||
accessor: col.accessor,
|
||||
active: !col.active,
|
||||
})
|
||||
} else {
|
||||
acc.newColumnState.push(col)
|
||||
acc.toggledColumns.push({
|
||||
[col.accessor]: col.active,
|
||||
accessor: col.accessor,
|
||||
active: col.active,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -178,8 +182,14 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
|
||||
const setActiveColumns = React.useCallback(
|
||||
async (activeColumnAccessors: string[]) => {
|
||||
const activeColumns: ColumnPreference[] = formatColumnPreferences(
|
||||
tableColumns.sort((first, second) => {
|
||||
const activeColumns: Pick<Column, 'accessor' | 'active'>[] = tableColumns
|
||||
.map((col) => {
|
||||
return {
|
||||
accessor: col.accessor,
|
||||
active: activeColumnAccessors.includes(col.accessor),
|
||||
}
|
||||
})
|
||||
.sort((first, second) => {
|
||||
const indexOfFirst = activeColumnAccessors.indexOf(first.accessor)
|
||||
const indexOfSecond = activeColumnAccessors.indexOf(second.accessor)
|
||||
|
||||
@@ -188,8 +198,7 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
}
|
||||
|
||||
return indexOfFirst > indexOfSecond ? 1 : -1
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
const { state: columnState, Table } = await getTableState({
|
||||
collectionSlug,
|
||||
@@ -230,7 +239,7 @@ export const TableColumnsProvider: React.FC<Props> = ({
|
||||
|
||||
if (collectionHasChanged || !listPreferences) {
|
||||
const currentPreferences = await getPreference<{
|
||||
columns: ColumnPreference[]
|
||||
columns: ListPreferences['columns']
|
||||
}>(preferenceKey)
|
||||
|
||||
prevCollection.current = defaultCollection
|
||||
|
||||
@@ -3,10 +3,9 @@ import type {
|
||||
ClientConfig,
|
||||
ClientField,
|
||||
CollectionConfig,
|
||||
Column,
|
||||
ColumnPreference,
|
||||
Field,
|
||||
ImportMap,
|
||||
ListPreferences,
|
||||
PaginatedDocs,
|
||||
Payload,
|
||||
SanitizedCollectionConfig,
|
||||
@@ -15,6 +14,9 @@ import type {
|
||||
import { getTranslation, type I18nClient } from '@payloadcms/translations'
|
||||
import { fieldAffectsData, fieldIsHiddenOrDisabled, flattenTopLevelFields } from 'payload/shared'
|
||||
|
||||
// eslint-disable-next-line payload/no-imports-from-exports-dir
|
||||
import type { Column } from '../exports/client/index.js'
|
||||
|
||||
import { RenderServerComponent } from '../elements/RenderServerComponent/index.js'
|
||||
import { buildColumnState } from '../elements/TableColumns/buildColumnState.js'
|
||||
import { buildPolymorphicColumnState } from '../elements/TableColumns/buildPolymorphicColumnState.js'
|
||||
@@ -69,8 +71,8 @@ export const renderTable = ({
|
||||
clientConfig?: ClientConfig
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
collections?: string[]
|
||||
columnPreferences: ColumnPreference[]
|
||||
columns?: ColumnPreference[]
|
||||
columnPreferences: ListPreferences['columns']
|
||||
columns?: ListPreferences['columns']
|
||||
customCellProps?: Record<string, any>
|
||||
docs: PaginatedDocs['docs']
|
||||
drawerSlug?: string
|
||||
@@ -107,7 +109,7 @@ export const renderTable = ({
|
||||
const columns = columnsFromArgs
|
||||
? columnsFromArgs?.filter((column) =>
|
||||
flattenTopLevelFields(fields, true)?.some(
|
||||
(field) => 'name' in field && column[field.name],
|
||||
(field) => 'name' in field && field.name === column.accessor,
|
||||
),
|
||||
)
|
||||
: getInitialColumns(fields, useAsTitle, [])
|
||||
@@ -128,7 +130,7 @@ export const renderTable = ({
|
||||
const columns = columnsFromArgs
|
||||
? columnsFromArgs?.filter((column) =>
|
||||
flattenTopLevelFields(clientCollectionConfig.fields, true)?.some(
|
||||
(field) => 'name' in field && field.name in column,
|
||||
(field) => 'name' in field && field.name === column.accessor,
|
||||
),
|
||||
)
|
||||
: getInitialColumns(
|
||||
|
||||
@@ -151,7 +151,6 @@ export function DefaultListView(props: ListViewClientProps) {
|
||||
])
|
||||
}
|
||||
}, [setStepNav, labels, drawerDepth])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<TableColumnsProvider
|
||||
|
||||
@@ -170,7 +170,12 @@ describe('Text', () => {
|
||||
user: client.user,
|
||||
key: 'text-fields-list',
|
||||
value: {
|
||||
columns: [{ disableListColumnText: true }],
|
||||
columns: [
|
||||
{
|
||||
accessor: 'disableListColumnText',
|
||||
active: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@payload-config": ["./test/_community/config.ts"],
|
||||
"@payload-config": ["./test/fields-relationship/config.ts"],
|
||||
"@payloadcms/live-preview": ["./packages/live-preview/src"],
|
||||
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
|
||||
"@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"],
|
||||
|
||||
Reference in New Issue
Block a user