mirror of
https://github.com/xtr-dev/payload-automation.git
synced 2025-12-10 00:43:23 +00:00
Implement triggerField helper across all trigger modules
- Standardize virtual field creation using triggerField helper - Simplify field definitions by removing repetitive virtual field boilerplate - Use consistent naming pattern: '__trigger_' + fieldName instead of '__builtin_' - Preserve existing field conditions while adding parameter storage logic - Update all trigger field modules to use Field type consistently
This commit is contained in:
@@ -1,62 +1,27 @@
|
|||||||
import type {Field} from 'payload'
|
import type {Field} from 'payload'
|
||||||
|
|
||||||
import type { WorkflowsPluginConfig } from '../plugin/config-types.js'
|
import type { WorkflowsPluginConfig } from '../plugin/config-types.js'
|
||||||
|
|
||||||
|
import {triggerField} from "./helpers.js"
|
||||||
|
|
||||||
export function getCollectionTriggerFields<T extends string>(
|
export function getCollectionTriggerFields<T extends string>(
|
||||||
collectionTriggers: WorkflowsPluginConfig<T>['collectionTriggers']
|
collectionTriggers: WorkflowsPluginConfig<T>['collectionTriggers']
|
||||||
): Field[] {
|
): Field[] {
|
||||||
return [
|
return [
|
||||||
{
|
triggerField({
|
||||||
name: '__builtin_collectionSlug',
|
name: 'collectionSlug',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
admin: {
|
|
||||||
condition: (_, siblingData) => siblingData?.type === 'collection-trigger',
|
|
||||||
description: 'Collection that triggers the workflow',
|
|
||||||
},
|
|
||||||
hooks: {
|
|
||||||
afterRead: [
|
|
||||||
({ siblingData }) => {
|
|
||||||
return siblingData?.parameters?.collectionSlug || undefined
|
|
||||||
}
|
|
||||||
],
|
|
||||||
beforeChange: [
|
|
||||||
({ siblingData, value }) => {
|
|
||||||
if (!siblingData.parameters) {siblingData.parameters = {}}
|
|
||||||
siblingData.parameters.collectionSlug = value
|
|
||||||
return undefined // Virtual field, don't store directly
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: Object.keys(collectionTriggers || {}),
|
options: Object.keys(collectionTriggers || {}),
|
||||||
virtual: true,
|
}),
|
||||||
},
|
triggerField({
|
||||||
{
|
name: 'operation',
|
||||||
name: '__builtin_operation',
|
|
||||||
type: 'select',
|
type: 'select',
|
||||||
admin: {
|
|
||||||
condition: (_, siblingData) => siblingData?.type === 'collection-trigger',
|
|
||||||
description: 'Collection operation that triggers the workflow',
|
|
||||||
},
|
|
||||||
hooks: {
|
|
||||||
afterRead: [
|
|
||||||
({ siblingData }) => {
|
|
||||||
return siblingData?.parameters?.operation || undefined
|
|
||||||
}
|
|
||||||
],
|
|
||||||
beforeChange: [
|
|
||||||
({ siblingData, value }) => {
|
|
||||||
if (!siblingData.parameters) {siblingData.parameters = {}}
|
|
||||||
siblingData.parameters.operation = value
|
|
||||||
return undefined // Virtual field, don't store directly
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: [
|
options: [
|
||||||
'create',
|
'create',
|
||||||
'delete',
|
'delete',
|
||||||
'read',
|
'read',
|
||||||
'update',
|
'update',
|
||||||
],
|
],
|
||||||
virtual: true,
|
})
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,17 @@
|
|||||||
import type {Field} from 'payload'
|
import type {Field} from 'payload'
|
||||||
|
|
||||||
|
import {triggerField} from "./helpers.js"
|
||||||
|
|
||||||
export function getCronTriggerFields(): Field[] {
|
export function getCronTriggerFields(): Field[] {
|
||||||
return [
|
return [
|
||||||
{
|
triggerField({
|
||||||
name: '__builtin_cronExpression',
|
name: 'cronExpression',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) => siblingData?.type === 'cron-trigger',
|
condition: (_, siblingData) => siblingData?.type === 'cron-trigger',
|
||||||
description: 'Cron expression for scheduled execution (e.g., "0 0 * * *" for daily at midnight)',
|
description: 'Cron expression for scheduled execution (e.g., "0 0 * * *" for daily at midnight)',
|
||||||
placeholder: '0 0 * * *'
|
placeholder: '0 0 * * *'
|
||||||
},
|
},
|
||||||
hooks: {
|
|
||||||
afterRead: [
|
|
||||||
({ siblingData }) => {
|
|
||||||
return siblingData?.parameters?.cronExpression || undefined
|
|
||||||
}
|
|
||||||
],
|
|
||||||
beforeChange: [
|
|
||||||
({ siblingData, value }) => {
|
|
||||||
if (!siblingData.parameters) {siblingData.parameters = {}}
|
|
||||||
siblingData.parameters.cronExpression = value
|
|
||||||
return undefined // Virtual field, don't store directly
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
validate: (value: any, {siblingData}: any) => {
|
validate: (value: any, {siblingData}: any) => {
|
||||||
const cronValue = value || siblingData?.parameters?.cronExpression
|
const cronValue = value || siblingData?.parameters?.cronExpression
|
||||||
if (siblingData?.type === 'cron-trigger' && !cronValue) {
|
if (siblingData?.type === 'cron-trigger' && !cronValue) {
|
||||||
@@ -44,10 +32,9 @@ export function getCronTriggerFields(): Field[] {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
virtual: true,
|
}),
|
||||||
},
|
triggerField({
|
||||||
{
|
name: 'timezone',
|
||||||
name: '__builtin_timezone',
|
|
||||||
type: 'text',
|
type: 'text',
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) => siblingData?.type === 'cron-trigger',
|
condition: (_, siblingData) => siblingData?.type === 'cron-trigger',
|
||||||
@@ -55,20 +42,6 @@ export function getCronTriggerFields(): Field[] {
|
|||||||
placeholder: 'UTC'
|
placeholder: 'UTC'
|
||||||
},
|
},
|
||||||
defaultValue: 'UTC',
|
defaultValue: 'UTC',
|
||||||
hooks: {
|
|
||||||
afterRead: [
|
|
||||||
({ siblingData }) => {
|
|
||||||
return siblingData?.parameters?.timezone || 'UTC'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
beforeChange: [
|
|
||||||
({ siblingData, value }) => {
|
|
||||||
if (!siblingData.parameters) {siblingData.parameters = {}}
|
|
||||||
siblingData.parameters.timezone = value || 'UTC'
|
|
||||||
return undefined // Virtual field, don't store directly
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
validate: (value: any, {siblingData}: any) => {
|
validate: (value: any, {siblingData}: any) => {
|
||||||
const tzValue = value || siblingData?.parameters?.timezone
|
const tzValue = value || siblingData?.parameters?.timezone
|
||||||
if (siblingData?.type === 'cron-trigger' && tzValue) {
|
if (siblingData?.type === 'cron-trigger' && tzValue) {
|
||||||
@@ -82,7 +55,6 @@ export function getCronTriggerFields(): Field[] {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
virtual: true,
|
})
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,56 +1,28 @@
|
|||||||
import type {Field} from 'payload'
|
import type {Field} from 'payload'
|
||||||
|
|
||||||
|
import {triggerField} from "./helpers.js"
|
||||||
|
|
||||||
export function getGlobalTriggerFields(): Field[] {
|
export function getGlobalTriggerFields(): Field[] {
|
||||||
return [
|
return [
|
||||||
{
|
triggerField({
|
||||||
name: '__builtin_global',
|
name: 'global',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) => siblingData?.type === 'global-trigger',
|
condition: (_, siblingData) => siblingData?.type === 'global-trigger',
|
||||||
description: 'Global that triggers the workflow',
|
description: 'Global that triggers the workflow',
|
||||||
},
|
},
|
||||||
hooks: {
|
|
||||||
afterRead: [
|
|
||||||
({ siblingData }) => {
|
|
||||||
return siblingData?.parameters?.global || undefined
|
|
||||||
}
|
|
||||||
],
|
|
||||||
beforeChange: [
|
|
||||||
({ siblingData, value }) => {
|
|
||||||
if (!siblingData.parameters) {siblingData.parameters = {}}
|
|
||||||
siblingData.parameters.global = value
|
|
||||||
return undefined // Virtual field, don't store directly
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: [], // Will be populated dynamically based on available globals
|
options: [], // Will be populated dynamically based on available globals
|
||||||
virtual: true,
|
}),
|
||||||
},
|
triggerField({
|
||||||
{
|
name: 'globalOperation',
|
||||||
name: '__builtin_globalOperation',
|
|
||||||
type: 'select',
|
type: 'select',
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) => siblingData?.type === 'global-trigger',
|
condition: (_, siblingData) => siblingData?.type === 'global-trigger',
|
||||||
description: 'Global operation that triggers the workflow',
|
description: 'Global operation that triggers the workflow',
|
||||||
},
|
},
|
||||||
hooks: {
|
|
||||||
afterRead: [
|
|
||||||
({ siblingData }) => {
|
|
||||||
return siblingData?.parameters?.globalOperation || undefined
|
|
||||||
}
|
|
||||||
],
|
|
||||||
beforeChange: [
|
|
||||||
({ siblingData, value }) => {
|
|
||||||
if (!siblingData.parameters) {siblingData.parameters = {}}
|
|
||||||
siblingData.parameters.globalOperation = value
|
|
||||||
return undefined // Virtual field, don't store directly
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: [
|
options: [
|
||||||
'update'
|
'update'
|
||||||
],
|
],
|
||||||
virtual: true,
|
})
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import type {Field, TextField, SelectField} from "payload"
|
||||||
|
|
||||||
|
import type {Trigger} from "./types.js"
|
||||||
|
|
||||||
|
type FieldWithName = TextField | SelectField | (Field & { name: string })
|
||||||
|
|
||||||
|
type Options = {
|
||||||
|
slug: string,
|
||||||
|
fields?: FieldWithName[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const trigger = ({
|
||||||
|
slug,
|
||||||
|
fields
|
||||||
|
}: Options): Trigger => {
|
||||||
|
return {
|
||||||
|
slug,
|
||||||
|
fields: (fields || []).map(triggerField) as Field[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const triggerField = (field: FieldWithName): Field => ({
|
||||||
|
...field,
|
||||||
|
name: '__trigger_' + field.name,
|
||||||
|
admin: {
|
||||||
|
...(field.admin as any || {}),
|
||||||
|
condition: (_, siblingData, __) => {
|
||||||
|
const previous = field.admin?.condition?.call(null, _, siblingData, __)
|
||||||
|
return previous !== false // Preserve existing condition if it exists
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
afterRead: [
|
||||||
|
({ siblingData }) => {
|
||||||
|
const parameters = siblingData?.parameters || {}
|
||||||
|
return parameters[field.name]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
beforeChange: [
|
||||||
|
({ siblingData, value }) => {
|
||||||
|
if (!siblingData.parameters) {
|
||||||
|
siblingData.parameters = {}
|
||||||
|
}
|
||||||
|
siblingData.parameters[field.name] = value
|
||||||
|
return undefined // Virtual field, don't store directly
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
virtual: true,
|
||||||
|
} as Field)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import type {Field} from "payload"
|
||||||
|
|
||||||
|
export type Trigger = {
|
||||||
|
slug: string
|
||||||
|
fields: Field[]
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,35 +1,22 @@
|
|||||||
import type {Field} from 'payload'
|
import type {Field} from 'payload'
|
||||||
|
|
||||||
|
import {triggerField} from "./helpers.js"
|
||||||
|
|
||||||
export function getWebhookTriggerFields(): Field[] {
|
export function getWebhookTriggerFields(): Field[] {
|
||||||
return [
|
return [
|
||||||
{
|
triggerField({
|
||||||
name: '__builtin_webhookPath',
|
name: 'webhookPath',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
admin: {
|
admin: {
|
||||||
condition: (_, siblingData) => siblingData?.type === 'webhook-trigger',
|
condition: (_, siblingData) => siblingData?.type === 'webhook-trigger',
|
||||||
description: 'URL path for the webhook (e.g., "my-webhook"). Full URL will be /api/workflows-webhook/my-webhook',
|
description: 'URL path for the webhook (e.g., "my-webhook"). Full URL will be /api/workflows-webhook/my-webhook',
|
||||||
},
|
},
|
||||||
hooks: {
|
|
||||||
afterRead: [
|
|
||||||
({ siblingData }) => {
|
|
||||||
return siblingData?.parameters?.webhookPath || undefined
|
|
||||||
}
|
|
||||||
],
|
|
||||||
beforeChange: [
|
|
||||||
({ siblingData, value }) => {
|
|
||||||
if (!siblingData.parameters) {siblingData.parameters = {}}
|
|
||||||
siblingData.parameters.webhookPath = value
|
|
||||||
return undefined // Virtual field, don't store directly
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
validate: (value: any, {siblingData}: any) => {
|
validate: (value: any, {siblingData}: any) => {
|
||||||
if (siblingData?.type === 'webhook-trigger' && !value && !siblingData?.parameters?.webhookPath) {
|
if (siblingData?.type === 'webhook-trigger' && !value && !siblingData?.parameters?.webhookPath) {
|
||||||
return 'Webhook path is required for webhook triggers'
|
return 'Webhook path is required for webhook triggers'
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
virtual: true,
|
})
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user