feat: threads operation through field condition function (#12132)

This PR updates the field `condition` function property to include a new
`operation` argument.

The `operation` arg provides a string relating to which operation the
field type is currently executing within.

#### Changes:

- Added `operation: Operation` in the Condition type.
- Updated relevant condition checks to ensure correct parameter usage.
This commit is contained in:
Patrik
2025-04-16 15:38:53 -04:00
committed by GitHub
parent 4426625b83
commit c877b1ad43
8 changed files with 46 additions and 2 deletions

View File

@@ -541,6 +541,7 @@ The `ctx` object:
| Property | Description | | Property | Description |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`blockData`** | The nearest parent block's data. If the field is not inside a block, this will be `undefined`. | | **`blockData`** | The nearest parent block's data. If the field is not inside a block, this will be `undefined`. |
| **`operation`** | A string relating to which operation the field type is currently executing within. |
| **`path`** | The full path to the field in the schema, represented as an array of string segments, including array indexes. I.e `['group', 'myArray', '1', 'textField']`. | | **`path`** | The full path to the field in the schema, represented as an array of string segments, including array indexes. I.e `['group', 'myArray', '1', 'textField']`. |
| **`user`** | The currently authenticated user object. | | **`user`** | The currently authenticated user object. |

View File

@@ -269,6 +269,7 @@ export type Condition<TData extends TypeWithID = any, TSiblingData = any> = (
siblingData: Partial<TSiblingData>, siblingData: Partial<TSiblingData>,
{ {
blockData, blockData,
operation,
path, path,
user, user,
}: { }: {
@@ -276,6 +277,10 @@ export type Condition<TData extends TypeWithID = any, TSiblingData = any> = (
* The data of the nearest parent block. If the field is not within a block, `blockData` will be equal to `undefined`. * The data of the nearest parent block. If the field is not within a block, `blockData` will be equal to `undefined`.
*/ */
blockData: Partial<TData> blockData: Partial<TData>
/**
* A string relating to which operation the field type is currently executing within.
*/
operation: Operation
/** /**
* The path of the field, e.g. ["group", "myArray", 1, "textField"]. The path is the schemaPath but with indexes and would be used in the context of field data, not field schemas. * The path of the field, e.g. ["group", "myArray", 1, "textField"]. The path is the schemaPath but with indexes and would be used in the context of field data, not field schemas.
*/ */

View File

@@ -109,7 +109,12 @@ export const promise = async ({
const passesCondition = field.admin?.condition const passesCondition = field.admin?.condition
? Boolean( ? Boolean(
field.admin.condition(data, siblingData, { blockData, path: pathSegments, user: req.user }), field.admin.condition(data, siblingData, {
blockData,
operation,
path: pathSegments,
user: req.user,
}),
) )
: true : true
let skipValidationFromHere = skipValidation || !passesCondition let skipValidationFromHere = skipValidation || !passesCondition

View File

@@ -827,6 +827,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
if (passesCondition && typeof tab.admin?.condition === 'function') { if (passesCondition && typeof tab.admin?.condition === 'function') {
tabPassesCondition = tab.admin.condition(fullData, data, { tabPassesCondition = tab.admin.condition(fullData, data, {
blockData, blockData,
operation,
path: pathSegments, path: pathSegments,
user: req.user, user: req.user,
}) })

View File

@@ -151,6 +151,7 @@ export const iterateFields = async ({
? Boolean( ? Boolean(
field.admin.condition(fullData || {}, data || {}, { field.admin.condition(fullData || {}, data || {}, {
blockData, blockData,
operation,
path: pathSegments, path: pathSegments,
user: req.user, user: req.user,
}), }),

View File

@@ -10,6 +10,7 @@ import type { Config } from '../../payload-types.js'
import { import {
ensureCompilationIsDone, ensureCompilationIsDone,
initPageConsoleErrorCatch, initPageConsoleErrorCatch,
saveDocAndAssert,
// throttleTest, // throttleTest,
} from '../../../helpers.js' } from '../../../helpers.js'
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js' import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
@@ -225,4 +226,19 @@ describe('Conditional Logic', () => {
await expect(numberField).toBeVisible() 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), condition: ({ toggleField }) => Boolean(toggleField),
}, },
}, },
{
name: 'fieldWithOperationCondition',
type: 'text',
admin: {
condition: (data, siblingData, { operation }) => {
if (operation === 'create') {
return true
}
return false
},
},
},
{ {
name: 'customFieldWithField', name: 'customFieldWithField',
type: 'text', type: 'text',
@@ -217,7 +230,7 @@ const ConditionalLogic: CollectionConfig = {
name: 'numberField', name: 'numberField',
type: 'number', type: 'number',
admin: { admin: {
condition: (data, siblingData, { path, user }) => { condition: (data, siblingData, { path }) => {
// Ensure path has enough depth // Ensure path has enough depth
if (path.length < 5) { if (path.length < 5) {
return false return false

View File

@@ -790,6 +790,7 @@ export interface ConditionalLogic {
text: string; text: string;
toggleField?: boolean | null; toggleField?: boolean | null;
fieldWithCondition?: string | null; fieldWithCondition?: string | null;
fieldWithOperationCondition?: string | null;
customFieldWithField?: string | null; customFieldWithField?: string | null;
customFieldWithHOC?: string | null; customFieldWithHOC?: string | null;
customClientFieldWithCondition?: string | null; customClientFieldWithCondition?: string | null;
@@ -2364,6 +2365,7 @@ export interface ConditionalLogicSelect<T extends boolean = true> {
text?: T; text?: T;
toggleField?: T; toggleField?: T;
fieldWithCondition?: T; fieldWithCondition?: T;
fieldWithOperationCondition?: T;
customFieldWithField?: T; customFieldWithField?: T;
customFieldWithHOC?: T; customFieldWithHOC?: T;
customClientFieldWithCondition?: T; customClientFieldWithCondition?: T;