@xtr-dev/payload-automation 0.0.38 → 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 (64) 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/plugin/collection-hook.js +34 -0
  19. package/dist/plugin/collection-hook.js.map +1 -1
  20. package/package.json +4 -3
  21. package/dist/collections/Workflow.d.ts +0 -3
  22. package/dist/collections/WorkflowRuns.d.ts +0 -2
  23. package/dist/components/ErrorDisplay.d.ts +0 -9
  24. package/dist/components/StatusCell.d.ts +0 -6
  25. package/dist/core/trigger-custom-workflow.d.ts +0 -52
  26. package/dist/core/workflow-executor.d.ts +0 -90
  27. package/dist/exports/client.d.ts +0 -2
  28. package/dist/exports/fields.d.ts +0 -1
  29. package/dist/exports/rsc.d.ts +0 -1
  30. package/dist/exports/server.d.ts +0 -5
  31. package/dist/exports/views.d.ts +0 -1
  32. package/dist/fields/parameter.d.ts +0 -4
  33. package/dist/index.d.ts +0 -2
  34. package/dist/plugin/collection-hook.d.ts +0 -1
  35. package/dist/plugin/config-types.d.ts +0 -18
  36. package/dist/plugin/global-hook.d.ts +0 -1
  37. package/dist/plugin/index.d.ts +0 -4
  38. package/dist/plugin/logger.d.ts +0 -20
  39. package/dist/steps/create-document-handler.d.ts +0 -2
  40. package/dist/steps/create-document.d.ts +0 -46
  41. package/dist/steps/delete-document-handler.d.ts +0 -2
  42. package/dist/steps/delete-document.d.ts +0 -39
  43. package/dist/steps/http-request-handler.d.ts +0 -2
  44. package/dist/steps/http-request.d.ts +0 -155
  45. package/dist/steps/index.d.ts +0 -12
  46. package/dist/steps/read-document-handler.d.ts +0 -2
  47. package/dist/steps/read-document.d.ts +0 -46
  48. package/dist/steps/send-email-handler.d.ts +0 -2
  49. package/dist/steps/send-email.d.ts +0 -44
  50. package/dist/steps/update-document-handler.d.ts +0 -2
  51. package/dist/steps/update-document.d.ts +0 -46
  52. package/dist/test/basic.test.js +0 -14
  53. package/dist/test/basic.test.js.map +0 -1
  54. package/dist/test/create-document-step.test.js +0 -378
  55. package/dist/test/create-document-step.test.js.map +0 -1
  56. package/dist/test/http-request-step.test.js +0 -361
  57. package/dist/test/http-request-step.test.js.map +0 -1
  58. package/dist/test/workflow-executor.test.js +0 -530
  59. package/dist/test/workflow-executor.test.js.map +0 -1
  60. package/dist/triggers/collection-trigger.d.ts +0 -2
  61. package/dist/triggers/global-trigger.d.ts +0 -2
  62. package/dist/triggers/index.d.ts +0 -2
  63. package/dist/triggers/types.d.ts +0 -5
  64. package/dist/types/index.d.ts +0 -31
