@nocobase/plugin-workflow 0.19.0-alpha.3 → 0.19.0-alpha.5

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 (39) hide show
  1. package/dist/client/components/{ExecutionStatusSelect.d.ts → ExecutionStatus.d.ts} +1 -0
  2. package/dist/client/index.d.ts +1 -0
  3. package/dist/client/index.js +31 -30
  4. package/dist/client/nodes/end.d.ts +22 -0
  5. package/dist/client/nodes/index.d.ts +3 -0
  6. package/dist/client/schemas/executions.d.ts +14 -1
  7. package/dist/client/triggers/index.d.ts +1 -0
  8. package/dist/client/triggers/schedule/index.d.ts +1 -0
  9. package/dist/externalVersion.js +10 -10
  10. package/dist/locale/ko_KR.json +168 -0
  11. package/dist/locale/zh-CN.json +17 -1
  12. package/dist/node_modules/cron-parser/package.json +1 -1
  13. package/dist/node_modules/lru-cache/package.json +1 -1
  14. package/dist/server/Plugin.d.ts +4 -1
  15. package/dist/server/Plugin.js +77 -48
  16. package/dist/server/Processor.d.ts +3 -1
  17. package/dist/server/Processor.js +27 -15
  18. package/dist/server/actions/executions.d.ts +1 -0
  19. package/dist/server/actions/executions.js +38 -0
  20. package/dist/server/collections/jobs.js +4 -0
  21. package/dist/server/collections/workflows.js +5 -0
  22. package/dist/server/instructions/ConditionInstruction.d.ts +1 -0
  23. package/dist/server/instructions/ConditionInstruction.js +1 -0
  24. package/dist/server/instructions/CreateInstruction.js +5 -5
  25. package/dist/server/instructions/DestroyInstruction.js +3 -3
  26. package/dist/server/instructions/EndInstruction.d.ts +6 -0
  27. package/dist/server/instructions/EndInstruction.js +46 -0
  28. package/dist/server/instructions/QueryInstruction.js +2 -2
  29. package/dist/server/instructions/UpdateInstruction.js +3 -3
  30. package/dist/server/migrations/20240115220721-add-node-key-to-job.d.ts +6 -0
  31. package/dist/server/migrations/20240115220721-add-node-key-to-job.js +54 -0
  32. package/dist/server/triggers/CollectionTrigger.d.ts +6 -0
  33. package/dist/server/triggers/CollectionTrigger.js +37 -7
  34. package/dist/server/triggers/ScheduleTrigger.d.ts +1 -0
  35. package/dist/server/triggers/ScheduleTrigger.js +1 -0
  36. package/dist/server/triggers/index.d.ts +2 -0
  37. package/dist/server/triggers/index.js +4 -0
  38. package/dist/server/types/Workflow.d.ts +5 -2
  39. package/package.json +3 -3
@@ -0,0 +1,22 @@
1
+ import { Instruction } from '.';
2
+ export default class extends Instruction {
3
+ title: string;
4
+ type: string;
5
+ group: string;
6
+ description: string;
7
+ fieldset: {
8
+ endStatus: {
9
+ type: string;
10
+ title: string;
11
+ 'x-decorator': string;
12
+ 'x-component': string;
13
+ enum: {
14
+ label: string;
15
+ value: number;
16
+ }[];
17
+ required: boolean;
18
+ default: number;
19
+ };
20
+ };
21
+ end: boolean;
22
+ }
@@ -1,8 +1,10 @@
1
1
  import { ISchema } from '@formily/react';
2
2
  import React from 'react';
3
3
  import { SchemaInitializerItemType } from '@nocobase/client';
4
+ import WorkflowPlugin from '..';
4
5
  import { UseVariableOptions, VariableOption } from '../variable';
