@gadmin2n/schematics 0.0.150 → 0.0.152
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.md +125 -36
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +42 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/gitignore +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.seed-timestamp +0 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/check-dev-env.js +218 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/page-manage.ts +78 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +37 -67
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/index.ts +0 -17
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agenda/agenda.controller.ts +46 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.controller.ts +60 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-callback.controller.ts +3 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.controller.ts +9 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.ts +55 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.module.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/page-transfer.service.ts +491 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/perm-transfer.dto.ts +213 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/perm-transfer.module.ts +28 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/resource-transfer.service.ts +137 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/role-transfer.service.ts +248 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/transfer-token.service.ts +65 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/user-transfer.service.ts +146 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.ts +55 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.module.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.ts +55 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.module.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.spec.ts +46 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.ts +3 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +55 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.module.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +96 -14
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +41 -41
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-database-function.spec.ts +36 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-database-function.ts +90 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-catalog.spec.ts +4 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-trigger.pg.spec.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution-idempotency.spec.ts +115 -63
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-outbox.service.spec.ts +166 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-outbox.service.ts +217 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.spec.ts +33 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.ts +57 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.spec.ts +196 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.ts +125 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-node-type.controller.ts +9 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +148 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.module.ts +12 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +14 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +75 -45
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +25 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/TransferExportModal.tsx +115 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/TransferImportModal.tsx +257 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +0 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +40 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +15 -13
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +40 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +15 -13
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +2 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/list.tsx +89 -65
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/list.tsx +51 -127
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/permissionReadme/index.tsx +53 -109
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/list.tsx +45 -41
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/list.tsx +51 -72
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/list.tsx +49 -40
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +16 -5
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ReadonlyNodePanel.test.tsx +28 -10
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.test.tsx +60 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +94 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-instance-show.css +13 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/default-widgets.tsx +3 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +8 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +167 -94
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerConfigEditor.tsx +95 -95
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerLifecycleConfigEditor.test.tsx +81 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerLifecycleConfigEditor.tsx +126 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +48 -52
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/forEachConnection.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +1 -3
- package/package.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.local.md +0 -8
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/ac.config.ts +0 -24
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/SqlModal.tsx +0 -495
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { Prisma, WorkflowInstanceStatus } from '@prisma/client';
|
|
3
|
+
import { PrismaService } from 'nestjs-prisma';
|
|
4
|
+
|
|
5
|
+
export interface MarkWorkflowInstanceFailedInput {
|
|
6
|
+
instanceId: bigint;
|
|
7
|
+
expectedStatuses: WorkflowInstanceStatus[];
|
|
8
|
+
temporalRunId?: string | null;
|
|
9
|
+
result: Prisma.InputJsonValue;
|
|
10
|
+
startedAt?: Date;
|
|
11
|
+
finishedAt?: Date;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WorkflowFailureCallback {
|
|
15
|
+
connectionRef: string;
|
|
16
|
+
path: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Injectable()
|
|
20
|
+
export class WorkflowLifecycleService {
|
|
21
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
22
|
+
|
|
23
|
+
async markFailed(input: MarkWorkflowInstanceFailedInput): Promise<boolean> {
|
|
24
|
+
return this.prisma.$transaction(async (tx) => {
|
|
25
|
+
const failedAt = input.finishedAt ?? new Date();
|
|
26
|
+
const updated = await tx.workflowInstance.updateMany({
|
|
27
|
+
where: {
|
|
28
|
+
id: input.instanceId,
|
|
29
|
+
status: { in: input.expectedStatuses },
|
|
30
|
+
...(input.temporalRunId !== undefined && {
|
|
31
|
+
temporalRunId: input.temporalRunId,
|
|
32
|
+
}),
|
|
33
|
+
},
|
|
34
|
+
data: {
|
|
35
|
+
status: 'FAILED',
|
|
36
|
+
result: input.result,
|
|
37
|
+
...(input.startedAt && { startedAt: input.startedAt }),
|
|
38
|
+
finishedAt: failedAt,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
if (updated.count !== 1) return false;
|
|
42
|
+
|
|
43
|
+
const instance = await tx.workflowInstance.findUniqueOrThrow({
|
|
44
|
+
where: { id: input.instanceId },
|
|
45
|
+
select: {
|
|
46
|
+
versionId: true,
|
|
47
|
+
sourceOutboxId: true,
|
|
48
|
+
workflow: { select: { code: true } },
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
if (instance.sourceOutboxId === null) return true;
|
|
52
|
+
|
|
53
|
+
const version = await tx.workflowVersion.findUniqueOrThrow({
|
|
54
|
+
where: { id: instance.versionId },
|
|
55
|
+
select: { dsl: true },
|
|
56
|
+
});
|
|
57
|
+
const callback = extractWorkflowFailureCallback(version.dsl);
|
|
58
|
+
if (!callback) return true;
|
|
59
|
+
|
|
60
|
+
const source = await tx.workflowEventOutbox.findUnique({
|
|
61
|
+
where: { id: instance.sourceOutboxId },
|
|
62
|
+
select: {
|
|
63
|
+
schemaName: true,
|
|
64
|
+
tableName: true,
|
|
65
|
+
operation: true,
|
|
66
|
+
primaryKey: true,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
if (!source)
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Workflow event ${instance.sourceOutboxId} was not found for lifecycle notification`,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const eventKey = `workflow-instance:${input.instanceId}:FAILED`;
|
|
75
|
+
await tx.workflowLifecycleOutbox.upsert({
|
|
76
|
+
where: { eventKey },
|
|
77
|
+
create: {
|
|
78
|
+
eventKey,
|
|
79
|
+
workflowInstanceId: input.instanceId,
|
|
80
|
+
eventType: 'FAILED',
|
|
81
|
+
workflowCode: instance.workflow.code,
|
|
82
|
+
businessReference: {
|
|
83
|
+
schema: source.schemaName,
|
|
84
|
+
table: source.tableName,
|
|
85
|
+
operation: source.operation,
|
|
86
|
+
primaryKey: source.primaryKey,
|
|
87
|
+
},
|
|
88
|
+
connectionRef: callback.connectionRef,
|
|
89
|
+
callbackPath: callback.path,
|
|
90
|
+
failedAt,
|
|
91
|
+
},
|
|
92
|
+
update: {},
|
|
93
|
+
});
|
|
94
|
+
return true;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function extractWorkflowFailureCallback(
|
|
100
|
+
dsl: unknown,
|
|
101
|
+
): WorkflowFailureCallback | null {
|
|
102
|
+
const nodes = asRecord(dsl).nodes;
|
|
103
|
+
if (!Array.isArray(nodes)) return null;
|
|
104
|
+
const trigger = nodes
|
|
105
|
+
.map(asRecord)
|
|
106
|
+
.find((node) => node.type === 'event_trigger');
|
|
107
|
+
if (!trigger) return null;
|
|
108
|
+
const config = asRecord(trigger.config);
|
|
109
|
+
if (config.failureCallback === undefined) return null;
|
|
110
|
+
const callback = asRecord(config.failureCallback);
|
|
111
|
+
const connectionRef =
|
|
112
|
+
typeof callback.connectionRef === 'string'
|
|
113
|
+
? callback.connectionRef.trim()
|
|
114
|
+
: '';
|
|
115
|
+
const path = typeof callback.path === 'string' ? callback.path.trim() : '';
|
|
116
|
+
if (!connectionRef || !path.startsWith('/'))
|
|
117
|
+
throw new Error('WORKFLOW_FAILURE_CALLBACK_CONFIG_INVALID');
|
|
118
|
+
return { connectionRef, path };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function asRecord(value: unknown): Record<string, any> {
|
|
122
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
123
|
+
? (value as Record<string, any>)
|
|
124
|
+
: {};
|
|
125
|
+
}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
import { ACGuard } from '@gadmin2n/nest-common';
|
|
1
2
|
import { Controller, Get, UseGuards } from '@nestjs/common';
|
|
2
3
|
import { ApiTags } from '@nestjs/swagger';
|
|
3
|
-
import
|
|
4
|
+
import { UseRoles } from 'nest-access-control';
|
|
4
5
|
import { WorkflowNodeTypeService } from './workflow-node-type.service';
|
|
5
6
|
|
|
6
|
-
@
|
|
7
|
-
@UseGuards(AuthGuard)
|
|
7
|
+
@UseGuards(ACGuard)
|
|
8
8
|
@Controller('workflow-node-types')
|
|
9
|
+
@ApiTags('workflow-node-types')
|
|
9
10
|
export class WorkflowNodeTypeController {
|
|
10
11
|
constructor(private readonly service: WorkflowNodeTypeService) {}
|
|
11
12
|
|
|
12
13
|
@Get()
|
|
14
|
+
@UseRoles({
|
|
15
|
+
resource: 'workflow',
|
|
16
|
+
action: 'read',
|
|
17
|
+
possession: 'any',
|
|
18
|
+
})
|
|
13
19
|
findAll() {
|
|
14
20
|
return this.service.findAll();
|
|
15
21
|
}
|
|
@@ -22,6 +22,7 @@ import { UseRoles } from 'nest-access-control';
|
|
|
22
22
|
import { PrismaService } from 'nestjs-prisma';
|
|
23
23
|
import { AllowUnauthorizedRequest } from '../../lib/auth.guard';
|
|
24
24
|
import { TemporalService } from './temporal.service';
|
|
25
|
+
import { listWorkflowDatabaseFunctions } from './workflow-database-function';
|
|
25
26
|
import {
|
|
26
27
|
ApproveInstanceDto,
|
|
27
28
|
ExecuteWorkflowDto,
|
|
@@ -43,8 +44,9 @@ import {
|
|
|
43
44
|
} from './workflow.dto';
|
|
44
45
|
import { WorkflowService } from './workflow.service';
|
|
45
46
|
|
|
46
|
-
@
|
|
47
|
+
@UseGuards(ACGuard)
|
|
47
48
|
@Controller('workflow')
|
|
49
|
+
@ApiTags('workflow')
|
|
48
50
|
export class WorkflowController {
|
|
49
51
|
constructor(
|
|
50
52
|
private readonly workflowService: WorkflowService,
|
|
@@ -55,6 +57,11 @@ export class WorkflowController {
|
|
|
55
57
|
) {}
|
|
56
58
|
|
|
57
59
|
@Get()
|
|
60
|
+
@UseRoles({
|
|
61
|
+
resource: 'workflow',
|
|
62
|
+
action: 'read',
|
|
63
|
+
possession: 'any',
|
|
64
|
+
})
|
|
58
65
|
findAll(@Query() query: WorkflowListQueryDto) {
|
|
59
66
|
return this.workflowService.findMany({
|
|
60
67
|
status: query.status,
|
|
@@ -66,7 +73,6 @@ export class WorkflowController {
|
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
@Post('event-catalog/register')
|
|
69
|
-
@UseGuards(ACGuard)
|
|
70
76
|
@UseRoles({
|
|
71
77
|
resource: 'workflowEventRegistration',
|
|
72
78
|
action: 'create',
|
|
@@ -77,31 +83,71 @@ export class WorkflowController {
|
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
@Get('overview')
|
|
86
|
+
@UseRoles({
|
|
87
|
+
resource: 'workflow',
|
|
88
|
+
action: 'read',
|
|
89
|
+
possession: 'any',
|
|
90
|
+
})
|
|
80
91
|
getOverview() {
|
|
81
92
|
return this.workflowService.getOverview();
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
@Get('callable')
|
|
96
|
+
@UseRoles({
|
|
97
|
+
resource: 'workflow',
|
|
98
|
+
action: 'read',
|
|
99
|
+
possession: 'any',
|
|
100
|
+
})
|
|
85
101
|
findCallable() {
|
|
86
102
|
return this.workflowService.findCallableWorkflows();
|
|
87
103
|
}
|
|
88
104
|
|
|
89
105
|
@Get('external-interaction-options')
|
|
106
|
+
@UseRoles({
|
|
107
|
+
resource: 'workflow',
|
|
108
|
+
action: 'read',
|
|
109
|
+
possession: 'any',
|
|
110
|
+
})
|
|
90
111
|
findExternalInteractionOptions() {
|
|
91
112
|
return this.workflowService.findExternalInteractionOptions();
|
|
92
113
|
}
|
|
93
114
|
|
|
115
|
+
@Get('database-functions')
|
|
116
|
+
@UseRoles({
|
|
117
|
+
resource: 'workflow',
|
|
118
|
+
action: 'read',
|
|
119
|
+
possession: 'any',
|
|
120
|
+
})
|
|
121
|
+
findDatabaseFunctions() {
|
|
122
|
+
return listWorkflowDatabaseFunctions(this.prisma);
|
|
123
|
+
}
|
|
124
|
+
|
|
94
125
|
@Get('event-catalog/overview')
|
|
126
|
+
@UseRoles({
|
|
127
|
+
resource: 'workflowEventRegistration',
|
|
128
|
+
action: 'read',
|
|
129
|
+
possession: 'any',
|
|
130
|
+
})
|
|
95
131
|
findBusinessEventCatalogOverview() {
|
|
96
132
|
return this.workflowService.findBusinessEventCatalogOverview();
|
|
97
133
|
}
|
|
98
134
|
|
|
99
135
|
@Get('event-catalog/sources')
|
|
136
|
+
@UseRoles({
|
|
137
|
+
resource: 'workflowEventRegistration',
|
|
138
|
+
action: 'read',
|
|
139
|
+
possession: 'any',
|
|
140
|
+
})
|
|
100
141
|
findBusinessEventSources() {
|
|
101
142
|
return this.workflowService.findBusinessEventSources();
|
|
102
143
|
}
|
|
103
144
|
|
|
104
145
|
@Get('event-catalog/:registrationCode/instances')
|
|
146
|
+
@UseRoles({
|
|
147
|
+
resource: 'workflowEventRegistration',
|
|
148
|
+
action: 'read',
|
|
149
|
+
possession: 'any',
|
|
150
|
+
})
|
|
105
151
|
findBusinessEventInstances(
|
|
106
152
|
@Param('registrationCode') registrationCode: string,
|
|
107
153
|
@Query() query: WorkflowInstanceListQueryDto,
|
|
@@ -114,7 +160,6 @@ export class WorkflowController {
|
|
|
114
160
|
}
|
|
115
161
|
|
|
116
162
|
@Post('event-catalog/unregister')
|
|
117
|
-
@UseGuards(ACGuard)
|
|
118
163
|
@UseRoles({
|
|
119
164
|
resource: 'workflowEventRegistration',
|
|
120
165
|
action: 'delete',
|
|
@@ -125,6 +170,11 @@ export class WorkflowController {
|
|
|
125
170
|
}
|
|
126
171
|
|
|
127
172
|
@Get('event-catalog')
|
|
173
|
+
@UseRoles({
|
|
174
|
+
resource: 'workflowEventRegistration',
|
|
175
|
+
action: 'read',
|
|
176
|
+
possession: 'any',
|
|
177
|
+
})
|
|
128
178
|
findBusinessEventCatalog() {
|
|
129
179
|
return this.workflowService.findBusinessEventCatalog();
|
|
130
180
|
}
|
|
@@ -132,6 +182,11 @@ export class WorkflowController {
|
|
|
132
182
|
// ─── Export/Import Endpoints ──────────────────────────────────────────────────
|
|
133
183
|
|
|
134
184
|
@Post(':id/export-token')
|
|
185
|
+
@UseRoles({
|
|
186
|
+
resource: 'workflow',
|
|
187
|
+
action: 'read',
|
|
188
|
+
possession: 'any',
|
|
189
|
+
})
|
|
135
190
|
async generateExportToken(@Param('id', ParseIntPipe) id: number, @Req() req) {
|
|
136
191
|
const baseUrl = `${req.protocol}://${req.get('host')}/api`;
|
|
137
192
|
return this.workflowExportService.generateExportToken(BigInt(id), baseUrl);
|
|
@@ -150,11 +205,21 @@ export class WorkflowController {
|
|
|
150
205
|
}
|
|
151
206
|
|
|
152
207
|
@Post('import-preview')
|
|
208
|
+
@UseRoles({
|
|
209
|
+
resource: 'workflow',
|
|
210
|
+
action: 'update',
|
|
211
|
+
possession: 'any',
|
|
212
|
+
})
|
|
153
213
|
async importPreview(@Body() dto: ImportPayloadDto) {
|
|
154
214
|
return this.workflowExportService.importPreview(dto.payload);
|
|
155
215
|
}
|
|
156
216
|
|
|
157
217
|
@Post('import-confirm')
|
|
218
|
+
@UseRoles({
|
|
219
|
+
resource: 'workflow',
|
|
220
|
+
action: 'update',
|
|
221
|
+
possession: 'any',
|
|
222
|
+
})
|
|
158
223
|
async importConfirm(@Body() dto: ImportPayloadDto, @Req() req) {
|
|
159
224
|
return this.workflowExportService.importConfirm(
|
|
160
225
|
dto.payload,
|
|
@@ -163,16 +228,31 @@ export class WorkflowController {
|
|
|
163
228
|
}
|
|
164
229
|
|
|
165
230
|
@Post()
|
|
231
|
+
@UseRoles({
|
|
232
|
+
resource: 'workflow',
|
|
233
|
+
action: 'create',
|
|
234
|
+
possession: 'any',
|
|
235
|
+
})
|
|
166
236
|
create(@Req() req, @Body() dto: CreateWorkflowDto) {
|
|
167
237
|
return this.workflowService.create(dto, req.user.userid);
|
|
168
238
|
}
|
|
169
239
|
|
|
170
240
|
@Get(':id')
|
|
241
|
+
@UseRoles({
|
|
242
|
+
resource: 'workflow',
|
|
243
|
+
action: 'read',
|
|
244
|
+
possession: 'any',
|
|
245
|
+
})
|
|
171
246
|
findOne(@Param('id', ParseIntPipe) id: number) {
|
|
172
247
|
return this.workflowService.findOne(BigInt(id));
|
|
173
248
|
}
|
|
174
249
|
|
|
175
250
|
@Patch(':id')
|
|
251
|
+
@UseRoles({
|
|
252
|
+
resource: 'workflow',
|
|
253
|
+
action: 'update',
|
|
254
|
+
possession: 'any',
|
|
255
|
+
})
|
|
176
256
|
update(
|
|
177
257
|
@Param('id', ParseIntPipe) id: number,
|
|
178
258
|
@Body() dto: UpdateWorkflowDto,
|
|
@@ -181,11 +261,21 @@ export class WorkflowController {
|
|
|
181
261
|
}
|
|
182
262
|
|
|
183
263
|
@Patch(':id/save')
|
|
264
|
+
@UseRoles({
|
|
265
|
+
resource: 'workflow',
|
|
266
|
+
action: 'update',
|
|
267
|
+
possession: 'any',
|
|
268
|
+
})
|
|
184
269
|
saveDraft(@Param('id', ParseIntPipe) id: number, @Body() dto: SaveDraftDto) {
|
|
185
270
|
return this.workflowService.saveDraft(BigInt(id), dto.dsl);
|
|
186
271
|
}
|
|
187
272
|
|
|
188
273
|
@Patch(':id/toggle')
|
|
274
|
+
@UseRoles({
|
|
275
|
+
resource: 'workflow',
|
|
276
|
+
action: 'update',
|
|
277
|
+
possession: 'any',
|
|
278
|
+
})
|
|
189
279
|
toggleEnabled(
|
|
190
280
|
@Param('id', ParseIntPipe) id: number,
|
|
191
281
|
@Body() dto: ToggleEnabledDto,
|
|
@@ -194,16 +284,31 @@ export class WorkflowController {
|
|
|
194
284
|
}
|
|
195
285
|
|
|
196
286
|
@Delete(':id')
|
|
287
|
+
@UseRoles({
|
|
288
|
+
resource: 'workflow',
|
|
289
|
+
action: 'delete',
|
|
290
|
+
possession: 'any',
|
|
291
|
+
})
|
|
197
292
|
remove(@Param('id', ParseIntPipe) id: number) {
|
|
198
293
|
return this.workflowService.remove(BigInt(id));
|
|
199
294
|
}
|
|
200
295
|
|
|
201
296
|
@Get(':id/versions')
|
|
297
|
+
@UseRoles({
|
|
298
|
+
resource: 'workflow',
|
|
299
|
+
action: 'read',
|
|
300
|
+
possession: 'any',
|
|
301
|
+
})
|
|
202
302
|
getVersions(@Param('id', ParseIntPipe) id: number) {
|
|
203
303
|
return this.workflowService.getVersions(BigInt(id));
|
|
204
304
|
}
|
|
205
305
|
|
|
206
306
|
@Get(':id/versions/:version')
|
|
307
|
+
@UseRoles({
|
|
308
|
+
resource: 'workflow',
|
|
309
|
+
action: 'read',
|
|
310
|
+
possession: 'any',
|
|
311
|
+
})
|
|
207
312
|
getVersionDsl(
|
|
208
313
|
@Param('id', ParseIntPipe) id: number,
|
|
209
314
|
@Param('version', ParseIntPipe) version: number,
|
|
@@ -212,6 +317,11 @@ export class WorkflowController {
|
|
|
212
317
|
}
|
|
213
318
|
|
|
214
319
|
@Post(':id/publish')
|
|
320
|
+
@UseRoles({
|
|
321
|
+
resource: 'workflow',
|
|
322
|
+
action: 'update',
|
|
323
|
+
possession: 'any',
|
|
324
|
+
})
|
|
215
325
|
publish(
|
|
216
326
|
@Param('id', ParseIntPipe) id: number,
|
|
217
327
|
@Req() req,
|
|
@@ -221,6 +331,11 @@ export class WorkflowController {
|
|
|
221
331
|
}
|
|
222
332
|
|
|
223
333
|
@Get(':id/instances')
|
|
334
|
+
@UseRoles({
|
|
335
|
+
resource: 'workflowExecution',
|
|
336
|
+
action: 'read',
|
|
337
|
+
possession: 'any',
|
|
338
|
+
})
|
|
224
339
|
getInstances(
|
|
225
340
|
@Param('id', ParseIntPipe) id: number,
|
|
226
341
|
@Query() query: WorkflowInstanceListQueryDto,
|
|
@@ -233,6 +348,11 @@ export class WorkflowController {
|
|
|
233
348
|
}
|
|
234
349
|
|
|
235
350
|
@Get(':id/stats')
|
|
351
|
+
@UseRoles({
|
|
352
|
+
resource: 'workflow',
|
|
353
|
+
action: 'read',
|
|
354
|
+
possession: 'any',
|
|
355
|
+
})
|
|
236
356
|
getStats(@Param('id', ParseIntPipe) id: number) {
|
|
237
357
|
return this.workflowService.getStats(BigInt(id));
|
|
238
358
|
}
|
|
@@ -240,7 +360,6 @@ export class WorkflowController {
|
|
|
240
360
|
// ─── Execution Endpoints ──────────────────────────────────────────────────────
|
|
241
361
|
|
|
242
362
|
@Post('actions/:code/execute')
|
|
243
|
-
@UseGuards(ACGuard)
|
|
244
363
|
@UseRoles({
|
|
245
364
|
resource: 'workflowExecution',
|
|
246
365
|
action: 'create',
|
|
@@ -261,6 +380,11 @@ export class WorkflowController {
|
|
|
261
380
|
}
|
|
262
381
|
|
|
263
382
|
@Get('instance/:instanceId')
|
|
383
|
+
@UseRoles({
|
|
384
|
+
resource: 'workflowExecution',
|
|
385
|
+
action: 'read',
|
|
386
|
+
possession: 'any',
|
|
387
|
+
})
|
|
264
388
|
getInstanceDetail(
|
|
265
389
|
@Param('instanceId', ParseIntPipe) instanceId: number,
|
|
266
390
|
@Req() req,
|
|
@@ -272,6 +396,11 @@ export class WorkflowController {
|
|
|
272
396
|
}
|
|
273
397
|
|
|
274
398
|
@Post('instance/:instanceId/cancel')
|
|
399
|
+
@UseRoles({
|
|
400
|
+
resource: 'workflowExecution',
|
|
401
|
+
action: 'update',
|
|
402
|
+
possession: 'any',
|
|
403
|
+
})
|
|
275
404
|
async cancelInstance(
|
|
276
405
|
@Param('instanceId', ParseIntPipe) instanceId: number,
|
|
277
406
|
@Req() req,
|
|
@@ -286,6 +415,11 @@ export class WorkflowController {
|
|
|
286
415
|
}
|
|
287
416
|
|
|
288
417
|
@Post('instance/:instanceId/retry')
|
|
418
|
+
@UseRoles({
|
|
419
|
+
resource: 'workflowExecution',
|
|
420
|
+
action: 'update',
|
|
421
|
+
possession: 'any',
|
|
422
|
+
})
|
|
289
423
|
async retryInstance(
|
|
290
424
|
@Param('instanceId', ParseIntPipe) instanceId: number,
|
|
291
425
|
@Req() req,
|
|
@@ -298,6 +432,11 @@ export class WorkflowController {
|
|
|
298
432
|
}
|
|
299
433
|
|
|
300
434
|
@Post('instance/:instanceId/retry-from-node')
|
|
435
|
+
@UseRoles({
|
|
436
|
+
resource: 'workflowExecution',
|
|
437
|
+
action: 'update',
|
|
438
|
+
possession: 'any',
|
|
439
|
+
})
|
|
301
440
|
async retryInstanceFromNode(
|
|
302
441
|
@Param('instanceId', ParseIntPipe) instanceId: number,
|
|
303
442
|
@Body() dto: RetryFromNodeDto,
|
|
@@ -312,6 +451,11 @@ export class WorkflowController {
|
|
|
312
451
|
}
|
|
313
452
|
|
|
314
453
|
@Post('instance/:instanceId/approve')
|
|
454
|
+
@UseRoles({
|
|
455
|
+
resource: 'workflowExecution',
|
|
456
|
+
action: 'update',
|
|
457
|
+
possession: 'any',
|
|
458
|
+
})
|
|
315
459
|
async approveInstance(
|
|
316
460
|
@Param('instanceId', ParseIntPipe) instanceId: number,
|
|
317
461
|
@Body() dto: ApproveInstanceDto,
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { Module } from '@nestjs/common';
|
|
2
2
|
import { HttpRequestModule } from '../httpRequest/httpRequest.module';
|
|
3
3
|
import { HumanApprovalModule } from '../humanApproval/humanApproval.module';
|
|
4
|
+
import { IntegrationConnectionModule } from '../integrationConnection/integrationConnection.module';
|
|
4
5
|
import { UserModule } from '../user/user.module';
|
|
5
6
|
import { WorkflowConfigModule } from '../workflowConfig/workflowConfig.module';
|
|
6
7
|
import { TemporalModule } from './temporal.module';
|
|
7
8
|
import { WorkflowCompilerService } from './workflow-compiler.service';
|
|
8
9
|
import { WorkflowExportService } from './workflow-export.service';
|
|
10
|
+
import { WorkflowLifecycleOutboxService } from './workflow-lifecycle-outbox.service';
|
|
11
|
+
import { WorkflowLifecycleRuntimeController } from './workflow-lifecycle-runtime.controller';
|
|
12
|
+
import { WorkflowLifecycleService } from './workflow-lifecycle.service';
|
|
9
13
|
import { WorkflowNodeTypeController } from './workflow-node-type.controller';
|
|
10
14
|
import { WorkflowNodeTypeService } from './workflow-node-type.service';
|
|
11
15
|
import { WorkflowRuntimeFacade } from './workflow-runtime.facade';
|
|
@@ -18,15 +22,22 @@ import { WorkflowService } from './workflow.service';
|
|
|
18
22
|
TemporalModule,
|
|
19
23
|
HumanApprovalModule,
|
|
20
24
|
HttpRequestModule,
|
|
25
|
+
IntegrationConnectionModule,
|
|
21
26
|
WorkflowConfigModule,
|
|
22
27
|
],
|
|
23
|
-
controllers: [
|
|
28
|
+
controllers: [
|
|
29
|
+
WorkflowController,
|
|
30
|
+
WorkflowNodeTypeController,
|
|
31
|
+
WorkflowLifecycleRuntimeController,
|
|
32
|
+
],
|
|
24
33
|
providers: [
|
|
25
34
|
WorkflowService,
|
|
26
35
|
WorkflowNodeTypeService,
|
|
27
36
|
WorkflowExportService,
|
|
28
37
|
WorkflowCompilerService,
|
|
29
38
|
WorkflowRuntimeFacade,
|
|
39
|
+
WorkflowLifecycleService,
|
|
40
|
+
WorkflowLifecycleOutboxService,
|
|
30
41
|
],
|
|
31
42
|
exports: [WorkflowService, WorkflowCompilerService, WorkflowRuntimeFacade],
|
|
32
43
|
})
|
|
@@ -5,6 +5,7 @@ import { HumanApprovalService } from '../humanApproval/human-approval.service';
|
|
|
5
5
|
import { TemporalService } from './temporal.service';
|
|
6
6
|
import { signWebhookPayload } from './webhook-signature.util';
|
|
7
7
|
import { WorkflowCompilerService } from './workflow-compiler.service';
|
|
8
|
+
import { WorkflowLifecycleService } from './workflow-lifecycle.service';
|
|
8
9
|
import { WorkflowService } from './workflow.service';
|
|
9
10
|
|
|
10
11
|
describe('WorkflowService — workflow list run counts', () => {
|
|
@@ -37,6 +38,7 @@ describe('WorkflowService — workflow list run counts', () => {
|
|
|
37
38
|
{} as any,
|
|
38
39
|
{} as any,
|
|
39
40
|
{} as any,
|
|
41
|
+
{} as any,
|
|
40
42
|
);
|
|
41
43
|
|
|
42
44
|
const result = await service.findMany({});
|
|
@@ -152,6 +154,10 @@ describe('WorkflowService — cron lifecycle hooks', () => {
|
|
|
152
154
|
{ provide: TemporalService, useValue: temporal },
|
|
153
155
|
{ provide: HumanApprovalService, useValue: {} },
|
|
154
156
|
{ provide: WorkflowCompilerService, useValue: compiler },
|
|
157
|
+
{
|
|
158
|
+
provide: WorkflowLifecycleService,
|
|
159
|
+
useValue: { markFailed: jest.fn() },
|
|
160
|
+
},
|
|
155
161
|
],
|
|
156
162
|
}).compile();
|
|
157
163
|
|
|
@@ -1563,6 +1569,10 @@ describe('WorkflowService — receiveWebhook', () => {
|
|
|
1563
1569
|
provide: WorkflowCompilerService,
|
|
1564
1570
|
useValue: { compile: jest.fn(async (dsl: any) => dsl) },
|
|
1565
1571
|
},
|
|
1572
|
+
{
|
|
1573
|
+
provide: WorkflowLifecycleService,
|
|
1574
|
+
useValue: { markFailed: jest.fn() },
|
|
1575
|
+
},
|
|
1566
1576
|
],
|
|
1567
1577
|
}).compile();
|
|
1568
1578
|
|
|
@@ -1815,6 +1825,10 @@ describe('WorkflowService — approveInstance', () => {
|
|
|
1815
1825
|
{ provide: TemporalService, useValue: temporal },
|
|
1816
1826
|
{ provide: HumanApprovalService, useValue: humanApproval },
|
|
1817
1827
|
{ provide: WorkflowCompilerService, useValue: {} },
|
|
1828
|
+
{
|
|
1829
|
+
provide: WorkflowLifecycleService,
|
|
1830
|
+
useValue: { markFailed: jest.fn() },
|
|
1831
|
+
},
|
|
1818
1832
|
],
|
|
1819
1833
|
}).compile();
|
|
1820
1834
|
service = module.get(WorkflowService);
|