@xtr-dev/payload-automation 0.0.37 → 0.0.39

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.
Files changed (66) hide show
  1. package/README.md +6 -1
  2. package/dist/collections/Workflow.js +2 -4
  3. package/dist/collections/Workflow.js.map +1 -1
  4. package/dist/components/WorkflowBuilder/StepConfigurationForm.js +316 -0
  5. package/dist/components/WorkflowBuilder/StepConfigurationForm.js.map +1 -0
  6. package/dist/components/WorkflowBuilder/WorkflowBuilder.js +211 -0
  7. package/dist/components/WorkflowBuilder/WorkflowBuilder.js.map +1 -0
  8. package/dist/components/WorkflowBuilder/WorkflowToolbar.js +107 -0
  9. package/dist/components/WorkflowBuilder/WorkflowToolbar.js.map +1 -0
  10. package/dist/components/WorkflowBuilder/index.js +6 -0
  11. package/dist/components/WorkflowBuilder/index.js.map +1 -0
  12. package/dist/components/WorkflowBuilder/nodes/StepNode.js +139 -0
  13. package/dist/components/WorkflowBuilder/nodes/StepNode.js.map +1 -0
  14. package/dist/core/workflow-executor.js +150 -116
  15. package/dist/core/workflow-executor.js.map +1 -1
  16. package/dist/fields/WorkflowBuilderField.js +119 -0
  17. package/dist/fields/WorkflowBuilderField.js.map +1 -0
  18. package/dist/fields/parameter.js +1 -1
  19. package/dist/fields/parameter.js.map +1 -1
  20. package/dist/plugin/collection-hook.js +34 -0
  21. package/dist/plugin/collection-hook.js.map +1 -1
  22. package/package.json +4 -3
  23. package/dist/collections/Workflow.d.ts +0 -3
  24. package/dist/collections/WorkflowRuns.d.ts +0 -2
  25. package/dist/components/ErrorDisplay.d.ts +0 -9
  26. package/dist/components/StatusCell.d.ts +0 -6
  27. package/dist/core/trigger-custom-workflow.d.ts +0 -52
  28. package/dist/core/workflow-executor.d.ts +0 -90
  29. package/dist/exports/client.d.ts +0 -2
  30. package/dist/exports/fields.d.ts +0 -1
  31. package/dist/exports/rsc.d.ts +0 -1
  32. package/dist/exports/server.d.ts +0 -5
  33. package/dist/exports/views.d.ts +0 -1
  34. package/dist/fields/parameter.d.ts +0 -4
  35. package/dist/index.d.ts +0 -2
  36. package/dist/plugin/collection-hook.d.ts +0 -1
  37. package/dist/plugin/config-types.d.ts +0 -18
  38. package/dist/plugin/global-hook.d.ts +0 -1
  39. package/dist/plugin/index.d.ts +0 -4
  40. package/dist/plugin/logger.d.ts +0 -20
  41. package/dist/steps/create-document-handler.d.ts +0 -2
  42. package/dist/steps/create-document.d.ts +0 -46
  43. package/dist/steps/delete-document-handler.d.ts +0 -2
  44. package/dist/steps/delete-document.d.ts +0 -39
  45. package/dist/steps/http-request-handler.d.ts +0 -2
  46. package/dist/steps/http-request.d.ts +0 -155
  47. package/dist/steps/index.d.ts +0 -12
  48. package/dist/steps/read-document-handler.d.ts +0 -2
  49. package/dist/steps/read-document.d.ts +0 -46
  50. package/dist/steps/send-email-handler.d.ts +0 -2
  51. package/dist/steps/send-email.d.ts +0 -44
  52. package/dist/steps/update-document-handler.d.ts +0 -2
  53. package/dist/steps/update-document.d.ts +0 -46
  54. package/dist/test/basic.test.js +0 -14
  55. package/dist/test/basic.test.js.map +0 -1
  56. package/dist/test/create-document-step.test.js +0 -378
  57. package/dist/test/create-document-step.test.js.map +0 -1
  58. package/dist/test/http-request-step.test.js +0 -361
  59. package/dist/test/http-request-step.test.js.map +0 -1
  60. package/dist/test/workflow-executor.test.js +0 -530
  61. package/dist/test/workflow-executor.test.js.map +0 -1
  62. package/dist/triggers/collection-trigger.d.ts +0 -2
  63. package/dist/triggers/global-trigger.d.ts +0 -2
  64. package/dist/triggers/index.d.ts +0 -2
  65. package/dist/triggers/types.d.ts +0 -5
  66. package/dist/types/index.d.ts +0 -31
