feat: builds beforeDuplicate admin hook, closes #1243

This commit is contained in:
James
2022-10-12 11:44:41 -04:00
parent 5ca5abab42
commit 6f6f2f8e7b
5 changed files with 91 additions and 3 deletions

View File

@@ -62,6 +62,7 @@ You can customize the way that the Admin panel behaves on a collection-by-collec
| Option | Description |
| ---------------------------- | -------------|
| `group` | Text used as a label for grouping collection links together in the navigation. |
| `hooks` | Admin-specific hooks for this collection. [More](#admin-hooks) |
| `useAsTitle` | Specify a top-level field to use for a document title throughout the Admin panel. If no field is defined, the ID of the document is used as the title. |
| `description` | Text or React component to display below the Collection label in the List view to give editors more information. |
| `defaultColumns` | Array of field names that correspond to which columns to show by default in this collection's List view. |
@@ -131,6 +132,50 @@ For example, let's say you have a Posts collection with `title`, `metaDescriptio
If you are adding <strong>listSearchableFields</strong>, make sure you index each of these fields so your admin queries can remain performant.
</Banner>
### Admin Hooks
In addition to collection hooks themselves, Payload provides for admin UI-specific hooks that you can leverage.
**`beforeDuplicate`**
The `beforeDuplicate` hook is an async function that accepts an object containing the data to duplicate, as well as the locale of the doc to duplicate. Within this hook, you can modify the data to be duplicated, which is useful in cases where you have unique fields that need to be incremented or similar, as well as if you want to automatically modify a document's `title`.
Example:
```ts
import { BeforeDuplicate, CollectionConfig } from 'payload/types';
// Your auto-generated Page type
import { Page } from '../payload-types.ts';
const beforeDuplicate: BeforeDuplicate<Page> = ({ data }) => {
return {
...data,
title: `${data.title} Copy`,
uniqueField: data.uniqueField ? `${data.uniqueField}-copy` : '',
};
};
export const Page: CollectionConfig = {
slug: 'pages',
admin: {
hooks: {
beforeDuplicate,
}
},
fields: [
{
name: 'title',
type: 'text',
},
{
name: 'uniqueField',
type: 'text',
unique: true,
}
]
}
```
### TypeScript
You can import collection types as follows:

View File

@@ -37,7 +37,15 @@ const Duplicate: React.FC<Props> = ({ slug, collection, id }) => {
locale,
depth: 0,
});
const data = await response.json();
let data = await response.json();
if (typeof collection.admin.hooks?.beforeDuplicate === 'function') {
data = await collection.admin.hooks.beforeDuplicate({
data,
locale,
});
}
const result = await requests.post(`${serverURL}${api}/${slug}`, {
headers: {
'Content-Type': 'application/json',
@@ -97,7 +105,7 @@ const Duplicate: React.FC<Props> = ({ slug, collection, id }) => {
pathname: `${admin}/collections/${slug}/${duplicateID}`,
});
}, 10);
}, [modified, localization, collection.labels.singular, setModified, toggleModal, modalSlug, serverURL, api, slug, id, push, admin]);
}, [modified, localization, collection, setModified, toggleModal, modalSlug, serverURL, api, slug, id, push, admin]);
const confirm = useCallback(async () => {
setHasClicked(false);

View File

@@ -32,6 +32,9 @@ const collectionSchema = joi.object().keys({
joi.string(),
componentSchema,
),
hooks: joi.object({
beforeDuplicate: joi.func(),
}),
enableRichTextRelationship: joi.boolean(),
components: joi.object({
views: joi.object({

View File

@@ -143,6 +143,13 @@ export type AfterForgotPasswordHook = (args: {
args?: any;
}) => any;
type BeforeDuplicateArgs<T> = {
data: T
locale?: string
}
export type BeforeDuplicate<T = any> = (args: BeforeDuplicateArgs<T>) => T | Promise<T>
export type CollectionAdminOptions = {
/**
* Field to use as title in Edit view and first column in List view
@@ -156,6 +163,12 @@ export type CollectionAdminOptions = {
* Additional fields to be searched via the full text search
*/
listSearchableFields?: string[];
hooks?: {
/**
* Function that allows you to modify a document's data before it is duplicated
*/
beforeDuplicate?: BeforeDuplicate;
}
/**
* Place collections into a navigational group
* */

View File

@@ -1,7 +1,26 @@
import type { CollectionConfig } from '../../../../src/collections/config/types';
import type { BeforeDuplicate, CollectionConfig } from '../../../../src/collections/config/types';
import { IndexedField } from '../../payload-types';
const beforeDuplicate: BeforeDuplicate<IndexedField> = ({ data }) => {
return {
...data,
uniqueText: data.uniqueText ? `${data.uniqueText}-copy` : '',
group: {
...data.group || {},
localizedUnique: data.group?.localizedUnique ? `${data.group?.localizedUnique}-copy` : '',
},
collapsibleTextUnique: data.collapsibleTextUnique ? `${data.collapsibleTextUnique}-copy` : '',
collapsibleLocalizedUnique: data.collapsibleLocalizedUnique ? `${data.collapsibleLocalizedUnique}-copy` : '',
};
};
const IndexedFields: CollectionConfig = {
slug: 'indexed-fields',
admin: {
hooks: {
beforeDuplicate,
},
},
fields: [
{
name: 'text',