@@ -0,0 +1,119 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React, { useCallback, useEffect, useState } from 'react';
4
+ import { useField } from '@payloadcms/ui';
5
+ import { WorkflowBuilder } from '../components/WorkflowBuilder/index.js';
6
+ // Import the step types from the steps module
7
+ import * as stepTasks from '../steps/index.js';
8
+ // Extract available step types from imported tasks
9
+ const getAvailableStepTypes = ()=>{
10
+ const stepTypes = [];
11
+ // Get all exported step tasks
12
+ const tasks = [
13
+ stepTasks.HttpRequestStepTask,
14
+ stepTasks.CreateDocumentStepTask,
15
+ stepTasks.ReadDocumentStepTask,
16
+ stepTasks.UpdateDocumentStepTask,
17
+ stepTasks.DeleteDocumentStepTask,
18
+ stepTasks.SendEmailStepTask
19
+ ];
20
+ tasks.forEach((task)=>{
21
+ if (task && task.slug) {
22
+ stepTypes.push({
23
+ slug: task.slug,
24
+ label: undefined,
25
+ inputSchema: task.inputSchema,
26
+ outputSchema: task.outputSchema
27
+ });
28
+ }
29
+ });
30
+ return stepTypes;
31
+ };
32
+ export const WorkflowBuilderField = ({ name, path })=>{
33
+ const availableStepTypes = getAvailableStepTypes();
34
+ const { value: steps, setValue: setSteps } = useField({
35
+ path: 'steps'
36
+ });
37
+ const { value: layout, setValue: setLayout } = useField({
38
+ path: 'layout'
39
+ });
40
+ const { value: workflowName } = useField({
41
+ path: 'name'
42
+ });
43
+ const [workflowData, setWorkflowData] = useState({
44
+ id: 'temp',
45
+ name: workflowName || 'Workflow',
46
+ steps: steps || [],
47
+ layout: layout || {}
48
+ });
49
+ // Update local state when form fields change
50
+ useEffect(()=>{
51
+ setWorkflowData({
52
+ id: 'temp',
53
+ name: workflowName || 'Workflow',
54
+ steps: steps || [],
55
+ layout: layout || {}
56
+ });
57
+ }, [
58
+ steps,
59
+ layout,
60
+ workflowName
61
+ ]);
62
+ const handleSave = useCallback((updatedWorkflow)=>{
63
+ // Update the form fields
64
+ if (updatedWorkflow.steps) {
65
+ setSteps(updatedWorkflow.steps);
66
+ }
67
+ if (updatedWorkflow.layout) {
68
+ setLayout(updatedWorkflow.layout);
69
+ }
70
+ }, [
71
+ setSteps,
72
+ setLayout
73
+ ]);
74
+ return /*#__PURE__*/ _jsxs("div", {
75
+ style: {
76
+ marginTop: '20px',
77
+ marginBottom: '20px',
78
+ border: '1px solid var(--theme-elevation-100)',
79
+ borderRadius: '4px',
80
+ overflow: 'hidden'
81
+ },
82
+ children: [
83
+ /*#__PURE__*/ _jsxs("div", {
84
+ style: {
85
+ background: 'var(--theme-elevation-50)',
86
+ padding: '12px 16px',
87
+ borderBottom: '1px solid var(--theme-elevation-100)'
88
+ },
89
+ children: [
90
+ /*#__PURE__*/ _jsx("h3", {
91
+ style: {
92
+ margin: 0,
93
+ fontSize: '16px',
94
+ fontWeight: '600',
95
+ color: 'var(--theme-text)'
96
+ },
97
+ children: "Visual Workflow Builder"
98
+ }),
99
+ /*#__PURE__*/ _jsx("p", {
100
+ style: {
101
+ margin: '4px 0 0',
102
+ fontSize: '12px',
103
+ color: 'var(--theme-text-400)'
104
+ },
105
+ children: "Drag and drop steps to build your workflow visually. Click on any step to configure its parameters."
106
+ })
107
+ ]
108
+ }),
109
+ /*#__PURE__*/ _jsx(WorkflowBuilder, {
110
+ workflow: workflowData,
111
+ availableStepTypes: availableStepTypes,
112
+ onSave: handleSave,
113
+ readonly: false
114
+ })
115
+ ]
116
+ });
117
+ };
118
+
119
+ //# sourceMappingURL=WorkflowBuilderField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/fields/WorkflowBuilderField.tsx"],"sourcesContent":["'use client'\n\nimport React, { useCallback, useEffect, useState } from 'react'\nimport { useField, useFormFields } from '@payloadcms/ui'\nimport { WorkflowBuilder } from '../components/WorkflowBuilder/index.js'\n\n// Import the step types from the steps module\nimport * as stepTasks from '../steps/index.js'\n\n// Extract available step types from imported tasks\nconst getAvailableStepTypes = () => {\n const stepTypes: Array<{\n slug: string\n label?: string\n inputSchema?: any[]\n outputSchema?: any[]\n }> = []\n\n // Get all exported step tasks\n const tasks = [\n stepTasks.HttpRequestStepTask,\n stepTasks.CreateDocumentStepTask,\n stepTasks.ReadDocumentStepTask,\n stepTasks.UpdateDocumentStepTask,\n stepTasks.DeleteDocumentStepTask,\n stepTasks.SendEmailStepTask\n ]\n\n tasks.forEach(task => {\n if (task && task.slug) {\n stepTypes.push({\n slug: task.slug,\n label: undefined, // Tasks don't have labels, will use slug\n inputSchema: task.inputSchema,\n outputSchema: task.outputSchema\n })\n }\n })\n\n return stepTypes\n}\n\ninterface WorkflowBuilderFieldProps {\n name?: string\n path?: string\n}\n\nexport const WorkflowBuilderField: React.FC<WorkflowBuilderFieldProps> = ({ \n name, \n path\n}) => {\n const availableStepTypes = getAvailableStepTypes()\n const { value: steps, setValue: setSteps } = useField<any>({ path: 'steps' })\n const { value: layout, setValue: setLayout } = useField<any>({ path: 'layout' })\n const { value: workflowName } = useField<string>({ path: 'name' })\n \n const [workflowData, setWorkflowData] = useState<any>({\n id: 'temp',\n name: workflowName || 'Workflow',\n steps: steps || [],\n layout: layout || {}\n })\n\n // Update local state when form fields change\n useEffect(() => {\n setWorkflowData({\n id: 'temp',\n name: workflowName || 'Workflow',\n steps: steps || [],\n layout: layout || {}\n })\n }, [steps, layout, workflowName])\n\n const handleSave = useCallback((updatedWorkflow: any) => {\n // Update the form fields\n if (updatedWorkflow.steps) {\n setSteps(updatedWorkflow.steps)\n }\n if (updatedWorkflow.layout) {\n setLayout(updatedWorkflow.layout)\n }\n }, [setSteps, setLayout])\n\n return (\n <div style={{ \n marginTop: '20px',\n marginBottom: '20px',\n border: '1px solid var(--theme-elevation-100)',\n borderRadius: '4px',\n overflow: 'hidden'\n }}>\n <div style={{\n background: 'var(--theme-elevation-50)',\n padding: '12px 16px',\n borderBottom: '1px solid var(--theme-elevation-100)'\n }}>\n <h3 style={{ margin: 0, fontSize: '16px', fontWeight: '600', color: 'var(--theme-text)' }}>\n Visual Workflow Builder\n </h3>\n <p style={{ margin: '4px 0 0', fontSize: '12px', color: 'var(--theme-text-400)' }}>\n Drag and drop steps to build your workflow visually. Click on any step to configure its parameters.\n </p>\n </div>\n \n <WorkflowBuilder\n workflow={workflowData}\n availableStepTypes={availableStepTypes}\n onSave={handleSave}\n readonly={false}\n />\n </div>\n )\n}"],"names":["React","useCallback","useEffect","useState","useField","WorkflowBuilder","stepTasks","getAvailableStepTypes","stepTypes","tasks","HttpRequestStepTask","CreateDocumentStepTask","ReadDocumentStepTask","UpdateDocumentStepTask","DeleteDocumentStepTask","SendEmailStepTask","forEach","task","slug","push","label","undefined","inputSchema","outputSchema","WorkflowBuilderField","name","path","availableStepTypes","value","steps","setValue","setSteps","layout","setLayout","workflowName","workflowData","setWorkflowData","id","handleSave","updatedWorkflow","div","style","marginTop","marginBottom","border","borderRadius","overflow","background","padding","borderBottom","h3","margin","fontSize","fontWeight","color","p","workflow","onSave","readonly"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAC/D,SAASC,QAAQ,QAAuB,iBAAgB;AACxD,SAASC,eAAe,QAAQ,yCAAwC;AAExE,8CAA8C;AAC9C,YAAYC,eAAe,oBAAmB;AAE9C,mDAAmD;AACnD,MAAMC,wBAAwB;IAC5B,MAAMC,YAKD,EAAE;IAEP,8BAA8B;IAC9B,MAAMC,QAAQ;QACZH,UAAUI,mBAAmB;QAC7BJ,UAAUK,sBAAsB;QAChCL,UAAUM,oBAAoB;QAC9BN,UAAUO,sBAAsB;QAChCP,UAAUQ,sBAAsB;QAChCR,UAAUS,iBAAiB;KAC5B;IAEDN,MAAMO,OAAO,CAACC,CAAAA;QACZ,IAAIA,QAAQA,KAAKC,IAAI,EAAE;YACrBV,UAAUW,IAAI,CAAC;gBACbD,MAAMD,KAAKC,IAAI;gBACfE,OAAOC;gBACPC,aAAaL,KAAKK,WAAW;gBAC7BC,cAAcN,KAAKM,YAAY;YACjC;QACF;IACF;IAEA,OAAOf;AACT;AAOA,OAAO,MAAMgB,uBAA4D,CAAC,EACxEC,IAAI,EACJC,IAAI,EACL;IACC,MAAMC,qBAAqBpB;IAC3B,MAAM,EAAEqB,OAAOC,KAAK,EAAEC,UAAUC,QAAQ,EAAE,GAAG3B,SAAc;QAAEsB,MAAM;IAAQ;IAC3E,MAAM,EAAEE,OAAOI,MAAM,EAAEF,UAAUG,SAAS,EAAE,GAAG7B,SAAc;QAAEsB,MAAM;IAAS;IAC9E,MAAM,EAAEE,OAAOM,YAAY,EAAE,GAAG9B,SAAiB;QAAEsB,MAAM;IAAO;IAEhE,MAAM,CAACS,cAAcC,gBAAgB,GAAGjC,SAAc;QACpDkC,IAAI;QACJZ,MAAMS,gBAAgB;QACtBL,OAAOA,SAAS,EAAE;QAClBG,QAAQA,UAAU,CAAC;IACrB;IAEA,6CAA6C;IAC7C9B,UAAU;QACRkC,gBAAgB;YACdC,IAAI;YACJZ,MAAMS,gBAAgB;YACtBL,OAAOA,SAAS,EAAE;YAClBG,QAAQA,UAAU,CAAC;QACrB;IACF,GAAG;QAACH;QAAOG;QAAQE;KAAa;IAEhC,MAAMI,aAAarC,YAAY,CAACsC;QAC9B,yBAAyB;QACzB,IAAIA,gBAAgBV,KAAK,EAAE;YACzBE,SAASQ,gBAAgBV,KAAK;QAChC;QACA,IAAIU,gBAAgBP,MAAM,EAAE;YAC1BC,UAAUM,gBAAgBP,MAAM;QAClC;IACF,GAAG;QAACD;QAAUE;KAAU;IAExB,qBACE,MAACO;QAAIC,OAAO;YACVC,WAAW;YACXC,cAAc;YACdC,QAAQ;YACRC,cAAc;YACdC,UAAU;QACZ;;0BACE,MAACN;gBAAIC,OAAO;oBACVM,YAAY;oBACZC,SAAS;oBACTC,cAAc;gBAChB;;kCACE,KAACC;wBAAGT,OAAO;4BAAEU,QAAQ;4BAAGC,UAAU;4BAAQC,YAAY;4BAAOC,OAAO;wBAAoB;kCAAG;;kCAG3F,KAACC;wBAAEd,OAAO;4BAAEU,QAAQ;4BAAWC,UAAU;4BAAQE,OAAO;wBAAwB;kCAAG;;;;0BAKrF,KAACjD;gBACCmD,UAAUrB;gBACVR,oBAAoBA;gBACpB8B,QAAQnB;gBACRoB,UAAU;;;;AAIlB,EAAC"}
@@ -34,6 +34,40 @@ export const createCollectionTriggerHook = (collectionSlug, hookType)=>{
34
34
  collection: collectionSlug
35
35
  }
