feat: add pre save/ post save hooks (#3812)
This commit is contained in:
parent
946f7a0dc4
commit
812716e18b
@ -226,8 +226,6 @@ export default class TestBackend implements Implementation {
|
|||||||
const unpubEntry = {
|
const unpubEntry = {
|
||||||
...unpubStore[existingEntryIndex],
|
...unpubStore[existingEntryIndex],
|
||||||
data: raw,
|
data: raw,
|
||||||
title: options.parsedData && options.parsedData.title,
|
|
||||||
description: options.parsedData && options.parsedData.description,
|
|
||||||
mediaFiles: assetProxies.map(this.normalizeAsset),
|
mediaFiles: assetProxies.map(this.normalizeAsset),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -242,8 +240,6 @@ export default class TestBackend implements Implementation {
|
|||||||
metaData: {
|
metaData: {
|
||||||
collection: options.collectionName as string,
|
collection: options.collectionName as string,
|
||||||
status: (options.status || this.options.initialWorkflowStatus) as string,
|
status: (options.status || this.options.initialWorkflowStatus) as string,
|
||||||
title: options.parsedData && options.parsedData.title,
|
|
||||||
description: options.parsedData && options.parsedData.description,
|
|
||||||
},
|
},
|
||||||
slug,
|
slug,
|
||||||
mediaFiles: assetProxies.map(this.normalizeAsset),
|
mediaFiles: assetProxies.map(this.normalizeAsset),
|
||||||
|
@ -702,18 +702,16 @@ export class Backend {
|
|||||||
async persistEntry({
|
async persistEntry({
|
||||||
config,
|
config,
|
||||||
collection,
|
collection,
|
||||||
entryDraft,
|
entryDraft: draft,
|
||||||
assetProxies,
|
assetProxies,
|
||||||
usedSlugs,
|
usedSlugs,
|
||||||
unpublished = false,
|
unpublished = false,
|
||||||
status,
|
status,
|
||||||
}: PersistArgs) {
|
}: PersistArgs) {
|
||||||
const newEntry = entryDraft.getIn(['entry', 'newRecord']) || false;
|
const modifiedData = await this.invokePreSaveEvent(draft.get('entry'));
|
||||||
|
const entryDraft = (modifiedData && draft.setIn(['entry', 'data'], modifiedData)) || draft;
|
||||||
|
|
||||||
const parsedData = {
|
const newEntry = entryDraft.getIn(['entry', 'newRecord']) || false;
|
||||||
title: entryDraft.getIn(['entry', 'data', 'title'], 'No Title') as string,
|
|
||||||
description: entryDraft.getIn(['entry', 'data', 'description'], 'No Description!') as string,
|
|
||||||
};
|
|
||||||
|
|
||||||
let entryObj: {
|
let entryObj: {
|
||||||
path: string;
|
path: string;
|
||||||
@ -782,7 +780,6 @@ export class Backend {
|
|||||||
const updatedOptions = { unpublished, status };
|
const updatedOptions = { unpublished, status };
|
||||||
const opts = {
|
const opts = {
|
||||||
newEntry,
|
newEntry,
|
||||||
parsedData,
|
|
||||||
commitMessage,
|
commitMessage,
|
||||||
collectionName,
|
collectionName,
|
||||||
useWorkflow,
|
useWorkflow,
|
||||||
@ -795,6 +792,8 @@ export class Backend {
|
|||||||
|
|
||||||
await this.implementation.persistEntry(entryObj, assetProxies, opts);
|
await this.implementation.persistEntry(entryObj, assetProxies, opts);
|
||||||
|
|
||||||
|
await this.invokePostSaveEvent(entryDraft.get('entry'));
|
||||||
|
|
||||||
if (!useWorkflow) {
|
if (!useWorkflow) {
|
||||||
await this.invokePostPublishEvent(entryDraft.get('entry'));
|
await this.invokePostPublishEvent(entryDraft.get('entry'));
|
||||||
}
|
}
|
||||||
@ -804,7 +803,7 @@ export class Backend {
|
|||||||
|
|
||||||
async invokeEventWithEntry(event: string, entry: EntryMap) {
|
async invokeEventWithEntry(event: string, entry: EntryMap) {
|
||||||
const { login, name } = (await this.currentUser()) as User;
|
const { login, name } = (await this.currentUser()) as User;
|
||||||
await invokeEvent({ name: event, data: { entry, author: { login, name } } });
|
return await invokeEvent({ name: event, data: { entry, author: { login, name } } });
|
||||||
}
|
}
|
||||||
|
|
||||||
async invokePrePublishEvent(entry: EntryMap) {
|
async invokePrePublishEvent(entry: EntryMap) {
|
||||||
@ -823,6 +822,14 @@ export class Backend {
|
|||||||
await this.invokeEventWithEntry('postUnpublish', entry);
|
await this.invokeEventWithEntry('postUnpublish', entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async invokePreSaveEvent(entry: EntryMap) {
|
||||||
|
return await this.invokeEventWithEntry('preSave', entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
async invokePostSaveEvent(entry: EntryMap) {
|
||||||
|
await this.invokeEventWithEntry('postSave', entry);
|
||||||
|
}
|
||||||
|
|
||||||
async persistMedia(config: Config, file: AssetProxy) {
|
async persistMedia(config: Config, file: AssetProxy) {
|
||||||
const user = (await this.currentUser()) as User;
|
const user = (await this.currentUser()) as User;
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -45,7 +45,14 @@ describe('registry', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('eventHandlers', () => {
|
describe('eventHandlers', () => {
|
||||||
const events = ['prePublish', 'postPublish', 'preUnpublish', 'postUnpublish'];
|
const events = [
|
||||||
|
'prePublish',
|
||||||
|
'postPublish',
|
||||||
|
'preUnpublish',
|
||||||
|
'postUnpublish',
|
||||||
|
'preSave',
|
||||||
|
'postSave',
|
||||||
|
];
|
||||||
|
|
||||||
describe('registerEventListener', () => {
|
describe('registerEventListener', () => {
|
||||||
it('should throw error on invalid event', () => {
|
it('should throw error on invalid event', () => {
|
||||||
|
@ -3,7 +3,14 @@ import produce from 'immer';
|
|||||||
import { oneLine } from 'common-tags';
|
import { oneLine } from 'common-tags';
|
||||||
import EditorComponent from 'ValueObjects/EditorComponent';
|
import EditorComponent from 'ValueObjects/EditorComponent';
|
||||||
|
|
||||||
const allowedEvents = ['prePublish', 'postPublish', 'preUnpublish', 'postUnpublish'];
|
const allowedEvents = [
|
||||||
|
'prePublish',
|
||||||
|
'postPublish',
|
||||||
|
'preUnpublish',
|
||||||
|
'postUnpublish',
|
||||||
|
'preSave',
|
||||||
|
'postSave',
|
||||||
|
];
|
||||||
const eventHandlers = {};
|
const eventHandlers = {};
|
||||||
allowedEvents.forEach(e => {
|
allowedEvents.forEach(e => {
|
||||||
eventHandlers[e] = [];
|
eventHandlers[e] = [];
|
||||||
@ -213,7 +220,7 @@ export async function invokeEvent({ name, data }) {
|
|||||||
const handlers = registry.eventHandlers[name];
|
const handlers = registry.eventHandlers[name];
|
||||||
for (const { handler, options } of handlers) {
|
for (const { handler, options } of handlers) {
|
||||||
try {
|
try {
|
||||||
await handler(data, options);
|
return await handler(data, options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(`Failed running handler for event ${name} with message: ${e.message}`);
|
console.warn(`Failed running handler for event ${name} with message: ${e.message}`);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,10 @@ export interface StaticallyTypedRecord<T> {
|
|||||||
keys: [K1, K2, K3],
|
keys: [K1, K2, K3],
|
||||||
defaultValue?: V,
|
defaultValue?: V,
|
||||||
): T[K1][K2][K3];
|
): T[K1][K2][K3];
|
||||||
|
setIn<K1 extends keyof T, K2 extends keyof T[K1], V extends T[K1][K2]>(
|
||||||
|
keys: [K1, K2],
|
||||||
|
value: V,
|
||||||
|
): StaticallyTypedRecord<T>;
|
||||||
toJS(): T;
|
toJS(): T;
|
||||||
isEmpty(): boolean;
|
isEmpty(): boolean;
|
||||||
some<K extends keyof T>(predicate: (value: T[K], key: K, iter: this) => boolean): boolean;
|
some<K extends keyof T>(predicate: (value: T[K], key: K, iter: this) => boolean): boolean;
|
||||||
|
@ -52,7 +52,6 @@ export type Entry = { path: string; slug: string; raw: string };
|
|||||||
|
|
||||||
export type PersistOptions = {
|
export type PersistOptions = {
|
||||||
newEntry?: boolean;
|
newEntry?: boolean;
|
||||||
parsedData?: { title: string; description: string };
|
|
||||||
commitMessage: string;
|
commitMessage: string;
|
||||||
collectionName?: string;
|
collectionName?: string;
|
||||||
useWorkflow?: boolean;
|
useWorkflow?: boolean;
|
||||||
|
@ -399,24 +399,18 @@ CMS.registerEventListener({
|
|||||||
name: 'prePublish',
|
name: 'prePublish',
|
||||||
handler: ({ author, entry }) => console.log(JSON.stringify({ author, data: entry.get('data') })),
|
handler: ({ author, entry }) => console.log(JSON.stringify({ author, data: entry.get('data') })),
|
||||||
});
|
});
|
||||||
|
|
||||||
CMS.registerEventListener({
|
|
||||||
name: 'postPublish',
|
|
||||||
handler: ({ author, entry }) => console.log(JSON.stringify({ author, data: entry.get('data') })),
|
|
||||||
});
|
|
||||||
|
|
||||||
CMS.registerEventListener({
|
|
||||||
name: 'preUnpublish',
|
|
||||||
handler: ({ author, entry }) => console.log(JSON.stringify({ author, data: entry.get('data') })),
|
|
||||||
});
|
|
||||||
|
|
||||||
CMS.registerEventListener({
|
|
||||||
name: 'postUnpublish',
|
|
||||||
handler: ({ author, entry }) => console.log(JSON.stringify({ author, data: entry.get('data') })),
|
|
||||||
});
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** Supported events are `prePublish`, `postPublish`, `preUnpublish` and `postUnpublish`.
|
Supported events are `prePublish`, `postPublish`, `preUnpublish`, `postUnpublish`, `preSave` and `postSave`. The `preSave` hook can be used to modify the entry data like so:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
CMS.registerEventListener({
|
||||||
|
name: 'preSave',
|
||||||
|
handler: ({ entry }) => {
|
||||||
|
return entry.get('data').set('title', 'new title');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## Dynamic Default Values
|
## Dynamic Default Values
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user