feat: view component types (#11126)

It is currently very difficult to build custom edit and list views or
inject custom components into these views because these views and
components are not explicitly typed. Instances of these components were
not fully type safe as well, i.e. when rendering them via
`RenderServerComponent`, there was little to no type-checking in most
cases.

There is now a 1:1 type match for all views and view components and they
now receive type-checking at render time.

The following types have been newly added and/or improved:

List View:

  - `ListViewClientProps`
  - `ListViewServerProps`
  - `BeforeListClientProps`
  - `BeforeListServerProps`
  - `BeforeListTableClientProps`
  - `BeforeListTableServerProps`
  - `AfterListClientProps`
  - `AfterListServerProps`
  - `AfterListTableClientProps`
  - `AfterListTableServerProps`
  - `ListViewSlotSharedClientProps`

Document View:

  - `DocumentViewClientProps`
  - `DocumentViewServerProps`
  - `SaveButtonClientProps`
  - `SaveButtonServerProps`
  - `SaveDraftButtonClientProps`
  - `SaveDraftButtonServerProps`
  - `PublishButtonClientProps`
  - `PublishButtonServerProps`
  - `PreviewButtonClientProps`
  - `PreviewButtonServerProps`

Root View:

  - `AdminViewClientProps`
  - `AdminViewServerProps`

General:

  - `ViewDescriptionClientProps`
  - `ViewDescriptionServerProps`

A few other changes were made in a non-breaking way:

  - `Column` is now exported from `payload`
  - `ListPreferences` is now exported from `payload`
  - `ListViewSlots` is now exported from `payload`
  - `ListViewClientProps` is now exported from `payload`
- `AdminViewProps` is now an alias of `AdminViewServerProps` (listed
above)
- `ClientSideEditViewProps` is now an alias of `DocumentViewClientProps`
(listed above)
- `ServerSideEditViewProps` is now an alias of `DocumentViewServerProps`
(listed above)
- `ListComponentClientProps` is now an alias of `ListViewClientProps`
(listed above)
- `ListComponentServerProps` is now an alias of `ListViewServerProps`
(listed above)
- `CustomSaveButton` is now marked as deprecated because this is only
relevant to the config (see correct type above)
- `CustomSaveDraftButton` is now marked as deprecated because this is
only relevant to the config (see correct type above)
- `CustomPublishButton` is now marked as deprecated because this is only
relevant to the config (see correct type above)
- `CustomPreviewButton` is now marked as deprecated because this is only
relevant to the config (see correct type above)
 
This PR _does not_ apply these changes to _root_ components, i.e.
`afterNavLinks`. Those will come in a future PR.

Related: #10987.
This commit is contained in:
Jacob Fletcher
2025-02-17 14:08:23 -05:00
committed by GitHub
parent 938472bf1f
commit b80010b1a1
86 changed files with 683 additions and 495 deletions

View File

@@ -1,16 +1,16 @@
import type { DocumentTabConfig, DocumentTabProps } from 'payload' import type { DocumentTabConfig, DocumentTabServerProps, ServerProps } from 'payload'
import type React from 'react' import type React from 'react'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
import { Fragment } from 'react' import { Fragment } from 'react'
import './index.scss'
import { DocumentTabLink } from './TabLink.js' import { DocumentTabLink } from './TabLink.js'
import './index.scss'
export const baseClass = 'doc-tab' export const baseClass = 'doc-tab'
export const DocumentTab: React.FC< export const DocumentTab: React.FC<
{ readonly Pill_Component?: React.FC } & DocumentTabConfig & DocumentTabProps { readonly Pill_Component?: React.FC } & DocumentTabConfig & DocumentTabServerProps
> = (props) => { > = (props) => {
const { const {
apiURL, apiURL,
@@ -27,6 +27,7 @@ export const DocumentTab: React.FC<
Pill, Pill,
Pill_Component, Pill_Component,
} = props } = props
const { config } = payload const { config } = payload
const { routes } = config const { routes } = config
@@ -83,7 +84,7 @@ export const DocumentTab: React.FC<
i18n, i18n,
payload, payload,
permissions, permissions,
}, } satisfies ServerProps,
})} })}
</Fragment> </Fragment>
) : null} ) : null}

View File