5
6
  export type NodeAvailableContext = {
7
+ engine: WorkflowPlugin;
6
8
  workflow: object;
7
9
  upstream: object;
8
10
  branchIndex: number;
@@ -32,6 +34,7 @@ export declare abstract class Instruction {
32
34
  useScopeVariables?(node: any, options?: any): VariableOption[];
33
35
  useInitializers?(node: any): SchemaInitializerItemType | null;
34
36
  isAvailable?(ctx: NodeAvailableContext): boolean;
37
+ end?: boolean | ((node: any) => boolean);
35
38
  }
36
39
  export declare const NodeContext: React.Context<any>;
37
40
  export declare function useNodeContext(): any;
@@ -184,6 +184,18 @@ export declare const executionSchema: {
184
184
  useDataSource: string;
185
185
  };
186
186
  properties: {
187
+ id: {
188
+ type: string;
189
+ 'x-decorator': string;
190
+ 'x-component': string;
191
+ properties: {
192
+ id: {
193
+ type: string;
194
+ 'x-component': string;
195
+ 'x-read-pretty': boolean;
196
+ };
197
+ };
198
+ };
187
199
  createdAt: {
188
200
  type: string;
189
201
  'x-decorator': string;
@@ -215,9 +227,11 @@ export declare const executionSchema: {
215
227
  type: string;
216
228
  'x-decorator': string;
217
229
  'x-component': string;
230
+ title: string;
218
231
  properties: {
219
232
  status: {
220
233
  type: string;
234
+ 'x-decorator': string;
221
235
  'x-component': string;
222
236
  'x-read-pretty': boolean;
223
237
  };
@@ -237,7 +251,6 @@ export declare const executionSchema: {
237
251
  properties: {
238
252
  link: {
239
253
  type: string;
240
- title: string;
241
254
  'x-component': string;
242
255
  };
243
256
  };
@@ -3,6 +3,7 @@ import { ISchema } from '@formily/react';
3
3
  import { SchemaInitializerItemType } from '@nocobase/client';
4
4
  import { UseVariableOptions, VariableOption } from '../variable';
5
5
  export declare abstract class Trigger {
6
+ sync: boolean;
6
7
  title: string;
7
8
  description?: string;
8
9
  useVariables?(config: Record<string, any>, options?: UseVariableOptions): VariableOption[];
@@ -2,6 +2,7 @@
2
2
  import { SchemaInitializerItemType, useCollectionDataSource } from '@nocobase/client';
3
3
  import { Trigger } from '..';
4
4
  export default class extends Trigger {
5
+ sync: boolean;
5
6
  title: string;
6
7
  description: string;
7
8
  fieldset: {
@@ -2,21 +2,21 @@ module.exports = {
2
2
  "react": "18.2.0",
3
3
  "antd": "5.12.8",
4
4
  "@ant-design/icons": "5.2.6",
5
- "@nocobase/client": "0.19.0-alpha.3",
5
+ "@nocobase/client": "0.19.0-alpha.5",
6
6
  "react-router-dom": "6.21.0",
7
- "@nocobase/utils": "0.19.0-alpha.3",
7
+ "@nocobase/utils": "0.19.0-alpha.5",
8
8
  "react-i18next": "11.18.6",
9
- "@nocobase/database": "0.19.0-alpha.3",
10
- "@nocobase/server": "0.19.0-alpha.3",
11
- "@nocobase/logger": "0.19.0-alpha.3",
12
- "@nocobase/evaluators": "0.19.0-alpha.3",
9
+ "@formily/core": "2.3.0",
13
10
  "@formily/react": "2.3.0",
11
+ "@nocobase/database": "0.19.0-alpha.5",
12
+ "@nocobase/server": "0.19.0-alpha.5",
13
+ "@nocobase/logger": "0.19.0-alpha.5",
14
+ "@nocobase/evaluators": "0.19.0-alpha.5",
14
15
  "lodash": "4.17.21",
15
- "@formily/core": "2.3.0",
16
16
  "@formily/antd-v5": "1.1.9",
17
- "@nocobase/actions": "0.19.0-alpha.3",
17
+ "@nocobase/actions": "0.19.0-alpha.5",
18
18
  "sequelize": "6.35.2",
19
- "@nocobase/plugin-workflow-test": "0.19.0-alpha.3",
20
- "@nocobase/test": "0.19.0-alpha.3",
19
+ "@nocobase/plugin-workflow-test": "0.19.0-alpha.5",
20
+ "@nocobase/test": "0.19.0-alpha.5",
21
21
  "dayjs": "1.11.10"
22
22
  };
@@ -0,0 +1,168 @@
1
+ {
2
+ "Workflow": "워크플로우",
3
+ "Execution history": "실행 기록",
4
+ "Clear all executions": "모든 실행 기록 지우기",
5
+ "Clear executions will not reset executed count, and started executions will not be deleted, are you sure you want to delete them all?": "지우기 작업은 실행 횟수를 재설정하지 않으며 시작된 실행이 삭제되지 않습니다. 모두 삭제하시겠습니까?",
6
+ "Executed": "실행됨",
7
+ "Sync enabled status of all workflows from the database": "데이터베이스에서 모든 워크플로우의 활성 상태 동기화",
8
+ "Trigger type": "트리거 유형",
9
+ "Status": "상태",
10
+ "On": "활성",
11
+ "Off": "비활성",
12
+ "Version": "버전",
13
+ "Copy to new version": "새 버전으로 복사",
14
+ "Duplicate": "복제",
15
+ "Duplicate to new workflow": "새로운 워크플로우로 복제",
16
+ "Delete a main version will cause all other revisions to be deleted too.": "주 버전을 삭제하면 모든 다른 수정 사항도 삭제됩니다.",
17
+ "Loading": "로딩 중",
18
+ "Load failed": "로드 실패",
19
+ "Use transaction": "트랜잭션 사용",
20
+ "Data operation nodes in the workflow will run in the same transaction until any interruption. Any failure will cause data rollback, and will also rollback the history of the execution.": "워크플로우의 데이터 작업 노드는 어떠한 방해가 발생할 때까지 동일한 트랜잭션에서 실행됩니다. 어떠한 실패도 데이터 롤백을 유발하며 실행 이력도 롤백됩니다.",
21
+ "Auto delete history when execution is on end status": "실행이 종료 상태일 때 자동으로 이력 삭제",
22
+ "Trigger": "트리거",
23
+ "Trigger variables": "트리거 변수",
24
+ "Trigger data": "트리거 데이터",
25
+ "Trigger time": "트리거 시간",
26
+ "Triggered at": "트리거 시간",
27
+ "Bind workflows": "워크플로우 바인딩",
28
+ "Workflow will be triggered after submitting succeeded.": "제출 성공 후 워크플로우가 트리거됩니다.",
29
+ "Workflow will be triggered after saving succeeded.": "저장 성공 후 워크플로우가 트리거됩니다.",
30
+ "Workflow will be triggered directly once the button is clicked, without data saving.": "버튼을 클릭하면 데이터 저장 없이 워크플로우가 직접 트리거됩니다.",
31
+ "Submit to workflow": "워크플로우에 제출",
32
+ "Add workflow": "워크플로우 추가",
33
+ "Select workflow": "워크플로우 선택",
34
+ "Trigger data context": "트리거 데이터 컨텍스트",
35
+ "Full form data": "전체 폼 데이터",
36
+ "Select context": "컨텍스트 선택",
37
+ "Collection event": "데이터 테이블 이벤트",
38
+ "Event will be triggered on collection data row created, updated or deleted.": "데이터 테이블의 데이터 행이 생성, 업데이트 또는 삭제될 때 이벤트가 트리거됩니다.",
39
+ "Trigger on": "트리거 조건",
40
+ "After record added": "레코드 추가 후",
41
+ "After record updated": "레코드 업데이트 후",
42
+ "After record added or updated": "레코드 추가 또는 업데이트 후",
43
+ "After record deleted": "레코드 삭제 후",
44
+ "Changed fields": "변경된 필드",
45
+ "Triggered only if one of the selected fields changes. If unselected, it means that it will be triggered when any field changes. When the record is added or deleted, any field is considered to have been changed.":
46
+ "선택한 필드 중 하나라도 변경되면 트리거됩니다. 선택하지 않으면 어떤 필드가 변경되더라도 트리거됩니다. 레코드가 추가되거나 삭제될 때는 어떤 필드든지 변경된 것으로 간주됩니다.",
47
+ "Only triggers when match conditions": "일치하는 조건이 충족될 때만 트리거됩니다",
48
+ "Preload associations": "연결 데이터를 미리 로드합니다",
49
+ "Please select the associated fields that need to be accessed in subsequent nodes. With more than two levels of to-many associations may cause performance issue, please use with caution.":
50
+ "후속 노드에서 액세스해야 하는 연관 필드를 선택하십시오. 두 개 이상의 수많은 연관 레벨은 성능 문제를 발생시킬 수 있으므로 주의해서 사용하십시오.",
51
+ "Schedule event": "일정 이벤트",
52
+ "Event will be scheduled and triggered based on time conditions.": "이벤트는 시간 조건을 기반으로 예약되고 트리거됩니다.",
53
+ "Trigger mode": "트리거 모드",
54
+ "Based on certain date": "특정 날짜를 기준으로",
55
+ "Based on date field of collection": "컬렉션의 날짜 필드를 기반으로",
56
+ "Starts on": "시작 날짜",
57
+ "Ends on": "종료 날짜",
58
+ "No end": "종료 없음",
59
+ "Exactly at": "정확한 시각",
60
+ "Repeat mode": "반복 모드",
61
+ "Repeat limit": "반복 제한",
62
+ "No limit": "제한 없음",
63
+ "Seconds": "초",
64
+ "Minutes": "분",
65
+ "Hours": "시간",
66
+ "Days": "일",
67
+ "Weeks": "주",
68
+ "Months": "월",
69
+ "No repeat": "반복 없음",
70
+ "Every": "매",
71
+ "By minute": "분당",
72
+ "By hour": "시간당",
73
+ "By day": "매일",
74
+ "By week": "매주",
75
+ "By month": "매월",
76
+ "By field": "필드별",
77
+ "By custom date": "사용자 정의 날짜별",
78
+ "Advanced": "고급",
79
+ "End": "종료",
80
+ "Node result": "노드 결과",
81
+ "Variable key of node": "노드 변수 키",
82
+ "Scope variables": "범위 변수",
83
+ "Operator": "연산자",
84
+ "Calculate an expression based on a calculation engine and obtain a value as the result. Variables in the upstream nodes can be used in the expression. The expression can be a static or dynamic one from an expression collections.":
85
+ "계산 엔진을 기반으로 식을 계산하고 결과값을 얻습니다. 상류 노드의 변수를 식에서 사용할 수 있습니다. 식은 표현식 컬렉션에서 정적 또는 동적일 수 있습니다.",
86
+ "String operation": "문자열 연산",
87
+ "System variables": "시스템 변수",
88
+ "System time": "시스템 시간",
89
+ "Date variables": "날짜 변수",
90
+ "Executed at": "실행된 시각",
91
+ "Queueing": "대기 중",
92
+ "On going": "진행 중",
93
+ "Resolved": "해결됨",
94
+ "Pending": "보류 중",
95
+ "Failed": "실패",
96
+ "Error": "오류",
97
+ "Aborted": "중단됨",
98
+ "Canceled": "취소됨",
99
+ "Rejected": "거부됨",
100
+ "Retry needed": "재시도 필요",
101
+ "Triggered but still waiting in the queue to execute.": "트리거되었지만 아직 대기열에서 실행 대기 중입니다.",
102
+ "Started and executing, maybe waiting for an async callback (manual, delay, etc.).":
103
+ "시작되어 실행 중이며, 비동기 콜백을 기다리는 중일 수 있습니다(수동, 지연 등).",
104
+ "Successfully finished.": "성공적으로 완료됨",
105
+ "Failed to satisfy node configurations.": "노드 구성을 충족하지 못했습니다.",
106
+ "Some node meets error.": "일부 노드에서 오류가 발생했습니다.",
107
+ "Running of some node was aborted by program flow.": "프로그램 플로우에 의해 일부 노드의 실행이 중단되었습니다.",
108
+ "Manually canceled the whole execution when waiting.": "대기 중에 수동으로 전체 실행이 취소되었습니다.",
109
+ "Rejected from a manual node.": "수동 노드에서 거부되었습니다.",
110
+ "General failed but should do another try.": "일반적인 실패이지만 다시 시도해야 합니다.",
111
+ "Operations": "작업",
112
+ "This node contains branches, deleting will also be performed on them, are you sure?":
113
+ "이 노드에는 분기가 포함되어 있습니다. 삭제하면 그들에게도 적용됩니다. 계속하시겠습니까?",
114
+ "Control": "프로세스 제어",
115
+ "Collection operations": "데이터 테이블 조작",
116
+ "Manual": "수동 처리",
117
+ "Extended types": "확장된 유형",
118
+ "Node type": "노드 유형",
119
+ "Calculation": "계산",
120
+ "Calculation engine": "계산 엔진",
121
+ "Basic": "기본",
122
+ "Calculation expression": "계산식",
123
+ "Expression syntax error": "식 문법 오류",
124
+ "Syntax references: ": "문법 참조:",
125
+ "Calculation result": "계산 결과",
126
+ "True": "참",
127
+ "False": "거짓",
128
+ "concat": "연결",
129
+ "Condition": "조건",
130
+ "Based on the boolean result of the calculation to determine whether to \"continue\" or \"exit\" the process, or continue on different branches of \"yes\" and \"no\".":
131
+ "계산 결과의 참/거짓을 기반으로 프로세스를 '계속' 또는 '종료'하거나 '예' 및 '아니오'의 다른 분기에서 계속합니다.",
132
+ "Mode": "모드",
133
+ "Continue when \"Yes\"": "\"예\"일 때 계속",
134
+ "Branch into \"Yes\" and \"No\"": "\"예\" 및 \"아니오\"로 분기",
135
+ "Condition expression": "조건식",
136
+ "Create record": "레코드 생성",
137
+ "Add a new record to a collection. You can use variables from upstream nodes to assign values to fields.":
138
+ "컬렉션에 새로운 레코드를 추가합니다. 상류 노드의 변수를 사용하여 필드에 값을 할당할 수 있습니다.",
139
+ "Update record": "레코드 업데이트",
140
+ "Update records of a collection. You can use variables from upstream nodes as query conditions and field values.":
141
+ "데이터 테이블의 레코드를 업데이트합니다. 상류 노드의 변수를 쿼리 조건 및 필드 값으로 사용할 수 있습니다.",
142
+ "Update mode": "업데이트 모드",
143
+ "Update in a batch": "일괄 업데이트",
144
+ "Update one by one": "개별 업데이트",
145
+ "Update all eligible data at one time, which has better performance when the amount of data is large. But the updated data will not trigger other workflows, and will not record audit logs.":
146
+ "일괄로 모든 해당 데이터를 한 번에 업데이트하며, 데이터 양이 많을 때 성능이 더 좋습니다. 그러나 업데이트된 데이터는 다른 워크플로를 트리거하지 않으며 감사 로그를 기록하지 않습니다.",
147
+ "The updated data can trigger other workflows, and the audit log will also be recorded. But it is usually only applicable to several or dozens of pieces of data, otherwise there will be performance problems.":
148
+ "업데이트된 데이터는 다른 워크플로를 트리거하고 감사 로그도 기록할 수 있습니다. 그러나 일반적으로 몇 개 또는 몇 십 개의 데이터에만 적용되며, 그렇지 않으면 성능 문제가 발생할 수 있습니다.",
149
+ "Query record": "데이터 조회",
150
+ "Query records from a collection. You can use variables from upstream nodes as query conditions.":
151
+ "데이터 테이블에서 레코드를 조회합니다. 상류 노드의 변수를 쿼리 조건으로 사용할 수 있습니다.",
152
+ "Allow multiple records as a result": "다중 레코드 결과 허용",
153
+ "If checked, when there are multiple records in the query result, an array will be returned as the result, which can be operated on one by one using a loop node. Otherwise, only one record will be returned.":
154
+ "선택한 경우, 쿼리 결과에 여러 레코드가 있는 경우 결과로 배열이 반환되어 루프 노드를 사용하여 하나씩 조작할 수 있습니다. 그렇지 않으면 하나의 레코드만 반환됩니다.",
155
+ "Exit when the query result is null": "쿼리 결과가 null인 경우 종료",
156
+ "Please select the collection first": "먼저 데이터 테이블을 선택하세요.",
157
+ "Only update records matching conditions": "조건과 일치하는 레코드만 업데이트",
158
+ "Please add at least one condition": "최소한 하나의 조건을 추가하세요.",
159
+ "Unassigned fields will be set to default values, and those without default values will be set to null.":
160
+ "미할당된 필드는 기본값으로 설정되며 기본값이 없는 필드는 null로 설정됩니다.",
161
+ "Delete record": "데이터 삭제",
162
+ "Delete records of a collection. Could use variables in the workflow context as a filter. All records matching the filter will be deleted.":
163
+ "데이터 테이블의 레코드를 삭제합니다. 워크플로 컨텍스트의 변수를 필터로 사용할 수 있습니다. 필터와 일치하는 모든 레코드가 삭제됩니다.",
164
+ "Executed workflow cannot be modified": "이미 실행된 워크플로는 수정할 수 없습니다.",
165
+ "Cannot delete": "삭제할 수 없음",
166
+ "The result of this node has been referenced by other nodes ({{nodes}}), please remove the usage before deleting.":
167
+ "이 노드의 결과가 다른 노드에서 참조되었습니다({{nodes}}). 삭제 전에 참조를 제거하세요."
168
+ }
@@ -27,6 +27,14 @@
27
27
  "Trigger time": "触发时间",
28
28
  "Triggered at": "触发时间",
29
29
 
30
+ "Execute mode": "执行模式",
31
+ "Execute workflow asynchronously or synchronously based on trigger type, and could not be changed after created.": "基于触发类型异步或同步执行工作流,创建后不可更改。",
32
+ "Asynchronously": "异步",
33
+ "Synchronously": "同步",
34
+ "Will be executed in the background as a queued task.": "将作为队列任务在后台执行。",
35
+ "For user actions that require immediate feedback. Can not use asynchronous nodes in such mode, and it is not recommended to perform time-consuming operations under synchronous mode.":
36
+ "适用于需要即时反馈的用户操作。不能在此模式下使用异步节点,并且不建议在同步模式下执行耗时的操作。",
37
+
30
38
  "Bind workflows": "绑定工作流",
31
39
  "Workflow will be triggered after submitting succeeded.": "提交成功后触发工作流。",
32
40
  "Workflow will be triggered after saving succeeded.": "保存成功后触发工作流。",
@@ -116,6 +124,9 @@
116
124
  "Rejected from a manual node.": "被人工节点拒绝继续。",
117
125
  "General failed but should do another try.": "执行失败,需重试。",
118
126
 
127
+ "Cancel the execution": "取消执行",
128
+ "Are you sure you want to cancel the execution?": "确定要取消该执行吗?",
129
+
119
130
  "Operations": "操作",
120
131
  "This node contains branches, deleting will also be preformed to them, are you sure?":
121
132
  "节点包含分支,将同时删除其所有分支下的子节点,确定继续?",
@@ -174,5 +185,10 @@
174
185
  "Executed workflow cannot be modified": "已经执行过的工作流不能被修改",
175
186
  "Can not delete": "无法删除",
176
187
  "The result of this node has been referenced by other nodes ({{nodes}}), please remove the usage before deleting.":
177
- "该节点的执行结果已被其他节点({{nodes}})引用,删除前请先移除引用。"
188
+ "该节点的执行结果已被其他节点({{nodes}})引用,删除前请先移除引用。",
189
+
190
+ "End process": "结束流程",
191
+ "End the process immediately, with set status.": "以设置的状态立即结束流程。",
192
+ "End status": "结束状态",
193
+ "Succeeded": "成功"
178
194
  }
@@ -1 +1 @@
1
- {"name":"cron-parser","version":"4.4.0","description":"Node.js library for parsing crontab instructions","main":"lib/parser.js","types":"index.d.ts","typesVersions":{"<4.1":{"*":["types/ts3/*"]}},"directories":{"test":"test"},"scripts":{"test:tsd":"tsd","test:unit":"TZ=UTC tap ./test/*.js","test:cover":"TZ=UTC tap --coverage-report=html ./test/*.js","lint":"eslint .","lint:fix":"eslint --fix .","test":"npm run lint && npm run test:unit && npm run test:tsd"},"repository":{"type":"git","url":"https://github.com/harrisiirak/cron-parser.git"},"keywords":["cron","crontab","parser"],"author":"Harri Siirak","contributors":["Nicholas Clawson","Daniel Prentis <daniel@salsitasoft.com>","Renault John Lecoultre","Richard Astbury <richard.astbury@gmail.com>","Meaglin Wasabi <Meaglin.wasabi@gmail.com>","Mike Kusold <hello@mikekusold.com>","Alex Kit <alex.kit@atmajs.com>","Santiago Gimeno <santiago.gimeno@gmail.com>","Daniel <darc.tec@gmail.com>","Christian Steininger <christian.steininger.cs@gmail.com>","Mykola Piskovyi <m.piskovyi@gmail.com>","Brian Vaughn <brian.david.vaughn@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Yasuhiroki <yasuhiroki.duck@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Brendan Warkentin <faazshift@gmail.com>","Charlie Fish <fishcharlie.code@gmail.com>","Ian Graves <ian+diskimage@iangrav.es>","Andy Thompson <me@andytson.com>","Regev Brody <regevbr@gmail.com>"],"license":"MIT","dependencies":{"luxon":"^1.28.0"},"devDependencies":{"eslint":"^8.2.0","sinon":"^10.0.0","tap":"^16.0.1","tsd":"^0.19.0"},"engines":{"node":">=0.8"},"browser":{"fs":false},"tap":{"check-coverage":false},"tsd":{"directory":"test","compilerOptions":{"lib":["es2017","dom"]}},"_lastModified":"2024-01-09T10:43:15.058Z"}
1
+ {"name":"cron-parser","version":"4.4.0","description":"Node.js library for parsing crontab instructions","main":"lib/parser.js","types":"index.d.ts","typesVersions":{"<4.1":{"*":["types/ts3/*"]}},"directories":{"test":"test"},"scripts":{"test:tsd":"tsd","test:unit":"TZ=UTC tap ./test/*.js","test:cover":"TZ=UTC tap --coverage-report=html ./test/*.js","lint":"eslint .","lint:fix":"eslint --fix .","test":"npm run lint && npm run test:unit && npm run test:tsd"},"repository":{"type":"git","url":"https://github.com/harrisiirak/cron-parser.git"},"keywords":["cron","crontab","parser"],"author":"Harri Siirak","contributors":["Nicholas Clawson","Daniel Prentis <daniel@salsitasoft.com>","Renault John Lecoultre","Richard Astbury <richard.astbury@gmail.com>","Meaglin Wasabi <Meaglin.wasabi@gmail.com>","Mike Kusold <hello@mikekusold.com>","Alex Kit <alex.kit@atmajs.com>","Santiago Gimeno <santiago.gimeno@gmail.com>","Daniel <darc.tec@gmail.com>","Christian Steininger <christian.steininger.cs@gmail.com>","Mykola Piskovyi <m.piskovyi@gmail.com>","Brian Vaughn <brian.david.vaughn@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Yasuhiroki <yasuhiroki.duck@gmail.com>","Nicholas Clawson <nickclaw@gmail.com>","Brendan Warkentin <faazshift@gmail.com>","Charlie Fish <fishcharlie.code@gmail.com>","Ian Graves <ian+diskimage@iangrav.es>","Andy Thompson <me@andytson.com>","Regev Brody <regevbr@gmail.com>"],"license":"MIT","dependencies":{"luxon":"^1.28.0"},"devDependencies":{"eslint":"^8.2.0","sinon":"^10.0.0","tap":"^16.0.1","tsd":"^0.19.0"},"engines":{"node":">=0.8"},"browser":{"fs":false},"tap":{"check-coverage":false},"tsd":{"directory":"test","compilerOptions":{"lib":["es2017","dom"]}},"_lastModified":"2024-01-30T09:21:20.958Z"}
@@ -1 +1 @@
1
- {"name":"lru-cache","description":"A cache object that deletes the least-recently-used items.","version":"8.0.5","author":"Isaac Z. Schlueter <i@izs.me>","keywords":["mru","lru","cache"],"sideEffects":false,"scripts":{"build":"npm run prepare","preprepare":"rm -rf dist","prepare":"tsc -p tsconfig.json && tsc -p tsconfig-esm.json","postprepare":"bash fixup.sh","pretest":"npm run prepare","presnap":"npm run prepare","test":"c8 tap","snap":"c8 tap","preversion":"npm test","postversion":"npm publish","prepublishOnly":"git push origin --follow-tags","format":"prettier --write .","typedoc":"typedoc --tsconfig tsconfig-esm.json ./src/*.ts","benchmark-results-typedoc":"bash scripts/benchmark-results-typedoc.sh","prebenchmark":"npm run prepare","benchmark":"make -C benchmark","preprofile":"npm run prepare","profile":"make -C benchmark profile"},"main":"./dist/cjs/index-cjs.js","module":"./dist/mjs/index.js","types":"./dist/mjs/index.d.ts","exports":{"./min":{"import":{"types":"./dist/mjs/index.d.ts","default":"./dist/mjs/index.min.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.min.js"}},".":{"import":{"types":"./dist/mjs/index.d.ts","default":"./dist/mjs/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index-cjs.js"}}},"repository":"git://github.com/isaacs/node-lru-cache.git","devDependencies":{"@size-limit/preset-small-lib":"^7.0.8","@types/node":"^17.0.31","@types/tap":"^15.0.6","benchmark":"^2.1.4","c8":"^7.11.2","clock-mock":"^1.0.6","esbuild":"^0.17.11","eslint-config-prettier":"^8.5.0","marked":"^4.2.12","mkdirp":"^2.1.5","prettier":"^2.6.2","size-limit":"^7.0.8","tap":"^16.3.4","ts-node":"^10.7.0","tslib":"^2.4.0","typedoc":"^0.23.24","typescript":"^4.6.4"},"license":"ISC","files":["dist"],"engines":{"node":">=16.14"},"prettier":{"semi":false,"printWidth":70,"tabWidth":2,"useTabs":false,"singleQuote":true,"jsxSingleQuote":false,"bracketSameLine":true,"arrowParens":"avoid","endOfLine":"lf"},"tap":{"coverage":false,"node-arg":["--expose-gc","--no-warnings","--loader","ts-node/esm"],"ts":false},"size-limit":[{"path":"./dist/mjs/index.js"}],"_lastModified":"2024-01-09T10:43:14.717Z"}
1
+ {"name":"lru-cache","description":"A cache object that deletes the least-recently-used items.","version":"8.0.5","author":"Isaac Z. Schlueter <i@izs.me>","keywords":["mru","lru","cache"],"sideEffects":false,"scripts":{"build":"npm run prepare","preprepare":"rm -rf dist","prepare":"tsc -p tsconfig.json && tsc -p tsconfig-esm.json","postprepare":"bash fixup.sh","pretest":"npm run prepare","presnap":"npm run prepare","test":"c8 tap","snap":"c8 tap","preversion":"npm test","postversion":"npm publish","prepublishOnly":"git push origin --follow-tags","format":"prettier --write .","typedoc":"typedoc --tsconfig tsconfig-esm.json ./src/*.ts","benchmark-results-typedoc":"bash scripts/benchmark-results-typedoc.sh","prebenchmark":"npm run prepare","benchmark":"make -C benchmark","preprofile":"npm run prepare","profile":"make -C benchmark profile"},"main":"./dist/cjs/index-cjs.js","module":"./dist/mjs/index.js","types":"./dist/mjs/index.d.ts","exports":{"./min":{"import":{"types":"./dist/mjs/index.d.ts","default":"./dist/mjs/index.min.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.min.js"}},".":{"import":{"types":"./dist/mjs/index.d.ts","default":"./dist/mjs/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index-cjs.js"}}},"repository":"git://github.com/isaacs/node-lru-cache.git","devDependencies":{"@size-limit/preset-small-lib":"^7.0.8","@types/node":"^17.0.31","@types/tap":"^15.0.6","benchmark":"^2.1.4","c8":"^7.11.2","clock-mock":"^1.0.6","esbuild":"^0.17.11","eslint-config-prettier":"^8.5.0","marked":"^4.2.12","mkdirp":"^2.1.5","prettier":"^2.6.2","size-limit":"^7.0.8","tap":"^16.3.4","ts-node":"^10.7.0","tslib":"^2.4.0","typedoc":"^0.23.24","typescript":"^4.6.4"},"license":"ISC","files":["dist"],"engines":{"node":">=16.14"},"prettier":{"semi":false,"printWidth":70,"tabWidth":2,"useTabs":false,"singleQuote":true,"jsxSingleQuote":false,"bracketSameLine":true,"arrowParens":"avoid","endOfLine":"lf"},"tap":{"coverage":false,"node-arg":["--expose-gc","--no-warnings","--loader","ts-node/esm"],"ts":false},"size-limit":[{"path":"./dist/mjs/index.js"}],"_lastModified":"2024-01-30T09:21:20.626Z"}
@@ -1,3 +1,4 @@
1
+ import { Transactionable } from '@nocobase/database';
1
2
  import { Plugin } from '@nocobase/server';
2
3
  import { Registry } from '@nocobase/utils';
3
4
  import { Logger } from '@nocobase/logger';
@@ -19,6 +20,7 @@ export default class PluginWorkflowServer extends Plugin {
19
20
  private loggerCache;
20
21
  private meter;
21
22
  getLogger(workflowId: ID): Logger;
23
+ isWorkflowSync(workflow: WorkflowModel): boolean;
22
24
  onBeforeSave: (instance: WorkflowModel, options: any) => Promise<void>;
23
25
  registerTrigger<T extends Trigger>(type: string, trigger: T | {
24
26
  new (p: Plugin): T;
@@ -32,7 +34,8 @@ export default class PluginWorkflowServer extends Plugin {
32
34
  toggle(workflow: WorkflowModel, enable?: boolean): void;
33
35
  trigger(workflow: WorkflowModel, context: object, options?: {
34
36
  context?: any;
35
- }): void;
37
+ } & Transactionable): void | Promise<Processor | null>;
38
+ private triggerSync;
36
39
  resume(job: any): Promise<void>;
37
40
  createProcessor(execution: ExecutionModel, options?: {}): Processor;
38
41
  private createExecution;
@@ -43,6 +43,7 @@ var import_CollectionTrigger = __toESM(require("./triggers/CollectionTrigger"));
43
43
  var import_ScheduleTrigger = __toESM(require("./triggers/ScheduleTrigger"));
44
44
  var import_CalculationInstruction = __toESM(require("./instructions/CalculationInstruction"));
45
45
  var import_ConditionInstruction = __toESM(require("./instructions/ConditionInstruction"));
46
+ var import_EndInstruction = __toESM(require("./instructions/EndInstruction"));
46
47
  var import_CreateInstruction = __toESM(require("./instructions/CreateInstruction"));
47
48
  var import_DestroyInstruction = __toESM(require("./instructions/DestroyInstruction"));
48
49
  var import_QueryInstruction = __toESM(require("./instructions/QueryInstruction"));
@@ -73,6 +74,13 @@ class PluginWorkflowServer extends import_server.Plugin {
73
74
  this.loggerCache.set(key, logger);
74
75
  return logger;
75
76
  }
77
+ isWorkflowSync(workflow) {
78
+ const trigger = this.triggers.get(workflow.type);
79
+ if (!trigger) {
80
+ throw new Error(`invalid trigger type ${workflow.type} of workflow ${workflow.id}`);
81
+ }
82
+ return trigger.sync ?? workflow.sync;
83
+ }
76
84
  onBeforeSave = async (instance, options) => {
77
85
  const Model = instance.constructor;
78
86
  if (instance.enabled) {
@@ -140,6 +148,7 @@ class PluginWorkflowServer extends import_server.Plugin {
140
148
  initInstructions(more = {}) {
141
149
  this.registerInstruction("calculation", import_CalculationInstruction.default);
142
150
  this.registerInstruction("condition", import_ConditionInstruction.default);
151
+ this.registerInstruction("end", import_EndInstruction.default);
143
152
  this.registerInstruction("create", import_CreateInstruction.default);
144
153
  this.registerInstruction("destroy", import_DestroyInstruction.default);
145
154
  this.registerInstruction("query", import_QueryInstruction.default);
@@ -231,7 +240,7 @@ class PluginWorkflowServer extends import_server.Plugin {
231
240
  this.getLogger(workflow.id).error(`trigger type ${workflow.type} of workflow ${workflow.id} is not implemented`);
232
241
  return;
233
242
  }
234
- if (typeof enable !== "undefined" ? enable : workflow.get("enabled")) {
243
+ if (enable ?? workflow.get("enabled")) {
235
244
  const prev = workflow.previous();
236
245
  if (prev.config) {
237
246
  trigger.off({ ...workflow.get(), ...prev });
@@ -245,14 +254,17 @@ class PluginWorkflowServer extends import_server.Plugin {
245
254
  const logger = this.getLogger(workflow.id);
246
255
  if (!this.ready) {
247
256
  logger.warn(`app is not ready, event of workflow ${workflow.id} will be ignored`);
248
- logger.debug(`ignored event data:`, { data: context });
257
+ logger.debug(`ignored event data:`, context);
249
258
  return;
250
259
  }
251
260
  if (context == null) {
252
261
  logger.warn(`workflow ${workflow.id} event data context is null, event will be ignored`);
253
262
  return;
254
263
  }
255
- this.events.push([workflow, context, options]);
264
+ if (this.isWorkflowSync(workflow)) {
265
+ return this.triggerSync(workflow, context, options);
266
+ }
267
+ this.events.push([workflow, context, { context: options.context }]);
256
268
  this.eventsCount = this.events.length;
257
269
  logger.info(`new event triggered, now events: ${this.events.length}`);
258
270
  logger.debug(`event data:`, {
@@ -263,6 +275,21 @@ class PluginWorkflowServer extends import_server.Plugin {
263
275
  }
264
276
  setTimeout(this.prepare);
265
277
  }
278
+ async triggerSync(workflow, context, options = {}) {
279
+ let execution;
280
+ try {
281
+ execution = await this.createExecution(workflow, context, options);
282
+ } catch (err) {
283
+ this.getLogger(workflow.id).error(`creating execution failed: ${err.message}`, err);
284
+ return null;
285
+ }
286
+ try {
287
+ return this.process(execution, null, options);
288
+ } catch (err) {
289
+ this.getLogger(execution.workflowId).error(`execution (${execution.id}) error: ${err.message}`, err);
290
+ }
291
+ return null;
292
+ }
266
293
  async resume(job) {
267
294
  if (!job.execution) {
268
295
  job.execution = await job.getExecution();
@@ -276,52 +303,50 @@ class PluginWorkflowServer extends import_server.Plugin {
276
303
  createProcessor(execution, options = {}) {
277
304
  return new import_Processor.default(execution, { ...options, plugin: this });
278
305
  }
279
- async createExecution(event) {
280
- var _a;
281
- const [workflow, context, options] = event;
282
- if ((_a = options.context) == null ? void 0 : _a.executionId) {
283
- const existed = await workflow.countExecutions({
284
- where: {
285
- id: options.context.executionId
286
- }
287
- });
288
- if (existed) {
289
- this.getLogger(workflow.id).warn(
290
- `workflow ${workflow.id} has already been triggered in same execution (${options.context.executionId}), and newly triggering will be skipped.`
291
- );
292
- return null;
306
+ async createExecution(workflow, context, options) {
307
+ const { transaction = await this.db.sequelize.transaction() } = options;
308
+ const trigger = this.triggers.get(workflow.type);
309
+ const valid = await trigger.validateEvent(workflow, context, { ...options, transaction });
310
+ if (!valid) {
311
+ if (!options.transaction) {
312
+ await transaction.commit();
293
313
  }
314
+ return null;
294
315
  }
295
- return this.db.sequelize.transaction(async (transaction) => {
296
- const execution = await workflow.createExecution(
297
- {
298
- context,
299
- key: workflow.key,
300
- status: import_constants.EXECUTION_STATUS.QUEUEING
316
+ const execution = await workflow.createExecution(
317
+ {
318
+ context,
319
+ key: workflow.key,
320
+ status: import_constants.EXECUTION_STATUS.QUEUEING
321
+ },
322
+ { transaction }
323
+ );
324
+ this.getLogger(workflow.id).info(`execution of workflow ${workflow.id} created as ${execution.id}`);
325
+ await workflow.increment(["executed", "allExecuted"], { transaction });
326
+ if (this.db.options.dialect !== "postgres") {
327
+ await workflow.reload({ transaction });
328
+ }
329
+ await workflow.constructor.update(
330
+ {
331
+ allExecuted: workflow.allExecuted
332
+ },
333
+ {
334
+ where: {
335
+ key: workflow.key
301
336
  },
302
- { transaction }
303
- );
304
- this.getLogger(workflow.id).info(`execution of workflow ${workflow.id} created as ${execution.id}`);
305
- await workflow.increment(["executed", "allExecuted"], { transaction });
306
- if (this.db.options.dialect !== "postgres") {
307
- await workflow.reload({ transaction });
337
+ transaction
308
338
  }
309
- await workflow.constructor.update(
310
- {
311
- allExecuted: workflow.allExecuted
312
- },
313
- {
314
- where: {
315
- key: workflow.key
316
- },
317
- transaction
318
- }
319
- );
320
- execution.workflow = workflow;
321
- return execution;
322
- });
339
+ );
340
+ if (!options.transaction) {
341
+ await transaction.commit();
342
+ }
343
+ execution.workflow = workflow;
344
+ return execution;
323
345
  }
324
346
  prepare = async () => {
347
+ if (this.executing && this.db.options.dialect === "sqlite") {
348
+ await this.executing;
349
+ }
325
350
  const event = this.events.shift();
326
351
  this.eventsCount = this.events.length;
327
352
  if (!event) {
@@ -331,8 +356,8 @@ class PluginWorkflowServer extends import_server.Plugin {
331
356
  const logger = this.getLogger(event[0].id);
332
357
  logger.info(`preparing execution for event`);
333
358
  try {
334
- const execution = await this.createExecution(event);
335
- if (!this.executing && !this.pending.length) {
359
+ const execution = await this.createExecution(...event);
360
+ if (execution && !this.executing && !this.pending.length) {
336
361
  this.pending.push([execution]);
337
362
  }
338
363
  } catch (err) {
@@ -353,6 +378,9 @@ class PluginWorkflowServer extends import_server.Plugin {
353
378
  this.getLogger("dispatcher").warn(`workflow executing is not finished, new dispatching will be ignored`);
354
379
  return;
355
380
  }
381
+ if (this.events.length) {
382
+ return this.prepare();
383
+ }
356
384
  this.executing = (async () => {
357
385
  let next = null;
358
386
  if (this.pending.length) {
@@ -384,12 +412,12 @@ class PluginWorkflowServer extends import_server.Plugin {
384
412
  }
385
413
  })();
386
414
  }
387
- async process(execution, job) {
415
+ async process(execution, job, { transaction } = {}) {
388
416
  var _a, _b;
389
417
  if (execution.status === import_constants.EXECUTION_STATUS.QUEUEING) {
390
- await execution.update({ status: import_constants.EXECUTION_STATUS.STARTED });
418
+ await execution.update({ status: import_constants.EXECUTION_STATUS.STARTED }, { transaction });
391
419
  }
392
- const processor = this.createProcessor(execution);
420
+ const processor = this.createProcessor(execution, { transaction });
393
421
  this.getLogger(execution.workflowId).info(`execution (${execution.id}) ${job ? "resuming" : "starting"}...`);
394
422
  try {
395
423
  await (job ? processor.resume(job) : processor.start());
@@ -402,5 +430,6 @@ class PluginWorkflowServer extends import_server.Plugin {
402
430
  } catch (err) {
403
431
  this.getLogger(execution.workflowId).error(`execution (${execution.id}) error: ${err.message}`, err);
404
432
  }
433
+ return processor;
405
434
  }
406
435
  }
@@ -1,4 +1,4 @@
1
- import { Transactionable } from '@nocobase/database';
1
+ import { Transaction, Transactionable } from '@nocobase/database';
2
2
  import { Logger } from '@nocobase/logger';
3
3
  import type Plugin from './Plugin';
4
4
  import type { ExecutionModel, FlowNodeModel, JobModel } from './types';
@@ -19,12 +19,14 @@ export default class Processor {
19
19
  [-6]: -6;
20
20
  };
21
21
  logger: Logger;
22
+ transaction: Transaction;
22
23
  nodes: FlowNodeModel[];
23
24
  nodesMap: Map<number, FlowNodeModel>;
24
25
  jobsMap: Map<number, JobModel>;
25
26
  jobsMapByNodeKey: {
26
27
  [key: string]: any;
27
28
  };
29
+ lastSavedJob: JobModel | null;
28
30
  constructor(execution: ExecutionModel, options: ProcessorOptions);
29
31
  private makeNodes;
30
32
  private makeJobs;