@acorex/platform 21.0.0-next.7 → 21.0.0-next.71
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/fesm2022/acorex-platform-auth.mjs +281 -23
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/acorex-platform-common-common-settings.provider-Bi1RYif5.mjs +163 -0
- package/fesm2022/acorex-platform-common-common-settings.provider-Bi1RYif5.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +1381 -276
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +1538 -611
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain.mjs +557 -826
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +1372 -210
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs +121 -0
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-components.mjs +6298 -1929
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +456 -204
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs +371 -0
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-entity-file-list-popup.component-_yrP5SQe.mjs +100 -0
- package/fesm2022/acorex-platform-layout-entity-file-list-popup.component-_yrP5SQe.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-entity.mjs +22537 -9975
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +865 -218
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +2138 -487
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-button-widget-designer.component-C3VoBb_b.mjs → acorex-platform-layout-widgets-button-widget-designer.component-Dy7jF-oD.mjs} +10 -10
- package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-Dy7jF-oD.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs → acorex-platform-layout-widgets-image-preview.popup-C_EPAvCU.mjs} +6 -7
- package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-C_EPAvCU.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-page-widget-designer.component-BtZMBxYp.mjs → acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs} +12 -12
- package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +116 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-BcpRkpJp.mjs} +6 -6
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-BcpRkpJp.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-DQtK4lxl.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-DQtK4lxl.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-text-block-widget-designer.component-Df1BFkSa.mjs → acorex-platform-layout-widgets-text-block-widget-designer.component-Vo4fWHtX.mjs} +6 -6
- package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-Vo4fWHtX.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets.mjs +10434 -7982
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-native.mjs +8 -7
- package/fesm2022/acorex-platform-native.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs +391 -166
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CWLfNqV0.mjs +160 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CWLfNqV0.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-C7cT82K2.mjs +120 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-C7cT82K2.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs → acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs} +21 -28
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-error-401.component-cfREo88K.mjs → acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs} +4 -4
- package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-error-404.component-CdCV5ZoA.mjs → acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs} +4 -4
- package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-offline.component-DR6G8gPC.mjs +19 -0
- package/fesm2022/acorex-platform-themes-default-error-offline.component-DR6G8gPC.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +2289 -90
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs → acorex-platform-themes-shared-icon-chooser-column.component-CqkWJYdv.mjs} +6 -6
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-CqkWJYdv.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-icon-chooser-view.component-9W52W6Nu.mjs → acorex-platform-themes-shared-icon-chooser-view.component-BOTuLdWN.mjs} +6 -6
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-BOTuLdWN.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs → acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs} +52 -33
- package/fesm2022/acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-D566Kdvy.mjs +94 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-D566Kdvy.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-D7-rCGl7.mjs +86 -0
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-D7-rCGl7.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +790 -612
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +978 -238
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/fesm2022/acorex-platform.mjs.map +1 -1
- package/package.json +40 -38
- package/{auth/index.d.ts → types/acorex-platform-auth.d.ts} +241 -4
- package/{common/index.d.ts → types/acorex-platform-common.d.ts} +833 -89
- package/{core/index.d.ts → types/acorex-platform-core.d.ts} +779 -164
- package/{domain/index.d.ts → types/acorex-platform-domain.d.ts} +744 -412
- package/{layout/builder/index.d.ts → types/acorex-platform-layout-builder.d.ts} +277 -55
- package/types/acorex-platform-layout-components.d.ts +3257 -0
- package/{layout/designer/index.d.ts → types/acorex-platform-layout-designer.d.ts} +96 -18
- package/types/acorex-platform-layout-entity.d.ts +4492 -0
- package/{layout/views/index.d.ts → types/acorex-platform-layout-views.d.ts} +247 -62
- package/{layout/widget-core/index.d.ts → types/acorex-platform-layout-widget-core.d.ts} +437 -131
- package/{layout/widgets/index.d.ts → types/acorex-platform-layout-widgets.d.ts} +1140 -506
- package/{native/index.d.ts → types/acorex-platform-native.d.ts} +0 -7
- package/types/acorex-platform-runtime.d.ts +571 -0
- package/{themes/default/index.d.ts → types/acorex-platform-themes-default.d.ts} +254 -7
- package/{themes/shared/index.d.ts → types/acorex-platform-themes-shared.d.ts} +30 -2
- package/{workflow/index.d.ts → types/acorex-platform-workflow.d.ts} +620 -617
- package/fesm2022/acorex-platform-common-common-settings.provider-zhqNP3xb.mjs +0 -71
- package/fesm2022/acorex-platform-common-common-settings.provider-zhqNP3xb.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-C3VoBb_b.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs +0 -135
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-BtZMBxYp.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-Df1BFkSa.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs +0 -157
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DfJEx_bs.mjs +0 -1542
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DfJEx_bs.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs +0 -101
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-cfREo88K.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-404.component-CdCV5ZoA.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-offline.component-E7SzBcAt.mjs +0 -19
- package/fesm2022/acorex-platform-themes-default-error-offline.component-E7SzBcAt.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-9W52W6Nu.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DTnfRy5f.mjs +0 -65
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DTnfRy5f.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DY0JtT1v.mjs +0 -64
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DY0JtT1v.mjs.map +0 -1
- package/layout/components/index.d.ts +0 -1669
- package/layout/entity/index.d.ts +0 -2287
- package/runtime/index.d.ts +0 -307
- /package/{index.d.ts → types/acorex-platform.d.ts} +0 -0
|
@@ -2,7 +2,8 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { Injectable, inject, InjectionToken, Optional, Inject, NgModule } from '@angular/core';
|
|
3
3
|
import { Subject, filter } from 'rxjs';
|
|
4
4
|
import { cloneDeep, get, set } from 'lodash-es';
|
|
5
|
-
import { setSmart, AXPDataGenerator } from '@acorex/platform/core';
|
|
5
|
+
import { setSmart, AXPExpressionEvaluatorService, AXPDataGenerator } from '@acorex/platform/core';
|
|
6
|
+
import { AXTranslationService } from '@acorex/core/translation';
|
|
6
7
|
import { AXPCommandService } from '@acorex/platform/runtime';
|
|
7
8
|
|
|
8
9
|
class AXPWorkflowError extends Error {
|
|
@@ -23,10 +24,10 @@ class AXPWorkflowEventService {
|
|
|
23
24
|
get events$() {
|
|
24
25
|
return this.eventSubject.asObservable();
|
|
25
26
|
}
|
|
26
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
27
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
27
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
28
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowEventService, providedIn: 'root' }); }
|
|
28
29
|
}
|
|
29
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
30
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowEventService, decorators: [{
|
|
30
31
|
type: Injectable,
|
|
31
32
|
args: [{
|
|
32
33
|
providedIn: 'root',
|
|
@@ -116,10 +117,10 @@ class AXPWorkflowRegistryService {
|
|
|
116
117
|
});
|
|
117
118
|
}
|
|
118
119
|
}
|
|
119
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
120
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
120
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
121
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowRegistryService, providedIn: 'root' }); }
|
|
121
122
|
}
|
|
122
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
123
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowRegistryService, decorators: [{
|
|
123
124
|
type: Injectable,
|
|
124
125
|
args: [{
|
|
125
126
|
providedIn: 'root',
|
|
@@ -158,17 +159,17 @@ class AXPWorkflowAction {
|
|
|
158
159
|
dispatch(event) {
|
|
159
160
|
this.eventService.dispatch(event);
|
|
160
161
|
}
|
|
161
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
162
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
162
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowAction, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
163
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowAction }); }
|
|
163
164
|
}
|
|
164
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
165
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowAction, decorators: [{
|
|
165
166
|
type: Injectable
|
|
166
167
|
}] });
|
|
167
168
|
class AXPWorkflowFunction {
|
|
168
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
169
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
169
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowFunction, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
170
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowFunction }); }
|
|
170
171
|
}
|
|
171
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
172
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowFunction, decorators: [{
|
|
172
173
|
type: Injectable
|
|
173
174
|
}] });
|
|
174
175
|
function createWorkFlowEvent(type) {
|
|
@@ -184,10 +185,10 @@ class AXPWorkflowDecideAction extends AXPWorkflowAction {
|
|
|
184
185
|
async execute(context) {
|
|
185
186
|
// its a fake action
|
|
186
187
|
}
|
|
187
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
188
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
188
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDecideAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
189
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDecideAction, providedIn: 'root' }); }
|
|
189
190
|
}
|
|
190
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
191
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDecideAction, decorators: [{
|
|
191
192
|
type: Injectable,
|
|
192
193
|
args: [{
|
|
193
194
|
providedIn: 'root',
|
|
@@ -373,10 +374,10 @@ class AXPWorkflowService {
|
|
|
373
374
|
}
|
|
374
375
|
return this.injector.get(functionType);
|
|
375
376
|
}
|
|
376
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
377
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
377
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowService, deps: [{ token: AXPWorkflowRegistryService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
378
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowService, providedIn: 'root' }); }
|
|
378
379
|
}
|
|
379
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
380
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowService, decorators: [{
|
|
380
381
|
type: Injectable,
|
|
381
382
|
args: [{
|
|
382
383
|
providedIn: 'root',
|
|
@@ -401,28 +402,28 @@ class AXPStartWorkflowAction extends AXPWorkflowAction {
|
|
|
401
402
|
throw e;
|
|
402
403
|
}
|
|
403
404
|
}
|
|
404
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
405
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
405
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPStartWorkflowAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
406
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPStartWorkflowAction, providedIn: 'root' }); }
|
|
406
407
|
}
|
|
407
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
408
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPStartWorkflowAction, decorators: [{
|
|
408
409
|
type: Injectable,
|
|
409
410
|
args: [{
|
|
410
411
|
providedIn: 'root',
|
|
411
412
|
}]
|
|
412
413
|
}] });
|
|
413
414
|
|
|
414
|
-
/**
|
|
415
|
-
* Injection token for workflow definition loaders.
|
|
416
|
-
* Multiple loaders can be provided (multi: true).
|
|
417
|
-
*/
|
|
418
|
-
const AXP_WORKFLOW_DEFINITION_LOADER = new InjectionToken('AXP_WORKFLOW_DEFINITION_LOADER');
|
|
419
|
-
|
|
420
415
|
// ============================================
|
|
421
416
|
// WORKFLOW INSTANCE v3.0.0 TYPES
|
|
422
417
|
// Based on Elsa Workflow Instance schema: https://elsaworkflows.io/schemas/workflow-instance/v3.0.0/schema.json
|
|
423
418
|
// Compatible with Elsa backend while using ACoreX naming conventions
|
|
424
419
|
// ============================================
|
|
425
420
|
|
|
421
|
+
// Note:
|
|
422
|
+
// Previous versions defined dedicated activity result/command types here
|
|
423
|
+
// (AXPActivityResult / AXPActivity) that wrapped output and outcome.
|
|
424
|
+
// Activities are now modeled directly as AXPCommand with outcome stored in
|
|
425
|
+
// AXPExecuteCommandResult.metadata.outcome.
|
|
426
|
+
|
|
426
427
|
const AXP_ACTIVITY_PROVIDER = new InjectionToken('AXP_ACTIVITY_PROVIDER', {
|
|
427
428
|
factory: () => [],
|
|
428
429
|
});
|
|
@@ -598,6 +599,19 @@ class AXPActivityDefinitionService {
|
|
|
598
599
|
this.pendingActivityRequests.set(name, requestPromise);
|
|
599
600
|
return requestPromise;
|
|
600
601
|
}
|
|
602
|
+
/**
|
|
603
|
+
* Get all activity definitions (flat list) by loading root categories and their activities.
|
|
604
|
+
* Used by activity selector UIs (e.g. automation command configurator).
|
|
605
|
+
*/
|
|
606
|
+
async getAllActivities() {
|
|
607
|
+
const categories = await this.getCategories(undefined);
|
|
608
|
+
const all = [];
|
|
609
|
+
for (const cat of categories) {
|
|
610
|
+
const activities = await this.getActivitiesByCategoryId(cat.id);
|
|
611
|
+
all.push(...activities);
|
|
612
|
+
}
|
|
613
|
+
return all;
|
|
614
|
+
}
|
|
601
615
|
/**
|
|
602
616
|
* Get category ID containing a specific activity definition
|
|
603
617
|
*
|
|
@@ -615,7 +629,7 @@ class AXPActivityDefinitionService {
|
|
|
615
629
|
if (definition && definition.category) {
|
|
616
630
|
// Try to find category by name/id
|
|
617
631
|
const categories = await this.getCategories();
|
|
618
|
-
const found = categories.find(cat => cat.id === definition.category
|
|
632
|
+
const found = categories.find((cat) => cat.id === definition.category?.id);
|
|
619
633
|
if (found) {
|
|
620
634
|
return found.id;
|
|
621
635
|
}
|
|
@@ -842,10 +856,10 @@ class AXPActivityDefinitionService {
|
|
|
842
856
|
this.pendingActivitiesRequests.clear();
|
|
843
857
|
this.pendingActivityRequests.clear();
|
|
844
858
|
}
|
|
845
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
846
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
859
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityDefinitionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
860
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityDefinitionService, providedIn: 'root' }); }
|
|
847
861
|
}
|
|
848
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
862
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityDefinitionService, decorators: [{
|
|
849
863
|
type: Injectable,
|
|
850
864
|
args: [{
|
|
851
865
|
providedIn: 'root',
|
|
@@ -858,61 +872,357 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
858
872
|
*/
|
|
859
873
|
const AXP_WORKFLOW_ENGINE = new InjectionToken('AXP_WORKFLOW_ENGINE');
|
|
860
874
|
|
|
875
|
+
//#region ---- Error Codes ----
|
|
876
|
+
/**
|
|
877
|
+
* Stable workflow engine error codes for UI branching (toasts, take-over flow, etc.).
|
|
878
|
+
*/
|
|
879
|
+
const AXP_WORKFLOW_ERROR_CODES = {
|
|
880
|
+
TASK_NOT_ASSIGNEE: 'WORKFLOW_TASK_NOT_ASSIGNEE',
|
|
881
|
+
CLAIM_REQUIRED: 'WORKFLOW_CLAIM_REQUIRED',
|
|
882
|
+
REASSIGN_NOT_ALLOWED: 'WORKFLOW_REASSIGN_NOT_ALLOWED',
|
|
883
|
+
};
|
|
884
|
+
//#endregion
|
|
885
|
+
//#region ---- Engine Error ----
|
|
886
|
+
/**
|
|
887
|
+
* Business-rule failure from {@link AXPWorkflowEngine} (expected, user-facing).
|
|
888
|
+
*/
|
|
889
|
+
class AXPWorkflowEngineError extends Error {
|
|
890
|
+
constructor(message, code, details) {
|
|
891
|
+
super(message);
|
|
892
|
+
this.code = code;
|
|
893
|
+
this.details = details;
|
|
894
|
+
this.name = 'AXPWorkflowEngineError';
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Resolves a stable error code from an unknown thrown value.
|
|
899
|
+
*/
|
|
900
|
+
function getWorkflowEngineErrorCode(error) {
|
|
901
|
+
if (error instanceof AXPWorkflowEngineError) {
|
|
902
|
+
return error.code;
|
|
903
|
+
}
|
|
904
|
+
return undefined;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Resolves a user-facing message and optional code from an unknown thrown value.
|
|
908
|
+
*/
|
|
909
|
+
function getWorkflowEngineErrorInfo(error) {
|
|
910
|
+
if (error instanceof AXPWorkflowEngineError) {
|
|
911
|
+
return { message: error.message, code: error.code };
|
|
912
|
+
}
|
|
913
|
+
if (error instanceof Error) {
|
|
914
|
+
return { message: error.message };
|
|
915
|
+
}
|
|
916
|
+
return { message: 'An unexpected workflow error occurred' };
|
|
917
|
+
}
|
|
918
|
+
//#endregion
|
|
919
|
+
|
|
920
|
+
/**
|
|
921
|
+
* Activity types that use the task board (suspend until user acts via inbox), not inline interactive execution.
|
|
922
|
+
*/
|
|
923
|
+
const AXP_WORKFLOW_TASK_BOARD_ACTIVITY_TYPES = [
|
|
924
|
+
'workflow-activity:human-task',
|
|
925
|
+
'workflow-activity:cartable',
|
|
926
|
+
];
|
|
927
|
+
function axpIsWorkflowTaskBoardActivityType(activityType) {
|
|
928
|
+
return !!activityType && AXP_WORKFLOW_TASK_BOARD_ACTIVITY_TYPES.includes(activityType);
|
|
929
|
+
}
|
|
930
|
+
|
|
861
931
|
//#endregion
|
|
862
932
|
/**
|
|
863
|
-
*
|
|
933
|
+
* Workflow Expression Scope Service
|
|
934
|
+
*
|
|
935
|
+
* Shared service for building expression evaluation scope from workflow data.
|
|
936
|
+
* Used by both Local Engine and Mock Runtime to manage workflow data (inputs, variables, outputs).
|
|
937
|
+
*
|
|
938
|
+
* Responsibilities:
|
|
939
|
+
* - Build expression evaluation scope from workflow state
|
|
940
|
+
* - Provide context.eval() function for accessing workflow data
|
|
941
|
+
* - Manage workflow data structure (inputs, variables, outputs)
|
|
942
|
+
*
|
|
943
|
+
* This service does NOT:
|
|
944
|
+
* - Execute activities
|
|
945
|
+
* - Evaluate expressions (delegates to AXPExpressionEvaluatorService)
|
|
946
|
+
* - Manage workflow state (handled by runtime)
|
|
947
|
+
*
|
|
948
|
+
* @example
|
|
949
|
+
* ```typescript
|
|
950
|
+
* const scopeService = inject(WorkflowExpressionScopeService);
|
|
864
951
|
*
|
|
865
|
-
*
|
|
866
|
-
*
|
|
867
|
-
*
|
|
952
|
+
* // Build scope from workflow state
|
|
953
|
+
* const scope = scopeService.buildScope({
|
|
954
|
+
* inputs: state.input || {},
|
|
955
|
+
* variables: state.variables || {},
|
|
956
|
+
* outputs: activityOutputs
|
|
957
|
+
* });
|
|
868
958
|
*
|
|
869
|
-
*
|
|
959
|
+
* // Or build from state directly
|
|
960
|
+
* const scope = scopeService.buildScopeFromState(state, activityOutputs);
|
|
961
|
+
* ```
|
|
870
962
|
*/
|
|
871
|
-
class
|
|
963
|
+
class WorkflowExpressionScopeService {
|
|
964
|
+
//#region ---- Private Helpers (dot-notation input normalization) ----
|
|
965
|
+
/**
|
|
966
|
+
* Collect dot-notation key-value pairs from nested objects so that e.g.
|
|
967
|
+
* { metadata: { "metadata.questionnaire.id": "x" } } becomes { "metadata.questionnaire.id": "x" } at root.
|
|
968
|
+
* Top-level non-dot keys are kept as-is.
|
|
969
|
+
*/
|
|
970
|
+
flattenDotKeysFromTree(obj) {
|
|
971
|
+
if (obj === null || typeof obj !== 'object')
|
|
972
|
+
return obj;
|
|
973
|
+
const result = {};
|
|
974
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
975
|
+
if (key.includes('.')) {
|
|
976
|
+
result[key] = value;
|
|
977
|
+
}
|
|
978
|
+
else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
979
|
+
for (const [k, v] of Object.entries(value)) {
|
|
980
|
+
if (k.includes('.')) {
|
|
981
|
+
result[k] = v;
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
result[key + '.' + k] = v;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
else {
|
|
989
|
+
result[key] = value;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
return result;
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Expand flat keys with dots into nested objects.
|
|
996
|
+
* e.g. { "metadata.questionnaire.id": "x" } -> { metadata: { questionnaire: { id: "x" } } }.
|
|
997
|
+
*/
|
|
998
|
+
expandDotKeys(obj) {
|
|
999
|
+
if (obj === null || typeof obj !== 'object')
|
|
1000
|
+
return obj;
|
|
1001
|
+
const result = {};
|
|
1002
|
+
const dotKeys = [];
|
|
1003
|
+
const simpleKeys = [];
|
|
1004
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1005
|
+
if (key.includes('.')) {
|
|
1006
|
+
dotKeys.push([key, value]);
|
|
1007
|
+
}
|
|
1008
|
+
else {
|
|
1009
|
+
simpleKeys.push([key, value]);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
for (const [key, value] of dotKeys) {
|
|
1013
|
+
const parts = key.split('.');
|
|
1014
|
+
let current = result;
|
|
1015
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1016
|
+
const part = parts[i];
|
|
1017
|
+
if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {
|
|
1018
|
+
current[part] = {};
|
|
1019
|
+
}
|
|
1020
|
+
current = current[part];
|
|
1021
|
+
}
|
|
1022
|
+
current[parts[parts.length - 1]] = value;
|
|
1023
|
+
}
|
|
1024
|
+
for (const [key, value] of simpleKeys) {
|
|
1025
|
+
result[key] = value;
|
|
1026
|
+
}
|
|
1027
|
+
return result;
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Normalize workflow input so that flat dot-notation keys (e.g. from form schema
|
|
1031
|
+
* "metadata.questionnaire.id") become nested for expression access (inputs.metadata.questionnaire.id).
|
|
1032
|
+
*/
|
|
1033
|
+
normalizeInputs(input) {
|
|
1034
|
+
if (!input || typeof input !== 'object')
|
|
1035
|
+
return {};
|
|
1036
|
+
const flattened = this.flattenDotKeysFromTree(input);
|
|
1037
|
+
return this.expandDotKeys(flattened);
|
|
1038
|
+
}
|
|
1039
|
+
//#endregion
|
|
1040
|
+
//#region ---- Public Methods ----
|
|
1041
|
+
/**
|
|
1042
|
+
* Build expression evaluation scope for workflow activities.
|
|
1043
|
+
*
|
|
1044
|
+
* Provides workflow-specific data (inputs, variables, outputs) and context.eval() function.
|
|
1045
|
+
* Other data (session, current user, etc.) are provided by expression evaluator scope providers.
|
|
1046
|
+
*
|
|
1047
|
+
* Scope includes:
|
|
1048
|
+
* - inputs: Workflow input values (accessible as inputs.propertyName)
|
|
1049
|
+
* - variables: Workflow state variables (accessible as variables.propertyName or vars.propertyName)
|
|
1050
|
+
* - outputs: Previous activity outputs (accessible as outputs.activityId)
|
|
1051
|
+
* - context.eval(path): Function to access nested properties from workflow data
|
|
1052
|
+
*
|
|
1053
|
+
* Expressions can use:
|
|
1054
|
+
* - {{inputs.userName}} - Direct access to workflow input
|
|
1055
|
+
* - {{variables.someVar}} or {{vars.someVar}} - Direct access to workflow variable
|
|
1056
|
+
* - {{outputs.activityId.property}} - Direct access to previous activity output
|
|
1057
|
+
* - {{context.eval("inputs.userName")}} - Access via context.eval (supports nested paths)
|
|
1058
|
+
* - {{context.eval("variables.someVar")}} - Access variables via context.eval
|
|
1059
|
+
* - {{context.eval("outputs.activityId.property")}} - Access outputs via context.eval
|
|
1060
|
+
* - {{session.currentUser().name}} - Access current user via expression evaluator scope providers
|
|
1061
|
+
*
|
|
1062
|
+
* The context.eval() function provides a unified way to access all workflow data,
|
|
1063
|
+
* similar to how entity-detail-list uses context.eval() to access parent data.
|
|
1064
|
+
*
|
|
1065
|
+
* @param context - Workflow expression context containing inputs, variables, and outputs
|
|
1066
|
+
* @returns Expression evaluator scope with workflow data and context.eval() function
|
|
1067
|
+
*/
|
|
1068
|
+
buildScope(context) {
|
|
1069
|
+
// Normalize inputs so flat dot-notation keys (e.g. metadata.questionnaire.id from forms) become nested for expressions
|
|
1070
|
+
const inputs = this.normalizeInputs(context.inputs || {});
|
|
1071
|
+
// Build merged workflow data object for context.eval()
|
|
1072
|
+
// This allows expressions like: context.eval("inputs.userName") or context.eval("variables.count")
|
|
1073
|
+
const workflowData = {
|
|
1074
|
+
inputs,
|
|
1075
|
+
variables: context.variables || {},
|
|
1076
|
+
vars: context.variables || {}, // Alias for convenience
|
|
1077
|
+
outputs: context.outputs || {},
|
|
1078
|
+
};
|
|
1079
|
+
// Build scope object with workflow-specific data and context.eval()
|
|
1080
|
+
// Note: AXPExpressionEvaluatorScope type expects { [namespace]: { [name]: Function } }
|
|
1081
|
+
// but evaluate() method actually accepts flat objects with values too
|
|
1082
|
+
// We'll use 'any' to allow both values and functions
|
|
1083
|
+
const scope = {
|
|
1084
|
+
// Direct access to workflow data
|
|
1085
|
+
inputs: workflowData.inputs,
|
|
1086
|
+
variables: workflowData.variables,
|
|
1087
|
+
vars: workflowData.vars,
|
|
1088
|
+
outputs: workflowData.outputs,
|
|
1089
|
+
// Context object with eval function (similar to entity-detail-list pattern)
|
|
1090
|
+
context: {
|
|
1091
|
+
eval: (path) => {
|
|
1092
|
+
// Use lodash get to access nested properties
|
|
1093
|
+
// Supports paths like: "inputs.userName", "variables.count", "outputs.activityId.property"
|
|
1094
|
+
return get(workflowData, path);
|
|
1095
|
+
},
|
|
1096
|
+
},
|
|
1097
|
+
};
|
|
1098
|
+
return scope;
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Build expression evaluation scope from workflow instance state.
|
|
1102
|
+
*
|
|
1103
|
+
* Convenience method that extracts data from AXPWorkflowInstanceState.
|
|
1104
|
+
*
|
|
1105
|
+
* @param state - Workflow instance state
|
|
1106
|
+
* @param activityOutputs - Map of activity outputs (activityId -> output)
|
|
1107
|
+
* @returns Expression evaluator scope with workflow data and context.eval() function
|
|
1108
|
+
*/
|
|
1109
|
+
buildScopeFromState(state, activityOutputs) {
|
|
1110
|
+
// Convert activity outputs to record format
|
|
1111
|
+
const outputs = {};
|
|
1112
|
+
if (activityOutputs) {
|
|
1113
|
+
if (activityOutputs instanceof Map) {
|
|
1114
|
+
activityOutputs.forEach((output, activityId) => {
|
|
1115
|
+
outputs[activityId] = output;
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
else {
|
|
1119
|
+
Object.assign(outputs, activityOutputs);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
// Convenience alias for the last activity output (if available).
|
|
1123
|
+
// This allows expressions like: {{outputs.last.someField}}
|
|
1124
|
+
if (outputs['last'] === undefined && state.lastActivityOutput !== undefined) {
|
|
1125
|
+
outputs['last'] = state.lastActivityOutput;
|
|
1126
|
+
}
|
|
1127
|
+
return this.buildScope({
|
|
1128
|
+
inputs: this.normalizeInputs((state.input || {})),
|
|
1129
|
+
variables: state.variables || {},
|
|
1130
|
+
outputs: outputs,
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowExpressionScopeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1134
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowExpressionScopeService, providedIn: 'root' }); }
|
|
1135
|
+
}
|
|
1136
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowExpressionScopeService, decorators: [{
|
|
1137
|
+
type: Injectable,
|
|
1138
|
+
args: [{
|
|
1139
|
+
providedIn: 'root'
|
|
1140
|
+
}]
|
|
1141
|
+
}] });
|
|
1142
|
+
|
|
1143
|
+
//#region ---- Constants ----
|
|
1144
|
+
/**
|
|
1145
|
+
* Activity types handled internally by the workflow engine (e.g. mock backend).
|
|
1146
|
+
* When such an activity is not registered as Command on the client, we skip execution
|
|
1147
|
+
* without warning — the engine will run it when executing the workflow.
|
|
1148
|
+
*/
|
|
1149
|
+
const ENGINE_BUILTIN_ACTIVITY_TYPES = new Set([
|
|
1150
|
+
'workflow-activity:set-variable',
|
|
1151
|
+
'workflow-activity:http-request',
|
|
1152
|
+
'workflow-activity:resolve-employee-user-id',
|
|
1153
|
+
]);
|
|
1154
|
+
//#endregion
|
|
1155
|
+
/**
|
|
1156
|
+
* Activity Executor Service
|
|
1157
|
+
*
|
|
1158
|
+
* Service for executing workflow activities via CommandBus.
|
|
1159
|
+
* Automatically evaluates expressions in activity inputs before execution.
|
|
1160
|
+
*
|
|
1161
|
+
* @example
|
|
1162
|
+
* ```typescript
|
|
1163
|
+
* const executor = inject(ActivityExecutor);
|
|
1164
|
+
*
|
|
1165
|
+
* // Execute activity with task and workflow state (expressions will be evaluated)
|
|
1166
|
+
* const result = await executor.execute(task, workflowState, activityOutputs);
|
|
1167
|
+
* ```
|
|
1168
|
+
*/
|
|
1169
|
+
class ActivityExecutor {
|
|
872
1170
|
constructor() {
|
|
873
1171
|
//#region ---- Services & Dependencies ----
|
|
874
1172
|
this.commandService = inject(AXPCommandService);
|
|
1173
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
1174
|
+
this.expressionScopeService = inject(WorkflowExpressionScopeService);
|
|
1175
|
+
this.translateService = inject(AXTranslationService);
|
|
875
1176
|
}
|
|
876
1177
|
//#endregion
|
|
877
1178
|
//#region ---- Public Methods ----
|
|
878
1179
|
/**
|
|
879
|
-
* Execute a
|
|
1180
|
+
* Execute a workflow activity with expression evaluation.
|
|
880
1181
|
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
1182
|
+
* Evaluates expressions in activity inputs using workflow state,
|
|
1183
|
+
* then executes the activity via CommandBus.
|
|
883
1184
|
*
|
|
884
|
-
* @param task -
|
|
1185
|
+
* @param task - Workflow task containing activity information
|
|
1186
|
+
* @param workflowState - Current workflow instance state (for expression evaluation)
|
|
1187
|
+
* @param activityOutputs - Map of previous activity outputs (for expression evaluation)
|
|
885
1188
|
* @returns Execution result with output and outcome
|
|
886
|
-
*
|
|
887
|
-
* @throws Error if task is not a frontend task
|
|
888
1189
|
*/
|
|
889
|
-
async execute(task) {
|
|
890
|
-
// Validate execution mode
|
|
891
|
-
if (task.executionMode !== 'frontend' && task.executionMode !== 'both') {
|
|
892
|
-
throw new Error(`Task '${task.activityId}' is not a frontend task. ` +
|
|
893
|
-
`Execution mode: ${task.executionMode}. Backend tasks are handled automatically.`);
|
|
894
|
-
}
|
|
1190
|
+
async execute(task, workflowState, activityOutputs) {
|
|
895
1191
|
try {
|
|
1192
|
+
const activityName = task.activityType;
|
|
1193
|
+
// Evaluate inputs if workflow state is provided
|
|
1194
|
+
let evaluatedInputs = task.input || {};
|
|
1195
|
+
if (workflowState) {
|
|
1196
|
+
// Prefer explicit outputs, fallback to outputs stored in state
|
|
1197
|
+
const outputsForScope = activityOutputs ??
|
|
1198
|
+
workflowState.activityOutputs ??
|
|
1199
|
+
undefined;
|
|
1200
|
+
// Build expression scope from workflow state
|
|
1201
|
+
const scope = this.expressionScopeService.buildScopeFromState(workflowState, outputsForScope);
|
|
1202
|
+
// Evaluate all inputs recursively (handles nested objects and arrays)
|
|
1203
|
+
evaluatedInputs = await this.expressionEvaluator.evaluate(task.input || {}, scope);
|
|
1204
|
+
}
|
|
896
1205
|
// Check if command exists
|
|
897
|
-
const commandExists = this.commandService.exists(
|
|
1206
|
+
const commandExists = this.commandService.exists(activityName);
|
|
898
1207
|
if (!commandExists) {
|
|
899
|
-
|
|
900
|
-
`
|
|
1208
|
+
if (!ENGINE_BUILTIN_ACTIVITY_TYPES.has(activityName)) {
|
|
1209
|
+
console.warn(`[ActivityExecutor] ⚠️ Activity '${activityName}' is not registered as Command. ` +
|
|
1210
|
+
`Skipping execution.`);
|
|
1211
|
+
}
|
|
901
1212
|
return {
|
|
902
1213
|
output: null,
|
|
903
1214
|
outcome: 'Done'
|
|
904
1215
|
};
|
|
905
1216
|
}
|
|
906
|
-
//
|
|
907
|
-
|
|
908
|
-
let commandInput = task.input || task.config || {};
|
|
1217
|
+
// Flatten properties if nested (designer-style nested payload)
|
|
1218
|
+
let commandInput = evaluatedInputs;
|
|
909
1219
|
if (commandInput['properties'] && typeof commandInput['properties'] === 'object') {
|
|
910
1220
|
// Flatten: {properties: {text: "..."}} -> {text: "..."}
|
|
911
1221
|
commandInput = { ...commandInput['properties'] };
|
|
912
1222
|
}
|
|
913
1223
|
// Execute activity via CommandBus
|
|
914
|
-
// Activities
|
|
915
|
-
const result = await this.commandService.execute(
|
|
1224
|
+
// Activities (AXPActivity) return {output, outcome}; legacy may return {output, outcomes}
|
|
1225
|
+
const result = await this.commandService.execute(activityName, commandInput);
|
|
916
1226
|
if (!result) {
|
|
917
1227
|
return {
|
|
918
1228
|
output: null,
|
|
@@ -922,42 +1232,151 @@ class FrontendTaskExecutor {
|
|
|
922
1232
|
if (!result.success) {
|
|
923
1233
|
return {
|
|
924
1234
|
output: {
|
|
925
|
-
error: result.message?.text,
|
|
1235
|
+
error: await this.resolveCommandMessageTextForError(result.message?.text),
|
|
926
1236
|
},
|
|
927
1237
|
outcome: 'Failed',
|
|
928
1238
|
};
|
|
929
1239
|
}
|
|
930
1240
|
const commandResult = result.data;
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
// Default to 'Done' if no outcomes specified
|
|
1241
|
+
// Prefer unified outcome in result.metadata; fall back to legacy data.outcome/outcomes.
|
|
1242
|
+
const metadataOutcome = result?.metadata?.['outcome'];
|
|
934
1243
|
let outcome = 'Done';
|
|
935
|
-
if (
|
|
936
|
-
outcome =
|
|
1244
|
+
if (typeof metadataOutcome === 'string' && metadataOutcome.length > 0) {
|
|
1245
|
+
outcome = metadataOutcome;
|
|
1246
|
+
}
|
|
1247
|
+
else if (typeof commandResult?.outcome === 'string' && commandResult.outcome.length > 0) {
|
|
1248
|
+
outcome = commandResult.outcome;
|
|
937
1249
|
}
|
|
1250
|
+
else {
|
|
1251
|
+
const outcomes = (commandResult?.outcomes ?? {});
|
|
1252
|
+
if (outcomes && typeof outcomes === 'object' && Object.keys(outcomes).length > 0) {
|
|
1253
|
+
outcome = outcomes['Done'] ? 'Done' : Object.keys(outcomes)[0] || 'Done';
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
// Prefer output wrapper when present; otherwise treat data itself as output.
|
|
1257
|
+
const output = commandResult && typeof commandResult === 'object' && 'output' in commandResult
|
|
1258
|
+
? commandResult.output
|
|
1259
|
+
: commandResult;
|
|
938
1260
|
return {
|
|
939
|
-
output:
|
|
1261
|
+
output: output ?? null,
|
|
940
1262
|
outcome,
|
|
941
1263
|
};
|
|
942
1264
|
}
|
|
943
1265
|
catch (error) {
|
|
944
|
-
console.error(`[
|
|
1266
|
+
console.error(`[ActivityExecutor] ❌ Error evaluating expressions or executing activity:`, error);
|
|
945
1267
|
return {
|
|
946
1268
|
output: { error: error.message || 'Unknown error' },
|
|
947
1269
|
outcome: 'Failed'
|
|
948
1270
|
};
|
|
949
1271
|
}
|
|
950
1272
|
}
|
|
951
|
-
|
|
952
|
-
|
|
1273
|
+
/**
|
|
1274
|
+
* Resolves command failure message text for workflow output: `@` keys via translate, MLS maps via resolve.
|
|
1275
|
+
*/
|
|
1276
|
+
async resolveCommandMessageTextForError(value) {
|
|
1277
|
+
if (value == null) {
|
|
1278
|
+
return '';
|
|
1279
|
+
}
|
|
1280
|
+
if (typeof value === 'string') {
|
|
1281
|
+
return value.startsWith('@') ? await this.translateService.translateAsync(value) : value;
|
|
1282
|
+
}
|
|
1283
|
+
return this.translateService.resolve(value);
|
|
1284
|
+
}
|
|
1285
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ActivityExecutor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1286
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ActivityExecutor, providedIn: 'root' }); }
|
|
953
1287
|
}
|
|
954
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1288
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ActivityExecutor, decorators: [{
|
|
955
1289
|
type: Injectable,
|
|
956
1290
|
args: [{
|
|
957
1291
|
providedIn: 'root'
|
|
958
1292
|
}]
|
|
959
1293
|
}] });
|
|
960
1294
|
|
|
1295
|
+
const AXP_WORKFLOW_CONTINUATION_HOOK = new InjectionToken('AXP_WORKFLOW_CONTINUATION_HOOK');
|
|
1296
|
+
/** When true on resume `userInput`, skips the post-step continuation dialog (auto-advance). */
|
|
1297
|
+
const AXP_WORKFLOW_SUPPRESS_CONTINUATION_INPUT_KEY = '_suppressWorkflowContinuation';
|
|
1298
|
+
function isWorkflowContinuationSuppressed(userInput) {
|
|
1299
|
+
if (userInput == null || typeof userInput !== 'object') {
|
|
1300
|
+
return false;
|
|
1301
|
+
}
|
|
1302
|
+
return userInput[AXP_WORKFLOW_SUPPRESS_CONTINUATION_INPUT_KEY] === true;
|
|
1303
|
+
}
|
|
1304
|
+
//#endregion
|
|
1305
|
+
|
|
1306
|
+
//#region ---- Inline frontend classification ----
|
|
1307
|
+
/**
|
|
1308
|
+
* Frontend step executed inline (dialog/popup), not suspended on the task board.
|
|
1309
|
+
* Derived from execution mode and task-board activity types — no per-activity hardcoding.
|
|
1310
|
+
*/
|
|
1311
|
+
function axpIsWorkflowInlineFrontendTask(task) {
|
|
1312
|
+
if (!task) {
|
|
1313
|
+
return false;
|
|
1314
|
+
}
|
|
1315
|
+
if (axpIsWorkflowTaskBoardActivityType(task.activityType)) {
|
|
1316
|
+
return false;
|
|
1317
|
+
}
|
|
1318
|
+
return task.executionMode === 'frontend' || task.executionMode === 'both';
|
|
1319
|
+
}
|
|
1320
|
+
/** @deprecated Use {@link axpIsWorkflowInlineFrontendTask}. */
|
|
1321
|
+
function axpIsWorkflowInteractiveFrontendTask(task) {
|
|
1322
|
+
return axpIsWorkflowInlineFrontendTask(task);
|
|
1323
|
+
}
|
|
1324
|
+
//#endregion
|
|
1325
|
+
//#region ---- Continuation metadata on tasks ----
|
|
1326
|
+
/** Resolved before-interactive behavior from task metadata (set by engine from activity definition). */
|
|
1327
|
+
function axpResolveWorkflowContinuationBeforeInteractive(task) {
|
|
1328
|
+
return task?.continuation?.beforeInteractive ?? 'default';
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Whether to skip the pre-interactive "continue?" prompt based on activity metadata.
|
|
1332
|
+
* Assignee-specific rules are applied in workflow-management (needs session).
|
|
1333
|
+
*/
|
|
1334
|
+
function axpShouldSkipBeforeInteractiveFromMetadata(behavior, completedWasHumanTask) {
|
|
1335
|
+
return behavior === 'skip-when-chained-from-human-task' && completedWasHumanTask;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Whether to show a "continue?" prompt before running inline frontend activities.
|
|
1339
|
+
* Skips when the user already resumed a task-board step (primary action / resume).
|
|
1340
|
+
*/
|
|
1341
|
+
function axpShouldOfferBeforeInteractiveFlow(context) {
|
|
1342
|
+
return !context.completedActivityId;
|
|
1343
|
+
}
|
|
1344
|
+
//#endregion
|
|
1345
|
+
//#region ---- Step advancement gate ----
|
|
1346
|
+
/** Resume outcomes that do not advance the workflow graph (draft save, cancel, loop back). */
|
|
1347
|
+
const NON_ADVANCING_RESUME_OUTCOMES = new Set(['saved', 'cancelled', 'cancel', 'save', 'draft']);
|
|
1348
|
+
/**
|
|
1349
|
+
* Whether the workflow advanced enough to consider a continuation prompt.
|
|
1350
|
+
* Includes pending interactive steps when inbox bookmarks are already consumed.
|
|
1351
|
+
*/
|
|
1352
|
+
function axpShouldOfferWorkflowContinuationAfterStep(context, activeBookmarkActivityIds) {
|
|
1353
|
+
const outcome = context.resumeOutcome?.trim().toLowerCase();
|
|
1354
|
+
if (outcome && NON_ADVANCING_RESUME_OUTCOMES.has(outcome)) {
|
|
1355
|
+
return false;
|
|
1356
|
+
}
|
|
1357
|
+
const pendingActivityId = context.pendingNextTask?.activityId;
|
|
1358
|
+
const completedActivityId = context.completedActivityId;
|
|
1359
|
+
if (pendingActivityId && completedActivityId && pendingActivityId === completedActivityId) {
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
if (activeBookmarkActivityIds.length === 0) {
|
|
1363
|
+
const pending = context.pendingNextTask;
|
|
1364
|
+
if (completedActivityId && pending && pending.activityId !== completedActivityId) {
|
|
1365
|
+
if (axpIsWorkflowInlineFrontendTask(pending) ||
|
|
1366
|
+
axpIsWorkflowTaskBoardActivityType(pending.activityType)) {
|
|
1367
|
+
return true;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
return false;
|
|
1371
|
+
}
|
|
1372
|
+
/** No continuation on bare workflow start (bookmarks exist before any step completes). */
|
|
1373
|
+
if (!completedActivityId) {
|
|
1374
|
+
return false;
|
|
1375
|
+
}
|
|
1376
|
+
return activeBookmarkActivityIds.some((id) => id !== completedActivityId);
|
|
1377
|
+
}
|
|
1378
|
+
//#endregion
|
|
1379
|
+
|
|
961
1380
|
//#endregion
|
|
962
1381
|
/**
|
|
963
1382
|
* Workflow Manager - Facade for workflow lifecycle orchestration.
|
|
@@ -967,13 +1386,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
967
1386
|
*
|
|
968
1387
|
* Responsibilities:
|
|
969
1388
|
* - Orchestrate workflow lifecycle (start, execute, complete, resume)
|
|
970
|
-
* - Delegate execution to
|
|
1389
|
+
* - Delegate execution to ActivityExecutor
|
|
971
1390
|
* - Cache workflow state in memory
|
|
972
1391
|
* - Expose a stable API for UI
|
|
973
1392
|
*
|
|
974
1393
|
* Rules:
|
|
975
1394
|
* - No HTTP calls (delegates to AXPWorkflowEngine)
|
|
976
|
-
* - No CommandBus / Command execution (delegates to
|
|
1395
|
+
* - No CommandBus / Command execution (delegates to ActivityExecutor)
|
|
977
1396
|
* - No workflow branching logic (backend decides)
|
|
978
1397
|
* - No business validation (backend validates)
|
|
979
1398
|
* - No backend assumptions (uses abstract runtime service)
|
|
@@ -982,7 +1401,8 @@ class AXPWorkflowManager {
|
|
|
982
1401
|
constructor() {
|
|
983
1402
|
//#region ---- Services & Dependencies ----
|
|
984
1403
|
this.workflowEngine = inject(AXP_WORKFLOW_ENGINE);
|
|
985
|
-
this.
|
|
1404
|
+
this.activityExecutor = inject(ActivityExecutor);
|
|
1405
|
+
this.continuationHook = inject(AXP_WORKFLOW_CONTINUATION_HOOK, { optional: true });
|
|
986
1406
|
//#endregion
|
|
987
1407
|
//#region ---- State Cache ----
|
|
988
1408
|
/**
|
|
@@ -998,6 +1418,175 @@ class AXPWorkflowManager {
|
|
|
998
1418
|
}
|
|
999
1419
|
//#endregion
|
|
1000
1420
|
//#region ---- Public Methods ----
|
|
1421
|
+
/**
|
|
1422
|
+
* Execute frontend activities interactively until reaching workflow-activity:human-task or completion.
|
|
1423
|
+
*
|
|
1424
|
+
* Interactive = show form/popup immediately (user sees and acts). Only workflow-activity:human-task
|
|
1425
|
+
* is not interactive (goes to task board). Other frontend activities (show-layout-popup, show-toast, etc.)
|
|
1426
|
+
* even with taskType human-task in definition are executed here.
|
|
1427
|
+
*
|
|
1428
|
+
* @param instanceId - Workflow instance ID
|
|
1429
|
+
* @param task - Current task to execute
|
|
1430
|
+
* @param state - Current workflow state
|
|
1431
|
+
* @param lastActivityOutput - Last activity output (for expression evaluation)
|
|
1432
|
+
* @returns Final result with nextTask (if workflow-activity:human-task) or completion status
|
|
1433
|
+
*/
|
|
1434
|
+
async executeInteractiveFlow(instanceId, task, state, activityOutputs) {
|
|
1435
|
+
let currentTask = task;
|
|
1436
|
+
let currentState = state;
|
|
1437
|
+
let currentActivityOutputs = {
|
|
1438
|
+
...(currentState.activityOutputs || {}),
|
|
1439
|
+
...(activityOutputs || {}),
|
|
1440
|
+
};
|
|
1441
|
+
const maxIterations = 100; // Prevent infinite loops
|
|
1442
|
+
let iterationCount = 0;
|
|
1443
|
+
while (currentTask && iterationCount < maxIterations) {
|
|
1444
|
+
iterationCount++;
|
|
1445
|
+
// Interactive = frontend executionMode and NOT task-board activities (human-task, cartable)
|
|
1446
|
+
const isInteractive = (currentTask.executionMode === 'frontend' || currentTask.executionMode === 'both') &&
|
|
1447
|
+
!axpIsWorkflowTaskBoardActivityType(currentTask.activityType);
|
|
1448
|
+
if (isInteractive) {
|
|
1449
|
+
// Execute frontend activity
|
|
1450
|
+
const execResult = await this.activityExecutor.execute(currentTask, currentState, currentActivityOutputs);
|
|
1451
|
+
// Track outputs locally (backend should also persist and return them)
|
|
1452
|
+
currentActivityOutputs = {
|
|
1453
|
+
...currentActivityOutputs,
|
|
1454
|
+
[currentTask.activityId]: execResult.output,
|
|
1455
|
+
};
|
|
1456
|
+
// Send result to backend
|
|
1457
|
+
const completeResponse = await this.workflowEngine.frontActivtyComplete({
|
|
1458
|
+
instanceId,
|
|
1459
|
+
activityNode: currentTask.activityId,
|
|
1460
|
+
output: execResult.output || {},
|
|
1461
|
+
outcome: execResult.outcome,
|
|
1462
|
+
});
|
|
1463
|
+
// Update state cache
|
|
1464
|
+
if (completeResponse.state) {
|
|
1465
|
+
const normalizedState = { ...completeResponse.state };
|
|
1466
|
+
if (normalizedState.lastUpdated && !(normalizedState.lastUpdated instanceof Date)) {
|
|
1467
|
+
normalizedState.lastUpdated = new Date(normalizedState.lastUpdated);
|
|
1468
|
+
}
|
|
1469
|
+
currentState = normalizedState;
|
|
1470
|
+
// Prefer outputs returned by backend; fallback to local cache
|
|
1471
|
+
currentActivityOutputs = {
|
|
1472
|
+
...currentActivityOutputs,
|
|
1473
|
+
...(normalizedState.activityOutputs || {}),
|
|
1474
|
+
};
|
|
1475
|
+
this.stateCache.set(instanceId, normalizedState);
|
|
1476
|
+
}
|
|
1477
|
+
// Backend decides: if no nextTask, workflow is completed
|
|
1478
|
+
if (!completeResponse.nextTask) {
|
|
1479
|
+
return {
|
|
1480
|
+
nextTask: null,
|
|
1481
|
+
state: currentState,
|
|
1482
|
+
output: completeResponse.output,
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
// Backend decides: if nextTask is task-board activity or not frontend, return it (task board or done)
|
|
1486
|
+
const nextInteractive = (completeResponse.nextTask.executionMode === 'frontend' || completeResponse.nextTask.executionMode === 'both') &&
|
|
1487
|
+
!axpIsWorkflowTaskBoardActivityType(completeResponse.nextTask.activityType);
|
|
1488
|
+
if (!nextInteractive) {
|
|
1489
|
+
const humanTaskNext = completeResponse.nextTask;
|
|
1490
|
+
let boundaryContinuationOffer;
|
|
1491
|
+
if (humanTaskNext &&
|
|
1492
|
+
axpIsWorkflowTaskBoardActivityType(humanTaskNext.activityType)) {
|
|
1493
|
+
boundaryContinuationOffer =
|
|
1494
|
+
(await this.continuationHook?.offerAfterWorkflowStep?.({
|
|
1495
|
+
instanceId,
|
|
1496
|
+
completedActivityId: currentTask.activityId,
|
|
1497
|
+
resumeOutcome: execResult.outcome,
|
|
1498
|
+
pendingNextTask: humanTaskNext,
|
|
1499
|
+
})) ?? 'not-offered';
|
|
1500
|
+
}
|
|
1501
|
+
return {
|
|
1502
|
+
nextTask: humanTaskNext,
|
|
1503
|
+
state: currentState,
|
|
1504
|
+
boundaryContinuationOffer,
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
// Continue with next interactive frontend task
|
|
1508
|
+
currentTask = completeResponse.nextTask;
|
|
1509
|
+
}
|
|
1510
|
+
else {
|
|
1511
|
+
// Not interactive (e.g. human-task / cartable) - return as-is for task board
|
|
1512
|
+
return {
|
|
1513
|
+
nextTask: currentTask,
|
|
1514
|
+
state: currentState,
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
// Max iterations reached
|
|
1519
|
+
if (iterationCount >= maxIterations) {
|
|
1520
|
+
console.warn(`[AXPWorkflowManager] ⚠️ Maximum iterations (${maxIterations}) reached`);
|
|
1521
|
+
}
|
|
1522
|
+
return {
|
|
1523
|
+
nextTask: currentTask,
|
|
1524
|
+
state: currentState,
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Runs inline interactive activities when allowed, with an optional pre-flow continuation prompt.
|
|
1529
|
+
*/
|
|
1530
|
+
async runInteractiveFlowWithContinuation(instanceId, pendingTask, state, continuationContext, suppressContinuation, activityOutputs) {
|
|
1531
|
+
let continuationOffer = 'not-offered';
|
|
1532
|
+
if (!suppressContinuation &&
|
|
1533
|
+
axpShouldOfferBeforeInteractiveFlow(continuationContext) &&
|
|
1534
|
+
axpIsWorkflowInlineFrontendTask(pendingTask) &&
|
|
1535
|
+
this.continuationHook?.offerBeforeInteractiveFlow) {
|
|
1536
|
+
continuationOffer =
|
|
1537
|
+
(await this.continuationHook.offerBeforeInteractiveFlow({
|
|
1538
|
+
...continuationContext,
|
|
1539
|
+
instanceId,
|
|
1540
|
+
pendingNextTask: pendingTask,
|
|
1541
|
+
})) ?? 'not-offered';
|
|
1542
|
+
if (continuationOffer === 'declined') {
|
|
1543
|
+
await this.revertResumeAfterDeclinedInteractiveContinuation(instanceId, continuationContext, pendingTask);
|
|
1544
|
+
const revertedState = this.stateCache.get(instanceId) ?? state;
|
|
1545
|
+
return { nextTask: null, state: revertedState, continuationOffer };
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
const interactiveResult = await this.executeInteractiveFlow(instanceId, pendingTask, state, activityOutputs);
|
|
1549
|
+
const boundaryOffer = interactiveResult.boundaryContinuationOffer;
|
|
1550
|
+
if (boundaryOffer && boundaryOffer !== 'not-offered') {
|
|
1551
|
+
continuationOffer = boundaryOffer;
|
|
1552
|
+
}
|
|
1553
|
+
return { ...interactiveResult, continuationOffer };
|
|
1554
|
+
}
|
|
1555
|
+
async invokeWorkflowContinuationAfterStep(context, priorOffer, suppressContinuation = false) {
|
|
1556
|
+
if (suppressContinuation || priorOffer === 'declined') {
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
if (priorOffer && priorOffer !== 'not-offered') {
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
await this.continuationHook?.offerAfterWorkflowStep?.(context);
|
|
1563
|
+
}
|
|
1564
|
+
/**
|
|
1565
|
+
* Restores the suspended task-board step when the user declines a pre-interactive continuation prompt.
|
|
1566
|
+
*/
|
|
1567
|
+
async revertResumeAfterDeclinedInteractiveContinuation(instanceId, context, abortedTask) {
|
|
1568
|
+
const suspendedStepId = context.completedActivityId;
|
|
1569
|
+
if (!suspendedStepId) {
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
const revert = this.workflowEngine.revertResumeAfterDeclinedInteractiveContinuation?.bind(this.workflowEngine);
|
|
1573
|
+
if (!revert) {
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
const result = await revert({
|
|
1577
|
+
instanceId,
|
|
1578
|
+
suspendedStepId,
|
|
1579
|
+
abortedStepId: abortedTask.activityId,
|
|
1580
|
+
bookmarkId: context.completedBookmarkId,
|
|
1581
|
+
});
|
|
1582
|
+
if (result.success && result.state) {
|
|
1583
|
+
let normalizedState = { ...result.state };
|
|
1584
|
+
if (normalizedState.lastUpdated && !(normalizedState.lastUpdated instanceof Date)) {
|
|
1585
|
+
normalizedState.lastUpdated = new Date(normalizedState.lastUpdated);
|
|
1586
|
+
}
|
|
1587
|
+
this.stateCache.set(instanceId, normalizedState);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1001
1590
|
/**
|
|
1002
1591
|
* Start a new workflow instance.
|
|
1003
1592
|
*
|
|
@@ -1025,90 +1614,44 @@ class AXPWorkflowManager {
|
|
|
1025
1614
|
try {
|
|
1026
1615
|
const response = await this.workflowEngine.start({
|
|
1027
1616
|
workflowId,
|
|
1028
|
-
input
|
|
1617
|
+
input,
|
|
1029
1618
|
});
|
|
1030
1619
|
// Cache state (normalize Date)
|
|
1031
|
-
|
|
1620
|
+
let startNormalizedState = { ...response.state };
|
|
1032
1621
|
if (startNormalizedState.lastUpdated && !(startNormalizedState.lastUpdated instanceof Date)) {
|
|
1033
1622
|
startNormalizedState.lastUpdated = new Date(startNormalizedState.lastUpdated);
|
|
1034
1623
|
}
|
|
1035
1624
|
this.stateCache.set(response.instanceId, startNormalizedState);
|
|
1625
|
+
// 🎯 Interactive flow: Execute frontend activities that are NOT task-board types (those go to task board)
|
|
1626
|
+
let finalNextTask = response.pendingTask || null;
|
|
1627
|
+
let finalOutput = startNormalizedState.output;
|
|
1628
|
+
const pendingTask = response.pendingTask;
|
|
1629
|
+
if (pendingTask &&
|
|
1630
|
+
(pendingTask.executionMode === 'frontend' || pendingTask.executionMode === 'both') &&
|
|
1631
|
+
!axpIsWorkflowTaskBoardActivityType(pendingTask.activityType)) {
|
|
1632
|
+
const interactiveResult = await this.runInteractiveFlowWithContinuation(response.instanceId, pendingTask, startNormalizedState, { instanceId: response.instanceId, pendingNextTask: pendingTask }, isWorkflowContinuationSuppressed(input), (response.activityOutputs ?? response.state.activityOutputs));
|
|
1633
|
+
finalNextTask = interactiveResult.nextTask;
|
|
1634
|
+
startNormalizedState = interactiveResult.state;
|
|
1635
|
+
if (interactiveResult.output != null) {
|
|
1636
|
+
finalOutput = interactiveResult.output;
|
|
1637
|
+
}
|
|
1638
|
+
this.stateCache.set(response.instanceId, startNormalizedState);
|
|
1639
|
+
}
|
|
1640
|
+
// If backend returned null or non-executable task, return it as-is
|
|
1641
|
+
// Backend already decided workflow status (suspended, completed, etc.)
|
|
1036
1642
|
return {
|
|
1037
1643
|
success: true,
|
|
1038
1644
|
instanceId: response.instanceId,
|
|
1039
1645
|
state: startNormalizedState,
|
|
1040
|
-
nextTask:
|
|
1041
|
-
output:
|
|
1646
|
+
nextTask: finalNextTask,
|
|
1647
|
+
output: finalOutput,
|
|
1042
1648
|
};
|
|
1043
1649
|
}
|
|
1044
1650
|
catch (error) {
|
|
1045
1651
|
console.error('[AXPWorkflowManager] ❌ Error starting workflow:', error);
|
|
1046
1652
|
return {
|
|
1047
1653
|
success: false,
|
|
1048
|
-
error: error.message || 'Failed to start workflow'
|
|
1049
|
-
};
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
/**
|
|
1053
|
-
* Execute a frontend task.
|
|
1054
|
-
*
|
|
1055
|
-
* Delegates to FrontendTaskExecutor for actual execution.
|
|
1056
|
-
* Only executes tasks with executionMode 'frontend' or 'both'.
|
|
1057
|
-
*
|
|
1058
|
-
* @param task - Task to execute
|
|
1059
|
-
* @returns Execution result with output and outcome
|
|
1060
|
-
*
|
|
1061
|
-
* @throws Error if task is not a frontend task
|
|
1062
|
-
*/
|
|
1063
|
-
async execute(task) {
|
|
1064
|
-
return this.frontendTaskExecutor.execute(task);
|
|
1065
|
-
}
|
|
1066
|
-
/**
|
|
1067
|
-
* Complete a task and get next task from backend.
|
|
1068
|
-
*
|
|
1069
|
-
* Sends task result to backend API.
|
|
1070
|
-
* Backend decides: next task, fail, or complete workflow.
|
|
1071
|
-
*
|
|
1072
|
-
* @param instanceId - Workflow instance ID
|
|
1073
|
-
* @param task - Completed task
|
|
1074
|
-
* @param outcome - Task outcome (e.g., 'Done', 'Confirmed', 'Cancelled')
|
|
1075
|
-
* @param output - Task output/result (optional)
|
|
1076
|
-
* @returns Complete result with next task (if any)
|
|
1077
|
-
*/
|
|
1078
|
-
async complete(instanceId, task, outcome, output) {
|
|
1079
|
-
try {
|
|
1080
|
-
// Send result to backend - backend decides next step
|
|
1081
|
-
const response = await this.workflowEngine.resume({
|
|
1082
|
-
instanceId,
|
|
1083
|
-
stepId: task.activityId,
|
|
1084
|
-
taskToken: task.taskToken,
|
|
1085
|
-
outcome,
|
|
1086
|
-
userInput: output
|
|
1087
|
-
});
|
|
1088
|
-
// Update cache
|
|
1089
|
-
let completeNormalizedState = response.state;
|
|
1090
|
-
if (response.state) {
|
|
1091
|
-
// Normalize lastUpdated to Date (for cache safety)
|
|
1092
|
-
completeNormalizedState = { ...response.state };
|
|
1093
|
-
if (completeNormalizedState.lastUpdated && !(completeNormalizedState.lastUpdated instanceof Date)) {
|
|
1094
|
-
completeNormalizedState.lastUpdated = new Date(completeNormalizedState.lastUpdated);
|
|
1095
|
-
}
|
|
1096
|
-
this.stateCache.set(instanceId, completeNormalizedState);
|
|
1097
|
-
}
|
|
1098
|
-
return {
|
|
1099
|
-
success: true,
|
|
1100
|
-
instanceId,
|
|
1101
|
-
state: completeNormalizedState,
|
|
1102
|
-
nextTask: response.nextTask || null,
|
|
1103
|
-
output: response.output
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
catch (error) {
|
|
1107
|
-
console.error('[AXPWorkflowManager] ❌ Error completing task:', error);
|
|
1108
|
-
return {
|
|
1109
|
-
success: false,
|
|
1110
|
-
instanceId,
|
|
1111
|
-
error: error.message || 'Failed to complete task'
|
|
1654
|
+
error: error.message || 'Failed to start workflow',
|
|
1112
1655
|
};
|
|
1113
1656
|
}
|
|
1114
1657
|
}
|
|
@@ -1137,36 +1680,70 @@ class AXPWorkflowManager {
|
|
|
1137
1680
|
stepId,
|
|
1138
1681
|
taskToken,
|
|
1139
1682
|
outcome,
|
|
1140
|
-
userInput
|
|
1683
|
+
userInput,
|
|
1141
1684
|
});
|
|
1142
1685
|
// Update cache with state from backend
|
|
1143
|
-
|
|
1144
|
-
// Normalize lastUpdated to Date (for cache safety)
|
|
1145
|
-
const normalizedState = { ...response.state };
|
|
1146
|
-
if (normalizedState.lastUpdated && !(normalizedState.lastUpdated instanceof Date)) {
|
|
1147
|
-
normalizedState.lastUpdated = new Date(normalizedState.lastUpdated);
|
|
1148
|
-
}
|
|
1149
|
-
this.stateCache.set(instanceId, normalizedState);
|
|
1150
|
-
}
|
|
1151
|
-
// Normalize state Date for return
|
|
1152
|
-
const normalizedState = response.state ? { ...response.state } : undefined;
|
|
1686
|
+
let normalizedState = response.state ? { ...response.state } : undefined;
|
|
1153
1687
|
if (normalizedState && normalizedState.lastUpdated && !(normalizedState.lastUpdated instanceof Date)) {
|
|
1154
1688
|
normalizedState.lastUpdated = new Date(normalizedState.lastUpdated);
|
|
1155
1689
|
}
|
|
1156
|
-
|
|
1690
|
+
if (normalizedState) {
|
|
1691
|
+
this.stateCache.set(instanceId, normalizedState);
|
|
1692
|
+
}
|
|
1693
|
+
// 🎯 Interactive flow: Execute frontend activities that are NOT task-board types (those go to task board)
|
|
1694
|
+
let finalNextTask = response.nextTask || null;
|
|
1695
|
+
let finalOutput = response.output;
|
|
1696
|
+
const nextTask = response.nextTask;
|
|
1697
|
+
let resumeContinuationOffer;
|
|
1698
|
+
if (nextTask &&
|
|
1699
|
+
(nextTask.executionMode === 'frontend' || nextTask.executionMode === 'both') &&
|
|
1700
|
+
!axpIsWorkflowTaskBoardActivityType(nextTask.activityType)) {
|
|
1701
|
+
const completedBookmarkId = typeof userInput === 'object' && userInput != null && 'bookmarkId' in userInput
|
|
1702
|
+
? String(userInput.bookmarkId ?? '')
|
|
1703
|
+
: undefined;
|
|
1704
|
+
const interactiveResult = await this.runInteractiveFlowWithContinuation(instanceId, nextTask, normalizedState, {
|
|
1705
|
+
instanceId,
|
|
1706
|
+
completedActivityId: stepId,
|
|
1707
|
+
completedBookmarkId: completedBookmarkId || undefined,
|
|
1708
|
+
resumeOutcome: outcome,
|
|
1709
|
+
pendingNextTask: nextTask,
|
|
1710
|
+
}, isWorkflowContinuationSuppressed(userInput), normalizedState?.activityOutputs);
|
|
1711
|
+
finalNextTask = interactiveResult.nextTask;
|
|
1712
|
+
normalizedState = interactiveResult.state;
|
|
1713
|
+
resumeContinuationOffer = interactiveResult.continuationOffer;
|
|
1714
|
+
if (interactiveResult.output != null) {
|
|
1715
|
+
finalOutput = interactiveResult.output;
|
|
1716
|
+
}
|
|
1717
|
+
this.stateCache.set(instanceId, normalizedState);
|
|
1718
|
+
}
|
|
1719
|
+
// If backend returned null or non-executable task, return it as-is
|
|
1720
|
+
// Backend already decided workflow status (suspended, completed, etc.)
|
|
1721
|
+
const resumeResult = {
|
|
1157
1722
|
success: true,
|
|
1158
1723
|
instanceId,
|
|
1159
1724
|
state: normalizedState || response.state,
|
|
1160
|
-
nextTask:
|
|
1161
|
-
output:
|
|
1725
|
+
nextTask: finalNextTask,
|
|
1726
|
+
output: finalOutput,
|
|
1162
1727
|
};
|
|
1728
|
+
const completedBookmarkIdForContinuation = typeof userInput === 'object' && userInput != null && 'bookmarkId' in userInput
|
|
1729
|
+
? String(userInput.bookmarkId ?? '')
|
|
1730
|
+
: undefined;
|
|
1731
|
+
await this.invokeWorkflowContinuationAfterStep({
|
|
1732
|
+
instanceId,
|
|
1733
|
+
completedActivityId: stepId,
|
|
1734
|
+
completedBookmarkId: completedBookmarkIdForContinuation || undefined,
|
|
1735
|
+
resumeOutcome: outcome,
|
|
1736
|
+
pendingNextTask: finalNextTask,
|
|
1737
|
+
}, resumeContinuationOffer, isWorkflowContinuationSuppressed(userInput));
|
|
1738
|
+
return resumeResult;
|
|
1163
1739
|
}
|
|
1164
1740
|
catch (error) {
|
|
1165
|
-
|
|
1741
|
+
const { message, code } = getWorkflowEngineErrorInfo(error);
|
|
1166
1742
|
return {
|
|
1167
1743
|
success: false,
|
|
1168
1744
|
instanceId,
|
|
1169
|
-
error:
|
|
1745
|
+
error: message,
|
|
1746
|
+
errorCode: code,
|
|
1170
1747
|
};
|
|
1171
1748
|
}
|
|
1172
1749
|
}
|
|
@@ -1196,7 +1773,7 @@ class AXPWorkflowManager {
|
|
|
1196
1773
|
// Fetch from backend
|
|
1197
1774
|
try {
|
|
1198
1775
|
const state = await this.workflowEngine.getState({
|
|
1199
|
-
instanceId
|
|
1776
|
+
instanceId,
|
|
1200
1777
|
});
|
|
1201
1778
|
// Normalize lastUpdated to Date (for cache safety)
|
|
1202
1779
|
const normalizedState = { ...state };
|
|
@@ -1212,16 +1789,87 @@ class AXPWorkflowManager {
|
|
|
1212
1789
|
return null;
|
|
1213
1790
|
}
|
|
1214
1791
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1792
|
+
/**
|
|
1793
|
+
* Claim a pooled workflow task (assign current user on the bookmark without advancing the workflow).
|
|
1794
|
+
* Supported only when the injected workflow engine implements {@link AXPWorkflowEngine.claimTask}.
|
|
1795
|
+
*/
|
|
1796
|
+
async claimTask(instanceId, bookmarkId, stepId) {
|
|
1797
|
+
const claim = this.workflowEngine.claimTask?.bind(this.workflowEngine);
|
|
1798
|
+
if (!claim) {
|
|
1799
|
+
return {
|
|
1800
|
+
success: false,
|
|
1801
|
+
instanceId,
|
|
1802
|
+
error: 'Claim task is not supported by this workflow engine',
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
try {
|
|
1806
|
+
const result = await claim({ instanceId, bookmarkId, stepId });
|
|
1807
|
+
return {
|
|
1808
|
+
success: result.success,
|
|
1809
|
+
instanceId,
|
|
1810
|
+
error: result.error,
|
|
1811
|
+
errorCode: result.errorCode,
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
catch (error) {
|
|
1815
|
+
const { message, code } = getWorkflowEngineErrorInfo(error);
|
|
1816
|
+
return {
|
|
1817
|
+
success: false,
|
|
1818
|
+
instanceId,
|
|
1819
|
+
error: message,
|
|
1820
|
+
errorCode: code,
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
/**
|
|
1825
|
+
* Reassign a human-task bookmark to the current user without advancing the workflow.
|
|
1826
|
+
* Supported only when the injected workflow engine implements {@link AXPWorkflowEngine.reassignTaskToSelf}.
|
|
1827
|
+
*/
|
|
1828
|
+
async reassignTaskToSelf(instanceId, bookmarkId, stepId) {
|
|
1829
|
+
const reassign = this.workflowEngine.reassignTaskToSelf?.bind(this.workflowEngine);
|
|
1830
|
+
if (!reassign) {
|
|
1831
|
+
return {
|
|
1832
|
+
success: false,
|
|
1833
|
+
instanceId,
|
|
1834
|
+
error: 'Reassign task is not supported by this workflow engine',
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
try {
|
|
1838
|
+
const result = await reassign({ instanceId, bookmarkId, stepId });
|
|
1839
|
+
return {
|
|
1840
|
+
success: result.success,
|
|
1841
|
+
instanceId,
|
|
1842
|
+
error: result.error,
|
|
1843
|
+
errorCode: result.errorCode,
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
catch (error) {
|
|
1847
|
+
const { message, code } = getWorkflowEngineErrorInfo(error);
|
|
1848
|
+
return {
|
|
1849
|
+
success: false,
|
|
1850
|
+
instanceId,
|
|
1851
|
+
error: message,
|
|
1852
|
+
errorCode: code,
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1857
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowManager, providedIn: 'root' }); }
|
|
1217
1858
|
}
|
|
1218
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1859
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowManager, decorators: [{
|
|
1219
1860
|
type: Injectable,
|
|
1220
1861
|
args: [{
|
|
1221
|
-
providedIn: 'root'
|
|
1862
|
+
providedIn: 'root',
|
|
1222
1863
|
}]
|
|
1223
1864
|
}] });
|
|
1224
1865
|
|
|
1866
|
+
const AXP_WORKFLOW_PROVIDER = new InjectionToken('AXP_WORKFLOW_PROVIDER', {
|
|
1867
|
+
factory: () => [],
|
|
1868
|
+
});
|
|
1869
|
+
const AXP_WORKFLOW_CATEGORY_PROVIDER = new InjectionToken('AXP_WORKFLOW_CATEGORY_PROVIDER', {
|
|
1870
|
+
factory: () => [],
|
|
1871
|
+
});
|
|
1872
|
+
|
|
1225
1873
|
//#endregion
|
|
1226
1874
|
/**
|
|
1227
1875
|
* Local engine implementation that manages workflow progression and state.
|
|
@@ -1232,16 +1880,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
1232
1880
|
* - Maintains workflow state in memory
|
|
1233
1881
|
* - Does not require backend API calls
|
|
1234
1882
|
*
|
|
1235
|
-
* Execution of frontend tasks is handled by AXPWorkflowManager via
|
|
1883
|
+
* Execution of frontend tasks is handled by AXPWorkflowManager via ActivityExecutor.
|
|
1236
1884
|
* This engine only manages workflow progression and state storage.
|
|
1237
1885
|
*
|
|
1238
1886
|
* This is the DEFAULT engine provider. Applications can override it with
|
|
1239
1887
|
* an API-based engine implementation.
|
|
1240
1888
|
*/
|
|
1241
1889
|
class AXPWorkflowLocalEngine {
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
this.
|
|
1890
|
+
constructor() {
|
|
1891
|
+
//#region ---- Services & Dependencies ----
|
|
1892
|
+
this.activityDefinitionService = inject(AXPActivityDefinitionService);
|
|
1893
|
+
this.workflowProviders = inject(AXP_WORKFLOW_PROVIDER, { optional: true }) || [];
|
|
1894
|
+
this.multiLanguageResolver = inject(AXTranslationService);
|
|
1245
1895
|
//#endregion
|
|
1246
1896
|
//#region ---- Instance Storage ----
|
|
1247
1897
|
/**
|
|
@@ -1267,20 +1917,30 @@ class AXPWorkflowLocalEngine {
|
|
|
1267
1917
|
* Backend activities are skipped.
|
|
1268
1918
|
*/
|
|
1269
1919
|
async start(request) {
|
|
1920
|
+
console.log(`[WorkflowLocalEngine] 🚀 Starting workflow: ${request.workflowId}`, request);
|
|
1270
1921
|
// Generate instance ID
|
|
1271
1922
|
const instanceId = AXPDataGenerator.uuid();
|
|
1272
1923
|
const now = new Date();
|
|
1273
1924
|
// Load workflow definition
|
|
1925
|
+
console.log(`[WorkflowLocalEngine] 📥 Loading workflow definition: ${request.workflowId}`);
|
|
1274
1926
|
const definition = await this.getDefinition(request.workflowId);
|
|
1275
1927
|
if (!definition) {
|
|
1928
|
+
console.error(`[WorkflowLocalEngine] ❌ Workflow definition not found: ${request.workflowId}`);
|
|
1276
1929
|
throw new Error(`Workflow definition not found: ${request.workflowId}`);
|
|
1277
1930
|
}
|
|
1931
|
+
console.log(`[WorkflowLocalEngine] ✅ Definition loaded:`, {
|
|
1932
|
+
name: definition.name,
|
|
1933
|
+
activitiesCount: definition.graph?.activities?.length || 0,
|
|
1934
|
+
connectionsCount: definition.graph?.connections?.length || 0,
|
|
1935
|
+
});
|
|
1278
1936
|
// Initialize workflow state
|
|
1279
1937
|
const state = {
|
|
1280
1938
|
instanceId,
|
|
1281
1939
|
workflowId: request.workflowId,
|
|
1282
1940
|
status: 'running',
|
|
1283
1941
|
variables: {},
|
|
1942
|
+
activityOutputs: {},
|
|
1943
|
+
lastActivityOutput: undefined,
|
|
1284
1944
|
input: request.input || {},
|
|
1285
1945
|
output: undefined,
|
|
1286
1946
|
lastUpdated: now,
|
|
@@ -1297,13 +1957,22 @@ class AXPWorkflowLocalEngine {
|
|
|
1297
1957
|
// Store instance
|
|
1298
1958
|
this.instances.set(instanceId, localState);
|
|
1299
1959
|
// Execute workflow steps
|
|
1960
|
+
console.log(`[WorkflowLocalEngine] ⚙️ Executing workflow steps...`);
|
|
1300
1961
|
const pendingTask = await this.executeWorkflowSteps(localState);
|
|
1301
1962
|
// Update state
|
|
1302
1963
|
localState.state.lastUpdated = new Date();
|
|
1964
|
+
console.log(`[WorkflowLocalEngine] ✅ Workflow started:`, {
|
|
1965
|
+
instanceId,
|
|
1966
|
+
status: localState.state.status,
|
|
1967
|
+
hasPendingTask: !!pendingTask,
|
|
1968
|
+
pendingTaskType: pendingTask?.activityType,
|
|
1969
|
+
});
|
|
1303
1970
|
return {
|
|
1304
1971
|
instanceId,
|
|
1305
1972
|
state: localState.state,
|
|
1306
1973
|
pendingTask: pendingTask || null,
|
|
1974
|
+
activityOutputs: localState.state.activityOutputs,
|
|
1975
|
+
lastActivityOutput: localState.state.lastActivityOutput,
|
|
1307
1976
|
};
|
|
1308
1977
|
}
|
|
1309
1978
|
/**
|
|
@@ -1324,11 +1993,18 @@ class AXPWorkflowLocalEngine {
|
|
|
1324
1993
|
throw new Error(`Workflow instance not found: ${request.instanceId}`);
|
|
1325
1994
|
}
|
|
1326
1995
|
// Store activity result (from external execution)
|
|
1996
|
+
const outcome = request.outcome ?? 'Done';
|
|
1327
1997
|
localState.activityResults.set(request.stepId, {
|
|
1328
1998
|
output: request.userInput || {},
|
|
1329
|
-
outcome
|
|
1999
|
+
outcome,
|
|
1330
2000
|
});
|
|
1331
2001
|
localState.completedActivities.add(request.stepId);
|
|
2002
|
+
// Store activity output for expression evaluation
|
|
2003
|
+
localState.state.activityOutputs = {
|
|
2004
|
+
...(localState.state.activityOutputs || {}),
|
|
2005
|
+
[request.stepId]: request.userInput || {},
|
|
2006
|
+
};
|
|
2007
|
+
localState.state.lastActivityOutput = request.userInput || {};
|
|
1332
2008
|
// Merge output/userInput into state variables
|
|
1333
2009
|
if (request.userInput) {
|
|
1334
2010
|
localState.state.variables = {
|
|
@@ -1336,6 +2012,11 @@ class AXPWorkflowLocalEngine {
|
|
|
1336
2012
|
...(request.userInput || {}),
|
|
1337
2013
|
};
|
|
1338
2014
|
}
|
|
2015
|
+
localState.state.variables = {
|
|
2016
|
+
...localState.state.variables,
|
|
2017
|
+
[`${request.stepId}_outcome`]: outcome,
|
|
2018
|
+
[`${request.stepId}_activityOutput`]: request.userInput || {},
|
|
2019
|
+
};
|
|
1339
2020
|
// Mark activity as completed and continue progression
|
|
1340
2021
|
// Continue progressing workflow steps (skipping backend activities)
|
|
1341
2022
|
const nextTask = await this.executeWorkflowSteps(localState);
|
|
@@ -1348,7 +2029,7 @@ class AXPWorkflowLocalEngine {
|
|
|
1348
2029
|
}
|
|
1349
2030
|
return {
|
|
1350
2031
|
output: request.userInput || {},
|
|
1351
|
-
outcomes: { [
|
|
2032
|
+
outcomes: { [outcome]: true },
|
|
1352
2033
|
state: localState.state,
|
|
1353
2034
|
nextTask: nextTask || null,
|
|
1354
2035
|
};
|
|
@@ -1371,15 +2052,26 @@ class AXPWorkflowLocalEngine {
|
|
|
1371
2052
|
//#endregion
|
|
1372
2053
|
//#region ---- Private Methods ----
|
|
1373
2054
|
/**
|
|
1374
|
-
* Get workflow definition from available
|
|
2055
|
+
* Get workflow definition from available providers.
|
|
1375
2056
|
*/
|
|
1376
2057
|
async getDefinition(workflowId) {
|
|
1377
|
-
// Try all
|
|
1378
|
-
const
|
|
1379
|
-
for (const
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
2058
|
+
// Try all providers in order
|
|
2059
|
+
const resolvedProviders = await Promise.allSettled(this.workflowProviders);
|
|
2060
|
+
for (const p of resolvedProviders) {
|
|
2061
|
+
if (p.status === 'fulfilled' && p.value) {
|
|
2062
|
+
const provider = p.value;
|
|
2063
|
+
// Check if provider has getByName method
|
|
2064
|
+
if (typeof provider.getByName === 'function') {
|
|
2065
|
+
try {
|
|
2066
|
+
const definition = await provider.getByName(workflowId);
|
|
2067
|
+
if (definition) {
|
|
2068
|
+
return definition;
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
catch {
|
|
2072
|
+
// Continue on error - try other providers
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
1383
2075
|
}
|
|
1384
2076
|
}
|
|
1385
2077
|
return null;
|
|
@@ -1393,20 +2085,20 @@ class AXPWorkflowLocalEngine {
|
|
|
1393
2085
|
* Returns the next pending task (if frontend activity found) or null (if completed).
|
|
1394
2086
|
*/
|
|
1395
2087
|
async executeWorkflowSteps(localState) {
|
|
1396
|
-
const
|
|
1397
|
-
const activities =
|
|
1398
|
-
const connections =
|
|
2088
|
+
const graph = localState.definition.graph;
|
|
2089
|
+
const activities = graph.activities || [];
|
|
2090
|
+
const connections = graph.connections || [];
|
|
1399
2091
|
// Build activity map
|
|
1400
2092
|
const activityMap = new Map();
|
|
1401
|
-
activities.forEach(activity => {
|
|
2093
|
+
activities.forEach((activity) => {
|
|
1402
2094
|
activityMap.set(activity.id, activity);
|
|
1403
2095
|
});
|
|
1404
2096
|
// Build connection graph
|
|
1405
2097
|
const outgoingConnections = new Map();
|
|
1406
2098
|
const incomingConnections = new Map();
|
|
1407
|
-
connections.forEach(conn => {
|
|
1408
|
-
const sourceId = conn.source.
|
|
1409
|
-
const targetId = conn.target.
|
|
2099
|
+
connections.forEach((conn) => {
|
|
2100
|
+
const sourceId = conn.source.activtyName;
|
|
2101
|
+
const targetId = conn.target.activtyName;
|
|
1410
2102
|
if (!outgoingConnections.has(sourceId)) {
|
|
1411
2103
|
outgoingConnections.set(sourceId, []);
|
|
1412
2104
|
}
|
|
@@ -1416,19 +2108,25 @@ class AXPWorkflowLocalEngine {
|
|
|
1416
2108
|
}
|
|
1417
2109
|
incomingConnections.get(targetId).push(conn);
|
|
1418
2110
|
});
|
|
1419
|
-
// Find starting activity (no incoming connections, or first activity)
|
|
2111
|
+
// Find starting activity (use startActivityId or no incoming connections, or first activity)
|
|
1420
2112
|
let currentActivityId = localState.currentActivityId;
|
|
1421
2113
|
if (!currentActivityId) {
|
|
1422
|
-
//
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
currentActivityId = activity.id;
|
|
1426
|
-
break;
|
|
1427
|
-
}
|
|
2114
|
+
// Use startActivityId if available
|
|
2115
|
+
if (graph.startActivityId) {
|
|
2116
|
+
currentActivityId = graph.startActivityId;
|
|
1428
2117
|
}
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
2118
|
+
else {
|
|
2119
|
+
// Find root activity (no incoming connections)
|
|
2120
|
+
for (const activity of activities) {
|
|
2121
|
+
if (!incomingConnections.has(activity.id)) {
|
|
2122
|
+
currentActivityId = activity.id;
|
|
2123
|
+
break;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
// If no root found, use first activity
|
|
2127
|
+
if (!currentActivityId && activities.length > 0) {
|
|
2128
|
+
currentActivityId = activities[0].id;
|
|
2129
|
+
}
|
|
1432
2130
|
}
|
|
1433
2131
|
}
|
|
1434
2132
|
// Execute workflow steps
|
|
@@ -1444,11 +2142,21 @@ class AXPWorkflowLocalEngine {
|
|
|
1444
2142
|
currentActivityId = nextId ?? undefined;
|
|
1445
2143
|
continue;
|
|
1446
2144
|
}
|
|
1447
|
-
//
|
|
1448
|
-
|
|
2145
|
+
// Get activity definition to retrieve executionMode and title
|
|
2146
|
+
console.log(`[WorkflowLocalEngine] 🔍 Getting activity definition for: ${activity.name}`);
|
|
2147
|
+
const activityDefinition = await this.activityDefinitionService.getActivityByName(activity.name);
|
|
2148
|
+
console.log(`[WorkflowLocalEngine] 📋 Activity definition:`, {
|
|
2149
|
+
name: activityDefinition?.name,
|
|
2150
|
+
type: activityDefinition?.type,
|
|
2151
|
+
executionMode: activityDefinition?.executionMode,
|
|
2152
|
+
title: activityDefinition?.title,
|
|
2153
|
+
found: !!activityDefinition,
|
|
2154
|
+
});
|
|
2155
|
+
const executionMode = activityDefinition?.executionMode || 'frontend';
|
|
2156
|
+
const activityTitle = this.multiLanguageResolver.resolve(activityDefinition?.title) || activityDefinition?.name;
|
|
1449
2157
|
// Handle backend activities: skip
|
|
1450
2158
|
if (executionMode === 'backend') {
|
|
1451
|
-
console.log(`[WorkflowLocalEngine] ⏭️ Skipping backend activity: ${activity.
|
|
2159
|
+
console.log(`[WorkflowLocalEngine] ⏭️ Skipping backend activity: ${activity.name} (${activity.id})`);
|
|
1452
2160
|
localState.completedActivities.add(currentActivityId);
|
|
1453
2161
|
localState.activityResults.set(currentActivityId, {
|
|
1454
2162
|
output: null,
|
|
@@ -1462,14 +2170,14 @@ class AXPWorkflowLocalEngine {
|
|
|
1462
2170
|
// Handle frontend/both activities: return as pendingTask (do NOT execute)
|
|
1463
2171
|
if (executionMode === 'frontend' || executionMode === 'both') {
|
|
1464
2172
|
// Create task for external execution
|
|
2173
|
+
// Note: Expression evaluation will be done by ActivityExecutor
|
|
1465
2174
|
const task = {
|
|
1466
2175
|
taskToken: AXPDataGenerator.uuid(),
|
|
1467
2176
|
activityId: activity.id,
|
|
1468
|
-
activityType: activity.
|
|
1469
|
-
activityName:
|
|
2177
|
+
activityType: activity.name,
|
|
2178
|
+
activityName: activityTitle || undefined,
|
|
1470
2179
|
executionMode: executionMode,
|
|
1471
|
-
input: activity
|
|
1472
|
-
config: activity.customProperties || {},
|
|
2180
|
+
input: activity.inputs || {}, // Pass raw inputs - executor will evaluate
|
|
1473
2181
|
};
|
|
1474
2182
|
// Store task token for secure resume
|
|
1475
2183
|
this.taskTokens.set(task.taskToken, {
|
|
@@ -1509,36 +2217,63 @@ class AXPWorkflowLocalEngine {
|
|
|
1509
2217
|
for (const conn of connections) {
|
|
1510
2218
|
const sourcePort = conn.source.port || 'Done';
|
|
1511
2219
|
if (sourcePort === outcome) {
|
|
1512
|
-
return conn.target.
|
|
2220
|
+
return conn.target.activtyName;
|
|
1513
2221
|
}
|
|
1514
2222
|
}
|
|
1515
2223
|
// If no matching outcome, use first connection (default path)
|
|
1516
2224
|
if (connections.length > 0) {
|
|
1517
|
-
return connections[0].target.
|
|
2225
|
+
return connections[0].target.activtyName;
|
|
1518
2226
|
}
|
|
1519
2227
|
return null;
|
|
1520
2228
|
}
|
|
1521
|
-
|
|
1522
|
-
|
|
2229
|
+
async frontActivtyComplete(request) {
|
|
2230
|
+
const localState = this.instances.get(request.instanceId);
|
|
2231
|
+
if (!localState) {
|
|
2232
|
+
throw new Error(`Workflow instance not found: ${request.instanceId}`);
|
|
2233
|
+
}
|
|
2234
|
+
// Store activity result
|
|
2235
|
+
const outcome = request.outcome ?? 'Done';
|
|
2236
|
+
localState.activityResults.set(request.activityNode, {
|
|
2237
|
+
output: request.output || {},
|
|
2238
|
+
outcome,
|
|
2239
|
+
});
|
|
2240
|
+
localState.completedActivities.add(request.activityNode);
|
|
2241
|
+
// Store outputs for expression evaluation
|
|
2242
|
+
localState.state.activityOutputs = {
|
|
2243
|
+
...(localState.state.activityOutputs || {}),
|
|
2244
|
+
[request.activityNode]: request.output || {},
|
|
2245
|
+
};
|
|
2246
|
+
localState.state.lastActivityOutput = request.output || {};
|
|
2247
|
+
// Merge output into workflow variables
|
|
2248
|
+
localState.state.variables = {
|
|
2249
|
+
...localState.state.variables,
|
|
2250
|
+
...(request.output || {}),
|
|
2251
|
+
};
|
|
2252
|
+
// Continue workflow progression
|
|
2253
|
+
const nextTask = await this.executeWorkflowSteps(localState);
|
|
2254
|
+
// Update state timestamp
|
|
2255
|
+
localState.state.lastUpdated = new Date();
|
|
2256
|
+
// Determine final status
|
|
2257
|
+
if (!nextTask && localState.state.status === 'running') {
|
|
2258
|
+
localState.state.status = 'completed';
|
|
2259
|
+
localState.state.output = localState.state.variables;
|
|
2260
|
+
}
|
|
2261
|
+
return {
|
|
2262
|
+
output: request.output || {},
|
|
2263
|
+
outcomes: { [outcome]: true },
|
|
2264
|
+
nextTask: nextTask || null,
|
|
2265
|
+
state: localState.state,
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowLocalEngine, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2269
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowLocalEngine }); }
|
|
1523
2270
|
}
|
|
1524
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2271
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowLocalEngine, decorators: [{
|
|
1525
2272
|
type: Injectable
|
|
1526
|
-
}]
|
|
1527
|
-
type: Optional
|
|
1528
|
-
}, {
|
|
1529
|
-
type: Inject,
|
|
1530
|
-
args: [AXP_WORKFLOW_DEFINITION_LOADER]
|
|
1531
|
-
}] }] });
|
|
2273
|
+
}] });
|
|
1532
2274
|
|
|
1533
2275
|
// Workflow Runtime Services
|
|
1534
2276
|
|
|
1535
|
-
const AXP_WORKFLOW_PROVIDER = new InjectionToken('AXP_WORKFLOW_PROVIDER', {
|
|
1536
|
-
factory: () => [],
|
|
1537
|
-
});
|
|
1538
|
-
const AXP_WORKFLOW_CATEGORY_PROVIDER = new InjectionToken('AXP_WORKFLOW_CATEGORY_PROVIDER', {
|
|
1539
|
-
factory: () => [],
|
|
1540
|
-
});
|
|
1541
|
-
|
|
1542
2277
|
//#region ---- Imports ----
|
|
1543
2278
|
//#endregion
|
|
1544
2279
|
/**
|
|
@@ -1659,7 +2394,7 @@ class AXPWorkflowDefinitionService {
|
|
|
1659
2394
|
* - Returns cached result on subsequent calls
|
|
1660
2395
|
*
|
|
1661
2396
|
* @param categoryId - Category ID to get workflow definitions from
|
|
1662
|
-
* @returns Array of workflow
|
|
2397
|
+
* @returns Array of workflow definitions
|
|
1663
2398
|
*/
|
|
1664
2399
|
async getWorkflowsByCategoryId(categoryId) {
|
|
1665
2400
|
// ✅ Fast path: Return cached result
|
|
@@ -1684,12 +2419,12 @@ class AXPWorkflowDefinitionService {
|
|
|
1684
2419
|
return requestPromise;
|
|
1685
2420
|
}
|
|
1686
2421
|
/**
|
|
1687
|
-
* Get single workflow definition
|
|
2422
|
+
* Get single workflow definition by name with O(1) lookup
|
|
1688
2423
|
*
|
|
1689
2424
|
* Optimization: Uses Map for instant retrieval
|
|
1690
2425
|
*
|
|
1691
2426
|
* @param name - Workflow name (unique identifier)
|
|
1692
|
-
* @returns Workflow definition
|
|
2427
|
+
* @returns Workflow definition or undefined if not found
|
|
1693
2428
|
*/
|
|
1694
2429
|
async getWorkflowByName(name) {
|
|
1695
2430
|
// ✅ Fast path: O(1) lookup in cache
|
|
@@ -1718,13 +2453,18 @@ class AXPWorkflowDefinitionService {
|
|
|
1718
2453
|
}
|
|
1719
2454
|
}
|
|
1720
2455
|
// ✅ Try loading the workflow definition to find its category
|
|
2456
|
+
// Note: AXPWorkflowDefinition doesn't have category field
|
|
2457
|
+
// Category is managed separately through category providers
|
|
2458
|
+
// This method searches through cached categories
|
|
1721
2459
|
const definition = await this.getWorkflowByName(workflowName);
|
|
1722
|
-
if (definition
|
|
1723
|
-
//
|
|
2460
|
+
if (definition) {
|
|
2461
|
+
// Search through all categories to find which one contains this workflow
|
|
1724
2462
|
const categories = await this.getCategories();
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
2463
|
+
for (const category of categories) {
|
|
2464
|
+
const workflows = await this.getWorkflowsByCategoryId(category.id);
|
|
2465
|
+
if (workflows.some(w => w.name === workflowName)) {
|
|
2466
|
+
return category.id;
|
|
2467
|
+
}
|
|
1728
2468
|
}
|
|
1729
2469
|
}
|
|
1730
2470
|
return undefined;
|
|
@@ -1850,12 +2590,12 @@ class AXPWorkflowDefinitionService {
|
|
|
1850
2590
|
const resolvedProviders = await Promise.allSettled(this.workflowProviders);
|
|
1851
2591
|
// Try providers first
|
|
1852
2592
|
for (const p of resolvedProviders) {
|
|
1853
|
-
if (p.status === 'fulfilled' && p.value && typeof p.value.
|
|
2593
|
+
if (p.status === 'fulfilled' && p.value && typeof p.value.getByName === 'function') {
|
|
1854
2594
|
try {
|
|
1855
|
-
const
|
|
1856
|
-
if (
|
|
1857
|
-
this.workflowsByName.set(name,
|
|
1858
|
-
return
|
|
2595
|
+
const definition = await p.value.getByName(name);
|
|
2596
|
+
if (definition) {
|
|
2597
|
+
this.workflowsByName.set(name, definition);
|
|
2598
|
+
return definition;
|
|
1859
2599
|
}
|
|
1860
2600
|
}
|
|
1861
2601
|
catch {
|
|
@@ -1949,17 +2689,17 @@ class AXPWorkflowDefinitionService {
|
|
|
1949
2689
|
this.pendingWorkflowsRequests.clear();
|
|
1950
2690
|
this.pendingWorkflowRequests.clear();
|
|
1951
2691
|
}
|
|
1952
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1953
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2692
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDefinitionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2693
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDefinitionService, providedIn: 'root' }); }
|
|
1954
2694
|
}
|
|
1955
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2695
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowDefinitionService, decorators: [{
|
|
1956
2696
|
type: Injectable,
|
|
1957
2697
|
args: [{
|
|
1958
2698
|
providedIn: 'root',
|
|
1959
2699
|
}]
|
|
1960
2700
|
}] });
|
|
1961
2701
|
|
|
1962
|
-
// Workflow
|
|
2702
|
+
// Workflow Instance Types (Storage/Database)
|
|
1963
2703
|
|
|
1964
2704
|
class AXPWorkflowModule {
|
|
1965
2705
|
static forRoot(config) {
|
|
@@ -2044,9 +2784,9 @@ class AXPWorkflowModule {
|
|
|
2044
2784
|
f();
|
|
2045
2785
|
});
|
|
2046
2786
|
}
|
|
2047
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2048
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
2049
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
2787
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowModule, deps: [{ token: 'AXPWorkflowModuleFactory', optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
2788
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowModule }); }
|
|
2789
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowModule, providers: [
|
|
2050
2790
|
AXPWorkflowLocalEngine,
|
|
2051
2791
|
{
|
|
2052
2792
|
provide: AXP_WORKFLOW_ENGINE,
|
|
@@ -2055,7 +2795,7 @@ class AXPWorkflowModule {
|
|
|
2055
2795
|
AXPWorkflowManager,
|
|
2056
2796
|
] }); }
|
|
2057
2797
|
}
|
|
2058
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2798
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowModule, decorators: [{
|
|
2059
2799
|
type: NgModule,
|
|
2060
2800
|
args: [{
|
|
2061
2801
|
imports: [],
|
|
@@ -2081,5 +2821,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
2081
2821
|
* Generated bundle index. Do not edit.
|
|
2082
2822
|
*/
|
|
2083
2823
|
|
|
2084
|
-
export { AXPActivityDefinitionService, AXPWorkflowAction, AXPWorkflowContext, AXPWorkflowDefinitionService, AXPWorkflowError, AXPWorkflowEventService, AXPWorkflowFunction, AXPWorkflowLocalEngine, AXPWorkflowManager, AXPWorkflowModule, AXPWorkflowRegistryService, AXPWorkflowService, AXP_ACTIVITY_CATEGORY_PROVIDER, AXP_ACTIVITY_PROVIDER, AXP_WORKFLOW_CATEGORY_PROVIDER,
|
|
2824
|
+
export { AXPActivityDefinitionService, AXPWorkflowAction, AXPWorkflowContext, AXPWorkflowDefinitionService, AXPWorkflowEngineError, AXPWorkflowError, AXPWorkflowEventService, AXPWorkflowFunction, AXPWorkflowLocalEngine, AXPWorkflowManager, AXPWorkflowModule, AXPWorkflowRegistryService, AXPWorkflowService, AXP_ACTIVITY_CATEGORY_PROVIDER, AXP_ACTIVITY_PROVIDER, AXP_WORKFLOW_CATEGORY_PROVIDER, AXP_WORKFLOW_CONTINUATION_HOOK, AXP_WORKFLOW_ENGINE, AXP_WORKFLOW_ERROR_CODES, AXP_WORKFLOW_PROVIDER, AXP_WORKFLOW_SUPPRESS_CONTINUATION_INPUT_KEY, AXP_WORKFLOW_TASK_BOARD_ACTIVITY_TYPES, ActivityExecutor, WorkflowExpressionScopeService, axpIsWorkflowInlineFrontendTask, axpIsWorkflowInteractiveFrontendTask, axpIsWorkflowTaskBoardActivityType, axpResolveWorkflowContinuationBeforeInteractive, axpShouldOfferBeforeInteractiveFlow, axpShouldOfferWorkflowContinuationAfterStep, axpShouldSkipBeforeInteractiveFromMetadata, createWorkFlowEvent, getWorkflowEngineErrorCode, getWorkflowEngineErrorInfo, isWorkflowContinuationSuppressed, ofType };
|
|
2085
2825
|
//# sourceMappingURL=acorex-platform-workflow.mjs.map
|