@masterteam/work-center 0.0.66 → 0.0.68

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.
@@ -19,7 +19,7 @@ import { ClientForm } from '@masterteam/forms/client-form';
19
19
  import { HttpClient } from '@angular/common/http';
20
20
  import { Router, ActivatedRoute } from '@angular/router';
21
21
  import { Drawer } from '@masterteam/components/drawer';
22
- import { RuntimeActionContextStore, RuntimeActionRunner, resolveActionLabel } from '@masterteam/components/runtime-action';
22
+ import { RuntimeActionContextStore, RuntimeActionRunner, RUNTIME_ACTION_CONFIRM_DIALOG, hasActionFormFields, buildActionPayload, resolveActionLabel } from '@masterteam/components/runtime-action';
23
23
  import { Action, Selector, State, Store, select } from '@ngxs/store';
24
24
  import { handleApiRequest } from '@masterteam/components';
25
25
  import { ClientInstancePreview } from '@masterteam/client-components/client-instance-preview';
@@ -27,6 +27,7 @@ import { EntitiesPreview } from '@masterteam/components/entities';
27
27
  import { Tabs } from '@masterteam/components/tabs';
28
28
  import { DiscussionThread } from '@masterteam/discussion';
29
29
  import { StructureBuilder } from '@masterteam/structure-builder';
30
+ import { ConfirmationService } from '@masterteam/components/confirmation';
30
31
 
31
32
  class WorkCenterClientFormModal {
32
33
  modal = inject(ModalService);
@@ -2350,14 +2351,281 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
2350
2351
  }, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\r\n @if (details().type === \"ProcessStep\") {\r\n <mt-work-center-process-step-type\r\n [details]=\"details()\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else if (details().type === \"ProcessRequest\") {\r\n <mt-work-center-process-request-type\r\n [details]=\"details()\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else if (details().type === \"EscalationInstance\") {\r\n <mt-work-center-escalation-instance-type\r\n [details]=\"details()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else if (details().type === \"Module\" || details().type === \"GeneralTask\") {\r\n <mt-work-center-module-type\r\n [details]=\"details()\"\r\n [lookups]=\"lookups()\"\r\n [readOnly]=\"readOnly()\"\r\n />\r\n } @else {\r\n <div class=\"mt-modal-content flex h-full items-center justify-center p-4\">\r\n <p class=\"text-sm text-surface-500\">{{ t(\"modal.unsupportedType\") }}</p>\r\n </div>\r\n }\r\n</ng-container>\r\n" }]
2351
2352
  }], propDecorators: { details: [{ type: i0.Input, args: [{ isSignal: true, alias: "details", required: true }] }], lookups: [{ type: i0.Input, args: [{ isSignal: true, alias: "lookups", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }] } });
2352
2353
 
