Merge branch 'main' into feat/folders

This commit is contained in:
Jarrod Flesch
2025-04-18 10:56:46 -04:00
157 changed files with 2010 additions and 445 deletions

View File

@@ -10,6 +10,7 @@ import type { Config } from '../../payload-types.js'
import {
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
// throttleTest,
} from '../../../helpers.js'
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
@@ -225,4 +226,19 @@ describe('Conditional Logic', () => {
await expect(numberField).toBeVisible()
})
test('should render field based on operation argument', async () => {
await page.goto(url.create)
const textField = page.locator('#field-text')
const fieldWithOperationCondition = page.locator('#field-fieldWithOperationCondition')
await textField.fill('some text')
await expect(fieldWithOperationCondition).toBeVisible()
await saveDocAndAssert(page)
await expect(fieldWithOperationCondition).toBeHidden()
})
})

View File

@@ -24,6 +24,19 @@ const ConditionalLogic: CollectionConfig = {
condition: ({ toggleField }) => Boolean(toggleField),
},
},
{
name: 'fieldWithOperationCondition',
type: 'text',
admin: {
condition: (data, siblingData, { operation }) => {
if (operation === 'create') {
return true
}
return false
},
},
},
{
name: 'customFieldWithField',
type: 'text',
@@ -217,7 +230,7 @@ const ConditionalLogic: CollectionConfig = {
name: 'numberField',
type: 'number',
admin: {
condition: (data, siblingData, { path, user }) => {
condition: (data, siblingData, { path }) => {
// Ensure path has enough depth
if (path.length < 5) {
return false

View File

@@ -650,6 +650,163 @@ describe('relationship', () => {
await expect(page.locator(tableRowLocator)).toHaveCount(1)
})
test('should be able to select relationship with drawer appearance', async () => {
await page.goto(url.create)
const relationshipField = page.locator('#field-relationshipDrawer')
await relationshipField.click()
const listDrawerContent = page.locator('.list-drawer').locator('.drawer__content')
await expect(listDrawerContent).toBeVisible()
const firstRow = listDrawerContent.locator('table tbody tr').first()
const button = firstRow.locator('button')
await button.click()
await expect(listDrawerContent).toBeHidden()
const selectedValue = relationshipField.locator('.relationship--single-value__text')
await expect(selectedValue).toBeVisible()
// Fill required field
await page.locator('#field-relationship').click()
await page.locator('.rs__option:has-text("Seeded text document")').click()
await saveDocAndAssert(page)
})
test('should be able to search within relationship list drawer', async () => {
await page.goto(url.create)
const relationshipField = page.locator('#field-relationshipDrawer')
await relationshipField.click()
const searchField = page.locator('.list-drawer .search-filter')
await expect(searchField).toBeVisible()
const searchInput = searchField.locator('input')
await searchInput.fill('seeded')
const rows = page.locator('.list-drawer table tbody tr')
await expect(rows).toHaveCount(1)
const closeButton = page.locator('.list-drawer__header-close')
await closeButton.click()
await expect(page.locator('.list-drawer')).toBeHidden()
})
test('should handle read-only relationship field when `appearance: "drawer"`', async () => {
await page.goto(url.create)
const readOnlyField = page.locator(
'#field-relationshipDrawerReadOnly .rs__control--is-disabled',
)
await expect(readOnlyField).toBeVisible()
})
test('should handle polymorphic relationship when `appearance: "drawer"`', async () => {
await page.goto(url.create)
const relationshipField = page.locator('#field-polymorphicRelationshipDrawer')
await relationshipField.click()
const listDrawerContent = page.locator('.list-drawer').locator('.drawer__content')
await expect(listDrawerContent).toBeVisible()
const relationToSelector = page.locator('.list-header__select-collection')
await expect(relationToSelector).toBeVisible()
await relationToSelector.locator('.rs__control').click()
const option = relationToSelector.locator('.rs__option').nth(1)
await option.click()
const firstRow = listDrawerContent.locator('table tbody tr').first()
const button = firstRow.locator('button')
await button.click()
await expect(listDrawerContent).toBeHidden()
const selectedValue = relationshipField.locator('.relationship--single-value__text')
await expect(selectedValue).toBeVisible()
// Fill required field
await page.locator('#field-relationship').click()
await page.locator('.rs__option:has-text("Seeded text document")').click()
await saveDocAndAssert(page)
})
test('should handle `hasMany` relationship when `appearance: "drawer"`', async () => {
await page.goto(url.create)
const relationshipField = page.locator('#field-relationshipDrawerHasMany')
await relationshipField.click()
const listDrawerContent = page.locator('.list-drawer').locator('.drawer__content')
await expect(listDrawerContent).toBeVisible()
const firstRow = listDrawerContent.locator('table tbody tr').first()
const button = firstRow.locator('button')
await button.click()
await expect(listDrawerContent).toBeHidden()
const selectedValue = relationshipField.locator('.relationship--multi-value-label__text')
await expect(selectedValue).toBeVisible()
})
test('should handle `hasMany` polymorphic relationship when `appearance: "drawer"`', async () => {
await page.goto(url.create)
const relationshipField = page.locator('#field-relationshipDrawerHasManyPolymorphic')
await relationshipField.click()
const listDrawerContent = page.locator('.list-drawer').locator('.drawer__content')
await expect(listDrawerContent).toBeVisible()
const firstRow = listDrawerContent.locator('table tbody tr').first()
const button = firstRow.locator('button')
await button.click()
await expect(listDrawerContent).toBeHidden()
const selectedValue = relationshipField.locator('.relationship--multi-value-label__text')
await expect(selectedValue).toBeVisible()
})
test('should not be allowed to create in relationship list drawer when `allowCreate` is `false`', async () => {
await page.goto(url.create)
const relationshipField = page.locator('#field-relationshipDrawerWithAllowCreateFalse')
await relationshipField.click()
const listDrawerContent = page.locator('.list-drawer').locator('.drawer__content')
await expect(listDrawerContent).toBeVisible()
const createNewButton = listDrawerContent.locator('list-drawer__create-new-button')
await expect(createNewButton).toBeHidden()
})
test('should respect `filterOptions` in the relationship list drawer for filtered relationship', async () => {
// Create test documents
await createTextFieldDoc({ text: 'list drawer test' })
await createTextFieldDoc({ text: 'not test' })
await page.goto(url.create)
const relationshipField = page.locator('#field-relationshipDrawerWithFilterOptions')
await relationshipField.click()
const listDrawerContent = page.locator('.list-drawer').locator('.drawer__content')
await expect(listDrawerContent).toBeVisible()
const rows = page.locator('.list-drawer table tbody tr')
await expect(rows).toHaveCount(1)
})
test('should filter out existing values from relationship list drawer', async () => {
await page.goto(url.create)
await page.locator('#field-relationshipDrawer').click()
const listDrawerContent = page.locator('.list-drawer').locator('.drawer__content')
await expect(listDrawerContent).toBeVisible()
const rows = listDrawerContent.locator('table tbody tr')
await expect(rows).toHaveCount(2)
await listDrawerContent.getByText('Seeded text document', { exact: true }).click()
const selectedValue = page.locator(
'#field-relationshipDrawer .relationship--single-value__text',
)
await expect(selectedValue).toHaveText('Seeded text document')
await page.locator('#field-relationshipDrawer').click()
const newRows = listDrawerContent.locator('table tbody tr')
await expect(newRows).toHaveCount(1)
await expect(listDrawerContent.getByText('Seeded text document')).toHaveCount(0)
})
})
async function createTextFieldDoc(overrides?: Partial<TextField>): Promise<TextField> {

View File

@@ -126,6 +126,71 @@ const RelationshipFields: CollectionConfig = {
type: 'relationship',
hasMany: true,
},
{
name: 'relationshipDrawer',
relationTo: 'text-fields',
admin: { appearance: 'drawer' },
type: 'relationship',
},
{
name: 'relationshipDrawerReadOnly',
relationTo: 'text-fields',
admin: {
readOnly: true,
appearance: 'drawer',
},
type: 'relationship',
},
{
name: 'polymorphicRelationshipDrawer',
admin: { appearance: 'drawer' },
type: 'relationship',
relationTo: ['text-fields', 'array-fields'],
},
{
name: 'relationshipDrawerHasMany',
relationTo: 'text-fields',
admin: {
appearance: 'drawer',
},
hasMany: true,
type: 'relationship',
},
{
name: 'relationshipDrawerHasManyPolymorphic',
relationTo: ['text-fields'],
admin: {
appearance: 'drawer',
},
hasMany: true,
type: 'relationship',
},
{
name: 'relationshipDrawerWithAllowCreateFalse',
admin: {
allowCreate: false,
appearance: 'drawer',
},
type: 'relationship',
relationTo: 'text-fields',
},
{
name: 'relationshipDrawerWithFilterOptions',
admin: { appearance: 'drawer' },
type: 'relationship',
relationTo: ['text-fields'],
filterOptions: ({ relationTo }) => {
if (relationTo === 'text-fields') {
return {
text: {
equals: 'list drawer test',
},
}
} else {
return true
}
},
},
],
slug: relationshipFieldsSlug,
}

View File

@@ -790,6 +790,7 @@ export interface ConditionalLogic {
text: string;
toggleField?: boolean | null;
fieldWithCondition?: string | null;
fieldWithOperationCondition?: string | null;
customFieldWithField?: string | null;
customFieldWithHOC?: string | null;
customClientFieldWithCondition?: string | null;
@@ -1312,6 +1313,29 @@ export interface RelationshipField {
| null;
relationToRow?: (string | null) | RowField;
relationToRowMany?: (string | RowField)[] | null;
relationshipDrawer?: (string | null) | TextField;
relationshipDrawerReadOnly?: (string | null) | TextField;
polymorphicRelationshipDrawer?:
| ({
relationTo: 'text-fields';
value: string | TextField;
} | null)
| ({
relationTo: 'array-fields';
value: string | ArrayField;
} | null);
relationshipDrawerHasMany?: (string | TextField)[] | null;
relationshipDrawerHasManyPolymorphic?:
| {
relationTo: 'text-fields';
value: string | TextField;
}[]
| null;
relationshipDrawerWithAllowCreateFalse?: (string | null) | TextField;
relationshipDrawerWithFilterOptions?: {
relationTo: 'text-fields';
value: string | TextField;
} | null;
updatedAt: string;
createdAt: string;
}
@@ -2341,6 +2365,7 @@ export interface ConditionalLogicSelect<T extends boolean = true> {
text?: T;
toggleField?: T;
fieldWithCondition?: T;
fieldWithOperationCondition?: T;
customFieldWithField?: T;
customFieldWithHOC?: T;
customClientFieldWithCondition?: T;
@@ -2786,6 +2811,13 @@ export interface RelationshipFieldsSelect<T extends boolean = true> {
relationshipWithMinRows?: T;
relationToRow?: T;
relationToRowMany?: T;
relationshipDrawer?: T;
relationshipDrawerReadOnly?: T;
polymorphicRelationshipDrawer?: T;
relationshipDrawerHasMany?: T;
relationshipDrawerHasManyPolymorphic?: T;
relationshipDrawerWithAllowCreateFalse?: T;
relationshipDrawerWithFilterOptions?: T;
updatedAt?: T;
createdAt?: T;
}