36
36
  };
37
+ // Check if any trigger has a condition and evaluate it
38
+ let shouldExecute = false;
39
+ for (const trigger of workflow.triggers || []){
40
+ if (trigger.type === 'collection-hook' && trigger.parameters?.collectionSlug === collectionSlug && trigger.parameters?.hook === hookType) {
41
+ if (trigger.condition) {
42
+ // Evaluate the condition
43
+ try {
44
+ const conditionMet = executor.evaluateCondition(trigger.condition, context);
45
+ if (conditionMet) {
46
+ shouldExecute = true;
47
+ break;
48
+ }
49
+ } catch (error) {
50
+ payload.logger.error({
51
+ workflowId: workflow.id,
52
+ condition: trigger.condition,
53
+ error: error instanceof Error ? error.message : 'Unknown error'
54
+ }, 'Failed to evaluate trigger condition');
55
+ }
56
+ } else {
57
+ // No condition means always execute
58
+ shouldExecute = true;
59
+ break;
60
+ }
61
+ }
62
+ }
63
+ if (!shouldExecute) {
64
+ payload.logger.debug({
65
+ workflowId: workflow.id,
66
+ collection: collectionSlug,
67
+ hookType
68
+ }, 'Workflow skipped due to unmet condition');
69
+ continue;
70
+ }
37
71
  try {
38
72
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
73
  await executor.execute(workflow, context, req);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/plugin/collection-hook.ts"],"sourcesContent":["import {WorkflowExecutor} from \"../core/workflow-executor.js\"\n\nexport const createCollectionTriggerHook = (collectionSlug: string, hookType: string) => {\n return async (args: any) => {\n const req = 'req' in args ? args.req :\n 'args' in args ? args.args.req :\n undefined\n if (!req) {\n throw new Error('No request object found in hook arguments')\n }\n const payload = req.payload\n const {docs: workflows} = await payload.find({\n collection: 'workflows',\n depth: 2,\n limit: 100,\n where: {\n 'triggers.parameters.collectionSlug': {\n equals: collectionSlug\n },\n 'triggers.parameters.hook': {\n equals: hookType\n },\n 'triggers.type': {\n equals: 'collection-hook'\n }\n }\n })\n const executor = new WorkflowExecutor(payload, payload.logger)\n // invoke each workflow\n for (const workflow of workflows) {\n // Create execution context\n const context = {\n steps: {},\n trigger: {\n ...args,\n type: 'collection',\n collection: collectionSlug,\n }\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await executor.execute(workflow as any, context, req)\n payload.logger.info({\n workflowId: workflow.id,\n collection: collectionSlug,\n hookType\n }, 'Workflow executed successfully')\n } catch (error) {\n payload.logger.error({\n workflowId: workflow.id,\n collection: collectionSlug,\n hookType,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Workflow execution failed')\n // Don't throw to prevent breaking the original operation\n }\n }\n }\n}\n"],"names":["WorkflowExecutor","createCollectionTriggerHook","collectionSlug","hookType","args","req","undefined","Error","payload","docs","workflows","find","collection","depth","limit","where","equals","executor","logger","workflow","context","steps","trigger","type","execute","info","workflowId","id","error","message"],"mappings":"AAAA,SAAQA,gBAAgB,QAAO,+BAA8B;AAE7D,OAAO,MAAMC,8BAA8B,CAACC,gBAAwBC;IAClE,OAAO,OAAOC;QACZ,MAAMC,MAAM,SAASD,OAAOA,KAAKC,GAAG,GAClC,UAAUD,OAAOA,KAAKA,IAAI,CAACC,GAAG,GAC5BC;QACJ,IAAI,CAACD,KAAK;YACR,MAAM,IAAIE,MAAM;QAClB;QACA,MAAMC,UAAUH,IAAIG,OAAO;QAC3B,MAAM,EAACC,MAAMC,SAAS,EAAC,GAAG,MAAMF,QAAQG,IAAI,CAAC;YAC3CC,YAAY;YACZC,OAAO;YACPC,OAAO;YACPC,OAAO;gBACL,sCAAsC;oBACpCC,QAAQd;gBACV;gBACA,4BAA4B;oBAC1Bc,QAAQb;gBACV;gBACA,iBAAiB;oBACfa,QAAQ;gBACV;YACF;QACF;QACA,MAAMC,WAAW,IAAIjB,iBAAiBQ,SAASA,QAAQU,MAAM;QAC7D,uBAAuB;QACvB,KAAK,MAAMC,YAAYT,UAAW;YAChC,2BAA2B;YAC3B,MAAMU,UAAU;gBACdC,OAAO,CAAC;gBACRC,SAAS;oBACP,GAAGlB,IAAI;oBACPmB,MAAM;oBACNX,YAAYV;gBACd;YACF;YAEA,IAAI;gBACF,8DAA8D;gBAC9D,MAAMe,SAASO,OAAO,CAACL,UAAiBC,SAASf;gBACjDG,QAAQU,MAAM,CAACO,IAAI,CAAC;oBAClBC,YAAYP,SAASQ,EAAE;oBACvBf,YAAYV;oBACZC;gBACF,GAAG;YACL,EAAE,OAAOyB,OAAO;gBACdpB,QAAQU,MAAM,CAACU,KAAK,CAAC;oBACnBF,YAAYP,SAASQ,EAAE;oBACvBf,YAAYV;oBACZC;oBACAyB,OAAOA,iBAAiBrB,QAAQqB,MAAMC,OAAO,GAAG;gBAClD,GAAG;YACH,yDAAyD;YAC3D;QACF;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/plugin/collection-hook.ts"],"sourcesContent":["import {WorkflowExecutor} from \"../core/workflow-executor.js\"\n\nexport const createCollectionTriggerHook = (collectionSlug: string, hookType: string) => {\n return async (args: any) => {\n const req = 'req' in args ? args.req :\n 'args' in args ? args.args.req :\n undefined\n if (!req) {\n throw new Error('No request object found in hook arguments')\n }\n const payload = req.payload\n const {docs: workflows} = await payload.find({\n collection: 'workflows',\n depth: 2,\n limit: 100,\n where: {\n 'triggers.parameters.collectionSlug': {\n equals: collectionSlug\n },\n 'triggers.parameters.hook': {\n equals: hookType\n },\n 'triggers.type': {\n equals: 'collection-hook'\n }\n }\n })\n const executor = new WorkflowExecutor(payload, payload.logger)\n // invoke each workflow\n for (const workflow of workflows) {\n // Create execution context\n const context = {\n steps: {},\n trigger: {\n ...args,\n type: 'collection',\n collection: collectionSlug,\n }\n }\n\n // Check if any trigger has a condition and evaluate it\n let shouldExecute = false\n for (const trigger of workflow.triggers || []) {\n if (trigger.type === 'collection-hook' && \n trigger.parameters?.collectionSlug === collectionSlug && \n trigger.parameters?.hook === hookType) {\n \n if (trigger.condition) {\n // Evaluate the condition\n try {\n const conditionMet = executor.evaluateCondition(trigger.condition, context)\n if (conditionMet) {\n shouldExecute = true\n break\n }\n } catch (error) {\n payload.logger.error({\n workflowId: workflow.id,\n condition: trigger.condition,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Failed to evaluate trigger condition')\n }\n } else {\n // No condition means always execute\n shouldExecute = true\n break\n }\n }\n }\n\n if (!shouldExecute) {\n payload.logger.debug({\n workflowId: workflow.id,\n collection: collectionSlug,\n hookType\n }, 'Workflow skipped due to unmet condition')\n continue\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await executor.execute(workflow as any, context, req)\n payload.logger.info({\n workflowId: workflow.id,\n collection: collectionSlug,\n hookType\n }, 'Workflow executed successfully')\n } catch (error) {\n payload.logger.error({\n workflowId: workflow.id,\n collection: collectionSlug,\n hookType,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'Workflow execution failed')\n // Don't throw to prevent breaking the original operation\n }\n }\n }\n}\n"],"names":["WorkflowExecutor","createCollectionTriggerHook","collectionSlug","hookType","args","req","undefined","Error","payload","docs","workflows","find","collection","depth","limit","where","equals","executor","logger","workflow","context","steps","trigger","type","shouldExecute","triggers","parameters","hook","condition","conditionMet","evaluateCondition","error","workflowId","id","message","debug","execute","info"],"mappings":"AAAA,SAAQA,gBAAgB,QAAO,+BAA8B;AAE7D,OAAO,MAAMC,8BAA8B,CAACC,gBAAwBC;IAClE,OAAO,OAAOC;QACZ,MAAMC,MAAM,SAASD,OAAOA,KAAKC,GAAG,GAClC,UAAUD,OAAOA,KAAKA,IAAI,CAACC,GAAG,GAC5BC;QACJ,IAAI,CAACD,KAAK;YACR,MAAM,IAAIE,MAAM;QAClB;QACA,MAAMC,UAAUH,IAAIG,OAAO;QAC3B,MAAM,EAACC,MAAMC,SAAS,EAAC,GAAG,MAAMF,QAAQG,IAAI,CAAC;YAC3CC,YAAY;YACZC,OAAO;YACPC,OAAO;YACPC,OAAO;gBACL,sCAAsC;oBACpCC,QAAQd;gBACV;gBACA,4BAA4B;oBAC1Bc,QAAQb;gBACV;gBACA,iBAAiB;oBACfa,QAAQ;gBACV;YACF;QACF;QACA,MAAMC,WAAW,IAAIjB,iBAAiBQ,SAASA,QAAQU,MAAM;QAC7D,uBAAuB;QACvB,KAAK,MAAMC,YAAYT,UAAW;YAChC,2BAA2B;YAC3B,MAAMU,UAAU;gBACdC,OAAO,CAAC;gBACRC,SAAS;oBACP,GAAGlB,IAAI;oBACPmB,MAAM;oBACNX,YAAYV;gBACd;YACF;YAEA,uDAAuD;YACvD,IAAIsB,gBAAgB;YACpB,KAAK,MAAMF,WAAWH,SAASM,QAAQ,IAAI,EAAE,CAAE;gBAC7C,IAAIH,QAAQC,IAAI,KAAK,qBACjBD,QAAQI,UAAU,EAAExB,mBAAmBA,kBACvCoB,QAAQI,UAAU,EAAEC,SAASxB,UAAU;oBAEzC,IAAImB,QAAQM,SAAS,EAAE;wBACrB,yBAAyB;wBACzB,IAAI;4BACF,MAAMC,eAAeZ,SAASa,iBAAiB,CAACR,QAAQM,SAAS,EAAER;4BACnE,IAAIS,cAAc;gCAChBL,gBAAgB;gCAChB;4BACF;wBACF,EAAE,OAAOO,OAAO;4BACdvB,QAAQU,MAAM,CAACa,KAAK,CAAC;gCACnBC,YAAYb,SAASc,EAAE;gCACvBL,WAAWN,QAAQM,SAAS;gCAC5BG,OAAOA,iBAAiBxB,QAAQwB,MAAMG,OAAO,GAAG;4BAClD,GAAG;wBACL;oBACF,OAAO;wBACL,oCAAoC;wBACpCV,gBAAgB;wBAChB;oBACF;gBACF;YACF;YAEA,IAAI,CAACA,eAAe;gBAClBhB,QAAQU,MAAM,CAACiB,KAAK,CAAC;oBACnBH,YAAYb,SAASc,EAAE;oBACvBrB,YAAYV;oBACZC;gBACF,GAAG;gBACH;YACF;YAEA,IAAI;gBACF,8DAA8D;gBAC9D,MAAMc,SAASmB,OAAO,CAACjB,UAAiBC,SAASf;gBACjDG,QAAQU,MAAM,CAACmB,IAAI,CAAC;oBAClBL,YAAYb,SAASc,EAAE;oBACvBrB,YAAYV;oBACZC;gBACF,GAAG;YACL,EAAE,OAAO4B,OAAO;gBACdvB,QAAQU,MAAM,CAACa,KAAK,CAAC;oBACnBC,YAAYb,SAASc,EAAE;oBACvBrB,YAAYV;oBACZC;oBACA4B,OAAOA,iBAAiBxB,QAAQwB,MAAMG,OAAO,GAAG;gBAClD,GAAG;YACH,yDAAyD;YAC3D;QACF;IACF;AACF,EAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtr-dev/payload-automation",
