diff --git a/docs/custom-components/custom-views.mdx b/docs/custom-components/custom-views.mdx
index 59e18ddcfea..b6ea06bd6d7 100644
--- a/docs/custom-components/custom-views.mdx
+++ b/docs/custom-components/custom-views.mdx
@@ -52,6 +52,7 @@ For more granular control, pass a configuration object instead. Payload exposes
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Component` \* | Pass in the component path that should be rendered when a user navigates to this route. |
| `path` \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
+| `condition` | Optional function that receives `req` and `doc` as arguments and returns a `boolean`. When `true`, the route and associated tab are rendered. Defaults to `true`. |
| `exact` | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
| `strict` | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
| `sensitive` | When true, will match if the path is case sensitive. |
diff --git a/docs/custom-components/document-views.mdx b/docs/custom-components/document-views.mdx
index 36b63b1109e..1f0ba3fc24c 100644
--- a/docs/custom-components/document-views.mdx
+++ b/docs/custom-components/document-views.mdx
@@ -181,3 +181,38 @@ export function MyCustomTabComponent(props: DocumentTabClientProps) {
)
}
```
+
+## Restricting Document Views
+
+You can restrict access to specific Document Views by using the `views.edit.[key].condition` property in your [Collection Config](../configuration/collections) or [Global Config](../configuration/globals). This allows you to control which user roles can access specific views.
+
+To restrict access, define a condition function that returns a `boolean`. This function receives both the `req` and the relevant `doc` as arguments.
+
+If the condition returns `false`, the corresponding **view and its tab** will not be rendered or accessible to the user.
+
+#### Example
+
+```ts
+import type { CollectionConfig } from 'payload'
+
+export const MyCollection: CollectionConfig = {
+ slug: 'my-collection',
+ // ...
+ admin: {
+ // ...
+ components: {
+ views: {
+ edit: {
+ api: {
+ condition: ({ doc, req: { user } }) => {
+ return user?.roles?.includes('admin') ?? false
+ },
+ },
+ },
+ },
+ },
+ },
+}
+```
+
+In this example, only users with the `admin` role can access the API View and its associated tab. This setup works for both Collection and Global Document Views.
diff --git a/packages/next/src/elements/DocumentHeader/Tabs/index.tsx b/packages/next/src/elements/DocumentHeader/Tabs/index.tsx
index 6efef9a5be1..85f56ba09b2 100644
--- a/packages/next/src/elements/DocumentHeader/Tabs/index.tsx
+++ b/packages/next/src/elements/DocumentHeader/Tabs/index.tsx
@@ -1,8 +1,10 @@
import type { I18n } from '@payloadcms/translations'
import type {
+ Data,
DocumentTabClientProps,
DocumentTabServerPropsOnly,
Payload,
+ PayloadRequest,
SanitizedCollectionConfig,
SanitizedGlobalConfig,
SanitizedPermissions,
@@ -13,19 +15,21 @@ import React from 'react'
import { ShouldRenderTabs } from './ShouldRenderTabs.js'
import { DocumentTab } from './Tab/index.js'
-import { getTabs } from './tabs/index.js'
import './index.scss'
+import { getTabs } from './tabs/index.js'
const baseClass = 'doc-tabs'
export const DocumentTabs: React.FC<{
collectionConfig: SanitizedCollectionConfig
+ doc: Data
globalConfig: SanitizedGlobalConfig
i18n: I18n
payload: Payload
permissions: SanitizedPermissions
+ req?: PayloadRequest
}> = (props) => {
- const { collectionConfig, globalConfig, i18n, payload, permissions } = props
+ const { collectionConfig, doc, globalConfig, i18n, payload, permissions, req } = props
const { config } = payload
const tabs = getTabs({
@@ -38,13 +42,33 @@ export const DocumentTabs: React.FC<{
- {tabs?.map(({ tab, viewPath }, index) => {
+ {tabs?.map(({ name, tab, viewPath }, index) => {
const { condition } = tab || {}
-
const meetsCondition =
!condition || condition({ collectionConfig, config, globalConfig, permissions })
- if (!meetsCondition) {
+ let viewConfig
+
+ if (collectionConfig) {
+ if (typeof collectionConfig?.admin?.components?.views?.edit === 'object') {
+ viewConfig = collectionConfig.admin.components.views.edit[name]
+ }
+ } else if (globalConfig) {
+ if (typeof globalConfig?.admin?.components?.views?.edit === 'object') {
+ viewConfig = globalConfig.admin.components.views.edit[name]
+ }
+ }
+
+ const { condition: viewCondition } = viewConfig || {}
+
+ const meetsViewCondition =
+ !viewCondition ||
+ viewCondition({
+ doc,
+ req,
+ })
+
+ if (!meetsCondition || !meetsViewCondition) {
return null
}
diff --git a/packages/next/src/elements/DocumentHeader/Tabs/tabs/index.tsx b/packages/next/src/elements/DocumentHeader/Tabs/tabs/index.tsx
index 6c35864aacb..3d907a4469d 100644
--- a/packages/next/src/elements/DocumentHeader/Tabs/tabs/index.tsx
+++ b/packages/next/src/elements/DocumentHeader/Tabs/tabs/index.tsx
@@ -12,7 +12,7 @@ export const getTabs = ({
}: {
collectionConfig?: SanitizedCollectionConfig
globalConfig?: SanitizedGlobalConfig
-}): { tab: DocumentTabConfig; viewPath: string }[] => {
+}): { name: string; tab: DocumentTabConfig; viewPath: string }[] => {
const customViews =
collectionConfig?.admin?.components?.views?.edit ||
globalConfig?.admin?.components?.views?.edit ||
@@ -20,6 +20,7 @@ export const getTabs = ({
return [
{
+ name: 'default',
tab: {
href: '',
label: ({ t }) => t('general:edit'),
@@ -29,6 +30,7 @@ export const getTabs = ({
viewPath: '/',
},
{
+ name: 'livePreview',
tab: {
condition: ({ collectionConfig, config, globalConfig }) => {
if (collectionConfig) {
@@ -55,6 +57,7 @@ export const getTabs = ({
viewPath: '/preview',
},
{
+ name: 'versions',
tab: {
condition: ({ collectionConfig, globalConfig, permissions }) =>
Boolean(
@@ -71,6 +74,7 @@ export const getTabs = ({
viewPath: '/versions',
},
{
+ name: 'api',
tab: {
condition: ({ collectionConfig, globalConfig }) =>
(collectionConfig && !collectionConfig?.admin?.hideAPIURL) ||
diff --git a/packages/next/src/elements/DocumentHeader/index.tsx b/packages/next/src/elements/DocumentHeader/index.tsx
index 399edf3021a..c6d65ef7538 100644
--- a/packages/next/src/elements/DocumentHeader/index.tsx
+++ b/packages/next/src/elements/DocumentHeader/index.tsx
@@ -1,6 +1,8 @@
import type { I18n } from '@payloadcms/translations'
import type {
+ Data,
Payload,
+ PayloadRequest,
SanitizedCollectionConfig,
SanitizedGlobalConfig,
SanitizedPermissions,
@@ -16,13 +18,15 @@ const baseClass = `doc-header`
export const DocumentHeader: React.FC<{
collectionConfig?: SanitizedCollectionConfig
+ doc: Data
globalConfig?: SanitizedGlobalConfig
hideTabs?: boolean
i18n: I18n
payload: Payload
permissions: SanitizedPermissions
+ req?: PayloadRequest
}> = (props) => {
- const { collectionConfig, globalConfig, hideTabs, i18n, payload, permissions } = props
+ const { collectionConfig, doc, globalConfig, hideTabs, i18n, payload, permissions, req } = props
return (
@@ -30,10 +34,12 @@ export const DocumentHeader: React.FC<{
{!hideTabs && (
)}
diff --git a/packages/next/src/views/Account/index.tsx b/packages/next/src/views/Account/index.tsx
index 71536650963..a5294148425 100644
--- a/packages/next/src/views/Account/index.tsx
+++ b/packages/next/src/views/Account/index.tsx
@@ -136,6 +136,7 @@ export async function Account({ initPageResult, params, searchParams }: AdminVie
= {
Component?: React.FC
@@ -27,14 +30,18 @@ export type ViewFromConfig = {
export const getDocumentView = ({
collectionConfig,
config,
+ doc,
docPermissions,
globalConfig,
+ req,
routeSegments,
}: {
collectionConfig?: SanitizedCollectionConfig
config: SanitizedConfig
+ doc: Data
docPermissions: SanitizedCollectionPermission | SanitizedGlobalPermission
globalConfig?: SanitizedGlobalConfig
+ req?: PayloadRequest
routeSegments: string[]
}): {
View: ViewToRender
@@ -52,6 +59,21 @@ export const getDocumentView = ({
(collectionConfig && collectionConfig?.admin?.components?.views) ||
(globalConfig && globalConfig?.admin?.components?.views)
+ const viewCondition = (viewKey: string): boolean => {
+ const passesCondition = getViewCondition({
+ name: viewKey,
+ collectionConfig,
+ doc,
+ globalConfig,
+ req,
+ })
+
+ if (passesCondition === true) {
+ return true
+ }
+ return false
+ }
+
if (!docPermissions?.read) {
throw new Error('not-found')
}
@@ -119,7 +141,8 @@ export const getDocumentView = ({
switch (segment4) {
// --> /collections/:collectionSlug/:id/api
case 'api': {
- if (collectionConfig?.admin?.hideAPIURL !== true) {
+ const passesCondition = viewCondition('api')
+ if (passesCondition && collectionConfig?.admin?.hideAPIURL !== true) {
View = getCustomViewByKey(views, 'api') || DefaultAPIView
}
break
@@ -127,8 +150,10 @@ export const getDocumentView = ({
case 'preview': {
// --> /collections/:collectionSlug/:id/preview
+
+ const passesCondition = viewCondition('preview')
if (
- (collectionConfig && collectionConfig?.admin?.livePreview) ||
+ (passesCondition && collectionConfig && collectionConfig?.admin?.livePreview) ||
config?.admin?.livePreview?.collections?.includes(collectionConfig?.slug)
) {
View = getCustomViewByKey(views, 'livePreview') || DefaultLivePreviewView
@@ -138,7 +163,8 @@ export const getDocumentView = ({
case 'versions': {
// --> /collections/:collectionSlug/:id/versions
- if (docPermissions?.readVersions) {
+ const passesCondition = viewCondition('versions')
+ if (passesCondition && docPermissions?.readVersions) {
View = getCustomViewByKey(views, 'versions') || DefaultVersionsView
} else {
View = UnauthorizedViewWithGutter
@@ -185,7 +211,8 @@ export const getDocumentView = ({
default: {
// --> /collections/:collectionSlug/:id/versions/:version
if (segment4 === 'versions') {
- if (docPermissions?.readVersions) {
+ const passesCondition = viewCondition('versions')
+ if (passesCondition && docPermissions?.readVersions) {
View = getCustomViewByKey(views, 'version') || DefaultVersionView
} else {
View = UnauthorizedViewWithGutter
@@ -240,7 +267,8 @@ export const getDocumentView = ({
switch (segment3) {
// --> /globals/:globalSlug/api
case 'api': {
- if (globalConfig?.admin?.hideAPIURL !== true) {
+ const passesCondition = viewCondition('api')
+ if (passesCondition && globalConfig?.admin?.hideAPIURL !== true) {
View = getCustomViewByKey(views, 'api') || DefaultAPIView
}
@@ -249,8 +277,9 @@ export const getDocumentView = ({
case 'preview': {
// --> /globals/:globalSlug/preview
+ const passesCondition = viewCondition('preview')
if (
- (globalConfig && globalConfig?.admin?.livePreview) ||
+ (passesCondition && globalConfig && globalConfig?.admin?.livePreview) ||
config?.admin?.livePreview?.globals?.includes(globalConfig?.slug)
) {
View = getCustomViewByKey(views, 'livePreview') || DefaultLivePreviewView
@@ -261,7 +290,8 @@ export const getDocumentView = ({
case 'versions': {
// --> /globals/:globalSlug/versions
- if (docPermissions?.readVersions) {
+ const passesCondition = viewCondition('versions')
+ if (passesCondition && docPermissions?.readVersions) {
View = getCustomViewByKey(views, 'versions') || DefaultVersionsView
} else {
View = UnauthorizedViewWithGutter
diff --git a/packages/next/src/views/Document/getMetaBySegment.tsx b/packages/next/src/views/Document/getMetaBySegment.tsx
index 2d42819e697..34a7b3507bf 100644
--- a/packages/next/src/views/Document/getMetaBySegment.tsx
+++ b/packages/next/src/views/Document/getMetaBySegment.tsx
@@ -1,5 +1,10 @@
import type { Metadata } from 'next'
-import type { EditConfig, SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload'
+import type {
+ EditConfig,
+ PayloadRequest,
+ SanitizedCollectionConfig,
+ SanitizedGlobalConfig,
+} from 'payload'
import type { GenerateViewMetadata } from '../Root/index.js'
@@ -16,6 +21,7 @@ export type GenerateEditViewMetadata = (
args: {
collectionConfig?: null | SanitizedCollectionConfig
globalConfig?: null | SanitizedGlobalConfig
+ req?: PayloadRequest
view?: keyof EditConfig
} & Parameters[0],
) => Promise
@@ -25,6 +31,7 @@ export const getMetaBySegment: GenerateEditViewMetadata = async ({
config,
globalConfig,
params,
+ req,
}) => {
const { segments } = params
@@ -124,6 +131,7 @@ export const getMetaBySegment: GenerateEditViewMetadata = async ({
const { viewKey } = getDocumentView({
collectionConfig,
config,
+ doc: {},
docPermissions: {
create: true,
delete: true,
@@ -133,6 +141,7 @@ export const getMetaBySegment: GenerateEditViewMetadata = async ({
update: true,
},
globalConfig,
+ req,
routeSegments: typeof segments === 'string' ? [segments] : segments,
})
diff --git a/packages/next/src/views/Document/getViewCondition.ts b/packages/next/src/views/Document/getViewCondition.ts
new file mode 100644
index 00000000000..c500400a9c6
--- /dev/null
+++ b/packages/next/src/views/Document/getViewCondition.ts
@@ -0,0 +1,34 @@
+import type {
+ Data,
+ PayloadRequest,
+ SanitizedCollectionConfig,
+ SanitizedGlobalConfig,
+} from 'payload'
+
+export const getViewCondition = (args: {
+ collectionConfig: SanitizedCollectionConfig
+ doc: Data
+ globalConfig: SanitizedGlobalConfig
+ name: string
+ req: PayloadRequest
+}): boolean => {
+ const { name, collectionConfig, doc, globalConfig, req } = args
+
+ let viewConfig
+
+ if (collectionConfig) {
+ if (typeof collectionConfig?.admin?.components?.views?.edit === 'object') {
+ viewConfig = collectionConfig.admin.components.views.edit[name]
+ }
+ } else if (globalConfig) {
+ if (typeof globalConfig?.admin?.components?.views?.edit === 'object') {
+ viewConfig = globalConfig.admin.components.views.edit[name]
+ }
+ }
+
+ const { condition } = viewConfig || {}
+
+ const meetsCondition = !condition || (condition && Boolean(condition({ doc, req })))
+
+ return meetsCondition
+}
diff --git a/packages/next/src/views/Document/index.tsx b/packages/next/src/views/Document/index.tsx
index 94ac33fcbf5..92db5d568a0 100644
--- a/packages/next/src/views/Document/index.tsx
+++ b/packages/next/src/views/Document/index.tsx
@@ -241,8 +241,10 @@ export const renderDocument = async ({
;({ View } = getDocumentView({
collectionConfig,
config,
+ doc,
docPermissions,
globalConfig,
+ req,
routeSegments: segments,
}))
}
@@ -340,10 +342,12 @@ export const renderDocument = async ({
{showHeader && !drawerSlug && (
)}
diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts
index 346cce47dad..f901ec4e73e 100644
--- a/packages/payload/src/config/types.ts
+++ b/packages/payload/src/config/types.ts
@@ -18,6 +18,7 @@ import type { DeepRequired } from 'ts-essentials'
import type { RichTextAdapterProvider } from '../admin/RichText.js'
import type {
+ Data,
DocumentSubViewTypes,
DocumentTabConfig,
DocumentViewServerProps,
@@ -348,6 +349,8 @@ export type Endpoint = {
*/
export type EditViewComponent = DocumentViewComponent
+export type ViewCondition = (args: { doc: Data; req: PayloadRequest }) => boolean
+
export type DocumentViewComponent = PayloadComponent
/**
@@ -359,6 +362,7 @@ export type EditViewConfig = DocumentViewConfig
type BaseDocumentViewConfig = {
actions?: CustomComponent[]
+ condition?: ViewCondition
meta?: MetaConfig
tab?: DocumentTabConfig
}
diff --git a/test/admin/collections/Users.ts b/test/admin/collections/Users.ts
index 6cd4bd3551a..2046cf6793f 100644
--- a/test/admin/collections/Users.ts
+++ b/test/admin/collections/Users.ts
@@ -20,5 +20,21 @@ export const Users: CollectionConfig = {
position: 'sidebar',
},
},
+ {
+ name: 'roles',
+ type: 'select',
+ hasMany: true,
+ options: [
+ {
+ label: 'Admin',
+ value: 'admin',
+ },
+ {
+ label: 'User',
+ value: 'user',
+ },
+ ],
+ defaultValue: 'user',
+ },
],
}
diff --git a/test/admin/collections/ViewConditions.ts b/test/admin/collections/ViewConditions.ts
new file mode 100644
index 00000000000..cf83e197e49
--- /dev/null
+++ b/test/admin/collections/ViewConditions.ts
@@ -0,0 +1,33 @@
+import type { CollectionConfig } from 'payload'
+
+import { viewConditionsCollectionSlug } from '../slugs.js'
+
+export const ViewConditions: CollectionConfig = {
+ slug: viewConditionsCollectionSlug,
+ admin: {
+ components: {
+ views: {
+ edit: {
+ api: {
+ condition: (args) => {
+ const { doc, req } = args
+ const trueTitle = doc?.title === 't'
+ if (req.user?.roles?.includes('admin') || trueTitle) {
+ return true
+ } else {
+ return false
+ }
+ },
+ },
+ },
+ },
+ },
+ },
+ fields: [
+ {
+ name: 'title',
+ type: 'text',
+ },
+ ],
+ versions: true,
+}
diff --git a/test/admin/config.ts b/test/admin/config.ts
index 44537855ef7..c8735471eda 100644
--- a/test/admin/config.ts
+++ b/test/admin/config.ts
@@ -27,6 +27,7 @@ import { UploadCollection } from './collections/Upload.js'
import { UploadTwoCollection } from './collections/UploadTwo.js'
import { UseAsTitleGroupField } from './collections/UseAsTitleGroupField.js'
import { Users } from './collections/Users.js'
+import { ViewConditions } from './collections/ViewConditions.js'
import { with300Documents } from './collections/With300Documents.js'
import { CustomGlobalViews1 } from './globals/CustomViews1.js'
import { CustomGlobalViews2 } from './globals/CustomViews2.js'
@@ -37,6 +38,7 @@ import { GlobalHidden } from './globals/Hidden.js'
import { GlobalNoApiView } from './globals/NoApiView.js'
import { GlobalNotInView } from './globals/NotInView.js'
import { Settings } from './globals/Settings.js'
+import { ViewConditionsGlobal } from './globals/ViewConditionsGlobal.js'
import { seed } from './seed.js'
import {
customAdminRoutes,
@@ -179,6 +181,7 @@ export default buildConfigWithDefaults({
with300Documents,
ListDrawer,
Placeholder,
+ ViewConditions,
UseAsTitleGroupField,
DisableBulkEdit,
],
@@ -192,6 +195,7 @@ export default buildConfigWithDefaults({
GlobalGroup1A,
GlobalGroup1B,
Settings,
+ ViewConditionsGlobal,
],
i18n: {
translations: {
@@ -226,6 +230,15 @@ export default buildConfigWithDefaults({
if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') {
await seed(payload)
}
+
+ const user = await payload.create({
+ collection: 'users',
+ data: {
+ email: 'admin@payloadcms.com',
+ password: 'demo',
+ roles: ['admin'],
+ },
+ })
},
typescript: {
outputFile: path.resolve(dirname, 'payload-types.ts'),
diff --git a/test/admin/e2e/document-view/e2e.spec.ts b/test/admin/e2e/document-view/e2e.spec.ts
index f84cf0ea82e..063a859a212 100644
--- a/test/admin/e2e/document-view/e2e.spec.ts
+++ b/test/admin/e2e/document-view/e2e.spec.ts
@@ -40,6 +40,8 @@ import {
placeholderCollectionSlug,
postsCollectionSlug,
reorderTabsSlug,
+ viewConditionsCollectionSlug,
+ viewConditionsGlobalSlug,
} from '../../slugs.js'
const { beforeAll, beforeEach, describe } = test
@@ -72,6 +74,8 @@ describe('Document View', () => {
let placeholderURL: AdminUrlUtil
let collectionCustomViewPathId: string
let editMenuItemsURL: AdminUrlUtil
+ let viewConditionsURL: AdminUrlUtil
+ let viewConditionsGlobalURL: AdminUrlUtil
let reorderTabsURL: AdminUrlUtil
beforeAll(async ({ browser }, testInfo) => {
@@ -90,6 +94,8 @@ describe('Document View', () => {
customFieldsURL = new AdminUrlUtil(serverURL, customFieldsSlug)
placeholderURL = new AdminUrlUtil(serverURL, placeholderCollectionSlug)
editMenuItemsURL = new AdminUrlUtil(serverURL, editMenuItemsSlug)
+ viewConditionsURL = new AdminUrlUtil(serverURL, viewConditionsCollectionSlug)
+ viewConditionsGlobalURL = new AdminUrlUtil(serverURL, viewConditionsGlobalSlug)
reorderTabsURL = new AdminUrlUtil(serverURL, reorderTabsSlug)
const context = await browser.newContext()
@@ -708,6 +714,32 @@ describe('Document View', () => {
await expect(customEditMenuItem).toBeVisible()
})
})
+
+ describe('conditional document views and tabs', () => {
+ test('collection - should hide API tab and view when user does not meet condition', async () => {
+ await page.goto(viewConditionsURL.create)
+ await page.locator('#field-title').fill(title)
+ await saveDocAndAssert(page)
+ const docTabs = page.locator('.doc-tabs__tabs')
+ await expect(docTabs).not.toContainText('API')
+ const apiViewURL = `${page.url()}/api`
+ await page.goto(apiViewURL)
+ const notFound = page.locator('.not-found__content')
+ await expect(notFound).toBeVisible()
+ })
+
+ test('global - should hide API tab and view in global when user does not meet condition', async () => {
+ await page.goto(viewConditionsGlobalURL.global(viewConditionsGlobalSlug))
+ await page.locator('#field-title').fill(title)
+ await saveDocAndAssert(page)
+ const docTabs = page.locator('.doc-tabs__tabs')
+ await expect(docTabs).not.toContainText('API')
+ const apiViewURL = `${page.url()}/api`
+ await page.goto(apiViewURL)
+ const notFound = page.locator('.not-found__content')
+ await expect(notFound).toBeVisible()
+ })
+ })
})
async function createPost(overrides?: Partial): Promise {
diff --git a/test/admin/globals/ViewConditionsGlobal.ts b/test/admin/globals/ViewConditionsGlobal.ts
new file mode 100644
index 00000000000..6c92e9dc962
--- /dev/null
+++ b/test/admin/globals/ViewConditionsGlobal.ts
@@ -0,0 +1,31 @@
+import type { GlobalConfig } from 'payload'
+
+import { viewConditionsGlobalSlug } from '../slugs.js'
+
+export const ViewConditionsGlobal: GlobalConfig = {
+ slug: viewConditionsGlobalSlug,
+ admin: {
+ components: {
+ views: {
+ edit: {
+ api: {
+ condition: ({ req: { user } }) => {
+ const isAdmin = user && 'roles' in user && user?.roles?.includes('admin')
+ if (isAdmin) {
+ return true
+ }
+ return false
+ },
+ },
+ },
+ },
+ },
+ },
+ fields: [
+ {
+ name: 'title',
+ type: 'text',
+ },
+ ],
+ versions: true,
+}
diff --git a/test/admin/payload-types.ts b/test/admin/payload-types.ts
index 88fb0f3d5da..aea2d1de9e0 100644
--- a/test/admin/payload-types.ts
+++ b/test/admin/payload-types.ts
@@ -91,6 +91,7 @@ export interface Config {
with300documents: With300Document;
'with-list-drawer': WithListDrawer;
placeholder: Placeholder;
+ 'view-conditions': ViewCondition;
'use-as-title-group-field': UseAsTitleGroupField;
'disable-bulk-edit': DisableBulkEdit;
'payload-locked-documents': PayloadLockedDocument;
@@ -123,6 +124,7 @@ export interface Config {
with300documents: With300DocumentsSelect | With300DocumentsSelect;
'with-list-drawer': WithListDrawerSelect | WithListDrawerSelect;
placeholder: PlaceholderSelect | PlaceholderSelect;
+ 'view-conditions': ViewConditionsSelect | ViewConditionsSelect;
'use-as-title-group-field': UseAsTitleGroupFieldSelect | UseAsTitleGroupFieldSelect;
'disable-bulk-edit': DisableBulkEditSelect | DisableBulkEditSelect;
'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect;
@@ -142,6 +144,7 @@ export interface Config {
'group-globals-one': GroupGlobalsOne;
'group-globals-two': GroupGlobalsTwo;
settings: Setting;
+ 'view-conditions-global': ViewConditionsGlobal;
};
globalsSelect: {
'hidden-global': HiddenGlobalSelect | HiddenGlobalSelect;
@@ -153,6 +156,7 @@ export interface Config {
'group-globals-one': GroupGlobalsOneSelect | GroupGlobalsOneSelect;
'group-globals-two': GroupGlobalsTwoSelect | GroupGlobalsTwoSelect;
settings: SettingsSelect | SettingsSelect;
+ 'view-conditions-global': ViewConditionsGlobalSelect | ViewConditionsGlobalSelect;
};
locale: 'es' | 'en';
user: User & {
@@ -284,6 +288,7 @@ export interface User {
id: string;
textField?: string | null;
sidebarField?: string | null;
+ roles?: ('admin' | 'user')[] | null;
updatedAt: string;
createdAt: string;
email: string;
@@ -539,6 +544,16 @@ export interface Placeholder {
updatedAt: string;
createdAt: string;
}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "view-conditions".
+ */
+export interface ViewCondition {
+ id: string;
+ title?: string | null;
+ updatedAt: string;
+ createdAt: string;
+}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "use-as-title-group-field".
@@ -661,6 +676,10 @@ export interface PayloadLockedDocument {
relationTo: 'placeholder';
value: string | Placeholder;
} | null)
+ | ({
+ relationTo: 'view-conditions';
+ value: string | ViewCondition;
+ } | null)
| ({
relationTo: 'use-as-title-group-field';
value: string | UseAsTitleGroupField;
@@ -811,6 +830,7 @@ export interface PostsSelect {
export interface UsersSelect {
textField?: T;
sidebarField?: T;
+ roles?: T;
updatedAt?: T;
createdAt?: T;
email?: T;
@@ -1043,6 +1063,15 @@ export interface PlaceholderSelect {
updatedAt?: T;
createdAt?: T;
}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "view-conditions_select".
+ */
+export interface ViewConditionsSelect {
+ title?: T;
+ updatedAt?: T;
+ createdAt?: T;
+}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "use-as-title-group-field_select".
@@ -1183,6 +1212,16 @@ export interface Setting {
updatedAt?: string | null;
createdAt?: string | null;
}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "view-conditions-global".
+ */
+export interface ViewConditionsGlobal {
+ id: string;
+ title?: string | null;
+ updatedAt?: string | null;
+ createdAt?: string | null;
+}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "hidden-global_select".
@@ -1274,6 +1313,16 @@ export interface SettingsSelect {
createdAt?: T;
globalType?: T;
}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "view-conditions-global_select".
+ */
+export interface ViewConditionsGlobalSelect {
+ title?: T;
+ updatedAt?: T;
+ createdAt?: T;
+ globalType?: T;
+}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".
diff --git a/test/admin/slugs.ts b/test/admin/slugs.ts
index 9b47ca79f9a..c325d728144 100644
--- a/test/admin/slugs.ts
+++ b/test/admin/slugs.ts
@@ -62,3 +62,6 @@ export const globalSlugs = [
]
export const with300DocumentsSlug = 'with300documents'
export const editMenuItemsSlug = 'edit-menu-items'
+export const viewConditionsCollectionSlug = 'view-conditions'
+
+export const viewConditionsGlobalSlug = 'view-conditions-global'
diff --git a/test/database/up-down-migration/migrations/20250624_142145.ts b/test/database/up-down-migration/migrations/20250624_142145.ts
index a5346c2c988..0f65d8f5993 100644
--- a/test/database/up-down-migration/migrations/20250624_142145.ts
+++ b/test/database/up-down-migration/migrations/20250624_142145.ts
@@ -1,4 +1,4 @@
-import type { MigrateDownArgs, MigrateUpArgs} from '@payloadcms/db-postgres';
+import type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/db-postgres'
import { sql } from '@payloadcms/db-postgres'