2354
+ const FORM_VALIDATION_WARNINGS = 'FormValidationWarnings';
2355
+ /** Handles the process action validation handshake owned by Work Center. */
2356
+ class WorkCenterActionValidationHandler {
2357
+ confirmation = inject(ConfirmationService);
2358
+ runner = inject(RuntimeActionRunner);
2359
+ transloco = inject(TranslocoService);
2360
+ async recover(action, error, submittedPayload, defaultAfterSuccess) {
2361
+ const validationError = readProcessActionValidationError(error);
2362
+ if (validationError?.kind !== FORM_VALIDATION_WARNINGS ||
2363
+ !validationError.requiresAcknowledgement ||
2364
+ !validationError.validationWarningsToken) {
2365
+ return null;
2366
+ }
2367
+ const confirmed = await this.confirmWarnings(this.resolveValidationMessages(validationError));
2368
+ if (!confirmed) {
2369
+ return {
2370
+ status: 'cancelled',
2371
+ actionKey: action.actionKey,
2372
+ afterSuccess: null,
2373
+ };
2374
+ }
2375
+ const retryPayload = {
2376
+ ...(submittedPayload ?? {}),
2377
+ validationWarningsToken: validationError.validationWarningsToken,
2378
+ };
2379
+ // This descriptor is intentionally ephemeral. A later action rebuilds its
2380
+ // payload from the current form and therefore cannot reuse this token.
2381
+ return this.runner.execute({
2382
+ ...action,
2383
+ needConfirmation: false,
2384
+ payloadKeys: Object.keys(retryPayload),
2385
+ payloadTemplate: retryPayload,
2386
+ }, { defaultAfterSuccess, silent: true });
2387
+ }
2388
+ resolveErrorMessage(error, fallback) {
2389
+ const validationError = readProcessActionValidationError(error);
2390
+ if (validationError) {
2391
+ const messages = this.resolveValidationMessages(validationError);
2392
+ if (messages.length)
2393
+ return messages.join('\n');
2394
+ if (validationError.message)
2395
+ return validationError.message;
2396
+ }
2397
+ return readHttpErrorMessage(error) ?? fallback;
2398
+ }
2399
+ resolveValidationMessages(validationError) {
2400
+ const messages = [];
2401
+ const seen = new Set();
2402
+ for (const result of validationError.results) {
2403
+ if (result.passed === true && result.isEvaluationError !== true)
2404
+ continue;
2405
+ const message = resolveLocalizedText(result.message, this.transloco.getActiveLang()) ??
2406
+ readNonEmptyString(result.errorMessage);
2407
+ if (!message || seen.has(message))
2408
+ continue;
2409
+ seen.add(message);
2410
+ messages.push(message);
2411
+ }
2412
+ if (!messages.length && validationError.message) {
2413
+ messages.push(validationError.message);
2414
+ }
2415
+ return messages;
2416
+ }
2417
+ confirmWarnings(messages) {
2418
+ const warningLines = messages.map((message) => `• ${message}`).join('\n');
2419
+ const question = this.transloco.translate('workCenter.actions.validationWarningsQuestion');
2420
+ const message = warningLines ? `${warningLines}\n\n${question}` : question;
2421
+ return new Promise((resolve) => {
2422
+ let settled = false;
2423
+ const settle = (value) => {
2424
+ if (settled)
2425
+ return;
2426
+ settled = true;
2427
+ resolve(value);
2428
+ };
2429
+ this.confirmation.confirm({
2430
+ type: 'dialog',
2431
+ header: this.transloco.translate('workCenter.actions.validationWarningsHeader'),
2432
+ message,
2433
+ icon: 'alert.alert-triangle',
2434
+ acceptLabel: this.transloco.translate('workCenter.actions.acknowledgeAndContinue'),
2435
+ rejectLabel: this.transloco.translate('workCenter.modal.cancel'),
2436
+ acceptButton: { severity: 'warn' },
2437
+ rejectButton: { severity: 'secondary', variant: 'outlined' },
2438
+ accept: () => settle(true),
2439
+ reject: () => settle(false),
2440
+ });
2441
+ });
2442
+ }
2443
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionValidationHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2444
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionValidationHandler, providedIn: 'root' });
2445
+ }
2446
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterActionValidationHandler, decorators: [{
2447
+ type: Injectable,
2448
+ args: [{ providedIn: 'root' }]
2449
+ }] });
2450
+ function readProcessActionValidationError(error) {
2451
+ const body = readRecord(error)?.['error'] ?? error;
2452
+ const envelope = readRecord(body);
2453
+ const errors = readRecord(envelope?.['errors']);
2454
+ const details = readRecord(errors?.['details']);
2455
+ const kind = readNonEmptyString(details?.['kind']);
2456
+ if (!kind)
2457
+ return null;
2458
+ const validation = readRecord(details?.['validation']);
2459
+ const results = Array.isArray(validation?.['results'])
2460
+ ? validation['results']
2461
+ .map((result) => readRecord(result))
2462
+ .filter((result) => !!result)
2463
+ .map((result) => result)
2464
+ : [];
2465
+ return {
2466
+ kind,
2467
+ requiresAcknowledgement: details?.['requiresAcknowledgement'] === true,
2468
+ validationWarningsToken: readNonEmptyString(details?.['validationWarningsToken']),
2469
+ message: readNonEmptyString(errors?.['message']),
2470
+ results,
2471
+ };
2472
+ }
2473
+ function resolveLocalizedText(value, activeLang) {
2474
+ const direct = readNonEmptyString(value);
2475
+ if (direct)
2476
+ return direct;
2477
+ const record = readRecord(value);
2478
+ if (!record)
2479
+ return null;
2480
+ const normalizedLang = activeLang.trim();
2481
+ const baseLang = normalizedLang.split('-')[0];
2482
+ for (const candidate of [
2483
+ record[normalizedLang],
2484
+ record[baseLang],
2485
+ record['display'],
2486
+ record['en'],
2487
+ record['ar'],
2488
+ ]) {
2489
+ const text = readNonEmptyString(candidate);
2490
+ if (text)
2491
+ return text;
2492
+ }
2493
+ return null;
2494
+ }
2495
+ function readHttpErrorMessage(error) {
2496
+ const record = readRecord(error);
2497
+ const body = readRecord(record?.['error']);
2498
+ const errors = readRecord(body?.['errors']);
2499
+ return (readNonEmptyString(errors?.['message']) ??
2500
+ readNonEmptyString(body?.['message']) ??
2501
+ readNonEmptyString(record?.['message']));
2502
+ }
2503
+ function readRecord(value) {
2504
+ return value && typeof value === 'object'
2505
+ ? value
2506
+ : null;
2507
+ }
2508
+ function readNonEmptyString(value) {
2509
+ if (typeof value !== 'string')
2510
+ return null;
2511
+ const normalized = value.trim();
2512
+ return normalized.length ? normalized : null;
2513
+ }
2514
+
2515
+ /** Executes Work Center actions while preserving form payloads for validation retries. */
2516
+ class WorkCenterRuntimeActionExecutor {
2517
+ runner = inject(RuntimeActionRunner);
2518
+ actionContext = inject(RuntimeActionContextStore);
2519
+ modal = inject(ModalService);
2520
+ validation = inject(WorkCenterActionValidationHandler);
2521
+ confirmDialogClass = inject(RUNTIME_ACTION_CONFIRM_DIALOG, {
2522
+ optional: true,
2523
+ });
2524
+ async execute(action, defaultAfterSuccess) {
2525
+ if (action.needConfirmation &&
2526
+ hasActionFormFields(action) &&
2527
+ this.confirmDialogClass) {
2528
+ return this.executeFormAction(action, defaultAfterSuccess);
2529
+ }
2530
+ let submittedPayload;
2531
+ let result = await this.runner.execute(action, {
2532
+ defaultAfterSuccess,
2533
+ silent: true,
2534
+ externalPayloadResolvers: {
2535
+ values: () => this.actionContext.resolveFormValues(),
2536
+ },
2537
+ transformPayload: (payload) => {
2538
+ submittedPayload = payload;
2539
+ return payload;
2540
+ },
2541
+ });
2542
+ if (result.status === 'error') {
2543
+ result =
2544
+ (await this.validation.recover(action, result.error, submittedPayload, defaultAfterSuccess)) ?? result;
2545
+ }
2546
+ return result;
2547
+ }
2548
+ executeFormAction(action, defaultAfterSuccess) {
2549
+ return new Promise((resolve) => {
2550
+ let pendingRun = null;
2551
+ let finalResult = null;
2552
+ const ref = this.modal.openModal(this.confirmDialogClass, 'dialog', {
2553
+ header: resolveActionLabel(action),
2554
+ width: '40rem',
2555
+ dismissableMask: true,
2556
+ inputValues: {
2557
+ action,
2558
+ onSubmit: async (formValue) => {
2559
+ const submittedPayload = buildActionPayload(action, formValue, {
2560
+ values: () => this.actionContext.resolveFormValues(),
2561
+ });
2562
+ const executablePayload = submittedPayload ?? {};
2563
+ const executableAction = {
2564
+ ...action,
2565
+ needConfirmation: false,
2566
+ payloadKeys: Object.keys(executablePayload),
2567
+ payloadTemplate: executablePayload,
2568
+ };
2569
+ pendingRun = (async () => {
2570
+ let result = await this.runner.execute(executableAction, {
2571
+ defaultAfterSuccess,
2572
+ silent: true,
2573
+ });
2574
+ if (result.status === 'error') {
2575
+ result =
2576
+ (await this.validation.recover(action, result.error, submittedPayload, defaultAfterSuccess)) ?? result;
2577
+ }
2578
+ return result;
2579
+ })();
2580
+ finalResult = await pendingRun;
2581
+ // Every backend outcome leaves the action dialog. The footer then
2582
+ // refreshes on success or displays the actionable validation error.
2583
+ return true;
2584
+ },
2585
+ },
2586
+ });
2587
+ ref.onClose.pipe(take(1)).subscribe(async () => {
2588
+ if (finalResult) {
2589
+ resolve(finalResult);
2590
+ return;
2591
+ }
2592
+ if (pendingRun) {
2593
+ try {
2594
+ resolve(await pendingRun);
2595
+ }
2596
+ catch (error) {
2597
+ resolve({
2598
+ status: 'error',
2599
+ actionKey: action.actionKey,
2600
+ afterSuccess: null,
2601
+ error,
2602
+ });
2603
+ }
2604
+ return;
2605
+ }
2606
+ resolve({
2607
+ status: 'cancelled',
2608
+ actionKey: action.actionKey,
2609
+ afterSuccess: null,
2610
+ });
2611
+ });
2612
+ });
2613
+ }
2614
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterRuntimeActionExecutor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2615
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterRuntimeActionExecutor });
2616
+ }
2617
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterRuntimeActionExecutor, decorators: [{
2618
+ type: Injectable
2619
+ }] });
2620
+
2353
2621
  const DEFAULT_GENERAL_TASK_MODAL_STYLE_CLASS = '!w-[70vw] !h-[90vh]';
