feat: improve cms event types (#769)
This commit is contained in:
parent
b967b61e51
commit
4444dd791c
@ -59,6 +59,7 @@ import type {
|
||||
Entry,
|
||||
EntryData,
|
||||
EntryDraft,
|
||||
EventData,
|
||||
FilterRule,
|
||||
ImplementationEntry,
|
||||
MediaField,
|
||||
@ -68,7 +69,6 @@ import type {
|
||||
UnknownField,
|
||||
User,
|
||||
} from './interface';
|
||||
import type { AllowedEvent } from './lib/registry';
|
||||
import type { AsyncLock } from './lib/util';
|
||||
import type { RootState } from './store';
|
||||
import type AssetProxy from './valueObjects/AssetProxy';
|
||||
@ -908,17 +908,19 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
|
||||
return slug;
|
||||
}
|
||||
|
||||
async invokeEventWithEntry(event: AllowedEvent, entry: Entry) {
|
||||
async getEventData(entry: Entry): Promise<EventData> {
|
||||
const { login, name = '' } = (await this.currentUser()) as User;
|
||||
return await invokeEvent({ name: event, data: { entry, author: { login, name } } });
|
||||
return { entry, author: { login, name } };
|
||||
}
|
||||
|
||||
async invokePreSaveEvent(entry: Entry) {
|
||||
return await this.invokeEventWithEntry('preSave', entry);
|
||||
async invokePreSaveEvent(entry: Entry): Promise<EntryData> {
|
||||
const eventData = await this.getEventData(entry);
|
||||
return await invokeEvent('preSave', eventData);
|
||||
}
|
||||
|
||||
async invokePostSaveEvent(entry: Entry) {
|
||||
await this.invokeEventWithEntry('postSave', entry);
|
||||
async invokePostSaveEvent(entry: Entry): Promise<void> {
|
||||
const eventData = await this.getEventData(entry);
|
||||
await invokeEvent('postSave', eventData);
|
||||
}
|
||||
|
||||
async persistMedia(config: Config, file: AssetProxy) {
|
||||
|
@ -232,7 +232,7 @@ const App = ({
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
invokeEvent({ name: 'mounted' });
|
||||
invokeEvent('mounted');
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
@ -825,16 +825,32 @@ export interface EventData {
|
||||
author: { login: string | undefined; name: string };
|
||||
}
|
||||
|
||||
export type EventListenerOptions = Record<string, unknown>;
|
||||
export type PreSaveEventHandler<O extends Record<string, unknown> = Record<string, unknown>> = (
|
||||
data: EventData,
|
||||
options: O,
|
||||
) => EntryData | undefined | null | void | Promise<EntryData | undefined | null | void>;
|
||||
|
||||
export type EventListenerHandler = (
|
||||
data: EventData | undefined,
|
||||
options: EventListenerOptions,
|
||||
) => Promise<EntryData | undefined | null | void>;
|
||||
export type PostSaveEventHandler<O extends Record<string, unknown> = Record<string, unknown>> = (
|
||||
data: EventData,
|
||||
options: O,
|
||||
) => void | Promise<void>;
|
||||
|
||||
export interface EventListener {
|
||||
name: AllowedEvent;
|
||||
handler: EventListenerHandler;
|
||||
export type MountedEventHandler<O extends Record<string, unknown> = Record<string, unknown>> = (
|
||||
options: O,
|
||||
) => void | Promise<void>;
|
||||
|
||||
export type EventHandlers<O extends Record<string, unknown> = Record<string, unknown>> = {
|
||||
preSave: PreSaveEventHandler<O>;
|
||||
postSave: PostSaveEventHandler<O>;
|
||||
mounted: MountedEventHandler<O>;
|
||||
};
|
||||
|
||||
export interface EventListener<
|
||||
E extends AllowedEvent = 'mounted',
|
||||
O extends Record<string, unknown> = Record<string, unknown>,
|
||||
> {
|
||||
name: E;
|
||||
handler: EventHandlers<O>[E];
|
||||
}
|
||||
|
||||
export interface AdditionalLinkOptions {
|
||||
|
@ -9,11 +9,15 @@ import type {
|
||||
Config,
|
||||
CustomIcon,
|
||||
Entry,
|
||||
EntryData,
|
||||
EventData,
|
||||
EventListener,
|
||||
FieldPreviewComponent,
|
||||
LocalePhrasesRoot,
|
||||
MountedEventHandler,
|
||||
ObjectValue,
|
||||
PostSaveEventHandler,
|
||||
PreSaveEventHandler,
|
||||
PreviewStyle,
|
||||
PreviewStyleOptions,
|
||||
ShortcodeConfig,
|
||||
@ -29,10 +33,16 @@ import type {
|
||||
export const allowedEvents = ['mounted', 'preSave', 'postSave'] as const;
|
||||
export type AllowedEvent = (typeof allowedEvents)[number];
|
||||
|
||||
type EventHandlerRegistry = {
|
||||
preSave: { handler: PreSaveEventHandler; options: Record<string, unknown> }[];
|
||||
postSave: { handler: PostSaveEventHandler; options: Record<string, unknown> }[];
|
||||
mounted: { handler: MountedEventHandler; options: Record<string, unknown> }[];
|
||||
};
|
||||
|
||||
const eventHandlers = allowedEvents.reduce((acc, e) => {
|
||||
acc[e] = [];
|
||||
return acc;
|
||||
}, {} as Record<AllowedEvent, { handler: EventListener['handler']; options: Record<string, unknown> }[]>);
|
||||
}, {} as EventHandlerRegistry);
|
||||
|
||||
interface Registry {
|
||||
backends: Record<string, BackendInitializer>;
|
||||
@ -44,7 +54,7 @@ interface Registry {
|
||||
additionalLinks: Record<string, AdditionalLink>;
|
||||
widgetValueSerializers: Record<string, WidgetValueSerializer>;
|
||||
locales: Record<string, LocalePhrasesRoot>;
|
||||
eventHandlers: typeof eventHandlers;
|
||||
eventHandlers: EventHandlerRegistry;
|
||||
previewStyles: PreviewStyle[];
|
||||
|
||||
/** Markdown editor */
|
||||
@ -309,9 +319,8 @@ export function getBackend<EF extends BaseField = UnknownField>(
|
||||
/**
|
||||
* Event Handlers
|
||||
*/
|
||||
function validateEventName(name: string) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if (!allowedEvents.includes(name as any)) {
|
||||
function validateEventName(name: AllowedEvent) {
|
||||
if (!allowedEvents.includes(name)) {
|
||||
throw new Error(`Invalid event name '${name}'`);
|
||||
}
|
||||
}
|
||||
@ -321,21 +330,48 @@ export function getEventListeners(name: AllowedEvent) {
|
||||
return [...registry.eventHandlers[name]];
|
||||
}
|
||||
|
||||
export function registerEventListener(
|
||||
{ name, handler }: EventListener,
|
||||
options: Record<string, unknown> = {},
|
||||
) {
|
||||
export function registerEventListener<
|
||||
E extends AllowedEvent,
|
||||
O extends Record<string, unknown> = Record<string, unknown>,
|
||||
>({ name, handler }: EventListener<E, O>, options?: O) {
|
||||
validateEventName(name);
|
||||
registry.eventHandlers[name].push({ handler, options });
|
||||
registry.eventHandlers[name].push({
|
||||
handler: handler as MountedEventHandler & PreSaveEventHandler & PostSaveEventHandler,
|
||||
options: options ?? {},
|
||||
});
|
||||
}
|
||||
|
||||
export async function invokeEvent({ name, data }: { name: AllowedEvent; data?: EventData }) {
|
||||
export async function invokeEvent(name: 'preSave', data: EventData): Promise<EntryData>;
|
||||
export async function invokeEvent(name: 'postSave', data: EventData): Promise<void>;
|
||||
export async function invokeEvent(name: 'mounted'): Promise<void>;
|
||||
export async function invokeEvent(name: AllowedEvent, data?: EventData): Promise<void | EntryData> {
|
||||
validateEventName(name);
|
||||
|
||||
if (name === 'mounted') {
|
||||
console.info('[StaticCMS] Firing mounted event');
|
||||
const handlers = registry.eventHandlers[name];
|
||||
for (const { handler, options } of handlers) {
|
||||
handler(options);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (name === 'postSave') {
|
||||
console.info(`[StaticCMS] Firing post save event`, data);
|
||||
const handlers = registry.eventHandlers[name];
|
||||
for (const { handler, options } of handlers) {
|
||||
handler(data!, options);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const handlers = registry.eventHandlers[name];
|
||||
|
||||
console.info(`[StaticCMS] Firing event ${name}`, data);
|
||||
console.info(`[StaticCMS] Firing pre save event`, data);
|
||||
|
||||
let _data = data ? { ...data } : undefined;
|
||||
let _data = { ...data! };
|
||||
for (const { handler, options } of handlers) {
|
||||
const result = await handler(_data, options);
|
||||
if (_data !== undefined && result !== undefined) {
|
||||
@ -346,7 +382,8 @@ export async function invokeEvent({ name, data }: { name: AllowedEvent; data?: E
|
||||
_data = { ..._data, entry };
|
||||
}
|
||||
}
|
||||
return _data?.entry.data;
|
||||
|
||||
return _data.entry.data;
|
||||
}
|
||||
|
||||
export function removeEventListener({ name, handler }: EventListener) {
|
||||
|
@ -17,6 +17,7 @@ For common options, see [Common widget options](/docs/widgets#common-widget-opti
|
||||
| Name | Type | Default | Description |
|
||||
| ---------------- | ------- | ------- | -------------------------------------------------------------------------------------- |
|
||||
| allow_regenerate | boolean | `true` | _Optional_. If set to `false` the `Generate new UUID` button does not appear in the UI |
|
||||
| prefix | string | | _Optional_. A value to add at the beginning of the UUID |
|
||||
|
||||
## Example
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user