diff --git a/packages/next/src/elements/DocumentHeader/Tabs/Tab/index.tsx b/packages/next/src/elements/DocumentHeader/Tabs/Tab/index.tsx index 5726434d2e..df46dea645 100644 --- a/packages/next/src/elements/DocumentHeader/Tabs/Tab/index.tsx +++ b/packages/next/src/elements/DocumentHeader/Tabs/Tab/index.tsx @@ -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, })} ) : null} diff --git a/packages/next/src/elements/DocumentHeader/Tabs/index.tsx b/packages/next/src/elements/DocumentHeader/Tabs/index.tsx index 2bfa190dc3..4fead80bec 100644 --- a/packages/next/src/elements/DocumentHeader/Tabs/index.tsx +++ b/packages/next/src/elements/DocumentHeader/Tabs/index.tsx @@ -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 ( = () => { +export function APIView(props: DocumentViewServerProps) { return } diff --git a/packages/next/src/views/Account/index.tsx b/packages/next/src/views/Account/index.tsx index eccabbb36e..e5058cc534 100644 --- a/packages/next/src/views/Account/index.tsx +++ b/packages/next/src/views/Account/index.tsx @@ -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 = async ({ - initPageResult, - params, - searchParams, -}) => { +export async function Account({ initPageResult, params, searchParams }: AdminViewServerProps) { const { languageOptions, locale, @@ -153,6 +149,7 @@ export const Account: React.FC = async ({ Fallback: EditView, importMap: payload.importMap, serverProps: { + doc: data, i18n, initPageResult, locale, @@ -162,7 +159,7 @@ export const Account: React.FC = async ({ routeSegments: [], searchParams, user, - }, + } satisfies DocumentViewServerPropsOnly, })} diff --git a/packages/next/src/views/CreateFirstUser/index.tsx b/packages/next/src/views/CreateFirstUser/index.tsx index 3840a8ea48..c9f701bfd5 100644 --- a/packages/next/src/views/CreateFirstUser/index.tsx +++ b/packages/next/src/views/CreateFirstUser/index.tsx @@ -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 = async ({ initPageResult }) => { +export async function CreateFirstUserView({ initPageResult }: AdminViewServerProps) { const { locale, req, diff --git a/packages/next/src/views/Dashboard/Default/index.tsx b/packages/next/src/views/Dashboard/Default/index.tsx index 112d91594a..524761f8c3 100644 --- a/packages/next/src/views/Dashboard/Default/index.tsx +++ b/packages/next/src/views/Dashboard/Default/index.tsx @@ -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 - permissions: SanitizedPermissions - visibleEntities: VisibleEntities } & ServerProps -export const DefaultDashboard: React.FC = (props) => { +export type DashboardViewServerProps = DashboardViewClientProps & DashboardViewServerPropsOnly + +export function DefaultDashboard(props: DashboardViewServerProps) { const { globalData, i18n, @@ -65,7 +69,7 @@ export const DefaultDashboard: React.FC = (props) => { permissions, searchParams, user, - }, + } satisfies ServerProps, })} @@ -182,7 +186,7 @@ export const DefaultDashboard: React.FC = (props) => { permissions, searchParams, user, - }, + } satisfies ServerProps, })} diff --git a/packages/next/src/views/Dashboard/index.tsx b/packages/next/src/views/Dashboard/index.tsx index b59eaaab14..5861a4a462 100644 --- a/packages/next/src/views/Dashboard/index.tsx +++ b/packages/next/src/views/Dashboard/index.tsx @@ -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 = async ({ - initPageResult, - params, - searchParams, -}) => { +export async function Dashboard({ initPageResult, params, searchParams }: AdminViewServerProps) { const { locale, permissions, @@ -108,7 +106,7 @@ export const Dashboard: React.FC = 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 = async ({ searchParams, user, visibleEntities, - }, + } satisfies DashboardViewServerPropsOnly, })} ) diff --git a/packages/next/src/views/Document/getViewsFromConfig.tsx b/packages/next/src/views/Document/getViewsFromConfig.tsx index 3cf0494e12..e0128c38ac 100644 --- a/packages/next/src/views/Document/getViewsFromConfig.tsx +++ b/packages/next/src/views/Document/getViewsFromConfig.tsx @@ -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 - DefaultView: ViewFromConfig + CustomView: ViewFromConfig + DefaultView: ViewFromConfig /** * 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 + ErrorView: ViewFromConfig viewKey: string } | null => { // Conditionally import and lazy load the default view - let DefaultView: ViewFromConfig = null - let CustomView: ViewFromConfig = null - let ErrorView: ViewFromConfig = null + let DefaultView: ViewFromConfig = null + let CustomView: ViewFromConfig = null + let ErrorView: ViewFromConfig = null let viewKey: string const { diff --git a/packages/next/src/views/Document/handleServerFunction.tsx b/packages/next/src/views/Document/handleServerFunction.tsx index 57cb4a747d..90632aac28 100644 --- a/packages/next/src/views/Document/handleServerFunction.tsx +++ b/packages/next/src/views/Document/handleServerFunction.tsx @@ -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: {}, diff --git a/packages/next/src/views/Document/index.tsx b/packages/next/src/views/Document/index.tsx index e4dc94b6a0..5b37230980 100644 --- a/packages/next/src/views/Document/index.tsx +++ b/packages/next/src/views/Document/index.tsx @@ -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 - let DefaultView: ViewFromConfig - let ErrorView: ViewFromConfig + let CustomView: ViewFromConfig + let DefaultView: ViewFromConfig + let ErrorView: ViewFromConfig 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, })} @@ -381,16 +396,16 @@ export const renderDocument = async ({ } } -export const Document: React.FC = 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() diff --git a/packages/next/src/views/Document/renderDocumentSlots.tsx b/packages/next/src/views/Document/renderDocumentSlots.tsx index b74eb50bce..dde74e5e26 100644 --- a/packages/next/src/views/Document/renderDocumentSlots.tsx +++ b/packages/next/src/views/Document/renderDocumentSlots.tsx @@ -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, }) } } diff --git a/packages/next/src/views/Edit/index.tsx b/packages/next/src/views/Edit/index.tsx index 9922274a69..116c1affd4 100644 --- a/packages/next/src/views/Edit/index.tsx +++ b/packages/next/src/views/Edit/index.tsx @@ -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 = (props) => { +export const EditView: React.FC = (props) => { return } diff --git a/packages/next/src/views/ForgotPassword/index.tsx b/packages/next/src/views/ForgotPassword/index.tsx index 3cdbebaf9a..38d8e42a5d 100644 --- a/packages/next/src/views/ForgotPassword/index.tsx +++ b/packages/next/src/views/ForgotPassword/index.tsx @@ -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 = ({ initPageResult }) => { +export function ForgotPasswordView({ initPageResult }: AdminViewServerProps) { const { req: { i18n, diff --git a/packages/next/src/views/List/handleServerFunction.tsx b/packages/next/src/views/List/handleServerFunction.tsx index 223b96291a..ea792b25ee 100644 --- a/packages/next/src/views/List/handleServerFunction.tsx +++ b/packages/next/src/views/List/handleServerFunction.tsx @@ -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, diff --git a/packages/next/src/views/List/index.tsx b/packages/next/src/views/List/index.tsx index 42e5d882fe..585035bd9c 100644 --- a/packages/next/src/views/List/index.tsx +++ b/packages/next/src/views/List/index.tsx @@ -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 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({ - adminRoute, - path: `/collections/${collectionSlug}/create`, - }), - } + 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, })} @@ -235,7 +237,7 @@ export const renderListView = async ( throw new Error('not-found') } -export const ListView: React.FC = async (args) => { +export const ListView: React.FC = async (args) => { try { const { List: RenderedList } = await renderListView({ ...args, enableRowSelections: true }) return RenderedList diff --git a/packages/next/src/views/List/renderListViewSlots.tsx b/packages/next/src/views/List/renderListViewSlots.tsx index 48419a1333..5eb3840742 100644 --- a/packages/next/src/views/List/renderListViewSlots.tsx +++ b/packages/next/src/views/List/renderListViewSlots.tsx @@ -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, }) } diff --git a/packages/next/src/views/LivePreview/index.tsx b/packages/next/src/views/LivePreview/index.tsx index 4c952a7b55..4e7f303b42 100644 --- a/packages/next/src/views/LivePreview/index.tsx +++ b/packages/next/src/views/LivePreview/index.tsx @@ -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 = async (props) => { +export async function LivePreviewView(props: DocumentViewServerProps) { const { doc, initPageResult } = props const { collectionConfig, globalConfig, locale, req } = initPageResult diff --git a/packages/next/src/views/Login/index.tsx b/packages/next/src/views/Login/index.tsx index 905ff2777d..3cc344530f 100644 --- a/packages/next/src/views/Login/index.tsx +++ b/packages/next/src/views/Login/index.tsx @@ -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 = ({ 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 = ({ initPageResult, params, se const { admin: { components: { afterLogin, beforeLogin } = {}, user: userSlug }, - collections, routes: { admin }, } = config @@ -76,9 +75,8 @@ export const LoginView: React.FC = ({ initPageResult, params, se permissions, searchParams, user, - }, + } satisfies ServerProps, })} - {!collectionConfig?.auth?.disableLocalStrategy && ( = ({ initPageResult, params, se permissions, searchParams, user, - }, + } satisfies ServerProps, })} ) diff --git a/packages/next/src/views/Logout/index.tsx b/packages/next/src/views/Logout/index.tsx index a9b256ec4a..6f38365d81 100644 --- a/packages/next/src/views/Logout/index.tsx +++ b/packages/next/src/views/Logout/index.tsx @@ -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 = (props) => { +export function LogoutInactivity(props: AdminViewServerProps) { return } diff --git a/packages/next/src/views/NotFound/index.tsx b/packages/next/src/views/NotFound/index.tsx index c18e217937..235585025b 100644 --- a/packages/next/src/views/NotFound/index.tsx +++ b/packages/next/src/views/NotFound/index.tsx @@ -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 = () => { +export function NotFoundView(props: AdminViewServerProps) { return } diff --git a/packages/next/src/views/ResetPassword/index.tsx b/packages/next/src/views/ResetPassword/index.tsx index 7c090bc881..46a60f3f92 100644 --- a/packages/next/src/views/ResetPassword/index.tsx +++ b/packages/next/src/views/ResetPassword/index.tsx @@ -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 = ({ initPageResult, params }) => { +export function ResetPassword({ initPageResult, params }: AdminViewServerProps) { const { req } = initPageResult const { diff --git a/packages/next/src/views/Root/getViewFromConfig.ts b/packages/next/src/views/Root/getViewFromConfig.ts index 05ec03570f..3ae02d6c8e 100644 --- a/packages/next/src/views/Root/getViewFromConfig.ts +++ b/packages/next/src/views/Root/getViewFromConfig.ts @@ -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]: React.FC + [K in Exclude]: React.FC } export type ViewFromConfig = { - Component?: React.FC - payloadComponent?: AdminViewComponent + Component?: React.FC + payloadComponent?: PayloadComponent } const oneSegmentViews: OneSegmentViews = { diff --git a/packages/next/src/views/Root/index.tsx b/packages/next/src/views/Root/index.tsx index cb53bd54a5..9877ed539d 100644 --- a/packages/next/src/views/Root/index.tsx +++ b/packages/next/src/views/Root/index.tsx @@ -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 ( diff --git a/packages/next/src/views/Unauthorized/index.tsx b/packages/next/src/views/Unauthorized/index.tsx index 86fd9d3704..cb297fc8b4 100644 --- a/packages/next/src/views/Unauthorized/index.tsx +++ b/packages/next/src/views/Unauthorized/index.tsx @@ -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 = ({ - initPageResult, -}) => { +export function UnauthorizedView({ initPageResult }: AdminViewServerProps) { const { permissions, req: { diff --git a/packages/next/src/views/Verify/index.tsx b/packages/next/src/views/Verify/index.tsx index cee82f0e8d..390e6510dd 100644 --- a/packages/next/src/views/Verify/index.tsx +++ b/packages/next/src/views/Verify/index.tsx @@ -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 = 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 { diff --git a/packages/next/src/views/Version/index.tsx b/packages/next/src/views/Version/index.tsx index 42cd32be41..deda5cf7e7 100644 --- a/packages/next/src/views/Version/index.tsx +++ b/packages/next/src/views/Version/index.tsx @@ -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 = async (props) => { +export async function VersionView(props: DocumentViewServerProps) { const { i18n, initPageResult, routeSegments, searchParams } = props const { diff --git a/packages/next/src/views/Versions/buildColumns.tsx b/packages/next/src/views/Versions/buildColumns.tsx index c62358d907..1e1a703809 100644 --- a/packages/next/src/views/Versions/buildColumns.tsx +++ b/packages/next/src/views/Versions/buildColumns.tsx @@ -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' diff --git a/packages/next/src/views/Versions/index.client.tsx b/packages/next/src/views/Versions/index.client.tsx index a84fb43b6a..a3fa76d11d 100644 --- a/packages/next/src/views/Versions/index.client.tsx +++ b/packages/next/src/views/Versions/index.client.tsx @@ -1,8 +1,7 @@ 'use client' -import type { SanitizedCollectionConfig } from 'payload' +import type { Column, SanitizedCollectionConfig } from 'payload' import { - type Column, LoadingOverlayToggle, Pagination, PerPage, diff --git a/packages/next/src/views/Versions/index.tsx b/packages/next/src/views/Versions/index.tsx index b54281b897..820ed2ce56 100644 --- a/packages/next/src/views/Versions/index.tsx +++ b/packages/next/src/views/Versions/index.tsx @@ -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 = async (props) => { +export async function VersionsView(props: DocumentViewServerProps) { const { initPageResult, searchParams } = props const { diff --git a/packages/payload/src/admin/elements/PreviewButton.ts b/packages/payload/src/admin/elements/PreviewButton.ts index dad525625b..f4e5f8bc70 100644 --- a/packages/payload/src/admin/elements/PreviewButton.ts +++ b/packages/payload/src/admin/elements/PreviewButton.ts @@ -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 diff --git a/packages/payload/src/admin/elements/PublishButton.ts b/packages/payload/src/admin/elements/PublishButton.ts index 8fabd59c2f..1e8256a763 100644 --- a/packages/payload/src/admin/elements/PublishButton.ts +++ b/packages/payload/src/admin/elements/PublishButton.ts @@ -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 diff --git a/packages/payload/src/admin/elements/SaveButton.ts b/packages/payload/src/admin/elements/SaveButton.ts index 917775cc66..4dabfc3fa9 100644 --- a/packages/payload/src/admin/elements/SaveButton.ts +++ b/packages/payload/src/admin/elements/SaveButton.ts @@ -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 diff --git a/packages/payload/src/admin/elements/SaveDraftButton.ts b/packages/payload/src/admin/elements/SaveDraftButton.ts index ff2f410ae8..90857845f0 100644 --- a/packages/payload/src/admin/elements/SaveDraftButton.ts +++ b/packages/payload/src/admin/elements/SaveDraftButton.ts @@ -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 diff --git a/packages/payload/src/admin/elements/Table.ts b/packages/payload/src/admin/elements/Table.ts new file mode 100644 index 0000000000..6da1dae223 --- /dev/null +++ b/packages/payload/src/admin/elements/Table.ts @@ -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[] +} diff --git a/packages/payload/src/admin/types.ts b/packages/payload/src/admin/types.ts index 3b20a3ac64..f98d8075b4 100644 --- a/packages/payload/src/admin/types.ts +++ b/packages/payload/src/admin/types.ts @@ -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 = { Component?: React.ComponentType props?: Partial @@ -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< diff --git a/packages/payload/src/admin/elements/Tab.ts b/packages/payload/src/admin/views/document.ts similarity index 54% rename from packages/payload/src/admin/elements/Tab.ts rename to packages/payload/src/admin/views/document.ts index 06b6e7dcab..db0b2ee2db 100644 --- a/packages/payload/src/admin/elements/Tab.ts +++ b/packages/payload/src/admin/views/document.ts @@ -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 }> diff --git a/packages/payload/src/admin/views/types.ts b/packages/payload/src/admin/views/index.ts similarity index 60% rename from packages/payload/src/admin/views/types.ts rename to packages/payload/src/admin/views/index.ts index 7dbad82c82..7e5244807d 100644 --- a/packages/payload/src/admin/views/types.ts +++ b/packages/payload/src/admin/views/index.ts @@ -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 +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 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 diff --git a/packages/payload/src/admin/views/list.ts b/packages/payload/src/admin/views/list.ts new file mode 100644 index 0000000000..c066a34331 --- /dev/null +++ b/packages/payload/src/admin/views/list.ts @@ -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` + * 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 + resolvedFilterOptions?: Map +} & 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 diff --git a/packages/payload/src/bin/generateImportMap/iterateConfig.ts b/packages/payload/src/bin/generateImportMap/iterateConfig.ts index 9e93eeb718..c48f2ee432 100644 --- a/packages/payload/src/bin/generateImportMap/iterateConfig.ts +++ b/packages/payload/src/bin/generateImportMap/iterateConfig.ts @@ -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' diff --git a/packages/payload/src/collections/config/types.ts b/packages/payload/src/collections/config/types.ts index eafa2be926..0f60f0e5fa 100644 --- a/packages/payload/src/collections/config/types.ts +++ b/packages/payload/src/collections/config/types.ts @@ -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 diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index ac636aa58a..747b75fed3 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -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 +export type EditViewComponent = PayloadComponent 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 export type { EmailAdapter, SendEmailOptions } - -export type { DocumentSubViewTypes, ServerPropsFromView, ViewTypes } diff --git a/packages/ui/src/elements/DocumentControls/index.tsx b/packages/ui/src/elements/DocumentControls/index.tsx index c63ef1aee4..be8d3495da 100644 --- a/packages/ui/src/elements/DocumentControls/index.tsx +++ b/packages/ui/src/elements/DocumentControls/index.tsx @@ -1,7 +1,5 @@ 'use client' import type { - ClientCollectionConfig, - ClientGlobalConfig, ClientUser, SanitizedCollectionConfig, SanitizedCollectionPermission, diff --git a/packages/ui/src/elements/PreviewButton/index.tsx b/packages/ui/src/elements/PreviewButton/index.tsx index da8dc5aaf6..052eb74fb0 100644 --- a/packages/ui/src/elements/PreviewButton/index.tsx +++ b/packages/ui/src/elements/PreviewButton/index.tsx @@ -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 ( diff --git a/packages/ui/src/elements/PublishButton/ScheduleDrawer/buildUpcomingColumns.tsx b/packages/ui/src/elements/PublishButton/ScheduleDrawer/buildUpcomingColumns.tsx index d709f5bd1f..9216710b0b 100644 --- a/packages/ui/src/elements/PublishButton/ScheduleDrawer/buildUpcomingColumns.tsx +++ b/packages/ui/src/elements/PublishButton/ScheduleDrawer/buildUpcomingColumns.tsx @@ -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' diff --git a/packages/ui/src/elements/PublishButton/ScheduleDrawer/index.tsx b/packages/ui/src/elements/PublishButton/ScheduleDrawer/index.tsx index 20de068e5d..295fb75bd9 100644 --- a/packages/ui/src/elements/PublishButton/ScheduleDrawer/index.tsx +++ b/packages/ui/src/elements/PublishButton/ScheduleDrawer/index.tsx @@ -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' diff --git a/packages/ui/src/elements/PublishButton/index.tsx b/packages/ui/src/elements/PublishButton/index.tsx index f74b83be5b..66031e0051 100644 --- a/packages/ui/src/elements/PublishButton/index.tsx +++ b/packages/ui/src/elements/PublishButton/index.tsx @@ -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, diff --git a/packages/ui/src/elements/RelationshipTable/index.tsx b/packages/ui/src/elements/RelationshipTable/index.tsx index bd02f9dfcd..d3250fb1a7 100644 --- a/packages/ui/src/elements/RelationshipTable/index.tsx +++ b/packages/ui/src/elements/RelationshipTable/index.tsx @@ -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' diff --git a/packages/ui/src/elements/SaveButton/index.tsx b/packages/ui/src/elements/SaveButton/index.tsx index 633d553f83..689038d4f0 100644 --- a/packages/ui/src/elements/SaveButton/index.tsx +++ b/packages/ui/src/elements/SaveButton/index.tsx @@ -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() diff --git a/packages/ui/src/elements/SaveDraftButton/index.tsx b/packages/ui/src/elements/SaveDraftButton/index.tsx index cc6d6216b3..509c51c8e0 100644 --- a/packages/ui/src/elements/SaveDraftButton/index.tsx +++ b/packages/ui/src/elements/SaveDraftButton/index.tsx @@ -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 }, diff --git a/packages/ui/src/elements/Table/index.tsx b/packages/ui/src/elements/Table/index.tsx index 9c915aff1a..15aa757e26 100644 --- a/packages/ui/src/elements/Table/index.tsx +++ b/packages/ui/src/elements/Table/index.tsx @@ -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[] diff --git a/packages/ui/src/elements/TableColumns/buildColumnState.tsx b/packages/ui/src/elements/TableColumns/buildColumnState.tsx index c0d2532192..8eaacb507d 100644 --- a/packages/ui/src/elements/TableColumns/buildColumnState.tsx +++ b/packages/ui/src/elements/TableColumns/buildColumnState.tsx @@ -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, diff --git a/packages/ui/src/elements/TableColumns/index.tsx b/packages/ui/src/elements/TableColumns/index.tsx index 7458f9adef..4c79730a7b 100644 --- a/packages/ui/src/elements/TableColumns/index.tsx +++ b/packages/ui/src/elements/TableColumns/index.tsx @@ -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' diff --git a/packages/ui/src/elements/ViewDescription/index.tsx b/packages/ui/src/elements/ViewDescription/index.tsx index e227549e18..57207c376f 100644 --- a/packages/ui/src/elements/ViewDescription/index.tsx +++ b/packages/ui/src/elements/ViewDescription/index.tsx @@ -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 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 = (props) => { +export function ViewDescription(props: ViewDescriptionClientProps) { const { i18n } = useTranslation() const { description } = props diff --git a/packages/ui/src/exports/client/index.ts b/packages/ui/src/exports/client/index.ts index 2695b849b3..70c9cc0fb7 100644 --- a/packages/ui/src/exports/client/index.ts +++ b/packages/ui/src/exports/client/index.ts @@ -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' +export type { + /** + * @deprecated + * This export will be removed in the next major version. + * Use `import type { ListViewSlots } from 'payload'` instead. + */ + ListViewSlots, +} from 'payload' -/* - @deprecated - This export will be removed in the next major version. - Use `import { ListPreferences } from 'payload'` instead. -*/ -export type { ListPreferences } 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' diff --git a/packages/ui/src/utilities/buildTableState.ts b/packages/ui/src/utilities/buildTableState.ts index 49572dcbe8..0f170f6a24 100644 --- a/packages/ui/src/utilities/buildTableState.ts +++ b/packages/ui/src/utilities/buildTableState.ts @@ -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' diff --git a/packages/ui/src/views/Edit/index.tsx b/packages/ui/src/views/Edit/index.tsx index 1ae69566b2..0925d6ba7d 100644 --- a/packages/ui/src/views/Edit/index.tsx +++ b/packages/ui/src/views/Edit/index.tsx @@ -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 = ({ +export function DefaultEditView({ Description, PreviewButton, PublishButton, SaveButton, SaveDraftButton, Upload: CustomUpload, -}) => { +}: DocumentViewClientProps) { const { id, action, diff --git a/packages/ui/src/views/List/index.tsx b/packages/ui/src/views/List/index.tsx index f92129d60e..fc9d48df34 100644 --- a/packages/ui/src/views/List/index.tsx +++ b/packages/ui/src/views/List/index.tsx @@ -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 - resolvedFilterOptions?: Map -} & ListViewSlots - -export const DefaultListView: React.FC = (props) => { +export function DefaultListView(props: ListViewClientProps) { const { AfterList, AfterListTable, @@ -193,7 +167,10 @@ export const DefaultListView: React.FC = (props) => { + } /> diff --git a/packages/ui/src/views/List/types.ts b/packages/ui/src/views/List/types.ts index 24bb1eef02..8c49dd0718 100644 --- a/packages/ui/src/views/List/types.ts +++ b/packages/ui/src/views/List/types.ts @@ -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 -} diff --git a/test/admin/collections/Geo.ts b/test/admin/collections/Geo.ts index dd87ba976b..88c6dca8de 100644 --- a/test/admin/collections/Geo.ts +++ b/test/admin/collections/Geo.ts @@ -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'], }, }, }, diff --git a/test/admin/components/CustomTabComponent/client.tsx b/test/admin/components/CustomTabComponent/client.tsx index ab1305568d..070c9f2114 100644 --- a/test/admin/components/CustomTabComponent/client.tsx +++ b/test/admin/components/CustomTabComponent/client.tsx @@ -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 Custom Tab Component } diff --git a/test/admin/components/CustomTabComponent/index.tsx b/test/admin/components/CustomTabComponent/index.tsx index f15594e591..498eed6f7b 100644 --- a/test/admin/components/CustomTabComponent/index.tsx +++ b/test/admin/components/CustomTabComponent/index.tsx @@ -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 ( diff --git a/test/admin/components/ViewDescription/index.tsx b/test/admin/components/ViewDescription/index.tsx index 0ab57475f7..bc94cdd50a 100644 --- a/test/admin/components/ViewDescription/index.tsx +++ b/test/admin/components/ViewDescription/index.tsx @@ -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 ( diff --git a/test/admin/components/AdminButton/index.tsx b/test/admin/components/actions/AdminButton/index.tsx similarity index 100% rename from test/admin/components/AdminButton/index.tsx rename to test/admin/components/actions/AdminButton/index.tsx diff --git a/test/admin/components/CollectionAPIButton/index.tsx b/test/admin/components/actions/CollectionAPIButton/index.tsx similarity index 100% rename from test/admin/components/CollectionAPIButton/index.tsx rename to test/admin/components/actions/CollectionAPIButton/index.tsx diff --git a/test/admin/components/CollectionEditButton/index.tsx b/test/admin/components/actions/CollectionEditButton/index.tsx similarity index 100% rename from test/admin/components/CollectionEditButton/index.tsx rename to test/admin/components/actions/CollectionEditButton/index.tsx diff --git a/test/admin/components/CollectionListButton/index.tsx b/test/admin/components/actions/CollectionListButton/index.tsx similarity index 100% rename from test/admin/components/CollectionListButton/index.tsx rename to test/admin/components/actions/CollectionListButton/index.tsx diff --git a/test/admin/components/GlobalAPIButton/index.tsx b/test/admin/components/actions/GlobalAPIButton/index.tsx similarity index 100% rename from test/admin/components/GlobalAPIButton/index.tsx rename to test/admin/components/actions/GlobalAPIButton/index.tsx diff --git a/test/admin/components/GlobalEditButton/index.tsx b/test/admin/components/actions/GlobalEditButton/index.tsx similarity index 100% rename from test/admin/components/GlobalEditButton/index.tsx rename to test/admin/components/actions/GlobalEditButton/index.tsx diff --git a/test/admin/components/views/CustomAccount/index.tsx b/test/admin/components/views/CustomAccount/index.tsx index 11f747d2a4..c01fe20117 100644 --- a/test/admin/components/views/CustomAccount/index.tsx +++ b/test/admin/components/views/CustomAccount/index.tsx @@ -1,8 +1,8 @@ -import type { AdminViewComponent, PayloadServerReactComponent } from 'payload' +import type { AdminViewServerProps } from 'payload' import React, { Fragment } from 'react' -export const CustomAccountView: PayloadServerReactComponent = () => { +export function CustomAccountView(props: AdminViewServerProps) { return (
= () => { +export function CustomDashboardView(props: AdminViewServerProps) { return (
= ({ - initPageResult, - params, - searchParams, -}) => { +export function CustomDefaultView({ initPageResult, params, searchParams }: AdminViewServerProps) { const { permissions, req: { diff --git a/test/admin/components/views/CustomEdit/index.tsx b/test/admin/components/views/CustomEdit/index.tsx index 04a8e54ce3..987bdc9af0 100644 --- a/test/admin/components/views/CustomEdit/index.tsx +++ b/test/admin/components/views/CustomEdit/index.tsx @@ -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 = ({ - initPageResult, -}) => { +export function CustomEditView({ initPageResult }: DocumentViewServerProps) { if (!initPageResult) { notFound() } diff --git a/test/admin/components/views/CustomEditDefault/index.tsx b/test/admin/components/views/CustomEditDefault/index.tsx index 469af39dfb..9f2464e4f3 100644 --- a/test/admin/components/views/CustomEditDefault/index.tsx +++ b/test/admin/components/views/CustomEditDefault/index.tsx @@ -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 = ({ - initPageResult, -}) => { +export function CustomDefaultEditView({ initPageResult }: DocumentViewServerProps) { if (!initPageResult) { notFound() } diff --git a/test/admin/components/views/CustomMinimal/index.tsx b/test/admin/components/views/CustomMinimal/index.tsx index dc3f8e9b6f..057ae8922b 100644 --- a/test/admin/components/views/CustomMinimal/index.tsx +++ b/test/admin/components/views/CustomMinimal/index.tsx @@ -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 = ({ initPageResult }) => { +export function CustomMinimalView({ initPageResult }: AdminViewServerProps) { const { req: { payload: { diff --git a/test/admin/components/views/CustomProtectedView/index.tsx b/test/admin/components/views/CustomProtectedView/index.tsx index afcb5e757d..7b828d3d44 100644 --- a/test/admin/components/views/CustomProtectedView/index.tsx +++ b/test/admin/components/views/CustomProtectedView/index.tsx @@ -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 = async ({ initPageResult }) => { +export async function CustomProtectedView({ initPageResult }: AdminViewServerProps) { const { req: { payload: { diff --git a/test/admin/components/views/CustomTabComponent/index.tsx b/test/admin/components/views/CustomTabComponent/index.tsx index 4126ac5d04..35cbd0cd5a 100644 --- a/test/admin/components/views/CustomTabComponent/index.tsx +++ b/test/admin/components/views/CustomTabComponent/index.tsx @@ -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 = ({ initPageResult }) => { +export function CustomTabComponentView({ initPageResult }: DocumentViewServerProps) { if (!initPageResult) { notFound() } diff --git a/test/admin/components/views/CustomTabLabel/index.tsx b/test/admin/components/views/CustomTabLabel/index.tsx index 72e0c3f4ed..4003c6deed 100644 --- a/test/admin/components/views/CustomTabLabel/index.tsx +++ b/test/admin/components/views/CustomTabLabel/index.tsx @@ -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 = ({ - initPageResult, -}) => { +export function CustomTabLabelView({ initPageResult }: DocumentViewServerProps) { if (!initPageResult) { notFound() } diff --git a/test/admin/components/views/CustomTabNested/index.tsx b/test/admin/components/views/CustomTabNested/index.tsx index a02f57d8ce..6d259975d7 100644 --- a/test/admin/components/views/CustomTabNested/index.tsx +++ b/test/admin/components/views/CustomTabNested/index.tsx @@ -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 = ({ - initPageResult, -}) => { +export function CustomNestedTabView({ initPageResult }: DocumentViewServerProps) { if (!initPageResult) { notFound() } diff --git a/test/admin/components/views/CustomTabWithParam/index.tsx b/test/admin/components/views/CustomTabWithParam/index.tsx index a085ad27e7..28df8560e9 100644 --- a/test/admin/components/views/CustomTabWithParam/index.tsx +++ b/test/admin/components/views/CustomTabWithParam/index.tsx @@ -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 = ({ params }) => { +export function CustomTabWithParamView({ params }: DocumentViewServerProps) { const paramValue = params?.segments?.[4] return ( diff --git a/test/admin/components/views/CustomVersions/index.tsx b/test/admin/components/views/CustomVersions/index.tsx index e6a7ce547b..b72129cb04 100644 --- a/test/admin/components/views/CustomVersions/index.tsx +++ b/test/admin/components/views/CustomVersions/index.tsx @@ -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 = ({ - initPageResult, -}) => { +export function CustomVersionsView({ initPageResult }: DocumentViewServerProps) { if (!initPageResult) { notFound() } diff --git a/test/admin/components/views/CustomView/index.tsx b/test/admin/components/views/CustomView/index.tsx index 4444fe4acc..1dde3d5539 100644 --- a/test/admin/components/views/CustomView/index.tsx +++ b/test/admin/components/views/CustomView/index.tsx @@ -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 = ({ initPageResult }) => { +export function CustomView({ initPageResult }: AdminViewServerProps) { const { req: { payload: { diff --git a/test/admin/components/views/CustomViewNested/index.tsx b/test/admin/components/views/CustomViewNested/index.tsx index d14e290190..d77e92a326 100644 --- a/test/admin/components/views/CustomViewNested/index.tsx +++ b/test/admin/components/views/CustomViewNested/index.tsx @@ -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 = ({ initPageResult }) => { +export function CustomNestedView({ initPageResult }: AdminViewServerProps) { const { req: { payload: { diff --git a/test/admin/components/views/CustomViewWithParam/index.tsx b/test/admin/components/views/CustomViewWithParam/index.tsx index b97b16d3ba..bca77e334d 100644 --- a/test/admin/components/views/CustomViewWithParam/index.tsx +++ b/test/admin/components/views/CustomViewWithParam/index.tsx @@ -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 = ({ initPageResult, params }) => { +export function CustomViewWithParam({ initPageResult, params }: AdminViewServerProps) { const { req: { payload: { diff --git a/test/admin/config.ts b/test/admin/config.ts index 10f587d43b..4f5ede8e4b 100644 --- a/test/admin/config.ts +++ b/test/admin/config.ts @@ -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', diff --git a/test/admin/globals/Global.ts b/test/admin/globals/Global.ts index b2bd2323d2..e654c584b6 100644 --- a/test/admin/globals/Global.ts +++ b/test/admin/globals/Global.ts @@ -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'], }, }, }, diff --git a/test/admin/payload-types.ts b/test/admin/payload-types.ts index 2574eaa861..b66ed60198 100644 --- a/test/admin/payload-types.ts +++ b/test/admin/payload-types.ts @@ -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;