2354
2622
  class WorkCenterItemModalFooterActions {
2355
2623
  http = inject(HttpClient);
2356
- runner = inject(RuntimeActionRunner);
2357
- actionContext = inject(RuntimeActionContextStore);
2358
2624
  facade = inject(WorkCenterFacade);
2359
2625
  modal = inject(ModalService);
2360
2626
  transloco = inject(TranslocoService);
2627
+ actionValidation = inject(WorkCenterActionValidationHandler);
2628
+ actionExecutor = inject(WorkCenterRuntimeActionExecutor);
2361
2629
  loadSub;
2362
2630
  lastContextKey = null;
2363
2631
  currentExecution = null;
@@ -2439,13 +2707,7 @@ class WorkCenterItemModalFooterActions {
2439
2707
  this.pendingActionKey.set(action.actionKey);
2440
2708
  const execution = { actionKey: action.actionKey, cancelled: false };
2441
2709
  this.currentExecution = execution;
2442
- const result = await this.runner.execute(action, {
2443
- defaultAfterSuccess: resolveDefaultAfterSuccess(action.actionKey),
2444
- silent: true,
2445
- externalPayloadResolvers: {
2446
- values: () => this.actionContext.resolveFormValues(),
2447
- },
2448
- });
2710
+ const result = await this.actionExecutor.execute(action, resolveDefaultAfterSuccess(action.actionKey));
2449
2711
  if (execution.cancelled) {
2450
2712
  return;
2451
2713
  }
@@ -2455,9 +2717,9 @@ class WorkCenterItemModalFooterActions {
2455
2717
  return;
2456
2718
  }
2457
2719
  if (result.status === 'error') {
2458
- const message = result.error instanceof Error
2459
- ? result.error.message
2460
- : `Failed to execute ${action.label}.`;
2720
+ const message = this.actionValidation.resolveErrorMessage(result.error, this.transloco.translate('workCenter.actions.executeFailed', {
2721
+ action: action.label,
2722
+ }));
2461
2723
  this.error.set(message);
2462
2724
  return;
2463
2725
  }
@@ -2562,13 +2824,13 @@ class WorkCenterItemModalFooterActions {
2562
2824
  };
2563
2825
  }
2564
2826
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterItemModalFooterActions, deps: [], target: i0.ɵɵFactoryTarget.Component });
2565
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterItemModalFooterActions, isStandalone: true, selector: "mt-work-center-item-modal-footer-actions", inputs: { contextKey: { classPropertyName: "contextKey", publicName: "contextKey", isSignal: true, isRequired: false, transformFunction: null }, previewLevelTarget: { classPropertyName: "previewLevelTarget", publicName: "previewLevelTarget", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionExecuted: "actionExecuted", previewLevelSelected: "previewLevelSelected", visibilityChange: "visibilityChange" }, host: { classAttribute: "flex w-full flex-1 flex-wrap items-center justify-end gap-2" }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\r\n @if (shouldRender()) {\r\n @if (error(); as error) {\r\n <span class=\"me-auto max-w-md text-sm text-red-600\">\r\n {{ error }}\r\n </span>\r\n } @else if (loading() && !displayActions().length) {\r\n <span class=\"me-auto text-sm text-surface-500\">{{\r\n t(\"modal.loadingActions\")\r\n }}</span>\r\n }\r\n\r\n @if (previewLevelTarget(); as previewLevelTarget) {\r\n <mt-button\r\n [label]=\"previewLevelLabel(previewLevelTarget, t)\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [disabled]=\"loading() || !!pendingActionKey()\"\r\n (onClick)=\"previewLevelSelected.emit(previewLevelTarget)\"\r\n />\r\n }\r\n\r\n @for (action of displayActions(); track action.actionKey + action.url) {\r\n <mt-button\r\n [label]=\"action.label\"\r\n [severity]=\"action.severity\"\r\n [variant]=\"action.variant\"\r\n [disabled]=\"loading() || !!pendingActionKey()\"\r\n [loading]=\"pendingActionKey() === action.actionKey\"\r\n (onClick)=\"executeAction(action)\"\r\n />\r\n }\r\n }\r\n</ng-container>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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"] }] });
2827
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: WorkCenterItemModalFooterActions, isStandalone: true, selector: "mt-work-center-item-modal-footer-actions", inputs: { contextKey: { classPropertyName: "contextKey", publicName: "contextKey", isSignal: true, isRequired: false, transformFunction: null }, previewLevelTarget: { classPropertyName: "previewLevelTarget", publicName: "previewLevelTarget", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionExecuted: "actionExecuted", previewLevelSelected: "previewLevelSelected", visibilityChange: "visibilityChange" }, host: { classAttribute: "flex w-full flex-1 flex-wrap items-center justify-end gap-2" }, providers: [WorkCenterRuntimeActionExecutor], ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\n @if (shouldRender()) {\n @if (error(); as error) {\n <span class=\"me-auto max-w-md whitespace-pre-line text-sm text-red-600\">\n {{ error }}\n </span>\n } @else if (loading() && !displayActions().length) {\n <span class=\"me-auto text-sm text-surface-500\">{{\n t(\"modal.loadingActions\")\n }}</span>\n }\n\n @if (previewLevelTarget(); as previewLevelTarget) {\n <mt-button\n [label]=\"previewLevelLabel(previewLevelTarget, t)\"\n severity=\"secondary\"\n variant=\"outlined\"\n [disabled]=\"loading() || !!pendingActionKey()\"\n (onClick)=\"previewLevelSelected.emit(previewLevelTarget)\"\n />\n }\n\n @for (action of displayActions(); track action.actionKey + action.url) {\n <mt-button\n [label]=\"action.label\"\n [severity]=\"action.severity\"\n [variant]=\"action.variant\"\n [disabled]=\"loading() || !!pendingActionKey()\"\n [loading]=\"pendingActionKey() === action.actionKey\"\n (onClick)=\"executeAction(action)\"\n />\n }\n }\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { 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"] }] });
2566
2828
  }
