mirror of
https://github.com/xtr-dev/payload-automation.git
synced 2025-12-10 00:43:23 +00:00
Initial commit
This commit is contained in:
68
examples/README.md
Normal file
68
examples/README.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# PayloadCMS Workflows Plugin Examples
|
||||
|
||||
This directory contains example code demonstrating how to use the PayloadCMS Workflows plugin.
|
||||
|
||||
## Manual Trigger Example
|
||||
|
||||
The `manual-trigger-example.ts` file shows how to:
|
||||
- Create a workflow with a manual trigger button in the admin UI
|
||||
- Trigger workflows programmatically using custom triggers
|
||||
- Access trigger data in workflow steps using JSONPath
|
||||
|
||||
### Setting up a Manual Trigger Workflow
|
||||
|
||||
1. Configure the plugin with a custom trigger:
|
||||
```typescript
|
||||
workflowsPlugin({
|
||||
triggers: [
|
||||
{
|
||||
slug: 'manual-trigger',
|
||||
inputs: [] // No inputs needed for simple manual triggers
|
||||
}
|
||||
],
|
||||
// ... other config
|
||||
})
|
||||
```
|
||||
|
||||
2. Create a workflow with the manual trigger:
|
||||
```typescript
|
||||
await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'My Manual Workflow',
|
||||
triggers: [
|
||||
{
|
||||
type: 'manual-trigger'
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
// Your workflow steps here
|
||||
]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
3. The workflow will now have a "Trigger Workflow" button in the admin UI
|
||||
|
||||
### Triggering Workflows Programmatically
|
||||
|
||||
```typescript
|
||||
import { triggerCustomWorkflow } from '@xtr-dev/payload-automation'
|
||||
|
||||
// Trigger all workflows with 'manual-trigger'
|
||||
const results = await triggerCustomWorkflow(payload, {
|
||||
slug: 'manual-trigger',
|
||||
data: {
|
||||
// Custom data to pass to the workflow
|
||||
source: 'api',
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Accessing Trigger Data in Steps
|
||||
|
||||
Use JSONPath expressions to access trigger data in your workflow steps:
|
||||
- `$.trigger.data.source` - Access custom data fields
|
||||
- `$.trigger.type` - The trigger type
|
||||
- `$.trigger.triggeredAt` - When the trigger was activated
|
||||
274
examples/custom-trigger-example.ts
Normal file
274
examples/custom-trigger-example.ts
Normal file
@@ -0,0 +1,274 @@
|
||||
import { buildConfig } from 'payload'
|
||||
import { workflowsPlugin, triggerCustomWorkflow } from '@xtr-dev/payload-automation'
|
||||
import type { Field } from 'payload'
|
||||
|
||||
// Example: Data import trigger with custom fields
|
||||
const dataImportFields: Field[] = [
|
||||
{
|
||||
name: 'sourceUrl',
|
||||
type: 'text',
|
||||
required: true,
|
||||
admin: {
|
||||
description: 'URL of the data source to import from'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'format',
|
||||
type: 'select',
|
||||
options: ['json', 'csv', 'xml'],
|
||||
required: true,
|
||||
admin: {
|
||||
description: 'Format of the data to import'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'mapping',
|
||||
type: 'json',
|
||||
admin: {
|
||||
description: 'Field mapping configuration'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// Example: Manual review trigger with approval fields
|
||||
const manualReviewFields: Field[] = [
|
||||
{
|
||||
name: 'reviewerId',
|
||||
type: 'text',
|
||||
required: true,
|
||||
admin: {
|
||||
description: 'ID of the reviewer'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'reviewNotes',
|
||||
type: 'textarea',
|
||||
admin: {
|
||||
description: 'Notes from the review'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'approved',
|
||||
type: 'checkbox',
|
||||
defaultValue: false,
|
||||
admin: {
|
||||
description: 'Whether the item was approved'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
export default buildConfig({
|
||||
// ... other config
|
||||
|
||||
plugins: [
|
||||
workflowsPlugin({
|
||||
collectionTriggers: {
|
||||
posts: true, // Enable all CRUD triggers for posts
|
||||
products: { // Selective triggers for products
|
||||
create: true,
|
||||
update: true
|
||||
}
|
||||
},
|
||||
|
||||
// Define custom triggers that will appear in the workflow UI
|
||||
triggers: [
|
||||
{
|
||||
slug: 'data-import',
|
||||
inputs: dataImportFields
|
||||
},
|
||||
{
|
||||
slug: 'manual-review',
|
||||
inputs: manualReviewFields
|
||||
},
|
||||
{
|
||||
slug: 'scheduled-report',
|
||||
inputs: [
|
||||
{
|
||||
name: 'reportType',
|
||||
type: 'select',
|
||||
options: ['daily', 'weekly', 'monthly'],
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
steps: [
|
||||
// ... your workflow steps
|
||||
]
|
||||
})
|
||||
],
|
||||
|
||||
onInit: async (payload) => {
|
||||
// Example 1: Trigger workflow from external data source
|
||||
// This could be called from a webhook, scheduled job, or any other event
|
||||
const handleDataImport = async (sourceUrl: string, format: string) => {
|
||||
const results = await triggerCustomWorkflow(payload, {
|
||||
slug: 'data-import',
|
||||
data: {
|
||||
sourceUrl,
|
||||
format,
|
||||
mapping: {
|
||||
title: 'name',
|
||||
description: 'summary'
|
||||
},
|
||||
importedAt: new Date().toISOString()
|
||||
}
|
||||
})
|
||||
|
||||
console.log('Data import workflows triggered:', results)
|
||||
}
|
||||
|
||||
// Example 2: Trigger workflow after custom business logic
|
||||
const handleDocumentReview = async (documentId: string, reviewerId: string, approved: boolean) => {
|
||||
// Perform your custom review logic here
|
||||
const reviewData = {
|
||||
documentId,
|
||||
reviewerId,
|
||||
reviewNotes: approved ? 'Document meets all requirements' : 'Needs revision',
|
||||
approved,
|
||||
reviewedAt: new Date().toISOString()
|
||||
}
|
||||
|
||||
// Trigger workflows that listen for manual review
|
||||
const results = await triggerCustomWorkflow(payload, {
|
||||
slug: 'manual-review',
|
||||
data: reviewData,
|
||||
user: {
|
||||
id: reviewerId,
|
||||
email: 'reviewer@example.com'
|
||||
}
|
||||
})
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// Example 3: Integrate with external services
|
||||
// You could set up listeners for external events
|
||||
if (process.env.ENABLE_EXTERNAL_SYNC) {
|
||||
// Listen to external service events (example with a hypothetical event emitter)
|
||||
// externalService.on('data-ready', async (event) => {
|
||||
// await triggerCustomWorkflow(payload, {
|
||||
// slug: 'data-import',
|
||||
// data: event.data
|
||||
// })
|
||||
// })
|
||||
}
|
||||
|
||||
// Example 4: Create scheduled reports using node-cron or similar
|
||||
// This shows how you might trigger a custom workflow on a schedule
|
||||
// without using the built-in cron trigger
|
||||
const scheduleReports = async () => {
|
||||
// This could be called by a cron job or scheduled task
|
||||
await triggerCustomWorkflow(payload, {
|
||||
slug: 'scheduled-report',
|
||||
data: {
|
||||
reportType: 'daily',
|
||||
generatedAt: new Date().toISOString(),
|
||||
metrics: {
|
||||
totalUsers: 1000,
|
||||
activeUsers: 750,
|
||||
newSignups: 25
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Example 5: Hook into collection operations for complex logic
|
||||
const postsCollection = payload.collections.posts
|
||||
if (postsCollection) {
|
||||
postsCollection.config.hooks = postsCollection.config.hooks || {}
|
||||
postsCollection.config.hooks.afterChange = postsCollection.config.hooks.afterChange || []
|
||||
|
||||
postsCollection.config.hooks.afterChange.push(async ({ doc, operation, req }) => {
|
||||
// Custom logic to determine if we should trigger a workflow
|
||||
if (operation === 'create' && doc.status === 'published') {
|
||||
// Trigger a custom workflow for newly published posts
|
||||
await triggerCustomWorkflow(payload, {
|
||||
slug: 'manual-review',
|
||||
data: {
|
||||
documentId: doc.id,
|
||||
documentType: 'post',
|
||||
reviewerId: 'auto-review',
|
||||
reviewNotes: 'Automatically queued for review',
|
||||
approved: false
|
||||
},
|
||||
req // Pass the request context
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Make functions available globally for testing/debugging
|
||||
;(global as any).handleDataImport = handleDataImport
|
||||
;(global as any).handleDocumentReview = handleDocumentReview
|
||||
;(global as any).scheduleReports = scheduleReports
|
||||
}
|
||||
})
|
||||
|
||||
// Example workflow configuration that would use these custom triggers:
|
||||
/*
|
||||
{
|
||||
name: "Process Data Import",
|
||||
triggers: [{
|
||||
type: "data-import",
|
||||
sourceUrl: "https://api.example.com/data",
|
||||
format: "json",
|
||||
mapping: { ... }
|
||||
}],
|
||||
steps: [
|
||||
{
|
||||
step: "http-request",
|
||||
name: "fetch-data",
|
||||
input: {
|
||||
url: "$.trigger.data.sourceUrl",
|
||||
method: "GET"
|
||||
}
|
||||
},
|
||||
{
|
||||
step: "create-document",
|
||||
name: "import-records",
|
||||
input: {
|
||||
collection: "imported-data",
|
||||
data: "$.steps.fetch-data.output.body"
|
||||
},
|
||||
dependencies: ["fetch-data"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
name: "Review Approval Workflow",
|
||||
triggers: [{
|
||||
type: "manual-review",
|
||||
reviewerId: "",
|
||||
reviewNotes: "",
|
||||
approved: false
|
||||
}],
|
||||
steps: [
|
||||
{
|
||||
step: "update-document",
|
||||
name: "update-status",
|
||||
input: {
|
||||
collection: "documents",
|
||||
id: "$.trigger.data.documentId",
|
||||
data: {
|
||||
status: "$.trigger.data.approved ? 'approved' : 'rejected'",
|
||||
reviewedBy: "$.trigger.data.reviewerId",
|
||||
reviewedAt: "$.trigger.data.reviewedAt"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
step: "send-email",
|
||||
name: "notify-author",
|
||||
input: {
|
||||
to: "author@example.com",
|
||||
subject: "Document Review Complete",
|
||||
text: "Your document has been $.trigger.data.approved ? 'approved' : 'rejected'"
|
||||
},
|
||||
dependencies: ["update-status"]
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
122
examples/manual-trigger-example.ts
Normal file
122
examples/manual-trigger-example.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Example: Manual Trigger Workflow
|
||||
*
|
||||
* This example shows how to create a workflow that can be triggered
|
||||
* manually from the PayloadCMS admin interface using a custom button.
|
||||
*/
|
||||
|
||||
import type { Payload } from 'payload'
|
||||
|
||||
/**
|
||||
* Create a workflow with manual trigger
|
||||
*/
|
||||
export async function createManualTriggerWorkflow(payload: Payload) {
|
||||
const workflow = await payload.create({
|
||||
collection: 'workflows',
|
||||
data: {
|
||||
name: 'Manual Data Processing',
|
||||
description: 'A workflow that can be triggered manually from the admin UI',
|
||||
triggers: [
|
||||
{
|
||||
type: 'manual-trigger' // This enables the trigger button in the admin
|
||||
}
|
||||
],
|
||||
steps: [
|
||||
{
|
||||
name: 'fetch-data',
|
||||
type: 'http-request-step',
|
||||
input: {
|
||||
url: 'https://api.example.com/data',
|
||||
method: 'GET'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'process-data',
|
||||
type: 'create-document',
|
||||
input: {
|
||||
collection: 'auditLog',
|
||||
data: {
|
||||
message: 'Manual workflow executed',
|
||||
triggeredAt: '$.trigger.data.timestamp'
|
||||
}
|
||||
},
|
||||
dependencies: ['fetch-data'] // This step depends on fetch-data
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
console.log('Created workflow:', workflow.id)
|
||||
return workflow
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a workflow programmatically using the custom trigger
|
||||
*/
|
||||
export async function triggerWorkflowProgrammatically(payload: Payload) {
|
||||
// Import the trigger functions from the plugin
|
||||
const { triggerCustomWorkflow, triggerWorkflowById } = await import('@xtr-dev/payload-automation')
|
||||
|
||||
// Option 1: Trigger all workflows with a specific trigger slug
|
||||
const results = await triggerCustomWorkflow(payload, {
|
||||
slug: 'manual-trigger',
|
||||
data: {
|
||||
source: 'api',
|
||||
timestamp: new Date().toISOString(),
|
||||
user: 'system'
|
||||
}
|
||||
})
|
||||
|
||||
console.log('Triggered workflows:', results)
|
||||
|
||||
// Option 2: Trigger a specific workflow by ID
|
||||
const workflowId = 'your-workflow-id'
|
||||
const result = await triggerWorkflowById(
|
||||
payload,
|
||||
workflowId,
|
||||
'manual-trigger',
|
||||
{
|
||||
source: 'api',
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
)
|
||||
|
||||
console.log('Triggered workflow:', result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage in your application
|
||||
*/
|
||||
export async function setupManualTriggerExample(payload: Payload) {
|
||||
// Create the workflow
|
||||
const workflow = await createManualTriggerWorkflow(payload)
|
||||
|
||||
// The workflow is now available in the admin UI with a trigger button
|
||||
console.log('Workflow created! You can now:')
|
||||
console.log('1. Go to the admin UI and navigate to the Workflows collection')
|
||||
console.log('2. Open the workflow:', workflow.name)
|
||||
console.log('3. Click the "Trigger Workflow" button to execute it manually')
|
||||
|
||||
// You can also trigger it programmatically
|
||||
await triggerWorkflowProgrammatically(payload)
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
*
|
||||
* 1. The manual trigger button appears automatically in the workflow admin UI
|
||||
* when a workflow has a trigger with type 'manual-trigger'
|
||||
*
|
||||
* 2. You can have multiple triggers on the same workflow, including manual triggers
|
||||
*
|
||||
* 3. The trigger passes data to the workflow execution context, accessible via:
|
||||
* - $.trigger.data - The custom data passed when triggering
|
||||
* - $.trigger.type - The trigger type ('manual-trigger')
|
||||
* - $.trigger.triggeredAt - Timestamp of when the trigger was activated
|
||||
*
|
||||
* 4. Manual triggers are useful for:
|
||||
* - Administrative tasks
|
||||
* - Data migration workflows
|
||||
* - Testing and debugging
|
||||
* - On-demand processing
|
||||
*/
|
||||
Reference in New Issue
Block a user