@masterteam/escalation 0.0.1
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/README.md +15 -0
- package/assets/escalation.css +2 -0
- package/fesm2022/masterteam-escalation.mjs +1190 -0
- package/fesm2022/masterteam-escalation.mjs.map +1 -0
- package/index.d.ts +335 -0
- package/package.json +44 -0
|
@@ -0,0 +1,1190 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, Injectable, computed, signal, linkedSignal, effect, Component } from '@angular/core';
|
|
3
|
+
import { Card } from '@masterteam/components/card';
|
|
4
|
+
import { StructureBuilder } from '@masterteam/structure-builder';
|
|
5
|
+
import { Action, Selector, State, Store, select } from '@ngxs/store';
|
|
6
|
+
import { HttpClient } from '@angular/common/http';
|
|
7
|
+
import { of } from 'rxjs';
|
|
8
|
+
import { tap, catchError, finalize } from 'rxjs/operators';
|
|
9
|
+
import * as i1 from '@angular/forms';
|
|
10
|
+
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
|
11
|
+
import { DynamicForm } from '@masterteam/forms/dynamic-form';
|
|
12
|
+
import { Skeleton } from 'primeng/skeleton';
|
|
13
|
+
|
|
14
|
+
class SetModuleInfo {
|
|
15
|
+
moduleType;
|
|
16
|
+
moduleId;
|
|
17
|
+
parentModuleType;
|
|
18
|
+
parentModuleId;
|
|
19
|
+
parentPath;
|
|
20
|
+
static type = '[Escalation] Set Module Info';
|
|
21
|
+
constructor(moduleType, moduleId, parentModuleType, parentModuleId, parentPath) {
|
|
22
|
+
this.moduleType = moduleType;
|
|
23
|
+
this.moduleId = moduleId;
|
|
24
|
+
this.parentModuleType = parentModuleType;
|
|
25
|
+
this.parentModuleId = parentModuleId;
|
|
26
|
+
this.parentPath = parentPath;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
class GetEscalation {
|
|
30
|
+
static type = '[Escalation] Get Escalation';
|
|
31
|
+
}
|
|
32
|
+
class GetFormulaProperties {
|
|
33
|
+
static type = '[Escalation] Get Formula Properties';
|
|
34
|
+
}
|
|
35
|
+
class GetGroups {
|
|
36
|
+
static type = '[Escalation] Get Groups';
|
|
37
|
+
}
|
|
38
|
+
class GetRolesForModule {
|
|
39
|
+
static type = '[Escalation] Get Roles For Module';
|
|
40
|
+
}
|
|
41
|
+
class GetStep {
|
|
42
|
+
stepId;
|
|
43
|
+
static type = '[Escalation] Get Step';
|
|
44
|
+
constructor(stepId) {
|
|
45
|
+
this.stepId = stepId;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class ValidateFlow {
|
|
49
|
+
static type = '[Escalation] Validate Flow';
|
|
50
|
+
}
|
|
51
|
+
class CreateStep {
|
|
52
|
+
payload;
|
|
53
|
+
static type = '[Escalation] Create Step';
|
|
54
|
+
constructor(payload) {
|
|
55
|
+
this.payload = payload;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
class UpdateStep {
|
|
59
|
+
stepId;
|
|
60
|
+
payload;
|
|
61
|
+
static type = '[Escalation] Update Step';
|
|
62
|
+
constructor(stepId, payload) {
|
|
63
|
+
this.stepId = stepId;
|
|
64
|
+
this.payload = payload;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
class CreateConnection {
|
|
68
|
+
payload;
|
|
69
|
+
static type = '[Escalation] Create Connection';
|
|
70
|
+
constructor(payload) {
|
|
71
|
+
this.payload = payload;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
class UpdateConnection {
|
|
75
|
+
connectionId;
|
|
76
|
+
payload;
|
|
77
|
+
static type = '[Escalation] Update Connection';
|
|
78
|
+
constructor(connectionId, payload) {
|
|
79
|
+
this.connectionId = connectionId;
|
|
80
|
+
this.payload = payload;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
class PublishEscalation {
|
|
84
|
+
isPublished;
|
|
85
|
+
static type = '[Escalation] Publish Escalation';
|
|
86
|
+
constructor(isPublished) {
|
|
87
|
+
this.isPublished = isPublished;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
class DeleteStep {
|
|
91
|
+
stepId;
|
|
92
|
+
static type = '[Escalation] Delete Step';
|
|
93
|
+
constructor(stepId) {
|
|
94
|
+
this.stepId = stepId;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
class DeleteConnection {
|
|
98
|
+
connectionId;
|
|
99
|
+
static type = '[Escalation] Delete Connection';
|
|
100
|
+
constructor(connectionId) {
|
|
101
|
+
this.connectionId = connectionId;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function startLoading(ctx, loadingName) {
|
|
106
|
+
const { loadingActive, errors } = ctx.getState();
|
|
107
|
+
if (!loadingActive.includes(loadingName)) {
|
|
108
|
+
ctx.patchState({
|
|
109
|
+
loadingActive: [...loadingActive, loadingName],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (errors && errors[loadingName]) {
|
|
113
|
+
const { [loadingName]: _removed, ...rest } = errors;
|
|
114
|
+
ctx.patchState({ errors: rest });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function endLoading(ctx, loadingName) {
|
|
118
|
+
const { loadingActive } = ctx.getState();
|
|
119
|
+
ctx.patchState({
|
|
120
|
+
loadingActive: loadingActive.filter((name) => name !== loadingName),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function setLoadingError(ctx, loadingName, message) {
|
|
124
|
+
const { errors } = ctx.getState();
|
|
125
|
+
ctx.patchState({
|
|
126
|
+
errors: { ...errors, [loadingName]: message },
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
131
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
132
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
133
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
134
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
135
|
+
};
|
|
136
|
+
const DEFAULT_STATE = {
|
|
137
|
+
moduleType: null,
|
|
138
|
+
moduleId: null,
|
|
139
|
+
escalation: null,
|
|
140
|
+
formulaProperties: [],
|
|
141
|
+
groups: [],
|
|
142
|
+
roles: [],
|
|
143
|
+
selectedStep: null,
|
|
144
|
+
isFlowValid: null,
|
|
145
|
+
loadingActive: [],
|
|
146
|
+
errors: {},
|
|
147
|
+
};
|
|
148
|
+
let EscalationState = class EscalationState {
|
|
149
|
+
http = inject(HttpClient);
|
|
150
|
+
baseUrl = 'EscalationSchemas';
|
|
151
|
+
groupsUrl = 'identity/Groups';
|
|
152
|
+
rolesUrl = 'identity/roles/scopes';
|
|
153
|
+
static moduleId(state) {
|
|
154
|
+
return state.moduleId;
|
|
155
|
+
}
|
|
156
|
+
static moduleType(state) {
|
|
157
|
+
return state.moduleType;
|
|
158
|
+
}
|
|
159
|
+
static escalation(state) {
|
|
160
|
+
return state.escalation;
|
|
161
|
+
}
|
|
162
|
+
static formulaProperties(state) {
|
|
163
|
+
return state.formulaProperties;
|
|
164
|
+
}
|
|
165
|
+
static groups(state) {
|
|
166
|
+
return state.groups;
|
|
167
|
+
}
|
|
168
|
+
static roles(state) {
|
|
169
|
+
return state.roles;
|
|
170
|
+
}
|
|
171
|
+
static selectedStep(state) {
|
|
172
|
+
return state.selectedStep;
|
|
173
|
+
}
|
|
174
|
+
static isFlowValid(state) {
|
|
175
|
+
return state.isFlowValid;
|
|
176
|
+
}
|
|
177
|
+
static stepsSchema(state) {
|
|
178
|
+
return state.escalation?.stepsSchema ?? [];
|
|
179
|
+
}
|
|
180
|
+
static connections(state) {
|
|
181
|
+
return state.escalation?.connections ?? [];
|
|
182
|
+
}
|
|
183
|
+
static isLoadingFactory(state) {
|
|
184
|
+
return (loadingName) => state.loadingActive.includes(loadingName);
|
|
185
|
+
}
|
|
186
|
+
static errorFactory(state) {
|
|
187
|
+
return (loadingName) => state.errors?.[loadingName] ?? null;
|
|
188
|
+
}
|
|
189
|
+
setModuleInfo(ctx, action) {
|
|
190
|
+
let parentPath = '';
|
|
191
|
+
if (action.parentModuleType && action.parentModuleId) {
|
|
192
|
+
parentPath = `/${action.parentModuleType}/${action.parentModuleId}`;
|
|
193
|
+
}
|
|
194
|
+
else if (action.parentPath) {
|
|
195
|
+
parentPath = action.parentPath;
|
|
196
|
+
}
|
|
197
|
+
ctx.patchState({
|
|
198
|
+
moduleType: action.moduleType,
|
|
199
|
+
moduleId: action.moduleId,
|
|
200
|
+
parentModuleType: action.parentModuleType ?? null,
|
|
201
|
+
parentModuleId: action.parentModuleId ?? null,
|
|
202
|
+
parentPath: parentPath ?? '',
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
getEscalation(ctx, _action) {
|
|
206
|
+
startLoading(ctx, 'getEscalation');
|
|
207
|
+
const state = ctx.getState();
|
|
208
|
+
const { moduleId, parentPath, moduleType } = state;
|
|
209
|
+
if (!moduleId) {
|
|
210
|
+
const message = 'Module ID is not set';
|
|
211
|
+
setLoadingError(ctx, 'getEscalation', message);
|
|
212
|
+
endLoading(ctx, 'getEscalation');
|
|
213
|
+
return of(null);
|
|
214
|
+
}
|
|
215
|
+
return this.http
|
|
216
|
+
.get(`${this.baseUrl}${parentPath}/${moduleType}/${moduleId}`, {
|
|
217
|
+
params: { Mode: 'edit' },
|
|
218
|
+
})
|
|
219
|
+
.pipe(tap((response) => {
|
|
220
|
+
const escalation = response?.data ?? null;
|
|
221
|
+
ctx.patchState({ escalation });
|
|
222
|
+
}), catchError((error) => {
|
|
223
|
+
const message = error?.error?.message ??
|
|
224
|
+
error?.message ??
|
|
225
|
+
'Failed to load escalation';
|
|
226
|
+
setLoadingError(ctx, 'getEscalation', message);
|
|
227
|
+
return of(null);
|
|
228
|
+
}), finalize(() => endLoading(ctx, 'getEscalation')));
|
|
229
|
+
}
|
|
230
|
+
getFormulaProperties(ctx, _action) {
|
|
231
|
+
startLoading(ctx, 'getFormulaProperties');
|
|
232
|
+
const state = ctx.getState();
|
|
233
|
+
const moduleId = state.moduleId;
|
|
234
|
+
if (!moduleId) {
|
|
235
|
+
const message = 'Module ID is not set';
|
|
236
|
+
setLoadingError(ctx, 'getFormulaProperties', message);
|
|
237
|
+
endLoading(ctx, 'getFormulaProperties');
|
|
238
|
+
return of(null);
|
|
239
|
+
}
|
|
240
|
+
return this.http
|
|
241
|
+
.get(`${this.baseUrl}/processFormulaProperties/${moduleId}`)
|
|
242
|
+
.pipe(tap((response) => {
|
|
243
|
+
const formulaProperties = Array.isArray(response?.data)
|
|
244
|
+
? response.data
|
|
245
|
+
: [];
|
|
246
|
+
ctx.patchState({ formulaProperties });
|
|
247
|
+
}), catchError((error) => {
|
|
248
|
+
const message = error?.error?.message ??
|
|
249
|
+
error?.message ??
|
|
250
|
+
'Failed to load formula properties';
|
|
251
|
+
setLoadingError(ctx, 'getFormulaProperties', message);
|
|
252
|
+
return of([]);
|
|
253
|
+
}), finalize(() => endLoading(ctx, 'getFormulaProperties')));
|
|
254
|
+
}
|
|
255
|
+
getGroups(ctx, _action) {
|
|
256
|
+
const state = ctx.getState();
|
|
257
|
+
if (state.groups.length) {
|
|
258
|
+
return of(state.groups);
|
|
259
|
+
}
|
|
260
|
+
startLoading(ctx, 'getGroups');
|
|
261
|
+
return this.http.get(this.groupsUrl).pipe(tap((response) => {
|
|
262
|
+
const groups = Array.isArray(response?.data) ? response.data : [];
|
|
263
|
+
ctx.patchState({ groups });
|
|
264
|
+
}), catchError((error) => {
|
|
265
|
+
const message = error?.error?.message ?? error?.message ?? 'Failed to load groups';
|
|
266
|
+
setLoadingError(ctx, 'getGroups', message);
|
|
267
|
+
return of([]);
|
|
268
|
+
}), finalize(() => endLoading(ctx, 'getGroups')));
|
|
269
|
+
}
|
|
270
|
+
getRolesForModule(ctx, _action) {
|
|
271
|
+
const state = ctx.getState();
|
|
272
|
+
const { moduleType, moduleId } = state;
|
|
273
|
+
if (!moduleType || !moduleId) {
|
|
274
|
+
const message = 'Module type and module ID must be set';
|
|
275
|
+
setLoadingError(ctx, 'getRolesForModule', message);
|
|
276
|
+
return of([]);
|
|
277
|
+
}
|
|
278
|
+
startLoading(ctx, 'getRolesForModule');
|
|
279
|
+
return this.http
|
|
280
|
+
.get(`${this.rolesUrl}/${moduleType}/${moduleId}`, {
|
|
281
|
+
params: { inherited: 'true' },
|
|
282
|
+
})
|
|
283
|
+
.pipe(tap((response) => {
|
|
284
|
+
const roles = Array.isArray(response?.data) ? response.data : [];
|
|
285
|
+
ctx.patchState({ roles });
|
|
286
|
+
}), catchError((error) => {
|
|
287
|
+
const message = error?.error?.message ?? error?.message ?? 'Failed to load roles';
|
|
288
|
+
setLoadingError(ctx, 'getRolesForModule', message);
|
|
289
|
+
return of([]);
|
|
290
|
+
}), finalize(() => endLoading(ctx, 'getRolesForModule')));
|
|
291
|
+
}
|
|
292
|
+
getStep(ctx, action) {
|
|
293
|
+
startLoading(ctx, 'getStep');
|
|
294
|
+
return this.http
|
|
295
|
+
.get(`${this.baseUrl}/step/${action.stepId}`, {
|
|
296
|
+
params: { Mode: 'edit' },
|
|
297
|
+
})
|
|
298
|
+
.pipe(tap((response) => {
|
|
299
|
+
const selectedStep = response?.data ?? null;
|
|
300
|
+
ctx.patchState({ selectedStep });
|
|
301
|
+
}), catchError((error) => {
|
|
302
|
+
const message = error?.error?.message ?? error?.message ?? 'Failed to load step';
|
|
303
|
+
setLoadingError(ctx, 'getStep', message);
|
|
304
|
+
return of(null);
|
|
305
|
+
}), finalize(() => endLoading(ctx, 'getStep')));
|
|
306
|
+
}
|
|
307
|
+
validateFlow(ctx, _action) {
|
|
308
|
+
startLoading(ctx, 'validateFlow');
|
|
309
|
+
const state = ctx.getState();
|
|
310
|
+
const { moduleId, parentPath, moduleType } = state;
|
|
311
|
+
if (!moduleId) {
|
|
312
|
+
const message = 'Escalation ID is not set';
|
|
313
|
+
setLoadingError(ctx, 'validateFlow', message);
|
|
314
|
+
endLoading(ctx, 'validateFlow');
|
|
315
|
+
return of(null);
|
|
316
|
+
}
|
|
317
|
+
return this.http
|
|
318
|
+
.get(`${this.baseUrl}/requestSchema${parentPath}/${moduleType}/${moduleId}/validity`)
|
|
319
|
+
.pipe(tap((response) => {
|
|
320
|
+
const isFlowValid = response?.data ?? null;
|
|
321
|
+
ctx.patchState({ isFlowValid });
|
|
322
|
+
}), catchError((error) => {
|
|
323
|
+
const message = error?.error?.message ??
|
|
324
|
+
error?.message ??
|
|
325
|
+
'Failed to validate flow';
|
|
326
|
+
setLoadingError(ctx, 'validateFlow', message);
|
|
327
|
+
return of(null);
|
|
328
|
+
}), finalize(() => endLoading(ctx, 'validateFlow')));
|
|
329
|
+
}
|
|
330
|
+
createStep(ctx, action) {
|
|
331
|
+
const state = ctx.getState();
|
|
332
|
+
const { moduleId, parentPath, moduleType } = state;
|
|
333
|
+
if (!moduleId) {
|
|
334
|
+
const message = 'Escalation ID is not set';
|
|
335
|
+
setLoadingError(ctx, 'createStep', message);
|
|
336
|
+
return of(null);
|
|
337
|
+
}
|
|
338
|
+
const tempId = -Date.now();
|
|
339
|
+
const tempStep = {
|
|
340
|
+
...action.payload,
|
|
341
|
+
id: tempId,
|
|
342
|
+
loading: true,
|
|
343
|
+
};
|
|
344
|
+
if (state.escalation) {
|
|
345
|
+
ctx.patchState({
|
|
346
|
+
escalation: {
|
|
347
|
+
...state.escalation,
|
|
348
|
+
stepsSchema: [...state.escalation.stepsSchema, tempStep],
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
startLoading(ctx, 'createStep');
|
|
353
|
+
return this.http
|
|
354
|
+
.post(`${this.baseUrl}${parentPath}/${moduleType}/${moduleId}/steps`, action.payload)
|
|
355
|
+
.pipe(tap((response) => {
|
|
356
|
+
const createdStep = response?.data;
|
|
357
|
+
const currentState = ctx.getState();
|
|
358
|
+
if (createdStep && currentState.escalation) {
|
|
359
|
+
const updatedSteps = currentState.escalation.stepsSchema.map((step) => step.id === tempId ? { ...createdStep, loading: false } : step);
|
|
360
|
+
ctx.patchState({
|
|
361
|
+
escalation: {
|
|
362
|
+
...currentState.escalation,
|
|
363
|
+
stepsSchema: updatedSteps,
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}), catchError((error) => {
|
|
368
|
+
const currentState = ctx.getState();
|
|
369
|
+
if (currentState.escalation) {
|
|
370
|
+
const filteredSteps = currentState.escalation.stepsSchema.filter((step) => step.id !== tempId);
|
|
371
|
+
ctx.patchState({
|
|
372
|
+
escalation: {
|
|
373
|
+
...currentState.escalation,
|
|
374
|
+
stepsSchema: filteredSteps,
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
const message = error?.error?.message ?? error?.message ?? 'Failed to create step';
|
|
379
|
+
setLoadingError(ctx, 'createStep', message);
|
|
380
|
+
return of(null);
|
|
381
|
+
}), finalize(() => endLoading(ctx, 'createStep')));
|
|
382
|
+
}
|
|
383
|
+
updateStep(ctx, action) {
|
|
384
|
+
const state = ctx.getState();
|
|
385
|
+
const moduleId = state.moduleId;
|
|
386
|
+
if (!moduleId) {
|
|
387
|
+
const message = 'Escalation ID is not set';
|
|
388
|
+
setLoadingError(ctx, 'updateStep', message);
|
|
389
|
+
return of(null);
|
|
390
|
+
}
|
|
391
|
+
if (state.escalation) {
|
|
392
|
+
const updatedSteps = state.escalation.stepsSchema.map((step) => step.id === action.stepId ? { ...step, loading: true } : step);
|
|
393
|
+
ctx.patchState({
|
|
394
|
+
escalation: {
|
|
395
|
+
...state.escalation,
|
|
396
|
+
stepsSchema: updatedSteps,
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
startLoading(ctx, 'updateStep');
|
|
401
|
+
return this.http
|
|
402
|
+
.put(`${this.baseUrl}/steps/${action.stepId}`, action.payload)
|
|
403
|
+
.pipe(tap((response) => {
|
|
404
|
+
const updatedStep = response?.data;
|
|
405
|
+
const currentState = ctx.getState();
|
|
406
|
+
if (updatedStep && currentState.escalation) {
|
|
407
|
+
ctx.patchState({
|
|
408
|
+
escalation: {
|
|
409
|
+
...currentState.escalation,
|
|
410
|
+
stepsSchema: currentState.escalation.stepsSchema.map((step) => step.id === updatedStep.id
|
|
411
|
+
? { ...updatedStep, loading: false }
|
|
412
|
+
: step),
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
}), catchError((error) => {
|
|
417
|
+
const currentState = ctx.getState();
|
|
418
|
+
if (currentState.escalation) {
|
|
419
|
+
const errorSteps = currentState.escalation.stepsSchema.map((step) => step.id === action.stepId ? { ...step, loading: false } : step);
|
|
420
|
+
ctx.patchState({
|
|
421
|
+
escalation: {
|
|
422
|
+
...currentState.escalation,
|
|
423
|
+
stepsSchema: errorSteps,
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
const message = error?.error?.message ?? error?.message ?? 'Failed to update step';
|
|
428
|
+
setLoadingError(ctx, 'updateStep', message);
|
|
429
|
+
return of(null);
|
|
430
|
+
}), finalize(() => endLoading(ctx, 'updateStep')));
|
|
431
|
+
}
|
|
432
|
+
createConnection(ctx, action) {
|
|
433
|
+
const state = ctx.getState();
|
|
434
|
+
const { moduleId, parentPath, moduleType } = state;
|
|
435
|
+
if (!moduleId) {
|
|
436
|
+
const message = 'Escalation ID is not set';
|
|
437
|
+
setLoadingError(ctx, 'createConnection', message);
|
|
438
|
+
return of(null);
|
|
439
|
+
}
|
|
440
|
+
const tempId = -Date.now();
|
|
441
|
+
const tempConnection = {
|
|
442
|
+
...action.payload,
|
|
443
|
+
id: tempId,
|
|
444
|
+
loading: true,
|
|
445
|
+
source: action.payload.sourceStepId,
|
|
446
|
+
target: action.payload.targetStepId,
|
|
447
|
+
};
|
|
448
|
+
if (state.escalation) {
|
|
449
|
+
ctx.patchState({
|
|
450
|
+
escalation: {
|
|
451
|
+
...state.escalation,
|
|
452
|
+
connections: [...state.escalation.connections, tempConnection],
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
startLoading(ctx, 'createConnection');
|
|
457
|
+
return this.http
|
|
458
|
+
.post(`${this.baseUrl}${parentPath}/${moduleType}/${moduleId}/connections`, action.payload)
|
|
459
|
+
.pipe(tap((response) => {
|
|
460
|
+
const createdConnection = response?.data;
|
|
461
|
+
const currentState = ctx.getState();
|
|
462
|
+
if (createdConnection && currentState.escalation) {
|
|
463
|
+
const updatedConnections = currentState.escalation.connections.map((conn) => conn.id === tempId
|
|
464
|
+
? { ...createdConnection, loading: false }
|
|
465
|
+
: conn);
|
|
466
|
+
ctx.patchState({
|
|
467
|
+
escalation: {
|
|
468
|
+
...currentState.escalation,
|
|
469
|
+
connections: updatedConnections,
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}), catchError((error) => {
|
|
474
|
+
const currentState = ctx.getState();
|
|
475
|
+
if (currentState.escalation) {
|
|
476
|
+
const filteredConnections = currentState.escalation.connections.filter((conn) => conn.id !== tempId);
|
|
477
|
+
ctx.patchState({
|
|
478
|
+
escalation: {
|
|
479
|
+
...currentState.escalation,
|
|
480
|
+
connections: filteredConnections,
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
const message = error?.error?.message ??
|
|
485
|
+
error?.message ??
|
|
486
|
+
'Failed to create connection';
|
|
487
|
+
setLoadingError(ctx, 'createConnection', message);
|
|
488
|
+
return of(null);
|
|
489
|
+
}), finalize(() => endLoading(ctx, 'createConnection')));
|
|
490
|
+
}
|
|
491
|
+
updateConnection(ctx, action) {
|
|
492
|
+
const state = ctx.getState();
|
|
493
|
+
const moduleId = state.moduleId;
|
|
494
|
+
if (!moduleId) {
|
|
495
|
+
const message = 'Escalation ID is not set';
|
|
496
|
+
setLoadingError(ctx, 'updateConnection', message);
|
|
497
|
+
return of(null);
|
|
498
|
+
}
|
|
499
|
+
if (state.escalation) {
|
|
500
|
+
const updatedConnections = state.escalation.connections.map((conn) => conn.id === action.connectionId ? { ...conn, loading: true } : conn);
|
|
501
|
+
ctx.patchState({
|
|
502
|
+
escalation: {
|
|
503
|
+
...state.escalation,
|
|
504
|
+
connections: updatedConnections,
|
|
505
|
+
},
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
startLoading(ctx, 'updateConnection');
|
|
509
|
+
return this.http
|
|
510
|
+
.put(`${this.baseUrl}/connections/${action.connectionId}`, action.payload)
|
|
511
|
+
.pipe(tap((response) => {
|
|
512
|
+
const updatedConnection = response?.data;
|
|
513
|
+
const currentState = ctx.getState();
|
|
514
|
+
if (updatedConnection && currentState.escalation) {
|
|
515
|
+
ctx.patchState({
|
|
516
|
+
escalation: {
|
|
517
|
+
...currentState.escalation,
|
|
518
|
+
connections: currentState.escalation.connections.map((conn) => conn.id === updatedConnection.id
|
|
519
|
+
? { ...updatedConnection, loading: false }
|
|
520
|
+
: conn),
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}), catchError((error) => {
|
|
525
|
+
const currentState = ctx.getState();
|
|
526
|
+
if (currentState.escalation) {
|
|
527
|
+
const errorConnections = currentState.escalation.connections.map((conn) => conn.id === action.connectionId
|
|
528
|
+
? { ...conn, loading: false }
|
|
529
|
+
: conn);
|
|
530
|
+
ctx.patchState({
|
|
531
|
+
escalation: {
|
|
532
|
+
...currentState.escalation,
|
|
533
|
+
connections: errorConnections,
|
|
534
|
+
},
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
const message = error?.error?.message ??
|
|
538
|
+
error?.message ??
|
|
539
|
+
'Failed to update connection';
|
|
540
|
+
setLoadingError(ctx, 'updateConnection', message);
|
|
541
|
+
return of(null);
|
|
542
|
+
}), finalize(() => endLoading(ctx, 'updateConnection')));
|
|
543
|
+
}
|
|
544
|
+
publishEscalation(ctx, action) {
|
|
545
|
+
startLoading(ctx, 'publishEscalation');
|
|
546
|
+
const state = ctx.getState();
|
|
547
|
+
const { moduleId, parentPath, moduleType } = state;
|
|
548
|
+
if (!moduleId) {
|
|
549
|
+
const message = 'Escalation ID is not set';
|
|
550
|
+
setLoadingError(ctx, 'publishEscalation', message);
|
|
551
|
+
endLoading(ctx, 'publishEscalation');
|
|
552
|
+
return of(null);
|
|
553
|
+
}
|
|
554
|
+
return this.http
|
|
555
|
+
.put(`${this.baseUrl}${parentPath}/${moduleType}/${moduleId}/publish`, { IsPublished: action.isPublished })
|
|
556
|
+
.pipe(tap((response) => {
|
|
557
|
+
const publishedData = response?.data;
|
|
558
|
+
if (publishedData && state.escalation) {
|
|
559
|
+
ctx.patchState({
|
|
560
|
+
escalation: {
|
|
561
|
+
...state.escalation,
|
|
562
|
+
isPublished: publishedData.isPublished,
|
|
563
|
+
isValid: publishedData.isValid,
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}), catchError((error) => {
|
|
568
|
+
const message = error?.error?.message ??
|
|
569
|
+
error?.message ??
|
|
570
|
+
'Failed to publish escalation';
|
|
571
|
+
setLoadingError(ctx, 'publishEscalation', message);
|
|
572
|
+
return of(null);
|
|
573
|
+
}), finalize(() => endLoading(ctx, 'publishEscalation')));
|
|
574
|
+
}
|
|
575
|
+
deleteStep(ctx, action) {
|
|
576
|
+
const state = ctx.getState();
|
|
577
|
+
if (state.escalation) {
|
|
578
|
+
const updatedSteps = state.escalation.stepsSchema.map((step) => step.id == action.stepId ? { ...step, loading: true } : step);
|
|
579
|
+
ctx.patchState({
|
|
580
|
+
escalation: {
|
|
581
|
+
...state.escalation,
|
|
582
|
+
stepsSchema: updatedSteps,
|
|
583
|
+
},
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
startLoading(ctx, 'deleteStep');
|
|
587
|
+
return this.http
|
|
588
|
+
.delete(`${this.baseUrl}/steps/${action.stepId}`)
|
|
589
|
+
.pipe(tap(() => {
|
|
590
|
+
const currentState = ctx.getState();
|
|
591
|
+
if (currentState.escalation) {
|
|
592
|
+
ctx.patchState({
|
|
593
|
+
escalation: {
|
|
594
|
+
...currentState.escalation,
|
|
595
|
+
stepsSchema: currentState.escalation.stepsSchema.filter((step) => step.id != action.stepId),
|
|
596
|
+
},
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
}), catchError((error) => {
|
|
600
|
+
const currentState = ctx.getState();
|
|
601
|
+
if (currentState.escalation) {
|
|
602
|
+
const errorSteps = currentState.escalation.stepsSchema.map((step) => step.id == action.stepId ? { ...step, loading: false } : step);
|
|
603
|
+
ctx.patchState({
|
|
604
|
+
escalation: {
|
|
605
|
+
...currentState.escalation,
|
|
606
|
+
stepsSchema: errorSteps,
|
|
607
|
+
},
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
const message = error?.error?.message ?? error?.message ?? 'Failed to delete step';
|
|
611
|
+
setLoadingError(ctx, 'deleteStep', message);
|
|
612
|
+
return of(null);
|
|
613
|
+
}), finalize(() => endLoading(ctx, 'deleteStep')));
|
|
614
|
+
}
|
|
615
|
+
deleteConnection(ctx, action) {
|
|
616
|
+
const state = ctx.getState();
|
|
617
|
+
if (state.escalation) {
|
|
618
|
+
const updatedConnections = state.escalation.connections.map((conn) => conn.id == action.connectionId ? { ...conn, loading: true } : conn);
|
|
619
|
+
ctx.patchState({
|
|
620
|
+
escalation: {
|
|
621
|
+
...state.escalation,
|
|
622
|
+
connections: updatedConnections,
|
|
623
|
+
},
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
startLoading(ctx, 'deleteConnection');
|
|
627
|
+
return this.http
|
|
628
|
+
.delete(`${this.baseUrl}/connections/${action.connectionId}`)
|
|
629
|
+
.pipe(tap(() => {
|
|
630
|
+
const currentState = ctx.getState();
|
|
631
|
+
if (currentState.escalation) {
|
|
632
|
+
ctx.patchState({
|
|
633
|
+
escalation: {
|
|
634
|
+
...currentState.escalation,
|
|
635
|
+
connections: currentState.escalation.connections.filter((conn) => conn.id != action.connectionId),
|
|
636
|
+
},
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
}), catchError((error) => {
|
|
640
|
+
const currentState = ctx.getState();
|
|
641
|
+
if (currentState.escalation) {
|
|
642
|
+
const errorConnections = currentState.escalation.connections.map((conn) => conn.id == action.connectionId
|
|
643
|
+
? { ...conn, loading: false }
|
|
644
|
+
: conn);
|
|
645
|
+
ctx.patchState({
|
|
646
|
+
escalation: {
|
|
647
|
+
...currentState.escalation,
|
|
648
|
+
connections: errorConnections,
|
|
649
|
+
},
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
const message = error?.error?.message ??
|
|
653
|
+
error?.message ??
|
|
654
|
+
'Failed to delete connection';
|
|
655
|
+
setLoadingError(ctx, 'deleteConnection', message);
|
|
656
|
+
return of(null);
|
|
657
|
+
}), finalize(() => endLoading(ctx, 'deleteConnection')));
|
|
658
|
+
}
|
|
659
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EscalationState, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
660
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EscalationState });
|
|
661
|
+
};
|
|
662
|
+
__decorate([
|
|
663
|
+
Action(SetModuleInfo)
|
|
664
|
+
], EscalationState.prototype, "setModuleInfo", null);
|
|
665
|
+
__decorate([
|
|
666
|
+
Action(GetEscalation)
|
|
667
|
+
], EscalationState.prototype, "getEscalation", null);
|
|
668
|
+
__decorate([
|
|
669
|
+
Action(GetFormulaProperties)
|
|
670
|
+
], EscalationState.prototype, "getFormulaProperties", null);
|
|
671
|
+
__decorate([
|
|
672
|
+
Action(GetGroups)
|
|
673
|
+
], EscalationState.prototype, "getGroups", null);
|
|
674
|
+
__decorate([
|
|
675
|
+
Action(GetRolesForModule)
|
|
676
|
+
], EscalationState.prototype, "getRolesForModule", null);
|
|
677
|
+
__decorate([
|
|
678
|
+
Action(GetStep)
|
|
679
|
+
], EscalationState.prototype, "getStep", null);
|
|
680
|
+
__decorate([
|
|
681
|
+
Action(ValidateFlow)
|
|
682
|
+
], EscalationState.prototype, "validateFlow", null);
|
|
683
|
+
__decorate([
|
|
684
|
+
Action(CreateStep)
|
|
685
|
+
], EscalationState.prototype, "createStep", null);
|
|
686
|
+
__decorate([
|
|
687
|
+
Action(UpdateStep)
|
|
688
|
+
], EscalationState.prototype, "updateStep", null);
|
|
689
|
+
__decorate([
|
|
690
|
+
Action(CreateConnection)
|
|
691
|
+
], EscalationState.prototype, "createConnection", null);
|
|
692
|
+
__decorate([
|
|
693
|
+
Action(UpdateConnection)
|
|
694
|
+
], EscalationState.prototype, "updateConnection", null);
|
|
695
|
+
__decorate([
|
|
696
|
+
Action(PublishEscalation)
|
|
697
|
+
], EscalationState.prototype, "publishEscalation", null);
|
|
698
|
+
__decorate([
|
|
699
|
+
Action(DeleteStep)
|
|
700
|
+
], EscalationState.prototype, "deleteStep", null);
|
|
701
|
+
__decorate([
|
|
702
|
+
Action(DeleteConnection)
|
|
703
|
+
], EscalationState.prototype, "deleteConnection", null);
|
|
704
|
+
__decorate([
|
|
705
|
+
Selector()
|
|
706
|
+
], EscalationState, "moduleId", null);
|
|
707
|
+
__decorate([
|
|
708
|
+
Selector()
|
|
709
|
+
], EscalationState, "moduleType", null);
|
|
710
|
+
__decorate([
|
|
711
|
+
Selector()
|
|
712
|
+
], EscalationState, "escalation", null);
|
|
713
|
+
__decorate([
|
|
714
|
+
Selector()
|
|
715
|
+
], EscalationState, "formulaProperties", null);
|
|
716
|
+
__decorate([
|
|
717
|
+
Selector()
|
|
718
|
+
], EscalationState, "groups", null);
|
|
719
|
+
__decorate([
|
|
720
|
+
Selector()
|
|
721
|
+
], EscalationState, "roles", null);
|
|
722
|
+
__decorate([
|
|
723
|
+
Selector()
|
|
724
|
+
], EscalationState, "selectedStep", null);
|
|
725
|
+
__decorate([
|
|
726
|
+
Selector()
|
|
727
|
+
], EscalationState, "isFlowValid", null);
|
|
728
|
+
__decorate([
|
|
729
|
+
Selector()
|
|
730
|
+
], EscalationState, "stepsSchema", null);
|
|
731
|
+
__decorate([
|
|
732
|
+
Selector()
|
|
733
|
+
], EscalationState, "connections", null);
|
|
734
|
+
__decorate([
|
|
735
|
+
Selector()
|
|
736
|
+
], EscalationState, "isLoadingFactory", null);
|
|
737
|
+
__decorate([
|
|
738
|
+
Selector()
|
|
739
|
+
], EscalationState, "errorFactory", null);
|
|
740
|
+
EscalationState = __decorate([
|
|
741
|
+
State({
|
|
742
|
+
name: 'escalation',
|
|
743
|
+
defaults: DEFAULT_STATE,
|
|
744
|
+
})
|
|
745
|
+
], EscalationState);
|
|
746
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EscalationState, decorators: [{
|
|
747
|
+
type: Injectable
|
|
748
|
+
}], propDecorators: { setModuleInfo: [], getEscalation: [], getFormulaProperties: [], getGroups: [], getRolesForModule: [], getStep: [], validateFlow: [], createStep: [], updateStep: [], createConnection: [], updateConnection: [], publishEscalation: [], deleteStep: [], deleteConnection: [] } });
|
|
749
|
+
|
|
750
|
+
class EscalationFacade {
|
|
751
|
+
store = inject(Store);
|
|
752
|
+
moduleType = select(EscalationState.moduleType);
|
|
753
|
+
moduleId = select(EscalationState.moduleId);
|
|
754
|
+
escalation = select(EscalationState.escalation);
|
|
755
|
+
formulaProperties = select(EscalationState.formulaProperties);
|
|
756
|
+
groups = select(EscalationState.groups);
|
|
757
|
+
roles = select(EscalationState.roles);
|
|
758
|
+
selectedStep = select(EscalationState.selectedStep);
|
|
759
|
+
isFlowValid = select(EscalationState.isFlowValid);
|
|
760
|
+
steps = select(EscalationState.stepsSchema);
|
|
761
|
+
connections = select(EscalationState.connections);
|
|
762
|
+
isLoading(loadingName) {
|
|
763
|
+
const loadingFactory = select(EscalationState.isLoadingFactory);
|
|
764
|
+
return computed(() => loadingFactory()(loadingName));
|
|
765
|
+
}
|
|
766
|
+
error(loadingName) {
|
|
767
|
+
const errorFactory = select(EscalationState.errorFactory);
|
|
768
|
+
return computed(() => errorFactory()(loadingName));
|
|
769
|
+
}
|
|
770
|
+
setModuleInfo(moduleType, moduleId, parentModuleType, parentModuleId, parentPath) {
|
|
771
|
+
return this.store.dispatch(new SetModuleInfo(moduleType, moduleId, parentModuleType, parentModuleId, parentPath));
|
|
772
|
+
}
|
|
773
|
+
loadEscalation() {
|
|
774
|
+
return this.store.dispatch(new GetEscalation());
|
|
775
|
+
}
|
|
776
|
+
loadFormulaProperties() {
|
|
777
|
+
return this.store.dispatch(new GetFormulaProperties());
|
|
778
|
+
}
|
|
779
|
+
loadGroups() {
|
|
780
|
+
return this.store.dispatch(new GetGroups());
|
|
781
|
+
}
|
|
782
|
+
loadRolesForModule() {
|
|
783
|
+
return this.store.dispatch(new GetRolesForModule());
|
|
784
|
+
}
|
|
785
|
+
loadStep(stepId) {
|
|
786
|
+
return this.store.dispatch(new GetStep(stepId));
|
|
787
|
+
}
|
|
788
|
+
validateFlow() {
|
|
789
|
+
return this.store.dispatch(new ValidateFlow());
|
|
790
|
+
}
|
|
791
|
+
createStep(payload) {
|
|
792
|
+
return this.store.dispatch(new CreateStep(payload));
|
|
793
|
+
}
|
|
794
|
+
updateStep(stepId, payload) {
|
|
795
|
+
return this.store.dispatch(new UpdateStep(stepId, payload));
|
|
796
|
+
}
|
|
797
|
+
createConnection(payload) {
|
|
798
|
+
return this.store.dispatch(new CreateConnection(payload));
|
|
799
|
+
}
|
|
800
|
+
updateConnection(connectionId, payload) {
|
|
801
|
+
return this.store.dispatch(new UpdateConnection(connectionId, payload));
|
|
802
|
+
}
|
|
803
|
+
publishEscalation(isPublished) {
|
|
804
|
+
return this.store.dispatch(new PublishEscalation(isPublished));
|
|
805
|
+
}
|
|
806
|
+
deleteStep(stepId) {
|
|
807
|
+
return this.store.dispatch(new DeleteStep(stepId));
|
|
808
|
+
}
|
|
809
|
+
deleteConnection(connectionId) {
|
|
810
|
+
return this.store.dispatch(new DeleteConnection(connectionId));
|
|
811
|
+
}
|
|
812
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EscalationFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
813
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EscalationFacade, providedIn: 'root' });
|
|
814
|
+
}
|
|
815
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EscalationFacade, decorators: [{
|
|
816
|
+
type: Injectable,
|
|
817
|
+
args: [{
|
|
818
|
+
providedIn: 'root',
|
|
819
|
+
}]
|
|
820
|
+
}] });
|
|
821
|
+
|
|
822
|
+
// shared/models/api.model.ts
|
|
823
|
+
|
|
824
|
+
class EscalationBuilder {
|
|
825
|
+
escalationFacade = inject(EscalationFacade);
|
|
826
|
+
groups = this.escalationFacade.groups;
|
|
827
|
+
roles = this.escalationFacade.roles;
|
|
828
|
+
escalation = this.escalationFacade.escalation;
|
|
829
|
+
loading = this.escalationFacade.isLoading('getEscalation');
|
|
830
|
+
loadingStep = this.escalationFacade.isLoading('getStep');
|
|
831
|
+
selectedStep = this.escalationFacade.selectedStep;
|
|
832
|
+
nodeFields = signal({
|
|
833
|
+
name: 'name',
|
|
834
|
+
}, ...(ngDevMode ? [{ debugName: "nodeFields" }] : []));
|
|
835
|
+
nodeFormControl = new FormControl();
|
|
836
|
+
isEditingInitialNode = signal(false, ...(ngDevMode ? [{ debugName: "isEditingInitialNode" }] : []));
|
|
837
|
+
availableNodes = [
|
|
838
|
+
{
|
|
839
|
+
id: 'FormStep',
|
|
840
|
+
label: 'New Step',
|
|
841
|
+
name: {
|
|
842
|
+
en: 'New Step',
|
|
843
|
+
ar: ' خطوة جديدة',
|
|
844
|
+
},
|
|
845
|
+
targetType: '1',
|
|
846
|
+
icon: 'general.plus-circle',
|
|
847
|
+
color: '#000000',
|
|
848
|
+
},
|
|
849
|
+
];
|
|
850
|
+
// Base form sections - defined once for reusability
|
|
851
|
+
baseNameFields = {
|
|
852
|
+
key: 'settings',
|
|
853
|
+
type: 'none',
|
|
854
|
+
bodyClass: 'space-y-2',
|
|
855
|
+
fields: [
|
|
856
|
+
{
|
|
857
|
+
key: 'name.en',
|
|
858
|
+
label: 'Name (English)',
|
|
859
|
+
placeholder: 'Enter name in English',
|
|
860
|
+
cssClass: 'w-full',
|
|
861
|
+
required: true,
|
|
862
|
+
},
|
|
863
|
+
{
|
|
864
|
+
key: 'name.ar',
|
|
865
|
+
label: 'Name (Arabic)',
|
|
866
|
+
placeholder: 'Enter name in Arabic',
|
|
867
|
+
cssClass: 'w-full',
|
|
868
|
+
required: true,
|
|
869
|
+
},
|
|
870
|
+
],
|
|
871
|
+
};
|
|
872
|
+
// Approver section with dynamic options
|
|
873
|
+
approverSection = computed(() => ({
|
|
874
|
+
key: 'settings',
|
|
875
|
+
type: 'header',
|
|
876
|
+
label: 'Approver',
|
|
877
|
+
headerClass: 'rounded-t-xl bg-slate-50 px-4 py-3 text-sm font-semibold text-slate-900 border border-slate-200 border-b-0',
|
|
878
|
+
bodyClass: 'rounded-b-xl border border-slate-200 p-4 space-y-3',
|
|
879
|
+
cssClass: ' ',
|
|
880
|
+
fields: [
|
|
881
|
+
{
|
|
882
|
+
key: 'targetType',
|
|
883
|
+
type: 'radio-button',
|
|
884
|
+
orientation: 'horizontal',
|
|
885
|
+
defaultValue: '1',
|
|
886
|
+
options: [
|
|
887
|
+
{ label: 'Group', value: '1' },
|
|
888
|
+
{ label: 'Role', value: '2' },
|
|
889
|
+
],
|
|
890
|
+
optionLabel: 'title',
|
|
891
|
+
optionValue: 'value',
|
|
892
|
+
placeholder: 'Enter Role',
|
|
893
|
+
cssClass: 'flex items-center gap-6 text-sm text-slate-700',
|
|
894
|
+
required: true,
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
key: 'group',
|
|
898
|
+
label: 'Select',
|
|
899
|
+
placeholder: 'Select group',
|
|
900
|
+
cssClass: 'mt-2 pt-3 border-t border-slate-200 w-full',
|
|
901
|
+
required: true,
|
|
902
|
+
type: 'select',
|
|
903
|
+
options: this.groups(),
|
|
904
|
+
optionLabel: 'title',
|
|
905
|
+
optionValue: 'id',
|
|
906
|
+
relations: [{ key: 'targetType', value: '1', action: 'show' }],
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
key: 'role',
|
|
910
|
+
label: 'Select',
|
|
911
|
+
placeholder: 'Enter target value',
|
|
912
|
+
cssClass: 'mt-2 pt-3 border-t border-slate-200 w-full',
|
|
913
|
+
required: true,
|
|
914
|
+
type: 'select',
|
|
915
|
+
options: this.roles(),
|
|
916
|
+
optionLabel: 'title',
|
|
917
|
+
optionValue: 'id',
|
|
918
|
+
relations: [{ key: 'targetType', value: '2', action: 'show' }],
|
|
919
|
+
},
|
|
920
|
+
],
|
|
921
|
+
}), ...(ngDevMode ? [{ debugName: "approverSection" }] : []));
|
|
922
|
+
slaSection = {
|
|
923
|
+
key: 'slaSection',
|
|
924
|
+
type: 'none',
|
|
925
|
+
bodyClass: 'space-y-1',
|
|
926
|
+
fields: [
|
|
927
|
+
{
|
|
928
|
+
key: 'sla',
|
|
929
|
+
label: 'SLA',
|
|
930
|
+
placeholder: 'Enter SLA',
|
|
931
|
+
cssClass: 'w-full',
|
|
932
|
+
required: true,
|
|
933
|
+
},
|
|
934
|
+
],
|
|
935
|
+
};
|
|
936
|
+
// Dynamic form configuration using linkedSignal
|
|
937
|
+
// Automatically rebuilds when isEditingInitialNode changes
|
|
938
|
+
nodeForm = linkedSignal(() => {
|
|
939
|
+
const sections = [this.baseNameFields];
|
|
940
|
+
// Conditionally include approver and SLA sections based on isEditingInitialNode
|
|
941
|
+
// Initial nodes only show name fields
|
|
942
|
+
if (!this.isEditingInitialNode()) {
|
|
943
|
+
sections.push(this.approverSection());
|
|
944
|
+
sections.push(this.slaSection);
|
|
945
|
+
}
|
|
946
|
+
return {
|
|
947
|
+
sections,
|
|
948
|
+
layout: {},
|
|
949
|
+
};
|
|
950
|
+
});
|
|
951
|
+
// Sample connection form configuration
|
|
952
|
+
connectionForm = signal({
|
|
953
|
+
sections: [
|
|
954
|
+
{
|
|
955
|
+
key: 'basic',
|
|
956
|
+
label: 'Basic Information',
|
|
957
|
+
type: 'none',
|
|
958
|
+
cssClass: 'p-4',
|
|
959
|
+
order: 1,
|
|
960
|
+
fields: [
|
|
961
|
+
{
|
|
962
|
+
key: 'priority',
|
|
963
|
+
label: 'Priority',
|
|
964
|
+
},
|
|
965
|
+
],
|
|
966
|
+
},
|
|
967
|
+
],
|
|
968
|
+
}, ...(ngDevMode ? [{ debugName: "connectionForm" }] : []));
|
|
969
|
+
// Nodes currently in the flow
|
|
970
|
+
steps = computed(() => {
|
|
971
|
+
return this.escalationFacade.steps().map((step) => ({
|
|
972
|
+
...step,
|
|
973
|
+
color: '#000000',
|
|
974
|
+
}));
|
|
975
|
+
}, ...(ngDevMode ? [{ debugName: "steps" }] : []));
|
|
976
|
+
// Connections between nodes
|
|
977
|
+
connections = computed(() => {
|
|
978
|
+
return this.escalationFacade.connections().map((connection) => ({
|
|
979
|
+
...connection,
|
|
980
|
+
from: connection.source,
|
|
981
|
+
to: connection.target,
|
|
982
|
+
}));
|
|
983
|
+
}, ...(ngDevMode ? [{ debugName: "connections" }] : []));
|
|
984
|
+
// Node Actions
|
|
985
|
+
nodeActions = signal([
|
|
986
|
+
{
|
|
987
|
+
key: 'edit',
|
|
988
|
+
icon: 'general.edit-05',
|
|
989
|
+
variant: 'outlined',
|
|
990
|
+
size: 'small',
|
|
991
|
+
tooltip: 'Edit',
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
key: 'delete',
|
|
995
|
+
icon: 'general.trash-01',
|
|
996
|
+
variant: 'outlined',
|
|
997
|
+
size: 'small',
|
|
998
|
+
severity: 'danger',
|
|
999
|
+
tooltip: 'Delete',
|
|
1000
|
+
},
|
|
1001
|
+
], ...(ngDevMode ? [{ debugName: "nodeActions" }] : []));
|
|
1002
|
+
constructor() {
|
|
1003
|
+
// Effect to watch selectedStep and patch form when it changes
|
|
1004
|
+
effect(() => {
|
|
1005
|
+
const step = this.selectedStep();
|
|
1006
|
+
if (step) {
|
|
1007
|
+
// Patch form with complete step data
|
|
1008
|
+
this.nodeFormControl.patchValue({
|
|
1009
|
+
name: step.name,
|
|
1010
|
+
targetType: step.targetType || '1',
|
|
1011
|
+
group: step.targetType === '1' ? parseInt(step.targetValue) : null,
|
|
1012
|
+
role: step.targetType === '2' ? step.targetValue : null,
|
|
1013
|
+
sla: step.sla,
|
|
1014
|
+
});
|
|
1015
|
+
console.log('Form patched with step data:', step);
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
onNodeActionsEvent(event) {
|
|
1020
|
+
console.log('Node action event:', event);
|
|
1021
|
+
}
|
|
1022
|
+
clearForm() {
|
|
1023
|
+
// Reset isEditingInitialNode flag
|
|
1024
|
+
this.isEditingInitialNode.set(false);
|
|
1025
|
+
// Reset form to default values
|
|
1026
|
+
this.nodeFormControl.reset({
|
|
1027
|
+
name: { en: '', ar: '' },
|
|
1028
|
+
targetType: '1',
|
|
1029
|
+
group: null,
|
|
1030
|
+
role: null,
|
|
1031
|
+
sla: 0,
|
|
1032
|
+
});
|
|
1033
|
+
console.log('Form cleared for new step');
|
|
1034
|
+
}
|
|
1035
|
+
onStructureAction(event) {
|
|
1036
|
+
console.log('Structure action received:', event);
|
|
1037
|
+
switch (event.action) {
|
|
1038
|
+
case 'createNode':
|
|
1039
|
+
if (event.data) {
|
|
1040
|
+
// Get form values
|
|
1041
|
+
const formValue = this.nodeFormControl.value;
|
|
1042
|
+
// Prepare step payload without properties
|
|
1043
|
+
const stepPayload = {
|
|
1044
|
+
name: formValue.name || { en: 'New Step', ar: 'خطوة جديدة' },
|
|
1045
|
+
targetType: formValue.targetType,
|
|
1046
|
+
targetValue: formValue.targetType === '1' ? formValue.group : formValue.role,
|
|
1047
|
+
sla: formValue.sla || 0,
|
|
1048
|
+
};
|
|
1049
|
+
// Create step via facade
|
|
1050
|
+
this.escalationFacade.createStep(stepPayload).subscribe({
|
|
1051
|
+
next: () => {
|
|
1052
|
+
console.log('Step created successfully:', stepPayload);
|
|
1053
|
+
},
|
|
1054
|
+
error: (error) => {
|
|
1055
|
+
console.error('Failed to create step:', error);
|
|
1056
|
+
},
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
break;
|
|
1060
|
+
case 'startUpdating':
|
|
1061
|
+
if (event.data) {
|
|
1062
|
+
this.clearForm();
|
|
1063
|
+
const stepId = event.data.id;
|
|
1064
|
+
// Set the flag based on whether node is initial
|
|
1065
|
+
// This will trigger nodeForm to rebuild automatically via linkedSignal
|
|
1066
|
+
this.isEditingInitialNode.set(!!event.data.isInitial);
|
|
1067
|
+
// Load step data
|
|
1068
|
+
this.escalationFacade.loadStep(stepId);
|
|
1069
|
+
}
|
|
1070
|
+
break;
|
|
1071
|
+
case 'startCreating':
|
|
1072
|
+
// Reset form for new step
|
|
1073
|
+
this.clearForm();
|
|
1074
|
+
break;
|
|
1075
|
+
case 'updateNode':
|
|
1076
|
+
if (event.data) {
|
|
1077
|
+
// Get form values
|
|
1078
|
+
const formValue = this.nodeFormControl.value;
|
|
1079
|
+
const stepId = event.data.id;
|
|
1080
|
+
// Prepare step payload
|
|
1081
|
+
const stepPayload = {
|
|
1082
|
+
name: formValue.name || event.data.name,
|
|
1083
|
+
targetType: formValue.targetType,
|
|
1084
|
+
targetValue: formValue.targetType === '1' ? formValue.group : formValue.role,
|
|
1085
|
+
sla: formValue.sla || event.data.sla,
|
|
1086
|
+
};
|
|
1087
|
+
// Update step via facade
|
|
1088
|
+
this.escalationFacade.updateStep(stepId, stepPayload).subscribe({
|
|
1089
|
+
next: () => {
|
|
1090
|
+
console.log('Step updated successfully:', stepPayload);
|
|
1091
|
+
},
|
|
1092
|
+
error: (error) => {
|
|
1093
|
+
console.error('Failed to update step:', error);
|
|
1094
|
+
},
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
break;
|
|
1098
|
+
case 'deleteNode':
|
|
1099
|
+
if (event.data) {
|
|
1100
|
+
const nodeIdToDelete = event.data.id;
|
|
1101
|
+
// Delete step from store
|
|
1102
|
+
this.escalationFacade.deleteStep(nodeIdToDelete).subscribe({
|
|
1103
|
+
next: () => {
|
|
1104
|
+
console.log('Node deleted:', nodeIdToDelete);
|
|
1105
|
+
},
|
|
1106
|
+
error: (error) => {
|
|
1107
|
+
console.error('Failed to delete node:', error);
|
|
1108
|
+
},
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
break;
|
|
1112
|
+
case 'createConnection':
|
|
1113
|
+
if (event.data) {
|
|
1114
|
+
// Create connection in store
|
|
1115
|
+
const connectionPayload = {
|
|
1116
|
+
sourceStepId: event.data.from,
|
|
1117
|
+
targetStepId: event.data.to,
|
|
1118
|
+
priority: event.data.priority ?? 1,
|
|
1119
|
+
formula: event.data.formula ?? [],
|
|
1120
|
+
};
|
|
1121
|
+
this.escalationFacade.createConnection(connectionPayload).subscribe({
|
|
1122
|
+
next: () => {
|
|
1123
|
+
console.log('Connection created:', event.data);
|
|
1124
|
+
},
|
|
1125
|
+
error: (error) => {
|
|
1126
|
+
console.error('Failed to create connection:', error);
|
|
1127
|
+
},
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
break;
|
|
1131
|
+
case 'updateConnection':
|
|
1132
|
+
if (event.data) {
|
|
1133
|
+
// Update connection in store
|
|
1134
|
+
const connectionId = event.data.id;
|
|
1135
|
+
const updatePayload = {
|
|
1136
|
+
sourceStepId: event.data.from,
|
|
1137
|
+
targetStepId: event.data.to,
|
|
1138
|
+
priority: event.data.priority ?? 1,
|
|
1139
|
+
formula: event.data.formula ?? [],
|
|
1140
|
+
};
|
|
1141
|
+
this.escalationFacade
|
|
1142
|
+
.updateConnection(connectionId, updatePayload)
|
|
1143
|
+
.subscribe({
|
|
1144
|
+
next: () => {
|
|
1145
|
+
console.log('Connection updated:', event.data);
|
|
1146
|
+
},
|
|
1147
|
+
error: (error) => {
|
|
1148
|
+
console.error('Failed to update connection:', error);
|
|
1149
|
+
},
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
break;
|
|
1153
|
+
case 'deleteConnection':
|
|
1154
|
+
if (event.data) {
|
|
1155
|
+
const connectionIdToDelete = event.data.id;
|
|
1156
|
+
// Delete connection from store
|
|
1157
|
+
this.escalationFacade
|
|
1158
|
+
.deleteConnection(connectionIdToDelete)
|
|
1159
|
+
.subscribe({
|
|
1160
|
+
next: () => {
|
|
1161
|
+
console.log('Connection deleted:', connectionIdToDelete);
|
|
1162
|
+
},
|
|
1163
|
+
error: (error) => {
|
|
1164
|
+
console.error('Failed to delete connection:', error);
|
|
1165
|
+
},
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
break;
|
|
1169
|
+
default:
|
|
1170
|
+
console.warn('Unknown structure action:', event.action);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EscalationBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1174
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: EscalationBuilder, isStandalone: true, selector: "mt-escalation-builder", ngImport: i0, template: "<mt-card class=\"h-[calc(100vh---spacing(26))] relative\" id=\"escalationCard\">\n @if (!loading()) {\n <mt-structure-builder\n class=\"flex-1\"\n [availableNodes]=\"availableNodes\"\n [connectionForm]=\"connectionForm()\"\n [nodeActions]=\"nodeActions()\"\n (nodeActionsEvent)=\"onNodeActionsEvent($event)\"\n [nodes]=\"steps()\"\n [connections]=\"connections()\"\n (action)=\"onStructureAction($event)\"\n [addModalType]=\"'drawer'\"\n [addModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\n [updateModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\n [addModalHeader]=\"'Add Step'\"\n [updateModalHeader]=\"'Edit Step'\"\n [appendTo]=\"'escalationCard'\"\n [nodeFields]=\"nodeFields()\"\n >\n <ng-template\n #nodeDialog\n let-close=\"close\"\n let-save=\"save\"\n let-node=\"node\"\n >\n <div class=\"p-4\">\n @if (loadingStep()) {\n <!-- Loading skeleton -->\n <div class=\"space-y-4\">\n <!-- Form fields skeleton -->\n <div class=\"space-y-4\">\n <div>\n <p-skeleton\n width=\"8rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"2.5rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n <div>\n <p-skeleton\n width=\"8rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"2.5rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n <div>\n <p-skeleton\n width=\"10rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"3rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n <div>\n <p-skeleton\n width=\"6rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"2.5rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n <div>\n <p-skeleton\n width=\"4rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"2.5rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n </div>\n </div>\n } @else {\n <!-- Actual content - just the form, no tabs -->\n <mt-dynamic-form\n [formConfig]=\"nodeForm()\"\n [formControl]=\"nodeFormControl\"\n ></mt-dynamic-form>\n }\n </div>\n </ng-template>\n </mt-structure-builder>\n }\n</mt-card>\n", dependencies: [{ kind: "component", type: StructureBuilder, selector: "mt-structure-builder", inputs: ["availableNodes", "nodeForm", "connectionForm", "nodeActions", "nodeFields", "isAutoLayout", "addModalType", "updateModalType", "addModalStyleClass", "updateModalStyleClass", "addModalHeader", "updateModalHeader", "appendTo", "nodes", "connections"], outputs: ["nodeActionsEvent", "action", "nodesChange", "connectionsChange"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }] });
|
|
1175
|
+
}
|
|
1176
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EscalationBuilder, decorators: [{
|
|
1177
|
+
type: Component,
|
|
1178
|
+
args: [{ selector: 'mt-escalation-builder', imports: [StructureBuilder, Card, ReactiveFormsModule, DynamicForm, Skeleton], host: {}, template: "<mt-card class=\"h-[calc(100vh---spacing(26))] relative\" id=\"escalationCard\">\n @if (!loading()) {\n <mt-structure-builder\n class=\"flex-1\"\n [availableNodes]=\"availableNodes\"\n [connectionForm]=\"connectionForm()\"\n [nodeActions]=\"nodeActions()\"\n (nodeActionsEvent)=\"onNodeActionsEvent($event)\"\n [nodes]=\"steps()\"\n [connections]=\"connections()\"\n (action)=\"onStructureAction($event)\"\n [addModalType]=\"'drawer'\"\n [addModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\n [updateModalStyleClass]=\"'!w-[25rem] !absolute !shadow-none'\"\n [addModalHeader]=\"'Add Step'\"\n [updateModalHeader]=\"'Edit Step'\"\n [appendTo]=\"'escalationCard'\"\n [nodeFields]=\"nodeFields()\"\n >\n <ng-template\n #nodeDialog\n let-close=\"close\"\n let-save=\"save\"\n let-node=\"node\"\n >\n <div class=\"p-4\">\n @if (loadingStep()) {\n <!-- Loading skeleton -->\n <div class=\"space-y-4\">\n <!-- Form fields skeleton -->\n <div class=\"space-y-4\">\n <div>\n <p-skeleton\n width=\"8rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"2.5rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n <div>\n <p-skeleton\n width=\"8rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"2.5rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n <div>\n <p-skeleton\n width=\"10rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"3rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n <div>\n <p-skeleton\n width=\"6rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"2.5rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n <div>\n <p-skeleton\n width=\"4rem\"\n height=\"1rem\"\n styleClass=\"mb-2\"\n ></p-skeleton>\n <p-skeleton\n width=\"100%\"\n height=\"2.5rem\"\n borderRadius=\"0.5rem\"\n ></p-skeleton>\n </div>\n </div>\n </div>\n } @else {\n <!-- Actual content - just the form, no tabs -->\n <mt-dynamic-form\n [formConfig]=\"nodeForm()\"\n [formControl]=\"nodeFormControl\"\n ></mt-dynamic-form>\n }\n </div>\n </ng-template>\n </mt-structure-builder>\n }\n</mt-card>\n" }]
|
|
1179
|
+
}], ctorParameters: () => [] });
|
|
1180
|
+
|
|
1181
|
+
const ESCALATION_STATES = [EscalationState];
|
|
1182
|
+
|
|
1183
|
+
// Re-export app state
|
|
1184
|
+
|
|
1185
|
+
/**
|
|
1186
|
+
* Generated bundle index. Do not edit.
|
|
1187
|
+
*/
|
|
1188
|
+
|
|
1189
|
+
export { CreateConnection, CreateStep, DeleteConnection, DeleteStep, ESCALATION_STATES, EscalationBuilder, EscalationFacade, EscalationState, GetEscalation, GetFormulaProperties, GetGroups, GetRolesForModule, GetStep, PublishEscalation, SetModuleInfo, UpdateConnection, UpdateStep, ValidateFlow };
|
|
1190
|
+
//# sourceMappingURL=masterteam-escalation.mjs.map
|