@xtr-dev/payload-automation 0.0.38 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -10
- package/dist/collections/Workflow.js +2 -4
- package/dist/collections/Workflow.js.map +1 -1
- package/dist/components/WorkflowBuilder/StepConfigurationForm.js +316 -0
- package/dist/components/WorkflowBuilder/StepConfigurationForm.js.map +1 -0
- package/dist/components/WorkflowBuilder/WorkflowBuilder.js +211 -0
- package/dist/components/WorkflowBuilder/WorkflowBuilder.js.map +1 -0
- package/dist/components/WorkflowBuilder/WorkflowToolbar.js +107 -0
- package/dist/components/WorkflowBuilder/WorkflowToolbar.js.map +1 -0
- package/dist/components/WorkflowBuilder/index.js +6 -0
- package/dist/components/WorkflowBuilder/index.js.map +1 -0
- package/dist/components/WorkflowBuilder/nodes/StepNode.js +139 -0
- package/dist/components/WorkflowBuilder/nodes/StepNode.js.map +1 -0
- package/dist/core/workflow-executor.js +150 -116
- package/dist/core/workflow-executor.js.map +1 -1
- package/dist/fields/WorkflowBuilderField.js +119 -0
- package/dist/fields/WorkflowBuilderField.js.map +1 -0
- package/dist/plugin/collection-hook.js +34 -0
- package/dist/plugin/collection-hook.js.map +1 -1
- package/package.json +4 -3
- package/dist/collections/Workflow.d.ts +0 -3
- package/dist/collections/WorkflowRuns.d.ts +0 -2
- package/dist/components/ErrorDisplay.d.ts +0 -9
- package/dist/components/StatusCell.d.ts +0 -6
- package/dist/core/trigger-custom-workflow.d.ts +0 -52
- package/dist/core/workflow-executor.d.ts +0 -90
- package/dist/exports/client.d.ts +0 -2
- package/dist/exports/fields.d.ts +0 -1
- package/dist/exports/rsc.d.ts +0 -1
- package/dist/exports/server.d.ts +0 -5
- package/dist/exports/views.d.ts +0 -1
- package/dist/fields/parameter.d.ts +0 -4
- package/dist/index.d.ts +0 -2
- package/dist/plugin/collection-hook.d.ts +0 -1
- package/dist/plugin/config-types.d.ts +0 -18
- package/dist/plugin/global-hook.d.ts +0 -1
- package/dist/plugin/index.d.ts +0 -4
- package/dist/plugin/logger.d.ts +0 -20
- package/dist/steps/create-document-handler.d.ts +0 -2
- package/dist/steps/create-document.d.ts +0 -46
- package/dist/steps/delete-document-handler.d.ts +0 -2
- package/dist/steps/delete-document.d.ts +0 -39
- package/dist/steps/http-request-handler.d.ts +0 -2
- package/dist/steps/http-request.d.ts +0 -155
- package/dist/steps/index.d.ts +0 -12
- package/dist/steps/read-document-handler.d.ts +0 -2
- package/dist/steps/read-document.d.ts +0 -46
- package/dist/steps/send-email-handler.d.ts +0 -2
- package/dist/steps/send-email.d.ts +0 -44
- package/dist/steps/update-document-handler.d.ts +0 -2
- package/dist/steps/update-document.d.ts +0 -46
- package/dist/test/basic.test.js +0 -14
- package/dist/test/basic.test.js.map +0 -1
- package/dist/test/create-document-step.test.js +0 -378
- package/dist/test/create-document-step.test.js.map +0 -1
- package/dist/test/http-request-step.test.js +0 -361
- package/dist/test/http-request-step.test.js.map +0 -1
- package/dist/test/workflow-executor.test.js +0 -530
- package/dist/test/workflow-executor.test.js.map +0 -1
- package/dist/triggers/collection-trigger.d.ts +0 -2
- package/dist/triggers/global-trigger.d.ts +0 -2
- package/dist/triggers/index.d.ts +0 -2
- package/dist/triggers/types.d.ts +0 -5
- package/dist/types/index.d.ts +0 -31
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ A comprehensive workflow automation plugin for PayloadCMS 3.x that enables visua
|
|
|
12
12
|
- ⏰ **Scheduled Workflows** - Use webhook triggers with external cron services
|
|
13
13
|
- 📊 **Execution Tracking** - Complete history and monitoring of workflow runs
|
|
14
14
|
- 🔧 **Extensible Steps** - HTTP requests, document CRUD, email notifications
|
|
15
|
-
-
|
|
15
|
+
- 🔧 **Handlebars Templates** - Dynamic data interpolation with automatic type conversion
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
@@ -56,7 +56,10 @@ The plugin uses separate exports to avoid bundling server-side code in client bu
|
|
|
56
56
|
import { workflowsPlugin } from '@xtr-dev/payload-automation/server'
|
|
57
57
|
|
|
58
58
|
// Client-side components
|
|
59
|
-
import {
|
|
59
|
+
import { StatusCell, ErrorDisplay } from '@xtr-dev/payload-automation/client'
|
|
60
|
+
|
|
61
|
+
// Helper utilities
|
|
62
|
+
import { /* helpers */ } from '@xtr-dev/payload-automation/helpers'
|
|
60
63
|
|
|
61
64
|
// Types only (safe for both server and client)
|
|
62
65
|
import type { WorkflowsPluginConfig } from '@xtr-dev/payload-automation'
|
|
@@ -71,7 +74,7 @@ Make external API calls with comprehensive error handling and retry logic.
|
|
|
71
74
|
- Support for GET, POST, PUT, DELETE, PATCH methods
|
|
72
75
|
- Authentication: Bearer token, Basic auth, API key headers
|
|
73
76
|
- Configurable timeouts and retry logic
|
|
74
|
-
-
|
|
77
|
+
- Handlebars templates for dynamic URLs and request bodies
|
|
75
78
|
|
|
76
79
|
**Error Handling:**
|
|
77
80
|
HTTP Request steps use a **response-based success model** rather than status-code-based failures:
|
|
@@ -92,7 +95,7 @@ HTTP Request steps use a **response-based success model** rather than status-cod
|
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
// Use in workflow conditions:
|
|
95
|
-
// "
|
|
98
|
+
// "{{steps.apiRequest.output.status}} >= 400" to handle errors
|
|
96
99
|
```
|
|
97
100
|
|
|
98
101
|
This design allows workflows to handle HTTP errors gracefully rather than failing completely, enabling robust error handling and retry logic.
|
|
@@ -129,8 +132,8 @@ For network failures (timeouts, DNS errors, connection failures), the plugin pro
|
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
// Access in workflow conditions:
|
|
132
|
-
// "
|
|
133
|
-
// "
|
|
135
|
+
// "{{steps.httpStep.errorDetails.errorType}} == 'timeout'"
|
|
136
|
+
// "{{steps.httpStep.errorDetails.duration}} > 5000"
|
|
134
137
|
```
|
|
135
138
|
|
|
136
139
|
### Document Operations
|
|
@@ -144,11 +147,39 @@ For network failures (timeouts, DNS errors, connection failures), the plugin pro
|
|
|
144
147
|
|
|
145
148
|
## Data Resolution
|
|
146
149
|
|
|
147
|
-
Use
|
|
150
|
+
Use Handlebars templates to access workflow data:
|
|
151
|
+
|
|
152
|
+
- `{{trigger.doc.id}}` - Access trigger document
|
|
153
|
+
- `{{steps.stepName.output}}` - Use previous step outputs
|
|
154
|
+
- `{{context}}` - Access workflow context
|
|
155
|
+
|
|
156
|
+
### Template Examples
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"url": "https://api.example.com/posts/{{steps.createPost.output.id}}",
|
|
161
|
+
"message": "Post {{trigger.doc.title}} was updated by {{trigger.req.user.email}}",
|
|
162
|
+
"timeout": "{{steps.configStep.output.timeoutMs}}"
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Automatic Type Conversion
|
|
148
167
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
-
|
|
168
|
+
Handlebars templates automatically convert string results to appropriate types based on field names:
|
|
169
|
+
|
|
170
|
+
- **Numbers**: `timeout`, `retries`, `delay`, `port`, `count`, etc. → converted to numbers
|
|
171
|
+
- **Booleans**: `enabled`, `active`, `success`, `complete`, etc. → converted to booleans
|
|
172
|
+
- **Numeric strings**: `"5000"` → `5000`, `"3.14"` → `3.14`
|
|
173
|
+
|
|
174
|
+
### Conditions
|
|
175
|
+
|
|
176
|
+
Conditions support Handlebars templates with comparison operators:
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"condition": "{{trigger.doc.status}} == 'published'"
|
|
181
|
+
}
|
|
182
|
+
```
|
|
152
183
|
|
|
153
184
|
## Requirements
|
|
154
185
|
|
|
@@ -216,6 +247,8 @@ export default async function handler(req, res) {
|
|
|
216
247
|
|
|
217
248
|
**Benefits**: Better reliability, proper process isolation, easier debugging, and leverages existing infrastructure.
|
|
218
249
|
|
|
250
|
+
**Note**: Built-in cron triggers have been removed in v0.0.37+ to focus on webhook-based scheduling which provides better reliability and debugging capabilities.
|
|
251
|
+
|
|
219
252
|
## Documentation
|
|
220
253
|
|
|
221
254
|
Full documentation coming soon. For now, explore the development environment in the repository for examples and patterns.
|
|
@@ -82,15 +82,13 @@ export const createWorkflowCollection = (options)=>{
|
|
|
82
82
|
options: steps.map((t)=>t.slug)
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
|
-
name: '
|
|
85
|
+
name: 'input',
|
|
86
86
|
type: 'json',
|
|
87
87
|
admin: {
|
|
88
|
-
|
|
88
|
+
description: 'Step input configuration. Use JSONPath expressions to reference dynamic data (e.g., {"url": "$.trigger.doc.webhookUrl", "data": "$.steps.previousStep.output.result"})'
|
|
89
89
|
},
|
|
90
90
|
defaultValue: {}
|
|
91
91
|
},
|
|
92
|
-
// Virtual fields for custom triggers
|
|
93
|
-
...steps.flatMap((step)=>(step.inputSchema || []).map((s)=>parameter(step.slug, s))),
|
|
94
92
|
{
|
|
95
93
|
name: 'dependencies',
|
|
96
94
|
type: 'text',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/collections/Workflow.ts"],"sourcesContent":["import type {CollectionConfig} from 'payload'\n\nimport type {WorkflowsPluginConfig} from \"../plugin/config-types.js\"\n\nimport {parameter} from \"../fields/parameter.js\"\nimport {collectionTrigger, globalTrigger} from \"../triggers/index.js\"\n\nexport const createWorkflowCollection: <T extends string>(options: WorkflowsPluginConfig<T>) => CollectionConfig = (options) => {\n const steps = options.steps || []\n const triggers = (options.triggers || []).map(t => t(options)).concat(collectionTrigger(options), globalTrigger(options))\n return {\n slug: 'workflows',\n access: {\n create: () => true,\n delete: () => true,\n read: () => true,\n update: () => true,\n },\n admin: {\n defaultColumns: ['name', 'updatedAt'],\n description: 'Create and manage automated workflows.',\n group: 'Automation',\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n admin: {\n description: 'Human-readable name for the workflow',\n },\n required: true,\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'Optional description of what this workflow does',\n },\n },\n {\n name: 'triggers',\n type: 'array',\n fields: [\n {\n name: 'type',\n type: 'select',\n options: [\n ...triggers.map(t => t.slug)\n ]\n },\n {\n name: 'parameters',\n type: 'json',\n admin: {\n hidden: true,\n },\n defaultValue: {}\n },\n // Virtual fields for custom triggers\n ...triggers.flatMap(t => (t.parameters || []).map(p => parameter(t.slug, p as any))),\n {\n name: 'condition',\n type: 'text',\n admin: {\n description: 'JSONPath expression that must evaluate to true for this trigger to execute the workflow (e.g., \"$.trigger.doc.status == \\'published\\'\")'\n },\n required: false\n },\n ]\n },\n {\n name: 'steps',\n type: 'array',\n fields: [\n {\n name: 'name',\n type: 'text',\n defaultValue: 'Unnamed Step'\n },\n {\n name: 'type',\n type: 'select',\n options: steps.map(t => t.slug)\n },\n {\n name: '
|
|
1
|
+
{"version":3,"sources":["../../src/collections/Workflow.ts"],"sourcesContent":["import type {CollectionConfig} from 'payload'\n\nimport type {WorkflowsPluginConfig} from \"../plugin/config-types.js\"\n\nimport {parameter} from \"../fields/parameter.js\"\nimport {collectionTrigger, globalTrigger} from \"../triggers/index.js\"\n\nexport const createWorkflowCollection: <T extends string>(options: WorkflowsPluginConfig<T>) => CollectionConfig = (options) => {\n const steps = options.steps || []\n const triggers = (options.triggers || []).map(t => t(options)).concat(collectionTrigger(options), globalTrigger(options))\n return {\n slug: 'workflows',\n access: {\n create: () => true,\n delete: () => true,\n read: () => true,\n update: () => true,\n },\n admin: {\n defaultColumns: ['name', 'updatedAt'],\n description: 'Create and manage automated workflows.',\n group: 'Automation',\n useAsTitle: 'name',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n admin: {\n description: 'Human-readable name for the workflow',\n },\n required: true,\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'Optional description of what this workflow does',\n },\n },\n {\n name: 'triggers',\n type: 'array',\n fields: [\n {\n name: 'type',\n type: 'select',\n options: [\n ...triggers.map(t => t.slug)\n ]\n },\n {\n name: 'parameters',\n type: 'json',\n admin: {\n hidden: true,\n },\n defaultValue: {}\n },\n // Virtual fields for custom triggers\n ...triggers.flatMap(t => (t.parameters || []).map(p => parameter(t.slug, p as any))),\n {\n name: 'condition',\n type: 'text',\n admin: {\n description: 'JSONPath expression that must evaluate to true for this trigger to execute the workflow (e.g., \"$.trigger.doc.status == \\'published\\'\")'\n },\n required: false\n },\n ]\n },\n {\n name: 'steps',\n type: 'array',\n fields: [\n {\n name: 'name',\n type: 'text',\n defaultValue: 'Unnamed Step'\n },\n {\n name: 'type',\n type: 'select',\n options: steps.map(t => t.slug)\n },\n {\n name: 'input',\n type: 'json',\n admin: {\n description: 'Step input configuration. Use JSONPath expressions to reference dynamic data (e.g., {\"url\": \"$.trigger.doc.webhookUrl\", \"data\": \"$.steps.previousStep.output.result\"})'\n },\n defaultValue: {}\n },\n {\n name: 'dependencies',\n type: 'text',\n admin: {\n description: 'Step names that must complete before this step can run'\n },\n hasMany: true,\n required: false\n },\n {\n name: 'condition',\n type: 'text',\n admin: {\n description: 'JSONPath expression that must evaluate to true for this step to execute (e.g., \"$.trigger.doc.status == \\'published\\'\")'\n },\n required: false\n },\n ],\n }\n ],\n versions: {\n drafts: {\n autosave: false,\n },\n maxPerDoc: 10,\n },\n }\n}\n"],"names":["parameter","collectionTrigger","globalTrigger","createWorkflowCollection","options","steps","triggers","map","t","concat","slug","access","create","delete","read","update","admin","defaultColumns","description","group","useAsTitle","fields","name","type","required","hidden","defaultValue","flatMap","parameters","p","hasMany","versions","drafts","autosave","maxPerDoc"],"mappings":"AAIA,SAAQA,SAAS,QAAO,yBAAwB;AAChD,SAAQC,iBAAiB,EAAEC,aAAa,QAAO,uBAAsB;AAErE,OAAO,MAAMC,2BAAsG,CAACC;IAClH,MAAMC,QAAQD,QAAQC,KAAK,IAAI,EAAE;IACjC,MAAMC,WAAW,AAACF,CAAAA,QAAQE,QAAQ,IAAI,EAAE,AAAD,EAAGC,GAAG,CAACC,CAAAA,IAAKA,EAAEJ,UAAUK,MAAM,CAACR,kBAAkBG,UAAUF,cAAcE;IAChH,OAAO;QACLM,MAAM;QACNC,QAAQ;YACNC,QAAQ,IAAM;YACdC,QAAQ,IAAM;YACdC,MAAM,IAAM;YACZC,QAAQ,IAAM;QAChB;QACAC,OAAO;YACLC,gBAAgB;gBAAC;gBAAQ;aAAY;YACrCC,aAAa;YACbC,OAAO;YACPC,YAAY;QACd;QACAC,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;gBACf;gBACAM,UAAU;YACZ;YACA;gBACEF,MAAM;gBACNC,MAAM;gBACNP,OAAO;oBACLE,aAAa;gBACf;YACF;YACA;gBACEI,MAAM;gBACNC,MAAM;gBACNF,QAAQ;oBACN;wBACEC,MAAM;wBACNC,MAAM;wBACNnB,SAAS;+BACJE,SAASC,GAAG,CAACC,CAAAA,IAAKA,EAAEE,IAAI;yBAC5B;oBACH;oBACA;wBACEY,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLS,QAAQ;wBACV;wBACAC,cAAc,CAAC;oBACjB;oBACA,qCAAqC;uBAClCpB,SAASqB,OAAO,CAACnB,CAAAA,IAAK,AAACA,CAAAA,EAAEoB,UAAU,IAAI,EAAE,AAAD,EAAGrB,GAAG,CAACsB,CAAAA,IAAK7B,UAAUQ,EAAEE,IAAI,EAAEmB;oBACzE;wBACEP,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAM,UAAU;oBACZ;iBACD;YACH;YACA;gBACEF,MAAM;gBACNC,MAAM;gBACNF,QAAQ;oBACN;wBACEC,MAAM;wBACNC,MAAM;wBACNG,cAAc;oBAChB;oBACA;wBACEJ,MAAM;wBACNC,MAAM;wBACNnB,SAASC,MAAME,GAAG,CAACC,CAAAA,IAAKA,EAAEE,IAAI;oBAChC;oBACA;wBACEY,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAQ,cAAc,CAAC;oBACjB;oBACA;wBACEJ,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAY,SAAS;wBACTN,UAAU;oBACZ;oBACA;wBACEF,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAM,UAAU;oBACZ;iBACD;YACH;SACD;QACDO,UAAU;YACRC,QAAQ;gBACNC,UAAU;YACZ;YACAC,WAAW;QACb;IACF;AACF,EAAC"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React, { useState, useCallback, useEffect } from 'react';
|
|
4
|
+
import { Button } from '@payloadcms/ui';
|
|
5
|
+
export const StepConfigurationForm = ({ selectedNode, availableStepTypes, availableSteps, onNodeUpdate, onClose })=>{
|
|
6
|
+
const [formData, setFormData] = useState(selectedNode?.data.configuration || {});
|
|
7
|
+
const [jsonText, setJsonText] = useState(()=>JSON.stringify(selectedNode?.data.configuration || {}, null, 2));
|
|
8
|
+
if (!selectedNode) return null;
|
|
9
|
+
const stepType = availableStepTypes.find((type)=>type.slug === selectedNode.data.stepType);
|
|
10
|
+
const inputSchema = stepType?.inputSchema || [];
|
|
11
|
+
// Update form data when selected node changes
|
|
12
|
+
useEffect(()=>{
|
|
13
|
+
const config = selectedNode?.data.configuration || {};
|
|
14
|
+
setFormData(config);
|
|
15
|
+
setJsonText(JSON.stringify(config, null, 2));
|
|
16
|
+
}, [
|
|
17
|
+
selectedNode
|
|
18
|
+
]);
|
|
19
|
+
const handleSave = useCallback(()=>{
|
|
20
|
+
// Update the node with form data
|
|
21
|
+
onNodeUpdate(selectedNode.id, {
|
|
22
|
+
...selectedNode.data,
|
|
23
|
+
configuration: formData
|
|
24
|
+
});
|
|
25
|
+
onClose();
|
|
26
|
+
}, [
|
|
27
|
+
selectedNode,
|
|
28
|
+
formData,
|
|
29
|
+
onNodeUpdate,
|
|
30
|
+
onClose
|
|
31
|
+
]);
|
|
32
|
+
const renderStepConfiguration = ()=>{
|
|
33
|
+
if (!inputSchema.length) {
|
|
34
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
35
|
+
style: {
|
|
36
|
+
padding: '20px',
|
|
37
|
+
textAlign: 'center',
|
|
38
|
+
color: 'var(--theme-text-400)',
|
|
39
|
+
fontStyle: 'italic'
|
|
40
|
+
},
|
|
41
|
+
children: "This step type has no configuration parameters."
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
45
|
+
style: {
|
|
46
|
+
marginBottom: '16px'
|
|
47
|
+
},
|
|
48
|
+
children: [
|
|
49
|
+
/*#__PURE__*/ _jsx("label", {
|
|
50
|
+
style: {
|
|
51
|
+
display: 'block',
|
|
52
|
+
marginBottom: '4px',
|
|
53
|
+
fontSize: '12px',
|
|
54
|
+
fontWeight: '500',
|
|
55
|
+
color: 'var(--theme-text)'
|
|
56
|
+
},
|
|
57
|
+
children: "Step Configuration"
|
|
58
|
+
}),
|
|
59
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
60
|
+
style: {
|
|
61
|
+
fontSize: '11px',
|
|
62
|
+
color: 'var(--theme-text-400)',
|
|
63
|
+
marginBottom: '8px'
|
|
64
|
+
},
|
|
65
|
+
children: [
|
|
66
|
+
"Configure this step's parameters in JSON format. Use JSONPath expressions like ",
|
|
67
|
+
/*#__PURE__*/ _jsx("code", {
|
|
68
|
+
children: "$.trigger.doc.id"
|
|
69
|
+
}),
|
|
70
|
+
" to reference dynamic data."
|
|
71
|
+
]
|
|
72
|
+
}),
|
|
73
|
+
/*#__PURE__*/ _jsxs("details", {
|
|
74
|
+
style: {
|
|
75
|
+
marginBottom: '12px'
|
|
76
|
+
},
|
|
77
|
+
children: [
|
|
78
|
+
/*#__PURE__*/ _jsx("summary", {
|
|
79
|
+
style: {
|
|
80
|
+
fontSize: '11px',
|
|
81
|
+
color: 'var(--theme-text-400)',
|
|
82
|
+
cursor: 'pointer',
|
|
83
|
+
marginBottom: '8px'
|
|
84
|
+
},
|
|
85
|
+
children: "📖 Available Fields (click to expand)"
|
|
86
|
+
}),
|
|
87
|
+
/*#__PURE__*/ _jsx("div", {
|
|
88
|
+
style: {
|
|
89
|
+
background: 'var(--theme-elevation-50)',
|
|
90
|
+
border: '1px solid var(--theme-elevation-100)',
|
|
91
|
+
borderRadius: '4px',
|
|
92
|
+
padding: '12px',
|
|
93
|
+
fontSize: '11px',
|
|
94
|
+
fontFamily: 'monospace'
|
|
95
|
+
},
|
|
96
|
+
children: inputSchema.map((field, index)=>/*#__PURE__*/ _jsxs("div", {
|
|
97
|
+
style: {
|
|
98
|
+
marginBottom: index < inputSchema.length - 1 ? '8px' : '0'
|
|
99
|
+
},
|
|
100
|
+
children: [
|
|
101
|
+
/*#__PURE__*/ _jsx("strong", {
|
|
102
|
+
children: field.name
|
|
103
|
+
}),
|
|
104
|
+
" (",
|
|
105
|
+
field.type,
|
|
106
|
+
")",
|
|
107
|
+
field.required && /*#__PURE__*/ _jsx("span", {
|
|
108
|
+
style: {
|
|
109
|
+
color: 'var(--theme-error-500)'
|
|
110
|
+
},
|
|
111
|
+
children: " *required"
|
|
112
|
+
}),
|
|
113
|
+
field.admin?.description && /*#__PURE__*/ _jsx("div", {
|
|
114
|
+
style: {
|
|
115
|
+
color: 'var(--theme-text-400)',
|
|
116
|
+
marginTop: '2px'
|
|
117
|
+
},
|
|
118
|
+
children: field.admin.description
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
}, field.name))
|
|
122
|
+
})
|
|
123
|
+
]
|
|
124
|
+
}),
|
|
125
|
+
/*#__PURE__*/ _jsx("textarea", {
|
|
126
|
+
value: jsonText,
|
|
127
|
+
onChange: (e)=>{
|
|
128
|
+
const text = e.target.value;
|
|
129
|
+
setJsonText(text);
|
|
130
|
+
try {
|
|
131
|
+
const parsed = JSON.parse(text);
|
|
132
|
+
setFormData(parsed);
|
|
133
|
+
} catch {
|
|
134
|
+
// Keep invalid JSON, user is still typing
|
|
135
|
+
// Don't update formData until JSON is valid
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
rows: Math.min(Math.max(inputSchema.length * 2, 6), 15),
|
|
139
|
+
style: {
|
|
140
|
+
width: '100%',
|
|
141
|
+
padding: '12px',
|
|
142
|
+
border: '1px solid var(--theme-elevation-100)',
|
|
143
|
+
borderRadius: '4px',
|
|
144
|
+
fontSize: '13px',
|
|
145
|
+
fontFamily: 'monospace',
|
|
146
|
+
lineHeight: '1.4',
|
|
147
|
+
background: 'var(--theme-input-bg)',
|
|
148
|
+
color: 'var(--theme-text)',
|
|
149
|
+
resize: 'vertical'
|
|
150
|
+
},
|
|
151
|
+
placeholder: '{\\n "field1": "value1",\\n "field2": "$.trigger.doc.id"\\n}'
|
|
152
|
+
})
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
157
|
+
style: {
|
|
158
|
+
height: '100%',
|
|
159
|
+
width: '100%',
|
|
160
|
+
display: 'flex',
|
|
161
|
+
flexDirection: 'column',
|
|
162
|
+
overflow: 'hidden'
|
|
163
|
+
},
|
|
164
|
+
children: [
|
|
165
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
166
|
+
style: {
|
|
167
|
+
padding: '16px',
|
|
168
|
+
borderBottom: '1px solid var(--theme-elevation-100)',
|
|
169
|
+
background: 'var(--theme-elevation-50)'
|
|
170
|
+
},
|
|
171
|
+
children: [
|
|
172
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
173
|
+
style: {
|
|
174
|
+
display: 'flex',
|
|
175
|
+
justifyContent: 'space-between',
|
|
176
|
+
alignItems: 'center'
|
|
177
|
+
},
|
|
178
|
+
children: [
|
|
179
|
+
/*#__PURE__*/ _jsx("h4", {
|
|
180
|
+
style: {
|
|
181
|
+
margin: 0,
|
|
182
|
+
fontSize: '16px',
|
|
183
|
+
fontWeight: '600',
|
|
184
|
+
color: 'var(--theme-text)'
|
|
185
|
+
},
|
|
186
|
+
children: "Configure Step"
|
|
187
|
+
}),
|
|
188
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
189
|
+
buttonStyle: "none",
|
|
190
|
+
onClick: onClose,
|
|
191
|
+
size: "small",
|
|
192
|
+
children: "×"
|
|
193
|
+
})
|
|
194
|
+
]
|
|
195
|
+
}),
|
|
196
|
+
/*#__PURE__*/ _jsx("div", {
|
|
197
|
+
style: {
|
|
198
|
+
fontSize: '12px',
|
|
199
|
+
color: 'var(--theme-text-400)',
|
|
200
|
+
marginTop: '4px'
|
|
201
|
+
},
|
|
202
|
+
children: stepType?.label || selectedNode.data.stepType
|
|
203
|
+
})
|
|
204
|
+
]
|
|
205
|
+
}),
|
|
206
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
207
|
+
style: {
|
|
208
|
+
flex: 1,
|
|
209
|
+
overflow: 'auto',
|
|
210
|
+
padding: '16px'
|
|
211
|
+
},
|
|
212
|
+
children: [
|
|
213
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
214
|
+
style: {
|
|
215
|
+
marginBottom: '16px'
|
|
216
|
+
},
|
|
217
|
+
children: [
|
|
218
|
+
/*#__PURE__*/ _jsx("label", {
|
|
219
|
+
style: {
|
|
220
|
+
display: 'block',
|
|
221
|
+
marginBottom: '4px',
|
|
222
|
+
fontSize: '12px',
|
|
223
|
+
fontWeight: '500'
|
|
224
|
+
},
|
|
225
|
+
children: "Step Name *"
|
|
226
|
+
}),
|
|
227
|
+
/*#__PURE__*/ _jsx("input", {
|
|
228
|
+
type: "text",
|
|
229
|
+
value: selectedNode.data.label || '',
|
|
230
|
+
onChange: (e)=>onNodeUpdate(selectedNode.id, {
|
|
231
|
+
...selectedNode.data,
|
|
232
|
+
label: e.target.value
|
|
233
|
+
}),
|
|
234
|
+
style: {
|
|
235
|
+
width: '100%',
|
|
236
|
+
padding: '8px',
|
|
237
|
+
border: '1px solid var(--theme-elevation-100)',
|
|
238
|
+
borderRadius: '4px',
|
|
239
|
+
fontSize: '14px'
|
|
240
|
+
},
|
|
241
|
+
required: true
|
|
242
|
+
})
|
|
243
|
+
]
|
|
244
|
+
}),
|
|
245
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
246
|
+
style: {
|
|
247
|
+
marginBottom: '16px'
|
|
248
|
+
},
|
|
249
|
+
children: [
|
|
250
|
+
/*#__PURE__*/ _jsx("label", {
|
|
251
|
+
style: {
|
|
252
|
+
display: 'block',
|
|
253
|
+
marginBottom: '4px',
|
|
254
|
+
fontSize: '12px',
|
|
255
|
+
fontWeight: '500'
|
|
256
|
+
},
|
|
257
|
+
children: "Dependencies"
|
|
258
|
+
}),
|
|
259
|
+
/*#__PURE__*/ _jsx("div", {
|
|
260
|
+
style: {
|
|
261
|
+
fontSize: '11px',
|
|
262
|
+
color: 'var(--theme-text-400)',
|
|
263
|
+
marginBottom: '8px'
|
|
264
|
+
},
|
|
265
|
+
children: "Steps that must complete before this step can run"
|
|
266
|
+
}),
|
|
267
|
+
availableSteps.filter((step)=>step !== selectedNode.id).map((stepId)=>/*#__PURE__*/ _jsxs("label", {
|
|
268
|
+
style: {
|
|
269
|
+
display: 'block',
|
|
270
|
+
fontSize: '12px',
|
|
271
|
+
marginBottom: '4px'
|
|
272
|
+
},
|
|
273
|
+
children: [
|
|
274
|
+
/*#__PURE__*/ _jsx("input", {
|
|
275
|
+
type: "checkbox",
|
|
276
|
+
checked: (selectedNode.data.dependencies || []).includes(stepId),
|
|
277
|
+
onChange: (e)=>{
|
|
278
|
+
const currentDeps = selectedNode.data.dependencies || [];
|
|
279
|
+
const newDeps = e.target.checked ? [
|
|
280
|
+
...currentDeps,
|
|
281
|
+
stepId
|
|
282
|
+
] : currentDeps.filter((dep)=>dep !== stepId);
|
|
283
|
+
onNodeUpdate(selectedNode.id, {
|
|
284
|
+
...selectedNode.data,
|
|
285
|
+
dependencies: newDeps
|
|
286
|
+
});
|
|
287
|
+
},
|
|
288
|
+
style: {
|
|
289
|
+
marginRight: '8px'
|
|
290
|
+
}
|
|
291
|
+
}),
|
|
292
|
+
stepId
|
|
293
|
+
]
|
|
294
|
+
}, stepId))
|
|
295
|
+
]
|
|
296
|
+
}),
|
|
297
|
+
renderStepConfiguration(),
|
|
298
|
+
/*#__PURE__*/ _jsx("div", {
|
|
299
|
+
style: {
|
|
300
|
+
borderTop: '1px solid var(--theme-elevation-100)',
|
|
301
|
+
paddingTop: '16px',
|
|
302
|
+
marginTop: '16px'
|
|
303
|
+
},
|
|
304
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
305
|
+
buttonStyle: "primary",
|
|
306
|
+
onClick: handleSave,
|
|
307
|
+
children: "Save Configuration"
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
]
|
|
311
|
+
})
|
|
312
|
+
]
|
|
313
|
+
});
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
//# sourceMappingURL=StepConfigurationForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/WorkflowBuilder/StepConfigurationForm.tsx"],"sourcesContent":["'use client'\n\nimport React, { useState, useCallback, useEffect } from 'react'\nimport type { Node } from '@xyflow/react'\nimport { Button } from '@payloadcms/ui'\n\ninterface StepField {\n name: string\n type: string\n label?: string\n admin?: {\n description?: string\n condition?: (data: any, siblingData: any) => boolean\n }\n options?: Array<{ label: string; value: string }>\n defaultValue?: any\n required?: boolean\n hasMany?: boolean\n fields?: StepField[] // For group fields\n}\n\ninterface StepType {\n slug: string\n label?: string\n inputSchema?: StepField[]\n outputSchema?: StepField[]\n}\n\ninterface StepConfigurationFormProps {\n selectedNode: Node | null\n availableStepTypes: StepType[]\n availableSteps: string[] // For dependency selection\n onNodeUpdate: (nodeId: string, data: Partial<Node['data']>) => void\n onClose: () => void\n}\n\nexport const StepConfigurationForm: React.FC<StepConfigurationFormProps> = ({\n selectedNode,\n availableStepTypes,\n availableSteps,\n onNodeUpdate,\n onClose\n}) => {\n const [formData, setFormData] = useState<Record<string, any>>(\n selectedNode?.data.configuration || {}\n )\n const [jsonText, setJsonText] = useState<string>(() => \n JSON.stringify(selectedNode?.data.configuration || {}, null, 2)\n )\n\n if (!selectedNode) return null\n\n const stepType = availableStepTypes.find(type => type.slug === selectedNode.data.stepType)\n const inputSchema = stepType?.inputSchema || []\n\n // Update form data when selected node changes\n useEffect(() => {\n const config = selectedNode?.data.configuration || {}\n setFormData(config)\n setJsonText(JSON.stringify(config, null, 2))\n }, [selectedNode])\n\n\n const handleSave = useCallback(() => {\n // Update the node with form data\n onNodeUpdate(selectedNode.id, {\n ...selectedNode.data,\n configuration: formData\n })\n \n onClose()\n }, [selectedNode, formData, onNodeUpdate, onClose])\n\n const renderStepConfiguration = () => {\n if (!inputSchema.length) {\n return (\n <div style={{ \n padding: '20px',\n textAlign: 'center',\n color: 'var(--theme-text-400)',\n fontStyle: 'italic'\n }}>\n This step type has no configuration parameters.\n </div>\n )\n }\n\n return (\n <div style={{ marginBottom: '16px' }}>\n <label style={{ \n display: 'block', \n marginBottom: '4px', \n fontSize: '12px', \n fontWeight: '500',\n color: 'var(--theme-text)' \n }}>\n Step Configuration\n </label>\n <div style={{ fontSize: '11px', color: 'var(--theme-text-400)', marginBottom: '8px' }}>\n Configure this step's parameters in JSON format. Use JSONPath expressions like <code>$.trigger.doc.id</code> to reference dynamic data.\n </div>\n \n {/* Schema Reference */}\n <details style={{ marginBottom: '12px' }}>\n <summary style={{ \n fontSize: '11px', \n color: 'var(--theme-text-400)', \n cursor: 'pointer',\n marginBottom: '8px'\n }}>\n 📖 Available Fields (click to expand)\n </summary>\n <div style={{ \n background: 'var(--theme-elevation-50)',\n border: '1px solid var(--theme-elevation-100)',\n borderRadius: '4px',\n padding: '12px',\n fontSize: '11px',\n fontFamily: 'monospace'\n }}>\n {inputSchema.map((field, index) => (\n <div key={field.name} style={{ marginBottom: index < inputSchema.length - 1 ? '8px' : '0' }}>\n <strong>{field.name}</strong> ({field.type})\n {field.required && <span style={{ color: 'var(--theme-error-500)' }}> *required</span>}\n {field.admin?.description && (\n <div style={{ color: 'var(--theme-text-400)', marginTop: '2px' }}>\n {field.admin.description}\n </div>\n )}\n </div>\n ))}\n </div>\n </details>\n\n <textarea\n value={jsonText}\n onChange={(e) => {\n const text = e.target.value\n setJsonText(text)\n try {\n const parsed = JSON.parse(text)\n setFormData(parsed)\n } catch {\n // Keep invalid JSON, user is still typing\n // Don't update formData until JSON is valid\n }\n }}\n rows={Math.min(Math.max(inputSchema.length * 2, 6), 15)}\n style={{\n width: '100%',\n padding: '12px',\n border: '1px solid var(--theme-elevation-100)',\n borderRadius: '4px',\n fontSize: '13px',\n fontFamily: 'monospace',\n lineHeight: '1.4',\n background: 'var(--theme-input-bg)',\n color: 'var(--theme-text)',\n resize: 'vertical'\n }}\n placeholder='{\\n \"field1\": \"value1\",\\n \"field2\": \"$.trigger.doc.id\"\\n}'\n />\n </div>\n )\n }\n\n return (\n <div style={{\n height: '100%',\n width: '100%',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden'\n }}>\n {/* Header */}\n <div style={{\n padding: '16px',\n borderBottom: '1px solid var(--theme-elevation-100)',\n background: 'var(--theme-elevation-50)'\n }}>\n <div style={{ \n display: 'flex', \n justifyContent: 'space-between', \n alignItems: 'center' \n }}>\n <h4 style={{ margin: 0, fontSize: '16px', fontWeight: '600', color: 'var(--theme-text)' }}>\n Configure Step\n </h4>\n <Button\n buttonStyle=\"none\"\n onClick={onClose}\n size=\"small\"\n >\n ×\n </Button>\n </div>\n <div style={{ fontSize: '12px', color: 'var(--theme-text-400)', marginTop: '4px' }}>\n {stepType?.label || (selectedNode.data.stepType as string)}\n </div>\n </div>\n\n {/* Form */}\n <div style={{ \n flex: 1, \n overflow: 'auto', \n padding: '16px' \n }}>\n {/* Basic step info */}\n <div style={{ marginBottom: '16px' }}>\n <label style={{ \n display: 'block', \n marginBottom: '4px', \n fontSize: '12px', \n fontWeight: '500' \n }}>\n Step Name *\n </label>\n <input\n type=\"text\"\n value={(selectedNode.data.label as string) || ''}\n onChange={(e) => onNodeUpdate(selectedNode.id, { \n ...selectedNode.data, \n label: e.target.value \n })}\n style={{\n width: '100%',\n padding: '8px',\n border: '1px solid var(--theme-elevation-100)',\n borderRadius: '4px',\n fontSize: '14px'\n }}\n required\n />\n </div>\n\n {/* Dependencies */}\n <div style={{ marginBottom: '16px' }}>\n <label style={{ \n display: 'block', \n marginBottom: '4px', \n fontSize: '12px', \n fontWeight: '500' \n }}>\n Dependencies\n </label>\n <div style={{ fontSize: '11px', color: 'var(--theme-text-400)', marginBottom: '8px' }}>\n Steps that must complete before this step can run\n </div>\n {availableSteps\n .filter(step => step !== selectedNode.id)\n .map(stepId => (\n <label key={stepId} style={{ \n display: 'block', \n fontSize: '12px', \n marginBottom: '4px' \n }}>\n <input\n type=\"checkbox\"\n checked={((selectedNode.data.dependencies as string[]) || []).includes(stepId)}\n onChange={(e) => {\n const currentDeps = (selectedNode.data.dependencies as string[]) || []\n const newDeps = e.target.checked\n ? [...currentDeps, stepId]\n : currentDeps.filter((dep: string) => dep !== stepId)\n \n onNodeUpdate(selectedNode.id, {\n ...selectedNode.data,\n dependencies: newDeps\n })\n }}\n style={{ marginRight: '8px' }}\n />\n {stepId}\n </label>\n ))}\n </div>\n\n {/* Step-specific configuration */}\n {renderStepConfiguration()}\n\n {/* Submit button */}\n <div style={{ \n borderTop: '1px solid var(--theme-elevation-100)', \n paddingTop: '16px', \n marginTop: '16px' \n }}>\n <Button\n buttonStyle=\"primary\"\n onClick={handleSave}\n >\n Save Configuration\n </Button>\n </div>\n </div>\n </div>\n )\n}"],"names":["React","useState","useCallback","useEffect","Button","StepConfigurationForm","selectedNode","availableStepTypes","availableSteps","onNodeUpdate","onClose","formData","setFormData","data","configuration","jsonText","setJsonText","JSON","stringify","stepType","find","type","slug","inputSchema","config","handleSave","id","renderStepConfiguration","length","div","style","padding","textAlign","color","fontStyle","marginBottom","label","display","fontSize","fontWeight","code","details","summary","cursor","background","border","borderRadius","fontFamily","map","field","index","strong","name","required","span","admin","description","marginTop","textarea","value","onChange","e","text","target","parsed","parse","rows","Math","min","max","width","lineHeight","resize","placeholder","height","flexDirection","overflow","borderBottom","justifyContent","alignItems","h4","margin","buttonStyle","onClick","size","flex","input","filter","step","stepId","checked","dependencies","includes","currentDeps","newDeps","dep","marginRight","borderTop","paddingTop"],"mappings":"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"}
|