Compare commits
1 Commits
docs/draft
...
feat/loadi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d27d09aa9e |
30
packages/next/src/elements/Nav/Loading.tsx
Normal file
30
packages/next/src/elements/Nav/Loading.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { ServerProps } from 'payload'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import './index.scss'
|
||||
import { NavHamburger } from './NavHamburger/index.js'
|
||||
import { NavWrapper } from './NavWrapper/index.js'
|
||||
|
||||
const baseClass = 'nav'
|
||||
|
||||
import { DefaultNavClient } from './index.client.js'
|
||||
|
||||
export type NavProps = ServerProps
|
||||
|
||||
export const DefaultNavLoading: React.FC = async () => {
|
||||
return (
|
||||
<NavWrapper baseClass={baseClass}>
|
||||
<nav className={`${baseClass}__wrap`}>
|
||||
<DefaultNavClient groups={[]} navPreferences={undefined} />
|
||||
|
||||
<div className={`${baseClass}__controls`}>{}</div>
|
||||
</nav>
|
||||
<div className={`${baseClass}__header`}>
|
||||
<div className={`${baseClass}__header-content`}>
|
||||
<NavHamburger baseClass={baseClass} />
|
||||
</div>
|
||||
</div>
|
||||
</NavWrapper>
|
||||
)
|
||||
}
|
||||
57
packages/next/src/templates/Default/Loading.tsx
Normal file
57
packages/next/src/templates/Default/Loading.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
ActionsProvider,
|
||||
AppHeader,
|
||||
BulkUploadProvider,
|
||||
EntityVisibilityProvider,
|
||||
NavToggler,
|
||||
} from '@payloadcms/ui'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import { DefaultNavLoading } from '../../elements/Nav/Loading.js'
|
||||
import { NavHamburger } from './NavHamburger/index.js'
|
||||
import { Wrapper } from './Wrapper/index.js'
|
||||
|
||||
const baseClass = 'template-default'
|
||||
|
||||
type DefaultTemplateLoaderProps = {
|
||||
children?: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const DefaultTemplateLoading: React.FC<DefaultTemplateLoaderProps> = ({
|
||||
children,
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<EntityVisibilityProvider
|
||||
visibleEntities={{
|
||||
collections: [],
|
||||
globals: [],
|
||||
}}
|
||||
>
|
||||
<BulkUploadProvider>
|
||||
<ActionsProvider Actions={{}}>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<div className={`${baseClass}__nav-toggler-wrapper`} id="nav-toggler">
|
||||
<div className={`${baseClass}__nav-toggler-container`} id="nav-toggler">
|
||||
<NavToggler className={`${baseClass}__nav-toggler`}>
|
||||
<NavHamburger />
|
||||
</NavToggler>
|
||||
</div>
|
||||
</div>
|
||||
<Wrapper baseClass={baseClass} className={className}>
|
||||
<DefaultNavLoading />
|
||||
<div className={`${baseClass}__wrap`}>
|
||||
<AppHeader />
|
||||
{children}
|
||||
</div>
|
||||
</Wrapper>
|
||||
</div>
|
||||
</ActionsProvider>
|
||||
</BulkUploadProvider>
|
||||
</EntityVisibilityProvider>
|
||||
)
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { formatAdminURL, isEditing as getIsEditing } from '@payloadcms/ui/shared
|
||||
import { buildFormState } from '@payloadcms/ui/utilities/buildFormState'
|
||||
import { notFound, redirect } from 'next/navigation.js'
|
||||
import { logError } from 'payload'
|
||||
import React from 'react'
|
||||
import React, { Suspense } from 'react'
|
||||
|
||||
import type { GenerateEditViewMetadata } from './getMetaBySegment.js'
|
||||
import type { ViewFromConfig } from './getViewsFromConfig.js'
|
||||
@@ -381,10 +381,19 @@ export const renderDocument = async ({
|
||||
}
|
||||
}
|
||||
|
||||
export const Document: React.FC<AdminViewProps> = async (args) => {
|
||||
const DocumentWithData: React.FC<AdminViewProps> = async (args) => {
|
||||
const { Document: RenderedDocument } = await renderDocument(args)
|
||||
return RenderedDocument
|
||||
}
|
||||
export const Document: React.FC<AdminViewProps> = (args) => {
|
||||
try {
|
||||
const { Document: RenderedDocument } = await renderDocument(args)
|
||||
return RenderedDocument
|
||||
return (
|
||||
<Suspense
|
||||
key={`document-view-${args?.initPageResult?.collectionConfig?.slug ?? args?.initPageResult?.globalConfig?.slug}`}
|
||||
>
|
||||
<DocumentWithData {...args} />
|
||||
</Suspense>
|
||||
)
|
||||
} catch (error) {
|
||||
if (error?.message === 'NEXT_REDIRECT') {
|
||||
throw error
|
||||
|
||||
@@ -12,7 +12,7 @@ import { renderFilters, renderTable, upsertPreferences } from '@payloadcms/ui/rs
|
||||
import { formatAdminURL, mergeListSearchAndWhere } from '@payloadcms/ui/shared'
|
||||
import { notFound } from 'next/navigation.js'
|
||||
import { isNumber } from 'payload/shared'
|
||||
import React, { Fragment } from 'react'
|
||||
import React, { Fragment, Suspense } from 'react'
|
||||
|
||||
import { renderListViewSlots } from './renderListViewSlots.js'
|
||||
import { resolveAllFilterOptions } from './resolveAllFilterOptions.js'
|
||||
@@ -235,10 +235,20 @@ export const renderListView = async (
|
||||
throw new Error('not-found')
|
||||
}
|
||||
|
||||
export const ListView: React.FC<ListViewArgs> = async (args) => {
|
||||
const ListViewWithData: React.FC<ListViewArgs> = async (args) => {
|
||||
const { List: RenderedList } = await renderListView({ ...args, enableRowSelections: true })
|
||||
return RenderedList
|
||||
}
|
||||
|
||||
export const ListView: React.FC<ListViewArgs> = (args) => {
|
||||
try {
|
||||
const { List: RenderedList } = await renderListView({ ...args, enableRowSelections: true })
|
||||
return RenderedList
|
||||
return (
|
||||
<Suspense
|
||||
key={`list-view-${args?.initPageResult?.collectionConfig?.slug ?? args?.initPageResult?.globalConfig?.slug}`}
|
||||
>
|
||||
<ListViewWithData {...args} />
|
||||
</Suspense>
|
||||
)
|
||||
} catch (error) {
|
||||
if (error.message === 'not-found') {
|
||||
notFound()
|
||||
|
||||
@@ -67,7 +67,7 @@ type GetViewFromConfigArgs = {
|
||||
segments: string[]
|
||||
}
|
||||
|
||||
type GetViewFromConfigResult = {
|
||||
export type GetViewFromConfigResult = {
|
||||
DefaultView: ViewFromConfig
|
||||
documentSubViewType?: DocumentSubViewTypes
|
||||
initPageOptions: Parameters<typeof initPage>[0]
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import type { I18nClient } from '@payloadcms/translations'
|
||||
import type { Metadata } from 'next'
|
||||
import type { ImportMap, SanitizedConfig } from 'payload'
|
||||
import type { ImportMap, InitPageResult, SanitizedConfig } from 'payload'
|
||||
|
||||
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
|
||||
import { formatAdminURL } from '@payloadcms/ui/shared'
|
||||
import { getClientConfig } from '@payloadcms/ui/utilities/getClientConfig'
|
||||
import { notFound, redirect } from 'next/navigation.js'
|
||||
import React, { Fragment } from 'react'
|
||||
import React, { Fragment, Suspense } from 'react'
|
||||
|
||||
import { DefaultTemplate } from '../../templates/Default/index.js'
|
||||
import { DefaultTemplateLoading } from '../../templates/Default/Loading.js'
|
||||
import { MinimalTemplate } from '../../templates/Minimal/index.js'
|
||||
import { initPage } from '../../utilities/initPage/index.js'
|
||||
import { getViewFromConfig } from './getViewFromConfig.js'
|
||||
import { getViewFromConfig, type GetViewFromConfigResult } from './getViewFromConfig.js'
|
||||
|
||||
export { generatePageMetadata } from './meta.js'
|
||||
|
||||
@@ -58,6 +59,14 @@ export const RootPage = async ({
|
||||
|
||||
const searchParams = await searchParamsPromise
|
||||
|
||||
const getViewFromConfigResult = getViewFromConfig({
|
||||
adminRoute,
|
||||
config,
|
||||
currentRoute,
|
||||
importMap,
|
||||
searchParams,
|
||||
segments,
|
||||
})
|
||||
const {
|
||||
DefaultView,
|
||||
documentSubViewType,
|
||||
@@ -66,17 +75,180 @@ export const RootPage = async ({
|
||||
templateClassName,
|
||||
templateType,
|
||||
viewType,
|
||||
} = getViewFromConfig({
|
||||
} = getViewFromConfigResult
|
||||
|
||||
const rootPageProps: BaseRootPageWithDataProps = {
|
||||
_createFirstUserRoute,
|
||||
adminRoute,
|
||||
config,
|
||||
currentRoute,
|
||||
getViewFromConfigResult,
|
||||
importMap,
|
||||
params,
|
||||
searchParams,
|
||||
segments,
|
||||
})
|
||||
userSlug,
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{!templateType && (
|
||||
<Suspense key={`main-view-${currentRoute}`}>
|
||||
<RootPageWithData {...rootPageProps} />
|
||||
</Suspense>
|
||||
)}
|
||||
{templateType === 'minimal' && (
|
||||
<MinimalTemplate className={templateClassName}>
|
||||
<Suspense key={`main-view-${currentRoute}`}>
|
||||
<RootPageWithData {...rootPageProps} />
|
||||
</Suspense>
|
||||
</MinimalTemplate>
|
||||
)}
|
||||
{templateType === 'default' && (
|
||||
<Suspense
|
||||
fallback={
|
||||
<RootPageWithDefaultTemplateFallback
|
||||
currentRoute={currentRoute}
|
||||
getViewFromConfigResult={{
|
||||
DefaultView,
|
||||
documentSubViewType,
|
||||
initPageOptions,
|
||||
serverProps,
|
||||
templateClassName,
|
||||
templateType,
|
||||
viewType,
|
||||
}}
|
||||
params={params}
|
||||
rootPageProps={rootPageProps}
|
||||
searchParams={searchParams}
|
||||
/>
|
||||
}
|
||||
key={`main-view-${currentRoute}`}
|
||||
>
|
||||
<RootPageWithDefaultTemplate
|
||||
currentRoute={currentRoute}
|
||||
getViewFromConfigResult={{
|
||||
DefaultView,
|
||||
documentSubViewType,
|
||||
initPageOptions,
|
||||
serverProps,
|
||||
templateClassName,
|
||||
templateType,
|
||||
viewType,
|
||||
}}
|
||||
params={params}
|
||||
rootPageProps={rootPageProps}
|
||||
searchParams={searchParams}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
const RootPageWithDefaultTemplateFallback: React.FC<{
|
||||
currentRoute: string
|
||||
getViewFromConfigResult: GetViewFromConfigResult
|
||||
params: { [key: string]: string | string[] }
|
||||
rootPageProps: Omit<BaseRootPageWithDataProps, 'initPageResult'>
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
}> = (args) => {
|
||||
const {
|
||||
currentRoute,
|
||||
getViewFromConfigResult: { documentSubViewType, initPageOptions, serverProps, viewType },
|
||||
params,
|
||||
rootPageProps,
|
||||
searchParams,
|
||||
} = args
|
||||
|
||||
return (
|
||||
<DefaultTemplateLoading>
|
||||
<Suspense key={`main-view-${currentRoute}`}>
|
||||
<RootPageWithData {...rootPageProps} />
|
||||
</Suspense>
|
||||
</DefaultTemplateLoading>
|
||||
)
|
||||
}
|
||||
|
||||
const RootPageWithDefaultTemplate: React.FC<{
|
||||
currentRoute: string
|
||||
getViewFromConfigResult: GetViewFromConfigResult
|
||||
params: { [key: string]: string | string[] }
|
||||
rootPageProps: Omit<BaseRootPageWithDataProps, 'initPageResult'>
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
}> = async (args) => {
|
||||
const {
|
||||
currentRoute,
|
||||
getViewFromConfigResult: { documentSubViewType, initPageOptions, serverProps, viewType },
|
||||
params,
|
||||
rootPageProps,
|
||||
searchParams,
|
||||
} = args
|
||||
|
||||
const initPageResult = await initPage(initPageOptions)
|
||||
|
||||
return (
|
||||
<DefaultTemplate
|
||||
collectionSlug={initPageResult?.collectionConfig?.slug}
|
||||
docID={initPageResult?.docID}
|
||||
documentSubViewType={documentSubViewType}
|
||||
globalSlug={initPageResult?.globalConfig?.slug}
|
||||
i18n={initPageResult?.req.i18n}
|
||||
locale={initPageResult?.locale}
|
||||
params={params}
|
||||
payload={initPageResult?.req.payload}
|
||||
permissions={initPageResult?.permissions}
|
||||
searchParams={searchParams}
|
||||
user={initPageResult?.req.user}
|
||||
viewActions={serverProps.viewActions}
|
||||
viewType={viewType}
|
||||
visibleEntities={{
|
||||
// The reason we are not passing in initPageResult.visibleEntities directly is due to a "Cannot assign to read only property of object '#<Object>" error introduced in React 19
|
||||
// which this caused as soon as initPageResult.visibleEntities is passed in
|
||||
collections: initPageResult?.visibleEntities?.collections,
|
||||
globals: initPageResult?.visibleEntities?.globals,
|
||||
}}
|
||||
>
|
||||
<Suspense key={`main-view-${currentRoute}`}>
|
||||
<RootPageWithData {...rootPageProps} />
|
||||
</Suspense>
|
||||
</DefaultTemplate>
|
||||
)
|
||||
}
|
||||
|
||||
type BaseRootPageWithDataProps = {
|
||||
_createFirstUserRoute: string
|
||||
adminRoute: string
|
||||
config: SanitizedConfig
|
||||
currentRoute: string
|
||||
getViewFromConfigResult: GetViewFromConfigResult
|
||||
importMap: ImportMap
|
||||
initPageResult?: InitPageResult | Promise<InitPageResult>
|
||||
params: { [key: string]: string | string[] }
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
userSlug: string
|
||||
}
|
||||
|
||||
const RootPageWithData: React.FC<BaseRootPageWithDataProps> = async (args) => {
|
||||
const {
|
||||
_createFirstUserRoute,
|
||||
adminRoute,
|
||||
config,
|
||||
currentRoute,
|
||||
getViewFromConfigResult: {
|
||||
DefaultView,
|
||||
documentSubViewType,
|
||||
initPageOptions,
|
||||
serverProps,
|
||||
viewType,
|
||||
},
|
||||
importMap,
|
||||
params,
|
||||
searchParams,
|
||||
userSlug,
|
||||
} = args
|
||||
|
||||
const initPageResult = (await args?.initPageResult) ?? (await initPage(initPageOptions))
|
||||
|
||||
const dbHasUser =
|
||||
initPageResult.req.user ||
|
||||
(await initPageResult?.req.payload.db
|
||||
@@ -122,7 +294,6 @@ export const RootPage = async ({
|
||||
if (!DefaultView?.Component && !DefaultView?.payloadComponent && !dbHasUser) {
|
||||
redirect(adminRoute)
|
||||
}
|
||||
|
||||
const clientConfig = getClientConfig({
|
||||
config,
|
||||
i18n: initPageResult?.req.i18n,
|
||||
@@ -147,37 +318,5 @@ export const RootPage = async ({
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{!templateType && <Fragment>{RenderedView}</Fragment>}
|
||||
{templateType === 'minimal' && (
|
||||
<MinimalTemplate className={templateClassName}>{RenderedView}</MinimalTemplate>
|
||||
)}
|
||||
{templateType === 'default' && (
|
||||
<DefaultTemplate
|
||||
collectionSlug={initPageResult?.collectionConfig?.slug}
|
||||
docID={initPageResult?.docID}
|
||||
documentSubViewType={documentSubViewType}
|
||||
globalSlug={initPageResult?.globalConfig?.slug}
|
||||
i18n={initPageResult?.req.i18n}
|
||||
locale={initPageResult?.locale}
|
||||
params={params}
|
||||
payload={initPageResult?.req.payload}
|
||||
permissions={initPageResult?.permissions}
|
||||
searchParams={searchParams}
|
||||
user={initPageResult?.req.user}
|
||||
viewActions={serverProps.viewActions}
|
||||
viewType={viewType}
|
||||
visibleEntities={{
|
||||
// The reason we are not passing in initPageResult.visibleEntities directly is due to a "Cannot assign to read only property of object '#<Object>" error introduced in React 19
|
||||
// which this caused as soon as initPageResult.visibleEntities is passed in
|
||||
collections: initPageResult?.visibleEntities?.collections,
|
||||
globals: initPageResult?.visibleEntities?.globals,
|
||||
}}
|
||||
>
|
||||
{RenderedView}
|
||||
</DefaultTemplate>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
return RenderedView
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user