2567
2829
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: WorkCenterItemModalFooterActions, decorators: [{
2568
2830
  type: Component,
2569
2831
  args: [{ selector: 'mt-work-center-item-modal-footer-actions', standalone: true, imports: [CommonModule, TranslocoDirective, Button], host: {
2570
2832
  class: 'flex w-full flex-1 flex-wrap items-center justify-end gap-2',
2571
- }, template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\r\n @if (shouldRender()) {\r\n @if (error(); as error) {\r\n <span class=\"me-auto max-w-md text-sm text-red-600\">\r\n {{ error }}\r\n </span>\r\n } @else if (loading() && !displayActions().length) {\r\n <span class=\"me-auto text-sm text-surface-500\">{{\r\n t(\"modal.loadingActions\")\r\n }}</span>\r\n }\r\n\r\n @if (previewLevelTarget(); as previewLevelTarget) {\r\n <mt-button\r\n [label]=\"previewLevelLabel(previewLevelTarget, t)\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n [disabled]=\"loading() || !!pendingActionKey()\"\r\n (onClick)=\"previewLevelSelected.emit(previewLevelTarget)\"\r\n />\r\n }\r\n\r\n @for (action of displayActions(); track action.actionKey + action.url) {\r\n <mt-button\r\n [label]=\"action.label\"\r\n [severity]=\"action.severity\"\r\n [variant]=\"action.variant\"\r\n [disabled]=\"loading() || !!pendingActionKey()\"\r\n [loading]=\"pendingActionKey() === action.actionKey\"\r\n (onClick)=\"executeAction(action)\"\r\n />\r\n }\r\n }\r\n</ng-container>\r\n" }]
2833
+ }, providers: [WorkCenterRuntimeActionExecutor], template: "<ng-container *transloco=\"let t; prefix: 'workCenter'\">\n @if (shouldRender()) {\n @if (error(); as error) {\n <span class=\"me-auto max-w-md whitespace-pre-line text-sm text-red-600\">\n {{ error }}\n </span>\n } @else if (loading() && !displayActions().length) {\n <span class=\"me-auto text-sm text-surface-500\">{{\n t(\"modal.loadingActions\")\n }}</span>\n }\n\n @if (previewLevelTarget(); as previewLevelTarget) {\n <mt-button\n [label]=\"previewLevelLabel(previewLevelTarget, t)\"\n severity=\"secondary\"\n variant=\"outlined\"\n [disabled]=\"loading() || !!pendingActionKey()\"\n (onClick)=\"previewLevelSelected.emit(previewLevelTarget)\"\n />\n }\n\n @for (action of displayActions(); track action.actionKey + action.url) {\n <mt-button\n [label]=\"action.label\"\n [severity]=\"action.severity\"\n [variant]=\"action.variant\"\n [disabled]=\"loading() || !!pendingActionKey()\"\n [loading]=\"pendingActionKey() === action.actionKey\"\n (onClick)=\"executeAction(action)\"\n />\n }\n }\n</ng-container>\n" }]
2572
2834
  }], ctorParameters: () => [], propDecorators: { contextKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextKey", required: false }] }], previewLevelTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewLevelTarget", required: false }] }], actionExecuted: [{ type: i0.Output, args: ["actionExecuted"] }], previewLevelSelected: [{ type: i0.Output, args: ["previewLevelSelected"] }], visibilityChange: [{ type: i0.Output, args: ["visibilityChange"] }] } });
2573
2835
  function normalizeMethod(value) {
2574
2836
  if (!value || typeof value !== 'string') {