fix(ui): properly reflects hook changes in ui (#10268)
Fixes #9882 and #9691 In 2.0, we would accept data coming back from an update operation and then reflect those changes in UI. However, in 3.0, we did not do that anymore - meaning you could change a document with hooks in `beforeChange` or `afterChange`, but then not see the changes made on the server. This PR updates the way that `mergeServerFormState` works, and adds a property to optionally allow values from server form state - which can then be used in the `onSuccess` form handler which may need to define new field values.
This commit is contained in:
22
test/hooks/collections/BeforeChange/index.ts
Normal file
22
test/hooks/collections/BeforeChange/index.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const BeforeChangeHooks: CollectionConfig = {
|
||||
slug: 'before-change-hooks',
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
({ data }) => {
|
||||
data.title = 'hi from hook'
|
||||
|
||||
return data
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { APIError } from 'payload'
|
||||
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { AfterOperationCollection } from './collections/AfterOperation/index.js'
|
||||
import { BeforeChangeHooks } from './collections/BeforeChange/index.js'
|
||||
import { BeforeValidateCollection } from './collections/BeforeValidate/index.js'
|
||||
import ChainingHooks from './collections/ChainingHooks/index.js'
|
||||
import ContextHooks from './collections/ContextHooks/index.js'
|
||||
@@ -25,6 +26,7 @@ export const HooksConfig: Promise<SanitizedConfig> = buildConfigWithDefaults({
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
BeforeChangeHooks,
|
||||
BeforeValidateCollection,
|
||||
AfterOperationCollection,
|
||||
ContextHooks,
|
||||
|
||||
@@ -23,6 +23,7 @@ let payload: PayloadTestSDK<Config>
|
||||
|
||||
describe('Hooks', () => {
|
||||
let url: AdminUrlUtil
|
||||
let beforeChangeURL: AdminUrlUtil
|
||||
let page: Page
|
||||
let serverURL: string
|
||||
|
||||
@@ -31,6 +32,7 @@ describe('Hooks', () => {
|
||||
;({ payload, serverURL } = await initPayloadE2ENoConfig<Config>({ dirname }))
|
||||
|
||||
url = new AdminUrlUtil(serverURL, 'before-validate')
|
||||
beforeChangeURL = new AdminUrlUtil(serverURL, 'before-change-hooks')
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
@@ -58,6 +60,18 @@ describe('Hooks', () => {
|
||||
|
||||
await expect(page.locator('#field-title')).toHaveValue('reset in beforeValidate')
|
||||
})
|
||||
|
||||
test('should reflect changes made in beforeChange collection hooks within ui after save', async () => {
|
||||
await page.goto(beforeChangeURL.create)
|
||||
await page.locator('#field-title').fill('should replace value with before change response')
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
await expect(page.locator('#field-title')).toHaveValue('hi from hook')
|
||||
await page.locator('#field-title').fill('helllooooooooo')
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
await expect(page.locator('#field-title')).toHaveValue('hi from hook')
|
||||
})
|
||||
})
|
||||
|
||||
async function clearAllDocs(): Promise<void> {
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface Config {
|
||||
'hooks-users': HooksUserAuthOperations;
|
||||
};
|
||||
collections: {
|
||||
'before-change-hooks': BeforeChangeHook;
|
||||
'before-validate': BeforeValidate;
|
||||
afterOperation: AfterOperation;
|
||||
'context-hooks': ContextHook;
|
||||
@@ -27,6 +28,7 @@ export interface Config {
|
||||
};
|
||||
collectionsJoins: {};
|
||||
collectionsSelect: {
|
||||
'before-change-hooks': BeforeChangeHooksSelect<false> | BeforeChangeHooksSelect<true>;
|
||||
'before-validate': BeforeValidateSelect<false> | BeforeValidateSelect<true>;
|
||||
afterOperation: AfterOperationSelect<false> | AfterOperationSelect<true>;
|
||||
'context-hooks': ContextHooksSelect<false> | ContextHooksSelect<true>;
|
||||
@@ -77,6 +79,16 @@ export interface HooksUserAuthOperations {
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "before-change-hooks".
|
||||
*/
|
||||
export interface BeforeChangeHook {
|
||||
id: string;
|
||||
title: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "before-validate".
|
||||
@@ -231,6 +243,10 @@ export interface DataHook {
|
||||
export interface PayloadLockedDocument {
|
||||
id: string;
|
||||
document?:
|
||||
| ({
|
||||
relationTo: 'before-change-hooks';
|
||||
value: string | BeforeChangeHook;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'before-validate';
|
||||
value: string | BeforeValidate;
|
||||
@@ -313,6 +329,15 @@ export interface PayloadMigration {
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "before-change-hooks_select".
|
||||
*/
|
||||
export interface BeforeChangeHooksSelect<T extends boolean = true> {
|
||||
title?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "before-validate_select".
|
||||
|
||||
Reference in New Issue
Block a user