@masterteam/workflow 0.0.35 → 0.0.36
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/assets/i18n/ar.json +12 -1
- package/assets/i18n/en.json +12 -1
- package/assets/workflow.css +1 -1
- package/fesm2022/masterteam-workflow.mjs +511 -24
- package/fesm2022/masterteam-workflow.mjs.map +1 -1
- package/package.json +5 -5
- package/types/masterteam-workflow.d.ts +149 -10
|
@@ -20,7 +20,7 @@ import { StructureBuilder } from '@masterteam/structure-builder';
|
|
|
20
20
|
import { Tabs } from '@masterteam/components/tabs';
|
|
21
21
|
import { Skeleton } from 'primeng/skeleton';
|
|
22
22
|
import { Action, Selector, State, Store, select } from '@ngxs/store';
|
|
23
|
-
import { HttpClient, HttpContextToken } from '@angular/common/http';
|
|
23
|
+
import { HttpClient, HttpParams, HttpContextToken } from '@angular/common/http';
|
|
24
24
|
import { of } from 'rxjs';
|
|
25
25
|
import { tap, catchError, finalize } from 'rxjs/operators';
|
|
26
26
|
|
|
@@ -68,6 +68,17 @@ class GetAppActionDetail {
|
|
|
68
68
|
this.actionKey = actionKey;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
class GetAppActionOptions {
|
|
72
|
+
actionKey;
|
|
73
|
+
fieldKey;
|
|
74
|
+
params;
|
|
75
|
+
static type = '[Workflow] Get App Action Options';
|
|
76
|
+
constructor(actionKey, fieldKey, params) {
|
|
77
|
+
this.actionKey = actionKey;
|
|
78
|
+
this.fieldKey = fieldKey;
|
|
79
|
+
this.params = params;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
71
82
|
class GetStep {
|
|
72
83
|
stepId;
|
|
73
84
|
static type = '[Workflow] Get Step';
|
|
@@ -176,6 +187,7 @@ const DEFAULT_STATE = {
|
|
|
176
187
|
roles: [],
|
|
177
188
|
appActionDescriptors: [],
|
|
178
189
|
selectedAppActionDescriptor: null,
|
|
190
|
+
appActionOptionsCache: {},
|
|
179
191
|
selectedStep: null,
|
|
180
192
|
isFlowValid: null,
|
|
181
193
|
loadingActive: [],
|
|
@@ -217,6 +229,9 @@ let WorkflowState = class WorkflowState {
|
|
|
217
229
|
static selectedAppActionDescriptor(state) {
|
|
218
230
|
return state.selectedAppActionDescriptor;
|
|
219
231
|
}
|
|
232
|
+
static appActionOptionsCache(state) {
|
|
233
|
+
return state.appActionOptionsCache ?? {};
|
|
234
|
+
}
|
|
220
235
|
static selectedStep(state) {
|
|
221
236
|
return state.selectedStep;
|
|
222
237
|
}
|
|
@@ -427,6 +442,64 @@ let WorkflowState = class WorkflowState {
|
|
|
427
442
|
return of(null);
|
|
428
443
|
}), finalize(() => endLoading(ctx, 'getAppActionDetail')));
|
|
429
444
|
}
|
|
445
|
+
getAppActionOptions(ctx, action) {
|
|
446
|
+
const cacheKey = buildAppActionOptionsCacheKey(action.actionKey, action.fieldKey, action.params);
|
|
447
|
+
const cached = ctx.getState().appActionOptionsCache?.[cacheKey];
|
|
448
|
+
if (cached && !cached.errorCode) {
|
|
449
|
+
return of(cached.options);
|
|
450
|
+
}
|
|
451
|
+
startLoading(ctx, 'getAppActionOptions');
|
|
452
|
+
let params = new HttpParams();
|
|
453
|
+
if (action.params) {
|
|
454
|
+
for (const [key, value] of Object.entries(action.params)) {
|
|
455
|
+
if (value === null || value === undefined || value === '')
|
|
456
|
+
continue;
|
|
457
|
+
params = params.set(key, String(value));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
const url = `${this.workflowAppActionsUrl}/actions/${encodeURIComponent(action.actionKey)}/options/${encodeURIComponent(action.fieldKey)}`;
|
|
461
|
+
return this.http
|
|
462
|
+
.get(url, params.keys().length ? { params } : {})
|
|
463
|
+
.pipe(tap((response) => {
|
|
464
|
+
const options = normalizeWorkflowAppActionOptions(response?.data);
|
|
465
|
+
const entry = {
|
|
466
|
+
options,
|
|
467
|
+
errorCode: null,
|
|
468
|
+
errorMessage: null,
|
|
469
|
+
loadedAt: Date.now(),
|
|
470
|
+
};
|
|
471
|
+
const state = ctx.getState();
|
|
472
|
+
ctx.patchState({
|
|
473
|
+
appActionOptionsCache: {
|
|
474
|
+
...(state.appActionOptionsCache ?? {}),
|
|
475
|
+
[cacheKey]: entry,
|
|
476
|
+
},
|
|
477
|
+
});
|
|
478
|
+
}), catchError((error) => {
|
|
479
|
+
const code = error?.error?.errors?.code ??
|
|
480
|
+
error?.error?.code ??
|
|
481
|
+
'workflow_app_action_options_error';
|
|
482
|
+
const message = error?.error?.errors?.message ??
|
|
483
|
+
error?.error?.message ??
|
|
484
|
+
error?.message ??
|
|
485
|
+
'Failed to load options';
|
|
486
|
+
const state = ctx.getState();
|
|
487
|
+
const entry = {
|
|
488
|
+
options: [],
|
|
489
|
+
errorCode: String(code),
|
|
490
|
+
errorMessage: String(message),
|
|
491
|
+
loadedAt: Date.now(),
|
|
492
|
+
};
|
|
493
|
+
ctx.patchState({
|
|
494
|
+
appActionOptionsCache: {
|
|
495
|
+
...(state.appActionOptionsCache ?? {}),
|
|
496
|
+
[cacheKey]: entry,
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
setLoadingError(ctx, 'getAppActionOptions', String(message));
|
|
500
|
+
return of([]);
|
|
501
|
+
}), finalize(() => endLoading(ctx, 'getAppActionOptions')));
|
|
502
|
+
}
|
|
430
503
|
getStep(ctx, action) {
|
|
431
504
|
startLoading(ctx, 'getStep');
|
|
432
505
|
return this.http
|
|
@@ -858,6 +931,9 @@ __decorate([
|
|
|
858
931
|
__decorate([
|
|
859
932
|
Action(GetAppActionDetail)
|
|
860
933
|
], WorkflowState.prototype, "getAppActionDetail", null);
|
|
934
|
+
__decorate([
|
|
935
|
+
Action(GetAppActionOptions)
|
|
936
|
+
], WorkflowState.prototype, "getAppActionOptions", null);
|
|
861
937
|
__decorate([
|
|
862
938
|
Action(GetStep)
|
|
863
939
|
], WorkflowState.prototype, "getStep", null);
|
|
@@ -915,6 +991,9 @@ __decorate([
|
|
|
915
991
|
__decorate([
|
|
916
992
|
Selector()
|
|
917
993
|
], WorkflowState, "selectedAppActionDescriptor", null);
|
|
994
|
+
__decorate([
|
|
995
|
+
Selector()
|
|
996
|
+
], WorkflowState, "appActionOptionsCache", null);
|
|
918
997
|
__decorate([
|
|
919
998
|
Selector()
|
|
920
999
|
], WorkflowState, "selectedStep", null);
|
|
@@ -941,7 +1020,7 @@ WorkflowState = __decorate([
|
|
|
941
1020
|
], WorkflowState);
|
|
942
1021
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkflowState, decorators: [{
|
|
943
1022
|
type: Injectable
|
|
944
|
-
}], propDecorators: { setModuleInfo: [], getWorkflows: [], getWorkflow: [], getFormulaProperties: [], getGroups: [], getRolesForModule: [], getAppActions: [], getAppActionDetail: [], getStep: [], validateFlow: [], createStep: [], updateStep: [], createConnection: [], updateConnection: [], publishWorkflow: [], deleteStep: [], deleteConnection: [] } });
|
|
1023
|
+
}], propDecorators: { setModuleInfo: [], getWorkflows: [], getWorkflow: [], getFormulaProperties: [], getGroups: [], getRolesForModule: [], getAppActions: [], getAppActionDetail: [], getAppActionOptions: [], getStep: [], validateFlow: [], createStep: [], updateStep: [], createConnection: [], updateConnection: [], publishWorkflow: [], deleteStep: [], deleteConnection: [] } });
|
|
945
1024
|
function normalizeWorkflowRoles(data) {
|
|
946
1025
|
if (!Array.isArray(data)) {
|
|
947
1026
|
return [];
|
|
@@ -989,6 +1068,13 @@ function normalizeWorkflowStepSchema(input) {
|
|
|
989
1068
|
function normalizeWorkflowStepDetail(input) {
|
|
990
1069
|
const type = normalizeWorkflowStepType$1(input?.type);
|
|
991
1070
|
const appAction = normalizeWorkflowAppAction(input, type);
|
|
1071
|
+
const systemKind = typeof input?.systemKind === 'string' && input.systemKind.length
|
|
1072
|
+
? input.systemKind
|
|
1073
|
+
: type === 'ApprovalCommit'
|
|
1074
|
+
? 'ApprovalCommit'
|
|
1075
|
+
: null;
|
|
1076
|
+
const isSystem = !!input?.isSystem || type === 'ApprovalCommit';
|
|
1077
|
+
const isLocked = !!input?.isLocked || type === 'ApprovalCommit';
|
|
992
1078
|
return {
|
|
993
1079
|
...input,
|
|
994
1080
|
id: Number(input?.id ?? 0),
|
|
@@ -1006,10 +1092,17 @@ function normalizeWorkflowStepDetail(input) {
|
|
|
1006
1092
|
? undefined
|
|
1007
1093
|
: !!input.hasForm,
|
|
1008
1094
|
appAction,
|
|
1095
|
+
systemKind,
|
|
1096
|
+
isSystem,
|
|
1097
|
+
isLocked,
|
|
1009
1098
|
};
|
|
1010
1099
|
}
|
|
1011
1100
|
function normalizeWorkflowStepType$1(type) {
|
|
1012
|
-
|
|
1101
|
+
if (type === 'AppAction')
|
|
1102
|
+
return 'AppAction';
|
|
1103
|
+
if (type === 'ApprovalCommit')
|
|
1104
|
+
return 'ApprovalCommit';
|
|
1105
|
+
return 'UserInput';
|
|
1013
1106
|
}
|
|
1014
1107
|
function normalizeWorkflowStepName(name) {
|
|
1015
1108
|
if (typeof name === 'string') {
|
|
@@ -1064,6 +1157,14 @@ function normalizeWorkflowAppAction(input, type) {
|
|
|
1064
1157
|
supportedScopes: Array.isArray(candidate?.supportedScopes)
|
|
1065
1158
|
? candidate.supportedScopes.map(String)
|
|
1066
1159
|
: [],
|
|
1160
|
+
configFields: normalizeAppActionConfigFields(candidate?.configFields),
|
|
1161
|
+
runtimeInputs: normalizeAppActionRuntimeInputs(candidate?.runtimeInputs),
|
|
1162
|
+
outputs: normalizeAppActionOutputs(candidate?.outputs),
|
|
1163
|
+
supportedPhases: Array.isArray(candidate?.supportedPhases)
|
|
1164
|
+
? candidate.supportedPhases
|
|
1165
|
+
.filter((value) => typeof value === 'string')
|
|
1166
|
+
.map((value) => value)
|
|
1167
|
+
: [],
|
|
1067
1168
|
};
|
|
1068
1169
|
}
|
|
1069
1170
|
function normalizeWorkflowAppActionDescriptors(data) {
|
|
@@ -1088,8 +1189,111 @@ function normalizeWorkflowAppActionDescriptor(data) {
|
|
|
1088
1189
|
supportedScopes: Array.isArray(record['supportedScopes'])
|
|
1089
1190
|
? record['supportedScopes'].map(String)
|
|
1090
1191
|
: [],
|
|
1192
|
+
configFields: normalizeAppActionConfigFields(record['configFields']),
|
|
1193
|
+
runtimeInputs: normalizeAppActionRuntimeInputs(record['runtimeInputs']),
|
|
1194
|
+
outputs: normalizeAppActionOutputs(record['outputs']),
|
|
1195
|
+
supportedPhases: Array.isArray(record['supportedPhases'])
|
|
1196
|
+
? record['supportedPhases']
|
|
1197
|
+
.filter((value) => typeof value === 'string')
|
|
1198
|
+
.map((value) => value)
|
|
1199
|
+
: [],
|
|
1091
1200
|
};
|
|
1092
1201
|
}
|
|
1202
|
+
function normalizeAppActionConfigFields(value) {
|
|
1203
|
+
if (!Array.isArray(value)) {
|
|
1204
|
+
return [];
|
|
1205
|
+
}
|
|
1206
|
+
return value.filter(isRecord$1).map((record) => ({
|
|
1207
|
+
key: readString(record, 'key') ?? '',
|
|
1208
|
+
displayName: readString(record, 'displayName') ?? readString(record, 'key') ?? '',
|
|
1209
|
+
description: readString(record, 'description') ?? null,
|
|
1210
|
+
type: (readString(record, 'type') ?? 'string'),
|
|
1211
|
+
required: !!record['required'],
|
|
1212
|
+
uiControl: readString(record, 'uiControl') ?? null,
|
|
1213
|
+
optionsProviderKey: readString(record, 'optionsProviderKey') ?? null,
|
|
1214
|
+
designerVisible: record['designerVisible'] === undefined ||
|
|
1215
|
+
record['designerVisible'] === null
|
|
1216
|
+
? true
|
|
1217
|
+
: !!record['designerVisible'],
|
|
1218
|
+
enumValues: Array.isArray(record['enumValues'])
|
|
1219
|
+
? record['enumValues']
|
|
1220
|
+
: undefined,
|
|
1221
|
+
defaultValue: record['defaultValue'],
|
|
1222
|
+
}));
|
|
1223
|
+
}
|
|
1224
|
+
function normalizeAppActionRuntimeInputs(value) {
|
|
1225
|
+
if (!Array.isArray(value)) {
|
|
1226
|
+
return [];
|
|
1227
|
+
}
|
|
1228
|
+
return value.filter(isRecord$1).map((record) => ({
|
|
1229
|
+
key: readString(record, 'key') ?? '',
|
|
1230
|
+
source: (readString(record, 'source') ?? 'Context'),
|
|
1231
|
+
contextKey: readString(record, 'contextKey') ?? null,
|
|
1232
|
+
resolverKey: readString(record, 'resolverKey') ?? null,
|
|
1233
|
+
required: !!record['required'],
|
|
1234
|
+
designerVisible: !!record['designerVisible'],
|
|
1235
|
+
}));
|
|
1236
|
+
}
|
|
1237
|
+
function normalizeAppActionOutputs(value) {
|
|
1238
|
+
if (!Array.isArray(value)) {
|
|
1239
|
+
return [];
|
|
1240
|
+
}
|
|
1241
|
+
return value.filter(isRecord$1).map((record) => ({
|
|
1242
|
+
key: readString(record, 'key') ?? '',
|
|
1243
|
+
type: readString(record, 'type') ?? 'string',
|
|
1244
|
+
persistToWorkflowContext: !!record['persistToWorkflowContext'],
|
|
1245
|
+
description: readString(record, 'description') ?? null,
|
|
1246
|
+
}));
|
|
1247
|
+
}
|
|
1248
|
+
function normalizeWorkflowAppActionOptions(value) {
|
|
1249
|
+
if (!Array.isArray(value)) {
|
|
1250
|
+
return [];
|
|
1251
|
+
}
|
|
1252
|
+
const result = [];
|
|
1253
|
+
for (const item of value) {
|
|
1254
|
+
if (!isRecord$1(item))
|
|
1255
|
+
continue;
|
|
1256
|
+
const rawValue = item['value'];
|
|
1257
|
+
if (rawValue === undefined ||
|
|
1258
|
+
rawValue === null ||
|
|
1259
|
+
(typeof rawValue !== 'string' &&
|
|
1260
|
+
typeof rawValue !== 'number' &&
|
|
1261
|
+
typeof rawValue !== 'boolean')) {
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
const labelRaw = item['label'];
|
|
1265
|
+
const label = typeof labelRaw === 'string'
|
|
1266
|
+
? labelRaw
|
|
1267
|
+
: isRecord$1(labelRaw)
|
|
1268
|
+
? labelRaw
|
|
1269
|
+
: String(rawValue);
|
|
1270
|
+
const metadata = isRecord$1(item['metadata'])
|
|
1271
|
+
? item['metadata']
|
|
1272
|
+
: undefined;
|
|
1273
|
+
result.push({
|
|
1274
|
+
value: rawValue,
|
|
1275
|
+
label,
|
|
1276
|
+
disabled: !!item['disabled'],
|
|
1277
|
+
metadata,
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
return result;
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Build a deterministic cache key for an options request:
|
|
1284
|
+
* `{actionKey}::{fieldKey}::{paramHash}`. The param hash is a sorted
|
|
1285
|
+
* `key=value&...` string of non-empty params, or `_` if none.
|
|
1286
|
+
*/
|
|
1287
|
+
function buildAppActionOptionsCacheKey(actionKey, fieldKey, params) {
|
|
1288
|
+
const paramHash = !params
|
|
1289
|
+
? '_'
|
|
1290
|
+
: Object.entries(params)
|
|
1291
|
+
.filter(([, value]) => value !== null && value !== undefined && value !== '')
|
|
1292
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
1293
|
+
.map(([key, value]) => `${key}=${String(value)}`)
|
|
1294
|
+
.join('&') || '_';
|
|
1295
|
+
return `${actionKey}::${fieldKey}::${paramHash}`;
|
|
1296
|
+
}
|
|
1093
1297
|
function upsertWorkflowAppActionDescriptor(descriptors, descriptor) {
|
|
1094
1298
|
const index = descriptors.findIndex((item) => item.actionKey === descriptor.actionKey);
|
|
1095
1299
|
if (index < 0) {
|
|
@@ -1176,6 +1380,7 @@ class WorkflowFacade {
|
|
|
1176
1380
|
roles = select(WorkflowState.roles);
|
|
1177
1381
|
appActionDescriptors = select(WorkflowState.appActionDescriptors);
|
|
1178
1382
|
selectedAppActionDescriptor = select(WorkflowState.selectedAppActionDescriptor);
|
|
1383
|
+
appActionOptionsCache = select(WorkflowState.appActionOptionsCache);
|
|
1179
1384
|
selectedStep = select(WorkflowState.selectedStep);
|
|
1180
1385
|
isFlowValid = select(WorkflowState.isFlowValid);
|
|
1181
1386
|
steps = select(WorkflowState.stepsSchema);
|
|
@@ -1215,6 +1420,18 @@ class WorkflowFacade {
|
|
|
1215
1420
|
loadAppActionDetail(actionKey) {
|
|
1216
1421
|
return this.store.dispatch(new GetAppActionDetail(actionKey));
|
|
1217
1422
|
}
|
|
1423
|
+
loadAppActionOptions(actionKey, fieldKey, params) {
|
|
1424
|
+
return this.store.dispatch(new GetAppActionOptions(actionKey, fieldKey, params));
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1427
|
+
* Synchronous lookup helper: returns the cached options entry for a given
|
|
1428
|
+
* (actionKey, fieldKey, params) combination, or `undefined` if the request
|
|
1429
|
+
* has not been issued yet. Pair with `loadAppActionOptions` to fetch.
|
|
1430
|
+
*/
|
|
1431
|
+
getCachedAppActionOptions(actionKey, fieldKey, params) {
|
|
1432
|
+
const cacheKey = buildAppActionOptionsCacheKey(actionKey, fieldKey, params);
|
|
1433
|
+
return this.appActionOptionsCache()?.[cacheKey];
|
|
1434
|
+
}
|
|
1218
1435
|
loadStep(stepId) {
|
|
1219
1436
|
return this.store.dispatch(new GetStep(stepId));
|
|
1220
1437
|
}
|
|
@@ -1261,6 +1478,100 @@ const SUPPORTED_PROPERTY_TYPES = [
|
|
|
1261
1478
|
'array',
|
|
1262
1479
|
'object',
|
|
1263
1480
|
];
|
|
1481
|
+
/**
|
|
1482
|
+
* Build the editor definition from a descriptor's explicit `configFields[]`.
|
|
1483
|
+
* Prefer this over `buildWorkflowAppActionConfigEditorDefinition` whenever
|
|
1484
|
+
* the backend ships descriptor-driven fields (per the AppActions handoff).
|
|
1485
|
+
*
|
|
1486
|
+
* Only `designerVisible !== false` fields are rendered. Returns an empty
|
|
1487
|
+
* schema when the input is empty so callers can fall back to JSON-Schema
|
|
1488
|
+
* parsing when needed.
|
|
1489
|
+
*/
|
|
1490
|
+
function buildWorkflowAppActionConfigEditorDefinitionFromFields(configFields) {
|
|
1491
|
+
const visibleFields = (configFields ?? []).filter((field) => field?.designerVisible !== false);
|
|
1492
|
+
if (!visibleFields.length) {
|
|
1493
|
+
return {
|
|
1494
|
+
mode: 'schema',
|
|
1495
|
+
schema: { type: 'object', properties: [], required: [] },
|
|
1496
|
+
fields: [],
|
|
1497
|
+
errors: [],
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
const properties = visibleFields.map((field) => ({
|
|
1501
|
+
key: field.key,
|
|
1502
|
+
title: field.displayName || field.key,
|
|
1503
|
+
description: field.description ?? null,
|
|
1504
|
+
type: field.type ?? 'string',
|
|
1505
|
+
required: !!field.required,
|
|
1506
|
+
enumValues: field.enumValues,
|
|
1507
|
+
rawSchema: {
|
|
1508
|
+
type: field.type,
|
|
1509
|
+
title: field.displayName,
|
|
1510
|
+
description: field.description ?? undefined,
|
|
1511
|
+
...(field.enumValues ? { enum: field.enumValues } : {}),
|
|
1512
|
+
},
|
|
1513
|
+
}));
|
|
1514
|
+
const schema = {
|
|
1515
|
+
type: 'object',
|
|
1516
|
+
properties,
|
|
1517
|
+
required: visibleFields.filter((f) => f.required).map((f) => f.key),
|
|
1518
|
+
};
|
|
1519
|
+
return {
|
|
1520
|
+
mode: 'schema',
|
|
1521
|
+
schema,
|
|
1522
|
+
fields: visibleFields.map((field) => mapDescriptorFieldToEditorField(field)),
|
|
1523
|
+
errors: [],
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
function mapDescriptorFieldToEditorField(field) {
|
|
1527
|
+
const title = field.displayName || field.key;
|
|
1528
|
+
const required = !!field.required;
|
|
1529
|
+
const description = field.description ?? null;
|
|
1530
|
+
const type = field.type ?? 'string';
|
|
1531
|
+
// Explicit uiControl from the descriptor takes precedence — including
|
|
1532
|
+
// `select` driven by an `optionsProviderKey` (no enum needed).
|
|
1533
|
+
if (field.uiControl === 'select' || field.optionsProviderKey) {
|
|
1534
|
+
return {
|
|
1535
|
+
key: field.key,
|
|
1536
|
+
title,
|
|
1537
|
+
description,
|
|
1538
|
+
type,
|
|
1539
|
+
kind: 'select',
|
|
1540
|
+
required,
|
|
1541
|
+
enumValues: field.enumValues,
|
|
1542
|
+
optionsProviderKey: field.optionsProviderKey ?? null,
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
if (field.uiControl === 'json' || type === 'array' || type === 'object') {
|
|
1546
|
+
return {
|
|
1547
|
+
key: field.key,
|
|
1548
|
+
title,
|
|
1549
|
+
description,
|
|
1550
|
+
type,
|
|
1551
|
+
kind: 'json',
|
|
1552
|
+
required,
|
|
1553
|
+
jsonValueType: type === 'array' ? 'array' : 'object',
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
if (field.uiControl === 'toggle' || type === 'boolean') {
|
|
1557
|
+
return { key: field.key, title, description, type, kind: 'toggle', required };
|
|
1558
|
+
}
|
|
1559
|
+
if (field.uiControl === 'number' || type === 'number') {
|
|
1560
|
+
return { key: field.key, title, description, type, kind: 'number', required };
|
|
1561
|
+
}
|
|
1562
|
+
if (field.enumValues?.length) {
|
|
1563
|
+
return {
|
|
1564
|
+
key: field.key,
|
|
1565
|
+
title,
|
|
1566
|
+
description,
|
|
1567
|
+
type,
|
|
1568
|
+
kind: 'select',
|
|
1569
|
+
required,
|
|
1570
|
+
enumValues: field.enumValues,
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
return { key: field.key, title, description, type, kind: 'text', required };
|
|
1574
|
+
}
|
|
1264
1575
|
function buildWorkflowAppActionConfigEditorDefinition(configSchemaJson) {
|
|
1265
1576
|
if (!configSchemaJson?.trim()) {
|
|
1266
1577
|
return {
|
|
@@ -1618,7 +1929,11 @@ function buildWorkflowStepPayload({ formValue, properties, hasNotification, appA
|
|
|
1618
1929
|
};
|
|
1619
1930
|
}
|
|
1620
1931
|
function normalizeWorkflowStepType(type) {
|
|
1621
|
-
|
|
1932
|
+
if (type === 'AppAction')
|
|
1933
|
+
return 'AppAction';
|
|
1934
|
+
if (type === 'ApprovalCommit')
|
|
1935
|
+
return 'ApprovalCommit';
|
|
1936
|
+
return 'UserInput';
|
|
1622
1937
|
}
|
|
1623
1938
|
function normalizeStepName(name) {
|
|
1624
1939
|
if (name && typeof name === 'object') {
|
|
@@ -1693,6 +2008,7 @@ class WorkflowBuilder {
|
|
|
1693
2008
|
loadingAppActions = this.workflowFacade.isLoading('getAppActions');
|
|
1694
2009
|
loadingAppActionDetail = this.workflowFacade.isLoading('getAppActionDetail');
|
|
1695
2010
|
appActionListError = this.workflowFacade.error('getAppActions');
|
|
2011
|
+
publishError = this.workflowFacade.error('publishWorkflow');
|
|
1696
2012
|
appActionDetailError = this.workflowFacade.error('getAppActionDetail');
|
|
1697
2013
|
selectedWorkflowId = computed(() => this.workflow()?.id, ...(ngDevMode ? [{ debugName: "selectedWorkflowId" }] : /* istanbul ignore next */ []));
|
|
1698
2014
|
connectionFormulaSchemaId = computed(() => this.workflow()?.id, ...(ngDevMode ? [{ debugName: "connectionFormulaSchemaId" }] : /* istanbul ignore next */ []));
|
|
@@ -1830,6 +2146,8 @@ class WorkflowBuilder {
|
|
|
1830
2146
|
variant: 'outlined',
|
|
1831
2147
|
size: 'small',
|
|
1832
2148
|
tooltip: 'Edit',
|
|
2149
|
+
// Locked system steps (e.g. Commit Approved Form) are not editable.
|
|
2150
|
+
condition: (node) => !node.isLocked,
|
|
1833
2151
|
},
|
|
1834
2152
|
{
|
|
1835
2153
|
key: 'delete',
|
|
@@ -1838,7 +2156,8 @@ class WorkflowBuilder {
|
|
|
1838
2156
|
size: 'small',
|
|
1839
2157
|
severity: 'danger',
|
|
1840
2158
|
tooltip: 'Delete',
|
|
1841
|
-
|
|
2159
|
+
// Initial step + locked system steps are not deletable.
|
|
2160
|
+
condition: (node) => !node.isInitial && !node.isLocked,
|
|
1842
2161
|
},
|
|
1843
2162
|
], ...(ngDevMode ? [{ debugName: "nodeActions" }] : /* istanbul ignore next */ []));
|
|
1844
2163
|
nodeDialogFooterConfig = {
|
|
@@ -1870,19 +2189,33 @@ class WorkflowBuilder {
|
|
|
1870
2189
|
}, ...(ngDevMode ? [{ debugName: "connectionFormulaConfig" }] : /* istanbul ignore next */ []));
|
|
1871
2190
|
steps = computed(() => this.workflowFacade.steps().map((step) => {
|
|
1872
2191
|
const isAppAction = step.type === 'AppAction';
|
|
2192
|
+
const isApprovalCommit = step.type === 'ApprovalCommit';
|
|
1873
2193
|
return {
|
|
1874
2194
|
...step,
|
|
1875
|
-
|
|
1876
|
-
icon
|
|
1877
|
-
|
|
2195
|
+
// System Approval-Commit step gets a distinct emerald accent + a
|
|
2196
|
+
// verified-check icon. Authoring is locked; the step is rendered
|
|
2197
|
+
// in icon mode like AppActions to communicate "system boundary".
|
|
2198
|
+
color: isApprovalCommit
|
|
2199
|
+
? '#059669'
|
|
2200
|
+
: isAppAction
|
|
2201
|
+
? '#B45309'
|
|
2202
|
+
: '#0369A1',
|
|
2203
|
+
icon: isApprovalCommit
|
|
2204
|
+
? 'general.check-verified-01'
|
|
2205
|
+
: isAppAction
|
|
2206
|
+
? 'general.zap'
|
|
2207
|
+
: step.isInitial
|
|
2208
|
+
? 'map.flag-04'
|
|
2209
|
+
: 'file.clipboard-check',
|
|
2210
|
+
subtitle: isApprovalCommit
|
|
2211
|
+
? this.transloco.translate('workflow.builder.approvalCommitSubtitle')
|
|
2212
|
+
: this.getStepTypeLabel(step.type),
|
|
2213
|
+
badge: isApprovalCommit
|
|
2214
|
+
? null
|
|
1878
2215
|
: step.isInitial
|
|
1879
|
-
? '
|
|
1880
|
-
:
|
|
1881
|
-
|
|
1882
|
-
badge: step.isInitial
|
|
1883
|
-
? this.transloco.translate('workflow.builder.initial')
|
|
1884
|
-
: null,
|
|
1885
|
-
style: isAppAction ? 'icon' : 'detail',
|
|
2216
|
+
? this.transloco.translate('workflow.builder.initial')
|
|
2217
|
+
: null,
|
|
2218
|
+
style: isAppAction || isApprovalCommit ? 'icon' : 'detail',
|
|
1886
2219
|
};
|
|
1887
2220
|
}), ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
|
|
1888
2221
|
connections = computed(() => this.workflowFacade.connections().map((connection) => ({
|
|
@@ -1955,7 +2288,7 @@ class WorkflowBuilder {
|
|
|
1955
2288
|
if (signature === this.lastAppActionDescriptorSignature) {
|
|
1956
2289
|
return;
|
|
1957
2290
|
}
|
|
1958
|
-
this.rebuildAppActionConfigEditor(this.getCurrentAppActionConfigJson(), descriptor?.configSchemaJson ?? null);
|
|
2291
|
+
this.rebuildAppActionConfigEditor(this.getCurrentAppActionConfigJson(), descriptor?.configSchemaJson ?? null, descriptor);
|
|
1959
2292
|
this.lastAppActionDescriptorSignature = signature;
|
|
1960
2293
|
});
|
|
1961
2294
|
this.stepForm.controls.targetType.valueChanges
|
|
@@ -2010,6 +2343,12 @@ class WorkflowBuilder {
|
|
|
2010
2343
|
if (!event.data) {
|
|
2011
2344
|
return;
|
|
2012
2345
|
}
|
|
2346
|
+
// Locked / system steps (e.g. Commit Approved Form) are
|
|
2347
|
+
// backend-owned and not editable from the FE builder. Hard
|
|
2348
|
+
// short-circuit before opening the editor dialog.
|
|
2349
|
+
if (event.data.isLocked || event.data.type === 'ApprovalCommit') {
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2013
2352
|
this.clearForm(normalizeWorkflowStepType(event.data.type));
|
|
2014
2353
|
this.isCreatingStep.set(false);
|
|
2015
2354
|
this.isEditingInitialNode.set(!!event.data.isInitial);
|
|
@@ -2052,6 +2391,12 @@ class WorkflowBuilder {
|
|
|
2052
2391
|
if (!event.data) {
|
|
2053
2392
|
return;
|
|
2054
2393
|
}
|
|
2394
|
+
// Defensive guard — UI hides the delete button on locked steps
|
|
2395
|
+
// already; this short-circuit is for any caller that bypasses
|
|
2396
|
+
// the canvas chrome (e.g. keyboard shortcuts).
|
|
2397
|
+
if (event.data.isLocked || event.data.type === 'ApprovalCommit') {
|
|
2398
|
+
return;
|
|
2399
|
+
}
|
|
2055
2400
|
this.confirmationService.confirmDelete({
|
|
2056
2401
|
type: 'dialog',
|
|
2057
2402
|
accept: () => {
|
|
@@ -2136,14 +2481,132 @@ class WorkflowBuilder {
|
|
|
2136
2481
|
return this.appActionConfigForm.get(key);
|
|
2137
2482
|
}
|
|
2138
2483
|
getAppActionEnumOptions(field) {
|
|
2484
|
+
// Dynamic options (loaded from the backend options endpoint) take
|
|
2485
|
+
// precedence over a descriptor's static enumValues. The cache lookup
|
|
2486
|
+
// depends on the current actionKey + the param context (requestSchemaId).
|
|
2487
|
+
if (field.optionsProviderKey) {
|
|
2488
|
+
const dynamic = this.getDynamicAppActionOptions(field.key);
|
|
2489
|
+
if (dynamic !== undefined) {
|
|
2490
|
+
return dynamic;
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2139
2493
|
return (field.enumValues ?? []).map((value) => ({
|
|
2140
2494
|
label: String(value),
|
|
2141
2495
|
value,
|
|
2142
2496
|
}));
|
|
2143
2497
|
}
|
|
2498
|
+
/**
|
|
2499
|
+
* Lookup the cached dynamic options for a given config field. Returns
|
|
2500
|
+
* an empty array on backend error so the template can render an error
|
|
2501
|
+
* state, or `undefined` when no fetch has been issued yet.
|
|
2502
|
+
*/
|
|
2503
|
+
getDynamicAppActionOptions(fieldKey) {
|
|
2504
|
+
const actionKey = this.appActionSettingsForm.controls.actionKey.value;
|
|
2505
|
+
if (!actionKey)
|
|
2506
|
+
return undefined;
|
|
2507
|
+
const params = this.buildAppActionOptionsParams();
|
|
2508
|
+
const cached = this.workflowFacade.getCachedAppActionOptions(actionKey, fieldKey, params);
|
|
2509
|
+
if (!cached)
|
|
2510
|
+
return undefined;
|
|
2511
|
+
const locale = this.transloco.getActiveLang();
|
|
2512
|
+
return cached.options.map((opt) => {
|
|
2513
|
+
const label = typeof opt.label === 'string'
|
|
2514
|
+
? opt.label
|
|
2515
|
+
: (opt.label?.[locale] ?? opt.label?.['en'] ?? String(opt.value));
|
|
2516
|
+
return {
|
|
2517
|
+
label,
|
|
2518
|
+
value: opt.value,
|
|
2519
|
+
disabled: !!opt.disabled,
|
|
2520
|
+
};
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
hasAppActionOptionsError(fieldKey) {
|
|
2524
|
+
const actionKey = this.appActionSettingsForm.controls.actionKey.value;
|
|
2525
|
+
if (!actionKey)
|
|
2526
|
+
return null;
|
|
2527
|
+
const cached = this.workflowFacade.getCachedAppActionOptions(actionKey, fieldKey, this.buildAppActionOptionsParams());
|
|
2528
|
+
return cached?.errorMessage ?? null;
|
|
2529
|
+
}
|
|
2530
|
+
buildAppActionOptionsParams() {
|
|
2531
|
+
const params = {};
|
|
2532
|
+
const workflowId = this.workflow()?.id;
|
|
2533
|
+
if (workflowId) {
|
|
2534
|
+
params['requestSchemaId'] = workflowId;
|
|
2535
|
+
}
|
|
2536
|
+
return params;
|
|
2537
|
+
}
|
|
2538
|
+
/**
|
|
2539
|
+
* Fire option-loading for every descriptor `select` field that uses
|
|
2540
|
+
* an `optionsProviderKey`. Called whenever the editor is rebuilt or
|
|
2541
|
+
* the active actionKey changes.
|
|
2542
|
+
*/
|
|
2543
|
+
loadDynamicAppActionOptions() {
|
|
2544
|
+
const actionKey = this.appActionSettingsForm.controls.actionKey.value;
|
|
2545
|
+
if (!actionKey)
|
|
2546
|
+
return;
|
|
2547
|
+
const definition = this.appActionConfigDefinition();
|
|
2548
|
+
const params = this.buildAppActionOptionsParams();
|
|
2549
|
+
for (const field of definition.fields) {
|
|
2550
|
+
if (field.kind !== 'select' || !field.optionsProviderKey)
|
|
2551
|
+
continue;
|
|
2552
|
+
this.workflowFacade
|
|
2553
|
+
.loadAppActionOptions(actionKey, field.key, params)
|
|
2554
|
+
.subscribe();
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2144
2557
|
getAppActionDescription() {
|
|
2145
2558
|
return this.currentAppActionDescriptor()?.description ?? null;
|
|
2146
2559
|
}
|
|
2560
|
+
/** Runtime inputs are non-editable (resolved at runtime); the editor
|
|
2561
|
+
* shows them as read-only "Resolved automatically" hints. */
|
|
2562
|
+
getAppActionRuntimeInputs() {
|
|
2563
|
+
return (this.currentAppActionDescriptor()?.runtimeInputs ?? []).filter((input) => input.designerVisible !== true);
|
|
2564
|
+
}
|
|
2565
|
+
/** Outputs are read-only informational hints. */
|
|
2566
|
+
getAppActionOutputs() {
|
|
2567
|
+
return this.currentAppActionDescriptor()?.outputs ?? [];
|
|
2568
|
+
}
|
|
2569
|
+
/** Phases the action supports (e.g. ['AfterCommit']). Drives the
|
|
2570
|
+
* placement warning when the step is placed before the commit step. */
|
|
2571
|
+
getAppActionSupportedPhases() {
|
|
2572
|
+
return this.currentAppActionDescriptor()?.supportedPhases ?? [];
|
|
2573
|
+
}
|
|
2574
|
+
/**
|
|
2575
|
+
* `true` when the current action is restricted to `AfterCommit` and
|
|
2576
|
+
* therefore should be placed downstream of the `Commit Approved Form`
|
|
2577
|
+
* step. Surfaces an inline guidance hint in the editor.
|
|
2578
|
+
*/
|
|
2579
|
+
isAppActionAfterCommitOnly() {
|
|
2580
|
+
const phases = this.getAppActionSupportedPhases();
|
|
2581
|
+
return phases.length === 1 && phases[0] === 'AfterCommit';
|
|
2582
|
+
}
|
|
2583
|
+
/**
|
|
2584
|
+
* `true` when an actionKey is set, descriptor lookup is not in flight,
|
|
2585
|
+
* and we still have no resolvable descriptor — i.e. the backend returned
|
|
2586
|
+
* `data: null` for the descriptor describe-one call. The saved config
|
|
2587
|
+
* is preserved per the AppActions handoff §5.3.
|
|
2588
|
+
*/
|
|
2589
|
+
isAppActionMissing() {
|
|
2590
|
+
const actionKey = this.appActionSettingsForm.controls.actionKey.value;
|
|
2591
|
+
if (!actionKey)
|
|
2592
|
+
return false;
|
|
2593
|
+
if (this.loadingAppActionDetail())
|
|
2594
|
+
return false;
|
|
2595
|
+
return !this.currentAppActionDescriptor();
|
|
2596
|
+
}
|
|
2597
|
+
describeRuntimeInputSource(input) {
|
|
2598
|
+
if (input.source === 'Context') {
|
|
2599
|
+
return input.contextKey
|
|
2600
|
+
? `Resolved from workflow context (${input.contextKey})`
|
|
2601
|
+
: 'Resolved from workflow context';
|
|
2602
|
+
}
|
|
2603
|
+
if (input.source === 'InternalResolver') {
|
|
2604
|
+
return input.resolverKey
|
|
2605
|
+
? `Resolved internally (${input.resolverKey})`
|
|
2606
|
+
: 'Resolved internally';
|
|
2607
|
+
}
|
|
2608
|
+
return input.source;
|
|
2609
|
+
}
|
|
2147
2610
|
getAppActionDisplayName() {
|
|
2148
2611
|
return (this.currentAppActionDescriptor()?.displayName ||
|
|
2149
2612
|
this.appActionSettingsForm.controls.actionKey.value ||
|
|
@@ -2225,7 +2688,22 @@ class WorkflowBuilder {
|
|
|
2225
2688
|
failureBehavior: editorState.appActionValue.failureBehavior,
|
|
2226
2689
|
timeoutSeconds: editorState.appActionValue.timeoutSeconds,
|
|
2227
2690
|
}, { emitEvent: false });
|
|
2228
|
-
this.rebuildAppActionConfigEditor(editorState.appActionValue.configJson, descriptor?.configSchemaJson ?? step.appAction?.configSchemaJson ?? null
|
|
2691
|
+
this.rebuildAppActionConfigEditor(editorState.appActionValue.configJson, descriptor?.configSchemaJson ?? step.appAction?.configSchemaJson ?? null, descriptor ??
|
|
2692
|
+
(step.appAction
|
|
2693
|
+
? {
|
|
2694
|
+
appCode: step.appAction.appCode,
|
|
2695
|
+
actionKey: step.appAction.actionKey,
|
|
2696
|
+
displayName: step.appAction.displayName ?? step.appAction.actionKey,
|
|
2697
|
+
description: step.appAction.description ?? null,
|
|
2698
|
+
configSchemaJson: step.appAction.configSchemaJson ?? null,
|
|
2699
|
+
requiredContextKeys: step.appAction.requiredContextKeys ?? [],
|
|
2700
|
+
supportedScopes: step.appAction.supportedScopes ?? [],
|
|
2701
|
+
configFields: step.appAction.configFields,
|
|
2702
|
+
runtimeInputs: step.appAction.runtimeInputs,
|
|
2703
|
+
outputs: step.appAction.outputs,
|
|
2704
|
+
supportedPhases: step.appAction.supportedPhases,
|
|
2705
|
+
}
|
|
2706
|
+
: null));
|
|
2229
2707
|
this.lastAppActionDescriptorSignature =
|
|
2230
2708
|
this.createAppActionDescriptorSignature(editorState.appActionValue.actionKey, descriptor?.configSchemaJson ??
|
|
2231
2709
|
step.appAction?.configSchemaJson ??
|
|
@@ -2240,7 +2718,8 @@ class WorkflowBuilder {
|
|
|
2240
2718
|
onAppActionActionChanged(actionKey) {
|
|
2241
2719
|
this.selectedTab.set('tab1');
|
|
2242
2720
|
this.lastAppActionDescriptorSignature = '';
|
|
2243
|
-
|
|
2721
|
+
const descriptor = this.resolveDescriptorForActionKey(actionKey);
|
|
2722
|
+
this.rebuildAppActionConfigEditor(DEFAULT_APP_ACTION_EDITOR_VALUE.configJson, descriptor?.configSchemaJson ?? null, descriptor);
|
|
2244
2723
|
if (actionKey) {
|
|
2245
2724
|
this.ensureAppActionDetailLoaded(actionKey);
|
|
2246
2725
|
}
|
|
@@ -2286,7 +2765,7 @@ class WorkflowBuilder {
|
|
|
2286
2765
|
timeoutSeconds: DEFAULT_APP_ACTION_EDITOR_VALUE.timeoutSeconds,
|
|
2287
2766
|
}, { emitEvent: false });
|
|
2288
2767
|
this.isPatchingStepForm = false;
|
|
2289
|
-
this.rebuildAppActionConfigEditor(DEFAULT_APP_ACTION_EDITOR_VALUE.configJson, this.draftAppActionDescriptor()?.configSchemaJson ?? null);
|
|
2768
|
+
this.rebuildAppActionConfigEditor(DEFAULT_APP_ACTION_EDITOR_VALUE.configJson, this.draftAppActionDescriptor()?.configSchemaJson ?? null, this.draftAppActionDescriptor());
|
|
2290
2769
|
this.ensureAppActionDetailLoaded(actionKey);
|
|
2291
2770
|
}
|
|
2292
2771
|
resetPropertiesTable() {
|
|
@@ -2347,8 +2826,12 @@ class WorkflowBuilder {
|
|
|
2347
2826
|
this.rebuildAppActionConfigEditor(DEFAULT_APP_ACTION_EDITOR_VALUE.configJson, null);
|
|
2348
2827
|
this.lastAppActionDescriptorSignature = '';
|
|
2349
2828
|
}
|
|
2350
|
-
rebuildAppActionConfigEditor(configJson, configSchemaJson) {
|
|
2351
|
-
|
|
2829
|
+
rebuildAppActionConfigEditor(configJson, configSchemaJson, descriptor) {
|
|
2830
|
+
// Per the AppActions handoff: prefer descriptor `configFields[]` when
|
|
2831
|
+
// present; fall back to JSON-Schema parsing for legacy descriptors.
|
|
2832
|
+
const definition = descriptor?.configFields && descriptor.configFields.length > 0
|
|
2833
|
+
? buildWorkflowAppActionConfigEditorDefinitionFromFields(descriptor.configFields)
|
|
2834
|
+
: buildWorkflowAppActionConfigEditorDefinition(configSchemaJson);
|
|
2352
2835
|
const editorValue = mapWorkflowAppActionConfigJsonToEditorValue(configJson, definition);
|
|
2353
2836
|
Object.keys(this.appActionConfigForm.controls).forEach((key) => {
|
|
2354
2837
|
this.appActionConfigForm.removeControl(key);
|
|
@@ -2362,6 +2845,10 @@ class WorkflowBuilder {
|
|
|
2362
2845
|
emitEvent: false,
|
|
2363
2846
|
});
|
|
2364
2847
|
this.appActionConfigDefinition.set(definition);
|
|
2848
|
+
// Kick off backend option-loading for any select field driven by an
|
|
2849
|
+
// `optionsProviderKey`. The cache lookup in `getAppActionEnumOptions`
|
|
2850
|
+
// picks up the populated options once they arrive.
|
|
2851
|
+
this.loadDynamicAppActionOptions();
|
|
2365
2852
|
}
|
|
2366
2853
|
ensureAppActionDiscoveryLoaded() {
|
|
2367
2854
|
this.workflowFacade.loadAppActions();
|
|
@@ -2498,7 +2985,7 @@ class WorkflowBuilder {
|
|
|
2498
2985
|
return '';
|
|
2499
2986
|
}
|
|
2500
2987
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkflowBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2501
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkflowBuilder, isStandalone: true, selector: "mt-workflow-builder", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workflow.builder'\">\r\n <div class=\"h-full flex flex-col\" id=\"workflow-builder-card\">\r\n <div class=\"flex justify-center w-full py-2\">\r\n <mt-tabs\r\n [active]=\"mainTab()\"\r\n (activeChange)=\"onMainTabChange($event)\"\r\n [options]=\"mainTabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n </div>\r\n @switch (mainTab()) {\r\n @case (\"workflow\") {\r\n @if (!loading()) {\r\n <mt-structure-builder\r\n class=\"flex-1\"\r\n [structureMode]=\"'workflow'\"\r\n [availableNodes]=\"availableNodes()\"\r\n [availableNodesLabel]=\"t('stepTemplates')\"\r\n [connectionForm]=\"connectionForm()\"\r\n [connectionFormulaSchemaId]=\"connectionFormulaSchemaId()\"\r\n [connectionFormulaConfig]=\"connectionFormulaConfig()\"\r\n [nodeActions]=\"nodeActions()\"\r\n [nodes]=\"steps()\"\r\n [connections]=\"connections()\"\r\n (action)=\"onStructureAction($event)\"\r\n [addModalType]=\"'drawer'\"\r\n [addModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\r\n [updateModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\r\n [addModalHeader]=\"'workflow.builder.addStep' | transloco\"\r\n [updateModalHeader]=\"'workflow.builder.editStep' | transloco\"\r\n [nodeDialogFooterConfig]=\"nodeDialogFooterConfig\"\r\n [appendTo]=\"'page-content'\"\r\n [nodeFields]=\"nodeFields()\"\r\n [availableTabsClass]=\"hasMultipleWorkflows() ? '!mt-28' : ''\"\r\n [layoutDirection]=\"'LR'\"\r\n >\r\n <div flowContent class=\"pointer-events-none\">\r\n @if (hasMultipleWorkflows()) {\r\n <div class=\"pointer-events-auto absolute top-4 start-4 z-10\">\r\n <mt-card class=\"w-64\">\r\n <mt-select-field\r\n [options]=\"workflows()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [ngModel]=\"selectedWorkflowId()\"\r\n (ngModelChange)=\"onWorkflowChange($event)\"\r\n class=\"mt-2\"\r\n />\r\n </mt-card>\r\n </div>\r\n }\r\n <div class=\"pointer-events-auto absolute top-4 end-4 z-10\">\r\n <div class=\"flex flex-col gap-2 w-80\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-10\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"dev.dataflow-01\"\r\n />\r\n <label>{{\r\n \"workflow.builder.enableWorkflow\" | transloco\r\n }}</label>\r\n </div>\r\n <mt-toggle-field\r\n [ngModel]=\"isPublished()\"\r\n (ngModelChange)=\"onPublishToggle($event)\"\r\n [disabled]=\"isPublishDisabled()\"\r\n ></mt-toggle-field>\r\n </div>\r\n </mt-card>\r\n </div>\r\n </div>\r\n </div>\r\n <ng-template\r\n #nodeDialog\r\n let-close=\"close\"\r\n let-save=\"save\"\r\n let-node=\"node\"\r\n let-drawerController=\"drawerController\"\r\n >\r\n <div class=\"p-4\">\r\n @if (loadingStep()) {\r\n <div class=\"space-y-4\">\r\n <div class=\"flex gap-2 mb-4\">\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <!-- Form fields skeleton -->\r\n <div class=\"space-y-4\">\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"10rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"3rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"4rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <mt-tabs\r\n [active]=\"selectedTab()\"\r\n (activeChange)=\"onNodeDialogTabChange($event)\"\r\n [options]=\"tabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n @switch (selectedTab()) {\r\n @case (\"tab1\") {\r\n <div class=\"mt-4 space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <mt-text-field\r\n [label]=\"t('nameEnglish')\"\r\n [placeholder]=\"t('enterNameEnglish')\"\r\n [formControl]=\"stepForm.controls.nameEn\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n <mt-text-field\r\n [label]=\"t('nameArabic')\"\r\n [placeholder]=\"t('enterNameArabic')\"\r\n [formControl]=\"stepForm.controls.nameAr\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n </div>\r\n\r\n @if (currentStepType() === \"UserInput\") {\r\n @if (!isEditingInitialNode()) {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"approver\") }}\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('approver')\"\r\n [options]=\"[\r\n { label: t('group'), value: '1' },\r\n { label: t('role'), value: '2' },\r\n ]\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.targetType\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n @if (\r\n stepForm.controls.targetType.value === \"1\"\r\n ) {\r\n <mt-select-field\r\n [label]=\"t('group')\"\r\n [placeholder]=\"t('selectGroup')\"\r\n [options]=\"groups()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [formControl]=\"stepForm.controls.group\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n } @else {\r\n <mt-select-field\r\n [label]=\"t('role')\"\r\n [placeholder]=\"t('selectRole')\"\r\n [options]=\"roles()\"\r\n [group]=\"hasGroupedRoles()\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.role\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n }\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n } @else {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"app\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-700\"\r\n >\r\n {{ t(\"appLabelPplus\") }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"action\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-900\"\r\n >\r\n {{ getAppActionDisplayName() }}\r\n </div>\r\n @if (getAppActionKey()) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ getAppActionKey() }}\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (\r\n getAppActionDescription();\r\n as description\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-muted-color\"\r\n >\r\n {{ description }}\r\n </div>\r\n }\r\n\r\n @if (\r\n getAppActionDiscoveryMessage();\r\n as discoveryMessage\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ discoveryMessage }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div>\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionConfiguration\") }}\r\n </div>\r\n <div class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"appActionConfigurationDescription\") }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n loadingAppActionDetail() &&\r\n appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div class=\"space-y-3\">\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"6rem\"\r\n ></p-skeleton>\r\n </div>\r\n } @else if (\r\n !appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-dashed border-surface-300 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionUnavailable\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"schema\" &&\r\n appActionConfigDefinition().fields.length === 0\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionNoConfigRequired\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"raw\"\r\n ) {\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionRawConfigFallback\") }}\r\n </div>\r\n <mt-textarea-field\r\n [label]=\"t('appActionConfigJson')\"\r\n [placeholder]=\"\r\n t('enterAppActionConfigJson')\r\n \"\r\n [formControl]=\"appActionRawConfigControl\"\r\n [rows]=\"'10'\"\r\n ></mt-textarea-field>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (\r\n field of appActionConfigDefinition().fields;\r\n track field.key\r\n ) {\r\n <div class=\"space-y-2\">\r\n @switch (field.kind) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-text-field>\r\n }\r\n @case (\"number\") {\r\n <mt-number-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-number-field>\r\n }\r\n @case (\"toggle\") {\r\n <mt-toggle-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [label]=\"field.title\"\r\n [options]=\"\r\n getAppActionEnumOptions(field)\r\n \"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-select-field>\r\n }\r\n @case (\"json\") {\r\n <mt-textarea-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n [rows]=\"'8'\"\r\n ></mt-textarea-field>\r\n }\r\n }\r\n\r\n @if (field.description) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ field.description }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getAppActionConfigMessages().length) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700\"\r\n >\r\n @for (\r\n message of getAppActionConfigMessages();\r\n track message\r\n ) {\r\n <div>{{ message }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"advancedExecution\") }}\r\n </div>\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n\r\n <mt-select-field\r\n [label]=\"t('failureBehavior')\"\r\n [options]=\"failureBehaviorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.failureBehavior\r\n \"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n <mt-number-field\r\n [label]=\"t('timeoutSeconds')\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.timeoutSeconds\r\n \"\r\n [required]=\"true\"\r\n [min]=\"1\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n }\r\n @case (\"tab2\") {\r\n <div class=\"mt-4\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-4\">\r\n <div class=\"flex flex-1 items-center gap-3\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"file.file-check-02\"\r\n />\r\n <div class=\"flex flex-col\">\r\n <label class=\"font-medium\">{{\r\n t(\"configureForm\")\r\n }}</label>\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"configureForm-description\")\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureForm')\"\r\n size=\"small\"\r\n (onClick)=\"openFormModal()\"\r\n ></mt-button>\r\n </div>\r\n </mt-card>\r\n </div>\r\n }\r\n @case (\"tab3\") {\r\n <div class=\"mt-4\">\r\n <mt-toggle-field\r\n toggleShape=\"card\"\r\n [label]=\"t('show-hide')\"\r\n [descriptionCard]=\"t('show-hide-notifications')\"\r\n icon=\"general.eye\"\r\n [formControl]=\"showHideControl\"\r\n >\r\n <ng-template #toggleCardBottom>\r\n @if (showHideControl.value) {\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureNotifications')\"\r\n size=\"small\"\r\n (onClick)=\"openNotificationsModal()\"\r\n ></mt-button>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-toggle-field>\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n </mt-structure-builder>\r\n } @else {\r\n <p-skeleton width=\"100%\" height=\"50rem\" />\r\n }\r\n }\r\n @case (\"notification\") {\r\n <div class=\"flex-1 flex justify-center items-start p-4\">\r\n <div class=\"w-1/2 max-[1025px]:w-full\">\r\n <mt-card [title]=\"t('notifications')\">\r\n <mt-notification-template />\r\n </mt-card>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "component", type: StructureBuilder, selector: "mt-structure-builder", inputs: ["availableNodes", "availableNodesLabel", "nodeForm", "nodeDialogFooterConfig", "connectionForm", "connectionFormulaSchemaId", "connectionFormulaConfig", "nodeActions", "nodeFields", "isAutoLayout", "readonly", "structureMode", "nodeStyle", "addModalType", "updateModalType", "addModalStyleClass", "updateModalStyleClass", "addModalHeader", "updateModalHeader", "appendTo", "availableTabsClass", "layoutDirection", "nodes", "connections", "nodeTemplate"], outputs: ["nodeActionsEvent", "action", "nodesChange", "connectionsChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: i2.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: NotificationTemplate, selector: "mt-notification-template" }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
|
|
2988
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkflowBuilder, isStandalone: true, selector: "mt-workflow-builder", ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workflow.builder'\">\r\n <div class=\"h-full flex flex-col\" id=\"workflow-builder-card\">\r\n <div class=\"flex justify-center w-full py-2\">\r\n <mt-tabs\r\n [active]=\"mainTab()\"\r\n (activeChange)=\"onMainTabChange($event)\"\r\n [options]=\"mainTabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n </div>\r\n @switch (mainTab()) {\r\n @case (\"workflow\") {\r\n @if (!loading()) {\r\n <mt-structure-builder\r\n class=\"flex-1\"\r\n [structureMode]=\"'workflow'\"\r\n [availableNodes]=\"availableNodes()\"\r\n [availableNodesLabel]=\"t('stepTemplates')\"\r\n [connectionForm]=\"connectionForm()\"\r\n [connectionFormulaSchemaId]=\"connectionFormulaSchemaId()\"\r\n [connectionFormulaConfig]=\"connectionFormulaConfig()\"\r\n [nodeActions]=\"nodeActions()\"\r\n [nodes]=\"steps()\"\r\n [connections]=\"connections()\"\r\n (action)=\"onStructureAction($event)\"\r\n [addModalType]=\"'drawer'\"\r\n [addModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\r\n [updateModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\r\n [addModalHeader]=\"'workflow.builder.addStep' | transloco\"\r\n [updateModalHeader]=\"'workflow.builder.editStep' | transloco\"\r\n [nodeDialogFooterConfig]=\"nodeDialogFooterConfig\"\r\n [appendTo]=\"'page-content'\"\r\n [nodeFields]=\"nodeFields()\"\r\n [availableTabsClass]=\"hasMultipleWorkflows() ? '!mt-28' : ''\"\r\n [layoutDirection]=\"'LR'\"\r\n >\r\n <div flowContent class=\"pointer-events-none\">\r\n @if (hasMultipleWorkflows()) {\r\n <div class=\"pointer-events-auto absolute top-4 start-4 z-10\">\r\n <mt-card class=\"w-64\">\r\n <mt-select-field\r\n [options]=\"workflows()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [ngModel]=\"selectedWorkflowId()\"\r\n (ngModelChange)=\"onWorkflowChange($event)\"\r\n class=\"mt-2\"\r\n />\r\n </mt-card>\r\n </div>\r\n }\r\n <div class=\"pointer-events-auto absolute top-4 end-4 z-10\">\r\n <div class=\"flex flex-col gap-2 w-80\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-10\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"dev.dataflow-01\"\r\n />\r\n <label>{{\r\n \"workflow.builder.enableWorkflow\" | transloco\r\n }}</label>\r\n </div>\r\n <mt-toggle-field\r\n [ngModel]=\"isPublished()\"\r\n (ngModelChange)=\"onPublishToggle($event)\"\r\n [disabled]=\"isPublishDisabled()\"\r\n ></mt-toggle-field>\r\n </div>\r\n </mt-card>\r\n\r\n @if (publishError()) {\r\n <mt-card>\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ publishError() }}\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n <ng-template\r\n #nodeDialog\r\n let-close=\"close\"\r\n let-save=\"save\"\r\n let-node=\"node\"\r\n let-drawerController=\"drawerController\"\r\n >\r\n <div class=\"p-4\">\r\n @if (loadingStep()) {\r\n <div class=\"space-y-4\">\r\n <div class=\"flex gap-2 mb-4\">\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <!-- Form fields skeleton -->\r\n <div class=\"space-y-4\">\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"10rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"3rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"4rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <mt-tabs\r\n [active]=\"selectedTab()\"\r\n (activeChange)=\"onNodeDialogTabChange($event)\"\r\n [options]=\"tabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n @switch (selectedTab()) {\r\n @case (\"tab1\") {\r\n <div class=\"mt-4 space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <mt-text-field\r\n [label]=\"t('nameEnglish')\"\r\n [placeholder]=\"t('enterNameEnglish')\"\r\n [formControl]=\"stepForm.controls.nameEn\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n <mt-text-field\r\n [label]=\"t('nameArabic')\"\r\n [placeholder]=\"t('enterNameArabic')\"\r\n [formControl]=\"stepForm.controls.nameAr\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n </div>\r\n\r\n @if (currentStepType() === \"UserInput\") {\r\n @if (!isEditingInitialNode()) {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"approver\") }}\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('approver')\"\r\n [options]=\"[\r\n { label: t('group'), value: '1' },\r\n { label: t('role'), value: '2' },\r\n ]\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.targetType\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n @if (\r\n stepForm.controls.targetType.value === \"1\"\r\n ) {\r\n <mt-select-field\r\n [label]=\"t('group')\"\r\n [placeholder]=\"t('selectGroup')\"\r\n [options]=\"groups()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [formControl]=\"stepForm.controls.group\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n } @else {\r\n <mt-select-field\r\n [label]=\"t('role')\"\r\n [placeholder]=\"t('selectRole')\"\r\n [options]=\"roles()\"\r\n [group]=\"hasGroupedRoles()\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.role\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n }\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n } @else {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"app\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-700\"\r\n >\r\n {{ t(\"appLabelPplus\") }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"action\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-900\"\r\n >\r\n {{ getAppActionDisplayName() }}\r\n </div>\r\n @if (getAppActionKey()) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ getAppActionKey() }}\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (\r\n getAppActionDescription();\r\n as description\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-muted-color\"\r\n >\r\n {{ description }}\r\n </div>\r\n }\r\n\r\n @if (\r\n getAppActionDiscoveryMessage();\r\n as discoveryMessage\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ discoveryMessage }}\r\n </div>\r\n }\r\n\r\n @if (isAppActionMissing()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n <div class=\"font-semibold\">\r\n {{ t(\"unknownAppAction\") }}\r\n </div>\r\n <div class=\"mt-1 text-xs\">\r\n {{ t(\"unknownAppActionHint\") }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div>\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionConfiguration\") }}\r\n </div>\r\n <div class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"appActionConfigurationDescription\") }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n loadingAppActionDetail() &&\r\n appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div class=\"space-y-3\">\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"6rem\"\r\n ></p-skeleton>\r\n </div>\r\n } @else if (\r\n !appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-dashed border-surface-300 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionUnavailable\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"schema\" &&\r\n appActionConfigDefinition().fields.length === 0\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionNoConfigRequired\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"raw\"\r\n ) {\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionRawConfigFallback\") }}\r\n </div>\r\n <mt-textarea-field\r\n [label]=\"t('appActionConfigJson')\"\r\n [placeholder]=\"\r\n t('enterAppActionConfigJson')\r\n \"\r\n [formControl]=\"appActionRawConfigControl\"\r\n [rows]=\"'10'\"\r\n ></mt-textarea-field>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (\r\n field of appActionConfigDefinition().fields;\r\n track field.key\r\n ) {\r\n <div class=\"space-y-2\">\r\n @switch (field.kind) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-text-field>\r\n }\r\n @case (\"number\") {\r\n <mt-number-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-number-field>\r\n }\r\n @case (\"toggle\") {\r\n <mt-toggle-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [label]=\"field.title\"\r\n [options]=\"\r\n getAppActionEnumOptions(field)\r\n \"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-select-field>\r\n }\r\n @case (\"json\") {\r\n <mt-textarea-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n [rows]=\"'8'\"\r\n ></mt-textarea-field>\r\n }\r\n }\r\n\r\n @if (field.description) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ field.description }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getAppActionConfigMessages().length) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700\"\r\n >\r\n @for (\r\n message of getAppActionConfigMessages();\r\n track message\r\n ) {\r\n <div>{{ message }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n\r\n @if (getAppActionRuntimeInputs().length) {\r\n <mt-card>\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionResolvedAutomatically\") }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionResolvedAutomaticallyHint\") }}\r\n </div>\r\n <div class=\"space-y-2\">\r\n @for (\r\n input of getAppActionRuntimeInputs();\r\n track input.key\r\n ) {\r\n <div\r\n class=\"flex items-start justify-between gap-3 rounded-lg border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ input.key }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{\r\n describeRuntimeInputSource(input)\r\n }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 rounded-full bg-surface-200 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-surface-600\"\r\n >\r\n {{ t(\"appActionRuntime\") }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n @if (getAppActionOutputs().length) {\r\n <mt-card>\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionOutputs\") }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionOutputsHint\") }}\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (\r\n output of getAppActionOutputs();\r\n track output.key\r\n ) {\r\n <span\r\n class=\"rounded-md bg-surface-100 px-2 py-0.5 text-xs font-mono text-surface-700\"\r\n [title]=\"output.description ?? ''\"\r\n >\r\n {{ output.key }}:{{ output.type }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n @if (isAppActionAfterCommitOnly()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-3 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionAfterCommitGuidance\") }}\r\n </div>\r\n }\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"advancedExecution\") }}\r\n </div>\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n\r\n <mt-select-field\r\n [label]=\"t('failureBehavior')\"\r\n [options]=\"failureBehaviorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.failureBehavior\r\n \"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n <mt-number-field\r\n [label]=\"t('timeoutSeconds')\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.timeoutSeconds\r\n \"\r\n [required]=\"true\"\r\n [min]=\"1\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n }\r\n @case (\"tab2\") {\r\n <div class=\"mt-4\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-4\">\r\n <div class=\"flex flex-1 items-center gap-3\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"file.file-check-02\"\r\n />\r\n <div class=\"flex flex-col\">\r\n <label class=\"font-medium\">{{\r\n t(\"configureForm\")\r\n }}</label>\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"configureForm-description\")\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureForm')\"\r\n size=\"small\"\r\n (onClick)=\"openFormModal()\"\r\n ></mt-button>\r\n </div>\r\n </mt-card>\r\n </div>\r\n }\r\n @case (\"tab3\") {\r\n <div class=\"mt-4\">\r\n <mt-toggle-field\r\n toggleShape=\"card\"\r\n [label]=\"t('show-hide')\"\r\n [descriptionCard]=\"t('show-hide-notifications')\"\r\n icon=\"general.eye\"\r\n [formControl]=\"showHideControl\"\r\n >\r\n <ng-template #toggleCardBottom>\r\n @if (showHideControl.value) {\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureNotifications')\"\r\n size=\"small\"\r\n (onClick)=\"openNotificationsModal()\"\r\n ></mt-button>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-toggle-field>\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n </mt-structure-builder>\r\n } @else {\r\n <p-skeleton width=\"100%\" height=\"50rem\" />\r\n }\r\n }\r\n @case (\"notification\") {\r\n <div class=\"flex-1 flex justify-center items-start p-4\">\r\n <div class=\"w-1/2 max-[1025px]:w-full\">\r\n <mt-card [title]=\"t('notifications')\">\r\n <mt-notification-template />\r\n </mt-card>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n", dependencies: [{ kind: "component", type: StructureBuilder, selector: "mt-structure-builder", inputs: ["availableNodes", "availableNodesLabel", "nodeForm", "nodeDialogFooterConfig", "connectionForm", "connectionFormulaSchemaId", "connectionFormulaConfig", "nodeActions", "nodeFields", "isAutoLayout", "readonly", "structureMode", "nodeStyle", "addModalType", "updateModalType", "addModalStyleClass", "updateModalStyleClass", "addModalHeader", "updateModalHeader", "appendTo", "availableTabsClass", "layoutDirection", "nodes", "connections", "nodeTemplate"], outputs: ["nodeActionsEvent", "action", "nodesChange", "connectionsChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: i2.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: NotificationTemplate, selector: "mt-notification-template" }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "pInputs", "format", "useGrouping", "maxFractionDigits", "min", "max", "required"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows", "required"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
|
|
2502
2989
|
}
|
|
2503
2990
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkflowBuilder, decorators: [{
|
|
2504
2991
|
type: Component,
|
|
@@ -2517,7 +3004,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2517
3004
|
TextField,
|
|
2518
3005
|
NumberField,
|
|
2519
3006
|
TextareaField,
|
|
2520
|
-
], host: {}, template: "<ng-container *transloco=\"let t; prefix: 'workflow.builder'\">\r\n <div class=\"h-full flex flex-col\" id=\"workflow-builder-card\">\r\n <div class=\"flex justify-center w-full py-2\">\r\n <mt-tabs\r\n [active]=\"mainTab()\"\r\n (activeChange)=\"onMainTabChange($event)\"\r\n [options]=\"mainTabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n </div>\r\n @switch (mainTab()) {\r\n @case (\"workflow\") {\r\n @if (!loading()) {\r\n <mt-structure-builder\r\n class=\"flex-1\"\r\n [structureMode]=\"'workflow'\"\r\n [availableNodes]=\"availableNodes()\"\r\n [availableNodesLabel]=\"t('stepTemplates')\"\r\n [connectionForm]=\"connectionForm()\"\r\n [connectionFormulaSchemaId]=\"connectionFormulaSchemaId()\"\r\n [connectionFormulaConfig]=\"connectionFormulaConfig()\"\r\n [nodeActions]=\"nodeActions()\"\r\n [nodes]=\"steps()\"\r\n [connections]=\"connections()\"\r\n (action)=\"onStructureAction($event)\"\r\n [addModalType]=\"'drawer'\"\r\n [addModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\r\n [updateModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\r\n [addModalHeader]=\"'workflow.builder.addStep' | transloco\"\r\n [updateModalHeader]=\"'workflow.builder.editStep' | transloco\"\r\n [nodeDialogFooterConfig]=\"nodeDialogFooterConfig\"\r\n [appendTo]=\"'page-content'\"\r\n [nodeFields]=\"nodeFields()\"\r\n [availableTabsClass]=\"hasMultipleWorkflows() ? '!mt-28' : ''\"\r\n [layoutDirection]=\"'LR'\"\r\n >\r\n <div flowContent class=\"pointer-events-none\">\r\n @if (hasMultipleWorkflows()) {\r\n <div class=\"pointer-events-auto absolute top-4 start-4 z-10\">\r\n <mt-card class=\"w-64\">\r\n <mt-select-field\r\n [options]=\"workflows()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [ngModel]=\"selectedWorkflowId()\"\r\n (ngModelChange)=\"onWorkflowChange($event)\"\r\n class=\"mt-2\"\r\n />\r\n </mt-card>\r\n </div>\r\n }\r\n <div class=\"pointer-events-auto absolute top-4 end-4 z-10\">\r\n <div class=\"flex flex-col gap-2 w-80\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-10\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"dev.dataflow-01\"\r\n />\r\n <label>{{\r\n \"workflow.builder.enableWorkflow\" | transloco\r\n }}</label>\r\n </div>\r\n <mt-toggle-field\r\n [ngModel]=\"isPublished()\"\r\n (ngModelChange)=\"onPublishToggle($event)\"\r\n [disabled]=\"isPublishDisabled()\"\r\n ></mt-toggle-field>\r\n </div>\r\n </mt-card>\r\n </div>\r\n </div>\r\n </div>\r\n <ng-template\r\n #nodeDialog\r\n let-close=\"close\"\r\n let-save=\"save\"\r\n let-node=\"node\"\r\n let-drawerController=\"drawerController\"\r\n >\r\n <div class=\"p-4\">\r\n @if (loadingStep()) {\r\n <div class=\"space-y-4\">\r\n <div class=\"flex gap-2 mb-4\">\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <!-- Form fields skeleton -->\r\n <div class=\"space-y-4\">\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"10rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"3rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"4rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <mt-tabs\r\n [active]=\"selectedTab()\"\r\n (activeChange)=\"onNodeDialogTabChange($event)\"\r\n [options]=\"tabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n @switch (selectedTab()) {\r\n @case (\"tab1\") {\r\n <div class=\"mt-4 space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <mt-text-field\r\n [label]=\"t('nameEnglish')\"\r\n [placeholder]=\"t('enterNameEnglish')\"\r\n [formControl]=\"stepForm.controls.nameEn\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n <mt-text-field\r\n [label]=\"t('nameArabic')\"\r\n [placeholder]=\"t('enterNameArabic')\"\r\n [formControl]=\"stepForm.controls.nameAr\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n </div>\r\n\r\n @if (currentStepType() === \"UserInput\") {\r\n @if (!isEditingInitialNode()) {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"approver\") }}\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('approver')\"\r\n [options]=\"[\r\n { label: t('group'), value: '1' },\r\n { label: t('role'), value: '2' },\r\n ]\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.targetType\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n @if (\r\n stepForm.controls.targetType.value === \"1\"\r\n ) {\r\n <mt-select-field\r\n [label]=\"t('group')\"\r\n [placeholder]=\"t('selectGroup')\"\r\n [options]=\"groups()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [formControl]=\"stepForm.controls.group\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n } @else {\r\n <mt-select-field\r\n [label]=\"t('role')\"\r\n [placeholder]=\"t('selectRole')\"\r\n [options]=\"roles()\"\r\n [group]=\"hasGroupedRoles()\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.role\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n }\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n } @else {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"app\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-700\"\r\n >\r\n {{ t(\"appLabelPplus\") }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"action\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-900\"\r\n >\r\n {{ getAppActionDisplayName() }}\r\n </div>\r\n @if (getAppActionKey()) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ getAppActionKey() }}\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (\r\n getAppActionDescription();\r\n as description\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-muted-color\"\r\n >\r\n {{ description }}\r\n </div>\r\n }\r\n\r\n @if (\r\n getAppActionDiscoveryMessage();\r\n as discoveryMessage\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ discoveryMessage }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div>\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionConfiguration\") }}\r\n </div>\r\n <div class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"appActionConfigurationDescription\") }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n loadingAppActionDetail() &&\r\n appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div class=\"space-y-3\">\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"6rem\"\r\n ></p-skeleton>\r\n </div>\r\n } @else if (\r\n !appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-dashed border-surface-300 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionUnavailable\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"schema\" &&\r\n appActionConfigDefinition().fields.length === 0\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionNoConfigRequired\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"raw\"\r\n ) {\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionRawConfigFallback\") }}\r\n </div>\r\n <mt-textarea-field\r\n [label]=\"t('appActionConfigJson')\"\r\n [placeholder]=\"\r\n t('enterAppActionConfigJson')\r\n \"\r\n [formControl]=\"appActionRawConfigControl\"\r\n [rows]=\"'10'\"\r\n ></mt-textarea-field>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (\r\n field of appActionConfigDefinition().fields;\r\n track field.key\r\n ) {\r\n <div class=\"space-y-2\">\r\n @switch (field.kind) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-text-field>\r\n }\r\n @case (\"number\") {\r\n <mt-number-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-number-field>\r\n }\r\n @case (\"toggle\") {\r\n <mt-toggle-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [label]=\"field.title\"\r\n [options]=\"\r\n getAppActionEnumOptions(field)\r\n \"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-select-field>\r\n }\r\n @case (\"json\") {\r\n <mt-textarea-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n [rows]=\"'8'\"\r\n ></mt-textarea-field>\r\n }\r\n }\r\n\r\n @if (field.description) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ field.description }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getAppActionConfigMessages().length) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700\"\r\n >\r\n @for (\r\n message of getAppActionConfigMessages();\r\n track message\r\n ) {\r\n <div>{{ message }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"advancedExecution\") }}\r\n </div>\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n\r\n <mt-select-field\r\n [label]=\"t('failureBehavior')\"\r\n [options]=\"failureBehaviorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.failureBehavior\r\n \"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n <mt-number-field\r\n [label]=\"t('timeoutSeconds')\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.timeoutSeconds\r\n \"\r\n [required]=\"true\"\r\n [min]=\"1\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n }\r\n @case (\"tab2\") {\r\n <div class=\"mt-4\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-4\">\r\n <div class=\"flex flex-1 items-center gap-3\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"file.file-check-02\"\r\n />\r\n <div class=\"flex flex-col\">\r\n <label class=\"font-medium\">{{\r\n t(\"configureForm\")\r\n }}</label>\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"configureForm-description\")\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureForm')\"\r\n size=\"small\"\r\n (onClick)=\"openFormModal()\"\r\n ></mt-button>\r\n </div>\r\n </mt-card>\r\n </div>\r\n }\r\n @case (\"tab3\") {\r\n <div class=\"mt-4\">\r\n <mt-toggle-field\r\n toggleShape=\"card\"\r\n [label]=\"t('show-hide')\"\r\n [descriptionCard]=\"t('show-hide-notifications')\"\r\n icon=\"general.eye\"\r\n [formControl]=\"showHideControl\"\r\n >\r\n <ng-template #toggleCardBottom>\r\n @if (showHideControl.value) {\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureNotifications')\"\r\n size=\"small\"\r\n (onClick)=\"openNotificationsModal()\"\r\n ></mt-button>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-toggle-field>\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n </mt-structure-builder>\r\n } @else {\r\n <p-skeleton width=\"100%\" height=\"50rem\" />\r\n }\r\n }\r\n @case (\"notification\") {\r\n <div class=\"flex-1 flex justify-center items-start p-4\">\r\n <div class=\"w-1/2 max-[1025px]:w-full\">\r\n <mt-card [title]=\"t('notifications')\">\r\n <mt-notification-template />\r\n </mt-card>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n" }]
|
|
3007
|
+
], host: {}, template: "<ng-container *transloco=\"let t; prefix: 'workflow.builder'\">\r\n <div class=\"h-full flex flex-col\" id=\"workflow-builder-card\">\r\n <div class=\"flex justify-center w-full py-2\">\r\n <mt-tabs\r\n [active]=\"mainTab()\"\r\n (activeChange)=\"onMainTabChange($event)\"\r\n [options]=\"mainTabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n </div>\r\n @switch (mainTab()) {\r\n @case (\"workflow\") {\r\n @if (!loading()) {\r\n <mt-structure-builder\r\n class=\"flex-1\"\r\n [structureMode]=\"'workflow'\"\r\n [availableNodes]=\"availableNodes()\"\r\n [availableNodesLabel]=\"t('stepTemplates')\"\r\n [connectionForm]=\"connectionForm()\"\r\n [connectionFormulaSchemaId]=\"connectionFormulaSchemaId()\"\r\n [connectionFormulaConfig]=\"connectionFormulaConfig()\"\r\n [nodeActions]=\"nodeActions()\"\r\n [nodes]=\"steps()\"\r\n [connections]=\"connections()\"\r\n (action)=\"onStructureAction($event)\"\r\n [addModalType]=\"'drawer'\"\r\n [addModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\r\n [updateModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\r\n [addModalHeader]=\"'workflow.builder.addStep' | transloco\"\r\n [updateModalHeader]=\"'workflow.builder.editStep' | transloco\"\r\n [nodeDialogFooterConfig]=\"nodeDialogFooterConfig\"\r\n [appendTo]=\"'page-content'\"\r\n [nodeFields]=\"nodeFields()\"\r\n [availableTabsClass]=\"hasMultipleWorkflows() ? '!mt-28' : ''\"\r\n [layoutDirection]=\"'LR'\"\r\n >\r\n <div flowContent class=\"pointer-events-none\">\r\n @if (hasMultipleWorkflows()) {\r\n <div class=\"pointer-events-auto absolute top-4 start-4 z-10\">\r\n <mt-card class=\"w-64\">\r\n <mt-select-field\r\n [options]=\"workflows()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [ngModel]=\"selectedWorkflowId()\"\r\n (ngModelChange)=\"onWorkflowChange($event)\"\r\n class=\"mt-2\"\r\n />\r\n </mt-card>\r\n </div>\r\n }\r\n <div class=\"pointer-events-auto absolute top-4 end-4 z-10\">\r\n <div class=\"flex flex-col gap-2 w-80\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-10\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"dev.dataflow-01\"\r\n />\r\n <label>{{\r\n \"workflow.builder.enableWorkflow\" | transloco\r\n }}</label>\r\n </div>\r\n <mt-toggle-field\r\n [ngModel]=\"isPublished()\"\r\n (ngModelChange)=\"onPublishToggle($event)\"\r\n [disabled]=\"isPublishDisabled()\"\r\n ></mt-toggle-field>\r\n </div>\r\n </mt-card>\r\n\r\n @if (publishError()) {\r\n <mt-card>\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ publishError() }}\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n <ng-template\r\n #nodeDialog\r\n let-close=\"close\"\r\n let-save=\"save\"\r\n let-node=\"node\"\r\n let-drawerController=\"drawerController\"\r\n >\r\n <div class=\"p-4\">\r\n @if (loadingStep()) {\r\n <div class=\"space-y-4\">\r\n <div class=\"flex gap-2 mb-4\">\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <!-- Form fields skeleton -->\r\n <div class=\"space-y-4\">\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"8rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"10rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"3rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"6rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n <div>\r\n <p-skeleton\r\n width=\"4rem\"\r\n height=\"1rem\"\r\n styleClass=\"mb-2\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n borderRadius=\"0.5rem\"\r\n ></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <mt-tabs\r\n [active]=\"selectedTab()\"\r\n (activeChange)=\"onNodeDialogTabChange($event)\"\r\n [options]=\"tabsList()\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n @switch (selectedTab()) {\r\n @case (\"tab1\") {\r\n <div class=\"mt-4 space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <mt-text-field\r\n [label]=\"t('nameEnglish')\"\r\n [placeholder]=\"t('enterNameEnglish')\"\r\n [formControl]=\"stepForm.controls.nameEn\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n <mt-text-field\r\n [label]=\"t('nameArabic')\"\r\n [placeholder]=\"t('enterNameArabic')\"\r\n [formControl]=\"stepForm.controls.nameAr\"\r\n [required]=\"true\"\r\n ></mt-text-field>\r\n </div>\r\n\r\n @if (currentStepType() === \"UserInput\") {\r\n @if (!isEditingInitialNode()) {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"approver\") }}\r\n </div>\r\n <mt-select-field\r\n [label]=\"t('approver')\"\r\n [options]=\"[\r\n { label: t('group'), value: '1' },\r\n { label: t('role'), value: '2' },\r\n ]\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.targetType\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n @if (\r\n stepForm.controls.targetType.value === \"1\"\r\n ) {\r\n <mt-select-field\r\n [label]=\"t('group')\"\r\n [placeholder]=\"t('selectGroup')\"\r\n [options]=\"groups()\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"id\"\r\n [formControl]=\"stepForm.controls.group\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n } @else {\r\n <mt-select-field\r\n [label]=\"t('role')\"\r\n [placeholder]=\"t('selectRole')\"\r\n [options]=\"roles()\"\r\n [group]=\"hasGroupedRoles()\"\r\n optionGroupLabel=\"label\"\r\n optionGroupChildren=\"items\"\r\n optionLabel=\"name.display\"\r\n optionValue=\"value\"\r\n [formControl]=\"stepForm.controls.role\"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n }\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n } @else {\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div class=\"grid gap-3\">\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"app\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-700\"\r\n >\r\n {{ t(\"appLabelPplus\") }}\r\n </div>\r\n </div>\r\n\r\n <div class=\"grid gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ t(\"action\") }}\r\n </label>\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-surface-900\"\r\n >\r\n {{ getAppActionDisplayName() }}\r\n </div>\r\n @if (getAppActionKey()) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ getAppActionKey() }}\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (\r\n getAppActionDescription();\r\n as description\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-2 text-sm text-muted-color\"\r\n >\r\n {{ description }}\r\n </div>\r\n }\r\n\r\n @if (\r\n getAppActionDiscoveryMessage();\r\n as discoveryMessage\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700\"\r\n >\r\n {{ discoveryMessage }}\r\n </div>\r\n }\r\n\r\n @if (isAppActionMissing()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n <div class=\"font-semibold\">\r\n {{ t(\"unknownAppAction\") }}\r\n </div>\r\n <div class=\"mt-1 text-xs\">\r\n {{ t(\"unknownAppActionHint\") }}\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div>\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionConfiguration\") }}\r\n </div>\r\n <div class=\"mt-1 text-sm text-muted-color\">\r\n {{ t(\"appActionConfigurationDescription\") }}\r\n </div>\r\n </div>\r\n\r\n @if (\r\n loadingAppActionDetail() &&\r\n appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div class=\"space-y-3\">\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"2.5rem\"\r\n ></p-skeleton>\r\n <p-skeleton\r\n width=\"100%\"\r\n height=\"6rem\"\r\n ></p-skeleton>\r\n </div>\r\n } @else if (\r\n !appActionSettingsForm.controls.actionKey.value\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-dashed border-surface-300 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionUnavailable\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"schema\" &&\r\n appActionConfigDefinition().fields.length === 0\r\n ) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-3 py-4 text-sm text-muted-color\"\r\n >\r\n {{ t(\"appActionNoConfigRequired\") }}\r\n </div>\r\n } @else if (\r\n appActionConfigDefinition().mode === \"raw\"\r\n ) {\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionRawConfigFallback\") }}\r\n </div>\r\n <mt-textarea-field\r\n [label]=\"t('appActionConfigJson')\"\r\n [placeholder]=\"\r\n t('enterAppActionConfigJson')\r\n \"\r\n [formControl]=\"appActionRawConfigControl\"\r\n [rows]=\"'10'\"\r\n ></mt-textarea-field>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (\r\n field of appActionConfigDefinition().fields;\r\n track field.key\r\n ) {\r\n <div class=\"space-y-2\">\r\n @switch (field.kind) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-text-field>\r\n }\r\n @case (\"number\") {\r\n <mt-number-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-number-field>\r\n }\r\n @case (\"toggle\") {\r\n <mt-toggle-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [label]=\"field.title\"\r\n [options]=\"\r\n getAppActionEnumOptions(field)\r\n \"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n ></mt-select-field>\r\n }\r\n @case (\"json\") {\r\n <mt-textarea-field\r\n [label]=\"field.title\"\r\n [formControl]=\"\r\n getAppActionConfigControl(\r\n field.key\r\n )\r\n \"\r\n [required]=\"field.required\"\r\n [rows]=\"'8'\"\r\n ></mt-textarea-field>\r\n }\r\n }\r\n\r\n @if (field.description) {\r\n <div class=\"text-xs text-muted-color\">\r\n {{ field.description }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (getAppActionConfigMessages().length) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700\"\r\n >\r\n @for (\r\n message of getAppActionConfigMessages();\r\n track message\r\n ) {\r\n <div>{{ message }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n\r\n @if (getAppActionRuntimeInputs().length) {\r\n <mt-card>\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionResolvedAutomatically\") }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionResolvedAutomaticallyHint\") }}\r\n </div>\r\n <div class=\"space-y-2\">\r\n @for (\r\n input of getAppActionRuntimeInputs();\r\n track input.key\r\n ) {\r\n <div\r\n class=\"flex items-start justify-between gap-3 rounded-lg border border-surface-200 bg-surface-50 px-3 py-2\"\r\n >\r\n <div class=\"min-w-0\">\r\n <div\r\n class=\"text-sm font-medium text-surface-900\"\r\n >\r\n {{ input.key }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{\r\n describeRuntimeInputSource(input)\r\n }}\r\n </div>\r\n </div>\r\n <span\r\n class=\"shrink-0 rounded-full bg-surface-200 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-surface-600\"\r\n >\r\n {{ t(\"appActionRuntime\") }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n @if (getAppActionOutputs().length) {\r\n <mt-card>\r\n <div class=\"space-y-3\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"appActionOutputs\") }}\r\n </div>\r\n <div class=\"text-xs text-muted-color\">\r\n {{ t(\"appActionOutputsHint\") }}\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (\r\n output of getAppActionOutputs();\r\n track output.key\r\n ) {\r\n <span\r\n class=\"rounded-md bg-surface-100 px-2 py-0.5 text-xs font-mono text-surface-700\"\r\n [title]=\"output.description ?? ''\"\r\n >\r\n {{ output.key }}:{{ output.type }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n </mt-card>\r\n }\r\n\r\n @if (isAppActionAfterCommitOnly()) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-3 py-3 text-sm text-amber-800\"\r\n >\r\n {{ t(\"appActionAfterCommitGuidance\") }}\r\n </div>\r\n }\r\n\r\n <mt-card>\r\n <div class=\"space-y-4\">\r\n <div\r\n class=\"text-sm font-semibold text-surface-900\"\r\n >\r\n {{ t(\"advancedExecution\") }}\r\n </div>\r\n\r\n <mt-number-field\r\n [label]=\"t('sla')\"\r\n [placeholder]=\"t('enterSla')\"\r\n [formControl]=\"stepForm.controls.sla\"\r\n [required]=\"true\"\r\n [min]=\"0\"\r\n ></mt-number-field>\r\n\r\n <mt-select-field\r\n [label]=\"t('failureBehavior')\"\r\n [options]=\"failureBehaviorOptions()\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.failureBehavior\r\n \"\r\n [required]=\"true\"\r\n ></mt-select-field>\r\n\r\n <mt-number-field\r\n [label]=\"t('timeoutSeconds')\"\r\n [formControl]=\"\r\n appActionSettingsForm.controls.timeoutSeconds\r\n \"\r\n [required]=\"true\"\r\n [min]=\"1\"\r\n ></mt-number-field>\r\n </div>\r\n </mt-card>\r\n }\r\n </div>\r\n }\r\n @case (\"tab2\") {\r\n <div class=\"mt-4\">\r\n <mt-card>\r\n <div class=\"flex items-center gap-4\">\r\n <div class=\"flex flex-1 items-center gap-3\">\r\n <mt-button\r\n [severity]=\"'secondary'\"\r\n icon=\"file.file-check-02\"\r\n />\r\n <div class=\"flex flex-col\">\r\n <label class=\"font-medium\">{{\r\n t(\"configureForm\")\r\n }}</label>\r\n <span class=\"text-sm text-muted-color\">{{\r\n t(\"configureForm-description\")\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureForm')\"\r\n size=\"small\"\r\n (onClick)=\"openFormModal()\"\r\n ></mt-button>\r\n </div>\r\n </mt-card>\r\n </div>\r\n }\r\n @case (\"tab3\") {\r\n <div class=\"mt-4\">\r\n <mt-toggle-field\r\n toggleShape=\"card\"\r\n [label]=\"t('show-hide')\"\r\n [descriptionCard]=\"t('show-hide-notifications')\"\r\n icon=\"general.eye\"\r\n [formControl]=\"showHideControl\"\r\n >\r\n <ng-template #toggleCardBottom>\r\n @if (showHideControl.value) {\r\n <div class=\"mt-3\">\r\n <mt-button\r\n [label]=\"t('configureNotifications')\"\r\n size=\"small\"\r\n (onClick)=\"openNotificationsModal()\"\r\n ></mt-button>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-toggle-field>\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n </mt-structure-builder>\r\n } @else {\r\n <p-skeleton width=\"100%\" height=\"50rem\" />\r\n }\r\n }\r\n @case (\"notification\") {\r\n <div class=\"flex-1 flex justify-center items-start p-4\">\r\n <div class=\"w-1/2 max-[1025px]:w-full\">\r\n <mt-card [title]=\"t('notifications')\">\r\n <mt-notification-template />\r\n </mt-card>\r\n </div>\r\n </div>\r\n }\r\n }\r\n </div>\r\n</ng-container>\r\n" }]
|
|
2521
3008
|
}], ctorParameters: () => [] });
|
|
2522
3009
|
|
|
2523
3010
|
// store/app.state.ts
|
|
@@ -2535,5 +3022,5 @@ const REQUEST_CONTEXT = new HttpContextToken(() => ({
|
|
|
2535
3022
|
* Generated bundle index. Do not edit.
|
|
2536
3023
|
*/
|
|
2537
3024
|
|
|
2538
|
-
export { CreateConnection, CreateStep, DeleteConnection, DeleteStep, GetAppActionDetail, GetAppActions, GetFormulaProperties, GetGroups, GetRolesForModule, GetStep, GetWorkflow, GetWorkflows, PublishWorkflow, REQUEST_CONTEXT, SetModuleInfo, UpdateConnection, UpdateStep, ValidateFlow, WorkflowBuilder, WorkflowFacade, WorkflowState };
|
|
3025
|
+
export { CreateConnection, CreateStep, DeleteConnection, DeleteStep, GetAppActionDetail, GetAppActionOptions, GetAppActions, GetFormulaProperties, GetGroups, GetRolesForModule, GetStep, GetWorkflow, GetWorkflows, PublishWorkflow, REQUEST_CONTEXT, SetModuleInfo, UpdateConnection, UpdateStep, ValidateFlow, WorkflowBuilder, WorkflowFacade, WorkflowState, buildAppActionOptionsCacheKey };
|
|
2539
3026
|
//# sourceMappingURL=masterteam-workflow.mjs.map
|