chore: passes allowCreate into list drawer and adds test (#11284)

### What?
We had an `allowCreate` prop for the list drawer that doesn't do
anything. This PR passes the prop through so it can be used.

### How?
Passes `allowCreate` down to the list view and ties it with
`hasCreatePermission`

#### Testing
- Use `admin` test suite and `withListDrawer` collection.
- Test added to the `admin/e2e/list-view`.

Fixes #11246
This commit is contained in:
Jessica Chowdhury
2025-02-20 12:31:36 +00:00
committed by GitHub
parent 26163a7535
commit c05f10abbc
9 changed files with 119 additions and 4 deletions

View File

@@ -87,6 +87,7 @@ export const ListDrawerContent: React.FC<ListDrawerProps> = ({
const { List: ViewResult } = (await serverFunction({ const { List: ViewResult } = (await serverFunction({
name: 'render-list', name: 'render-list',
args: { args: {
allowCreate,
collectionSlug: slug, collectionSlug: slug,
disableBulkDelete: true, disableBulkDelete: true,
disableBulkEdit: true, disableBulkEdit: true,
@@ -160,6 +161,7 @@ export const ListDrawerContent: React.FC<ListDrawerProps> = ({
return ( return (
<ListDrawerContextProvider <ListDrawerContextProvider
allowCreate={allowCreate}
createNewDrawerSlug={documentDrawerSlug} createNewDrawerSlug={documentDrawerSlug}
DocumentDrawerToggler={DocumentDrawerToggler} DocumentDrawerToggler={DocumentDrawerToggler}
drawerSlug={drawerSlug} drawerSlug={drawerSlug}

View File

@@ -7,6 +7,7 @@ import type { UseDocumentDrawer } from '../DocumentDrawer/types.js'
import type { Option } from '../ReactSelect/index.js' import type { Option } from '../ReactSelect/index.js'
export type ListDrawerContextProps = { export type ListDrawerContextProps = {
readonly allowCreate?: boolean
readonly createNewDrawerSlug?: string readonly createNewDrawerSlug?: string
readonly DocumentDrawerToggler?: ReturnType<UseDocumentDrawer>[1] readonly DocumentDrawerToggler?: ReturnType<UseDocumentDrawer>[1]
readonly drawerSlug?: string readonly drawerSlug?: string

View File

@@ -51,7 +51,7 @@ export function DefaultListView(props: ListViewClientProps) {
disableBulkDelete, disableBulkDelete,
disableBulkEdit, disableBulkEdit,
enableRowSelections, enableRowSelections,
hasCreatePermission, hasCreatePermission: hasCreatePermissionFromProps,
listMenuItems, listMenuItems,
listPreferences, listPreferences,
newDocumentURL, newDocumentURL,
@@ -63,7 +63,17 @@ export function DefaultListView(props: ListViewClientProps) {
const [Table, setTable] = useState(InitialTable) const [Table, setTable] = useState(InitialTable)
const { createNewDrawerSlug, drawerSlug: listDrawerSlug, onBulkSelect } = useListDrawerContext() const {
allowCreate,
createNewDrawerSlug,
drawerSlug: listDrawerSlug,
onBulkSelect,
} = useListDrawerContext()
const hasCreatePermission =
allowCreate !== undefined
? allowCreate && hasCreatePermissionFromProps
: hasCreatePermissionFromProps
useEffect(() => { useEffect(() => {
if (InitialTable) { if (InitialTable) {
@@ -145,7 +155,6 @@ export function DefaultListView(props: ListViewClientProps) {
]) ])
} }
}, [setStepNav, labels, drawerDepth]) }, [setStepNav, labels, drawerDepth])
return ( return (
<Fragment> <Fragment>
<TableColumnsProvider <TableColumnsProvider

View File

@@ -0,0 +1,30 @@
import type { CollectionConfig } from 'payload'
import { listDrawerSlug } from '../slugs.js'
export const ListDrawer: CollectionConfig = {
slug: listDrawerSlug,
admin: {
components: {
beforeListTable: [
{
path: '/components/BeforeList/index.js#SelectPostsButton',
},
],
},
},
fields: [
{
name: 'title',
type: 'text',
},
{
name: 'description',
type: 'text',
},
{
name: 'number',
type: 'number',
},
],
}

View File

@@ -0,0 +1,23 @@
// src/components/SelectPostsButton.tsx
'use client'
import { Button, type UseListDrawer, useListDrawer } from '@payloadcms/ui'
import { useMemo } from 'react'
type UseListDrawerArgs = Parameters<UseListDrawer>[0]
export const SelectPostsButton = () => {
const listDrawerArgs = useMemo<UseListDrawerArgs>(
() => ({
collectionSlugs: ['with-list-drawer'],
}),
[],
)
const [ListDrawer, _, { toggleDrawer }] = useListDrawer(listDrawerArgs)
return (
<>
<Button onClick={() => toggleDrawer()}>Select posts</Button>
<ListDrawer allowCreate={false} enableRowSelections={false} />
</>
)
}

View File

@@ -14,6 +14,7 @@ import { CollectionGroup1B } from './collections/Group1B.js'
import { CollectionGroup2A } from './collections/Group2A.js' import { CollectionGroup2A } from './collections/Group2A.js'
import { CollectionGroup2B } from './collections/Group2B.js' import { CollectionGroup2B } from './collections/Group2B.js'
import { CollectionHidden } from './collections/Hidden.js' import { CollectionHidden } from './collections/Hidden.js'
import { ListDrawer } from './collections/ListDrawer.js'
import { CollectionNoApiView } from './collections/NoApiView.js' import { CollectionNoApiView } from './collections/NoApiView.js'
import { CollectionNotInView } from './collections/NotInView.js' import { CollectionNotInView } from './collections/NotInView.js'
import { Posts } from './collections/Posts.js' import { Posts } from './collections/Posts.js'
@@ -39,7 +40,6 @@ import {
protectedCustomNestedViewPath, protectedCustomNestedViewPath,
publicCustomViewPath, publicCustomViewPath,
} from './shared.js' } from './shared.js'
export default buildConfigWithDefaults({ export default buildConfigWithDefaults({
admin: { admin: {
importMap: { importMap: {
@@ -157,6 +157,7 @@ export default buildConfigWithDefaults({
DisableDuplicate, DisableDuplicate,
BaseListFilter, BaseListFilter,
with300Documents, with300Documents,
ListDrawer,
], ],
globals: [ globals: [
GlobalHidden, GlobalHidden,

View File

@@ -19,6 +19,7 @@ import { customAdminRoutes } from '../../shared.js'
import { import {
customViews1CollectionSlug, customViews1CollectionSlug,
geoCollectionSlug, geoCollectionSlug,
listDrawerSlug,
postsCollectionSlug, postsCollectionSlug,
with300DocumentsSlug, with300DocumentsSlug,
} from '../../slugs.js' } from '../../slugs.js'
@@ -56,6 +57,7 @@ describe('List View', () => {
let baseListFiltersUrl: AdminUrlUtil let baseListFiltersUrl: AdminUrlUtil
let customViewsUrl: AdminUrlUtil let customViewsUrl: AdminUrlUtil
let with300DocumentsUrl: AdminUrlUtil let with300DocumentsUrl: AdminUrlUtil
let withListViewUrl: AdminUrlUtil
let serverURL: string let serverURL: string
let adminRoutes: ReturnType<typeof getRoutes> let adminRoutes: ReturnType<typeof getRoutes>
@@ -76,6 +78,7 @@ describe('List View', () => {
with300DocumentsUrl = new AdminUrlUtil(serverURL, with300DocumentsSlug) with300DocumentsUrl = new AdminUrlUtil(serverURL, with300DocumentsSlug)
baseListFiltersUrl = new AdminUrlUtil(serverURL, 'base-list-filters') baseListFiltersUrl = new AdminUrlUtil(serverURL, 'base-list-filters')
customViewsUrl = new AdminUrlUtil(serverURL, customViews1CollectionSlug) customViewsUrl = new AdminUrlUtil(serverURL, customViews1CollectionSlug)
withListViewUrl = new AdminUrlUtil(serverURL, listDrawerSlug)
const context = await browser.newContext() const context = await browser.newContext()
page = await context.newPage() page = await context.newPage()
@@ -156,6 +159,20 @@ describe('List View', () => {
`${adminRoutes.routes?.admin}/collections/posts/${id}`, `${adminRoutes.routes?.admin}/collections/posts/${id}`,
) )
}) })
test('should hide create new button when allowCreate is false', async () => {
await page.goto(withListViewUrl.list)
const drawerButton = page.locator('button', { hasText: 'Select Posts' })
await expect(drawerButton).toBeVisible()
await drawerButton.click()
const drawer = page.locator('.drawer__content')
await expect(drawer).toBeVisible()
const createButton = page.locator('button', { hasText: 'Create New' })
await expect(createButton).toBeHidden()
})
}) })
describe('list view custom components', () => { describe('list view custom components', () => {

View File

@@ -83,6 +83,7 @@ export interface Config {
'disable-duplicate': DisableDuplicate; 'disable-duplicate': DisableDuplicate;
'base-list-filters': BaseListFilter; 'base-list-filters': BaseListFilter;
with300documents: With300Document; with300documents: With300Document;
'with-list-drawer': WithListDrawer;
'payload-locked-documents': PayloadLockedDocument; 'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference; 'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration; 'payload-migrations': PayloadMigration;
@@ -106,6 +107,7 @@ export interface Config {
'disable-duplicate': DisableDuplicateSelect<false> | DisableDuplicateSelect<true>; 'disable-duplicate': DisableDuplicateSelect<false> | DisableDuplicateSelect<true>;
'base-list-filters': BaseListFiltersSelect<false> | BaseListFiltersSelect<true>; 'base-list-filters': BaseListFiltersSelect<false> | BaseListFiltersSelect<true>;
with300documents: With300DocumentsSelect<false> | With300DocumentsSelect<true>; with300documents: With300DocumentsSelect<false> | With300DocumentsSelect<true>;
'with-list-drawer': WithListDrawerSelect<false> | WithListDrawerSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>; 'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>; 'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>; 'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
@@ -445,6 +447,18 @@ export interface With300Document {
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "with-list-drawer".
*/
export interface WithListDrawer {
id: string;
title?: string | null;
description?: string | null;
number?: number | null;
updatedAt: string;
createdAt: string;
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents". * via the `definition` "payload-locked-documents".
@@ -519,6 +533,10 @@ export interface PayloadLockedDocument {
| ({ | ({
relationTo: 'with300documents'; relationTo: 'with300documents';
value: string | With300Document; value: string | With300Document;
} | null)
| ({
relationTo: 'with-list-drawer';
value: string | WithListDrawer;
} | null); } | null);
globalSlug?: string | null; globalSlug?: string | null;
user: { user: {
@@ -822,6 +840,17 @@ export interface With300DocumentsSelect<T extends boolean = true> {
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "with-list-drawer_select".
*/
export interface WithListDrawerSelect<T extends boolean = true> {
title?: T;
description?: T;
number?: T;
updatedAt?: T;
createdAt?: T;
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select". * via the `definition` "payload-locked-documents_select".

View File

@@ -13,6 +13,8 @@ export const noApiViewCollectionSlug = 'collection-no-api-view'
export const disableDuplicateSlug = 'disable-duplicate' export const disableDuplicateSlug = 'disable-duplicate'
export const uploadCollectionSlug = 'uploads' export const uploadCollectionSlug = 'uploads'
export const customFieldsSlug = 'custom-fields' export const customFieldsSlug = 'custom-fields'
export const listDrawerSlug = 'with-list-drawer'
export const collectionSlugs = [ export const collectionSlugs = [
usersCollectionSlug, usersCollectionSlug,
customViews1CollectionSlug, customViews1CollectionSlug,
@@ -27,6 +29,7 @@ export const collectionSlugs = [
noApiViewCollectionSlug, noApiViewCollectionSlug,
customFieldsSlug, customFieldsSlug,
disableDuplicateSlug, disableDuplicateSlug,
listDrawerSlug,
] ]
export const customGlobalViews1GlobalSlug = 'custom-global-views-one' export const customGlobalViews1GlobalSlug = 'custom-global-views-one'