chore: simplifies serverSideProps on document views

This commit is contained in:
Jarrod Flesch
2024-03-06 11:13:19 -05:00
parent 42114a3680
commit 16d5e5f906
17 changed files with 55 additions and 140 deletions

View File

@@ -41,8 +41,10 @@ export const initPage = async ({
}) })
const routeSegments = route.replace(payload.config.routes.admin, '').split('/').filter(Boolean) const routeSegments = route.replace(payload.config.routes.admin, '').split('/').filter(Boolean)
const collectionSlug = routeSegments[0] === 'collections' ? routeSegments[1] : undefined const [entityType, entitySlug, createOrID] = routeSegments
const globalSlug = routeSegments[0] === 'globals' ? routeSegments[1] : undefined const collectionSlug = entityType === 'collections' ? entitySlug : undefined
const globalSlug = entityType === 'globals' ? entitySlug : undefined
const docID = collectionSlug && createOrID !== 'create' ? createOrID : undefined
const { collections, globals, localization, routes } = payload.config const { collections, globals, localization, routes } = payload.config
@@ -95,6 +97,7 @@ export const initPage = async ({
return { return {
collectionConfig, collectionConfig,
cookies, cookies,
docID,
globalConfig, globalConfig,
locale, locale,
permissions, permissions,

View File

@@ -1,7 +1,5 @@
'use client' 'use client'
import type { EditViewProps } from 'payload/types'
import { import {
Checkbox, Checkbox,
CopyToClipboard, CopyToClipboard,
@@ -28,10 +26,8 @@ import './index.scss'
const baseClass = 'query-inspector' const baseClass = 'query-inspector'
export const APIViewClient: React.FC<EditViewProps> = (props) => { export const APIViewClient: React.FC = () => {
const { collectionSlug, globalSlug } = props const { id, collectionSlug, globalSlug, initialData } = useDocumentInfo()
const { id, initialData } = useDocumentInfo()
const searchParams = useSearchParams() const searchParams = useSearchParams()
const { i18n } = useTranslation() const { i18n } = useTranslation()

View File

@@ -2,13 +2,8 @@ import type { ServerSideEditViewProps } from 'payload/types'
import React from 'react' import React from 'react'
import { sanitizeEditViewProps } from '../Edit/sanitizeEditViewProps'
import { APIViewClient } from './index.client' import { APIViewClient } from './index.client'
export const APIView: React.FC<ServerSideEditViewProps> = async (props) => { export const APIView: React.FC<ServerSideEditViewProps> = () => {
// Perform server-side logic here, but no need to fetch data, etc. return <APIViewClient />
// The `Document` component is a wrapper around all edit views, including this one
// It sets up the document info context for the client to subscribe to
const clientSideProps = sanitizeEditViewProps(props)
return <APIViewClient {...clientSideProps} />
} }

View File

@@ -83,19 +83,10 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
req, req,
}) })
const componentProps: ServerSideEditViewProps = { const serverSideProps: ServerSideEditViewProps = {
id: user?.id,
action: `${serverURL}${api}/${userSlug}/${data?.id}?locale=${locale.code}`,
apiURL: `${serverURL}${api}/${userSlug}/${data?.id}?locale=${locale.code}`,
collectionSlug: userSlug,
data,
docPermissions: collectionPermissions,
docPreferences,
hasSavePermission: collectionPermissions?.update?.permission,
initPageResult, initPageResult,
initialState, routeSegments: [],
searchParams, searchParams,
updatedAt: '', // TODO
} }
return ( return (
@@ -118,7 +109,7 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
typeof CustomAccountComponent === 'function' ? CustomAccountComponent : undefined typeof CustomAccountComponent === 'function' ? CustomAccountComponent : undefined
} }
DefaultComponent={EditView} DefaultComponent={EditView}
componentProps={componentProps} componentProps={serverSideProps}
/> />
</Fragment> </Fragment>
) )

View File

@@ -4,7 +4,6 @@ import type {
DocumentPreferences, DocumentPreferences,
Document as DocumentType, Document as DocumentType,
Field, Field,
SanitizedConfig,
ServerSideEditViewProps, ServerSideEditViewProps,
} from 'payload/types' } from 'payload/types'
import type { DocumentPermissions } from 'payload/types' import type { DocumentPermissions } from 'payload/types'
@@ -38,6 +37,7 @@ export const Document: React.FC<AdminViewProps> = async ({
}) => { }) => {
const { const {
collectionConfig, collectionConfig,
docID: id,
globalConfig, globalConfig,
locale, locale,
permissions, permissions,
@@ -57,11 +57,8 @@ export const Document: React.FC<AdminViewProps> = async ({
} = initPageResult } = initPageResult
const segments = Array.isArray(params?.segments) ? params.segments : [] const segments = Array.isArray(params?.segments) ? params.segments : []
const [entityType, entitySlug, createOrID] = segments const collectionSlug = collectionConfig?.slug || undefined
const collectionSlug = entityType === 'collections' ? entitySlug : undefined const globalSlug = globalConfig?.slug || undefined
const globalSlug = entityType === 'globals' ? entitySlug : undefined
const isCreating = createOrID === 'create'
const id = (collectionSlug && !isCreating && createOrID) || undefined
const isEditing = Boolean(globalSlug || (collectionSlug && !!id)) const isEditing = Boolean(globalSlug || (collectionSlug && !!id))
@@ -180,23 +177,10 @@ export const Document: React.FC<AdminViewProps> = async ({
uploadEdits: undefined, uploadEdits: undefined,
} }
const componentProps: ServerSideEditViewProps = { const serverSideProps: ServerSideEditViewProps = {
id,
action: `${action}?${queryString.stringify(formQueryParams)}`,
apiURL,
canAccessAdmin: permissions?.canAccessAdmin,
collectionSlug,
data,
docPermissions,
docPreferences,
globalSlug,
hasSavePermission,
initPageResult, initPageResult,
initialState, routeSegments: segments,
isEditing,
params,
searchParams, searchParams,
updatedAt: data?.updatedAt?.toString(),
} }
return ( return (
@@ -226,7 +210,7 @@ export const Document: React.FC<AdminViewProps> = async ({
<RenderCustomComponent <RenderCustomComponent
CustomComponent={typeof CustomView === 'function' ? CustomView : undefined} CustomComponent={typeof CustomView === 'function' ? CustomView : undefined}
DefaultComponent={DefaultView} DefaultComponent={DefaultView}
componentProps={componentProps} componentProps={serverSideProps}
/> />
</FormQueryParamsProvider> </FormQueryParamsProvider>
</EditDepthProvider> </EditDepthProvider>

View File

@@ -1,7 +1,5 @@
'use client' 'use client'
import type { EditViewProps } from 'payload/types'
import { import {
LoadingOverlay, LoadingOverlay,
SetViewActions, SetViewActions,
@@ -13,7 +11,7 @@ import { useRouter } from 'next/navigation'
import React, { Fragment, useEffect } from 'react' import React, { Fragment, useEffect } from 'react'
import { useCallback } from 'react' import { useCallback } from 'react'
export const EditViewClient: React.FC<EditViewProps> = () => { export const EditViewClient: React.FC = () => {
const { id, collectionSlug, getDocPermissions, getVersions, globalSlug, setDocumentInfo } = const { id, collectionSlug, getDocPermissions, getVersions, globalSlug, setDocumentInfo } =
useDocumentInfo() useDocumentInfo()

View File

@@ -3,12 +3,7 @@ import type { ServerSideEditViewProps } from 'payload/types'
import React from 'react' import React from 'react'
import { EditViewClient } from './index.client' import { EditViewClient } from './index.client'
import { sanitizeEditViewProps } from './sanitizeEditViewProps'
export const EditView: React.FC<ServerSideEditViewProps> = (props) => { export const EditView: React.FC<ServerSideEditViewProps> = () => {
// Perform server-side logic here, but no need to fetch data, etc. return <EditViewClient />
// The `Document` component is a wrapper around all edit views, including this one
// It sets up the document info context for the client to subscribe to
const clientSideProps = sanitizeEditViewProps(props)
return <EditViewClient {...clientSideProps} />
} }

View File

@@ -5,6 +5,5 @@ export const sanitizeEditViewProps = (props: ServerSideEditViewProps) => {
delete clientSideProps.initPageResult.req delete clientSideProps.initPageResult.req
delete clientSideProps.initPageResult.collectionConfig delete clientSideProps.initPageResult.collectionConfig
delete clientSideProps.initPageResult.globalConfig delete clientSideProps.initPageResult.globalConfig
delete clientSideProps.searchParams
return clientSideProps as EditViewProps return clientSideProps as EditViewProps
} }

View File

@@ -1,6 +1,5 @@
'use client' 'use client'
import type { LivePreviewConfig } from 'payload/config' import type { LivePreviewConfig } from 'payload/config'
import type { EditViewProps } from 'payload/types'
import { DndContext } from '@dnd-kit/core' import { DndContext } from '@dnd-kit/core'
import React, { useCallback, useEffect, useState } from 'react' import React, { useCallback, useEffect, useState } from 'react'
@@ -11,7 +10,7 @@ import { customCollisionDetection } from './collisionDetection'
import { LivePreviewContext } from './context' import { LivePreviewContext } from './context'
import { sizeReducer } from './sizeReducer' import { sizeReducer } from './sizeReducer'
export type LivePreviewProviderProps = EditViewProps & { export type LivePreviewProviderProps = {
appIsReady?: boolean appIsReady?: boolean
breakpoints?: LivePreviewConfig['breakpoints'] breakpoints?: LivePreviewConfig['breakpoints']
children: React.ReactNode children: React.ReactNode

View File

@@ -1,7 +1,7 @@
'use client' 'use client'
import type { FormProps } from '@payloadcms/ui' import type { FormProps } from '@payloadcms/ui'
import type { LivePreviewConfig } from 'payload/config' import type { LivePreviewConfig } from 'payload/config'
import type { Data, EditViewProps } from 'payload/types' import type { Data } from 'payload/types'
import { import {
DocumentControls, DocumentControls,
@@ -198,15 +198,14 @@ const PreviewView: React.FC = (props) => {
) )
} }
export const LivePreviewClient: React.FC< export const LivePreviewClient: React.FC<{
EditViewProps & { breakpoints: LivePreviewConfig['breakpoints']
breakpoints: LivePreviewConfig['breakpoints'] initialData: Data
initialData: Data livePreviewConfig: LivePreviewConfig
livePreviewConfig: LivePreviewConfig url: string
url: string }> = (props) => {
} const { breakpoints, url } = props
> = (props) => { const { collectionSlug, globalSlug } = useDocumentInfo()
const { breakpoints, collectionSlug, globalSlug, url } = props
const { isPopupOpen, openPopupWindow, popupRef } = usePopupWindow({ const { isPopupOpen, openPopupWindow, popupRef } = usePopupWindow({
eventType: 'payload-live-preview', eventType: 'payload-live-preview',
@@ -221,7 +220,6 @@ export const LivePreviewClient: React.FC<
<Fragment> <Fragment>
<SetViewActions actions={componentMap?.actionsMap?.Edit?.LivePreview} /> <SetViewActions actions={componentMap?.actionsMap?.Edit?.LivePreview} />
<LivePreviewProvider <LivePreviewProvider
{...props}
breakpoints={breakpoints} breakpoints={breakpoints}
isPopupOpen={isPopupOpen} isPopupOpen={isPopupOpen}
openPopupWindow={openPopupWindow} openPopupWindow={openPopupWindow}

View File

@@ -23,7 +23,7 @@ export const LivePreviewView: React.FC = async (props: ServerSideEditViewProps)
} = initPageResult } = initPageResult
// TODO(JAKE): not sure what `data` is or what it should be // TODO(JAKE): not sure what `data` is or what it should be
const { data = {} } = props const data = 'data' in props ? props.data : {}
let livePreviewConfig: LivePreviewConfig = topLevelLivePreviewConfig let livePreviewConfig: LivePreviewConfig = topLevelLivePreviewConfig
@@ -62,15 +62,11 @@ export const LivePreviewView: React.FC = async (props: ServerSideEditViewProps)
: livePreviewConfig?.url : livePreviewConfig?.url
return ( return (
<React.Fragment> <LivePreviewClient
<LivePreviewClient breakpoints={breakpoints}
breakpoints={breakpoints} initialData={data}
collectionSlug={collectionConfig?.slug} livePreviewConfig={livePreviewConfig}
globalSlug={globalConfig?.slug} url={url}
initialData={data} />
livePreviewConfig={livePreviewConfig}
url={url}
/>
</React.Fragment>
) )
} }

View File

@@ -7,6 +7,7 @@ import {
formatDate, formatDate,
useComponentMap, useComponentMap,
useConfig, useConfig,
useDocumentInfo,
usePayloadAPI, usePayloadAPI,
useTranslation, useTranslation,
} from '@payloadcms/ui' } from '@payloadcms/ui'
@@ -26,11 +27,8 @@ import './index.scss'
const baseClass = 'view-version' const baseClass = 'view-version'
export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
id,
collectionSlug,
doc, doc,
docPermissions, docPermissions,
globalSlug,
initialComparisonDoc, initialComparisonDoc,
localeOptions, localeOptions,
mostRecentDoc, mostRecentDoc,
@@ -40,6 +38,7 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
const config = useConfig() const config = useConfig()
const { i18n } = useTranslation() const { i18n } = useTranslation()
const { id, collectionSlug, globalSlug } = useDocumentInfo()
const { getComponentMap, getFieldMap } = useComponentMap() const { getComponentMap, getFieldMap } = useComponentMap()

View File

@@ -1,6 +1,6 @@
import type { Option } from '@payloadcms/ui' import type { Option } from '@payloadcms/ui'
import type { CollectionPermission, GlobalPermission, Permissions, User } from 'payload/auth' import type { CollectionPermission, GlobalPermission } from 'payload/auth'
import type { Document, SanitizedCollectionConfig } from 'payload/types' import type { Document } from 'payload/types'
export type CompareOption = { export type CompareOption = {
label: string label: string
@@ -10,16 +10,11 @@ export type CompareOption = {
} }
export type DefaultVersionsViewProps = { export type DefaultVersionsViewProps = {
collectionSlug?: SanitizedCollectionConfig['slug']
doc: Document doc: Document
docPermissions: CollectionPermission | GlobalPermission docPermissions: CollectionPermission | GlobalPermission
globalSlug?: SanitizedCollectionConfig['slug']
id?: number | string
initialComparisonDoc: Document initialComparisonDoc: Document
localeOptions: Option[] localeOptions: Option[]
mostRecentDoc: Document mostRecentDoc: Document
permissions: Permissions
publishedDoc: Document publishedDoc: Document
user: User
versionID?: string versionID?: string
} }

View File

@@ -8,17 +8,18 @@ import React from 'react'
import { DefaultVersionView } from './Default' import { DefaultVersionView } from './Default'
export const VersionView: React.FC = async (props: ServerSideEditViewProps) => { export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
const { initPageResult, params } = props const { initPageResult, routeSegments } = props
const { const {
collectionConfig, collectionConfig,
docID: id,
globalConfig, globalConfig,
permissions, permissions,
req: { payload, payload: { config } = {}, user } = {}, req: { payload, payload: { config } = {} } = {},
} = initPageResult } = initPageResult
// /entityType/:entitySlug/:id/versions/:versionID // /entityType/:entitySlug/:id/versions/:versionID
const [entityType, entitySlug, id, versions, versionID] = params.segments const [entityType, entitySlug, docID, versions, versionID] = routeSegments
const collectionSlug = collectionConfig?.slug const collectionSlug = collectionConfig?.slug
const globalSlug = globalConfig?.slug const globalSlug = globalConfig?.slug
@@ -108,17 +109,12 @@ export const VersionView: React.FC = async (props: ServerSideEditViewProps) => {
return ( return (
<DefaultVersionView <DefaultVersionView
collectionSlug={collectionSlug}
doc={doc} doc={doc}
docPermissions={docPermissions} docPermissions={docPermissions}
globalSlug={globalSlug}
id={id}
initialComparisonDoc={mostRecentDoc} initialComparisonDoc={mostRecentDoc}
localeOptions={localeOptions} localeOptions={localeOptions}
mostRecentDoc={mostRecentDoc} mostRecentDoc={mostRecentDoc}
permissions={permissions}
publishedDoc={publishedDoc} publishedDoc={publishedDoc}
user={user}
versionID={versionID} versionID={versionID}
/> />
) )

View File

@@ -10,6 +10,7 @@ import {
SetViewActions, SetViewActions,
Table, Table,
useComponentMap, useComponentMap,
useDocumentInfo,
usePayloadAPI, usePayloadAPI,
useTranslation, useTranslation,
} from '@payloadcms/ui' } from '@payloadcms/ui'
@@ -18,26 +19,15 @@ import React, { Fragment, useEffect, useRef } from 'react'
export const VersionsViewClient: React.FC<{ export const VersionsViewClient: React.FC<{
baseClass: string baseClass: string
collectionSlug?: string
columns: Column[] columns: Column[]
fetchURL: string fetchURL: string
globalSlug?: string
id?: number | string
initialData: PaginatedDocs initialData: PaginatedDocs
paginationLimits?: SanitizedCollectionConfig['admin']['pagination']['limits'] paginationLimits?: SanitizedCollectionConfig['admin']['pagination']['limits']
}> = (props) => { }> = (props) => {
const { const { baseClass, columns, fetchURL, initialData, paginationLimits } = props
id,
baseClass,
collectionSlug,
columns,
fetchURL,
globalSlug,
initialData,
paginationLimits,
} = props
const { getComponentMap } = useComponentMap() const { getComponentMap } = useComponentMap()
const { id, collectionSlug, globalSlug } = useDocumentInfo()
const componentMap = getComponentMap({ const componentMap = getComponentMap({
collectionSlug, collectionSlug,

View File

@@ -5,7 +5,6 @@ import { notFound } from 'next/navigation'
import React from 'react' import React from 'react'
import { SetStepNav } from '../Edit/Default/SetStepNav' import { SetStepNav } from '../Edit/Default/SetStepNav'
import { sanitizeEditViewProps } from '../Edit/sanitizeEditViewProps'
import { buildVersionColumns } from './buildColumns' import { buildVersionColumns } from './buildColumns'
import { VersionsViewClient } from './index.client' import { VersionsViewClient } from './index.client'
import './index.scss' import './index.scss'
@@ -13,10 +12,11 @@ import './index.scss'
export const baseClass = 'versions' export const baseClass = 'versions'
export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) => { export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) => {
const { id, initPageResult, searchParams } = props const { initPageResult, searchParams } = props
const { const {
collectionConfig, collectionConfig,
docID: id,
globalConfig, globalConfig,
req: { req: {
i18n, i18n,
@@ -94,8 +94,6 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
? `${serverURL}${apiRoute}/globals/${globalSlug}/versions` ? `${serverURL}${apiRoute}/globals/${globalSlug}/versions`
: '' : ''
const clientSideProps = sanitizeEditViewProps(props)
return ( return (
<React.Fragment> <React.Fragment>
<SetStepNav <SetStepNav
@@ -109,11 +107,9 @@ export const VersionsView: React.FC<ServerSideEditViewProps> = async (props) =>
<main className={baseClass}> <main className={baseClass}>
<Gutter className={`${baseClass}__wrap`}> <Gutter className={`${baseClass}__wrap`}>
<VersionsViewClient <VersionsViewClient
{...clientSideProps}
baseClass={baseClass} baseClass={baseClass}
columns={columns} columns={columns}
fetchURL={fetchURL} fetchURL={fetchURL}
id={id}
initialData={versionsData} initialData={versionsData}
paginationLimits={collectionConfig?.admin?.pagination?.limits} paginationLimits={collectionConfig?.admin?.pagination?.limits}
/> />

View File

@@ -1,11 +1,9 @@
import type { Translations } from '@payloadcms/translations' import type { Translations } from '@payloadcms/translations'
import type { DocumentPermissions, Permissions, User } from '../../auth' import type { Permissions, User } from '../../auth'
import type { SanitizedCollectionConfig } from '../../collections/config/types' import type { SanitizedCollectionConfig } from '../../collections/config/types'
import type { SanitizedGlobalConfig } from '../../globals/config/types' import type { SanitizedGlobalConfig } from '../../globals/config/types'
import type { DocumentPreferences } from '../../preferences/types'
import type { PayloadRequest } from '../../types' import type { PayloadRequest } from '../../types'
import type { Data, FormState } from '../types'
export type AdminViewConfig = { export type AdminViewConfig = {
Component: AdminViewComponent Component: AdminViewComponent
@@ -33,6 +31,7 @@ export type EditViewProps = {
export type InitPageResult = { export type InitPageResult = {
collectionConfig?: SanitizedCollectionConfig collectionConfig?: SanitizedCollectionConfig
cookies: Map<string, string> cookies: Map<string, string>
docID?: string
globalConfig?: SanitizedGlobalConfig globalConfig?: SanitizedGlobalConfig
locale: Locale locale: Locale
permissions: Permissions permissions: Permissions
@@ -40,22 +39,8 @@ export type InitPageResult = {
translations: Translations translations: Translations
} }
export type ServerSideEditViewProps = EditViewProps & { export type ServerSideEditViewProps = {
action?: string
apiURL: string
canAccessAdmin?: boolean
data: Data
disableActions?: boolean
disableLeaveWithoutSaving?: boolean
docPermissions: DocumentPermissions
docPreferences: DocumentPreferences
hasSavePermission?: boolean
id?: string
initPageResult: InitPageResult initPageResult: InitPageResult
initialState?: FormState routeSegments: string[]
isEditing?: boolean
params?: { [key: string]: string | string[] }
searchParams: { [key: string]: string | string[] | undefined } searchParams: { [key: string]: string | string[] | undefined }
// isLoading: boolean
updatedAt: string
} }