3
- "version": "0.0.38",
3
+ "version": "0.0.39",
4
4
  "description": "PayloadCMS Automation Plugin - Comprehensive workflow automation system with visual workflow building, execution tracking, and step types",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -47,7 +47,7 @@
47
47
  "dist"
48
48
  ],
49
49
  "scripts": {
50
- "build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
50
+ "build": "pnpm copyfiles && pnpm build:swc",
51
51
  "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
52
52
  "build:types": "tsc --outDir dist --rootDir ./src",
53
53
  "clean": "rimraf {dist,*.tsbuildinfo}",
@@ -75,6 +75,7 @@
75
75
  "@payloadcms/ui": "3.45.0",
76
76
  "@playwright/test": "^1.52.0",
77
77
  "@swc/cli": "0.6.0",
78
+ "@types/handlebars": "^4.1.0",
78
79
  "@types/nock": "^11.1.0",
79
80
  "@types/node": "^22.5.4",
80
81
  "@types/node-cron": "^3.0.11",
@@ -135,7 +136,7 @@
135
136
  "registry": "https://registry.npmjs.org/",
136
137
  "packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184",
137
138
  "dependencies": {
138
- "jsonpath-plus": "^10.3.0",
139
+ "handlebars": "^4.7.8",
139
140
  "node-cron": "^4.2.1",
140
141
  "pino": "^9.9.0"
141
142
  }
@@ -1,3 +0,0 @@
1
- import type { CollectionConfig } from 'payload';
2
- import type { WorkflowsPluginConfig } from "../plugin/config-types.js";
3
- export declare const createWorkflowCollection: <T extends string>(options: WorkflowsPluginConfig<T>) => CollectionConfig;
@@ -1,2 +0,0 @@
1
- import type { CollectionConfig } from 'payload';
2
- export declare const WorkflowRunsCollection: CollectionConfig;
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- interface ErrorDisplayProps {
3
- value?: string;
4
- onChange?: (value: string) => void;
5
- readOnly?: boolean;
6
- path?: string;
7
- }
8
- export declare const ErrorDisplay: React.FC<ErrorDisplayProps>;
9
- export {};
@@ -1,6 +0,0 @@
1
- import React from 'react';
2
- interface StatusCellProps {
3
- cellData: string;
4
- }
5
- export declare const StatusCell: React.FC<StatusCellProps>;
6
- export {};
@@ -1,52 +0,0 @@
1
- import type { Payload, PayloadRequest } from 'payload';
2
- export interface CustomTriggerOptions {
3
- /**
4
- * Data to pass to the workflow execution context
5
- */
6
- data?: Record<string, unknown>;
7
- /**
8
- * Optional PayloadRequest to use for the workflow execution
9
- * If not provided, a minimal request will be created
10
- */
11
- req?: PayloadRequest;
12
- /**
13
- * The slug of the custom trigger to execute
14
- */
15
- slug: string;
16
- /**
17
- * Optional user information for tracking who triggered the workflow
18
- */
19
- user?: {
20
- email?: string;
21
- id?: string;
22
- };
23
- }
24
- export interface TriggerResult {
25
- error?: string;
26
- runId: number | string;
27
- status: 'failed' | 'triggered';
28
- workflowId: string;
29
- workflowName: string;
30
- }
31
- /**
32
- * Programmatically trigger workflows that have a matching custom trigger
33
- *
34
- * @example
35
- * ```typescript
36
- * // In your onInit or elsewhere in your code
37
- * await triggerCustomWorkflow(payload, {
38
- * slug: 'data-import',
39
- * data: {
40
- * source: 'external-api',
41
- * recordCount: 100,
42
- * importedAt: new Date().toISOString()
43
- * }
44
- * })
45
- * ```
46
- */
47
- export declare function triggerCustomWorkflow(payload: Payload, options: CustomTriggerOptions): Promise<TriggerResult[]>;
48
- /**
49
- * Helper function to trigger a single workflow by ID with custom trigger data
50
- * This is useful when you know exactly which workflow you want to trigger
51
- */
52
- export declare function triggerWorkflowById(payload: Payload, workflowId: string, triggerSlug: string, data?: Record<string, unknown>, req?: PayloadRequest): Promise<TriggerResult>;
@@ -1,90 +0,0 @@
1
- import type { Payload, PayloadRequest } from 'payload';
2
- export type PayloadWorkflow = {
3
- id: number;
4
- name: string;
5
- description?: null | string;
6
- triggers?: Array<{
7
- type?: null | string;
8
- condition?: null | string;
9
- parameters?: {
10
- collectionSlug?: null | string;
11
- operation?: null | string;
12
- global?: null | string;
13
- globalOperation?: null | string;
14
- [key: string]: unknown;
15
- } | null;
16
- [key: string]: unknown;
17
- }> | null;
18
- steps?: Array<{
19
- step?: null | string;
20
- name?: null | string;
21
- input?: unknown;
22
- dependencies?: null | string[];
23
- condition?: null | string;
24
- [key: string]: unknown;
25
- }> | null;
26
- [key: string]: unknown;
27
- };
28
- export type WorkflowStep = {
29
- name: string;
30
- } & NonNullable<PayloadWorkflow['steps']>[0];
31
- export type WorkflowTrigger = {
32
- type: string;
33
- } & NonNullable<PayloadWorkflow['triggers']>[0];
34
- export interface ExecutionContext {
35
- steps: Record<string, any>;
36
- trigger: Record<string, any>;
37
- }
38
- export declare class WorkflowExecutor {
39
- private payload;
40
- private logger;
41
- constructor(payload: Payload, logger: Payload['logger']);
42
- /**
43
- * Classifies error types based on error messages
44
- */
45
- private classifyErrorType;
46
- /**
47
- * Evaluate a step condition using JSONPath
48
- */
49
- private evaluateStepCondition;
50
- /**
51
- * Execute a single workflow step
52
- */
53
- private executeStep;
54
- /**
55
- * Extracts detailed error information from job logs and input
56
- */
57
- private extractErrorDetailsFromJob;
58
- /**
59
- * Parse a condition value (string literal, number, boolean, or JSONPath)
60
- */
61
- private parseConditionValue;
62
- /**
63
- * Resolve step execution order based on dependencies
64
- */
65
- private resolveExecutionOrder;
66
- /**
67
- * Resolve a JSONPath value from the context
68
- */
69
- private resolveJSONPathValue;
70
- /**
71
- * Resolve step input using JSONPath expressions
72
- */
73
- private resolveStepInput;
74
- /**
75
- * Safely serialize an object, handling circular references and non-serializable values
76
- */
77
- private safeSerialize;
78
- /**
79
- * Update workflow run with current context
80
- */
81
- private updateWorkflowRunContext;
82
- /**
83
- * Evaluate a condition using JSONPath and comparison operators
84
- */
85
- evaluateCondition(condition: string, context: ExecutionContext): boolean;
86
- /**
87
- * Execute a workflow with the given context
88
- */
89
- execute(workflow: PayloadWorkflow, context: ExecutionContext, req: PayloadRequest): Promise<void>;
90
- }
@@ -1,2 +0,0 @@
1
- export { StatusCell } from '../components/StatusCell.js';
2
- export { ErrorDisplay } from '../components/ErrorDisplay.js';
@@ -1 +0,0 @@
1
- export declare const WorkflowFields: {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,5 +0,0 @@
1
- export { triggerCustomWorkflow, triggerWorkflowById } from '../core/trigger-custom-workflow.js';
2
- export { WorkflowExecutor } from '../core/workflow-executor.js';
3
- export { workflowsPlugin } from '../plugin/index.js';
4
- export { createDocumentHandler, deleteDocumentHandler, httpStepHandler, readDocumentHandler, sendEmailHandler, updateDocumentHandler } from '../steps/index.js';
5
- export { CreateDocumentStepTask, DeleteDocumentStepTask, HttpRequestStepTask, ReadDocumentStepTask, SendEmailStepTask, UpdateDocumentStepTask } from '../steps/index.js';
@@ -1 +0,0 @@
1
- export {};
@@ -1,4 +0,0 @@
1
- import type { Field } from "payload";
2
- export declare const parameter: (slug: string, field: {
3
- name: string;
4
- } & Field) => Field;
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export type { PayloadWorkflow as Workflow, WorkflowStep, WorkflowTrigger } from './core/workflow-executor.js';
2
- export type { CustomTriggerOptions, ExecutionContext, TriggerResult, WorkflowsPluginConfig } from './types/index.js';
@@ -1 +0,0 @@
1
- export declare const createCollectionTriggerHook: (collectionSlug: string, hookType: string) => (args: any) => Promise<void>;
@@ -1,18 +0,0 @@
1
- import type { CollectionConfig, GlobalConfig, TaskConfig } from "payload";
2
- import type { Trigger } from "../triggers/types.js";
3
- export type TriggerConfig = (config: WorkflowsPluginConfig) => Trigger;
4
- export type WorkflowsPluginConfig<TSlug extends string = string, TGlobal extends string = string> = {
5
- collectionTriggers?: {
6
- [key in TSlug]?: {
7
- [key in keyof CollectionConfig['hooks']]?: true;
8
- } | true;
9
- };
10
- globalTriggers?: {
11
- [key in TGlobal]?: {
12
- [key in keyof GlobalConfig['hooks']]?: true;
13
- } | true;
14
- };
15
- enabled?: boolean;
16
- steps: TaskConfig<string>[];
17
- triggers?: TriggerConfig[];
18
- };
@@ -1 +0,0 @@
1
- export declare const createGlobalTriggerHook: (globalSlug: string, hookType: string) => (args: any) => Promise<void>;
@@ -1,4 +0,0 @@
1
- import type { Config } from 'payload';
2
- import type { WorkflowsPluginConfig } from "./config-types.js";
3
- export { getLogger } from './logger.js';
4
- export declare const workflowsPlugin: <TSlug extends string>(pluginOptions: WorkflowsPluginConfig<TSlug>) => (config: Config) => Config;
@@ -1,20 +0,0 @@
1
- import type { Payload } from 'payload';
2
- /**
3
- * Get a logger for config-time use (before Payload initialization)
4
- */
5
- export declare function getConfigLogger(): {
6
- debug: <T>(message: string, ...args: T[]) => void;
7
- error: <T>(message: string, ...args: T[]) => void;
8
- info: <T>(message: string, ...args: T[]) => void;
9
- warn: <T>(message: string, ...args: T[]) => void;
10
- };
11
- /**
12
- * Initialize the plugin logger using Payload's Pino instance
13
- * This creates a child logger with plugin identification
14
- */
15
- export declare function initializeLogger(payload: Payload): Payload['logger'];
16
- /**
17
- * Get the plugin logger instance
18
- * Throws error if not initialized
19
- */
20
- export declare function getLogger(): Payload['logger'];
@@ -1,2 +0,0 @@
1
- import type { TaskHandler } from "payload";
2
- export declare const createDocumentHandler: TaskHandler<'create-document'>;
@@ -1,46 +0,0 @@
1
- export declare const CreateDocumentStepTask: {
2
- slug: "create-document";
3
- handler: import("payload").TaskHandler<"create-document">;
4
- inputSchema: ({
5
- name: string;
6
- type: "text";
7
- admin: {
8
- description: string;
9
- };
10
- required: true;
11
- } | {
12
- name: string;
13
- type: "json";
14
- admin: {
15
- description: string;
16
- };
17
- required: true;
18
- } | {
19
- name: string;
20
- type: "checkbox";
21
- admin: {
22
- description: string;
23
- };
24
- required?: undefined;
25
- } | {
26
- name: string;
27
- type: "text";
28
- admin: {
29
- description: string;
30
- };
31
- required?: undefined;
32
- })[];
33
- outputSchema: ({
34
- name: string;
35
- type: "json";
36
- admin: {
37
- description: string;
38
- };
39
- } | {
40
- name: string;
41
- type: "text";
42
- admin: {
43
- description: string;
44
- };
45
- })[];
46
- };
@@ -1,2 +0,0 @@
1
- import type { TaskHandler } from "payload";
2
- export declare const deleteDocumentHandler: TaskHandler<'delete-document'>;
@@ -1,39 +0,0 @@
1
- export declare const DeleteDocumentStepTask: {
2
- slug: "delete-document";
3
- handler: import("payload").TaskHandler<"delete-document">;
4
- inputSchema: ({
5
- name: string;
6
- type: "text";
7
- admin: {
8
- description: string;
9
- };
10
- required: true;
11
- } | {
12
- name: string;
13
- type: "text";
14
- admin: {
15
- description: string;
16
- };
17
- required?: undefined;
18
- } | {
19
- name: string;
20
- type: "json";
21
- admin: {
22
- description: string;
23
- };
24
- required?: undefined;
25
- })[];
26
- outputSchema: ({
27
- name: string;
28
- type: "json";
29
- admin: {
30
- description: string;
31
- };
32
- } | {
33
- name: string;
34
- type: "number";
35
- admin: {
36
- description: string;
37
- };
38
- })[];
39
- };
@@ -1,2 +0,0 @@
1
- import type { TaskHandler } from "payload";
2
- export declare const httpStepHandler: TaskHandler<'http-request-step'>;