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

View File

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

View File

@@ -1,9 +1,9 @@
import type { EditViewComponent, PayloadServerReactComponent } from 'payload'
import type { DocumentViewServerProps } from 'payload'
import React from 'react'
import { APIViewClient } from './index.client.js'
export const APIView: PayloadServerReactComponent<EditViewComponent> = () => {
export function APIView(props: DocumentViewServerProps) {
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 { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
@@ -18,11 +18,7 @@ import { Settings } from './Settings/index.js'
export { generateAccountMetadata } from './meta.js'
export const Account: React.FC<AdminViewProps> = async ({
initPageResult,
params,
searchParams,
}) => {
export async function Account({ initPageResult, params, searchParams }: AdminViewServerProps) {
const {
languageOptions,
locale,
@@ -153,6 +149,7 @@ export const Account: React.FC<AdminViewProps> = async ({
Fallback: EditView,
importMap: payload.importMap,
serverProps: {
doc: data,
i18n,
initPageResult,
locale,
@@ -162,7 +159,7 @@ export const Account: React.FC<AdminViewProps> = async ({
routeSegments: [],
searchParams,
user,
},
} satisfies DocumentViewServerPropsOnly,
})}
<AccountClient />
</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 React from 'react'
@@ -11,7 +11,7 @@ import './index.scss'
export { generateCreateFirstUserMetadata } from './meta.js'
export const CreateFirstUserView: React.FC<AdminViewProps> = async ({ initPageResult }) => {
export async function CreateFirstUserView({ initPageResult }: AdminViewServerProps) {
const {
locale,
req,

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
import type {
AdminViewProps,
AdminViewServerProps,
DocumentViewServerProps,
PayloadComponent,
SanitizedCollectionConfig,
SanitizedCollectionPermission,
SanitizedConfig,
SanitizedGlobalConfig,
SanitizedGlobalPermission,
ServerSideEditViewProps,
} from 'payload'
import type React from 'react'
@@ -46,18 +46,18 @@ export const getViewsFromConfig = ({
overrideDocPermissions: true
}
)): {
CustomView: ViewFromConfig<ServerSideEditViewProps>
DefaultView: ViewFromConfig<ServerSideEditViewProps>
CustomView: ViewFromConfig<DocumentViewServerProps>
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
*/
ErrorView: ViewFromConfig<AdminViewProps>
ErrorView: ViewFromConfig<AdminViewServerProps>
viewKey: string
} | null => {
// Conditionally import and lazy load the default view
let DefaultView: ViewFromConfig<ServerSideEditViewProps> = null
let CustomView: ViewFromConfig<ServerSideEditViewProps> = null
let ErrorView: ViewFromConfig<AdminViewProps> = null
let DefaultView: ViewFromConfig<DocumentViewServerProps> = null
let CustomView: ViewFromConfig<DocumentViewServerProps> = null
let ErrorView: ViewFromConfig<AdminViewServerProps> = null
let viewKey: string
const {

View File

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

View File

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

View File

@@ -1,10 +1,10 @@
'use client'
import type { ClientSideEditViewProps } from 'payload'
import type { DocumentViewClientProps } from 'payload'
import { DefaultEditView } from '@payloadcms/ui'
import React from 'react'
export const EditView: React.FC<ClientSideEditViewProps> = (props) => {
export const EditView: React.FC<DocumentViewClientProps> = (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 { formatAdminURL, Translation } from '@payloadcms/ui/shared'
@@ -11,7 +11,7 @@ export { generateForgotPasswordMetadata } from './meta.js'
export const forgotPasswordBaseClass = 'forgot-password'
export const ForgotPasswordView: React.FC<AdminViewProps> = ({ initPageResult }) => {
export function ForgotPasswordView({ initPageResult }: AdminViewServerProps) {
const {
req: {
i18n,

View File

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

View File

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

View File

@@ -1,18 +1,29 @@
import type {
ListComponentClientProps,
ListComponentServerProps,
AfterListClientProps,
AfterListTableClientProps,
AfterListTableServerPropsOnly,
BeforeListClientProps,
BeforeListServerPropsOnly,
BeforeListTableClientProps,
BeforeListTableServerPropsOnly,
ListViewServerPropsOnly,
ListViewSlots,
} from '@payloadcms/ui'
import type { Payload, SanitizedCollectionConfig, StaticDescription } from 'payload'
ListViewSlotSharedClientProps,
Payload,
SanitizedCollectionConfig,
StaticDescription,
ViewDescriptionClientProps,
ViewDescriptionServerPropsOnly,
} from 'payload'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
type Args = {
clientProps: ListComponentClientProps
clientProps: ListViewSlotSharedClientProps
collectionConfig: SanitizedCollectionConfig
description?: StaticDescription
payload: Payload
serverProps: ListComponentServerProps
serverProps: ListViewServerPropsOnly
}
export const renderListViewSlots = ({
@@ -26,49 +37,49 @@ export const renderListViewSlots = ({
if (collectionConfig.admin.components?.afterList) {
result.AfterList = RenderServerComponent({
clientProps,
clientProps: clientProps satisfies AfterListClientProps,
Component: collectionConfig.admin.components.afterList,
importMap: payload.importMap,
serverProps,
serverProps: serverProps satisfies AfterListTableServerPropsOnly,
})
}
if (collectionConfig.admin.components?.afterListTable) {
result.AfterListTable = RenderServerComponent({
clientProps,
clientProps: clientProps satisfies AfterListTableClientProps,
Component: collectionConfig.admin.components.afterListTable,
importMap: payload.importMap,
serverProps,
serverProps: serverProps satisfies AfterListTableServerPropsOnly,
})
}
if (collectionConfig.admin.components?.beforeList) {
result.BeforeList = RenderServerComponent({
clientProps,
clientProps: clientProps satisfies BeforeListClientProps,
Component: collectionConfig.admin.components.beforeList,
importMap: payload.importMap,
serverProps,
serverProps: serverProps satisfies BeforeListServerPropsOnly,
})
}
if (collectionConfig.admin.components?.beforeListTable) {
result.BeforeListTable = RenderServerComponent({
clientProps,
clientProps: clientProps satisfies BeforeListTableClientProps,
Component: collectionConfig.admin.components.beforeListTable,
importMap: payload.importMap,
serverProps,
serverProps: serverProps satisfies BeforeListTableServerPropsOnly,
})
}
if (collectionConfig.admin.components?.Description) {
result.Description = RenderServerComponent({
clientProps: {
collectionSlug: collectionConfig.slug,
description,
...clientProps,
},
} satisfies ViewDescriptionClientProps,
Component: collectionConfig.admin.components.Description,
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 './index.scss'
import { LivePreviewClient } from './index.client.js'
export const LivePreviewView: PayloadServerReactComponent<EditViewComponent> = async (props) => {
export async function LivePreviewView(props: DocumentViewServerProps) {
const { doc, initPageResult } = props
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 { redirect } from 'next/navigation.js'
@@ -12,7 +12,7 @@ export { generateLoginMetadata } from './meta.js'
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 {
@@ -24,7 +24,6 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
const {
admin: { components: { afterLogin, beforeLogin } = {}, user: userSlug },
collections,
routes: { admin },
} = config
@@ -76,9 +75,8 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
permissions,
searchParams,
user,
},
} satisfies ServerProps,
})}
{!collectionConfig?.auth?.disableLocalStrategy && (
<LoginForm
prefillEmail={prefillEmail}
@@ -98,7 +96,7 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
permissions,
searchParams,
user,
},
} satisfies ServerProps,
})}
</Fragment>
)

View File

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

View File

@@ -1,11 +1,6 @@
import type { I18n } from '@payloadcms/translations'
import type { Metadata } from 'next'
import type {
AdminViewComponent,
ImportMap,
PayloadServerReactComponent,
SanitizedConfig,
} from 'payload'
import type { AdminViewServerProps, ImportMap, SanitizedConfig } from 'payload'
import { formatAdminURL } from '@payloadcms/ui/shared'
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" />
}

View File

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

View File

@@ -1,8 +1,8 @@
import type {
AdminViewComponent,
AdminViewProps,
AdminViewServerProps,
DocumentSubViewTypes,
ImportMap,
PayloadComponent,
SanitizedConfig,
ServerPropsFromView,
ViewTypes,
@@ -38,12 +38,12 @@ const baseClasses = {
}
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 = {
Component?: React.FC<AdminViewProps>
payloadComponent?: AdminViewComponent
Component?: React.FC<AdminViewServerProps>
payloadComponent?: PayloadComponent<AdminViewServerProps>
}
const oneSegmentViews: OneSegmentViews = {

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,7 @@
import type {
Document,
EditViewComponent,
DocumentViewServerProps,
OptionObject,
PayloadServerReactComponent,
SanitizedCollectionPermission,
SanitizedGlobalPermission,
} from 'payload'
@@ -17,7 +16,7 @@ import { getLatestVersion } from '../Versions/getLatestVersion.js'
import { DefaultVersionView } from './Default/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 {

View File

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

View File

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

View File

@@ -1,11 +1,6 @@
import { Gutter, ListQueryProvider, SetDocumentStepNav } from '@payloadcms/ui'
import { notFound } from 'next/navigation.js'
import {
type EditViewComponent,
logError,
type PaginatedDocs,
type PayloadServerReactComponent,
} from 'payload'
import { type DocumentViewServerProps, logError, type PaginatedDocs } from 'payload'
import { isNumber } from 'payload/shared'
import React from 'react'
@@ -16,7 +11,7 @@ import './index.scss'
export const baseClass = 'versions'
export const VersionsView: PayloadServerReactComponent<EditViewComponent> = async (props) => {
export async function VersionsView(props: DocumentViewServerProps) {
const { initPageResult, searchParams } = props
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,
} 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 { ConditionalDateProps } from './elements/DatePicker.js'
export type { DayPickerProps, SharedProps, TimePickerProps } from './elements/DatePicker.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 {
DocumentTabComponent,
DocumentTabCondition,
DocumentTabConfig,
DocumentTabProps,
} from './elements/Tab.js'
PreviewButtonClientProps,
PreviewButtonServerProps,
PreviewButtonServerPropsOnly,
} from './elements/PreviewButton.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'
@@ -397,14 +435,6 @@ export type {
VersionTab,
} from './forms/Diff.js'
export type {
FieldErrorClientComponent,
FieldErrorClientProps,
FieldErrorServerComponent,
FieldErrorServerProps,
GenericErrorProps,
} from './forms/Error.js'
export type {
BuildFormStateArgs,
Data,
@@ -416,6 +446,14 @@ export type {
Row,
}
export type {
FieldErrorClientComponent,
FieldErrorClientProps,
FieldErrorServerComponent,
FieldErrorServerProps,
GenericErrorProps,
} from './forms/Error.js'
export type {
ClientComponentProps,
ClientFieldBase,
@@ -438,18 +476,6 @@ export type {
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> = {
Component?: React.ComponentType<TComponentClientProps>
props?: Partial<any>
@@ -535,20 +561,104 @@ export type DocumentSlots = {
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 { RichTextAdapter, RichTextAdapterProvider, RichTextHooks } from './RichText.js'
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,
AdminViewConfig,
AdminViewProps,
ClientSideEditViewProps,
EditViewProps,
/**
* @deprecated
* The `AdminViewProps` type is deprecated and will be removed in the next major version.
* Use `AdminViewServerProps` instead.
*/
AdminViewServerProps as AdminViewProps,
AdminViewServerProps,
AdminViewServerPropsOnly,
InitPageResult,
ServerSideEditViewProps,
ServerPropsFromView,
ViewDescriptionClientProps,
ViewDescriptionServerProps,
ViewDescriptionServerPropsOnly,
ViewTypes,
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
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 { 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 { 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 collectionConfig?: SanitizedCollectionConfig
readonly globalConfig?: SanitizedGlobalConfig
readonly i18n: I18n
readonly payload: Payload
readonly permissions: SanitizedPermissions
} & ServerProps
export type DocumentTabServerProps = DocumentTabClientProps & DocumentTabServerPropsOnly
export type DocumentTabClientProps = {
path: string
}
export type DocumentTabCondition = (args: {
@@ -42,6 +69,9 @@ export type DocumentTabConfig = {
readonly Pill?: PayloadComponent
}
/**
* @todo: Remove this type as it's only used internally for the config (above)
*/
export type DocumentTabComponent = PayloadComponent<{
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 { ImportMap } from '../../bin/generateImportMap/index.js'
@@ -8,17 +8,19 @@ import type {
CustomComponent,
Locale,
MetaConfig,
Params,
PayloadComponent,
SanitizedConfig,
ServerProps,
} from '../../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 { Data, DocumentSlots } from '../types.js'
import type { Data, StaticDescription } from '../types.js'
import type { DocumentSubViewTypes } from './document.js'
export type AdminViewConfig = {
Component: AdminViewComponent
Component: PayloadComponent
/** Whether the path should be matched exactly or as a prefix */
exact?: boolean
meta?: MetaConfig
@@ -27,27 +29,32 @@ export type AdminViewConfig = {
strict?: boolean
}
export type AdminViewProps = {
export type AdminViewClientProps = {
clientConfig: ClientConfig
documentSubViewType?: DocumentSubViewTypes
viewType: ViewTypes
}
export type AdminViewServerPropsOnly = {
readonly clientConfig: ClientConfig
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 initialData?: Data
readonly initPageResult: InitPageResult
readonly params?: { [key: string]: string | string[] | undefined }
readonly redirectAfterDelete?: boolean
readonly redirectAfterDuplicate?: boolean
readonly searchParams: { [key: string]: string | string[] | undefined }
readonly viewType: ViewTypes
}
} & ServerProps
export type AdminViewComponent = PayloadComponent<AdminViewProps>
export type AdminViewServerProps = AdminViewClientProps & AdminViewServerPropsOnly
export type EditViewProps = {
readonly collectionSlug?: string
readonly globalSlug?: string
}
/**
* @deprecated This should be removed in favor of direct props
*/
export type AdminViewComponent = PayloadComponent<AdminViewServerProps>
export type VisibleEntities = {
collections: SanitizedCollectionConfig['slug'][]
@@ -68,15 +75,9 @@ export type InitPageResult = {
visibleEntities: VisibleEntities
}
export type ServerSideEditViewProps = {
readonly doc: Data
readonly initPageResult: InitPageResult
readonly routeSegments: string[]
} & ClientSideEditViewProps &
ServerProps
export type ClientSideEditViewProps = {} & DocumentSlots
/**
* @todo This should be renamed to `ViewType` (singular)
*/
export type ViewTypes =
| 'account'
| 'dashboard'
@@ -85,10 +86,19 @@ export type ViewTypes =
| 'reset'
| 'verify'
| 'version'
export type DocumentSubViewTypes = 'api' | 'default' | 'livePreview' | 'version' | 'versions'
export type ServerPropsFromView = {
collectionConfig?: SanitizedConfig['collections'][number]
globalConfig?: SanitizedConfig['globals'][number]
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
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 { AddToImportMap, Imports, InternalImportMap } from './index.js'

View File

@@ -1,13 +1,7 @@
import type { GraphQLInputObjectType, GraphQLNonNull, GraphQLObjectType } from 'graphql'
import type { DeepRequired, IsAny, MarkOptional } from 'ts-essentials'
import type {
CustomPreviewButton,
CustomPublishButton,
CustomSaveButton,
CustomSaveDraftButton,
CustomUpload,
} from '../../admin/types.js'
import type { CustomUpload } from '../../admin/types.js'
import type { Arguments as MeArguments } from '../../auth/operations/me.js'
import type {
Arguments as RefreshArguments,
@@ -287,23 +281,23 @@ export type CollectionAdminOptions = {
/**
* Replaces the "Preview" button
*/
PreviewButton?: CustomPreviewButton
PreviewButton?: CustomComponent
/**
* Replaces the "Publish" button
* + drafts must be enabled
*/
PublishButton?: CustomPublishButton
PublishButton?: CustomComponent
/**
* Replaces the "Save" button
* + drafts must be disabled
*/
SaveButton?: CustomSaveButton
SaveButton?: CustomComponent
/**
* Replaces the "Save Draft" button
* + drafts must be enabled
* + autosave must be disabled
*/
SaveDraftButton?: CustomSaveDraftButton
SaveDraftButton?: CustomComponent
/**
* Replaces the "Upload" section
* + 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 React from 'react'
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 { DocumentTabConfig, RichTextAdapter } from '../admin/types.js'
import type {
AdminViewConfig,
DocumentSubViewTypes,
ServerPropsFromView,
ServerSideEditViewProps,
ViewTypes,
VisibleEntities,
} from '../admin/views/types.js'
DocumentTabConfig,
DocumentViewServerProps,
RichTextAdapter,
} from '../admin/types.js'
import type { AdminViewConfig, ViewTypes, VisibleEntities } from '../admin/views/index.js'
import type { SanitizedPermissions } from '../auth/index.js'
import type {
AddToImportMap,
@@ -383,7 +381,7 @@ export type Endpoint = {
root?: never
}
export type EditViewComponent = PayloadComponent<ServerSideEditViewProps>
export type EditViewComponent = PayloadComponent<DocumentViewServerProps>
export type EditViewConfig = {
meta?: MetaConfig
@@ -407,22 +405,20 @@ export type EditViewConfig = {
}
)
type ClientProps = {
readonly [key: string]: unknown
}
export type Params = { [key: string]: string | string[] | undefined }
export type ServerProps = {
readonly documentSubViewType?: DocumentSubViewTypes
readonly i18n: I18nClient
readonly locale?: Locale
readonly params?: { [key: string]: string | string[] | undefined }
readonly params?: Params
readonly payload: Payload
readonly permissions?: SanitizedPermissions
readonly searchParams?: { [key: string]: string | string[] | undefined }
readonly searchParams?: Params
readonly user?: TypedUser
readonly viewType?: ViewTypes
readonly visibleEntities?: VisibleEntities
} & ClientProps
}
export const serverProps: (keyof ServerProps)[] = [
'payload',
@@ -1272,5 +1268,3 @@ export type EntityDescriptionFunction = ({ t }: { t: TFunction }) => string
export type EntityDescription = EntityDescriptionFunction | Record<string, string> | string
export type { EmailAdapter, SendEmailOptions }
export type { DocumentSubViewTypes, ServerPropsFromView, ViewTypes }

View File

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

View File

@@ -1,4 +1,6 @@
'use client'
import type { PreviewButtonClientProps } from 'payload'
import React from 'react'
import { Button } from '../Button/index.js'
@@ -6,7 +8,7 @@ import { usePreviewURL } from './usePreviewURL.js'
const baseClass = 'preview-btn'
export const PreviewButton: React.FC = () => {
export function PreviewButton(props: PreviewButtonClientProps) {
const { generatePreviewURL, label } = usePreviewURL()
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 React from 'react'
import type { Column } from '../../Table/index.js'
import type { UpcomingEvent } from './types.js'
import { formatDate } from '../../../utilities/formatDate.js'

View File

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

View File

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

View File

@@ -1,11 +1,10 @@
'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 React, { Fragment, useCallback, useEffect, useState } from 'react'
import type { DocumentDrawerProps } from '../DocumentDrawer/types.js'
import type { Column } from '../Table/index.js'
import { Button } from '../../elements/Button/index.js'
import { Pill } from '../../elements/Pill/index.js'

View File

@@ -1,5 +1,7 @@
'use client'
import type { SaveButtonClientProps } from 'payload'
import React, { useRef } from 'react'
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 { 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 { t } = useTranslation()
const { submit } = useForm()

View File

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

View File

@@ -1,6 +1,6 @@
'use client'
import type { ClientField } from 'payload'
import type { Column } from 'payload'
import React from 'react'
@@ -8,15 +8,6 @@ import './index.scss'
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 = {
readonly appearance?: 'condensed' | 'default'
readonly columns?: Column[]

View File

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

View File

@@ -1,10 +1,9 @@
'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 type { SortColumnProps } from '../SortColumn/index.js'
import type { Column } from '../Table/index.js'
import { useConfig } from '../../providers/Config/index.js'
import { usePreferences } from '../../providers/Preferences/index.js'

View File

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

View File

@@ -114,7 +114,15 @@ export {
RelationshipProvider,
useListRelationships,
} 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 { Thumbnail } from '../../elements/Thumbnail/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 { SelectMany } from '../../elements/SelectMany/index.js'
export {
DefaultListView,
type ListViewClientProps,
type ListViewSlots,
} from '../../views/List/index.js'
export { DefaultListView } from '../../views/List/index.js'
export type { ListComponentClientProps, ListComponentServerProps } from '../../views/List/types.js'
/*
@deprecated
This export will be removed in the next major version.
Use `import { ListPreferences } from 'payload'` instead.
export type {
/**
* @deprecated
* This export will be removed in the next major version.
* Use `import type { ListViewSlots } from 'payload'` instead.
*/
export type { ListPreferences } from 'payload'
ListViewSlots,
} from 'payload'
export type {
/**
* @deprecated
* This export will be removed in the next major version.
* Use `import type { ListViewClientProps } from 'payload'` instead.
*/
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'

View File

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

View File

@@ -1,6 +1,6 @@
'use client'
import type { ClientSideEditViewProps, ClientUser, FormState } from 'payload'
import type { ClientUser, DocumentViewClientProps, FormState } from 'payload'
import { useRouter, useSearchParams } from 'next/navigation.js'
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_
// When rendered within a drawer, props are empty
// This is solely to support custom edit views which get server-rendered
export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
export function DefaultEditView({
Description,
PreviewButton,
PublishButton,
SaveButton,
SaveDraftButton,
Upload: CustomUpload,
}) => {
}: DocumentViewClientProps) {
const {
id,
action,

View File

@@ -1,14 +1,12 @@
'use client'
import type { ListPreferences, ResolvedFilterOptions } from 'payload'
import type { ListViewClientProps } from 'payload'
import { getTranslation } from '@payloadcms/translations'
import { useRouter } from 'next/navigation.js'
import { formatFilesize, isNumber } from 'payload/shared'
import React, { Fragment, useEffect, useState } from 'react'
import type { Column } from '../../elements/Table/index.js'
import { useBulkUpload } from '../../elements/BulkUpload/index.js'
import { Button } from '../../elements/Button/index.js'
import { DeleteMany } from '../../elements/DeleteMany/index.js'
@@ -40,31 +38,7 @@ import './index.scss'
const baseClass = 'collection-list'
export type ListViewSlots = {
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) => {
export function DefaultListView(props: ListViewClientProps) {
const {
AfterList,
AfterListTable,
@@ -193,7 +167,10 @@ export const DefaultListView: React.FC<ListViewClientProps> = (props) => {
<RenderCustomComponent
CustomComponent={Description}
Fallback={
<ViewDescription description={collectionConfig?.admin?.description} />
<ViewDescription
collectionSlug={collectionSlug}
description={collectionConfig?.admin?.description}
/>
}
/>
</div>

View File

@@ -1,12 +1,4 @@
import type { I18n } from '@payloadcms/translations'
import type {
AdminViewProps,
Locale,
Payload,
SanitizedCollectionConfig,
SanitizedPermissions,
User,
} from 'payload'
import type { SanitizedCollectionConfig } from 'payload'
export type DefaultListViewProps = {
collectionSlug: SanitizedCollectionConfig['slug']
@@ -16,21 +8,3 @@ export type DefaultListViewProps = {
export type ListIndexProps = {
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: {
edit: {
api: {
actions: ['/components/CollectionAPIButton/index.js#CollectionAPIButton'],
actions: ['/components/actions/CollectionAPIButton/index.js#CollectionAPIButton'],
},
default: {
actions: ['/components/CollectionEditButton/index.js#CollectionEditButton'],
actions: ['/components/actions/CollectionEditButton/index.js#CollectionEditButton'],
},
},
list: {
actions: ['/components/CollectionListButton/index.js#CollectionListButton'],
actions: ['/components/actions/CollectionListButton/index.js#CollectionListButton'],
},
},
},

View File

@@ -1,5 +1,7 @@
'use client'
import type { DocumentTabClientProps } from 'payload'
import { useConfig } from '@payloadcms/ui'
import LinkImport from 'next/link.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
export const CustomTabComponentClient: React.FC<{
readonly path: string
}> = ({ path }) => {
export function CustomTabComponentClient({ path }: DocumentTabClientProps) {
const {
config: {
routes: { admin: adminRoute },
@@ -18,7 +18,7 @@ export const CustomTabComponentClient: React.FC<{
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>
}

View File

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

View File

@@ -1,15 +1,15 @@
'use client'
import type { StaticDescription } from 'payload'
import type { ViewDescriptionClientProps } from 'payload'
import { ViewDescription as DefaultViewDescription } from '@payloadcms/ui'
import React from 'react'
import { Banner } from '../Banner/index.js'
export const ViewDescription: React.FC<{ description: StaticDescription }> = ({
export function ViewDescription({
description = 'This is a custom view description component.',
}) => {
}: ViewDescriptionClientProps) {
return (
<Banner>
<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'
export const CustomAccountView: PayloadServerReactComponent<AdminViewComponent> = () => {
export function CustomAccountView(props: AdminViewServerProps) {
return (
<Fragment>
<div

View File

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

View File

@@ -5,19 +5,16 @@ import React from 'react'
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 { customViewPath } from '../../../shared.js'
import './index.scss'
const baseClass = 'custom-default-view'
export const CustomDefaultView: React.FC<AdminViewProps> = ({
initPageResult,
params,
searchParams,
}) => {
export function CustomDefaultView({ initPageResult, params, searchParams }: AdminViewServerProps) {
const {
permissions,
req: {

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload'
import type { AdminViewServerProps } from 'payload'
import { Button } from '@payloadcms/ui'
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
export const CustomProtectedView: React.FC<AdminViewProps> = async ({ initPageResult }) => {
export async function CustomProtectedView({ initPageResult }: AdminViewServerProps) {
const {
req: {
payload: {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import type { AdminViewProps } from 'payload'
import type { AdminViewServerProps } from 'payload'
import { Button } from '@payloadcms/ui'
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
export const CustomNestedView: React.FC<AdminViewProps> = ({ initPageResult }) => {
export function CustomNestedView({ initPageResult }: AdminViewServerProps) {
const {
req: {
payload: {

View File

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

View File

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

View File

@@ -9,10 +9,10 @@ export const Global: GlobalConfig = {
views: {
edit: {
api: {
actions: ['/components/GlobalAPIButton/index.js#GlobalAPIButton'],
actions: ['/components/actions/GlobalAPIButton/index.js#GlobalAPIButton'],
},
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.
*/
/**
* 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 {
auth: {
users: UserAuthOperations;
};
blocks: {};
collections: {
uploads: Upload;
posts: Post;
@@ -332,6 +277,9 @@ export interface CustomField {
* Static field description.
*/
descriptionAsString?: string | null;
/**
* Function description
*/
descriptionAsFunction?: string | null;
descriptionAsComponent?: string | null;
customSelectField?: string | null;