fix(next): dynamic params for custom collection and global views

This commit is contained in:
Jacob Fletcher
2024-03-25 18:08:08 -04:00
parent 7654ff686a
commit 1c1847f63c
18 changed files with 310 additions and 167 deletions

View File

@@ -17,7 +17,11 @@ import { Settings } from './Settings/index.js'
export { generateAccountMetadata } from './meta.js' export { generateAccountMetadata } from './meta.js'
export const Account: React.FC<AdminViewProps> = async ({ initPageResult, searchParams }) => { export const Account: React.FC<AdminViewProps> = async ({
initPageResult,
params,
searchParams,
}) => {
const { const {
locale, locale,
permissions, permissions,
@@ -87,6 +91,7 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
const viewComponentProps: ServerSideEditViewProps = { const viewComponentProps: ServerSideEditViewProps = {
initPageResult, initPageResult,
params,
routeSegments: [], routeSegments: [],
searchParams, searchParams,
} }

View File

@@ -1,16 +1,29 @@
import type { EditViewComponent } from 'payload/config' import type { EditViewComponent } from 'payload/config'
import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types' import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/types'
export const getCustomViewByPath = ( import { isPathMatchingRoute } from '../Root/isPathMatchingRoute.js'
export const getCustomViewByRoute = ({
baseRoute,
currentRoute,
views,
}: {
baseRoute: string
currentRoute: string
views: views:
| SanitizedCollectionConfig['admin']['components']['views'] | SanitizedCollectionConfig['admin']['components']['views']
| SanitizedGlobalConfig['admin']['components']['views'], | SanitizedGlobalConfig['admin']['components']['views']
path: string, }): EditViewComponent => {
): EditViewComponent => {
if (typeof views?.Edit === 'object' && typeof views?.Edit !== 'function') { if (typeof views?.Edit === 'object' && typeof views?.Edit !== 'function') {
const foundViewConfig = Object.entries(views.Edit).find(([, view]) => { const foundViewConfig = Object.entries(views.Edit).find(([, view]) => {
if (typeof view === 'object' && typeof view !== 'function' && 'path' in view) { if (typeof view === 'object' && typeof view !== 'function' && 'path' in view) {
return view.path === path const viewPath = `${baseRoute}${view.path}`
return isPathMatchingRoute({
currentRoute,
exact: true,
path: viewPath,
})
} }
return false return false
})?.[1] })?.[1]

View File

@@ -8,15 +8,17 @@ import type {
} from 'payload/types' } from 'payload/types'
import { isEntityHidden } from 'payload/utilities' import { isEntityHidden } from 'payload/utilities'
import React from 'react'
import { APIView as DefaultAPIView } from '../API/index.js' import { APIView as DefaultAPIView } from '../API/index.js'
import { EditView as DefaultEditView } from '../Edit/index.js' import { EditView as DefaultEditView } from '../Edit/index.js'
import { LivePreviewView as DefaultLivePreviewView } from '../LivePreview/index.js' import { LivePreviewView as DefaultLivePreviewView } from '../LivePreview/index.js'
import { NotFoundClient } from '../NotFound/index.client.js'
import { Unauthorized } from '../Unauthorized/index.js' import { Unauthorized } from '../Unauthorized/index.js'
import { VersionView as DefaultVersionView } from '../Version/index.js' import { VersionView as DefaultVersionView } from '../Version/index.js'
import { VersionsView as DefaultVersionsView } from '../Versions/index.js' import { VersionsView as DefaultVersionsView } from '../Versions/index.js'
import { getCustomViewByKey } from './getCustomViewByKey.js' import { getCustomViewByKey } from './getCustomViewByKey.js'
import { getCustomViewByPath } from './getCustomViewByPath.js' import { getCustomViewByRoute } from './getCustomViewByRoute.js'
export const getViewsFromConfig = ({ export const getViewsFromConfig = ({
collectionConfig, collectionConfig,
@@ -46,6 +48,10 @@ export const getViewsFromConfig = ({
let CustomView: EditViewComponent = null let CustomView: EditViewComponent = null
let ErrorView: AdminViewComponent = null let ErrorView: AdminViewComponent = null
const {
routes: { admin: adminRoute },
} = config
const views = const views =
(collectionConfig && collectionConfig?.admin?.components?.views) || (collectionConfig && collectionConfig?.admin?.components?.views) ||
(globalConfig && globalConfig?.admin?.components?.views) (globalConfig && globalConfig?.admin?.components?.views)
@@ -65,8 +71,7 @@ export const getViewsFromConfig = ({
} }
if (!EditOverride) { if (!EditOverride) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars const [collectionEntity, collectionSlug, segment3, segment4, segment5, ...remainingSegments] =
const [collectionEntity, collectionSlug, createOrID, nestedViewSlug, segmentFive] =
routeSegments routeSegments
const { const {
@@ -78,8 +83,9 @@ export const getViewsFromConfig = ({
} }
// `../:id`, or `../create` // `../:id`, or `../create`
if (routeSegments.length === 3) { switch (routeSegments.length) {
switch (createOrID) { case 3: {
switch (segment3) {
case 'create': { case 'create': {
if ('create' in docPermissions && docPermissions?.create?.permission) { if ('create' in docPermissions && docPermissions?.create?.permission) {
CustomView = getCustomViewByKey(views, 'Default') CustomView = getCustomViewByKey(views, 'Default')
@@ -97,13 +103,15 @@ export const getViewsFromConfig = ({
} else { } else {
ErrorView = Unauthorized ErrorView = Unauthorized
} }
break
} }
} }
break
} }
// `../:id/api`, `../:id/preview`, `../:id/versions`, etc // `../:id/api`, `../:id/preview`, `../:id/versions`, etc
if (routeSegments?.length === 4) { case 4: {
switch (nestedViewSlug) { switch (segment4) {
case 'api': { case 'api': {
if (collectionConfig?.admin?.hideAPIURL !== true) { if (collectionConfig?.admin?.hideAPIURL !== true) {
CustomView = getCustomViewByKey(views, 'API') CustomView = getCustomViewByKey(views, 'API')
@@ -130,22 +138,55 @@ export const getViewsFromConfig = ({
} }
default: { default: {
const path = `/${nestedViewSlug}` const baseRoute = [adminRoute, 'collections', collectionSlug, segment3]
CustomView = getCustomViewByPath(views, path) .filter(Boolean)
.join('/')
const currentRoute = [baseRoute, segment4, segment5, ...remainingSegments]
.filter(Boolean)
.join('/')
CustomView = getCustomViewByRoute({
baseRoute,
currentRoute,
views,
})
if (!CustomView) ErrorView = () => <NotFoundClient />
break break
} }
} }
break
} }
// `../:id/versions/:version`, etc // `../:id/versions/:version`, etc
if (routeSegments.length === 5) { default: {
if (nestedViewSlug === 'versions') { if (segment4 === 'versions') {
if (docPermissions?.readVersions?.permission) { if (docPermissions?.readVersions?.permission) {
CustomView = getCustomViewByKey(views, 'Version') CustomView = getCustomViewByKey(views, 'Version')
DefaultView = DefaultVersionView DefaultView = DefaultVersionView
} else { } else {
ErrorView = Unauthorized ErrorView = Unauthorized
} }
} else {
const baseRoute = [adminRoute, collectionEntity, collectionSlug, segment3]
.filter(Boolean)
.join('/')
const currentRoute = [baseRoute, segment4, segment5, ...remainingSegments]
.filter(Boolean)
.join('/')
CustomView = getCustomViewByRoute({
baseRoute,
currentRoute,
views,
})
if (!CustomView) ErrorView = () => <NotFoundClient />
}
break
} }
} }
} }
@@ -161,7 +202,7 @@ export const getViewsFromConfig = ({
if (!EditOverride) { if (!EditOverride) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [globalEntity, globalSlug, nestedViewSlug] = routeSegments const [globalEntity, globalSlug, segment3, ...remainingSegments] = routeSegments
const { const {
admin: { hidden }, admin: { hidden },
@@ -171,18 +212,20 @@ export const getViewsFromConfig = ({
return null return null
} }
if (routeSegments?.length === 2) { switch (routeSegments.length) {
case 2: {
if (docPermissions?.read?.permission) { if (docPermissions?.read?.permission) {
CustomView = getCustomViewByKey(views, 'Default') CustomView = getCustomViewByKey(views, 'Default')
DefaultView = DefaultEditView DefaultView = DefaultEditView
} else { } else {
ErrorView = Unauthorized ErrorView = Unauthorized
} }
break
} }
if (routeSegments?.length === 3) { case 3: {
// `../:slug/api`, `../:slug/preview`, `../:slug/versions`, etc // `../:slug/api`, `../:slug/preview`, `../:slug/versions`, etc
switch (nestedViewSlug) { switch (segment3) {
case 'api': { case 'api': {
if (globalConfig?.admin?.hideAPIURL !== true) { if (globalConfig?.admin?.hideAPIURL !== true) {
CustomView = getCustomViewByKey(views, 'API') CustomView = getCustomViewByKey(views, 'API')
@@ -218,17 +261,34 @@ export const getViewsFromConfig = ({
break break
} }
} }
break
} }
if (routeSegments?.length === 4) { default: {
// `../:slug/versions/:version`, etc // `../:slug/versions/:version`, etc
if (nestedViewSlug === 'versions') { if (segment3 === 'versions') {
if (docPermissions?.readVersions?.permission) { if (docPermissions?.readVersions?.permission) {
CustomView = getCustomViewByKey(views, 'Version') CustomView = getCustomViewByKey(views, 'Version')
DefaultView = DefaultVersionView DefaultView = DefaultVersionView
} else { } else {
ErrorView = Unauthorized ErrorView = Unauthorized
} }
} else {
const baseRoute = [adminRoute, 'globals', globalSlug].filter(Boolean).join('/')
const currentRoute = [baseRoute, segment3, ...remainingSegments]
.filter(Boolean)
.join('/')
CustomView = getCustomViewByRoute({
baseRoute,
currentRoute,
views,
})
if (!CustomView) ErrorView = () => <NotFoundClient />
}
break
} }
} }
} }

View File

@@ -1,23 +1,14 @@
import type { EditViewComponent } from 'payload/config' import type { EditViewComponent } from 'payload/config'
import type { import type { AdminViewComponent, ServerSideEditViewProps } from 'payload/types'
AdminViewComponent,
DocumentPreferences,
Document as DocumentType,
Field,
ServerSideEditViewProps,
} from 'payload/types'
import type { DocumentPermissions } from 'payload/types' import type { DocumentPermissions } from 'payload/types'
import type { AdminViewProps } from 'payload/types' import type { AdminViewProps } from 'payload/types'
import { DocumentHeader } from '@payloadcms/ui/elements/DocumentHeader' import { DocumentHeader } from '@payloadcms/ui/elements/DocumentHeader'
import { HydrateClientUser } from '@payloadcms/ui/elements/HydrateClientUser' import { HydrateClientUser } from '@payloadcms/ui/elements/HydrateClientUser'
import { RenderCustomComponent } from '@payloadcms/ui/elements/RenderCustomComponent' import { RenderCustomComponent } from '@payloadcms/ui/elements/RenderCustomComponent'
import { buildStateFromSchema } from '@payloadcms/ui/forms/buildStateFromSchema'
import { DocumentInfoProvider } from '@payloadcms/ui/providers/DocumentInfo' import { DocumentInfoProvider } from '@payloadcms/ui/providers/DocumentInfo'
import { EditDepthProvider } from '@payloadcms/ui/providers/EditDepth' import { EditDepthProvider } from '@payloadcms/ui/providers/EditDepth'
import { FormQueryParamsProvider } from '@payloadcms/ui/providers/FormQueryParams' import { FormQueryParamsProvider } from '@payloadcms/ui/providers/FormQueryParams'
import { formatDocTitle } from '@payloadcms/ui/utilities/formatDocTitle'
import { formatFields } from '@payloadcms/ui/utilities/formatFields'
import { docAccessOperation } from 'payload/operations' import { docAccessOperation } from 'payload/operations'
import React from 'react' import React from 'react'
@@ -222,6 +213,7 @@ export const Document: React.FC<AdminViewProps> = async ({
const viewComponentProps: ServerSideEditViewProps = { const viewComponentProps: ServerSideEditViewProps = {
initPageResult, initPageResult,
params,
routeSegments: segments, routeSegments: segments,
searchParams, searchParams,
} }

View File

@@ -1,6 +1,6 @@
import type { AdminViewComponent, SanitizedConfig } from 'payload/types' import type { AdminViewComponent, SanitizedConfig } from 'payload/types'
import { pathToRegexp } from 'path-to-regexp' import { isPathMatchingRoute } from './isPathMatchingRoute.js'
export const getCustomViewByRoute = ({ export const getCustomViewByRoute = ({
config, config,
@@ -23,22 +23,13 @@ export const getCustomViewByRoute = ({
typeof views === 'object' && typeof views === 'object' &&
Object.entries(views).find(([, view]) => { Object.entries(views).find(([, view]) => {
if (typeof view === 'object') { if (typeof view === 'object') {
const { exact, path: viewPath, sensitive, strict } = view return isPathMatchingRoute({
currentRoute,
const keys = [] exact: view.exact,
path: view.path,
// run the view path through `pathToRegexp` to resolve any dynamic segments sensitive: view.sensitive,
// i.e. `/admin/custom-view/:id` -> `/admin/custom-view/123` strict: view.strict,
const regex = pathToRegexp(viewPath, keys, {
sensitive,
strict,
}) })
const match = regex.exec(currentRoute)
const viewRoute = match?.[0] || viewPath
if (exact) return currentRoute === viewRoute
if (!exact) return viewRoute.startsWith(currentRoute)
} }
})?.[1] })?.[1]

View File

@@ -0,0 +1,30 @@
import { pathToRegexp } from 'path-to-regexp'
export const isPathMatchingRoute = ({
currentRoute,
exact,
path: viewPath,
sensitive,
strict,
}: {
currentRoute: string
exact?: boolean
path?: string
sensitive?: boolean
strict?: boolean
}) => {
const keys = []
// run the view path through `pathToRegexp` to resolve any dynamic segments
// i.e. `/admin/custom-view/:id` -> `/admin/custom-view/123`
const regex = pathToRegexp(viewPath, keys, {
sensitive,
strict,
})
const match = regex.exec(currentRoute)
const viewRoute = match?.[0] || viewPath
if (exact) return currentRoute === viewRoute
if (!exact) return viewRoute.startsWith(currentRoute)
}

View File

@@ -42,6 +42,7 @@ export type InitPageResult = {
export type ServerSideEditViewProps = { export type ServerSideEditViewProps = {
initPageResult: InitPageResult initPageResult: InitPageResult
params: { [key: string]: string | string[] | undefined }
routeSegments: string[] routeSegments: string[]
searchParams: { [key: string]: string | string[] | undefined } searchParams: { [key: string]: string | string[] | undefined }
} }

View File

@@ -5,7 +5,7 @@ import type {
SanitizedGlobalConfig, SanitizedGlobalConfig,
} from 'payload/types' } from 'payload/types'
import { isPlainObject } from 'packages/payload/src/utilities/isPlainObject.js' import { isPlainObject } from 'payload/utilities'
import React from 'react' import React from 'react'
import { ShouldRenderTabs } from './ShouldRenderTabs.js' import { ShouldRenderTabs } from './ShouldRenderTabs.js'

View File

@@ -1,11 +1,14 @@
import type { CollectionConfig } from 'payload/types' import type { CollectionConfig } from 'payload/types'
import { CustomTabComponent } from '../components/CustomTabComponent/index.js' import { CustomTabComponent } from '../components/CustomTabComponent/index.js'
import { CustomTabView } from '../components/views/CustomTab/index.js' import { CustomTabComponentView } from '../components/views/CustomTabComponent/index.js'
import { CustomTabView2 } from '../components/views/CustomTab2/index.js' import { CustomTabLabelView } from '../components/views/CustomTabLabel/index.js'
import { CustomNestedTabView } from '../components/views/CustomTabNested/index.js' import { CustomNestedTabView } from '../components/views/CustomTabNested/index.js'
import { CustomTabWithParamView } from '../components/views/CustomTabWithParam/index.js'
import { CustomVersionsView } from '../components/views/CustomVersions/index.js' import { CustomVersionsView } from '../components/views/CustomVersions/index.js'
import { import {
customCollectionParamViewPath,
customCollectionParamViewPathBase,
customEditLabel, customEditLabel,
customNestedTabViewPath, customNestedTabViewPath,
customTabLabel, customTabLabel,
@@ -26,7 +29,7 @@ export const CustomViews2: CollectionConfig = {
}, },
}, },
MyCustomView: { MyCustomView: {
Component: CustomTabView, Component: CustomTabLabelView,
Tab: { Tab: {
href: '/custom-tab-view', href: '/custom-tab-view',
label: customTabLabel, label: customTabLabel,
@@ -34,15 +37,27 @@ export const CustomViews2: CollectionConfig = {
path: '/custom-tab-view', path: '/custom-tab-view',
}, },
MyCustomViewWithCustomTab: { MyCustomViewWithCustomTab: {
Component: CustomTabView2, Component: CustomTabComponentView,
Tab: CustomTabComponent, Tab: CustomTabComponent,
path: customTabViewPath, path: customTabViewPath,
}, },
MyCustomViewWithNestedPath: { MyCustomViewWithNestedPath: {
Component: CustomNestedTabView, Component: CustomNestedTabView,
path: customNestedTabViewPath, path: customNestedTabViewPath,
tab: {
label: 'Custom Nested Tab View',
href: customNestedTabViewPath,
},
}, },
Versions: CustomVersionsView, Versions: CustomVersionsView,
CustomViewWithParam: {
Component: CustomTabWithParamView,
path: customCollectionParamViewPath,
Tab: {
label: 'Custom Param View',
href: `${customCollectionParamViewPathBase}/123`,
},
},
}, },
}, },
}, },

View File

@@ -1,16 +1,21 @@
'use client' 'use client'
import LinkImport from 'next/link' import { useConfig } from '@payloadcms/ui/providers/Config'
import { usePathname } from 'next/navigation' import LinkImport from 'next/link.js'
import { useParams } from 'next/navigation'
import React from 'react' import React from 'react'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
export const CustomTabComponentClient: React.FC<{ export const CustomTabComponentClient: React.FC<{
path: string path: string
}> = (props) => { }> = ({ path }) => {
const { path } = props const {
const pathname = usePathname() routes: { admin: adminRoute },
} = useConfig()
const params = useParams()
return <Link href={`${pathname}${path}`}>Custom Tab Component</Link> const baseRoute = (params.segments.slice(0, 3) as string[]).join('/')
return <Link href={`${adminRoute}/${baseRoute}${path}`}>Custom Tab Component</Link>
} }

View File

@@ -1,5 +1,5 @@
// As this is the demo folder, we import Payload SCSS functions relatively. // As this is the demo folder, we import Payload SCSS functions relatively.
@import '../../../../../packages/ui/src/exports/scss.scss'; @import '../../../../../packages/ui/src/scss/styles.scss';
// In your own projects, you'd import as follows: // In your own projects, you'd import as follows:
// @import '~payload/scss'; // @import '~payload/scss';

View File

@@ -1,5 +1,5 @@
// As this is the demo folder, we import Payload SCSS functions relatively. // As this is the demo folder, we import Payload SCSS functions relatively.
@import '../../../../../packages/ui/src/exports/scss.scss'; @import '../../../../../packages/ui/src/scss/styles.scss';
// In your own projects, you'd import as follows: // In your own projects, you'd import as follows:
// @import '~payload/scss'; // @import '~payload/scss';

View File

@@ -4,9 +4,9 @@ import React, { Fragment } from 'react'
import type { ServerSideEditViewProps } from '../../../../../packages/payload/types.js' import type { ServerSideEditViewProps } from '../../../../../packages/payload/types.js'
import { customTabViewTitle } from '../../../shared.js' import { customTabViewComponentTitle } from '../../../shared.js'
export const CustomTabView2: React.FC<ServerSideEditViewProps> = ({ initPageResult }) => { export const CustomTabComponentView: React.FC<ServerSideEditViewProps> = ({ initPageResult }) => {
if (!initPageResult) { if (!initPageResult) {
notFound() notFound()
} }
@@ -27,7 +27,7 @@ export const CustomTabView2: React.FC<ServerSideEditViewProps> = ({ initPageResu
paddingRight: 'var(--gutter-h)', paddingRight: 'var(--gutter-h)',
}} }}
> >
<h1 id="custom-view-title">{customTabViewTitle}</h1> <h1 id="custom-view-title">{customTabViewComponentTitle}</h1>
<p>This custom view was added through the Payload config:</p> <p>This custom view was added through the Payload config:</p>
<ul> <ul>
<li> <li>

View File

@@ -4,9 +4,9 @@ import React, { Fragment } from 'react'
import type { ServerSideEditViewProps } from '../../../../../packages/payload/types.js' import type { ServerSideEditViewProps } from '../../../../../packages/payload/types.js'
import { customTabViewTitle } from '../../../shared.js' import { customTabLabelViewTitle } from '../../../shared.js'
export const CustomTabView: React.FC<ServerSideEditViewProps> = ({ initPageResult }) => { export const CustomTabLabelView: React.FC<ServerSideEditViewProps> = ({ initPageResult }) => {
if (!initPageResult) { if (!initPageResult) {
notFound() notFound()
} }
@@ -27,7 +27,7 @@ export const CustomTabView: React.FC<ServerSideEditViewProps> = ({ initPageResul
paddingRight: 'var(--gutter-h)', paddingRight: 'var(--gutter-h)',
}} }}
> >
<h1 id="custom-view-title">{customTabViewTitle}</h1> <h1 id="custom-view-title">{customTabLabelViewTitle}</h1>
<p>This custom view was added through the Payload config:</p> <p>This custom view was added through the Payload config:</p>
<ul> <ul>
<li> <li>

View File

@@ -0,0 +1,24 @@
import type { AdminViewProps } from 'payload/types.js'
import React from 'react'
import { customParamViewTitle } from '../../../shared.js'
export const CustomTabWithParamView: React.FC<AdminViewProps> = ({ params }) => {
const paramValue = params?.segments?.[4]
return (
<div
style={{
marginTop: 'calc(var(--base) * 2)',
paddingLeft: 'var(--gutter-h)',
paddingRight: 'var(--gutter-h)',
}}
>
<h1 id="custom-view-title">{customParamViewTitle}</h1>
<p>
This custom collection view is using a dynamic URL parameter `slug: {paramValue || 'None'}`
</p>
</div>
)
}

View File

@@ -2,7 +2,8 @@ import type { GlobalConfig } from 'payload/types'
import { CustomTabComponent } from '../components/CustomTabComponent/index.js' import { CustomTabComponent } from '../components/CustomTabComponent/index.js'
import { CustomDefaultEditView } from '../components/views/CustomEditDefault/index.js' import { CustomDefaultEditView } from '../components/views/CustomEditDefault/index.js'
import { CustomTabView } from '../components/views/CustomTab/index.js' import { CustomTabComponentView } from '../components/views/CustomTabComponent/index.js'
import { CustomTabLabelView } from '../components/views/CustomTabLabel/index.js'
import { CustomVersionsView } from '../components/views/CustomVersions/index.js' import { CustomVersionsView } from '../components/views/CustomVersions/index.js'
import { customGlobalViews2GlobalSlug } from '../slugs.js' import { customGlobalViews2GlobalSlug } from '../slugs.js'
@@ -14,7 +15,7 @@ export const CustomGlobalViews2: GlobalConfig = {
Edit: { Edit: {
Default: CustomDefaultEditView, Default: CustomDefaultEditView,
MyCustomView: { MyCustomView: {
Component: CustomTabView, Component: CustomTabLabelView,
Tab: { Tab: {
href: '/custom-tab-view', href: '/custom-tab-view',
label: 'Custom', label: 'Custom',
@@ -22,7 +23,7 @@ export const CustomGlobalViews2: GlobalConfig = {
path: '/custom-tab-view', path: '/custom-tab-view',
}, },
MyCustomViewWithCustomTab: { MyCustomViewWithCustomTab: {
Component: CustomTabView, Component: CustomTabComponentView,
Tab: CustomTabComponent, Tab: CustomTabComponent,
path: '/custom-tab-component', path: '/custom-tab-component',
}, },

View File

@@ -22,8 +22,14 @@ export const customTabLabel = 'Custom Tab Label'
export const customTabViewPath = '/custom-tab-component' export const customTabViewPath = '/custom-tab-component'
export const customTabViewTitle = 'Custom View With Tab Component' export const customTabLabelViewTitle = 'Custom Tab Label View'
export const customTabViewComponentTitle = 'Custom View With Tab Component'
export const customNestedTabViewPath = `${customTabViewPath}/nested-view` export const customNestedTabViewPath = `${customTabViewPath}/nested-view`
export const customNestedTabViewTitle = 'Custom Nested Tab View' export const customNestedTabViewTitle = 'Custom Nested Tab View'
export const customCollectionParamViewPathBase = '/custom-param'
export const customCollectionParamViewPath = `${customCollectionParamViewPathBase}/:slug`

View File

@@ -28,7 +28,7 @@
} }
], ],
"paths": { "paths": {
"@payload-config": ["./test/_community/config.ts"], "@payload-config": ["./test/admin/config.ts"],
"@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview": ["./packages/live-preview/src"],
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
"@payloadcms/ui/assets": ["./packages/ui/src/assets/index.ts"], "@payloadcms/ui/assets": ["./packages/ui/src/assets/index.ts"],