package/README.md CHANGED
@@ -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 { TriggerWorkflowButton } from '@xtr-dev/payload-automation/client'
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'
@@ -216,6 +219,8 @@ export default async function handler(req, res) {
216
219
 
217
220
  **Benefits**: Better reliability, proper process isolation, easier debugging, and leverages existing infrastructure.
218
221
 
222
+ **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.
223
+
219
224
  ## Documentation
220
225
 
221
226
  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: 'parameters',
85
+ name: 'input',
86
86
  type: 'json',
87
87
  admin: {
88
- hidden: true
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: 'parameters',\n type: 'json',\n admin: {\n hidden: true,\n },\n defaultValue: {}\n },\n // Virtual fields for custom triggers\n ...steps.flatMap(step => (step.inputSchema || []).map(s => parameter(step.slug, s as any))),\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","step","inputSchema","s","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;4BACLS,QAAQ;wBACV;wBACAC,cAAc,CAAC;oBACjB;oBACA,qCAAqC;uBAClCrB,MAAMsB,OAAO,CAACG,CAAAA,OAAQ,AAACA,CAAAA,KAAKC,WAAW,IAAI,EAAE,AAAD,EAAGxB,GAAG,CAACyB,CAAAA,IAAKhC,UAAU8B,KAAKpB,IAAI,EAAEsB;oBAChF;wBACEV,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAe,SAAS;wBACTT,UAAU;oBACZ;oBACA;wBACEF,MAAM;wBACNC,MAAM;wBACNP,OAAO;4BACLE,aAAa;wBACf;wBACAM,UAAU;oBACZ;iBACD;YACH;SACD;QACDU,UAAU;YACRC,QAAQ;gBACNC,UAAU;YACZ;YACAC,WAAW;QACb;IACF;AACF,EAAC"}
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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"}
@@ -0,0 +1,211 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React, { useCallback, useMemo, useState } from 'react';
4
+ import { ReactFlow, addEdge, useNodesState, useEdgesState, Controls, Background, BackgroundVariant, MiniMap, Panel } from '@xyflow/react';
5
+ import '@xyflow/react/dist/style.css';
6
+ // Import custom node types
7
+ import { StepNode } from './nodes/StepNode.js';
8
+ import { WorkflowToolbar } from './WorkflowToolbar.js';
9
+ import { StepConfigurationForm } from './StepConfigurationForm.js';
10
+ // Define node types for React Flow
11
+ const nodeTypes = {
12
+ stepNode: StepNode
13
+ };
14
+ export const WorkflowBuilder = ({ workflow, availableStepTypes = [], onSave, readonly = false })=>{
15
+ const [selectedNode, setSelectedNode] = useState(null);
16
+ // Convert workflow steps to React Flow nodes
17
+ const initialNodes = useMemo(()=>{
18
+ if (!workflow?.steps) return [];
19
+ return workflow.steps.map((step, index)=>({
20
+ id: step.name || `step-${index}`,
21
+ type: 'stepNode',
22
+ position: step.position || {
23
+ x: 100 + index * 200,
24
+ y: 100
25
+ },
26
+ data: {
27
+ label: step.name || 'Unnamed Step',
28
+ stepType: step.type,
29
+ color: step.visual?.color || '#3b82f6',
30
+ icon: step.visual?.icon,
31
+ dependencies: step.dependencies || []
32
+ }
33
+ }));
34
+ }, [
35
+ workflow?.steps
36
+ ]);
37
+ // Convert dependencies to React Flow edges
38
+ const initialEdges = useMemo(()=>{
39
+ if (!workflow?.steps) return [];
40
+ const edges = [];
41
+ workflow.steps.forEach((step, index)=>{
42
+ const targetId = step.name || `step-${index}`;
43
+ if (step.dependencies) {
44
+ step.dependencies.forEach((depName)=>{
45
+ // Find the source step
46
+ const sourceStep = workflow.steps?.find((s)=>s.name === depName);
47
+ if (sourceStep) {
48
+ const sourceId = sourceStep.name || `step-${workflow.steps?.indexOf(sourceStep)}`;
49
+ edges.push({
50
+ id: `${sourceId}-${targetId}`,
51
+ source: sourceId,
52
+ target: targetId,
53
+ type: 'smoothstep'
54
+ });
55
+ }
56
+ });
57
+ }
58
+ });
59
+ return edges;
60
+ }, [
61
+ workflow?.steps
62
+ ]);
63
+ const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
64
+ const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
65
+ // Handle new connections
66
+ const onConnect = useCallback((params)=>{
67
+ if (readonly) return;
68
+ setEdges((eds)=>addEdge({
69
+ ...params,
70
+ type: 'smoothstep'
71
+ }, eds));
72
+ }, [
73
+ setEdges,
74
+ readonly
75
+ ]);
76
+ // Handle node selection
77
+ const onNodeClick = useCallback((_event, node)=>{
78
+ console.log('Node clicked:', node.id, node.data.label);
79
+ setSelectedNode(node);
80
+ }, []);
81
+ // Handle adding new step
82
+ const onAddStep = useCallback((stepType)=>{
83
+ if (readonly) return;
84
+ const newStep = {
85
+ id: `step-${Date.now()}`,
86
+ type: 'stepNode',
87
+ position: {
88
+ x: 100,
89
+ y: 100
90
+ },
91
+ data: {
92
+ label: 'New Step',
93
+ stepType,
94
+ color: '#3b82f6',
95
+ dependencies: []
96
+ }
97
+ };
98
+ setNodes((nds)=>[
99
+ ...nds,
100
+ newStep
101
+ ]);
102
+ }, [
103
+ setNodes,
104
+ readonly
105
+ ]);
106
+ // Handle updating a node's data
107
+ const handleNodeUpdate = useCallback((nodeId, newData)=>{
108
+ setNodes((nds)=>nds.map((node)=>node.id === nodeId ? {
109
+ ...node,
110
+ data: {
111
+ ...node.data,
112
+ ...newData
113
+ }
114
+ } : node));
115
+ }, [
116
+ setNodes
117
+ ]);
118
+ // Handle saving workflow
119
+ const handleSave = useCallback(()=>{
120
+ if (!workflow || !onSave) return;
121
+ // Convert nodes and edges back to workflow format
122
+ const updatedSteps = nodes.map((node)=>{
123
+ // Find dependencies from edges
124
+ const dependencies = edges.filter((edge)=>edge.target === node.id).map((edge)=>edge.source);
125
+ return {
126
+ name: node.id,
127
+ type: node.data.stepType,
128
+ position: node.position,
129
+ visual: {
130
+ color: node.data.color,
131
+ icon: node.data.icon
132
+ },
133
+ dependencies: dependencies.length > 0 ? dependencies : undefined
134
+ };
135
+ });
136
+ const updatedWorkflow = {
137
+ ...workflow,
138
+ steps: updatedSteps
139
+ };
140
+ onSave(updatedWorkflow);
141
+ }, [
142
+ workflow,
143
+ nodes,
144
+ edges,
145
+ onSave
146
+ ]);
147
+ return /*#__PURE__*/ _jsxs("div", {
148
+ style: {
149
+ width: '100%',
150
+ height: '600px',
151
+ display: 'flex',
152
+ background: 'var(--theme-bg)',
153
+ borderRadius: '4px',
154
+ border: '1px solid var(--theme-elevation-100)'
155
+ },
156
+ children: [
157
+ /*#__PURE__*/ _jsx("div", {
158
+ style: {
159
+ flex: selectedNode ? '1 1 70%' : '1 1 100%',
160
+ transition: 'flex 0.3s ease'
161
+ },
162
+ children: /*#__PURE__*/ _jsxs(ReactFlow, {
163
+ nodes: nodes,
164
+ edges: edges,
165
+ onNodesChange: onNodesChange,
166
+ onEdgesChange: onEdgesChange,
167
+ onConnect: onConnect,
168
+ onNodeClick: onNodeClick,
169
+ nodeTypes: nodeTypes,
170
+ fitView: true,
171
+ attributionPosition: "top-right",
172
+ children: [
173
+ /*#__PURE__*/ _jsx(Controls, {}),
174
+ /*#__PURE__*/ _jsx(MiniMap, {}),
175
+ /*#__PURE__*/ _jsx(Background, {
176
+ variant: BackgroundVariant.Dots,
177
+ gap: 12,
178
+ size: 1
179
+ }),
180
+ !readonly && /*#__PURE__*/ _jsx(Panel, {
181
+ position: "top-left",
182
+ children: /*#__PURE__*/ _jsx(WorkflowToolbar, {
183
+ availableStepTypes: availableStepTypes,
184
+ onAddStep: onAddStep,
185
+ onSave: handleSave
186
+ })
187
+ })
188
+ ]
189
+ })
190
+ }),
191
+ selectedNode && !readonly && /*#__PURE__*/ _jsx("div", {
192
+ style: {
193
+ flex: '0 0 30%',
194
+ borderLeft: '1px solid var(--theme-elevation-100)',
195
+ background: 'var(--theme-elevation-0)',
196
+ display: 'flex',
197
+ flexDirection: 'column'
198
+ },
199
+ children: /*#__PURE__*/ _jsx(StepConfigurationForm, {
200
+ selectedNode: selectedNode,
201
+ availableStepTypes: availableStepTypes,
202
+ availableSteps: nodes.map((node)=>node.id),
203
+ onNodeUpdate: handleNodeUpdate,
204
+ onClose: ()=>setSelectedNode(null)
205
+ })
206
+ })
207
+ ]
208
+ });
209
+ };
210
+
211
+ //# sourceMappingURL=WorkflowBuilder.js.map