Merge branch 'main' into fix/parent-labels-in-toast

This commit is contained in:
Jessica Chowdhury
2025-02-26 13:40:03 +00:00
216 changed files with 2854 additions and 1749 deletions

View File

@@ -3,6 +3,7 @@ import type { BrowserContext, Page } from '@playwright/test'
import { expect, test } from '@playwright/test'
import { addBlock } from 'helpers/e2e/addBlock.js'
import { openBlocksDrawer } from 'helpers/e2e/openBlocksDrawer.js'
import { reorderBlocks } from 'helpers/e2e/reorderBlocks.js'
import path from 'path'
import { fileURLToPath } from 'url'
@@ -289,6 +290,39 @@ describe('Block fields', () => {
})
describe('row manipulation', () => {
test('moving rows should immediately move custom row labels', async () => {
await page.goto(url.create)
// first ensure that the first block has the custom header, and that the second block doesn't
await expect(
page.locator('#field-blocks #blocks-row-0 .blocks-field__block-header'),
).toHaveText('Custom Block Label: Content 01')
const secondBlockHeader = page.locator(
'#field-blocks #blocks-row-1 .blocks-field__block-header',
)
await expect(secondBlockHeader.locator('.blocks-field__block-pill')).toHaveText('Number')
await expect(secondBlockHeader.locator('input[id="blocks.1.blockName"]')).toHaveValue(
'Second block',
)
await reorderBlocks({
page,
fieldName: 'blocks',
fromBlockIndex: 0,
toBlockIndex: 1,
})
// Important: do _not_ poll here, use `textContent()` instead of `toHaveText()`
// This will prevent Playwright from polling for the change to the DOM
expect(
await page.locator('#field-blocks #blocks-row-1 .blocks-field__block-header').textContent(),
).toMatch(/^Custom Block Label: Content/)
})
describe('react hooks', () => {
test('should add 2 new block rows', async () => {
await page.goto(url.create)

View File

@@ -0,0 +1,38 @@
'use client'
import { useField } from '@payloadcms/ui'
export function AfterField() {
const { setValue } = useField({ path: 'customJSON' })
return (
<button
id="set-custom-json"
onClick={(e) => {
e.preventDefault()
setValue({
users: [
{
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
isActive: true,
roles: ['admin', 'editor'],
},
{
id: 2,
name: 'Jane Smith',
email: 'jane.smith@example.com',
isActive: false,
roles: ['viewer'],
},
],
})
}}
style={{ marginTop: '5px', padding: '5px 10px' }}
type="button"
>
Set Custom JSON
</button>
)
}

View File

@@ -103,4 +103,24 @@ describe('JSON', () => {
'"foo.with.periods": "bar"',
)
})
test('should update', async () => {
const createdDoc = await payload.create({
collection: 'json-fields',
data: {
customJSON: {
default: 'value',
},
},
})
await page.goto(url.edit(createdDoc.id))
const jsonField = page.locator('.json-field #field-customJSON')
await expect(jsonField).toContainText('"default": "value"')
const originalHeight = (await page.locator('#field-customJSON').boundingBox())?.height || 0
await page.locator('#set-custom-json').click()
const newHeight = (await page.locator('#field-customJSON').boundingBox())?.height || 0
expect(newHeight).toBeGreaterThan(originalHeight)
})
})

View File

@@ -67,6 +67,16 @@ const JSON: CollectionConfig = {
},
],
},
{
name: 'customJSON',
type: 'json',
admin: {
components: {
afterInput: ['./collections/JSON/AfterField#AfterField'],
},
},
label: 'Custom Json',
},
],
versions: {
maxPerDoc: 1,

View File

@@ -170,12 +170,7 @@ describe('Text', () => {
user: client.user,
key: 'text-fields-list',
value: {
columns: [
{
accessor: 'disableListColumnText',
active: true,
},
],
columns: [{ disableListColumnText: true }],
},
})

View File

@@ -165,6 +165,68 @@ describe('Fields', () => {
expect(missResult).toBeFalsy()
})
it('should query like on value', async () => {
const miss = await payload.create({
collection: 'text-fields',
data: {
text: 'dog',
},
})
const hit = await payload.create({
collection: 'text-fields',
data: {
text: 'cat',
},
})
const { docs } = await payload.find({
collection: 'text-fields',
where: {
text: {
like: 'cat',
},
},
})
const hitResult = docs.find(({ id: findID }) => hit.id === findID)
const missResult = docs.find(({ id: findID }) => miss.id === findID)
expect(hitResult).toBeDefined()
expect(missResult).toBeFalsy()
})
it('should query not_like on value', async () => {
const hit = await payload.create({
collection: 'text-fields',
data: {
text: 'dog',
},
})
const miss = await payload.create({
collection: 'text-fields',
data: {
text: 'cat',
},
})
const { docs } = await payload.find({
collection: 'text-fields',
where: {
text: {
not_like: 'cat',
},
},
})
const hitResult = docs.find(({ id: findID }) => hit.id === findID)
const missResult = docs.find(({ id: findID }) => miss.id === findID)
expect(hitResult).toBeDefined()
expect(missResult).toBeFalsy()
})
it('should query hasMany within an array', async () => {
const docFirst = await payload.create({
collection: 'text-fields',
@@ -2713,6 +2775,20 @@ describe('Fields', () => {
expect(docIDs).not.toContain(bazBar.id)
})
it('should query nested properties - not_like', async () => {
const { docs } = await payload.find({
collection: 'json-fields',
where: {
'json.baz': { not_like: 'bar' },
},
})
const docIDs = docs.map(({ id }) => id)
expect(docIDs).toContain(fooBar.id)
expect(docIDs).not.toContain(bazBar.id)
})
it('should query nested properties - equals', async () => {
const { docs } = await payload.find({
collection: 'json-fields',

View File

@@ -1474,6 +1474,15 @@ export interface JsonField {
| boolean
| null;
};
customJSON?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
updatedAt: string;
createdAt: string;
}
@@ -3165,6 +3174,7 @@ export interface JsonFieldsSelect<T extends boolean = true> {
| {
jsonWithinGroup?: T;
};
customJSON?: T;
updatedAt?: T;
createdAt?: T;
}