@@ -1,5 +1,7 @@
import type { I18n } from '@payloadcms/translations' import type { I18n } from '@payloadcms/translations'
import type { import type {
DocumentTabClientProps,
DocumentTabServerPropsOnly,
Payload, Payload,
SanitizedCollectionConfig, SanitizedCollectionConfig,
SanitizedGlobalConfig, SanitizedGlobalConfig,
@@ -64,6 +66,7 @@ export const DocumentTabs: React.FC<{
return ( return (
<DocumentTab <DocumentTab
key={`tab-${index}`} key={`tab-${index}`}
path={viewConfig && 'path' in viewConfig ? viewConfig.path : ''}
{...{ {...{
...props, ...props,
...(tab || {}), ...(tab || {}),
@@ -83,7 +86,7 @@ export const DocumentTabs: React.FC<{
return RenderServerComponent({ return RenderServerComponent({
clientProps: { clientProps: {
path, path,
}, } satisfies DocumentTabClientProps,
Component: tab.Component, Component: tab.Component,
importMap: payload.importMap, importMap: payload.importMap,
key: `tab-custom-${index}`, key: `tab-custom-${index}`,
@@ -93,13 +96,14 @@ export const DocumentTabs: React.FC<{
i18n, i18n,
payload, payload,
permissions, permissions,
}, } satisfies DocumentTabServerPropsOnly,
}) })
} }
return ( return (
<DocumentTab <DocumentTab
key={`tab-custom-${index}`} key={`tab-custom-${index}`}
path={path}
{...{ {...{
...props, ...props,
...tab, ...tab,

View File

@@ -1,9 +1,9 @@
import type { EditViewComponent, PayloadServerReactComponent } from 'payload' import type { DocumentViewServerProps } from 'payload'
import React from 'react' import React from 'react'
import { APIViewClient } from './index.client.js' import { APIViewClient } from './index.client.js'
export const APIView: PayloadServerReactComponent<EditViewComponent> = () => { export function APIView(props: DocumentViewServerProps) {
return <APIViewClient /> return <APIViewClient />
} }

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps, DocumentViewServerPropsOnly } from 'payload'
import { DocumentInfoProvider, EditDepthProvider, HydrateAuthProvider } from '@payloadcms/ui' import { DocumentInfoProvider, EditDepthProvider, HydrateAuthProvider } from '@payloadcms/ui'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
@@ -18,11 +18,7 @@ import { Settings } from './Settings/index.js'
export { generateAccountMetadata } from './meta.js' export { generateAccountMetadata } from './meta.js'
export const Account: React.FC<AdminViewProps> = async ({ export async function Account({ initPageResult, params, searchParams }: AdminViewServerProps) {
initPageResult,
params,
searchParams,
}) => {
const { const {
languageOptions, languageOptions,
locale, locale,
@@ -153,6 +149,7 @@ export const Account: React.FC<AdminViewProps> = async ({
Fallback: EditView, Fallback: EditView,
importMap: payload.importMap, importMap: payload.importMap,
serverProps: { serverProps: {
doc: data,
i18n, i18n,
initPageResult, initPageResult,
locale, locale,
@@ -162,7 +159,7 @@ export const Account: React.FC<AdminViewProps> = async ({
routeSegments: [], routeSegments: [],
searchParams, searchParams,
user, user,
}, } satisfies DocumentViewServerPropsOnly,
})} })}
<AccountClient /> <AccountClient />
</EditDepthProvider> </EditDepthProvider>

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { buildFormState } from '@payloadcms/ui/utilities/buildFormState' import { buildFormState } from '@payloadcms/ui/utilities/buildFormState'
import React from 'react' import React from 'react'
@@ -11,7 +11,7 @@ import './index.scss'
export { generateCreateFirstUserMetadata } from './meta.js' export { generateCreateFirstUserMetadata } from './meta.js'
export const CreateFirstUserView: React.FC<AdminViewProps> = async ({ initPageResult }) => { export async function CreateFirstUserView({ initPageResult }: AdminViewServerProps) {
const { const {
locale, locale,
req, req,

View File

@@ -1,5 +1,5 @@
import type { groupNavItems } from '@payloadcms/ui/shared' import type { groupNavItems } from '@payloadcms/ui/shared'
import type { ClientUser, SanitizedPermissions, ServerProps, VisibleEntities } from 'payload' import type { ClientUser, Locale, ServerProps } from 'payload'
import { getTranslation } from '@payloadcms/translations' import { getTranslation } from '@payloadcms/translations'
import { Button, Card, Gutter, Locked } from '@payloadcms/ui' import { Button, Card, Gutter, Locked } from '@payloadcms/ui'
@@ -11,7 +11,11 @@ import './index.scss'
const baseClass = 'dashboard' const baseClass = 'dashboard'
export type DashboardProps = { export type DashboardViewClientProps = {
locale: Locale
}
export type DashboardViewServerPropsOnly = {
globalData: Array<{ globalData: Array<{
data: { _isLocked: boolean; _lastEditedAt: string; _userEditing: ClientUser | number | string } data: { _isLocked: boolean; _lastEditedAt: string; _userEditing: ClientUser | number | string }
lockDuration?: number lockDuration?: number
@@ -24,11 +28,11 @@ export type DashboardProps = {
*/ */
Link?: React.ComponentType Link?: React.ComponentType
navGroups?: ReturnType<typeof groupNavItems> navGroups?: ReturnType<typeof groupNavItems>
permissions: SanitizedPermissions
visibleEntities: VisibleEntities
} & ServerProps } & ServerProps
export const DefaultDashboard: React.FC<DashboardProps> = (props) => { export type DashboardViewServerProps = DashboardViewClientProps & DashboardViewServerPropsOnly
export function DefaultDashboard(props: DashboardViewServerProps) {
const { const {
globalData, globalData,
i18n, i18n,
@@ -65,7 +69,7 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
permissions, permissions,
searchParams, searchParams,
user, user,
}, } satisfies ServerProps,
})} })}
<Fragment> <Fragment>
@@ -182,7 +186,7 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
permissions, permissions,
searchParams, searchParams,
user, user,
}, } satisfies ServerProps,
})} })}
</Gutter> </Gutter>
</div> </div>

View File

@@ -1,20 +1,18 @@
import type { EntityToGroup } from '@payloadcms/ui/shared' import type { EntityToGroup } from '@payloadcms/ui/shared'
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { HydrateAuthProvider, SetStepNav } from '@payloadcms/ui' import { HydrateAuthProvider, SetStepNav } from '@payloadcms/ui'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
import { EntityType, groupNavItems } from '@payloadcms/ui/shared' import { EntityType, groupNavItems } from '@payloadcms/ui/shared'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
import type { DashboardViewClientProps, DashboardViewServerPropsOnly } from './Default/index.js'
import { DefaultDashboard } from './Default/index.js' import { DefaultDashboard } from './Default/index.js'
export { generateDashboardMetadata } from './meta.js' export { generateDashboardMetadata } from './meta.js'
export const Dashboard: React.FC<AdminViewProps> = async ({ export async function Dashboard({ initPageResult, params, searchParams }: AdminViewServerProps) {
initPageResult,
params,
searchParams,
}) => {
const { const {
locale, locale,
permissions, permissions,
@@ -108,7 +106,7 @@ export const Dashboard: React.FC<AdminViewProps> = async ({
{RenderServerComponent({ {RenderServerComponent({
clientProps: { clientProps: {
locale, locale,
}, } satisfies DashboardViewClientProps,
Component: config.admin?.components?.views?.dashboard?.Component, Component: config.admin?.components?.views?.dashboard?.Component,
Fallback: DefaultDashboard, Fallback: DefaultDashboard,
importMap: payload.importMap, importMap: payload.importMap,
@@ -123,7 +121,7 @@ export const Dashboard: React.FC<AdminViewProps> = async ({
searchParams, searchParams,
user, user,
visibleEntities, visibleEntities,
}, } satisfies DashboardViewServerPropsOnly,
})} })}
</Fragment> </Fragment>
) )

View File

@@ -1,12 +1,12 @@
import type { import type {
AdminViewProps, AdminViewServerProps,
DocumentViewServerProps,
PayloadComponent, PayloadComponent,
SanitizedCollectionConfig, SanitizedCollectionConfig,
SanitizedCollectionPermission, SanitizedCollectionPermission,
SanitizedConfig, SanitizedConfig,
SanitizedGlobalConfig, SanitizedGlobalConfig,
SanitizedGlobalPermission, SanitizedGlobalPermission,
ServerSideEditViewProps,
} from 'payload' } from 'payload'
import type React from 'react' import type React from 'react'
@@ -46,18 +46,18 @@ export const getViewsFromConfig = ({
overrideDocPermissions: true overrideDocPermissions: true
} }
)): { )): {
CustomView: ViewFromConfig<ServerSideEditViewProps> CustomView: ViewFromConfig<DocumentViewServerProps>
DefaultView: ViewFromConfig<ServerSideEditViewProps> DefaultView: ViewFromConfig<DocumentViewServerProps>
/** /**
* The error view to display if CustomView or DefaultView do not exist (could be either due to not found, or unauthorized). Can be null * The error view to display if CustomView or DefaultView do not exist (could be either due to not found, or unauthorized). Can be null
*/ */
ErrorView: ViewFromConfig<AdminViewProps> ErrorView: ViewFromConfig<AdminViewServerProps>
viewKey: string viewKey: string
} | null => { } | null => {
// Conditionally import and lazy load the default view // Conditionally import and lazy load the default view
let DefaultView: ViewFromConfig<ServerSideEditViewProps> = null let DefaultView: ViewFromConfig<DocumentViewServerProps> = null
let CustomView: ViewFromConfig<ServerSideEditViewProps> = null let CustomView: ViewFromConfig<DocumentViewServerProps> = null
let ErrorView: ViewFromConfig<AdminViewProps> = null let ErrorView: ViewFromConfig<AdminViewServerProps> = null
let viewKey: string let viewKey: string
const { const {

View File

@@ -145,6 +145,7 @@ export const renderDocumentHandler = async (args: {
disableActions, disableActions,
documentSubViewType: 'default', documentSubViewType: 'default',
drawerSlug, drawerSlug,
i18n,
importMap: payload.importMap, importMap: payload.importMap,
initialData, initialData,
initPageResult: { initPageResult: {
@@ -163,6 +164,7 @@ export const renderDocumentHandler = async (args: {
params: { params: {
segments: ['collections', collectionSlug, docID], segments: ['collections', collectionSlug, docID],
}, },
payload,
redirectAfterDelete, redirectAfterDelete,
redirectAfterDuplicate, redirectAfterDuplicate,
searchParams: {}, searchParams: {},

View File

@@ -1,4 +1,11 @@
import type { AdminViewProps, Data, PayloadComponent, ServerSideEditViewProps } from 'payload' import type {
AdminViewServerProps,
Data,
DocumentViewClientProps,
DocumentViewServerProps,
DocumentViewServerPropsOnly,
PayloadComponent,
} from 'payload'
import { DocumentInfoProvider, EditDepthProvider, HydrateAuthProvider } from '@payloadcms/ui' import { DocumentInfoProvider, EditDepthProvider, HydrateAuthProvider } from '@payloadcms/ui'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
@@ -41,8 +48,9 @@ export const renderDocument = async ({
searchParams, searchParams,
viewType, viewType,
}: { }: {
drawerSlug?: string
overrideEntityVisibility?: boolean overrideEntityVisibility?: boolean
} & AdminViewProps): Promise<{ } & AdminViewServerProps): Promise<{
data: Data data: Data
Document: React.ReactNode Document: React.ReactNode
}> => { }> => {
@@ -74,9 +82,9 @@ export const renderDocument = async ({
let isEditing = getIsEditing({ id: idFromArgs, collectionSlug, globalSlug }) let isEditing = getIsEditing({ id: idFromArgs, collectionSlug, globalSlug })
let RootViewOverride: PayloadComponent let RootViewOverride: PayloadComponent
let CustomView: ViewFromConfig<ServerSideEditViewProps> let CustomView: ViewFromConfig<DocumentViewServerProps>
let DefaultView: ViewFromConfig<ServerSideEditViewProps> let DefaultView: ViewFromConfig<DocumentViewServerProps>
let ErrorView: ViewFromConfig<AdminViewProps> let ErrorView: ViewFromConfig<AdminViewServerProps>
let apiURL: string let apiURL: string
@@ -161,7 +169,7 @@ export const renderDocument = async ({
}), }),
]) ])
const serverProps: ServerSideEditViewProps = { const documentViewServerProps: DocumentViewServerPropsOnly = {
doc, doc,
i18n, i18n,
initPageResult, initPageResult,
@@ -183,9 +191,11 @@ export const renderDocument = async ({
} }
const params = new URLSearchParams() const params = new URLSearchParams()
if (collectionConfig.versions?.drafts) { if (collectionConfig.versions?.drafts) {
params.append('draft', 'true') params.append('draft', 'true')
} }
if (locale?.code) { if (locale?.code) {
params.append('locale', locale.code) params.append('locale', locale.code)
} }
@@ -319,7 +329,12 @@ export const renderDocument = async ({
req, req,
}) })
const clientProps = { formState, ...documentSlots, documentSubViewType, viewType } const clientProps: DocumentViewClientProps = {
formState,
...documentSlots,
documentSubViewType,
viewType,
}
return { return {
data: doc, data: doc,
@@ -363,7 +378,7 @@ export const renderDocument = async ({
clientProps, clientProps,
Component: ErrorView.ComponentConfig || ErrorView.Component, Component: ErrorView.ComponentConfig || ErrorView.Component,
importMap, importMap,
serverProps, serverProps: documentViewServerProps,
}) })
: RenderServerComponent({ : RenderServerComponent({
clientProps, clientProps,
@@ -373,7 +388,7 @@ export const renderDocument = async ({
? CustomView?.ComponentConfig || CustomView?.Component ? CustomView?.ComponentConfig || CustomView?.Component
: DefaultView?.ComponentConfig || DefaultView?.Component, : DefaultView?.ComponentConfig || DefaultView?.Component,
importMap, importMap,
serverProps, serverProps: documentViewServerProps,
})} })}
</EditDepthProvider> </EditDepthProvider>
</DocumentInfoProvider> </DocumentInfoProvider>
@@ -381,16 +396,16 @@ export const renderDocument = async ({
} }
} }
export const Document: React.FC<AdminViewProps> = async (args) => { export async function Document(props: AdminViewServerProps) {
try { try {
const { Document: RenderedDocument } = await renderDocument(args) const { Document: RenderedDocument } = await renderDocument(props)
return RenderedDocument return RenderedDocument
} catch (error) { } catch (error) {
if (error?.message === 'NEXT_REDIRECT') { if (error?.message === 'NEXT_REDIRECT') {
throw error throw error
} }
logError({ err: error, payload: args.initPageResult.req.payload }) logError({ err: error, payload: props.initPageResult.req.payload })
if (error.message === 'not-found') { if (error.message === 'not-found') {
notFound() notFound()

View File

@@ -2,11 +2,17 @@ import type {
DefaultServerFunctionArgs, DefaultServerFunctionArgs,
DocumentSlots, DocumentSlots,
PayloadRequest, PayloadRequest,
PreviewButtonServerPropsOnly,
PublishButtonServerPropsOnly,
SanitizedCollectionConfig, SanitizedCollectionConfig,
SanitizedDocumentPermissions, SanitizedDocumentPermissions,
SanitizedGlobalConfig, SanitizedGlobalConfig,
SaveButtonServerPropsOnly,
SaveDraftButtonServerPropsOnly,
ServerProps, ServerProps,
StaticDescription, StaticDescription,
ViewDescriptionClientProps,
ViewDescriptionServerPropsOnly,
} from 'payload' } from 'payload'
import { ViewDescription } from '@payloadcms/ui' import { ViewDescription } from '@payloadcms/ui'
@@ -44,7 +50,7 @@ export const renderDocumentSlots: (args: {
components.PreviewButton = RenderServerComponent({ components.PreviewButton = RenderServerComponent({
Component: CustomPreviewButton, Component: CustomPreviewButton,
importMap: req.payload.importMap, importMap: req.payload.importMap,
serverProps, serverProps: serverProps satisfies PreviewButtonServerPropsOnly,
}) })
} }
@@ -64,11 +70,14 @@ export const renderDocumentSlots: (args: {
if (hasDescription) { if (hasDescription) {
components.Description = RenderServerComponent({ components.Description = RenderServerComponent({
clientProps: { description: staticDescription }, clientProps: {
collectionSlug: collectionConfig?.slug,
description: staticDescription,
} satisfies ViewDescriptionClientProps,
Component: CustomDescription, Component: CustomDescription,
Fallback: ViewDescription, Fallback: ViewDescription,
importMap: req.payload.importMap, importMap: req.payload.importMap,
serverProps, serverProps: serverProps satisfies ViewDescriptionServerPropsOnly,
}) })
} }
@@ -82,9 +91,10 @@ export const renderDocumentSlots: (args: {
components.PublishButton = RenderServerComponent({ components.PublishButton = RenderServerComponent({
Component: CustomPublishButton, Component: CustomPublishButton,
importMap: req.payload.importMap, importMap: req.payload.importMap,
serverProps, serverProps: serverProps satisfies PublishButtonServerPropsOnly,
}) })
} }
const CustomSaveDraftButton = const CustomSaveDraftButton =
collectionConfig?.admin?.components?.edit?.SaveDraftButton || collectionConfig?.admin?.components?.edit?.SaveDraftButton ||
globalConfig?.admin?.components?.elements?.SaveDraftButton globalConfig?.admin?.components?.elements?.SaveDraftButton
@@ -97,7 +107,7 @@ export const renderDocumentSlots: (args: {
components.SaveDraftButton = RenderServerComponent({ components.SaveDraftButton = RenderServerComponent({
Component: CustomSaveDraftButton, Component: CustomSaveDraftButton,
importMap: req.payload.importMap, importMap: req.payload.importMap,
serverProps, serverProps: serverProps satisfies SaveDraftButtonServerPropsOnly,
}) })
} }
} else { } else {
@@ -109,7 +119,7 @@ export const renderDocumentSlots: (args: {
components.SaveButton = RenderServerComponent({ components.SaveButton = RenderServerComponent({
Component: CustomSaveButton, Component: CustomSaveButton,
importMap: req.payload.importMap, importMap: req.payload.importMap,
serverProps, serverProps: serverProps satisfies SaveButtonServerPropsOnly,
}) })
} }
} }

View File

@@ -1,10 +1,10 @@
'use client' 'use client'
import type { ClientSideEditViewProps } from 'payload' import type { DocumentViewClientProps } from 'payload'
import { DefaultEditView } from '@payloadcms/ui' import { DefaultEditView } from '@payloadcms/ui'
import React from 'react' import React from 'react'
export const EditView: React.FC<ClientSideEditViewProps> = (props) => { export const EditView: React.FC<DocumentViewClientProps> = (props) => {
return <DefaultEditView {...props} /> return <DefaultEditView {...props} />
} }

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { Button, Link } from '@payloadcms/ui' import { Button, Link } from '@payloadcms/ui'
import { formatAdminURL, Translation } from '@payloadcms/ui/shared' import { formatAdminURL, Translation } from '@payloadcms/ui/shared'
@@ -11,7 +11,7 @@ export { generateForgotPasswordMetadata } from './meta.js'
export const forgotPasswordBaseClass = 'forgot-password' export const forgotPasswordBaseClass = 'forgot-password'
export const ForgotPasswordView: React.FC<AdminViewProps> = ({ initPageResult }) => { export function ForgotPasswordView({ initPageResult }: AdminViewServerProps) {
const { const {
req: { req: {
i18n, i18n,

View File

@@ -137,6 +137,7 @@ export const renderListHandler = async (args: {
disableBulkEdit, disableBulkEdit,
drawerSlug, drawerSlug,
enableRowSelections, enableRowSelections,
i18n,
importMap: payload.importMap, importMap: payload.importMap,
initPageResult: { initPageResult: {
collectionConfig: payload?.collections?.[collectionSlug]?.config, collectionConfig: payload?.collections?.[collectionSlug]?.config,
@@ -152,6 +153,7 @@ export const renderListHandler = async (args: {
params: { params: {
segments: ['collections', collectionSlug], segments: ['collections', collectionSlug],
}, },
payload,
query, query,
redirectAfterDelete, redirectAfterDelete,
redirectAfterDuplicate, redirectAfterDuplicate,

View File

@@ -1,10 +1,11 @@
import type { import type {
ListComponentClientProps, AdminViewServerProps,
ListComponentServerProps,
ListPreferences, ListPreferences,
ListQuery,
ListViewClientProps, ListViewClientProps,
} from '@payloadcms/ui' ListViewServerPropsOnly,
import type { AdminViewProps, ListQuery, Where } from 'payload' Where,
} from 'payload'
import { DefaultListView, HydrateAuthProvider, ListQueryProvider } from '@payloadcms/ui' import { DefaultListView, HydrateAuthProvider, ListQueryProvider } from '@payloadcms/ui'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
@@ -19,17 +20,18 @@ import { resolveAllFilterOptions } from './resolveAllFilterOptions.js'
export { generateListMetadata } from './meta.js' export { generateListMetadata } from './meta.js'
type ListViewArgs = { type RenderListViewArgs = {
customCellProps?: Record<string, any> customCellProps?: Record<string, any>
disableBulkDelete?: boolean disableBulkDelete?: boolean
disableBulkEdit?: boolean disableBulkEdit?: boolean
drawerSlug?: string
enableRowSelections: boolean enableRowSelections: boolean
overrideEntityVisibility?: boolean overrideEntityVisibility?: boolean
query: ListQuery query: ListQuery
} & AdminViewProps } & AdminViewServerProps
export const renderListView = async ( export const renderListView = async (
args: ListViewArgs, args: RenderListViewArgs,
): Promise<{ ): Promise<{
List: React.ReactNode List: React.ReactNode
}> => { }> => {
@@ -160,19 +162,20 @@ export const renderListView = async (
? collectionConfig.admin.description({ t: i18n.t }) ? collectionConfig.admin.description({ t: i18n.t })
: collectionConfig.admin.description : collectionConfig.admin.description
const sharedClientProps: ListComponentClientProps = { const newDocumentURL = formatAdminURL({
collectionSlug, adminRoute,
hasCreatePermission: permissions?.collections?.[collectionSlug]?.create, path: `/collections/${collectionSlug}/create`,
newDocumentURL: formatAdminURL({ })
adminRoute,
path: `/collections/${collectionSlug}/create`,
}),
}
const sharedServerProps: ListComponentServerProps = { const hasCreatePermission = permissions?.collections?.[collectionSlug]?.create
const serverProps: ListViewServerPropsOnly = {
collectionConfig, collectionConfig,
data,
i18n, i18n,
limit, limit,
listPreferences,
listSearchableFields: collectionConfig.admin.listSearchableFields,
locale: fullLocale, locale: fullLocale,
params, params,
payload, payload,
@@ -182,26 +185,17 @@ export const renderListView = async (
} }
const listViewSlots = renderListViewSlots({ const listViewSlots = renderListViewSlots({
clientProps: sharedClientProps, clientProps: {
collectionSlug,
hasCreatePermission,
newDocumentURL,
},
collectionConfig, collectionConfig,
description: staticDescription, description: staticDescription,
payload, payload,
serverProps: sharedServerProps, serverProps,
}) })
const clientProps: ListViewClientProps = {
...listViewSlots,
...sharedClientProps,
columnState,
disableBulkDelete,
disableBulkEdit,
enableRowSelections,
listPreferences,
renderedFilters,
resolvedFilterOptions,
Table,
}
const isInDrawer = Boolean(drawerSlug) const isInDrawer = Boolean(drawerSlug)
return { return {
@@ -215,16 +209,24 @@ export const renderListView = async (
modifySearchParams={!isInDrawer} modifySearchParams={!isInDrawer}
> >
{RenderServerComponent({ {RenderServerComponent({
clientProps, clientProps: {
...listViewSlots,
collectionSlug,
columnState,
disableBulkDelete,
disableBulkEdit,
enableRowSelections,
hasCreatePermission,
listPreferences,
newDocumentURL,
renderedFilters,
resolvedFilterOptions,
Table,
} satisfies ListViewClientProps,
Component: collectionConfig?.admin?.components?.views?.list?.Component, Component: collectionConfig?.admin?.components?.views?.list?.Component,
Fallback: DefaultListView, Fallback: DefaultListView,
importMap: payload.importMap, importMap: payload.importMap,
serverProps: { serverProps,
...sharedServerProps,
data,
listPreferences,
listSearchableFields: collectionConfig.admin.listSearchableFields,
},
})} })}
</ListQueryProvider> </ListQueryProvider>
</Fragment> </Fragment>
@@ -235,7 +237,7 @@ export const renderListView = async (
throw new Error('not-found') throw new Error('not-found')
} }
export const ListView: React.FC<ListViewArgs> = async (args) => { export const ListView: React.FC<RenderListViewArgs> = async (args) => {
try { try {
const { List: RenderedList } = await renderListView({ ...args, enableRowSelections: true }) const { List: RenderedList } = await renderListView({ ...args, enableRowSelections: true })
return RenderedList return RenderedList

View File

@@ -1,18 +1,29 @@
import type { import type {
ListComponentClientProps, AfterListClientProps,
ListComponentServerProps, AfterListTableClientProps,
AfterListTableServerPropsOnly,
BeforeListClientProps,
BeforeListServerPropsOnly,
BeforeListTableClientProps,
BeforeListTableServerPropsOnly,
ListViewServerPropsOnly,
ListViewSlots, ListViewSlots,
} from '@payloadcms/ui' ListViewSlotSharedClientProps,
import type { Payload, SanitizedCollectionConfig, StaticDescription } from 'payload' Payload,
SanitizedCollectionConfig,
StaticDescription,
ViewDescriptionClientProps,
ViewDescriptionServerPropsOnly,
} from 'payload'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
type Args = { type Args = {
clientProps: ListComponentClientProps clientProps: ListViewSlotSharedClientProps
collectionConfig: SanitizedCollectionConfig collectionConfig: SanitizedCollectionConfig
description?: StaticDescription description?: StaticDescription
payload: Payload payload: Payload
serverProps: ListComponentServerProps serverProps: ListViewServerPropsOnly
} }
export const renderListViewSlots = ({ export const renderListViewSlots = ({
@@ -26,49 +37,49 @@ export const renderListViewSlots = ({
if (collectionConfig.admin.components?.afterList) { if (collectionConfig.admin.components?.afterList) {
result.AfterList = RenderServerComponent({ result.AfterList = RenderServerComponent({
clientProps, clientProps: clientProps satisfies AfterListClientProps,
Component: collectionConfig.admin.components.afterList, Component: collectionConfig.admin.components.afterList,
importMap: payload.importMap, importMap: payload.importMap,
serverProps, serverProps: serverProps satisfies AfterListTableServerPropsOnly,
}) })
} }
if (collectionConfig.admin.components?.afterListTable) { if (collectionConfig.admin.components?.afterListTable) {
result.AfterListTable = RenderServerComponent({ result.AfterListTable = RenderServerComponent({
clientProps, clientProps: clientProps satisfies AfterListTableClientProps,
Component: collectionConfig.admin.components.afterListTable, Component: collectionConfig.admin.components.afterListTable,
importMap: payload.importMap, importMap: payload.importMap,
serverProps, serverProps: serverProps satisfies AfterListTableServerPropsOnly,
}) })
} }
if (collectionConfig.admin.components?.beforeList) { if (collectionConfig.admin.components?.beforeList) {
result.BeforeList = RenderServerComponent({ result.BeforeList = RenderServerComponent({
clientProps, clientProps: clientProps satisfies BeforeListClientProps,
Component: collectionConfig.admin.components.beforeList, Component: collectionConfig.admin.components.beforeList,
importMap: payload.importMap, importMap: payload.importMap,
serverProps, serverProps: serverProps satisfies BeforeListServerPropsOnly,
}) })
} }
if (collectionConfig.admin.components?.beforeListTable) { if (collectionConfig.admin.components?.beforeListTable) {
result.BeforeListTable = RenderServerComponent({ result.BeforeListTable = RenderServerComponent({
clientProps, clientProps: clientProps satisfies BeforeListTableClientProps,
Component: collectionConfig.admin.components.beforeListTable, Component: collectionConfig.admin.components.beforeListTable,
importMap: payload.importMap, importMap: payload.importMap,
serverProps, serverProps: serverProps satisfies BeforeListTableServerPropsOnly,
}) })
} }
if (collectionConfig.admin.components?.Description) { if (collectionConfig.admin.components?.Description) {
result.Description = RenderServerComponent({ result.Description = RenderServerComponent({
clientProps: { clientProps: {
collectionSlug: collectionConfig.slug,
description, description,
...clientProps, } satisfies ViewDescriptionClientProps,
},
Component: collectionConfig.admin.components.Description, Component: collectionConfig.admin.components.Description,
importMap: payload.importMap, importMap: payload.importMap,
serverProps, serverProps: serverProps satisfies ViewDescriptionServerPropsOnly,
}) })
} }

View File

@@ -1,11 +1,11 @@
import type { EditViewComponent, LivePreviewConfig, PayloadServerReactComponent } from 'payload' import type { DocumentViewServerProps, LivePreviewConfig } from 'payload'
import React from 'react' import React from 'react'
import './index.scss' import './index.scss'
import { LivePreviewClient } from './index.client.js' import { LivePreviewClient } from './index.client.js'
export const LivePreviewView: PayloadServerReactComponent<EditViewComponent> = async (props) => { export async function LivePreviewView(props: DocumentViewServerProps) {
const { doc, initPageResult } = props const { doc, initPageResult } = props
const { collectionConfig, globalConfig, locale, req } = initPageResult const { collectionConfig, globalConfig, locale, req } = initPageResult

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps, ServerProps } from 'payload'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
import { redirect } from 'next/navigation.js' import { redirect } from 'next/navigation.js'
@@ -12,7 +12,7 @@ export { generateLoginMetadata } from './meta.js'
export const loginBaseClass = 'login' export const loginBaseClass = 'login'
export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, searchParams }) => { export function LoginView({ initPageResult, params, searchParams }: AdminViewServerProps) {
const { locale, permissions, req } = initPageResult const { locale, permissions, req } = initPageResult
const { const {
@@ -24,7 +24,6 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
const { const {
admin: { components: { afterLogin, beforeLogin } = {}, user: userSlug }, admin: { components: { afterLogin, beforeLogin } = {}, user: userSlug },
collections,
routes: { admin }, routes: { admin },
} = config } = config
@@ -76,9 +75,8 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
permissions, permissions,
searchParams, searchParams,
user, user,
}, } satisfies ServerProps,
})} })}
{!collectionConfig?.auth?.disableLocalStrategy && ( {!collectionConfig?.auth?.disableLocalStrategy && (
<LoginForm <LoginForm
prefillEmail={prefillEmail} prefillEmail={prefillEmail}
@@ -98,7 +96,7 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
permissions, permissions,
searchParams, searchParams,
user, user,
}, } satisfies ServerProps,
})} })}
</Fragment> </Fragment>
) )

View File

@@ -1,9 +1,9 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import React from 'react' import React from 'react'
import './index.scss'
import { LogoutClient } from './LogoutClient.js' import { LogoutClient } from './LogoutClient.js'
import './index.scss'
const baseClass = 'logout' const baseClass = 'logout'
@@ -12,7 +12,7 @@ export { generateLogoutMetadata } from './meta.js'
export const LogoutView: React.FC< export const LogoutView: React.FC<
{ {
inactivity?: boolean inactivity?: boolean
} & AdminViewProps } & AdminViewServerProps
> = ({ inactivity, initPageResult, searchParams }) => { > = ({ inactivity, initPageResult, searchParams }) => {
const { const {
req: { req: {
@@ -35,6 +35,6 @@ export const LogoutView: React.FC<
) )
} }
export const LogoutInactivity: React.FC<AdminViewProps> = (props) => { export function LogoutInactivity(props: AdminViewServerProps) {
return <LogoutView inactivity {...props} /> return <LogoutView inactivity {...props} />
} }

View File

@@ -1,11 +1,6 @@
import type { I18n } from '@payloadcms/translations' import type { I18n } from '@payloadcms/translations'
import type { Metadata } from 'next' import type { Metadata } from 'next'
import type { import type { AdminViewServerProps, ImportMap, SanitizedConfig } from 'payload'
AdminViewComponent,
ImportMap,
PayloadServerReactComponent,
SanitizedConfig,
} from 'payload'
import { formatAdminURL } from '@payloadcms/ui/shared' import { formatAdminURL } from '@payloadcms/ui/shared'
import React from 'react' import React from 'react'
@@ -87,6 +82,6 @@ export const NotFoundPage = async ({
) )
} }
export const NotFoundView: PayloadServerReactComponent<AdminViewComponent> = () => { export function NotFoundView(props: AdminViewServerProps) {
return <NotFoundClient marginTop="large" /> return <NotFoundClient marginTop="large" />
} }

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { Button, Link } from '@payloadcms/ui' import { Button, Link } from '@payloadcms/ui'
import { formatAdminURL, Translation } from '@payloadcms/ui/shared' import { formatAdminURL, Translation } from '@payloadcms/ui/shared'
@@ -12,7 +12,7 @@ export const resetPasswordBaseClass = 'reset-password'
export { generateResetPasswordMetadata } from './meta.js' export { generateResetPasswordMetadata } from './meta.js'
export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params }) => { export function ResetPassword({ initPageResult, params }: AdminViewServerProps) {
const { req } = initPageResult const { req } = initPageResult
const { const {

View File

@@ -1,8 +1,8 @@
import type { import type {
AdminViewComponent, AdminViewServerProps,
AdminViewProps,
DocumentSubViewTypes, DocumentSubViewTypes,
ImportMap, ImportMap,
PayloadComponent,
SanitizedConfig, SanitizedConfig,
ServerPropsFromView, ServerPropsFromView,
ViewTypes, ViewTypes,
@@ -38,12 +38,12 @@ const baseClasses = {
} }
type OneSegmentViews = { type OneSegmentViews = {
[K in Exclude<keyof SanitizedConfig['admin']['routes'], 'reset'>]: React.FC<AdminViewProps> [K in Exclude<keyof SanitizedConfig['admin']['routes'], 'reset'>]: React.FC<AdminViewServerProps>
} }
export type ViewFromConfig = { export type ViewFromConfig = {
Component?: React.FC<AdminViewProps> Component?: React.FC<AdminViewServerProps>
payloadComponent?: AdminViewComponent payloadComponent?: PayloadComponent<AdminViewServerProps>
} }
const oneSegmentViews: OneSegmentViews = { const oneSegmentViews: OneSegmentViews = {

View File

@@ -1,6 +1,11 @@
import type { I18nClient } from '@payloadcms/translations' import type { I18nClient } from '@payloadcms/translations'
import type { Metadata } from 'next' import type { Metadata } from 'next'
import type { ImportMap, SanitizedConfig } from 'payload' import type {
AdminViewClientProps,
AdminViewServerPropsOnly,
ImportMap,
SanitizedConfig,
} from 'payload'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
import { formatAdminURL } from '@payloadcms/ui/shared' import { formatAdminURL } from '@payloadcms/ui/shared'
@@ -130,7 +135,7 @@ export const RootPage = async ({
}) })
const RenderedView = RenderServerComponent({ const RenderedView = RenderServerComponent({
clientProps: { clientConfig, documentSubViewType, viewType }, clientProps: { clientConfig, documentSubViewType, viewType } satisfies AdminViewClientProps,
Component: DefaultView.payloadComponent, Component: DefaultView.payloadComponent,
Fallback: DefaultView.Component, Fallback: DefaultView.Component,
importMap, importMap,
@@ -144,7 +149,7 @@ export const RootPage = async ({
params, params,
payload: initPageResult?.req.payload, payload: initPageResult?.req.payload,
searchParams, searchParams,
}, } satisfies AdminViewServerPropsOnly,
}) })
return ( return (

View File

@@ -1,4 +1,4 @@
import type { AdminViewComponent, PayloadServerReactComponent } from 'payload' import type { AdminViewServerProps } from 'payload'
import { Button } from '@payloadcms/ui' import { Button } from '@payloadcms/ui'
import { formatAdminURL } from '@payloadcms/ui/shared' import { formatAdminURL } from '@payloadcms/ui/shared'
@@ -11,9 +11,7 @@ export { generateUnauthorizedMetadata } from './meta.js'
const baseClass = 'unauthorized' const baseClass = 'unauthorized'
export const UnauthorizedView: PayloadServerReactComponent<AdminViewComponent> = ({ export function UnauthorizedView({ initPageResult }: AdminViewServerProps) {
initPageResult,
}) => {
const { const {
permissions, permissions,
req: { req: {

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { formatAdminURL } from '@payloadcms/ui/shared' import { formatAdminURL } from '@payloadcms/ui/shared'
import React from 'react' import React from 'react'
@@ -11,14 +11,10 @@ export const verifyBaseClass = 'verify'
export { generateVerifyMetadata } from './meta.js' export { generateVerifyMetadata } from './meta.js'
export const Verify: React.FC<AdminViewProps> = async ({ export async function Verify({ initPageResult, params, searchParams }: AdminViewServerProps) {
initPageResult,
params,
searchParams,
}) => {
// /:collectionSlug/verify/:token // /:collectionSlug/verify/:token
const [collectionSlug, verify, token] = params.segments const [collectionSlug, token] = params.segments
const { locale, permissions, req } = initPageResult const { locale, permissions, req } = initPageResult
const { const {

View File

@@ -1,8 +1,7 @@
import type { import type {
Document, Document,
EditViewComponent, DocumentViewServerProps,
OptionObject, OptionObject,
PayloadServerReactComponent,
SanitizedCollectionPermission, SanitizedCollectionPermission,
SanitizedGlobalPermission, SanitizedGlobalPermission,
} from 'payload' } from 'payload'
@@ -17,7 +16,7 @@ import { getLatestVersion } from '../Versions/getLatestVersion.js'
import { DefaultVersionView } from './Default/index.js' import { DefaultVersionView } from './Default/index.js'
import { RenderDiff } from './RenderFieldsToDiff/index.js' import { RenderDiff } from './RenderFieldsToDiff/index.js'
export const VersionView: PayloadServerReactComponent<EditViewComponent> = async (props) => { export async function VersionView(props: DocumentViewServerProps) {
const { i18n, initPageResult, routeSegments, searchParams } = props const { i18n, initPageResult, routeSegments, searchParams } = props
const { const {

View File

@@ -1,5 +1,6 @@
import type { I18n } from '@payloadcms/translations' import type { I18n } from '@payloadcms/translations'
import type { import type {
Column,
PaginatedDocs, PaginatedDocs,
SanitizedCollectionConfig, SanitizedCollectionConfig,
SanitizedConfig, SanitizedConfig,
@@ -7,7 +8,7 @@ import type {
TypeWithVersion, TypeWithVersion,
} from 'payload' } from 'payload'
import { type Column, SortColumn } from '@payloadcms/ui' import { SortColumn } from '@payloadcms/ui'
import React from 'react' import React from 'react'
import { AutosaveCell } from './cells/AutosaveCell/index.js' import { AutosaveCell } from './cells/AutosaveCell/index.js'

View File

@@ -1,8 +1,7 @@
'use client' 'use client'
import type { SanitizedCollectionConfig } from 'payload' import type { Column, SanitizedCollectionConfig } from 'payload'
import { import {
type Column,
LoadingOverlayToggle, LoadingOverlayToggle,
Pagination, Pagination,
PerPage, PerPage,

View File

@@ -1,11 +1,6 @@
import { Gutter, ListQueryProvider, SetDocumentStepNav } from '@payloadcms/ui' import { Gutter, ListQueryProvider, SetDocumentStepNav } from '@payloadcms/ui'
import { notFound } from 'next/navigation.js' import { notFound } from 'next/navigation.js'
import { import { type DocumentViewServerProps, logError, type PaginatedDocs } from 'payload'
type EditViewComponent,
logError,
type PaginatedDocs,
type PayloadServerReactComponent,
} from 'payload'
import { isNumber } from 'payload/shared' import { isNumber } from 'payload/shared'
import React from 'react' import React from 'react'
@@ -16,7 +11,7 @@ import './index.scss'
export const baseClass = 'versions' export const baseClass = 'versions'
export const VersionsView: PayloadServerReactComponent<EditViewComponent> = async (props) => { export async function VersionsView(props: DocumentViewServerProps) {
const { initPageResult, searchParams } = props const { initPageResult, searchParams } = props
const { const {

View File

@@ -1,3 +1,7 @@
import type { CustomComponent } from '../../config/types.js' import type { ServerProps } from '../../config/types.js'
export type CustomPreviewButton = CustomComponent export type PreviewButtonClientProps = {}
export type PreviewButtonServerPropsOnly = {} & ServerProps
export type PreviewButtonServerProps = PreviewButtonClientProps & PreviewButtonServerPropsOnly

View File

@@ -1,3 +1,9 @@
import type { CustomComponent } from '../../config/types.js' import type { ServerProps } from '../../config/types.js'
export type CustomPublishButton = CustomComponent export type PublishButtonClientProps = {
label?: string
}
export type PublishButtonServerPropsOnly = {} & ServerProps
export type PublishButtonServerProps = PublishButtonClientProps & PublishButtonServerPropsOnly

View File

@@ -1,3 +1,9 @@
import type { CustomComponent } from '../../config/types.js' import type { ServerProps } from '../../config/types.js'
export type CustomSaveButton = CustomComponent export type SaveButtonClientProps = {
label?: string
}
export type SaveButtonServerPropsOnly = {} & ServerProps
export type SaveButtonServerProps = SaveButtonClientProps & SaveButtonServerPropsOnly

View File

@@ -1,3 +1,7 @@
import type { CustomComponent } from '../../config/types.js' import type { ServerProps } from '../../config/types.js'
export type CustomSaveDraftButton = CustomComponent export type SaveDraftButtonClientProps = {}
export type SaveDraftButtonServerPropsOnly = {} & ServerProps
export type SaveDraftButtonServerProps = SaveDraftButtonClientProps & SaveDraftButtonServerPropsOnly

View File

@@ -0,0 +1,10 @@
import type { ClientField } from '../../fields/config/types.js'
export type Column = {
readonly accessor: string
readonly active: boolean
readonly CustomLabel?: React.ReactNode
readonly field: ClientField
readonly Heading: React.ReactNode
readonly renderedCells: React.ReactNode[]
}

View File

@@ -24,20 +24,58 @@ import type {
Row, Row,
} from './forms/Form.js' } from './forms/Form.js'
export type {
/**
* @deprecated
* The `CustomPreviewButton` type is deprecated and will be removed in the next major version.
* This type is only used for the Payload Config. Use `PreviewButtonClientProps` instead.
*/
CustomComponent as CustomPreviewButton,
/**
* @deprecated
* The `CustomPublishButton` type is deprecated and will be removed in the next major version.
* This type is only used for the Payload Config. Use `PreviewButtonClientProps` instead.
*/
CustomComponent as CustomPublishButton,
/**
* @deprecated
* The `CustomSaveButton` type is deprecated and will be removed in the next major version.
* This type is only used for the Payload Config. Use `PreviewButtonClientProps` instead.
*/
CustomComponent as CustomSaveButton,
/**
* @deprecated
* The `CustomSaveDraftButton` type is deprecated and will be removed in the next major version.
* This type is only used for the Payload Config. Use `PreviewButtonClientProps` instead.
*/
CustomComponent as CustomSaveDraftButton,
} from '../config/types.js'
export type { DefaultCellComponentProps, DefaultServerCellComponentProps } from './elements/Cell.js' export type { DefaultCellComponentProps, DefaultServerCellComponentProps } from './elements/Cell.js'
export type { ConditionalDateProps } from './elements/DatePicker.js' export type { ConditionalDateProps } from './elements/DatePicker.js'
export type { DayPickerProps, SharedProps, TimePickerProps } from './elements/DatePicker.js' export type { DayPickerProps, SharedProps, TimePickerProps } from './elements/DatePicker.js'
export type { NavGroupPreferences, NavPreferences } from './elements/Nav.js' export type { NavGroupPreferences, NavPreferences } from './elements/Nav.js'
export type { CustomPreviewButton } from './elements/PreviewButton.js'
export type { CustomPublishButton } from './elements/PublishButton.js'
export type { CustomSaveButton } from './elements/SaveButton.js'
export type { CustomSaveDraftButton } from './elements/SaveDraftButton.js'
export type { export type {
DocumentTabComponent, PreviewButtonClientProps,
DocumentTabCondition, PreviewButtonServerProps,
DocumentTabConfig, PreviewButtonServerPropsOnly,
DocumentTabProps, } from './elements/PreviewButton.js'
} from './elements/Tab.js' export type {
PublishButtonClientProps,
PublishButtonServerProps,
PublishButtonServerPropsOnly,
} from './elements/PublishButton.js'
export type {
SaveButtonClientProps,
SaveButtonServerProps,
SaveButtonServerPropsOnly,
} from './elements/SaveButton.js'
export type {
SaveDraftButtonClientProps,
SaveDraftButtonServerProps,
SaveDraftButtonServerPropsOnly,
} from './elements/SaveDraftButton.js'
export type { Column } from './elements/Table.js'
export type { CustomUpload } from './elements/Upload.js' export type { CustomUpload } from './elements/Upload.js'
@@ -397,14 +435,6 @@ export type {
VersionTab, VersionTab,
} from './forms/Diff.js' } from './forms/Diff.js'
export type {
FieldErrorClientComponent,
FieldErrorClientProps,
FieldErrorServerComponent,
FieldErrorServerProps,
GenericErrorProps,
} from './forms/Error.js'
export type { export type {
BuildFormStateArgs, BuildFormStateArgs,
Data, Data,
@@ -416,6 +446,14 @@ export type {
Row, Row,
} }
export type {
FieldErrorClientComponent,
FieldErrorClientProps,
FieldErrorServerComponent,
FieldErrorServerProps,
GenericErrorProps,
} from './forms/Error.js'
export type { export type {
ClientComponentProps, ClientComponentProps,
ClientFieldBase, ClientFieldBase,
@@ -438,18 +476,6 @@ export type {
export type { RowLabel, RowLabelComponent } from './forms/RowLabel.js' export type { RowLabel, RowLabelComponent } from './forms/RowLabel.js'
export type {
BuildTableStateArgs,
DefaultServerFunctionArgs,
ListQuery,
ServerFunction,
ServerFunctionArgs,
ServerFunctionClient,
ServerFunctionClientArgs,
ServerFunctionConfig,
ServerFunctionHandler,
} from './functions/index.js'
export type MappedServerComponent<TComponentClientProps extends JsonObject = JsonObject> = { export type MappedServerComponent<TComponentClientProps extends JsonObject = JsonObject> = {
Component?: React.ComponentType<TComponentClientProps> Component?: React.ComponentType<TComponentClientProps>
props?: Partial<any> props?: Partial<any>
@@ -535,20 +561,104 @@ export type DocumentSlots = {
Upload?: React.ReactNode Upload?: React.ReactNode
} }
export type {
BuildTableStateArgs,
DefaultServerFunctionArgs,
ListQuery,
ServerFunction,
ServerFunctionArgs,
ServerFunctionClient,
ServerFunctionClientArgs,
ServerFunctionConfig,
ServerFunctionHandler,
} from './functions/index.js'
export type { LanguageOptions } from './LanguageOptions.js' export type { LanguageOptions } from './LanguageOptions.js'
export type { RichTextAdapter, RichTextAdapterProvider, RichTextHooks } from './RichText.js' export type { RichTextAdapter, RichTextAdapterProvider, RichTextHooks } from './RichText.js'
export type { export type {
DocumentSubViewTypes,
DocumentTabClientProps,
/**
* @deprecated
* The `DocumentTabComponent` type is deprecated and will be removed in the next major version.
* Use `DocumentTabServerProps`or `DocumentTabClientProps` instead.
*/
DocumentTabComponent,
DocumentTabCondition,
DocumentTabConfig,
/**
* @deprecated
* The `DocumentTabProps` type is deprecated and will be removed in the next major version.
* Use `DocumentTabServerProps` instead.
*/
DocumentTabServerProps as DocumentTabProps,
DocumentTabServerProps,
DocumentTabServerPropsOnly,
/**
* @deprecated
* The `ClientSideEditViewProps` type is deprecated and will be removed in the next major version.
* Use `DocumentViewClientProps` instead.
*/
DocumentViewClientProps as ClientSideEditViewProps,
DocumentViewClientProps,
/**
* @deprecated
* The `ServerSideEditViewProps` is deprecated and will be removed in the next major version.
* Use `DocumentViewServerProps` instead.
*/
DocumentViewServerProps as ServerSideEditViewProps,
DocumentViewServerProps,
DocumentViewServerPropsOnly,
EditViewProps,
} from './views/document.js'
export type {
AdminViewClientProps,
/**
* @deprecated
* The `AdminViewComponent` type is deprecated and will be removed in the next major version.
* Type your component props directly instead.
*/
AdminViewComponent, AdminViewComponent,
AdminViewConfig, AdminViewConfig,
AdminViewProps, /**
ClientSideEditViewProps, * @deprecated
EditViewProps, * The `AdminViewProps` type is deprecated and will be removed in the next major version.
* Use `AdminViewServerProps` instead.
*/
AdminViewServerProps as AdminViewProps,
AdminViewServerProps,
AdminViewServerPropsOnly,
InitPageResult, InitPageResult,
ServerSideEditViewProps, ServerPropsFromView,
ViewDescriptionClientProps,
ViewDescriptionServerProps,
ViewDescriptionServerPropsOnly,
ViewTypes,
VisibleEntities, VisibleEntities,
} from './views/types.js' } from './views/index.js'
export type {
AfterListClientProps,
AfterListServerProps,
AfterListServerPropsOnly,
AfterListTableClientProps,
AfterListTableServerProps,
AfterListTableServerPropsOnly,
BeforeListClientProps,
BeforeListServerProps,
BeforeListServerPropsOnly,
BeforeListTableClientProps,
BeforeListTableServerProps,
BeforeListTableServerPropsOnly,
ListViewClientProps,
ListViewServerProps,
ListViewServerPropsOnly,
ListViewSlots,
ListViewSlotSharedClientProps,
} from './views/list.js'
type SchemaPath = {} & string type SchemaPath = {} & string
export type FieldSchemaMap = Map< export type FieldSchemaMap = Map<

View File

@@ -1,18 +1,45 @@
import type { I18n } from '@payloadcms/translations'
import type { SanitizedPermissions } from '../../auth/types.js' import type { SanitizedPermissions } from '../../auth/types.js'
import type { SanitizedCollectionConfig } from '../../collections/config/types.js' import type { SanitizedCollectionConfig } from '../../collections/config/types.js'
import type { PayloadComponent, SanitizedConfig } from '../../config/types.js' import type { PayloadComponent, SanitizedConfig, ServerProps } from '../../config/types.js'
import type { SanitizedGlobalConfig } from '../../globals/config/types.js' import type { SanitizedGlobalConfig } from '../../globals/config/types.js'
import type { Payload } from '../../index.js' import type { Data, DocumentSlots, FormState } from '../types.js'
import type { InitPageResult, ViewTypes } from './index.js'
export type DocumentTabProps = { export type EditViewProps = {
readonly collectionSlug?: string
readonly globalSlug?: string
}
export type DocumentViewServerPropsOnly = {
readonly doc: Data
readonly initPageResult: InitPageResult
readonly routeSegments: string[]
} & ServerProps
export type DocumentViewServerProps = DocumentViewClientProps & DocumentViewServerPropsOnly
export type DocumentViewClientProps = {
documentSubViewType: DocumentSubViewTypes
formState: FormState
viewType: ViewTypes
} & DocumentSlots
/**
* @todo: This should be renamed to `DocumentSubViewType` (singular)
*/
export type DocumentSubViewTypes = 'api' | 'default' | 'livePreview' | 'version' | 'versions'
export type DocumentTabServerPropsOnly = {
readonly apiURL?: string readonly apiURL?: string
readonly collectionConfig?: SanitizedCollectionConfig readonly collectionConfig?: SanitizedCollectionConfig
readonly globalConfig?: SanitizedGlobalConfig readonly globalConfig?: SanitizedGlobalConfig
readonly i18n: I18n
readonly payload: Payload
readonly permissions: SanitizedPermissions readonly permissions: SanitizedPermissions
} & ServerProps
export type DocumentTabServerProps = DocumentTabClientProps & DocumentTabServerPropsOnly
export type DocumentTabClientProps = {
path: string
} }
export type DocumentTabCondition = (args: { export type DocumentTabCondition = (args: {
@@ -42,6 +69,9 @@ export type DocumentTabConfig = {
readonly Pill?: PayloadComponent readonly Pill?: PayloadComponent
} }
/**
* @todo: Remove this type as it's only used internally for the config (above)
*/
export type DocumentTabComponent = PayloadComponent<{ export type DocumentTabComponent = PayloadComponent<{
path: string path: string
}> }>

View File

@@ -1,4 +1,4 @@
import type { ClientTranslationsObject } from '@payloadcms/translations' import type { ClientTranslationsObject, I18n } from '@payloadcms/translations'
import type { SanitizedPermissions } from '../../auth/index.js' import type { SanitizedPermissions } from '../../auth/index.js'
import type { ImportMap } from '../../bin/generateImportMap/index.js' import type { ImportMap } from '../../bin/generateImportMap/index.js'
@@ -8,17 +8,19 @@ import type {
CustomComponent, CustomComponent,
Locale, Locale,
MetaConfig, MetaConfig,
Params,
PayloadComponent, PayloadComponent,
SanitizedConfig, SanitizedConfig,
ServerProps, ServerProps,
} from '../../config/types.js' } from '../../config/types.js'
import type { SanitizedGlobalConfig } from '../../globals/config/types.js' import type { SanitizedGlobalConfig } from '../../globals/config/types.js'
import type { PayloadRequest } from '../../types/index.js' import type { Payload, PayloadRequest } from '../../types/index.js'
import type { LanguageOptions } from '../LanguageOptions.js' import type { LanguageOptions } from '../LanguageOptions.js'
import type { Data, DocumentSlots } from '../types.js' import type { Data, StaticDescription } from '../types.js'
import type { DocumentSubViewTypes } from './document.js'
export type AdminViewConfig = { export type AdminViewConfig = {
Component: AdminViewComponent Component: PayloadComponent
/** Whether the path should be matched exactly or as a prefix */ /** Whether the path should be matched exactly or as a prefix */
exact?: boolean exact?: boolean
meta?: MetaConfig meta?: MetaConfig
@@ -27,27 +29,32 @@ export type AdminViewConfig = {
strict?: boolean strict?: boolean
} }
export type AdminViewProps = { export type AdminViewClientProps = {
clientConfig: ClientConfig
documentSubViewType?: DocumentSubViewTypes
viewType: ViewTypes
}
export type AdminViewServerPropsOnly = {
readonly clientConfig: ClientConfig readonly clientConfig: ClientConfig
readonly disableActions?: boolean readonly disableActions?: boolean
readonly documentSubViewType?: DocumentSubViewTypes /**
readonly drawerSlug?: string * @todo remove `docID` here as it is already contained in `initPageResult`
*/
readonly docID?: number | string
readonly importMap: ImportMap readonly importMap: ImportMap
readonly initialData?: Data readonly initialData?: Data
readonly initPageResult: InitPageResult readonly initPageResult: InitPageResult
readonly params?: { [key: string]: string | string[] | undefined }
readonly redirectAfterDelete?: boolean readonly redirectAfterDelete?: boolean
readonly redirectAfterDuplicate?: boolean readonly redirectAfterDuplicate?: boolean
readonly searchParams: { [key: string]: string | string[] | undefined } } & ServerProps
readonly viewType: ViewTypes
}
export type AdminViewComponent = PayloadComponent<AdminViewProps> export type AdminViewServerProps = AdminViewClientProps & AdminViewServerPropsOnly
export type EditViewProps = { /**
readonly collectionSlug?: string * @deprecated This should be removed in favor of direct props
readonly globalSlug?: string */
} export type AdminViewComponent = PayloadComponent<AdminViewServerProps>
export type VisibleEntities = { export type VisibleEntities = {
collections: SanitizedCollectionConfig['slug'][] collections: SanitizedCollectionConfig['slug'][]
@@ -68,15 +75,9 @@ export type InitPageResult = {
visibleEntities: VisibleEntities visibleEntities: VisibleEntities
} }
export type ServerSideEditViewProps = { /**
readonly doc: Data * @todo This should be renamed to `ViewType` (singular)
readonly initPageResult: InitPageResult */
readonly routeSegments: string[]
} & ClientSideEditViewProps &
ServerProps
export type ClientSideEditViewProps = {} & DocumentSlots
export type ViewTypes = export type ViewTypes =
| 'account' | 'account'
| 'dashboard' | 'dashboard'
@@ -85,10 +86,19 @@ export type ViewTypes =
| 'reset' | 'reset'
| 'verify' | 'verify'
| 'version' | 'version'
export type DocumentSubViewTypes = 'api' | 'default' | 'livePreview' | 'version' | 'versions'
export type ServerPropsFromView = { export type ServerPropsFromView = {
collectionConfig?: SanitizedConfig['collections'][number] collectionConfig?: SanitizedConfig['collections'][number]
globalConfig?: SanitizedConfig['globals'][number] globalConfig?: SanitizedConfig['globals'][number]
viewActions: CustomComponent[] viewActions: CustomComponent[]
} }
// Description
export type ViewDescriptionClientProps = {
collectionSlug?: SanitizedCollectionConfig['slug']
description: StaticDescription
}
export type ViewDescriptionServerPropsOnly = {} & ServerProps
export type ViewDescriptionServerProps = ViewDescriptionClientProps & ViewDescriptionServerPropsOnly

View File

@@ -0,0 +1,75 @@
import type {
CollectionAdminOptions,
SanitizedCollectionConfig,
} from '../../collections/config/types.js'
import type { ServerProps } from '../../config/types.js'
import type { ListPreferences } from '../../preferences/types.js'
import type { ResolvedFilterOptions } from '../../types/index.js'
import type { Column } from '../elements/Table.js'
import type { Data } from '../types.js'
export type ListViewSlots = {
AfterList?: React.ReactNode
AfterListTable?: React.ReactNode
BeforeList?: React.ReactNode
BeforeListTable?: React.ReactNode
Description?: React.ReactNode
Table: React.ReactNode
}
/**
* The `ListViewServerPropsOnly` approach is needed to ensure type strictness when injecting component props
* There is no way to do something like `Omit<ListViewServerProps, keyof ListViewClientProps>`
* This is because `ListViewClientProps` is a union which is impossible to exclude from
* Exporting explicitly defined `ListViewServerPropsOnly`, etc. allows for the strictest typing
*/
export type ListViewServerPropsOnly = {
collectionConfig: SanitizedCollectionConfig
data: Data
limit: number
listPreferences: ListPreferences
listSearchableFields: CollectionAdminOptions['listSearchableFields']
} & ServerProps
export type ListViewServerProps = ListViewClientProps & ListViewServerPropsOnly
export type ListViewClientProps = {
beforeActions?: React.ReactNode[]
collectionSlug: SanitizedCollectionConfig['slug']
columnState: Column[]
disableBulkDelete?: boolean
disableBulkEdit?: boolean
enableRowSelections?: boolean
hasCreatePermission: boolean
listPreferences?: ListPreferences
newDocumentURL: string
preferenceKey?: string
renderedFilters?: Map<string, React.ReactNode>
resolvedFilterOptions?: Map<string, ResolvedFilterOptions>
} & ListViewSlots
export type ListViewSlotSharedClientProps = {
collectionSlug: SanitizedCollectionConfig['slug']
hasCreatePermission: boolean
newDocumentURL: string
}
// BeforeList
export type BeforeListClientProps = ListViewSlotSharedClientProps
export type BeforeListServerPropsOnly = {} & ListViewServerPropsOnly
export type BeforeListServerProps = BeforeListClientProps & BeforeListServerPropsOnly
// BeforeListTable
export type BeforeListTableClientProps = ListViewSlotSharedClientProps
export type BeforeListTableServerPropsOnly = {} & ListViewServerPropsOnly
export type BeforeListTableServerProps = BeforeListTableClientProps & BeforeListTableServerPropsOnly
// AfterList
export type AfterListClientProps = ListViewSlotSharedClientProps
export type AfterListServerPropsOnly = {} & ListViewServerPropsOnly
export type AfterListServerProps = AfterListClientProps & AfterListServerPropsOnly
// AfterListTable
export type AfterListTableClientProps = ListViewSlotSharedClientProps
export type AfterListTableServerPropsOnly = {} & ListViewServerPropsOnly
export type AfterListTableServerProps = AfterListTableClientProps & AfterListTableServerPropsOnly

View File

@@ -1,6 +1,6 @@
// @ts-strict-ignore // @ts-strict-ignore
import type { AdminViewConfig } from '../../admin/views/types.js' import type { AdminViewConfig } from '../../admin/views/index.js'
import type { SanitizedConfig } from '../../config/types.js' import type { SanitizedConfig } from '../../config/types.js'
import type { AddToImportMap, Imports, InternalImportMap } from './index.js' import type { AddToImportMap, Imports, InternalImportMap } from './index.js'

View File

@@ -1,13 +1,7 @@
import type { GraphQLInputObjectType, GraphQLNonNull, GraphQLObjectType } from 'graphql' import type { GraphQLInputObjectType, GraphQLNonNull, GraphQLObjectType } from 'graphql'
import type { DeepRequired, IsAny, MarkOptional } from 'ts-essentials' import type { DeepRequired, IsAny, MarkOptional } from 'ts-essentials'
import type { import type { CustomUpload } from '../../admin/types.js'
CustomPreviewButton,
CustomPublishButton,
CustomSaveButton,
CustomSaveDraftButton,
CustomUpload,
} from '../../admin/types.js'
import type { Arguments as MeArguments } from '../../auth/operations/me.js' import type { Arguments as MeArguments } from '../../auth/operations/me.js'
import type { import type {
Arguments as RefreshArguments, Arguments as RefreshArguments,
@@ -287,23 +281,23 @@ export type CollectionAdminOptions = {
/** /**
* Replaces the "Preview" button * Replaces the "Preview" button
*/ */
PreviewButton?: CustomPreviewButton PreviewButton?: CustomComponent
/** /**
* Replaces the "Publish" button * Replaces the "Publish" button
* + drafts must be enabled * + drafts must be enabled
*/ */
PublishButton?: CustomPublishButton PublishButton?: CustomComponent
/** /**
* Replaces the "Save" button * Replaces the "Save" button
* + drafts must be disabled * + drafts must be disabled
*/ */
SaveButton?: CustomSaveButton SaveButton?: CustomComponent
/** /**
* Replaces the "Save Draft" button * Replaces the "Save Draft" button
* + drafts must be enabled * + drafts must be enabled
* + autosave must be disabled * + autosave must be disabled
*/ */
SaveDraftButton?: CustomSaveDraftButton SaveDraftButton?: CustomComponent
/** /**
* Replaces the "Upload" section * Replaces the "Upload" section
* + upload must be enabled * + upload must be enabled

View File

@@ -14,18 +14,16 @@ import type { JSONSchema4 } from 'json-schema'
import type { DestinationStream, Level, pino } from 'pino' import type { DestinationStream, Level, pino } from 'pino'
import type React from 'react' import type React from 'react'
import type { default as sharp } from 'sharp' import type { default as sharp } from 'sharp'
import type { DeepRequired, MarkOptional } from 'ts-essentials' import type { DeepRequired } from 'ts-essentials'
import type { RichTextAdapterProvider } from '../admin/RichText.js' import type { RichTextAdapterProvider } from '../admin/RichText.js'
import type { DocumentTabConfig, RichTextAdapter } from '../admin/types.js'
import type { import type {
AdminViewConfig,
DocumentSubViewTypes, DocumentSubViewTypes,
ServerPropsFromView, DocumentTabConfig,
ServerSideEditViewProps, DocumentViewServerProps,
ViewTypes, RichTextAdapter,
VisibleEntities, } from '../admin/types.js'
} from '../admin/views/types.js' import type { AdminViewConfig, ViewTypes, VisibleEntities } from '../admin/views/index.js'
import type { SanitizedPermissions } from '../auth/index.js' import type { SanitizedPermissions } from '../auth/index.js'
import type { import type {
AddToImportMap, AddToImportMap,
@@ -383,7 +381,7 @@ export type Endpoint = {
root?: never root?: never
} }
export type EditViewComponent = PayloadComponent<ServerSideEditViewProps> export type EditViewComponent = PayloadComponent<DocumentViewServerProps>
export type EditViewConfig = { export type EditViewConfig = {
meta?: MetaConfig meta?: MetaConfig
@@ -407,22 +405,20 @@ export type EditViewConfig = {
} }
) )
type ClientProps = { export type Params = { [key: string]: string | string[] | undefined }
readonly [key: string]: unknown
}
export type ServerProps = { export type ServerProps = {
readonly documentSubViewType?: DocumentSubViewTypes readonly documentSubViewType?: DocumentSubViewTypes
readonly i18n: I18nClient readonly i18n: I18nClient
readonly locale?: Locale readonly locale?: Locale
readonly params?: { [key: string]: string | string[] | undefined } readonly params?: Params
readonly payload: Payload readonly payload: Payload
readonly permissions?: SanitizedPermissions readonly permissions?: SanitizedPermissions
readonly searchParams?: { [key: string]: string | string[] | undefined } readonly searchParams?: Params
readonly user?: TypedUser readonly user?: TypedUser
readonly viewType?: ViewTypes readonly viewType?: ViewTypes
readonly visibleEntities?: VisibleEntities readonly visibleEntities?: VisibleEntities
} & ClientProps }
export const serverProps: (keyof ServerProps)[] = [ export const serverProps: (keyof ServerProps)[] = [
'payload', 'payload',
@@ -1272,5 +1268,3 @@ export type EntityDescriptionFunction = ({ t }: { t: TFunction }) => string
export type EntityDescription = EntityDescriptionFunction | Record<string, string> | string export type EntityDescription = EntityDescriptionFunction | Record<string, string> | string
export type { EmailAdapter, SendEmailOptions } export type { EmailAdapter, SendEmailOptions }
export type { DocumentSubViewTypes, ServerPropsFromView, ViewTypes }

View File

@@ -1,7 +1,5 @@
'use client' 'use client'
import type { import type {
ClientCollectionConfig,
ClientGlobalConfig,
ClientUser, ClientUser,
SanitizedCollectionConfig, SanitizedCollectionConfig,
SanitizedCollectionPermission, SanitizedCollectionPermission,

View File

@@ -1,4 +1,6 @@
'use client' 'use client'
import type { PreviewButtonClientProps } from 'payload'
import React from 'react' import React from 'react'
import { Button } from '../Button/index.js' import { Button } from '../Button/index.js'
@@ -6,7 +8,7 @@ import { usePreviewURL } from './usePreviewURL.js'
const baseClass = 'preview-btn' const baseClass = 'preview-btn'
export const PreviewButton: React.FC = () => { export function PreviewButton(props: PreviewButtonClientProps) {
const { generatePreviewURL, label } = usePreviewURL() const { generatePreviewURL, label } = usePreviewURL()
return ( return (

View File

@@ -1,9 +1,8 @@
import type { ClientConfig } from 'payload' import type { ClientConfig, Column } from 'payload'
import { getTranslation, type I18nClient, type TFunction } from '@payloadcms/translations' import { getTranslation, type I18nClient, type TFunction } from '@payloadcms/translations'
import React from 'react' import React from 'react'
import type { Column } from '../../Table/index.js'
import type { UpcomingEvent } from './types.js' import type { UpcomingEvent } from './types.js'
import { formatDate } from '../../../utilities/formatDate.js' import { formatDate } from '../../../utilities/formatDate.js'

View File

@@ -1,7 +1,7 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
'use client' 'use client'
import type { Where } from 'payload' import type { Column, Where } from 'payload'
import { TZDateMini as TZDate } from '@date-fns/tz/date/mini' import { TZDateMini as TZDate } from '@date-fns/tz/date/mini'
import { useModal } from '@faceless-ui/modal' import { useModal } from '@faceless-ui/modal'
@@ -11,7 +11,6 @@ import * as qs from 'qs-esm'
import React, { useCallback, useMemo } from 'react' import React, { useCallback, useMemo } from 'react'
import { toast } from 'sonner' import { toast } from 'sonner'
import type { Column } from '../../Table/index.js'
import type { PublishType, UpcomingEvent } from './types.js' import type { PublishType, UpcomingEvent } from './types.js'
import { FieldLabel } from '../../../fields/FieldLabel/index.js' import { FieldLabel } from '../../../fields/FieldLabel/index.js'

View File

@@ -1,5 +1,7 @@
'use client' 'use client'
import type { PublishButtonClientProps } from 'payload'
import { useModal } from '@faceless-ui/modal' import { useModal } from '@faceless-ui/modal'
import * as qs from 'qs-esm' import * as qs from 'qs-esm'
import React, { useCallback } from 'react' import React, { useCallback } from 'react'
@@ -16,7 +18,7 @@ import { useTranslation } from '../../providers/Translation/index.js'
import { PopupList } from '../Popup/index.js' import { PopupList } from '../Popup/index.js'
import { ScheduleDrawer } from './ScheduleDrawer/index.js' import { ScheduleDrawer } from './ScheduleDrawer/index.js'
export const PublishButton: React.FC<{ label?: string }> = ({ label: labelProp }) => { export function PublishButton({ label: labelProp }: PublishButtonClientProps) {
const { const {
id, id,
collectionSlug, collectionSlug,

View File

@@ -1,11 +1,10 @@
'use client' 'use client'
import type { JoinFieldClient, ListQuery, PaginatedDocs, Where } from 'payload' import type { Column, JoinFieldClient, ListQuery, PaginatedDocs, Where } from 'payload'
import { getTranslation } from '@payloadcms/translations' import { getTranslation } from '@payloadcms/translations'
import React, { Fragment, useCallback, useEffect, useState } from 'react' import React, { Fragment, useCallback, useEffect, useState } from 'react'
import type { DocumentDrawerProps } from '../DocumentDrawer/types.js' import type { DocumentDrawerProps } from '../DocumentDrawer/types.js'
import type { Column } from '../Table/index.js'
import { Button } from '../../elements/Button/index.js' import { Button } from '../../elements/Button/index.js'
import { Pill } from '../../elements/Pill/index.js' import { Pill } from '../../elements/Pill/index.js'

View File

@@ -1,5 +1,7 @@
'use client' 'use client'
import type { SaveButtonClientProps } from 'payload'
import React, { useRef } from 'react' import React, { useRef } from 'react'
import { useForm, useFormModified } from '../../forms/Form/context.js' import { useForm, useFormModified } from '../../forms/Form/context.js'
@@ -10,7 +12,7 @@ import { useEditDepth } from '../../providers/EditDepth/index.js'
import { useOperation } from '../../providers/Operation/index.js' import { useOperation } from '../../providers/Operation/index.js'
import { useTranslation } from '../../providers/Translation/index.js' import { useTranslation } from '../../providers/Translation/index.js'
export const SaveButton: React.FC<{ label?: string }> = ({ label: labelProp }) => { export function SaveButton({ label: labelProp }: SaveButtonClientProps) {
const { uploadStatus } = useDocumentInfo() const { uploadStatus } = useDocumentInfo()
const { t } = useTranslation() const { t } = useTranslation()
const { submit } = useForm() const { submit } = useForm()

View File

@@ -1,5 +1,7 @@
'use client' 'use client'
import type { SaveDraftButtonClientProps } from 'payload'
import React, { useCallback, useRef } from 'react' import React, { useCallback, useRef } from 'react'
import { useForm, useFormModified } from '../../forms/Form/context.js' import { useForm, useFormModified } from '../../forms/Form/context.js'
@@ -14,7 +16,7 @@ import { useTranslation } from '../../providers/Translation/index.js'
const baseClass = 'save-draft' const baseClass = 'save-draft'
export const SaveDraftButton: React.FC = () => { export function SaveDraftButton(props: SaveDraftButtonClientProps) {
const { const {
config: { config: {
routes: { api }, routes: { api },

View File

@@ -1,6 +1,6 @@
'use client' 'use client'
import type { ClientField } from 'payload' import type { Column } from 'payload'
import React from 'react' import React from 'react'
@@ -8,15 +8,6 @@ import './index.scss'
const baseClass = 'table' const baseClass = 'table'
export type Column = {
readonly accessor: string
readonly active: boolean
readonly CustomLabel?: React.ReactNode
readonly field: ClientField
readonly Heading: React.ReactNode
readonly renderedCells: React.ReactNode[]
}
export type Props = { export type Props = {
readonly appearance?: 'condensed' | 'default' readonly appearance?: 'condensed' | 'default'
readonly columns?: Column[] readonly columns?: Column[]

View File

@@ -3,6 +3,7 @@ import type {
ClientCollectionConfig, ClientCollectionConfig,
ClientComponentProps, ClientComponentProps,
ClientField, ClientField,
Column,
DefaultCellComponentProps, DefaultCellComponentProps,
DefaultServerCellComponentProps, DefaultServerCellComponentProps,
Field, Field,
@@ -24,7 +25,6 @@ import {
import React from 'react' import React from 'react'
import type { SortColumnProps } from '../SortColumn/index.js' import type { SortColumnProps } from '../SortColumn/index.js'
import type { Column } from '../Table/index.js'
import { import {
RenderCustomComponent, RenderCustomComponent,

View File

@@ -1,10 +1,9 @@
'use client' 'use client'
import type { ClientCollectionConfig, ListPreferences, SanitizedCollectionConfig } from 'payload' import type { Column, ListPreferences, SanitizedCollectionConfig } from 'payload'
import React, { createContext, useCallback, useContext, useEffect } from 'react' import React, { createContext, useCallback, useContext, useEffect } from 'react'
import type { SortColumnProps } from '../SortColumn/index.js' import type { SortColumnProps } from '../SortColumn/index.js'
import type { Column } from '../Table/index.js'
import { useConfig } from '../../providers/Config/index.js' import { useConfig } from '../../providers/Config/index.js'
import { usePreferences } from '../../providers/Preferences/index.js' import { usePreferences } from '../../providers/Preferences/index.js'

View File

@@ -1,5 +1,5 @@
'use client' 'use client'
import type { DescriptionFunction, StaticDescription } from 'payload' import type { DescriptionFunction, StaticDescription, ViewDescriptionClientProps } from 'payload'
import { getTranslation } from '@payloadcms/translations' import { getTranslation } from '@payloadcms/translations'
import React from 'react' import React from 'react'
@@ -10,15 +10,11 @@ export type ViewDescriptionComponent = React.ComponentType<any>
type Description = DescriptionFunction | StaticDescription | string | ViewDescriptionComponent type Description = DescriptionFunction | StaticDescription | string | ViewDescriptionComponent
export type ViewDescriptionProps = {
readonly description?: StaticDescription
}
export function isComponent(description: Description): description is ViewDescriptionComponent { export function isComponent(description: Description): description is ViewDescriptionComponent {
return React.isValidElement(description) return React.isValidElement(description)
} }
export const ViewDescription: React.FC<ViewDescriptionProps> = (props) => { export function ViewDescription(props: ViewDescriptionClientProps) {
const { i18n } = useTranslation() const { i18n } = useTranslation()
const { description } = props const { description } = props

View File

@@ -114,7 +114,15 @@ export {
RelationshipProvider, RelationshipProvider,
useListRelationships, useListRelationships,
} from '../../elements/Table/RelationshipProvider/index.js' } from '../../elements/Table/RelationshipProvider/index.js'
export { type Column, Table } from '../../elements/Table/index.js' export { Table } from '../../elements/Table/index.js'
export type {
/**
* @deprecated
* This export will be removed in the next major version.
* Use `import { Column } from 'payload'` instead.
*/
Column,
} from 'payload'
export { DefaultCell } from '../../elements/Table/DefaultCell/index.js' export { DefaultCell } from '../../elements/Table/DefaultCell/index.js'
export { Thumbnail } from '../../elements/Thumbnail/index.js' export { Thumbnail } from '../../elements/Thumbnail/index.js'
export { Tooltip } from '../../elements/Tooltip/index.js' export { Tooltip } from '../../elements/Tooltip/index.js'
@@ -293,20 +301,52 @@ export { SelectAll } from '../../elements/SelectAll/index.js'
export { SelectRow } from '../../elements/SelectRow/index.js' export { SelectRow } from '../../elements/SelectRow/index.js'
export { SelectMany } from '../../elements/SelectMany/index.js' export { SelectMany } from '../../elements/SelectMany/index.js'
export { export { DefaultListView } from '../../views/List/index.js'
DefaultListView,
type ListViewClientProps,
type ListViewSlots,
} from '../../views/List/index.js'
export type { ListComponentClientProps, ListComponentServerProps } from '../../views/List/types.js' export type {
/**
* @deprecated
* This export will be removed in the next major version.
* Use `import type { ListViewSlots } from 'payload'` instead.
*/
ListViewSlots,
} from 'payload'
/* export type {
@deprecated /**
This export will be removed in the next major version. * @deprecated
Use `import { ListPreferences } from 'payload'` instead. * This export will be removed in the next major version.
*/ * Use `import type { ListViewClientProps } from 'payload'` instead.
export type { ListPreferences } from 'payload' */
ListViewClientProps,
} from 'payload'
export type {
/**
* @deprecated
* This export will be removed in the next major version.
* Use `import type { ListViewClientProps } from 'payload'` instead.
*/
ListViewClientProps as ListComponentClientProps,
} from 'payload'
export type {
/**
* @deprecated
* This export will be removed in the next major version.
* Use `import type { ListViewServerProps } from 'payload'` instead.
*/
ListViewServerProps as ListComponentServerProps,
} from 'payload'
export type {
/**
* @deprecated
* This export will be removed in the next major version.
* Use `import type { ListPreferences } from 'payload'` instead.
*/
ListPreferences,
} from 'payload'
export type { ListHeaderProps } from '../../views/List/ListHeader/index.js' export type { ListHeaderProps } from '../../views/List/ListHeader/index.js'

View File

@@ -2,6 +2,7 @@ import type {
BuildTableStateArgs, BuildTableStateArgs,
ClientCollectionConfig, ClientCollectionConfig,
ClientConfig, ClientConfig,
Column,
ErrorResult, ErrorResult,
ListPreferences, ListPreferences,
PaginatedDocs, PaginatedDocs,
@@ -11,8 +12,6 @@ import type {
import { formatErrors } from 'payload' import { formatErrors } from 'payload'
import { isNumber } from 'payload/shared' import { isNumber } from 'payload/shared'
import type { Column } from '../elements/Table/index.js'
import { getClientConfig } from './getClientConfig.js' import { getClientConfig } from './getClientConfig.js'
import { renderFilters, renderTable } from './renderTable.js' import { renderFilters, renderTable } from './renderTable.js'
import { upsertPreferences } from './upsertPreferences.js' import { upsertPreferences } from './upsertPreferences.js'

View File

@@ -1,6 +1,6 @@
'use client' 'use client'
import type { ClientSideEditViewProps, ClientUser, FormState } from 'payload' import type { ClientUser, DocumentViewClientProps, FormState } from 'payload'
import { useRouter, useSearchParams } from 'next/navigation.js' import { useRouter, useSearchParams } from 'next/navigation.js'
import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react' import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'
@@ -41,14 +41,14 @@ const baseClass = 'collection-edit'
// This component receives props only on _pages_ // This component receives props only on _pages_
// When rendered within a drawer, props are empty // When rendered within a drawer, props are empty
// This is solely to support custom edit views which get server-rendered // This is solely to support custom edit views which get server-rendered
export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({ export function DefaultEditView({
Description, Description,
PreviewButton, PreviewButton,
PublishButton, PublishButton,
SaveButton, SaveButton,
SaveDraftButton, SaveDraftButton,
Upload: CustomUpload, Upload: CustomUpload,
}) => { }: DocumentViewClientProps) {
const { const {
id, id,
action, action,

View File

@@ -1,14 +1,12 @@
'use client' 'use client'
import type { ListPreferences, ResolvedFilterOptions } from 'payload' import type { ListViewClientProps } from 'payload'
import { getTranslation } from '@payloadcms/translations' import { getTranslation } from '@payloadcms/translations'
import { useRouter } from 'next/navigation.js' import { useRouter } from 'next/navigation.js'
import { formatFilesize, isNumber } from 'payload/shared' import { formatFilesize, isNumber } from 'payload/shared'
import React, { Fragment, useEffect, useState } from 'react' import React, { Fragment, useEffect, useState } from 'react'
import type { Column } from '../../elements/Table/index.js'
import { useBulkUpload } from '../../elements/BulkUpload/index.js' import { useBulkUpload } from '../../elements/BulkUpload/index.js'
import { Button } from '../../elements/Button/index.js' import { Button } from '../../elements/Button/index.js'
import { DeleteMany } from '../../elements/DeleteMany/index.js' import { DeleteMany } from '../../elements/DeleteMany/index.js'
@@ -40,31 +38,7 @@ import './index.scss'
const baseClass = 'collection-list' const baseClass = 'collection-list'
export type ListViewSlots = { export function DefaultListView(props: ListViewClientProps) {
AfterList?: React.ReactNode
AfterListTable?: React.ReactNode
BeforeList?: React.ReactNode
BeforeListTable?: React.ReactNode
Description?: React.ReactNode
Table: React.ReactNode
}
export type ListViewClientProps = {
beforeActions?: React.ReactNode[]
collectionSlug: string
columnState: Column[]
disableBulkDelete?: boolean
disableBulkEdit?: boolean
enableRowSelections?: boolean
hasCreatePermission: boolean
listPreferences?: ListPreferences
newDocumentURL: string
preferenceKey?: string
renderedFilters?: Map<string, React.ReactNode>
resolvedFilterOptions?: Map<string, ResolvedFilterOptions>
} & ListViewSlots
export const DefaultListView: React.FC<ListViewClientProps> = (props) => {
const { const {
AfterList, AfterList,
AfterListTable, AfterListTable,
@@ -193,7 +167,10 @@ export const DefaultListView: React.FC<ListViewClientProps> = (props) => {
<RenderCustomComponent <RenderCustomComponent
CustomComponent={Description} CustomComponent={Description}
Fallback={ Fallback={
<ViewDescription description={collectionConfig?.admin?.description} /> <ViewDescription
collectionSlug={collectionSlug}
description={collectionConfig?.admin?.description}
/>
} }
/> />
</div> </div>

View File

@@ -1,12 +1,4 @@
import type { I18n } from '@payloadcms/translations' import type { SanitizedCollectionConfig } from 'payload'
import type {
AdminViewProps,
Locale,
Payload,
SanitizedCollectionConfig,
SanitizedPermissions,
User,
} from 'payload'
export type DefaultListViewProps = { export type DefaultListViewProps = {
collectionSlug: SanitizedCollectionConfig['slug'] collectionSlug: SanitizedCollectionConfig['slug']
@@ -16,21 +8,3 @@ export type DefaultListViewProps = {
export type ListIndexProps = { export type ListIndexProps = {
collection: SanitizedCollectionConfig collection: SanitizedCollectionConfig
} }
export type ListComponentClientProps = {
collectionSlug: SanitizedCollectionConfig['slug']
hasCreatePermission: boolean
newDocumentURL: string
}
export type ListComponentServerProps = {
collectionConfig: SanitizedCollectionConfig
i18n: I18n
limit: number
locale: Locale
params: AdminViewProps['params']
payload: Payload
permissions: SanitizedPermissions
searchParams: AdminViewProps['searchParams']
user: User
}

View File

@@ -9,14 +9,14 @@ export const Geo: CollectionConfig = {
views: { views: {
edit: { edit: {
api: { api: {
actions: ['/components/CollectionAPIButton/index.js#CollectionAPIButton'], actions: ['/components/actions/CollectionAPIButton/index.js#CollectionAPIButton'],
}, },
default: { default: {
actions: ['/components/CollectionEditButton/index.js#CollectionEditButton'], actions: ['/components/actions/CollectionEditButton/index.js#CollectionEditButton'],
}, },
}, },
list: { list: {
actions: ['/components/CollectionListButton/index.js#CollectionListButton'], actions: ['/components/actions/CollectionListButton/index.js#CollectionListButton'],
}, },
}, },
}, },

View File

@@ -1,5 +1,7 @@
'use client' 'use client'
import type { DocumentTabClientProps } from 'payload'
import { useConfig } from '@payloadcms/ui' import { useConfig } from '@payloadcms/ui'
import LinkImport from 'next/link.js' import LinkImport from 'next/link.js'
import { useParams } from 'next/navigation.js' import { useParams } from 'next/navigation.js'
@@ -7,9 +9,7 @@ import React from 'react'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
export const CustomTabComponentClient: React.FC<{ export function CustomTabComponentClient({ path }: DocumentTabClientProps) {
readonly path: string
}> = ({ path }) => {
const { const {
config: { config: {
routes: { admin: adminRoute }, routes: { admin: adminRoute },
@@ -18,7 +18,7 @@ export const CustomTabComponentClient: React.FC<{
const params = useParams() const params = useParams()
const baseRoute = (params.segments.slice(0, 3) as string[]).join('/') const baseRoute = (params.segments?.slice(0, 3) as string[]).join('/')
return <Link href={`${adminRoute}/${baseRoute}${path}`}>Custom Tab Component</Link> return <Link href={`${adminRoute}/${baseRoute}${path}`}>Custom Tab Component</Link>
} }

View File

@@ -1,11 +1,11 @@
import type { DocumentTabComponent } from 'payload' import type { DocumentTabServerProps } from 'payload'
import React from 'react' import React from 'react'
import { CustomTabComponentClient } from './client.js' import { CustomTabComponentClient } from './client.js'
import './index.scss' import './index.scss'
export const CustomTabComponent: DocumentTabComponent = (props) => { export function CustomTabComponent(props: DocumentTabServerProps) {
const { path } = props const { path } = props
return ( return (

View File

@@ -1,15 +1,15 @@
'use client' 'use client'
import type { StaticDescription } from 'payload' import type { ViewDescriptionClientProps } from 'payload'
import { ViewDescription as DefaultViewDescription } from '@payloadcms/ui' import { ViewDescription as DefaultViewDescription } from '@payloadcms/ui'
import React from 'react' import React from 'react'
import { Banner } from '../Banner/index.js' import { Banner } from '../Banner/index.js'
export const ViewDescription: React.FC<{ description: StaticDescription }> = ({ export function ViewDescription({
description = 'This is a custom view description component.', description = 'This is a custom view description component.',
}) => { }: ViewDescriptionClientProps) {
return ( return (
<Banner> <Banner>
<DefaultViewDescription description={description} /> <DefaultViewDescription description={description} />

View File

@@ -1,8 +1,8 @@
import type { AdminViewComponent, PayloadServerReactComponent } from 'payload' import type { AdminViewServerProps } from 'payload'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
export const CustomAccountView: PayloadServerReactComponent<AdminViewComponent> = () => { export function CustomAccountView(props: AdminViewServerProps) {
return ( return (
<Fragment> <Fragment>
<div <div

View File

@@ -1,8 +1,8 @@
import type { AdminViewComponent, PayloadServerReactComponent } from 'payload' import type { AdminViewServerProps } from 'payload'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
export const CustomDashboardView: PayloadServerReactComponent<AdminViewComponent> = () => { export function CustomDashboardView(props: AdminViewServerProps) {
return ( return (
<Fragment> <Fragment>
<div <div

View File

@@ -5,19 +5,16 @@ import React from 'react'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { Button, SetStepNav } from '@payloadcms/ui' import { Button, SetStepNav } from '@payloadcms/ui'
import { customViewPath } from '../../../shared.js' import { customViewPath } from '../../../shared.js'
import './index.scss' import './index.scss'
const baseClass = 'custom-default-view' const baseClass = 'custom-default-view'
export const CustomDefaultView: React.FC<AdminViewProps> = ({ export function CustomDefaultView({ initPageResult, params, searchParams }: AdminViewServerProps) {
initPageResult,
params,
searchParams,
}) => {
const { const {
permissions, permissions,
req: { req: {

View File

@@ -1,12 +1,10 @@
import type { EditViewComponent, PayloadServerReactComponent } from 'payload' import type { DocumentViewServerProps } from 'payload'
import { SetStepNav } from '@payloadcms/ui' import { SetStepNav } from '@payloadcms/ui'
import { notFound, redirect } from 'next/navigation.js' import { notFound, redirect } from 'next/navigation.js'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
export const CustomEditView: PayloadServerReactComponent<EditViewComponent> = ({ export function CustomEditView({ initPageResult }: DocumentViewServerProps) {
initPageResult,
}) => {
if (!initPageResult) { if (!initPageResult) {
notFound() notFound()
} }

View File

@@ -1,12 +1,10 @@
import type { EditViewComponent, PayloadServerReactComponent } from 'payload' import type { DocumentViewServerProps } from 'payload'
import { SetStepNav } from '@payloadcms/ui' import { SetStepNav } from '@payloadcms/ui'
import { notFound, redirect } from 'next/navigation.js' import { notFound, redirect } from 'next/navigation.js'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
export const CustomDefaultEditView: PayloadServerReactComponent<EditViewComponent> = ({ export function CustomDefaultEditView({ initPageResult }: DocumentViewServerProps) {
initPageResult,
}) => {
if (!initPageResult) { if (!initPageResult) {
notFound() notFound()
} }

View File

@@ -10,7 +10,7 @@ const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.
// import { Button } from 'payload/components/elements'; // import { Button } from 'payload/components/elements';
// import { useConfig } from 'payload/components/utilities'; // import { useConfig } from 'payload/components/utilities';
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { MinimalTemplate } from '@payloadcms/next/templates' import { MinimalTemplate } from '@payloadcms/next/templates'
import { Button } from '@payloadcms/ui' import { Button } from '@payloadcms/ui'
@@ -20,7 +20,7 @@ import './index.scss'
const baseClass = 'custom-minimal-view' const baseClass = 'custom-minimal-view'
export const CustomMinimalView: React.FC<AdminViewProps> = ({ initPageResult }) => { export function CustomMinimalView({ initPageResult }: AdminViewServerProps) {
const { const {
req: { req: {
payload: { payload: {

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { Button } from '@payloadcms/ui' import { Button } from '@payloadcms/ui'
import LinkImport from 'next/link.js' import LinkImport from 'next/link.js'
@@ -10,7 +10,7 @@ import { settingsGlobalSlug } from '../../../slugs.js'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
export const CustomProtectedView: React.FC<AdminViewProps> = async ({ initPageResult }) => { export async function CustomProtectedView({ initPageResult }: AdminViewServerProps) {
const { const {
req: { req: {
payload: { payload: {

View File

@@ -1,4 +1,4 @@
import type { ServerSideEditViewProps } from 'payload' import type { DocumentViewServerProps } from 'payload'
import { SetStepNav } from '@payloadcms/ui' import { SetStepNav } from '@payloadcms/ui'
import { notFound } from 'next/navigation.js' import { notFound } from 'next/navigation.js'
@@ -6,7 +6,7 @@ import React, { Fragment } from 'react'
import { customTabViewComponentTitle } from '../../../shared.js' import { customTabViewComponentTitle } from '../../../shared.js'
export const CustomTabComponentView: React.FC<ServerSideEditViewProps> = ({ initPageResult }) => { export function CustomTabComponentView({ initPageResult }: DocumentViewServerProps) {
if (!initPageResult) { if (!initPageResult) {
notFound() notFound()
} }

View File

@@ -1,4 +1,4 @@
import type { EditViewComponent, PayloadServerReactComponent } from 'payload' import type { DocumentViewServerProps } from 'payload'
import { SetStepNav } from '@payloadcms/ui' import { SetStepNav } from '@payloadcms/ui'
import { notFound } from 'next/navigation.js' import { notFound } from 'next/navigation.js'
@@ -6,9 +6,7 @@ import React, { Fragment } from 'react'
import { customTabLabelViewTitle } from '../../../shared.js' import { customTabLabelViewTitle } from '../../../shared.js'
export const CustomTabLabelView: PayloadServerReactComponent<EditViewComponent> = ({ export function CustomTabLabelView({ initPageResult }: DocumentViewServerProps) {
initPageResult,
}) => {
if (!initPageResult) { if (!initPageResult) {
notFound() notFound()
} }

View File

@@ -1,4 +1,4 @@
import type { EditViewComponent, PayloadServerReactComponent } from 'payload' import type { DocumentViewServerProps } from 'payload'
import { SetStepNav } from '@payloadcms/ui' import { SetStepNav } from '@payloadcms/ui'
import { notFound } from 'next/navigation.js' import { notFound } from 'next/navigation.js'
@@ -6,9 +6,7 @@ import React, { Fragment } from 'react'
import { customNestedTabViewTitle } from '../../../shared.js' import { customNestedTabViewTitle } from '../../../shared.js'
export const CustomNestedTabView: PayloadServerReactComponent<EditViewComponent> = ({ export function CustomNestedTabView({ initPageResult }: DocumentViewServerProps) {
initPageResult,
}) => {
if (!initPageResult) { if (!initPageResult) {
notFound() notFound()
} }

View File

@@ -1,10 +1,10 @@
import type { AdminViewProps } from 'payload' import type { DocumentViewServerProps } from 'payload'
import React from 'react' import React from 'react'
import { customParamViewTitle } from '../../../shared.js' import { customParamViewTitle } from '../../../shared.js'
export const CustomTabWithParamView: React.FC<AdminViewProps> = ({ params }) => { export function CustomTabWithParamView({ params }: DocumentViewServerProps) {
const paramValue = params?.segments?.[4] const paramValue = params?.segments?.[4]
return ( return (

View File

@@ -1,12 +1,10 @@
import type { EditViewComponent, PayloadServerReactComponent } from 'payload' import type { DocumentViewServerProps } from 'payload'
import { SetStepNav } from '@payloadcms/ui' import { SetStepNav } from '@payloadcms/ui'
import { notFound, redirect } from 'next/navigation.js' import { notFound, redirect } from 'next/navigation.js'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
export const CustomVersionsView: PayloadServerReactComponent<EditViewComponent> = ({ export function CustomVersionsView({ initPageResult }: DocumentViewServerProps) {
initPageResult,
}) => {
if (!initPageResult) { if (!initPageResult) {
notFound() notFound()
} }

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import LinkImport from 'next/link.js' import LinkImport from 'next/link.js'
import React from 'react' import React from 'react'
@@ -10,7 +10,7 @@ import { Button } from '@payloadcms/ui'
import { customNestedViewPath, customViewTitle } from '../../../shared.js' import { customNestedViewPath, customViewTitle } from '../../../shared.js'
import { ClientForm } from './index.client.js' import { ClientForm } from './index.client.js'
export const CustomView: React.FC<AdminViewProps> = ({ initPageResult }) => { export function CustomView({ initPageResult }: AdminViewServerProps) {
const { const {
req: { req: {
payload: { payload: {

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { Button } from '@payloadcms/ui' import { Button } from '@payloadcms/ui'
import LinkImport from 'next/link.js' import LinkImport from 'next/link.js'
@@ -8,7 +8,7 @@ import { customNestedViewTitle, customViewPath } from '../../../shared.js'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
export const CustomNestedView: React.FC<AdminViewProps> = ({ initPageResult }) => { export function CustomNestedView({ initPageResult }: AdminViewServerProps) {
const { const {
req: { req: {
payload: { payload: {

View File

@@ -4,7 +4,7 @@ import React from 'react'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
import type { AdminViewProps } from 'payload' import type { AdminViewServerProps } from 'payload'
import { import {
customParamViewPath, customParamViewPath,
@@ -12,7 +12,7 @@ import {
customParamViewTitle, customParamViewTitle,
} from '../../../shared.js' } from '../../../shared.js'
export const CustomViewWithParam: React.FC<AdminViewProps> = ({ initPageResult, params }) => { export function CustomViewWithParam({ initPageResult, params }: AdminViewServerProps) {
const { const {
req: { req: {
payload: { payload: {

View File

@@ -16,7 +16,6 @@ import { CollectionGroup2B } from './collections/Group2B.js'
import { CollectionHidden } from './collections/Hidden.js' import { CollectionHidden } from './collections/Hidden.js'
import { CollectionNoApiView } from './collections/NoApiView.js' import { CollectionNoApiView } from './collections/NoApiView.js'
import { CollectionNotInView } from './collections/NotInView.js' import { CollectionNotInView } from './collections/NotInView.js'
import { Orders } from './collections/Orders.js'
import { Posts } from './collections/Posts.js' import { Posts } from './collections/Posts.js'
import { UploadCollection } from './collections/Upload.js' import { UploadCollection } from './collections/Upload.js'
import { Users } from './collections/Users.js' import { Users } from './collections/Users.js'
@@ -47,7 +46,7 @@ export default buildConfigWithDefaults({
baseDir: path.resolve(dirname), baseDir: path.resolve(dirname),
}, },
components: { components: {
actions: ['/components/AdminButton/index.js#AdminButton'], actions: ['/components/actions/AdminButton/index.js#AdminButton'],
afterDashboard: [ afterDashboard: [
'/components/AfterDashboard/index.js#AfterDashboard', '/components/AfterDashboard/index.js#AfterDashboard',
'/components/AfterDashboardClient/index.js#AfterDashboardClient', '/components/AfterDashboardClient/index.js#AfterDashboardClient',

View File

@@ -9,10 +9,10 @@ export const Global: GlobalConfig = {
views: { views: {
edit: { edit: {
api: { api: {
actions: ['/components/GlobalAPIButton/index.js#GlobalAPIButton'], actions: ['/components/actions/GlobalAPIButton/index.js#GlobalAPIButton'],
}, },
default: { default: {
actions: ['/components/GlobalEditButton/index.js#GlobalEditButton'], actions: ['/components/actions/GlobalEditButton/index.js#GlobalEditButton'],
}, },
}, },
}, },

View File

@@ -6,65 +6,10 @@
* and re-run `payload generate:types` to regenerate this file. * and re-run `payload generate:types` to regenerate this file.
*/ */
/**
* Supported timezones in IANA format.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "supportedTimezones".
*/
export type SupportedTimezones =
| 'Pacific/Midway'
| 'Pacific/Niue'
| 'Pacific/Honolulu'
| 'Pacific/Rarotonga'
| 'America/Anchorage'
| 'Pacific/Gambier'
| 'America/Los_Angeles'
| 'America/Tijuana'
| 'America/Denver'
| 'America/Phoenix'
| 'America/Chicago'
| 'America/Guatemala'
| 'America/New_York'
| 'America/Bogota'
| 'America/Caracas'
| 'America/Santiago'
| 'America/Buenos_Aires'
| 'America/Sao_Paulo'
| 'Atlantic/South_Georgia'
| 'Atlantic/Azores'
| 'Atlantic/Cape_Verde'
| 'Europe/London'
| 'Europe/Berlin'
| 'Africa/Lagos'
| 'Europe/Athens'
| 'Africa/Cairo'
| 'Europe/Moscow'
| 'Asia/Riyadh'
| 'Asia/Dubai'
| 'Asia/Baku'
| 'Asia/Karachi'
| 'Asia/Tashkent'
| 'Asia/Calcutta'
| 'Asia/Dhaka'
| 'Asia/Almaty'
| 'Asia/Jakarta'
| 'Asia/Bangkok'
| 'Asia/Shanghai'
| 'Asia/Singapore'
| 'Asia/Tokyo'
| 'Asia/Seoul'
| 'Australia/Sydney'
| 'Pacific/Guam'
| 'Pacific/Noumea'
| 'Pacific/Auckland'
| 'Pacific/Fiji';
export interface Config { export interface Config {
auth: { auth: {
users: UserAuthOperations; users: UserAuthOperations;
}; };
blocks: {};
collections: { collections: {
uploads: Upload; uploads: Upload;
posts: Post; posts: Post;
@@ -332,6 +277,9 @@ export interface CustomField {
* Static field description. * Static field description.
*/ */
descriptionAsString?: string | null; descriptionAsString?: string | null;
/**
* Function description
*/
descriptionAsFunction?: string | null; descriptionAsFunction?: string | null;
descriptionAsComponent?: string | null; descriptionAsComponent?: string | null;
customSelectField?: string | null; customSelectField?: string | null;