@masterteam/work-center 0.0.83 → 0.0.85

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.
@@ -0,0 +1,538 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { HttpClient } from '@angular/common/http';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, input, computed, signal, effect, untracked, Component } from '@angular/core';
5
+ import { TranslocoService } from '@jsverse/transloco';
6
+ import { Table } from '@masterteam/components/table';
7
+ import { StructureBuilder } from '@masterteam/structure-builder';
8
+
9
+ /**
10
+ * Approval-history row projection for the process preview.
11
+ *
12
+ * The runtime stores one `step` record per *target user*, so a group step
13
+ * fans out into one record per member, and every workflow attempt (return →
14
+ * resubmit) creates a fresh fan-out for the same step schema. The table shows
15
+ * one row per attempt: sibling member records collapse, but separate attempts
16
+ * — and the completed history they carry — are preserved.
17
+ */
18
+ const PENDING$1 = 'pending';
19
+ const TERMINATED = 'terminated';
20
+ /** Statuses whose actor is not the assigned group/role, so the actor wins. */
21
+ const ACTOR_OVERRIDES_TARGET = new Set([TERMINATED]);
22
+ function buildApprovalRows(steps, options) {
23
+ const { resolveDisplayName } = options;
24
+ const currentIds = new Set((options.currentStepIds ?? []).map((id) => String(id)));
25
+ const rows = [];
26
+ for (const run of splitIntoRuns(steps)) {
27
+ const groupName = resolveGroupName(run[0].target, resolveDisplayName);
28
+ if (groupName) {
29
+ rows.push(buildGroupRow(run, groupName, currentIds, resolveDisplayName));
30
+ continue;
31
+ }
32
+ // Non-group targets keep one row per record, minus the pending siblings
33
+ // that were superseded when another member of the same fan-out acted.
34
+ const runHasAction = run.some(hasAction);
35
+ for (const step of run) {
36
+ if (runHasAction &&
37
+ run.length > 1 &&
38
+ isSupersededPending(step, currentIds)) {
39
+ continue;
40
+ }
41
+ rows.push({
42
+ stepName: resolveStepName(step, resolveDisplayName),
43
+ status: step.status,
44
+ user: {
45
+ kind: 'user',
46
+ value: step.actionUserInfo ?? step.targetUser ?? null,
47
+ },
48
+ createdAt: step.createdAt ?? '',
49
+ actionDate: step.actionDate ?? '',
50
+ });
51
+ }
52
+ }
53
+ return rows;
54
+ }
55
+ function buildGroupRow(run, groupName, currentIds, resolveDisplayName) {
56
+ const pendingOnGroup = run.find((step) => isCurrent(step, currentIds));
57
+ // While the attempt is open the row belongs to the group as a whole; once it
58
+ // closes, the record that carries the outcome represents it.
59
+ const repr = pendingOnGroup ?? resolveOutcome(run);
60
+ const actor = repr.actionUserInfo;
61
+ const showActor = !pendingOnGroup && !!actor && ACTOR_OVERRIDES_TARGET.has(statusKey(repr));
62
+ return {
63
+ stepName: resolveStepName(repr, resolveDisplayName),
64
+ status: repr.status,
65
+ user: showActor
66
+ ? { kind: 'user', value: actor }
67
+ : { kind: 'text', value: groupName },
68
+ createdAt: run[0].createdAt ?? '',
69
+ actionDate: pendingOnGroup ? '' : (repr.actionDate ?? ''),
70
+ };
71
+ }
72
+ /**
73
+ * Consecutive records sharing a step schema + target belong to the same
74
+ * attempt. The API orders steps by creation, so a later attempt on the same
75
+ * step is always separated by the records that sent the request back.
76
+ */
77
+ function splitIntoRuns(steps) {
78
+ const runs = [];
79
+ let currentKey = null;
80
+ for (const step of steps) {
81
+ const key = runKey(step);
82
+ if (key !== currentKey || runs.length === 0) {
83
+ runs.push([step]);
84
+ currentKey = key;
85
+ continue;
86
+ }
87
+ runs[runs.length - 1].push(step);
88
+ }
89
+ return runs;
90
+ }
91
+ function runKey(step) {
92
+ return `${step.stepSchemaId ?? ''}|${step.target?.groupKey ?? ''}`;
93
+ }
94
+ /** The record holding the attempt's outcome (Returned/Rejected/Terminated…). */
95
+ function resolveOutcome(run) {
96
+ for (let index = run.length - 1; index >= 0; index -= 1) {
97
+ const step = run[index];
98
+ if (statusKey(step) !== PENDING$1 && statusKey(step) !== '') {
99
+ return step;
100
+ }
101
+ }
102
+ return findLast(run, hasAction) ?? run[run.length - 1];
103
+ }
104
+ function isCurrent(step, currentIds) {
105
+ if (typeof step.isCurrent === 'boolean') {
106
+ return step.isCurrent;
107
+ }
108
+ if (currentIds.size > 0) {
109
+ return currentIds.has(String(step.stepId ?? ''));
110
+ }
111
+ return step.isActive !== false && statusKey(step) === PENDING$1;
112
+ }
113
+ /** A pending record left behind after a sibling acted — never actionable. */
114
+ function isSupersededPending(step, currentIds) {
115
+ return (statusKey(step) === PENDING$1 &&
116
+ !hasAction(step) &&
117
+ !isCurrent(step, currentIds));
118
+ }
119
+ function hasAction(step) {
120
+ if (step.actionUserInfo) {
121
+ return true;
122
+ }
123
+ const key = statusKey(step);
124
+ return key !== '' && key !== PENDING$1;
125
+ }
126
+ /** Status comes off the lookup key, never the localized display text. */
127
+ function statusKey(step) {
128
+ const status = step.status;
129
+ if (typeof status === 'string') {
130
+ return status.trim().toLowerCase();
131
+ }
132
+ if (status && typeof status === 'object') {
133
+ const key = status['key'];
134
+ if (typeof key === 'string') {
135
+ return key.trim().toLowerCase();
136
+ }
137
+ }
138
+ return '';
139
+ }
140
+ function resolveStepName(step, resolveDisplayName) {
141
+ return resolveDisplayName(step.stepName) || String(step.stepId ?? '--');
142
+ }
143
+ function resolveGroupName(target, resolveDisplayName) {
144
+ if (!target || target.type !== 'Group' || !target.group) {
145
+ return '';
146
+ }
147
+ return (resolveDisplayName(target.displayName) ||
148
+ resolveDisplayName(target.group.name));
149
+ }
150
+ function findLast(items, predicate) {
151
+ for (let index = items.length - 1; index >= 0; index -= 1) {
152
+ if (predicate(items[index])) {
153
+ return items[index];
154
+ }
155
+ }
156
+ return undefined;
157
+ }
158
+
159
+ /**
160
+ * Status projection for the process-preview diagram.
161
+ *
162
+ * The schema view colors every step by where it stands in the run — the icon
163
+ * and subtitle already say what *kind* of step it is, so color is free to
164
+ * carry progress. One color per state, reusing the workflow badge tones from
165
+ * `@masterteam/structure-builder`.
166
+ *
167
+ * The runtime stores one `step` record per target user, so a group step fans
168
+ * out into several records and every attempt (return → resubmit) creates a
169
+ * fresh fan-out. A schema node shows the state of its *latest* attempt.
170
+ */
171
+ /** Node accent color per state — every outcome gets its own hue. */
172
+ const PROCESS_STEP_STATUS_COLORS = {
173
+ approved: '#059669', // green — approved
174
+ current: '#d97706', // amber — running right now
175
+ noAction: '#0891b2', // cyan — closed without a decision from this target
176
+ notStarted: '#2563eb', // blue — not reached yet
177
+ rejected: '#dc2626', // red — rejected
178
+ resubmitted: '#7c3aed', // violet — sent back, then pushed forward again
179
+ returned: '#6b7280', // gray — sent back
180
+ terminated: '#334155', // slate — the run was killed outright
181
+ };
182
+ /**
183
+ * `NodeBadgeTone` per state, so the pill matches the node color. The tones the
184
+ * structure-builder names cover the original five; the rest use `accent`, which
185
+ * has no tone rule of its own and therefore inherits the node color exactly.
186
+ */
187
+ const PROCESS_STEP_STATUS_BADGE_TONES = {
188
+ approved: 'final',
189
+ current: 'current',
190
+ noAction: 'accent',
191
+ notStarted: 'initial',
192
+ rejected: 'closed',
193
+ resubmitted: 'accent',
194
+ returned: 'neutral',
195
+ terminated: 'accent',
196
+ };
197
+ const PENDING = 'pending';
198
+ const CURRENT_VIEW = { status: 'current', label: '' };
199
+ const NOT_STARTED_VIEW = {
200
+ status: 'notStarted',
201
+ label: '',
202
+ };
203
+ /**
204
+ * Decided status keys → visual state. A decided status that isn't listed reads
205
+ * as `noAction` — it closed, but not by a decision we can name, so the color
206
+ * must not claim one. The badge still shows the backend's own wording.
207
+ */
208
+ const DECIDED_STATUS_STATES = {
209
+ approved: 'approved',
210
+ noaction: 'noAction',
211
+ rejected: 'rejected',
212
+ resubmitted: 'resubmitted',
213
+ returned: 'returned',
214
+ terminated: 'terminated',
215
+ };
216
+ const UNCLASSIFIED_DECIDED_STATE = 'noAction';
217
+ /**
218
+ * Inside one attempt the strongest outcome represents the step, so a group
219
+ * fan-out where one member rejected reads as rejected while the siblings who
220
+ * never acted read as `noAction`.
221
+ */
222
+ const OUTCOME_PRECEDENCE = [
223
+ 'terminated',
224
+ 'rejected',
225
+ 'returned',
226
+ 'resubmitted',
227
+ 'approved',
228
+ 'noAction',
229
+ ];
230
+ /**
231
+ * Maps every schema-step id the runtime has touched to its visual state.
232
+ * Steps missing from the result were never reached — render them as
233
+ * {@link NOT_STARTED_VIEW}.
234
+ */
235
+ function buildSchemaStepStatuses(steps, options) {
236
+ const currentIds = new Set((options.currentSchemaIds ?? []).map((id) => String(id)));
237
+ const views = new Map();
238
+ // Later attempts overwrite earlier ones, so the last run on a step wins.
239
+ for (const run of splitBySchemaStep(steps)) {
240
+ const schemaId = String(run[0].stepSchemaId ?? '');
241
+ if (!schemaId) {
242
+ continue;
243
+ }
244
+ views.set(schemaId, resolveRunStatus(run, currentIds, options));
245
+ }
246
+ // A step can be current before any record closes — the flag always wins.
247
+ for (const id of currentIds) {
248
+ views.set(id, CURRENT_VIEW);
249
+ }
250
+ return views;
251
+ }
252
+ /**
253
+ * Reads a state straight off a schema step's own `status`, for schemas that
254
+ * carry it without a matching runtime record.
255
+ */
256
+ function resolveStatusView(status, resolveDisplayName) {
257
+ const key = normalizeStatusKey(status);
258
+ if (key === '' || key === PENDING) {
259
+ return NOT_STARTED_VIEW;
260
+ }
261
+ return {
262
+ status: DECIDED_STATUS_STATES[key] ?? UNCLASSIFIED_DECIDED_STATE,
263
+ label: resolveStatusLabel(status, resolveDisplayName),
264
+ };
265
+ }
266
+ function resolveRunStatus(run, currentIds, options) {
267
+ if (currentIds.has(String(run[0].stepSchemaId ?? '')) ||
268
+ run.some((step) => step.isCurrent === true)) {
269
+ return CURRENT_VIEW;
270
+ }
271
+ const decided = run
272
+ .map((step) => ({ step, state: decidedState(step) }))
273
+ .filter((entry) => entry.state !== null);
274
+ if (decided.length === 0) {
275
+ return NOT_STARTED_VIEW;
276
+ }
277
+ const outcome = OUTCOME_PRECEDENCE.map((state) => decided.find((entry) => entry.state === state)).find((entry) => !!entry) ?? decided[decided.length - 1];
278
+ return {
279
+ status: outcome.state,
280
+ label: resolveStatusLabel(outcome.step.status, options.resolveDisplayName),
281
+ };
282
+ }
283
+ function decidedState(step) {
284
+ const key = statusKey(step);
285
+ if (key === '' || key === PENDING) {
286
+ return null;
287
+ }
288
+ return DECIDED_STATUS_STATES[key] ?? UNCLASSIFIED_DECIDED_STATE;
289
+ }
290
+ /**
291
+ * Consecutive records sharing a schema step belong to the same attempt. The
292
+ * API orders steps by creation, so a later attempt is always separated by the
293
+ * records that sent the request back.
294
+ */
295
+ function splitBySchemaStep(steps) {
296
+ const runs = [];
297
+ let currentKey = null;
298
+ for (const step of steps) {
299
+ const key = String(step.stepSchemaId ?? '');
300
+ if (key !== currentKey || runs.length === 0) {
301
+ runs.push([step]);
302
+ currentKey = key;
303
+ continue;
304
+ }
305
+ runs[runs.length - 1].push(step);
306
+ }
307
+ return runs;
308
+ }
309
+ /** Status comes off the lookup key, never the localized display text. */
310
+ function normalizeStatusKey(status) {
311
+ if (typeof status === 'string') {
312
+ return status.trim().toLowerCase();
313
+ }
314
+ if (status && typeof status === 'object') {
315
+ const key = status['key'];
316
+ if (typeof key === 'string') {
317
+ return key.trim().toLowerCase();
318
+ }
319
+ }
320
+ return '';
321
+ }
322
+ function resolveStatusLabel(status, resolveDisplayName) {
323
+ return typeof status === 'string' ? status : resolveDisplayName(status);
324
+ }
325
+
326
+ class WorkCenterProcessPreview {
327
+ http = inject(HttpClient);
328
+ transloco = inject(TranslocoService);
329
+ loadSub;
330
+ requestId = input(null, ...(ngDevMode ? [{ debugName: "requestId" }] : /* istanbul ignore next */ []));
331
+ view = input('approvals', ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
332
+ approvalColumns = computed(() => [
333
+ {
334
+ key: 'stepName',
335
+ label: this.transloco.translate('workCenter.preview.name'),
336
+ },
337
+ {
338
+ key: 'status',
339
+ label: this.transloco.translate('workCenter.preview.status'),
340
+ type: 'entity',
341
+ },
342
+ {
343
+ key: 'user',
344
+ label: this.transloco.translate('workCenter.preview.userOrGroup'),
345
+ type: 'entity',
346
+ },
347
+ {
348
+ key: 'createdAt',
349
+ label: this.transloco.translate('workCenter.preview.initiationDate'),
350
+ type: 'entity',
351
+ },
352
+ {
353
+ key: 'actionDate',
354
+ label: this.transloco.translate('workCenter.preview.actionDate'),
355
+ type: 'entity',
356
+ },
357
+ ], ...(ngDevMode ? [{ debugName: "approvalColumns" }] : /* istanbul ignore next */ []));
358
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
359
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
360
+ preview = signal(null, ...(ngDevMode ? [{ debugName: "preview" }] : /* istanbul ignore next */ []));
361
+ canRenderPreview = computed(() => (this.requestId() ?? 0) > 0, ...(ngDevMode ? [{ debugName: "canRenderPreview" }] : /* istanbul ignore next */ []));
362
+ approvalRows = computed(() => {
363
+ const preview = this.preview();
364
+ const rows = buildApprovalRows(preview?.steps ?? [], {
365
+ currentStepIds: preview?.currentStepIds,
366
+ resolveDisplayName: (value) => this.resolveDisplayName(value),
367
+ });
368
+ return rows.map((row) => ({
369
+ stepName: row.stepName,
370
+ status: buildEntity('Status', 'Status', row.status),
371
+ user: row.user.kind === 'text'
372
+ ? buildEntity('User', 'Text', row.user.value)
373
+ : buildEntity('User', 'User', row.user.value),
374
+ createdAt: buildEntity('Initiation Date', 'DateTime', row.createdAt),
375
+ actionDate: buildEntity('Action Date', 'DateTime', row.actionDate),
376
+ }));
377
+ }, ...(ngDevMode ? [{ debugName: "approvalRows" }] : /* istanbul ignore next */ []));
378
+ hasApprovals = computed(() => this.approvalRows().length > 0, ...(ngDevMode ? [{ debugName: "hasApprovals" }] : /* istanbul ignore next */ []));
379
+ schemaNodes = computed(() => {
380
+ const preview = this.preview();
381
+ const steps = preview?.schema?.stepsSchema ?? [];
382
+ const connections = preview?.schema?.connections ?? [];
383
+ const sourceIds = new Set(connections.map((c) => String(c.source)));
384
+ // Where each step stands in the run — the color of a node is its state,
385
+ // not its type (the icon and subtitle already carry the type).
386
+ const statusViews = buildSchemaStepStatuses(preview?.steps ?? [], {
387
+ currentSchemaIds: preview?.currentStepSchemaIds,
388
+ resolveDisplayName: (value) => this.resolveDisplayName(value),
389
+ });
390
+ return steps.map((step) => {
391
+ const isAppAction = step.type === 'AppAction';
392
+ const isApprovalCommit = step.type === 'ApprovalCommit' || step.systemKind === 'ApprovalCommit';
393
+ // Treat a step as final if explicitly flagged or if it has no outgoing
394
+ // connection — the latter catches schemas where `isFinal` isn't set.
395
+ const isFinal = !isApprovalCommit &&
396
+ (step.isFinal === true || !sourceIds.has(String(step.id)));
397
+ const stepStatus = statusViews.get(String(step.id)) ??
398
+ resolveStatusView(step.status, (value) => this.resolveDisplayName(value));
399
+ const isCurrent = stepStatus.status === 'current';
400
+ return {
401
+ id: String(step.id),
402
+ name: isFinal
403
+ ? this.transloco.translate('workCenter.preview.end')
404
+ : this.resolveDisplayName(step.name) || String(step.id),
405
+ color: PROCESS_STEP_STATUS_COLORS[stepStatus.status],
406
+ icon: isApprovalCommit
407
+ ? 'general.check-verified-01'
408
+ : isAppAction
409
+ ? 'general.zap'
410
+ : isFinal
411
+ ? 'map.flag-04'
412
+ : step.isInitial
413
+ ? 'map.flag-04'
414
+ : 'file.clipboard-check',
415
+ subtitle: isApprovalCommit
416
+ ? this.transloco.translate('workCenter.preview.approvalCommitSubtitle')
417
+ : step.isInitial
418
+ ? this.transloco.translate('workCenter.preview.start')
419
+ : isFinal
420
+ ? this.transloco.translate('workCenter.preview.end')
421
+ : isAppAction
422
+ ? this.transloco.translate('workCenter.preview.appAction')
423
+ : this.transloco.translate('workCenter.preview.formStep'),
424
+ // The badge names the state the color stands for, preferring the
425
+ // backend's own wording. The current step keeps the built-in
426
+ // "Current" pill instead of a second badge.
427
+ badge: isCurrent
428
+ ? null
429
+ : stepStatus.label ||
430
+ this.transloco.translate(`workCenter.preview.stepStatus.${stepStatus.status}`),
431
+ // Semantic color for the badge — every step state renders with the
432
+ // same pill and is told apart by color alone.
433
+ badgeTone: PROCESS_STEP_STATUS_BADGE_TONES[stepStatus.status],
434
+ status: step.status ?? null,
435
+ style: isAppAction || isApprovalCommit ? 'icon' : 'detail',
436
+ current: isCurrent,
437
+ };
438
+ });
439
+ }, ...(ngDevMode ? [{ debugName: "schemaNodes" }] : /* istanbul ignore next */ []));
440
+ schemaConnections = computed(() => (this.preview()?.schema?.connections ?? []).map((connection, index) => ({
441
+ id: String(connection.id ?? `${connection.source}-${connection.target}-${index}`),
442
+ from: String(connection.source),
443
+ to: String(connection.target),
444
+ state: connection.state,
445
+ })), ...(ngDevMode ? [{ debugName: "schemaConnections" }] : /* istanbul ignore next */ []));
446
+ hasSchema = computed(() => this.schemaNodes().length > 0, ...(ngDevMode ? [{ debugName: "hasSchema" }] : /* istanbul ignore next */ []));
447
+ previewNodeFields = {
448
+ id: 'id',
449
+ name: 'name',
450
+ icon: 'icon',
451
+ color: 'color',
452
+ subtitle: 'subtitle',
453
+ badge: 'badge',
454
+ badgeTone: 'badgeTone',
455
+ status: 'status',
456
+ style: 'style',
457
+ current: 'current',
458
+ };
459
+ constructor() {
460
+ effect(() => {
461
+ const requestId = this.requestId() ?? 0;
462
+ if (requestId > 0) {
463
+ untracked(() => this.loadPreview(requestId));
464
+ return;
465
+ }
466
+ this.loadSub?.unsubscribe();
467
+ this.loading.set(false);
468
+ this.error.set(null);
469
+ this.preview.set(null);
470
+ });
471
+ }
472
+ ngOnDestroy() {
473
+ this.loadSub?.unsubscribe();
474
+ }
475
+ resolveDisplayName(name) {
476
+ if (typeof name === 'string') {
477
+ return name;
478
+ }
479
+ if (typeof name === 'number' || typeof name === 'boolean') {
480
+ return String(name);
481
+ }
482
+ if (!name || typeof name !== 'object') {
483
+ return '';
484
+ }
485
+ const map = name;
486
+ const locale = this.transloco.getActiveLang();
487
+ const candidates = [map['display'], map[locale], map['en'], map['ar']];
488
+ for (const candidate of candidates) {
489
+ if (typeof candidate === 'string' && candidate) {
490
+ return candidate;
491
+ }
492
+ if (typeof candidate === 'number' || typeof candidate === 'boolean') {
493
+ return String(candidate);
494
+ }
495
+ }
496
+ const fallback = Object.values(map).find((value) => typeof value === 'string' && value);
497
+ return typeof fallback === 'string' ? fallback : '';
498
+ }
499
+ loadPreview(requestId) {
500
+ this.loadSub?.unsubscribe();
501
+ this.loading.set(true);
502
+ this.error.set(null);
503
+ this.loadSub = this.http
504
+ .get(`processes/${requestId}/preview`)
505
+ .subscribe({
506
+ next: (response) => {
507
+ this.loading.set(false);
508
+ this.preview.set(response.data ?? null);
509
+ },
510
+ error: (error) => {
511
+ this.loading.set(false);
512
+ this.preview.set(null);
513
+ this.error.set(error?.error?.message ??
514
+ error?.message ??
515
+ this.transloco.translate('workCenter.preview.loadFailed'));
516
+ },
517
+ });
518
+ }
519
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterProcessPreview, deps: [], target: i0.ɵɵFactoryTarget.Component });
520
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterProcessPreview, isStandalone: true, selector: "mt-work-center-process-preview", inputs: { requestId: { classPropertyName: "requestId", publicName: "requestId", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!canRenderPreview()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process preview is not available for this item yet.\r\n </p>\r\n </div>\r\n} @else if (loading()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"text-sm text-surface-500\">Loading process preview...</p>\r\n </div>\r\n} @else if (error()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-red-300 bg-red-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-red-600\">{{ error() }}</p>\r\n </div>\r\n} @else {\r\n @if (view() === \"schema\") {\r\n @if (hasSchema()) {\r\n <div class=\"wc-process-preview-schema h-[70vh] overflow-hidden\">\r\n <mt-structure-builder\r\n class=\"h-full\"\r\n [layoutDirection]=\"'LR'\"\r\n [readonly]=\"true\"\r\n [structureMode]=\"'workflow'\"\r\n [nodeFields]=\"previewNodeFields\"\r\n [nodes]=\"schemaNodes()\"\r\n [connections]=\"schemaConnections()\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process steps are not available for this item yet.\r\n </p>\r\n </div>\r\n }\r\n } @else if (hasApprovals()) {\r\n <div class=\"max-h-[70vh] overflow-y-auto\">\r\n <mt-table\r\n noCard\r\n [data]=\"approvalRows()\"\r\n [columns]=\"approvalColumns()\"\r\n storageKey=\"work-center-process-preview-table\"\r\n [showFilters]=\"false\"\r\n [generalSearch]=\"false\"\r\n [clickableRows]=\"false\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process approvals data is not available for this item yet.\r\n </p>\r\n </div>\r\n }\r\n}\r\n", styles: [":host ::ng-deep .wc-process-preview-schema .wf-detail-row{align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "filterMode", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "persistStateExclude", "exportable", "printable", "groupable", "groupCountMap", "cellClickFilter", "freezeActions", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "captionStartTemplate", "captionEndTemplate", "emptyTitle", "emptyDescription", "emptyActionLabel", "emptyActionIcon", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy", "sortField", "sortDirection"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "emptyAction", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange", "sortFieldChange", "sortDirectionChange"] }, { kind: "component", type: StructureBuilder, selector: "mt-structure-builder", inputs: ["availableNodes", "availableNodesLabel", "nodeForm", "nodeDialogFooterConfig", "connectionForm", "connectionFormulaSchemaId", "connectionFormulaConfig", "connectionGuard", "nodeActions", "nodeFields", "isAutoLayout", "readonly", "structureMode", "nodeStyle", "addModalType", "updateModalType", "addModalStyleClass", "updateModalStyleClass", "addModalHeader", "updateModalHeader", "appendTo", "availableTabsClass", "layoutDirection", "nodes", "connections", "nodeTemplate"], outputs: ["nodeActionsEvent", "action", "nodesChange", "connectionsChange"] }] });
521
+ }
522
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterProcessPreview, decorators: [{
523
+ type: Component,
524
+ args: [{ selector: 'mt-work-center-process-preview', standalone: true, imports: [CommonModule, Table, StructureBuilder], template: "@if (!canRenderPreview()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process preview is not available for this item yet.\r\n </p>\r\n </div>\r\n} @else if (loading()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"text-sm text-surface-500\">Loading process preview...</p>\r\n </div>\r\n} @else if (error()) {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-red-300 bg-red-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-red-600\">{{ error() }}</p>\r\n </div>\r\n} @else {\r\n @if (view() === \"schema\") {\r\n @if (hasSchema()) {\r\n <div class=\"wc-process-preview-schema h-[70vh] overflow-hidden\">\r\n <mt-structure-builder\r\n class=\"h-full\"\r\n [layoutDirection]=\"'LR'\"\r\n [readonly]=\"true\"\r\n [structureMode]=\"'workflow'\"\r\n [nodeFields]=\"previewNodeFields\"\r\n [nodes]=\"schemaNodes()\"\r\n [connections]=\"schemaConnections()\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process steps are not available for this item yet.\r\n </p>\r\n </div>\r\n }\r\n } @else if (hasApprovals()) {\r\n <div class=\"max-h-[70vh] overflow-y-auto\">\r\n <mt-table\r\n noCard\r\n [data]=\"approvalRows()\"\r\n [columns]=\"approvalColumns()\"\r\n storageKey=\"work-center-process-preview-table\"\r\n [showFilters]=\"false\"\r\n [generalSearch]=\"false\"\r\n [clickableRows]=\"false\"\r\n />\r\n </div>\r\n } @else {\r\n <div\r\n class=\"flex min-h-[22rem] items-center justify-center rounded-lg border border-dashed border-surface-300 bg-surface-50 p-6\"\r\n >\r\n <p class=\"max-w-md text-center text-sm text-surface-500\">\r\n Process approvals data is not available for this item yet.\r\n </p>\r\n </div>\r\n }\r\n}\r\n", styles: [":host ::ng-deep .wc-process-preview-schema .wf-detail-row{align-items:center}\n"] }]
525
+ }], ctorParameters: () => [], propDecorators: { requestId: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestId", required: false }] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }] } });
526
+ function buildEntity(name, viewType, value) {
527
+ return {
528
+ name,
529
+ viewType,
530
+ value: value ?? '',
531
+ configuration: {
532
+ hideName: true,
533
+ },
534
+ };
535
+ }
536
+
537
+ export { WorkCenterProcessPreview };
538
+ //# sourceMappingURL=masterteam-work-center-work-center-process-preview-qG9T9HoP.mjs.map