@masterteam/delegations 0.0.21 → 0.0.22

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,6 +19,7 @@ import { ToastService } from '@masterteam/components/toast';
19
19
  import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
20
20
  import { Page } from '@masterteam/components/page';
21
21
  import { Breadcrumb } from '@masterteam/components/breadcrumb';
22
+ import { Card } from '@masterteam/components/card';
22
23
  import { Table } from '@masterteam/components/table';
23
24
  import * as i1$1 from '@angular/forms';
24
25
  import { FormControl, ReactiveFormsModule } from '@angular/forms';
@@ -460,6 +461,7 @@ class TopbarDelegationMenu {
460
461
  /** Path to the management page, e.g. `/control-panel/delegations` or `/delegations`. */
461
462
  managePath = input('/delegations', ...(ngDevMode ? [{ debugName: "managePath" }] : /* istanbul ignore next */ []));
462
463
  compact = input(false, ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
464
+ showManageLink = input(true, ...(ngDevMode ? [{ debugName: "showManageLink" }] : /* istanbul ignore next */ []));
463
465
  facade = inject(DelegationSessionFacade);
464
466
  modal = inject(ModalService);
465
467
  transloco = inject(TranslocoService);
@@ -507,7 +509,7 @@ class TopbarDelegationMenu {
507
509
  });
508
510
  }
509
511
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TopbarDelegationMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
510
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TopbarDelegationMenu, isStandalone: true, selector: "mt-topbar-delegation-menu", inputs: { managePath: { classPropertyName: "managePath", publicName: "managePath", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "popover", first: true, predicate: ["popover"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\n @if (mode() !== \"hidden\") {\n <div class=\"mt-delegation-trigger flex items-center gap-2\">\n <button\n type=\"button\"\n class=\"mt-delegation-trigger__button flex min-w-0 max-w-full items-center gap-2 rounded-full px-2 py-1 hover:bg-surface-100 cursor-pointer\"\n [attr.aria-label]=\"t('delegations.title')\"\n [attr.title]=\"\n mode() === 'active'\n ? t('delegations.session.banner', {\n delegatorName: onBehalfOf()?.displayName,\n })\n : null\n \"\n (click)=\"togglePopover($event)\"\n >\n @if (mode() === \"active\") {\n <mt-icon\n icon=\"user.users-check\"\n styleClass=\"text-lg text-primary\"\n ></mt-icon>\n @if (!compact()) {\n <span class=\"mt-delegation-trigger__label text-sm font-medium\">\n {{\n t(\"delegations.session.banner\", {\n delegatorName: onBehalfOf()?.displayName,\n })\n }}\n </span>\n }\n <mt-delegation-status-chip\n status=\"Active\"\n ></mt-delegation-status-chip>\n } @else {\n <mt-icon\n icon=\"user.users-plus\"\n styleClass=\"text-lg text-primary\"\n ></mt-icon>\n @if (!compact()) {\n <span class=\"mt-delegation-trigger__label text-sm font-medium\">\n {{ t(\"delegations.session.availableTitle\") }}\n </span>\n }\n }\n </button>\n </div>\n\n <p-popover #popover [pt]=\"{ content: { class: 'p-0!' } }\">\n <div class=\"flex flex-col min-w-80 max-w-96 p-0\">\n @if (mode() === \"active\" && active(); as session) {\n <!-- STATE C \u2014 active session -->\n <div\n class=\"flex items-start gap-3 border-b border-gray-200 px-4 py-4\"\n >\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-11! h-11! text-xl! text-gray-600! bg-surface-300!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0 flex-1\">\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\n </div>\n <div class=\"text-sm font-medium text-gray-900 truncate\">\n {{ onBehalfOf()?.displayName }}\n </div>\n <div class=\"text-xs text-gray-500 mt-1\">\n {{\n t(\"delegations.session.executedBy\", {\n actualUserName: executedBy()?.displayName,\n })\n }}\n </div>\n @if (session.delegation.scopeSummary) {\n @let summary =\n formatScopeSummary(session.delegation.scopeSummary);\n <div\n class=\"text-xs text-gray-500 mt-1 truncate\"\n [title]=\"summary\"\n >\n {{ t(\"delegations.column.scopeSummary\") }}:\n {{ summary }}\n </div>\n }\n </div>\n </div>\n\n <div class=\"flex flex-col gap-1 px-2 py-2\">\n <mt-button\n variant=\"text\"\n icon=\"arrow.arrow-left\"\n [label]=\"t('delegations.action.endSession')\"\n styleClass=\"w-full justify-start\"\n (click)=\"endSession($event)\"\n ></mt-button>\n </div>\n\n @if (candidates().length > 1) {\n <div class=\"border-t border-gray-200 pt-2 px-2 pb-2\">\n <div class=\"text-xs text-gray-500 px-2 pb-1\">\n {{ t(\"delegations.session.switchToAnother\") }}\n </div>\n @for (cand of candidates(); track cand.delegationId) {\n @if (cand.delegationId !== session.delegation.delegationId) {\n <button\n type=\"button\"\n class=\"flex items-center justify-between gap-2 w-full px-2 py-2 rounded-md hover:bg-surface-100 cursor-pointer\"\n (click)=\"switchTo(cand, $event)\"\n >\n <div class=\"flex items-center gap-2 min-w-0\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-7! h-7! text-sm! bg-surface-200!\"\n ></mt-avatar>\n <span class=\"text-sm text-gray-900 truncate\">\n {{ cand.delegator.displayName }}\n </span>\n </div>\n <mt-icon\n icon=\"arrow.switch-horizontal-01\"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n </button>\n }\n }\n </div>\n }\n } @else if (mode() === \"candidates\") {\n <!-- STATE B \u2014 candidates available -->\n <div class=\"border-b border-gray-200 px-4 py-3\">\n <div class=\"text-sm font-medium text-gray-900\">\n {{ t(\"delegations.session.youCanActAs\") }}\n </div>\n <div class=\"text-xs text-gray-500 mt-1\">\n {{ t(\"delegations.session.chooseDelegatorHint\") }}\n </div>\n </div>\n <div class=\"flex flex-col gap-1 px-2 py-2 max-h-72 overflow-y-auto\">\n @for (cand of candidates(); track cand.delegationId) {\n <button\n type=\"button\"\n class=\"flex items-center justify-between gap-2 w-full px-2 py-2 rounded-md hover:bg-surface-100 cursor-pointer text-start\"\n (click)=\"start(cand, $event)\"\n >\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-9! h-9! text-base! bg-surface-200!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <span class=\"text-sm font-medium text-gray-900 truncate\">\n {{ cand.delegator.displayName }}\n </span>\n @if (cand.scopeSummary) {\n @let summary = formatScopeSummary(cand.scopeSummary);\n <span\n class=\"text-xs text-gray-500 truncate\"\n [title]=\"summary\"\n >\n {{ summary }}\n </span>\n }\n </div>\n </div>\n <mt-icon\n icon=\"arrow.arrow-right\"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n </button>\n }\n </div>\n }\n\n <!-- Footer -->\n <div class=\"border-t border-gray-200 px-2 py-2\">\n <a\n [routerLink]=\"managePath()\"\n (click)=\"popover().hide()\"\n class=\"flex items-center gap-2 px-3 py-2 rounded-md text-gray-700 hover:bg-surface-100 text-sm cursor-pointer\"\n >\n <mt-icon\n icon=\"general.settings-02\"\n styleClass=\"text-base\"\n ></mt-icon>\n <span>{{ t(\"delegations.session.manage\") }}</span>\n </a>\n </div>\n </div>\n </p-popover>\n }\n</ng-container>\n", styles: [":host{display:inline-flex;align-items:center;min-width:0;max-width:100%}.mt-delegation-trigger{min-width:0;max-width:100%}.mt-delegation-trigger__button{transition:background-color .2s ease-out;min-width:0;max-width:100%}.mt-delegation-trigger__label{max-width:min(16rem,28vw);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(max-width:1200px){.mt-delegation-trigger__label{max-width:10rem}}@media(max-width:1024px){.mt-delegation-trigger__button{gap:.375rem;padding-inline:.375rem}.mt-delegation-trigger__label{display:none}}:host-context(.dark) .mt-delegation-trigger__button:hover{background-color:#94a3b826}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: DelegationStatusChip, selector: "mt-delegation-status-chip", inputs: ["status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
512
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TopbarDelegationMenu, isStandalone: true, selector: "mt-topbar-delegation-menu", inputs: { managePath: { classPropertyName: "managePath", publicName: "managePath", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, showManageLink: { classPropertyName: "showManageLink", publicName: "showManageLink", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "popover", first: true, predicate: ["popover"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\n @if (mode() !== \"hidden\") {\n <div class=\"mt-delegation-trigger flex items-center gap-2\">\n <button\n type=\"button\"\n class=\"mt-delegation-trigger__button flex min-w-0 max-w-full items-center gap-2 rounded-full px-2 py-1 hover:bg-surface-100 cursor-pointer\"\n [attr.aria-label]=\"t('delegations.title')\"\n [attr.title]=\"\n mode() === 'active'\n ? t('delegations.session.banner', {\n delegatorName: onBehalfOf()?.displayName,\n })\n : null\n \"\n (click)=\"togglePopover($event)\"\n >\n @if (mode() === \"active\") {\n <mt-icon\n icon=\"user.users-check\"\n styleClass=\"text-lg text-primary\"\n ></mt-icon>\n @if (!compact()) {\n <span class=\"mt-delegation-trigger__label text-sm font-medium\">\n {{\n t(\"delegations.session.banner\", {\n delegatorName: onBehalfOf()?.displayName,\n })\n }}\n </span>\n }\n <mt-delegation-status-chip\n status=\"Active\"\n ></mt-delegation-status-chip>\n } @else {\n <mt-icon\n icon=\"user.users-plus\"\n styleClass=\"text-lg text-primary\"\n ></mt-icon>\n @if (!compact()) {\n <span class=\"mt-delegation-trigger__label text-sm font-medium\">\n {{ t(\"delegations.session.availableTitle\") }}\n </span>\n }\n }\n </button>\n </div>\n\n <p-popover #popover [pt]=\"{ content: { class: 'p-0!' } }\">\n <div class=\"flex flex-col min-w-80 max-w-96 p-0\">\n @if (mode() === \"active\" && active(); as session) {\n <!-- STATE C \u2014 active session -->\n <div\n class=\"flex items-start gap-3 border-b border-gray-200 px-4 py-4\"\n >\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-11! h-11! text-xl! text-gray-600! bg-surface-300!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0 flex-1\">\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\n </div>\n <div class=\"text-sm font-medium text-gray-900 truncate\">\n {{ onBehalfOf()?.displayName }}\n </div>\n <div class=\"text-xs text-gray-500 mt-1\">\n {{\n t(\"delegations.session.executedBy\", {\n actualUserName: executedBy()?.displayName,\n })\n }}\n </div>\n @if (session.delegation.scopeSummary) {\n @let summary =\n formatScopeSummary(session.delegation.scopeSummary);\n <div\n class=\"text-xs text-gray-500 mt-1 truncate\"\n [title]=\"summary\"\n >\n {{ t(\"delegations.column.scopeSummary\") }}:\n {{ summary }}\n </div>\n }\n </div>\n </div>\n\n <div class=\"flex flex-col gap-1 px-2 py-2\">\n <mt-button\n variant=\"text\"\n icon=\"arrow.arrow-left\"\n [label]=\"t('delegations.action.endSession')\"\n styleClass=\"w-full justify-start\"\n (click)=\"endSession($event)\"\n ></mt-button>\n </div>\n\n @if (candidates().length > 1) {\n <div class=\"border-t border-gray-200 pt-2 px-2 pb-2\">\n <div class=\"text-xs text-gray-500 px-2 pb-1\">\n {{ t(\"delegations.session.switchToAnother\") }}\n </div>\n @for (cand of candidates(); track cand.delegationId) {\n @if (cand.delegationId !== session.delegation.delegationId) {\n <button\n type=\"button\"\n class=\"flex items-center justify-between gap-2 w-full px-2 py-2 rounded-md hover:bg-surface-100 cursor-pointer\"\n (click)=\"switchTo(cand, $event)\"\n >\n <div class=\"flex items-center gap-2 min-w-0\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-7! h-7! text-sm! bg-surface-200!\"\n ></mt-avatar>\n <span class=\"text-sm text-gray-900 truncate\">\n {{ cand.delegator.displayName }}\n </span>\n </div>\n <mt-icon\n icon=\"arrow.switch-horizontal-01\"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n </button>\n }\n }\n </div>\n }\n } @else if (mode() === \"candidates\") {\n <!-- STATE B \u2014 candidates available -->\n <div class=\"border-b border-gray-200 px-4 py-3\">\n <div class=\"text-sm font-medium text-gray-900\">\n {{ t(\"delegations.session.youCanActAs\") }}\n </div>\n <div class=\"text-xs text-gray-500 mt-1\">\n {{ t(\"delegations.session.chooseDelegatorHint\") }}\n </div>\n </div>\n <div class=\"flex flex-col gap-1 px-2 py-2 max-h-72 overflow-y-auto\">\n @for (cand of candidates(); track cand.delegationId) {\n <button\n type=\"button\"\n class=\"flex items-center justify-between gap-2 w-full px-2 py-2 rounded-md hover:bg-surface-100 cursor-pointer text-start\"\n (click)=\"start(cand, $event)\"\n >\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-9! h-9! text-base! bg-surface-200!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <span class=\"text-sm font-medium text-gray-900 truncate\">\n {{ cand.delegator.displayName }}\n </span>\n @if (cand.scopeSummary) {\n @let summary = formatScopeSummary(cand.scopeSummary);\n <span\n class=\"text-xs text-gray-500 truncate\"\n [title]=\"summary\"\n >\n {{ summary }}\n </span>\n }\n </div>\n </div>\n <mt-icon\n icon=\"arrow.arrow-right\"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n </button>\n }\n </div>\n }\n\n <!-- Footer -->\n @if (showManageLink()) {\n <div class=\"border-t border-gray-200 px-2 py-2\">\n <a\n [routerLink]=\"managePath()\"\n (click)=\"popover().hide()\"\n class=\"flex items-center gap-2 px-3 py-2 rounded-md text-gray-700 hover:bg-surface-100 text-sm cursor-pointer\"\n >\n <mt-icon\n icon=\"general.settings-02\"\n styleClass=\"text-base\"\n ></mt-icon>\n <span>{{ t(\"delegations.session.manage\") }}</span>\n </a>\n </div>\n }\n </div>\n </p-popover>\n }\n</ng-container>\n", styles: [":host{display:inline-flex;align-items:center;min-width:0;max-width:100%}.mt-delegation-trigger{min-width:0;max-width:100%}.mt-delegation-trigger__button{transition:background-color .2s ease-out;min-width:0;max-width:100%}.mt-delegation-trigger__label{max-width:min(16rem,28vw);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(max-width:1200px){.mt-delegation-trigger__label{max-width:10rem}}@media(max-width:1024px){.mt-delegation-trigger__button{gap:.375rem;padding-inline:.375rem}.mt-delegation-trigger__label{display:none}}:host-context(.dark) .mt-delegation-trigger__button:hover{background-color:#94a3b826}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: DelegationStatusChip, selector: "mt-delegation-status-chip", inputs: ["status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
511
513
  }
512
514
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TopbarDelegationMenu, decorators: [{
513
515
  type: Component,
@@ -520,8 +522,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
520
522
  RouterLink,
521
523
  TranslocoDirective,
522
524
  DelegationStatusChip,
523
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n @if (mode() !== \"hidden\") {\n <div class=\"mt-delegation-trigger flex items-center gap-2\">\n <button\n type=\"button\"\n class=\"mt-delegation-trigger__button flex min-w-0 max-w-full items-center gap-2 rounded-full px-2 py-1 hover:bg-surface-100 cursor-pointer\"\n [attr.aria-label]=\"t('delegations.title')\"\n [attr.title]=\"\n mode() === 'active'\n ? t('delegations.session.banner', {\n delegatorName: onBehalfOf()?.displayName,\n })\n : null\n \"\n (click)=\"togglePopover($event)\"\n >\n @if (mode() === \"active\") {\n <mt-icon\n icon=\"user.users-check\"\n styleClass=\"text-lg text-primary\"\n ></mt-icon>\n @if (!compact()) {\n <span class=\"mt-delegation-trigger__label text-sm font-medium\">\n {{\n t(\"delegations.session.banner\", {\n delegatorName: onBehalfOf()?.displayName,\n })\n }}\n </span>\n }\n <mt-delegation-status-chip\n status=\"Active\"\n ></mt-delegation-status-chip>\n } @else {\n <mt-icon\n icon=\"user.users-plus\"\n styleClass=\"text-lg text-primary\"\n ></mt-icon>\n @if (!compact()) {\n <span class=\"mt-delegation-trigger__label text-sm font-medium\">\n {{ t(\"delegations.session.availableTitle\") }}\n </span>\n }\n }\n </button>\n </div>\n\n <p-popover #popover [pt]=\"{ content: { class: 'p-0!' } }\">\n <div class=\"flex flex-col min-w-80 max-w-96 p-0\">\n @if (mode() === \"active\" && active(); as session) {\n <!-- STATE C \u2014 active session -->\n <div\n class=\"flex items-start gap-3 border-b border-gray-200 px-4 py-4\"\n >\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-11! h-11! text-xl! text-gray-600! bg-surface-300!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0 flex-1\">\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\n </div>\n <div class=\"text-sm font-medium text-gray-900 truncate\">\n {{ onBehalfOf()?.displayName }}\n </div>\n <div class=\"text-xs text-gray-500 mt-1\">\n {{\n t(\"delegations.session.executedBy\", {\n actualUserName: executedBy()?.displayName,\n })\n }}\n </div>\n @if (session.delegation.scopeSummary) {\n @let summary =\n formatScopeSummary(session.delegation.scopeSummary);\n <div\n class=\"text-xs text-gray-500 mt-1 truncate\"\n [title]=\"summary\"\n >\n {{ t(\"delegations.column.scopeSummary\") }}:\n {{ summary }}\n </div>\n }\n </div>\n </div>\n\n <div class=\"flex flex-col gap-1 px-2 py-2\">\n <mt-button\n variant=\"text\"\n icon=\"arrow.arrow-left\"\n [label]=\"t('delegations.action.endSession')\"\n styleClass=\"w-full justify-start\"\n (click)=\"endSession($event)\"\n ></mt-button>\n </div>\n\n @if (candidates().length > 1) {\n <div class=\"border-t border-gray-200 pt-2 px-2 pb-2\">\n <div class=\"text-xs text-gray-500 px-2 pb-1\">\n {{ t(\"delegations.session.switchToAnother\") }}\n </div>\n @for (cand of candidates(); track cand.delegationId) {\n @if (cand.delegationId !== session.delegation.delegationId) {\n <button\n type=\"button\"\n class=\"flex items-center justify-between gap-2 w-full px-2 py-2 rounded-md hover:bg-surface-100 cursor-pointer\"\n (click)=\"switchTo(cand, $event)\"\n >\n <div class=\"flex items-center gap-2 min-w-0\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-7! h-7! text-sm! bg-surface-200!\"\n ></mt-avatar>\n <span class=\"text-sm text-gray-900 truncate\">\n {{ cand.delegator.displayName }}\n </span>\n </div>\n <mt-icon\n icon=\"arrow.switch-horizontal-01\"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n </button>\n }\n }\n </div>\n }\n } @else if (mode() === \"candidates\") {\n <!-- STATE B \u2014 candidates available -->\n <div class=\"border-b border-gray-200 px-4 py-3\">\n <div class=\"text-sm font-medium text-gray-900\">\n {{ t(\"delegations.session.youCanActAs\") }}\n </div>\n <div class=\"text-xs text-gray-500 mt-1\">\n {{ t(\"delegations.session.chooseDelegatorHint\") }}\n </div>\n </div>\n <div class=\"flex flex-col gap-1 px-2 py-2 max-h-72 overflow-y-auto\">\n @for (cand of candidates(); track cand.delegationId) {\n <button\n type=\"button\"\n class=\"flex items-center justify-between gap-2 w-full px-2 py-2 rounded-md hover:bg-surface-100 cursor-pointer text-start\"\n (click)=\"start(cand, $event)\"\n >\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-9! h-9! text-base! bg-surface-200!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <span class=\"text-sm font-medium text-gray-900 truncate\">\n {{ cand.delegator.displayName }}\n </span>\n @if (cand.scopeSummary) {\n @let summary = formatScopeSummary(cand.scopeSummary);\n <span\n class=\"text-xs text-gray-500 truncate\"\n [title]=\"summary\"\n >\n {{ summary }}\n </span>\n }\n </div>\n </div>\n <mt-icon\n icon=\"arrow.arrow-right\"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n </button>\n }\n </div>\n }\n\n <!-- Footer -->\n <div class=\"border-t border-gray-200 px-2 py-2\">\n <a\n [routerLink]=\"managePath()\"\n (click)=\"popover().hide()\"\n class=\"flex items-center gap-2 px-3 py-2 rounded-md text-gray-700 hover:bg-surface-100 text-sm cursor-pointer\"\n >\n <mt-icon\n icon=\"general.settings-02\"\n styleClass=\"text-base\"\n ></mt-icon>\n <span>{{ t(\"delegations.session.manage\") }}</span>\n </a>\n </div>\n </div>\n </p-popover>\n }\n</ng-container>\n", styles: [":host{display:inline-flex;align-items:center;min-width:0;max-width:100%}.mt-delegation-trigger{min-width:0;max-width:100%}.mt-delegation-trigger__button{transition:background-color .2s ease-out;min-width:0;max-width:100%}.mt-delegation-trigger__label{max-width:min(16rem,28vw);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(max-width:1200px){.mt-delegation-trigger__label{max-width:10rem}}@media(max-width:1024px){.mt-delegation-trigger__button{gap:.375rem;padding-inline:.375rem}.mt-delegation-trigger__label{display:none}}:host-context(.dark) .mt-delegation-trigger__button:hover{background-color:#94a3b826}\n"] }]
524
- }], propDecorators: { managePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "managePath", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], popover: [{ type: i0.ViewChild, args: ['popover', { isSignal: true }] }] } });
525
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n @if (mode() !== \"hidden\") {\n <div class=\"mt-delegation-trigger flex items-center gap-2\">\n <button\n type=\"button\"\n class=\"mt-delegation-trigger__button flex min-w-0 max-w-full items-center gap-2 rounded-full px-2 py-1 hover:bg-surface-100 cursor-pointer\"\n [attr.aria-label]=\"t('delegations.title')\"\n [attr.title]=\"\n mode() === 'active'\n ? t('delegations.session.banner', {\n delegatorName: onBehalfOf()?.displayName,\n })\n : null\n \"\n (click)=\"togglePopover($event)\"\n >\n @if (mode() === \"active\") {\n <mt-icon\n icon=\"user.users-check\"\n styleClass=\"text-lg text-primary\"\n ></mt-icon>\n @if (!compact()) {\n <span class=\"mt-delegation-trigger__label text-sm font-medium\">\n {{\n t(\"delegations.session.banner\", {\n delegatorName: onBehalfOf()?.displayName,\n })\n }}\n </span>\n }\n <mt-delegation-status-chip\n status=\"Active\"\n ></mt-delegation-status-chip>\n } @else {\n <mt-icon\n icon=\"user.users-plus\"\n styleClass=\"text-lg text-primary\"\n ></mt-icon>\n @if (!compact()) {\n <span class=\"mt-delegation-trigger__label text-sm font-medium\">\n {{ t(\"delegations.session.availableTitle\") }}\n </span>\n }\n }\n </button>\n </div>\n\n <p-popover #popover [pt]=\"{ content: { class: 'p-0!' } }\">\n <div class=\"flex flex-col min-w-80 max-w-96 p-0\">\n @if (mode() === \"active\" && active(); as session) {\n <!-- STATE C \u2014 active session -->\n <div\n class=\"flex items-start gap-3 border-b border-gray-200 px-4 py-4\"\n >\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-11! h-11! text-xl! text-gray-600! bg-surface-300!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0 flex-1\">\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\n </div>\n <div class=\"text-sm font-medium text-gray-900 truncate\">\n {{ onBehalfOf()?.displayName }}\n </div>\n <div class=\"text-xs text-gray-500 mt-1\">\n {{\n t(\"delegations.session.executedBy\", {\n actualUserName: executedBy()?.displayName,\n })\n }}\n </div>\n @if (session.delegation.scopeSummary) {\n @let summary =\n formatScopeSummary(session.delegation.scopeSummary);\n <div\n class=\"text-xs text-gray-500 mt-1 truncate\"\n [title]=\"summary\"\n >\n {{ t(\"delegations.column.scopeSummary\") }}:\n {{ summary }}\n </div>\n }\n </div>\n </div>\n\n <div class=\"flex flex-col gap-1 px-2 py-2\">\n <mt-button\n variant=\"text\"\n icon=\"arrow.arrow-left\"\n [label]=\"t('delegations.action.endSession')\"\n styleClass=\"w-full justify-start\"\n (click)=\"endSession($event)\"\n ></mt-button>\n </div>\n\n @if (candidates().length > 1) {\n <div class=\"border-t border-gray-200 pt-2 px-2 pb-2\">\n <div class=\"text-xs text-gray-500 px-2 pb-1\">\n {{ t(\"delegations.session.switchToAnother\") }}\n </div>\n @for (cand of candidates(); track cand.delegationId) {\n @if (cand.delegationId !== session.delegation.delegationId) {\n <button\n type=\"button\"\n class=\"flex items-center justify-between gap-2 w-full px-2 py-2 rounded-md hover:bg-surface-100 cursor-pointer\"\n (click)=\"switchTo(cand, $event)\"\n >\n <div class=\"flex items-center gap-2 min-w-0\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-7! h-7! text-sm! bg-surface-200!\"\n ></mt-avatar>\n <span class=\"text-sm text-gray-900 truncate\">\n {{ cand.delegator.displayName }}\n </span>\n </div>\n <mt-icon\n icon=\"arrow.switch-horizontal-01\"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n </button>\n }\n }\n </div>\n }\n } @else if (mode() === \"candidates\") {\n <!-- STATE B \u2014 candidates available -->\n <div class=\"border-b border-gray-200 px-4 py-3\">\n <div class=\"text-sm font-medium text-gray-900\">\n {{ t(\"delegations.session.youCanActAs\") }}\n </div>\n <div class=\"text-xs text-gray-500 mt-1\">\n {{ t(\"delegations.session.chooseDelegatorHint\") }}\n </div>\n </div>\n <div class=\"flex flex-col gap-1 px-2 py-2 max-h-72 overflow-y-auto\">\n @for (cand of candidates(); track cand.delegationId) {\n <button\n type=\"button\"\n class=\"flex items-center justify-between gap-2 w-full px-2 py-2 rounded-md hover:bg-surface-100 cursor-pointer text-start\"\n (click)=\"start(cand, $event)\"\n >\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-9! h-9! text-base! bg-surface-200!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <span class=\"text-sm font-medium text-gray-900 truncate\">\n {{ cand.delegator.displayName }}\n </span>\n @if (cand.scopeSummary) {\n @let summary = formatScopeSummary(cand.scopeSummary);\n <span\n class=\"text-xs text-gray-500 truncate\"\n [title]=\"summary\"\n >\n {{ summary }}\n </span>\n }\n </div>\n </div>\n <mt-icon\n icon=\"arrow.arrow-right\"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n </button>\n }\n </div>\n }\n\n <!-- Footer -->\n @if (showManageLink()) {\n <div class=\"border-t border-gray-200 px-2 py-2\">\n <a\n [routerLink]=\"managePath()\"\n (click)=\"popover().hide()\"\n class=\"flex items-center gap-2 px-3 py-2 rounded-md text-gray-700 hover:bg-surface-100 text-sm cursor-pointer\"\n >\n <mt-icon\n icon=\"general.settings-02\"\n styleClass=\"text-base\"\n ></mt-icon>\n <span>{{ t(\"delegations.session.manage\") }}</span>\n </a>\n </div>\n }\n </div>\n </p-popover>\n }\n</ng-container>\n", styles: [":host{display:inline-flex;align-items:center;min-width:0;max-width:100%}.mt-delegation-trigger{min-width:0;max-width:100%}.mt-delegation-trigger__button{transition:background-color .2s ease-out;min-width:0;max-width:100%}.mt-delegation-trigger__label{max-width:min(16rem,28vw);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(max-width:1200px){.mt-delegation-trigger__label{max-width:10rem}}@media(max-width:1024px){.mt-delegation-trigger__button{gap:.375rem;padding-inline:.375rem}.mt-delegation-trigger__label{display:none}}:host-context(.dark) .mt-delegation-trigger__button:hover{background-color:#94a3b826}\n"] }]
526
+ }], propDecorators: { managePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "managePath", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], showManageLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "showManageLink", required: false }] }], popover: [{ type: i0.ViewChild, args: ['popover', { isSignal: true }] }] } });
525
527
 
526
528
  // ---------------------------------------------------------------------------
527
529
  // Lists / detail
@@ -540,6 +542,13 @@ class GetAssignedDelegations {
540
542
  this.query = query;
541
543
  }
542
544
  }
545
+ class GetAdminDelegations {
546
+ query;
547
+ static type = '[Delegations] Get Admin Delegations';
548
+ constructor(query = {}) {
549
+ this.query = query;
550
+ }
551
+ }
543
552
  class GetActiveAssignedDelegations {
544
553
  query;
545
554
  static type = '[Delegations] Get Active Assigned Delegations';
@@ -652,6 +661,7 @@ var DelegationsActionKey;
652
661
  (function (DelegationsActionKey) {
653
662
  DelegationsActionKey["GetMy"] = "getMy";
654
663
  DelegationsActionKey["GetAssigned"] = "getAssigned";
664
+ DelegationsActionKey["GetAdmin"] = "getAdmin";
655
665
  DelegationsActionKey["GetActive"] = "getActive";
656
666
  DelegationsActionKey["GetDetail"] = "getDetail";
657
667
  DelegationsActionKey["GetScopeOptions"] = "getScopeOptions";
@@ -705,6 +715,9 @@ let DelegationsState = class DelegationsState {
705
715
  static getAssigned(state) {
706
716
  return state.assigned;
707
717
  }
718
+ static getAdmin(state) {
719
+ return state.admin;
720
+ }
708
721
  static getActive(state) {
709
722
  return state.active;
710
723
  }
@@ -746,6 +759,15 @@ let DelegationsState = class DelegationsState {
746
759
  onSuccess: (response) => ({ assigned: response.data }),
747
760
  });
748
761
  }
762
+ getAdmin(ctx, { query }) {
763
+ const req$ = this.http.get(`${BASE}/All`, { params: buildListParams(query) });
764
+ return handleApiRequest({
765
+ ctx,
766
+ key: DelegationsActionKey.GetAdmin,
767
+ request$: req$,
768
+ onSuccess: (response) => ({ admin: response.data }),
769
+ });
770
+ }
749
771
  getActive(ctx, { query }) {
750
772
  const req$ = this.http.get(`${BASE}/user/activedelegations`, { params: buildListParams(query) });
751
773
  return handleApiRequest({
@@ -876,6 +898,9 @@ __decorate([
876
898
  __decorate([
877
899
  Action(GetAssignedDelegations)
878
900
  ], DelegationsState.prototype, "getAssigned", null);
901
+ __decorate([
902
+ Action(GetAdminDelegations)
903
+ ], DelegationsState.prototype, "getAdmin", null);
879
904
  __decorate([
880
905
  Action(GetActiveAssignedDelegations)
881
906
  ], DelegationsState.prototype, "getActive", null);
@@ -921,6 +946,9 @@ __decorate([
921
946
  __decorate([
922
947
  Selector()
923
948
  ], DelegationsState, "getAssigned", null);
949
+ __decorate([
950
+ Selector()
951
+ ], DelegationsState, "getAdmin", null);
924
952
  __decorate([
925
953
  Selector()
926
954
  ], DelegationsState, "getActive", null);
@@ -945,6 +973,7 @@ DelegationsState = __decorate([
945
973
  defaults: {
946
974
  my: null,
947
975
  assigned: null,
976
+ admin: null,
948
977
  active: null,
949
978
  detail: null,
950
979
  scopeOptions: null,
@@ -956,7 +985,7 @@ DelegationsState = __decorate([
956
985
  ], DelegationsState);
957
986
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationsState, decorators: [{
958
987
  type: Injectable
959
- }], propDecorators: { getMy: [], getAssigned: [], getActive: [], getDetail: [], clearDetail: [], getScopeOptions: [], previewScope: [], clearScopePreview: [], createLegacy: [], createV2: [], updateLegacy: [], updateV2: [], approve: [], reject: [], cancel: [] } });
988
+ }], propDecorators: { getMy: [], getAssigned: [], getAdmin: [], getActive: [], getDetail: [], clearDetail: [], getScopeOptions: [], previewScope: [], clearScopePreview: [], createLegacy: [], createV2: [], updateLegacy: [], updateV2: [], approve: [], reject: [], cancel: [] } });
960
989
 
961
990
  class DelegationsFacade {
962
991
  store = inject(Store);
@@ -965,6 +994,7 @@ class DelegationsFacade {
965
994
  // ---------------------------------------------------------------------------
966
995
  myPage = select(DelegationsState.getMy);
967
996
  assignedPage = select(DelegationsState.getAssigned);
997
+ adminPage = select(DelegationsState.getAdmin);
968
998
  activePage = select(DelegationsState.getActive);
969
999
  detail = select(DelegationsState.getDetail);
970
1000
  scopeOptions = select(DelegationsState.getScopeOptions);
@@ -976,12 +1006,14 @@ class DelegationsFacade {
976
1006
  // ---------------------------------------------------------------------------
977
1007
  myItems = computed(() => this.myPage()?.items ?? [], ...(ngDevMode ? [{ debugName: "myItems" }] : /* istanbul ignore next */ []));
978
1008
  assignedItems = computed(() => this.assignedPage()?.items ?? [], ...(ngDevMode ? [{ debugName: "assignedItems" }] : /* istanbul ignore next */ []));
1009
+ adminItems = computed(() => this.adminPage()?.items ?? [], ...(ngDevMode ? [{ debugName: "adminItems" }] : /* istanbul ignore next */ []));
979
1010
  activeItems = computed(() => this.activePage()?.items ?? [], ...(ngDevMode ? [{ debugName: "activeItems" }] : /* istanbul ignore next */ []));
980
1011
  // ---------------------------------------------------------------------------
981
1012
  // Loading
982
1013
  // ---------------------------------------------------------------------------
983
1014
  isLoadingMy = computed(() => this.loadingActive().includes(DelegationsActionKey.GetMy), ...(ngDevMode ? [{ debugName: "isLoadingMy" }] : /* istanbul ignore next */ []));
984
1015
  isLoadingAssigned = computed(() => this.loadingActive().includes(DelegationsActionKey.GetAssigned), ...(ngDevMode ? [{ debugName: "isLoadingAssigned" }] : /* istanbul ignore next */ []));
1016
+ isLoadingAdmin = computed(() => this.loadingActive().includes(DelegationsActionKey.GetAdmin), ...(ngDevMode ? [{ debugName: "isLoadingAdmin" }] : /* istanbul ignore next */ []));
985
1017
  isLoadingActive = computed(() => this.loadingActive().includes(DelegationsActionKey.GetActive), ...(ngDevMode ? [{ debugName: "isLoadingActive" }] : /* istanbul ignore next */ []));
986
1018
  isLoadingDetail = computed(() => this.loadingActive().includes(DelegationsActionKey.GetDetail), ...(ngDevMode ? [{ debugName: "isLoadingDetail" }] : /* istanbul ignore next */ []));
987
1019
  isLoadingScopeOptions = computed(() => this.loadingActive().includes(DelegationsActionKey.GetScopeOptions), ...(ngDevMode ? [{ debugName: "isLoadingScopeOptions" }] : /* istanbul ignore next */ []));
@@ -996,6 +1028,7 @@ class DelegationsFacade {
996
1028
  // ---------------------------------------------------------------------------
997
1029
  errorMy = computed(() => this.errors()[DelegationsActionKey.GetMy] ?? null, ...(ngDevMode ? [{ debugName: "errorMy" }] : /* istanbul ignore next */ []));
998
1030
  errorAssigned = computed(() => this.errors()[DelegationsActionKey.GetAssigned] ?? null, ...(ngDevMode ? [{ debugName: "errorAssigned" }] : /* istanbul ignore next */ []));
1031
+ errorAdmin = computed(() => this.errors()[DelegationsActionKey.GetAdmin] ?? null, ...(ngDevMode ? [{ debugName: "errorAdmin" }] : /* istanbul ignore next */ []));
999
1032
  errorDetail = computed(() => this.errors()[DelegationsActionKey.GetDetail] ?? null, ...(ngDevMode ? [{ debugName: "errorDetail" }] : /* istanbul ignore next */ []));
1000
1033
  errorScopeOptions = computed(() => this.errors()[DelegationsActionKey.GetScopeOptions] ?? null, ...(ngDevMode ? [{ debugName: "errorScopeOptions" }] : /* istanbul ignore next */ []));
1001
1034
  errorSave = computed(() => this.errors()[DelegationsActionKey.Create] ??
@@ -1010,6 +1043,9 @@ class DelegationsFacade {
1010
1043
  getAssigned(query = {}) {
1011
1044
  return this.store.dispatch(new GetAssignedDelegations(query));
1012
1045
  }
1046
+ getAdmin(query = {}) {
1047
+ return this.store.dispatch(new GetAdminDelegations(query));
1048
+ }
1013
1049
  getActive(query = {}) {
1014
1050
  return this.store.dispatch(new GetActiveAssignedDelegations(query));
1015
1051
  }
@@ -1555,6 +1591,21 @@ class ScopePicker {
1555
1591
  timer = setTimeout(() => this.facade.previewScope(s), 300);
1556
1592
  });
1557
1593
  });
1594
+ let lastGroupKeys = '';
1595
+ effect(() => {
1596
+ const groups = this.groups();
1597
+ const nextGroupKeys = groups.map((group) => group.key).join('|');
1598
+ if (!nextGroupKeys) {
1599
+ lastGroupKeys = '';
1600
+ this.expanded.set(new Set());
1601
+ return;
1602
+ }
1603
+ if (nextGroupKeys === lastGroupKeys) {
1604
+ return;
1605
+ }
1606
+ lastGroupKeys = nextGroupKeys;
1607
+ this.expanded.set(new Set(groups.map((group) => group.key)));
1608
+ });
1558
1609
  }
1559
1610
  isExpanded(group) {
1560
1611
  return this.expanded().has(group.key);
@@ -1618,7 +1669,7 @@ class ScopePicker {
1618
1669
  return this.transloco.getActiveLang();
1619
1670
  }
1620
1671
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ScopePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
1621
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ScopePicker, isStandalone: true, selector: "mt-scope-picker", inputs: { scope: { classPropertyName: "scope", publicName: "scope", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, delegatorUserId: { classPropertyName: "delegatorUserId", publicName: "delegatorUserId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scope: "scopeChange" }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div class=\"mt-scope-picker flex flex-col gap-4\">\n @if (isLoadingOptions()) {\n <p-skeleton height=\"2rem\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n } @else {\n <section class=\"flex flex-col gap-2\">\n <h4 class=\"text-sm font-medium text-gray-800\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </h4>\n\n @if (errorOptions(); as errorMessage) {\n <div\n class=\"rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700\"\n >\n {{ errorMessage }}\n </div>\n }\n\n @if (groups().length === 0 && !errorOptions()) {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </p>\n }\n\n @for (group of groups(); track group.key) {\n <div class=\"overflow-hidden rounded-md border border-gray-200\">\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center justify-between px-3 py-2 hover:bg-surface-50\"\n (click)=\"toggleAccordion(group)\"\n >\n <div class=\"flex min-w-0 items-center gap-2\">\n <mt-icon\n [icon]=\"\n isExpanded(group)\n ? 'arrow.chevron-down'\n : 'arrow.chevron-right'\n \"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n <span class=\"truncate text-sm text-gray-900\">\n {{ getGroupLabel(group) }}\n </span>\n </div>\n @if (selectedCount(group); as selectedGrantCount) {\n @if (selectedGrantCount > 0) {\n <span\n class=\"rounded-full bg-primary-50 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ selectedGrantCount }}\n </span>\n }\n }\n </button>\n\n @if (isExpanded(group)) {\n <div\n class=\"mt-scope-picker__group flex flex-col gap-3 bg-surface-50/40 px-3 py-3\"\n >\n @for (targetGroup of group.targets; track targetGroup.key) {\n <section\n class=\"rounded-md border border-surface-200 bg-white px-3 py-3\"\n >\n <div\n class=\"flex flex-wrap items-center justify-between gap-2\"\n >\n <div class=\"min-w-0\">\n <div class=\"truncate text-sm font-medium text-gray-900\">\n {{ getTargetLabel(targetGroup.target) }}\n </div>\n </div>\n @if (\n selectedTargetCount(targetGroup);\n as selectedTargetGrantCount\n ) {\n @if (selectedTargetGrantCount > 0) {\n <span\n class=\"rounded-full bg-primary-50 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ selectedTargetGrantCount }}\n </span>\n }\n }\n </div>\n\n <div\n class=\"mt-scope-picker__actions mt-3 flex flex-col gap-1\"\n >\n @for (\n grant of getTargetActions(targetGroup);\n track $index\n ) {\n <label\n class=\"flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 hover:bg-surface-100\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(grant)\"\n [disabled]=\"readonly()\"\n (change)=\"toggleGrant(grant)\"\n />\n <span class=\"text-sm\">\n {{ getActionLabel(grant) }}\n </span>\n @if (grant.action.isHighRisk) {\n <mt-icon\n icon=\"alert.alert-triangle\"\n styleClass=\"text-sm text-amber-500\"\n [pTooltip]=\"t('delegations.scope.highRisk')\"\n tooltipPosition=\"top\"\n ></mt-icon>\n }\n </label>\n }\n </div>\n </section>\n } @empty {\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </div>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <section\n class=\"flex flex-col gap-1 rounded-md border border-dashed border-gray-300 bg-surface-50 px-3 py-2\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"text-xs font-medium text-gray-700\">\n {{ t(\"delegations.scope.previewTitle\") }}\n </div>\n @if (isPreviewing()) {\n <p-skeleton width=\"6rem\" height=\"0.75rem\"></p-skeleton>\n }\n </div>\n @if (preview(); as p) {\n @if (p.isValid) {\n <div class=\"text-sm text-gray-900\">\n {{\n getPreviewSummary(p.summary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n } @else {\n <div class=\"text-sm text-red-700\">\n {{ t(\"delegations.scope.previewInvalid\") }}\n </div>\n }\n @if (p.warnings.length > 0) {\n <ul class=\"list-inside list-disc text-xs text-amber-700\">\n @for (w of p.warnings; track w.message) {\n <li>{{ w.message }}</li>\n }\n </ul>\n }\n @if (p.deniedItems.length > 0) {\n <ul class=\"list-inside list-disc text-xs text-red-700\">\n @for (d of p.deniedItems; track d.operationKey) {\n <li>\n {{ formatDeniedTarget(d.targetKey) }} /\n {{ formatDeniedOperation(d.operationKey) }} -\n {{ d.reasonCode }}\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </div>\n }\n </section>\n }\n </div>\n</ng-container>\n", styles: [":host{display:block}.mt-scope-picker__group{border-top:1px solid color-mix(in srgb,var(--p-surface-200, #e5e7eb) 65%,transparent)}.mt-scope-picker input[type=checkbox]{accent-color:var(--p-primary-color, currentColor)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1672
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ScopePicker, isStandalone: true, selector: "mt-scope-picker", inputs: { scope: { classPropertyName: "scope", publicName: "scope", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, delegatorUserId: { classPropertyName: "delegatorUserId", publicName: "delegatorUserId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { scope: "scopeChange" }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div class=\"mt-scope-picker flex flex-col gap-4\">\n @if (isLoadingOptions()) {\n <p-skeleton height=\"2rem\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n } @else {\n <section class=\"flex flex-col gap-2\">\n @if (errorOptions(); as errorMessage) {\n <div\n class=\"rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700\"\n >\n {{ errorMessage }}\n </div>\n }\n\n @if (groups().length === 0 && !errorOptions()) {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </p>\n }\n\n @for (group of groups(); track group.key) {\n <div class=\"overflow-hidden rounded-md border border-gray-200\">\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center justify-between px-3 py-2 hover:bg-surface-50\"\n (click)=\"toggleAccordion(group)\"\n >\n <div class=\"flex min-w-0 items-center gap-2\">\n <mt-icon\n [icon]=\"\n isExpanded(group)\n ? 'arrow.chevron-down'\n : 'arrow.chevron-right'\n \"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n <span class=\"truncate text-sm text-gray-900\">\n {{ getGroupLabel(group) }}\n </span>\n </div>\n @if (selectedCount(group); as selectedGrantCount) {\n @if (selectedGrantCount > 0) {\n <span\n class=\"rounded-full bg-primary-50 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ selectedGrantCount }}\n </span>\n }\n }\n </button>\n\n @if (isExpanded(group)) {\n <div\n class=\"mt-scope-picker__group flex flex-col gap-3 bg-surface-50/40 px-3 py-3\"\n >\n @for (targetGroup of group.targets; track targetGroup.key) {\n <section\n class=\"rounded-md border border-surface-200 bg-white px-3 py-3\"\n >\n <div\n class=\"flex flex-wrap items-center justify-between gap-2\"\n >\n <div class=\"min-w-0\">\n <div class=\"truncate text-sm font-medium text-gray-900\">\n {{ getTargetLabel(targetGroup.target) }}\n </div>\n </div>\n @if (\n selectedTargetCount(targetGroup);\n as selectedTargetGrantCount\n ) {\n @if (selectedTargetGrantCount > 0) {\n <span\n class=\"rounded-full bg-primary-50 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ selectedTargetGrantCount }}\n </span>\n }\n }\n </div>\n\n <div\n class=\"mt-scope-picker__actions mt-3 flex flex-col gap-1\"\n >\n @for (\n grant of getTargetActions(targetGroup);\n track $index\n ) {\n <label\n class=\"flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 hover:bg-surface-100\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(grant)\"\n [disabled]=\"readonly()\"\n (change)=\"toggleGrant(grant)\"\n />\n <span class=\"text-sm\">\n {{ getActionLabel(grant) }}\n </span>\n @if (grant.action.isHighRisk) {\n <mt-icon\n icon=\"alert.alert-triangle\"\n styleClass=\"text-sm text-amber-500\"\n [pTooltip]=\"t('delegations.scope.highRisk')\"\n tooltipPosition=\"top\"\n ></mt-icon>\n }\n </label>\n }\n </div>\n </section>\n } @empty {\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </div>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <section\n class=\"flex flex-col gap-1 rounded-md border border-dashed border-gray-300 bg-surface-50 px-3 py-2\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"text-xs font-medium text-gray-700\">\n {{ t(\"delegations.scope.previewTitle\") }}\n </div>\n @if (isPreviewing()) {\n <p-skeleton width=\"6rem\" height=\"0.75rem\"></p-skeleton>\n }\n </div>\n @if (preview(); as p) {\n @if (p.isValid) {\n <div class=\"text-sm text-gray-900\">\n {{\n getPreviewSummary(p.summary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n } @else {\n <div class=\"text-sm text-red-700\">\n {{ t(\"delegations.scope.previewInvalid\") }}\n </div>\n }\n @if (p.warnings.length > 0) {\n <ul class=\"list-inside list-disc text-xs text-amber-700\">\n @for (w of p.warnings; track w.message) {\n <li>{{ w.message }}</li>\n }\n </ul>\n }\n @if (p.deniedItems.length > 0) {\n <ul class=\"list-inside list-disc text-xs text-red-700\">\n @for (d of p.deniedItems; track d.operationKey) {\n <li>\n {{ formatDeniedTarget(d.targetKey) }} /\n {{ formatDeniedOperation(d.operationKey) }} -\n {{ d.reasonCode }}\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </div>\n }\n </section>\n }\n </div>\n</ng-container>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1622
1673
  }
1623
1674
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ScopePicker, decorators: [{
1624
1675
  type: Component,
@@ -1628,10 +1679,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1628
1679
  SkeletonModule,
1629
1680
  TooltipModule,
1630
1681
  TranslocoDirective,
1631
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div class=\"mt-scope-picker flex flex-col gap-4\">\n @if (isLoadingOptions()) {\n <p-skeleton height=\"2rem\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n } @else {\n <section class=\"flex flex-col gap-2\">\n <h4 class=\"text-sm font-medium text-gray-800\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </h4>\n\n @if (errorOptions(); as errorMessage) {\n <div\n class=\"rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700\"\n >\n {{ errorMessage }}\n </div>\n }\n\n @if (groups().length === 0 && !errorOptions()) {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </p>\n }\n\n @for (group of groups(); track group.key) {\n <div class=\"overflow-hidden rounded-md border border-gray-200\">\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center justify-between px-3 py-2 hover:bg-surface-50\"\n (click)=\"toggleAccordion(group)\"\n >\n <div class=\"flex min-w-0 items-center gap-2\">\n <mt-icon\n [icon]=\"\n isExpanded(group)\n ? 'arrow.chevron-down'\n : 'arrow.chevron-right'\n \"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n <span class=\"truncate text-sm text-gray-900\">\n {{ getGroupLabel(group) }}\n </span>\n </div>\n @if (selectedCount(group); as selectedGrantCount) {\n @if (selectedGrantCount > 0) {\n <span\n class=\"rounded-full bg-primary-50 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ selectedGrantCount }}\n </span>\n }\n }\n </button>\n\n @if (isExpanded(group)) {\n <div\n class=\"mt-scope-picker__group flex flex-col gap-3 bg-surface-50/40 px-3 py-3\"\n >\n @for (targetGroup of group.targets; track targetGroup.key) {\n <section\n class=\"rounded-md border border-surface-200 bg-white px-3 py-3\"\n >\n <div\n class=\"flex flex-wrap items-center justify-between gap-2\"\n >\n <div class=\"min-w-0\">\n <div class=\"truncate text-sm font-medium text-gray-900\">\n {{ getTargetLabel(targetGroup.target) }}\n </div>\n </div>\n @if (\n selectedTargetCount(targetGroup);\n as selectedTargetGrantCount\n ) {\n @if (selectedTargetGrantCount > 0) {\n <span\n class=\"rounded-full bg-primary-50 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ selectedTargetGrantCount }}\n </span>\n }\n }\n </div>\n\n <div\n class=\"mt-scope-picker__actions mt-3 flex flex-col gap-1\"\n >\n @for (\n grant of getTargetActions(targetGroup);\n track $index\n ) {\n <label\n class=\"flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 hover:bg-surface-100\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(grant)\"\n [disabled]=\"readonly()\"\n (change)=\"toggleGrant(grant)\"\n />\n <span class=\"text-sm\">\n {{ getActionLabel(grant) }}\n </span>\n @if (grant.action.isHighRisk) {\n <mt-icon\n icon=\"alert.alert-triangle\"\n styleClass=\"text-sm text-amber-500\"\n [pTooltip]=\"t('delegations.scope.highRisk')\"\n tooltipPosition=\"top\"\n ></mt-icon>\n }\n </label>\n }\n </div>\n </section>\n } @empty {\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </div>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <section\n class=\"flex flex-col gap-1 rounded-md border border-dashed border-gray-300 bg-surface-50 px-3 py-2\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"text-xs font-medium text-gray-700\">\n {{ t(\"delegations.scope.previewTitle\") }}\n </div>\n @if (isPreviewing()) {\n <p-skeleton width=\"6rem\" height=\"0.75rem\"></p-skeleton>\n }\n </div>\n @if (preview(); as p) {\n @if (p.isValid) {\n <div class=\"text-sm text-gray-900\">\n {{\n getPreviewSummary(p.summary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n } @else {\n <div class=\"text-sm text-red-700\">\n {{ t(\"delegations.scope.previewInvalid\") }}\n </div>\n }\n @if (p.warnings.length > 0) {\n <ul class=\"list-inside list-disc text-xs text-amber-700\">\n @for (w of p.warnings; track w.message) {\n <li>{{ w.message }}</li>\n }\n </ul>\n }\n @if (p.deniedItems.length > 0) {\n <ul class=\"list-inside list-disc text-xs text-red-700\">\n @for (d of p.deniedItems; track d.operationKey) {\n <li>\n {{ formatDeniedTarget(d.targetKey) }} /\n {{ formatDeniedOperation(d.operationKey) }} -\n {{ d.reasonCode }}\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </div>\n }\n </section>\n }\n </div>\n</ng-container>\n", styles: [":host{display:block}.mt-scope-picker__group{border-top:1px solid color-mix(in srgb,var(--p-surface-200, #e5e7eb) 65%,transparent)}.mt-scope-picker input[type=checkbox]{accent-color:var(--p-primary-color, currentColor)}\n"] }]
1682
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div class=\"mt-scope-picker flex flex-col gap-4\">\n @if (isLoadingOptions()) {\n <p-skeleton height=\"2rem\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n } @else {\n <section class=\"flex flex-col gap-2\">\n @if (errorOptions(); as errorMessage) {\n <div\n class=\"rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700\"\n >\n {{ errorMessage }}\n </div>\n }\n\n @if (groups().length === 0 && !errorOptions()) {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </p>\n }\n\n @for (group of groups(); track group.key) {\n <div class=\"overflow-hidden rounded-md border border-gray-200\">\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center justify-between px-3 py-2 hover:bg-surface-50\"\n (click)=\"toggleAccordion(group)\"\n >\n <div class=\"flex min-w-0 items-center gap-2\">\n <mt-icon\n [icon]=\"\n isExpanded(group)\n ? 'arrow.chevron-down'\n : 'arrow.chevron-right'\n \"\n styleClass=\"text-base text-gray-400\"\n ></mt-icon>\n <span class=\"truncate text-sm text-gray-900\">\n {{ getGroupLabel(group) }}\n </span>\n </div>\n @if (selectedCount(group); as selectedGrantCount) {\n @if (selectedGrantCount > 0) {\n <span\n class=\"rounded-full bg-primary-50 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ selectedGrantCount }}\n </span>\n }\n }\n </button>\n\n @if (isExpanded(group)) {\n <div\n class=\"mt-scope-picker__group flex flex-col gap-3 bg-surface-50/40 px-3 py-3\"\n >\n @for (targetGroup of group.targets; track targetGroup.key) {\n <section\n class=\"rounded-md border border-surface-200 bg-white px-3 py-3\"\n >\n <div\n class=\"flex flex-wrap items-center justify-between gap-2\"\n >\n <div class=\"min-w-0\">\n <div class=\"truncate text-sm font-medium text-gray-900\">\n {{ getTargetLabel(targetGroup.target) }}\n </div>\n </div>\n @if (\n selectedTargetCount(targetGroup);\n as selectedTargetGrantCount\n ) {\n @if (selectedTargetGrantCount > 0) {\n <span\n class=\"rounded-full bg-primary-50 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {{ selectedTargetGrantCount }}\n </span>\n }\n }\n </div>\n\n <div\n class=\"mt-scope-picker__actions mt-3 flex flex-col gap-1\"\n >\n @for (\n grant of getTargetActions(targetGroup);\n track $index\n ) {\n <label\n class=\"flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 hover:bg-surface-100\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(grant)\"\n [disabled]=\"readonly()\"\n (change)=\"toggleGrant(grant)\"\n />\n <span class=\"text-sm\">\n {{ getActionLabel(grant) }}\n </span>\n @if (grant.action.isHighRisk) {\n <mt-icon\n icon=\"alert.alert-triangle\"\n styleClass=\"text-sm text-amber-500\"\n [pTooltip]=\"t('delegations.scope.highRisk')\"\n tooltipPosition=\"top\"\n ></mt-icon>\n }\n </label>\n }\n </div>\n </section>\n } @empty {\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </div>\n }\n </div>\n }\n </div>\n }\n </section>\n\n <section\n class=\"flex flex-col gap-1 rounded-md border border-dashed border-gray-300 bg-surface-50 px-3 py-2\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"text-xs font-medium text-gray-700\">\n {{ t(\"delegations.scope.previewTitle\") }}\n </div>\n @if (isPreviewing()) {\n <p-skeleton width=\"6rem\" height=\"0.75rem\"></p-skeleton>\n }\n </div>\n @if (preview(); as p) {\n @if (p.isValid) {\n <div class=\"text-sm text-gray-900\">\n {{\n getPreviewSummary(p.summary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n } @else {\n <div class=\"text-sm text-red-700\">\n {{ t(\"delegations.scope.previewInvalid\") }}\n </div>\n }\n @if (p.warnings.length > 0) {\n <ul class=\"list-inside list-disc text-xs text-amber-700\">\n @for (w of p.warnings; track w.message) {\n <li>{{ w.message }}</li>\n }\n </ul>\n }\n @if (p.deniedItems.length > 0) {\n <ul class=\"list-inside list-disc text-xs text-red-700\">\n @for (d of p.deniedItems; track d.operationKey) {\n <li>\n {{ formatDeniedTarget(d.targetKey) }} /\n {{ formatDeniedOperation(d.operationKey) }} -\n {{ d.reasonCode }}\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </div>\n }\n </section>\n }\n </div>\n</ng-container>\n", styles: [":host{display:block}\n"] }]
1632
1683
  }], ctorParameters: () => [], propDecorators: { scope: [{ type: i0.Input, args: [{ isSignal: true, alias: "scope", required: false }] }, { type: i0.Output, args: ["scopeChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], delegatorUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "delegatorUserId", required: false }] }] } });
1633
1684
 
1634
1685
  const EMPTY_SCOPE = { grants: [], metadata: {} };
1686
+ function getCurrentDelegatorFromLocalStorage() {
1687
+ if (typeof localStorage === 'undefined') {
1688
+ return null;
1689
+ }
1690
+ try {
1691
+ const raw = localStorage.getItem('auth');
1692
+ if (!raw)
1693
+ return null;
1694
+ const parsed = JSON.parse(raw);
1695
+ if (!parsed || typeof parsed !== 'object')
1696
+ return null;
1697
+ const state = (parsed['state'] ?? parsed) ||
1698
+ null;
1699
+ const userWrapper = state?.['user'];
1700
+ const user = userWrapper?.['user'] ??
1701
+ userWrapper;
1702
+ if (!user || typeof user !== 'object')
1703
+ return null;
1704
+ const id = user['id'] ??
1705
+ user['userId'];
1706
+ if (!id)
1707
+ return null;
1708
+ const photo = user['photo'];
1709
+ const photoPath = typeof photo === 'string'
1710
+ ? photo
1711
+ : (photo?.fileName ?? null);
1712
+ return {
1713
+ id,
1714
+ userId: id,
1715
+ displayName: user['displayName'] ??
1716
+ user['name'] ??
1717
+ user['userName'] ??
1718
+ '',
1719
+ userName: user['userName'] ?? '',
1720
+ email: user['email'] ?? null,
1721
+ photo: photoPath,
1722
+ isExternal: !!user['isExternal'],
1723
+ };
1724
+ }
1725
+ catch {
1726
+ return null;
1727
+ }
1728
+ }
1635
1729
  function extractUserId(value) {
1636
1730
  if (typeof value === 'string') {
1637
1731
  return value.trim() || undefined;
@@ -1680,13 +1774,15 @@ class DelegationForm {
1680
1774
  isSaving = this.facade.isSaving;
1681
1775
  context = new HttpContext().set(REQUEST_CONTEXT, { useBaseUrl: false });
1682
1776
  scope = signal(EMPTY_SCOPE, ...(ngDevMode ? [{ debugName: "scope" }] : /* istanbul ignore next */ []));
1683
- /** Selected delegator id (admin mode only); drives scope/options + create payload. */
1777
+ currentDelegator = signal(getCurrentDelegatorFromLocalStorage(), ...(ngDevMode ? [{ debugName: "currentDelegator" }] : /* istanbul ignore next */ []));
1778
+ /** Selected delegator id drives scope/options loading and the admin payload. */
1684
1779
  selectedDelegatorId = computed(() => {
1685
- if (!this.adminMode())
1686
- return undefined;
1687
- return extractUserId(this.formValue()?.delegateFrom);
1780
+ if (this.adminMode()) {
1781
+ return extractUserId(this.formValue()?.delegateFrom);
1782
+ }
1783
+ return this.currentDelegator()?.id;
1688
1784
  }, ...(ngDevMode ? [{ debugName: "selectedDelegatorId" }] : /* istanbul ignore next */ []));
1689
- /** In admin mode the scope picker only loads once a delegator is chosen. */
1785
+ /** Admin mode waits for a chosen delegator; self-service always has one. */
1690
1786
  showScopePicker = computed(() => !this.adminMode() || !!this.selectedDelegatorId(), ...(ngDevMode ? [{ debugName: "showScopePicker" }] : /* istanbul ignore next */ []));
1691
1787
  specificDaysOptions = signal([
1692
1788
  { label: this.transloco.translate('delegations.days.sunday'), value: 0 },
@@ -1705,21 +1801,19 @@ class DelegationForm {
1705
1801
  bodyClass: 'grid grid-cols-1 gap-4 items-start lg:grid-cols-12',
1706
1802
  order: 1,
1707
1803
  fields: [
1708
- ...(this.adminMode()
1709
- ? [
1710
- new UserSearchFieldConfig({
1711
- key: 'delegateFrom',
1712
- label: this.transloco.translate('delegations.column.delegatorName'),
1713
- apiUrl: 'Identity/users',
1714
- context: this.context,
1715
- validators: [ValidatorConfig.required()],
1716
- cssClass: this.halfWidth,
1717
- colSpan: 6,
1718
- order: 0,
1719
- disabled: this.readonly() || !!this.delegationForEdit(),
1720
- }),
1721
- ]
1722
- : []),
1804
+ new UserSearchFieldConfig({
1805
+ key: 'delegateFrom',
1806
+ label: this.transloco.translate('delegations.column.delegatorName'),
1807
+ apiUrl: 'Identity/users',
1808
+ context: this.context,
1809
+ validators: [ValidatorConfig.required()],
1810
+ cssClass: this.halfWidth,
1811
+ colSpan: 6,
1812
+ order: 0,
1813
+ disabled: this.readonly() ||
1814
+ !this.adminMode() ||
1815
+ !!this.delegationForEdit(),
1816
+ }),
1723
1817
  new UserSearchFieldConfig({
1724
1818
  key: 'delegateTo',
1725
1819
  label: this.transloco.translate('delegations.column.delegatedTo'),
@@ -1819,6 +1913,7 @@ class DelegationForm {
1819
1913
  const d = this.detail();
1820
1914
  if (editing && d && d.row.delegationId === editing.delegationId) {
1821
1915
  this.delegationFormControl.patchValue({
1916
+ delegateFrom: this.mapPartyToUserValue(d.row.delegator),
1822
1917
  delegateTo: d.row.delegatedUser,
1823
1918
  description: '',
1824
1919
  delegateFromDateTime: d.row.startsAtUtc,
@@ -1834,12 +1929,26 @@ class DelegationForm {
1834
1929
  }
1835
1930
  else if (!editing) {
1836
1931
  this.delegationFormControl.reset({
1932
+ delegateFrom: null,
1837
1933
  delegationDaysType: 'FullRange',
1838
1934
  requiresApproval: true,
1839
1935
  });
1840
1936
  this.scope.set(EMPTY_SCOPE);
1841
1937
  }
1842
1938
  });
1939
+ effect(() => {
1940
+ const currentDelegator = this.currentDelegator();
1941
+ if (this.adminMode() || this.delegationForEdit() || !currentDelegator) {
1942
+ return;
1943
+ }
1944
+ const existingDelegator = extractUserId(this.delegationFormControl.getRawValue()?.delegateFrom);
1945
+ if (existingDelegator === currentDelegator.id) {
1946
+ return;
1947
+ }
1948
+ this.delegationFormControl.patchValue({
1949
+ delegateFrom: currentDelegator,
1950
+ });
1951
+ });
1843
1952
  }
1844
1953
  ngOnInit() {
1845
1954
  const editing = this.delegationForEdit();
@@ -1893,8 +2002,19 @@ class DelegationForm {
1893
2002
  });
1894
2003
  }
1895
2004
  }
2005
+ mapPartyToUserValue(party) {
2006
+ return {
2007
+ id: party.userId,
2008
+ userId: party.userId,
2009
+ displayName: party.displayName,
2010
+ userName: party.email || party.displayName,
2011
+ email: party.email ?? null,
2012
+ photo: null,
2013
+ isExternal: false,
2014
+ };
2015
+ }
1896
2016
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
1897
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationForm, isStandalone: true, selector: "mt-delegation-form", inputs: { delegationForEdit: { classPropertyName: "delegationForEdit", publicName: "delegationForEdit", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, adminMode: { classPropertyName: "adminMode", publicName: "adminMode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n 'delegation-form-content flex min-w-0 flex-col gap-3 overflow-x-hidden p-4 max-[640px]:p-3 ' +\n modal.contentClass\n \"\n >\n <mt-dynamic-form\n [formConfig]=\"formConfig()\"\n [formControl]=\"delegationFormControl\"\n />\n\n <div class=\"mt-2 border-t border-gray-200 pt-3 flex flex-col gap-2\">\n <h3 class=\"text-sm font-semibold text-gray-800\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </h3>\n @if (showScopePicker()) {\n <mt-scope-picker\n [(scope)]=\"scope\"\n [readonly]=\"readonly()\"\n [delegatorUserId]=\"selectedDelegatorId()\"\n ></mt-scope-picker>\n } @else {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </p>\n }\n </div>\n </div>\n\n <div\n [class]=\"\n 'delegation-form-footer ' +\n modal.footerClass +\n ' flex-col gap-2 sm:flex-row sm:items-center sm:justify-end'\n \"\n >\n <mt-button\n [label]=\"t('delegations.common.cancel')\"\n variant=\"outlined\"\n (click)=\"ref.close()\"\n styleClass=\"w-full sm:w-auto\"\n />\n @if (!readonly()) {\n <mt-button\n [label]=\"\n delegationForEdit()\n ? t('delegations.common.update')\n : t('delegations.common.create')\n \"\n [loading]=\"isSaving()\"\n [disabled]=\"!delegationFormControl.valid || !canSubmit()\"\n (click)=\"onSubmit()\"\n styleClass=\"w-full sm:w-auto\"\n />\n }\n </div>\n</ng-container>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ScopePicker, selector: "mt-scope-picker", inputs: ["scope", "readonly", "delegatorUserId"], outputs: ["scopeChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2017
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationForm, isStandalone: true, selector: "mt-delegation-form", inputs: { delegationForEdit: { classPropertyName: "delegationForEdit", publicName: "delegationForEdit", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, adminMode: { classPropertyName: "adminMode", publicName: "adminMode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n 'delegation-form-content flex min-w-0 flex-col gap-4 overflow-x-hidden p-4 max-[640px]:p-3 ' +\n modal.contentClass\n \"\n >\n <section class=\"delegation-form-section\">\n <mt-dynamic-form\n [formConfig]=\"formConfig()\"\n [formControl]=\"delegationFormControl\"\n />\n </section>\n\n <section class=\"delegation-form-section delegation-form-section--scope\">\n <header class=\"delegation-form-section__header\">\n <h3 class=\"delegation-form-section__title\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </h3>\n @if (adminMode() && !showScopePicker()) {\n <p class=\"delegation-form-section__subtitle\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </p>\n }\n </header>\n\n @if (showScopePicker()) {\n <mt-scope-picker\n [(scope)]=\"scope\"\n [readonly]=\"readonly()\"\n [delegatorUserId]=\"selectedDelegatorId()\"\n ></mt-scope-picker>\n } @else {\n <div class=\"delegation-form-section__empty\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </div>\n }\n </section>\n </div>\n\n <div\n [class]=\"\n 'delegation-form-footer ' +\n modal.footerClass +\n ' flex-col gap-2 sm:flex-row sm:items-center sm:justify-end'\n \"\n >\n <mt-button\n [label]=\"t('delegations.common.cancel')\"\n variant=\"outlined\"\n (click)=\"ref.close()\"\n styleClass=\"w-full sm:w-auto\"\n />\n @if (!readonly()) {\n <mt-button\n [label]=\"\n delegationForEdit()\n ? t('delegations.common.update')\n : t('delegations.common.create')\n \"\n [loading]=\"isSaving()\"\n [disabled]=\"!delegationFormControl.valid || !canSubmit()\"\n (click)=\"onSubmit()\"\n styleClass=\"w-full sm:w-auto\"\n />\n }\n </div>\n</ng-container>\n", styles: [":host{display:block}.delegation-form-section{display:flex;flex-direction:column;gap:1rem;border:1px solid var(--p-surface-200, #e5e7eb);border-radius:1rem;background:color-mix(in srgb,var(--p-surface-0, #ffffff) 92%,var(--p-primary-50, #eff6ff));padding:1rem}.delegation-form-section--scope{gap:.75rem}.delegation-form-section__header{display:flex;flex-direction:column;gap:.25rem}.delegation-form-section__title{margin:0;font-size:.95rem;font-weight:600;color:var(--p-surface-900, #111827)}.delegation-form-section__subtitle{margin:0;font-size:.8rem;color:var(--p-surface-500, #6b7280)}.delegation-form-section__empty{border:1px dashed var(--p-surface-300, #d1d5db);border-radius:.875rem;background:var(--p-surface-50, #f8fafc);padding:.875rem 1rem;font-size:.85rem;color:var(--p-surface-500, #6b7280)}@media(max-width:640px){.delegation-form-section{border-radius:.875rem;padding:.875rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DynamicForm, selector: "mt-dynamic-form", inputs: ["formConfig", "forcedHiddenFieldKeys", "preserveForcedHiddenValues", "visibleSectionKeys"], outputs: ["runtimeMessagesChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ScopePicker, selector: "mt-scope-picker", inputs: ["scope", "readonly", "delegatorUserId"], outputs: ["scopeChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1898
2018
  }
1899
2019
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationForm, decorators: [{
1900
2020
  type: Component,
@@ -1905,7 +2025,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1905
2025
  ReactiveFormsModule,
1906
2026
  ScopePicker,
1907
2027
  TranslocoDirective,
1908
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n 'delegation-form-content flex min-w-0 flex-col gap-3 overflow-x-hidden p-4 max-[640px]:p-3 ' +\n modal.contentClass\n \"\n >\n <mt-dynamic-form\n [formConfig]=\"formConfig()\"\n [formControl]=\"delegationFormControl\"\n />\n\n <div class=\"mt-2 border-t border-gray-200 pt-3 flex flex-col gap-2\">\n <h3 class=\"text-sm font-semibold text-gray-800\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </h3>\n @if (showScopePicker()) {\n <mt-scope-picker\n [(scope)]=\"scope\"\n [readonly]=\"readonly()\"\n [delegatorUserId]=\"selectedDelegatorId()\"\n ></mt-scope-picker>\n } @else {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </p>\n }\n </div>\n </div>\n\n <div\n [class]=\"\n 'delegation-form-footer ' +\n modal.footerClass +\n ' flex-col gap-2 sm:flex-row sm:items-center sm:justify-end'\n \"\n >\n <mt-button\n [label]=\"t('delegations.common.cancel')\"\n variant=\"outlined\"\n (click)=\"ref.close()\"\n styleClass=\"w-full sm:w-auto\"\n />\n @if (!readonly()) {\n <mt-button\n [label]=\"\n delegationForEdit()\n ? t('delegations.common.update')\n : t('delegations.common.create')\n \"\n [loading]=\"isSaving()\"\n [disabled]=\"!delegationFormControl.valid || !canSubmit()\"\n (click)=\"onSubmit()\"\n styleClass=\"w-full sm:w-auto\"\n />\n }\n </div>\n</ng-container>\n" }]
2028
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n 'delegation-form-content flex min-w-0 flex-col gap-4 overflow-x-hidden p-4 max-[640px]:p-3 ' +\n modal.contentClass\n \"\n >\n <section class=\"delegation-form-section\">\n <mt-dynamic-form\n [formConfig]=\"formConfig()\"\n [formControl]=\"delegationFormControl\"\n />\n </section>\n\n <section class=\"delegation-form-section delegation-form-section--scope\">\n <header class=\"delegation-form-section__header\">\n <h3 class=\"delegation-form-section__title\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </h3>\n @if (adminMode() && !showScopePicker()) {\n <p class=\"delegation-form-section__subtitle\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </p>\n }\n </header>\n\n @if (showScopePicker()) {\n <mt-scope-picker\n [(scope)]=\"scope\"\n [readonly]=\"readonly()\"\n [delegatorUserId]=\"selectedDelegatorId()\"\n ></mt-scope-picker>\n } @else {\n <div class=\"delegation-form-section__empty\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </div>\n }\n </section>\n </div>\n\n <div\n [class]=\"\n 'delegation-form-footer ' +\n modal.footerClass +\n ' flex-col gap-2 sm:flex-row sm:items-center sm:justify-end'\n \"\n >\n <mt-button\n [label]=\"t('delegations.common.cancel')\"\n variant=\"outlined\"\n (click)=\"ref.close()\"\n styleClass=\"w-full sm:w-auto\"\n />\n @if (!readonly()) {\n <mt-button\n [label]=\"\n delegationForEdit()\n ? t('delegations.common.update')\n : t('delegations.common.create')\n \"\n [loading]=\"isSaving()\"\n [disabled]=\"!delegationFormControl.valid || !canSubmit()\"\n (click)=\"onSubmit()\"\n styleClass=\"w-full sm:w-auto\"\n />\n }\n </div>\n</ng-container>\n", styles: [":host{display:block}.delegation-form-section{display:flex;flex-direction:column;gap:1rem;border:1px solid var(--p-surface-200, #e5e7eb);border-radius:1rem;background:color-mix(in srgb,var(--p-surface-0, #ffffff) 92%,var(--p-primary-50, #eff6ff));padding:1rem}.delegation-form-section--scope{gap:.75rem}.delegation-form-section__header{display:flex;flex-direction:column;gap:.25rem}.delegation-form-section__title{margin:0;font-size:.95rem;font-weight:600;color:var(--p-surface-900, #111827)}.delegation-form-section__subtitle{margin:0;font-size:.8rem;color:var(--p-surface-500, #6b7280)}.delegation-form-section__empty{border:1px dashed var(--p-surface-300, #d1d5db);border-radius:.875rem;background:var(--p-surface-50, #f8fafc);padding:.875rem 1rem;font-size:.85rem;color:var(--p-surface-500, #6b7280)}@media(max-width:640px){.delegation-form-section{border-radius:.875rem;padding:.875rem}}\n"] }]
1909
2029
  }], ctorParameters: () => [], propDecorators: { delegationForEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "delegationForEdit", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], adminMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "adminMode", required: false }] }] } });
1910
2030
 
1911
2031
  /**
@@ -1978,6 +2098,11 @@ class DelegationsList {
1978
2098
  * `withComponentInputBinding()` — admin passes `data: { adminMode: true }`.
1979
2099
  */
1980
2100
  adminMode = input(false, ...(ngDevMode ? [{ debugName: "adminMode" }] : /* istanbul ignore next */ []));
2101
+ surfaceTitleKey = input('delegations.title', ...(ngDevMode ? [{ debugName: "surfaceTitleKey" }] : /* istanbul ignore next */ []));
2102
+ assignedTabLabelKey = input('delegations.delegatedToMe', ...(ngDevMode ? [{ debugName: "assignedTabLabelKey" }] : /* istanbul ignore next */ []));
2103
+ assignedDecisionTab = input(false, ...(ngDevMode ? [{ debugName: "assignedDecisionTab" }] : /* istanbul ignore next */ []));
2104
+ assignedEmptyStateKey = input('delegations.empty.assigned', ...(ngDevMode ? [{ debugName: "assignedEmptyStateKey" }] : /* istanbul ignore next */ []));
2105
+ assignedStatus = input(null, ...(ngDevMode ? [{ debugName: "assignedStatus" }] : /* istanbul ignore next */ []));
1981
2106
  facade = inject(DelegationsFacade);
1982
2107
  modal = inject(ModalService);
1983
2108
  transloco = inject(TranslocoService);
@@ -1996,25 +2121,39 @@ class DelegationsList {
1996
2121
  },
1997
2122
  ], ...(ngDevMode ? [{ debugName: "breadcrumbItems" }] : /* istanbul ignore next */ []));
1998
2123
  activeTab = signal('my', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
1999
- tabs = signal([
2124
+ surfaceTitle = computed(() => this.transloco.translate(this.surfaceTitleKey()), ...(ngDevMode ? [{ debugName: "surfaceTitle" }] : /* istanbul ignore next */ []));
2125
+ tabs = computed(() => [
2000
2126
  {
2001
2127
  value: 'my',
2002
2128
  label: this.transloco.translate('delegations.myDelegations'),
2003
2129
  },
2004
2130
  {
2005
2131
  value: 'assigned',
2006
- label: this.transloco.translate('delegations.delegatedToMe'),
2132
+ label: this.assignedDecisionTab()
2133
+ ? `${this.transloco.translate('delegations.action.approve')} / ${this.transloco.translate('delegations.action.reject')}`
2134
+ : this.transloco.translate(this.assignedTabLabelKey()),
2007
2135
  },
2008
2136
  ], ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
2009
- isLoading = computed(() => this.activeTab() === 'my'
2010
- ? this.facade.isLoadingMy()
2011
- : this.facade.isLoadingAssigned(), ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
2137
+ isLoading = computed(() => this.adminMode()
2138
+ ? this.facade.isLoadingAdmin()
2139
+ : this.activeTab() === 'my'
2140
+ ? this.facade.isLoadingMy()
2141
+ : this.facade.isLoadingAssigned(), ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
2012
2142
  scopeOptions = this.facade.scopeOptions;
2013
- rows = computed(() => this.activeTab() === 'my'
2014
- ? this.facade.myItems()
2015
- : this.facade.assignedItems(), ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
2143
+ rows = computed(() => this.adminMode()
2144
+ ? this.facade.adminItems()
2145
+ : this.activeTab() === 'my'
2146
+ ? this.facade.myItems()
2147
+ : this.facade.assignedItems(), ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
2148
+ emptyStateKey = computed(() => this.adminMode()
2149
+ ? 'components.table.no-data-found'
2150
+ : this.activeTab() === 'my'
2151
+ ? 'delegations.empty.my'
2152
+ : this.assignedEmptyStateKey(), ...(ngDevMode ? [{ debugName: "emptyStateKey" }] : /* istanbul ignore next */ []));
2016
2153
  statusCol = viewChild.required('statusCol');
2017
2154
  userCol = viewChild.required('userCol');
2155
+ delegatorCol = viewChild.required('delegatorCol');
2156
+ delegatedUserCol = viewChild.required('delegatedUserCol');
2018
2157
  scopeCol = viewChild.required('scopeCol');
2019
2158
  daysCol = viewChild.required('daysCol');
2020
2159
  canCreate = computed(() => {
@@ -2084,56 +2223,80 @@ class DelegationsList {
2084
2223
  hidden: (row) => !this.has(row, 'StartSession'),
2085
2224
  },
2086
2225
  ], ...(ngDevMode ? [{ debugName: "rowActions" }] : /* istanbul ignore next */ []));
2087
- tableColumns = linkedSignal(() => [
2088
- {
2089
- key: 'effectiveStatus',
2090
- label: this.transloco.translate('delegations.column.status'),
2091
- type: 'custom',
2092
- customCellTpl: this.statusCol(),
2093
- width: '10rem',
2094
- },
2095
- {
2096
- key: this.activeTab() === 'my' ? 'delegatedUser' : 'delegator',
2097
- label: this.transloco.translate(this.activeTab() === 'my'
2098
- ? 'delegations.column.delegatedTo'
2099
- : 'delegations.column.delegatorName'),
2100
- type: 'custom',
2101
- customCellTpl: this.userCol(),
2102
- width: '16rem',
2103
- },
2104
- {
2105
- key: 'scopeSummary',
2106
- label: this.transloco.translate('delegations.column.scopeSummary'),
2107
- type: 'custom',
2108
- customCellTpl: this.scopeCol(),
2109
- width: '16rem',
2110
- },
2111
- {
2112
- key: 'startsAtUtc',
2113
- label: this.transloco.translate('delegations.column.startDate'),
2114
- type: 'dateTime',
2115
- width: '11rem',
2116
- },
2117
- {
2118
- key: 'endsAtUtc',
2119
- label: this.transloco.translate('delegations.column.endDate'),
2120
- type: 'dateTime',
2121
- width: '11rem',
2122
- },
2123
- {
2124
- key: 'createdAtUtc',
2125
- label: this.transloco.translate('delegations.column.createdDate'),
2126
- type: 'dateTime',
2127
- width: '11rem',
2128
- },
2129
- {
2130
- key: 'dayRuleMode',
2131
- label: this.transloco.translate('delegations.column.days'),
2132
- type: 'custom',
2133
- customCellTpl: this.daysCol(),
2134
- width: '12rem',
2135
- },
2136
- ], ...(ngDevMode ? [{ debugName: "tableColumns" }] : /* istanbul ignore next */ []));
2226
+ tableColumns = linkedSignal(() => {
2227
+ const baseColumns = [
2228
+ {
2229
+ key: 'effectiveStatus',
2230
+ label: this.transloco.translate('delegations.column.status'),
2231
+ type: 'custom',
2232
+ customCellTpl: this.statusCol(),
2233
+ width: '10rem',
2234
+ },
2235
+ {
2236
+ key: 'scopeSummary',
2237
+ label: this.transloco.translate('delegations.column.scopeSummary'),
2238
+ type: 'custom',
2239
+ customCellTpl: this.scopeCol(),
2240
+ width: '18rem',
2241
+ },
2242
+ {
2243
+ key: 'startsAtUtc',
2244
+ label: this.transloco.translate('delegations.column.startDate'),
2245
+ type: 'dateTime',
2246
+ width: '11rem',
2247
+ },
2248
+ {
2249
+ key: 'endsAtUtc',
2250
+ label: this.transloco.translate('delegations.column.endDate'),
2251
+ type: 'dateTime',
2252
+ width: '11rem',
2253
+ },
2254
+ {
2255
+ key: 'createdAtUtc',
2256
+ label: this.transloco.translate('delegations.column.createdDate'),
2257
+ type: 'dateTime',
2258
+ width: '11rem',
2259
+ },
2260
+ {
2261
+ key: 'dayRuleMode',
2262
+ label: this.transloco.translate('delegations.column.days'),
2263
+ type: 'custom',
2264
+ customCellTpl: this.daysCol(),
2265
+ width: '12rem',
2266
+ },
2267
+ ];
2268
+ if (this.adminMode()) {
2269
+ return [
2270
+ {
2271
+ key: 'delegator',
2272
+ label: this.transloco.translate('delegations.column.delegatorName'),
2273
+ type: 'custom',
2274
+ customCellTpl: this.delegatorCol(),
2275
+ width: '16rem',
2276
+ },
2277
+ {
2278
+ key: 'delegatedUser',
2279
+ label: this.transloco.translate('delegations.column.delegatedTo'),
2280
+ type: 'custom',
2281
+ customCellTpl: this.delegatedUserCol(),
2282
+ width: '16rem',
2283
+ },
2284
+ ...baseColumns,
2285
+ ];
2286
+ }
2287
+ return [
2288
+ {
2289
+ key: this.activeTab() === 'my' ? 'delegatedUser' : 'delegator',
2290
+ label: this.transloco.translate(this.activeTab() === 'my'
2291
+ ? 'delegations.column.delegatedTo'
2292
+ : 'delegations.column.delegatorName'),
2293
+ type: 'custom',
2294
+ customCellTpl: this.userCol(),
2295
+ width: '16rem',
2296
+ },
2297
+ ...baseColumns,
2298
+ ];
2299
+ }, ...(ngDevMode ? [{ debugName: "tableColumns" }] : /* istanbul ignore next */ []));
2137
2300
  busyIds = signal([], ...(ngDevMode ? [{ debugName: "busyIds" }] : /* istanbul ignore next */ []));
2138
2301
  weekdayKeys = [
2139
2302
  'sunday',
@@ -2155,11 +2318,18 @@ class DelegationsList {
2155
2318
  this.loadCurrentTab();
2156
2319
  }
2157
2320
  loadCurrentTab(query = { page: 1, pageSize: 25 }) {
2321
+ if (this.adminMode()) {
2322
+ this.facade.getAdmin(query);
2323
+ return;
2324
+ }
2158
2325
  if (this.activeTab() === 'my') {
2159
2326
  this.facade.getMy(query);
2160
2327
  }
2161
2328
  else {
2162
- this.facade.getAssigned(query);
2329
+ this.facade.getAssigned({
2330
+ ...query,
2331
+ status: query.status ?? this.assignedStatus() ?? undefined,
2332
+ });
2163
2333
  }
2164
2334
  }
2165
2335
  reloadCurrentTab() {
@@ -2180,6 +2350,9 @@ class DelegationsList {
2180
2350
  formatScopeSummary(value) {
2181
2351
  return formatDelegationScopeSummary(value, this.transloco.getActiveLang());
2182
2352
  }
2353
+ getListedParty(row) {
2354
+ return this.activeTab() === 'my' ? row.delegatedUser : row.delegator;
2355
+ }
2183
2356
  viewDetails(row) {
2184
2357
  this.modal.openModal(DelegationDetailDrawer, 'drawer', {
2185
2358
  header: this.transloco.translate('delegations.action.view'),
@@ -2235,7 +2408,7 @@ class DelegationsList {
2235
2408
  cancel(row) {
2236
2409
  this.mark(`cancel:${row.delegationId}`, true);
2237
2410
  this.facade
2238
- .cancel(row.delegationId, row.rowVersion)
2411
+ .cancel(row.delegationId, row.rowVersion, this.adminMode())
2239
2412
  .pipe(finalize(() => this.mark(`cancel:${row.delegationId}`, false)))
2240
2413
  .subscribe({ next: () => this.reloadCurrentTab() });
2241
2414
  }
@@ -2256,7 +2429,7 @@ class DelegationsList {
2256
2429
  this.busyIds.update((ids) => on ? [...ids, key] : ids.filter((id) => id !== key));
2257
2430
  }
2258
2431
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationsList, deps: [], target: i0.ɵɵFactoryTarget.Component });
2259
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationsList, isStandalone: true, selector: "mt-delegations-list", inputs: { showBreadcrumb: { classPropertyName: "showBreadcrumb", publicName: "showBreadcrumb", isSignal: true, isRequired: false, transformFunction: null }, adminMode: { classPropertyName: "adminMode", publicName: "adminMode", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "statusCol", first: true, predicate: ["statusCol"], descendants: true, isSignal: true }, { propertyName: "userCol", first: true, predicate: ["userCol"], descendants: true, isSignal: true }, { propertyName: "scopeCol", first: true, predicate: ["scopeCol"], descendants: true, isSignal: true }, { propertyName: "daysCol", first: true, predicate: ["daysCol"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex flex-col h-full gap-2 p-4\">\n @if (showBreadcrumb()) {\n <mt-breadcrumb [items]=\"breadcrumbItems()\"></mt-breadcrumb>\n }\n\n <div class=\"flex items-center gap-2 border-b border-gray-200\">\n @for (tab of tabs(); track tab.value) {\n <button\n type=\"button\"\n class=\"px-4 py-2 -mb-px border-b-2 text-sm font-medium transition-colors\"\n [class.border-primary]=\"activeTab() === tab.value\"\n [class.text-primary]=\"activeTab() === tab.value\"\n [class.border-transparent]=\"activeTab() !== tab.value\"\n [class.text-gray-500]=\"activeTab() !== tab.value\"\n (click)=\"switchTab(tab.value)\"\n >\n {{ tab.label }}\n </button>\n }\n </div>\n\n <mt-table\n [data]=\"rows()\"\n [columns]=\"tableColumns()\"\n [actions]=\"tableActions()\"\n [rowActions]=\"rowActions()\"\n [freezeActions]=\"true\"\n [loading]=\"isLoading()\"\n >\n <ng-template #statusCol let-row>\n <mt-delegation-status-chip\n [status]=\"row.effectiveStatus\"\n ></mt-delegation-status-chip>\n </ng-template>\n\n <ng-template #userCol let-row>\n @let party = activeTab() === \"my\" ? row.delegatedUser : row.delegator;\n <div class=\"flex items-center gap-2\">\n <mt-avatar icon=\"user.user-01\" styleClass=\"w-8! h-8!\"></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <span class=\"text-sm text-gray-900 truncate\">\n {{ party?.displayName }}\n </span>\n @if (party?.email) {\n <span class=\"text-xs text-gray-500 truncate\">\n {{ party.email }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #scopeCol let-row>\n @let summary = formatScopeSummary(row.scopeSummary);\n <span class=\"text-sm text-gray-700\" [title]=\"summary\">\n {{ summary || \"\u2014\" }}\n </span>\n </ng-template>\n\n <ng-template #daysCol let-row>\n <span class=\"text-sm text-gray-700\">{{ formatDays(row) }}</span>\n </ng-template>\n </mt-table>\n </div>\n</ng-container>\n", styles: [":host{display:block;min-width:0}:host ::ng-deep mt-table .p-datatable-table{min-width:72rem}:host ::ng-deep mt-table .p-datatable-header>div,:host ::ng-deep mt-table .p-datatable-header>div>div{gap:.75rem;min-width:0;flex-wrap:wrap}:host ::ng-deep mt-table .p-datatable-header mt-tabs{display:block;max-width:100%;overflow-x:auto;padding-bottom:.25rem}:host ::ng-deep mt-table .p-datatable-header mt-text-field{display:block;flex:1 1 16rem;min-width:min(100%,16rem)}:host ::ng-deep mt-table .p-datatable-header .p-inputtext,:host ::ng-deep mt-table .p-datatable-header .p-inputwrapper,:host ::ng-deep mt-table .p-datatable-header .p-selectbutton{width:100%;max-width:100%}@media(max-width:1024px){:host ::ng-deep mt-table .p-datatable-header>div{flex-direction:column;align-items:stretch}:host ::ng-deep mt-table .p-datatable-header>div>div{width:100%;justify-content:flex-start}:host ::ng-deep mt-table .p-datatable-header mt-text-field{flex-basis:100%;min-width:0}}@media(max-width:768px){:host ::ng-deep mt-table .p-datatable-table{min-width:64rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "component", type: Breadcrumb, selector: "mt-breadcrumb", inputs: ["items", "styleClass"], outputs: ["onItemClick"] }, { 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", "exportable", "printable", "groupable", "cellClickFilter", "freezeActions", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: DelegationStatusChip, selector: "mt-delegation-status-chip", inputs: ["status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2432
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationsList, isStandalone: true, selector: "mt-delegations-list", inputs: { showBreadcrumb: { classPropertyName: "showBreadcrumb", publicName: "showBreadcrumb", isSignal: true, isRequired: false, transformFunction: null }, adminMode: { classPropertyName: "adminMode", publicName: "adminMode", isSignal: true, isRequired: false, transformFunction: null }, surfaceTitleKey: { classPropertyName: "surfaceTitleKey", publicName: "surfaceTitleKey", isSignal: true, isRequired: false, transformFunction: null }, assignedTabLabelKey: { classPropertyName: "assignedTabLabelKey", publicName: "assignedTabLabelKey", isSignal: true, isRequired: false, transformFunction: null }, assignedDecisionTab: { classPropertyName: "assignedDecisionTab", publicName: "assignedDecisionTab", isSignal: true, isRequired: false, transformFunction: null }, assignedEmptyStateKey: { classPropertyName: "assignedEmptyStateKey", publicName: "assignedEmptyStateKey", isSignal: true, isRequired: false, transformFunction: null }, assignedStatus: { classPropertyName: "assignedStatus", publicName: "assignedStatus", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "statusCol", first: true, predicate: ["statusCol"], descendants: true, isSignal: true }, { propertyName: "userCol", first: true, predicate: ["userCol"], descendants: true, isSignal: true }, { propertyName: "delegatorCol", first: true, predicate: ["delegatorCol"], descendants: true, isSignal: true }, { propertyName: "delegatedUserCol", first: true, predicate: ["delegatedUserCol"], descendants: true, isSignal: true }, { propertyName: "scopeCol", first: true, predicate: ["scopeCol"], descendants: true, isSignal: true }, { propertyName: "daysCol", first: true, predicate: ["daysCol"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex h-full flex-col gap-4 p-4\">\n @if (showBreadcrumb()) {\n <mt-breadcrumb [items]=\"breadcrumbItems()\"></mt-breadcrumb>\n }\n\n <mt-card [title]=\"surfaceTitle()\">\n <div class=\"flex flex-col gap-4\">\n @if (!adminMode()) {\n <div class=\"flex items-center gap-2 border-b border-gray-200\">\n @for (tab of tabs(); track tab.value) {\n <button\n type=\"button\"\n class=\"px-4 py-2 -mb-px border-b-2 text-sm font-medium transition-colors\"\n [class.border-primary]=\"activeTab() === tab.value\"\n [class.text-primary]=\"activeTab() === tab.value\"\n [class.border-transparent]=\"activeTab() !== tab.value\"\n [class.text-gray-500]=\"activeTab() !== tab.value\"\n (click)=\"switchTab(tab.value)\"\n >\n {{ tab.label }}\n </button>\n }\n </div>\n }\n\n <mt-table\n [data]=\"rows()\"\n [columns]=\"tableColumns()\"\n [actions]=\"tableActions()\"\n [rowActions]=\"rowActions()\"\n [freezeActions]=\"true\"\n [loading]=\"isLoading()\"\n [noCard]=\"true\"\n >\n <ng-template #statusCol let-row>\n <mt-delegation-status-chip\n [status]=\"row.effectiveStatus\"\n ></mt-delegation-status-chip>\n </ng-template>\n\n <ng-template #userCol let-row>\n @let party = getListedParty(row);\n <div class=\"flex items-center gap-2\">\n <mt-avatar icon=\"user.user-01\" styleClass=\"w-8! h-8!\"></mt-avatar>\n <div class=\"flex min-w-0 flex-col\">\n <span class=\"truncate text-sm text-gray-900\">\n {{ party?.displayName }}\n </span>\n @if (party?.email) {\n <span class=\"truncate text-xs text-gray-500\">\n {{ party.email }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #delegatorCol let-row>\n <div class=\"flex items-center gap-2\">\n <mt-avatar icon=\"user.user-01\" styleClass=\"w-8! h-8!\"></mt-avatar>\n <div class=\"flex min-w-0 flex-col\">\n <span class=\"truncate text-sm text-gray-900\">\n {{ row.delegator?.displayName }}\n </span>\n @if (row.delegator?.email) {\n <span class=\"truncate text-xs text-gray-500\">\n {{ row.delegator.email }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #delegatedUserCol let-row>\n <div class=\"flex items-center gap-2\">\n <mt-avatar icon=\"user.user-01\" styleClass=\"w-8! h-8!\"></mt-avatar>\n <div class=\"flex min-w-0 flex-col\">\n <span class=\"truncate text-sm text-gray-900\">\n {{ row.delegatedUser?.displayName }}\n </span>\n @if (row.delegatedUser?.email) {\n <span class=\"truncate text-xs text-gray-500\">\n {{ row.delegatedUser.email }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #scopeCol let-row>\n @let summary = formatScopeSummary(row.scopeSummary);\n <span class=\"text-sm text-gray-700\" [title]=\"summary\">\n {{ summary || \"--\" }}\n </span>\n </ng-template>\n\n <ng-template #daysCol let-row>\n <span class=\"text-sm text-gray-700\">{{ formatDays(row) }}</span>\n </ng-template>\n\n <ng-template #empty>\n <p class=\"text-sm text-surface-500\">\n {{ t(emptyStateKey()) }}\n </p>\n </ng-template>\n </mt-table>\n </div>\n </mt-card>\n </div>\n</ng-container>\n", styles: [":host{display:block;min-width:0}:host ::ng-deep mt-table .p-datatable-table{min-width:72rem}:host ::ng-deep mt-table .p-datatable-header>div,:host ::ng-deep mt-table .p-datatable-header>div>div{gap:.75rem;min-width:0;flex-wrap:wrap}:host ::ng-deep mt-table .p-datatable-header mt-tabs{display:block;max-width:100%;overflow-x:auto;padding-bottom:.25rem}:host ::ng-deep mt-table .p-datatable-header mt-text-field{display:block;flex:1 1 16rem;min-width:min(100%,16rem)}:host ::ng-deep mt-table .p-datatable-header .p-inputtext,:host ::ng-deep mt-table .p-datatable-header .p-inputwrapper,:host ::ng-deep mt-table .p-datatable-header .p-selectbutton{width:100%;max-width:100%}@media(max-width:1024px){:host ::ng-deep mt-table .p-datatable-header>div{flex-direction:column;align-items:stretch}:host ::ng-deep mt-table .p-datatable-header>div>div{width:100%;justify-content:flex-start}:host ::ng-deep mt-table .p-datatable-header mt-text-field{flex-basis:100%;min-width:0}}@media(max-width:768px){:host ::ng-deep mt-table .p-datatable-table{min-width:64rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "component", type: Breadcrumb, selector: "mt-breadcrumb", inputs: ["items", "styleClass"], outputs: ["onItemClick"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { 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", "exportable", "printable", "groupable", "cellClickFilter", "freezeActions", "printTitle", "exportFilename", "actionShape", "rowActionsLoadingFn", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm", "groupBy"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "rowActionsRequested", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange", "groupByChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: DelegationStatusChip, selector: "mt-delegation-status-chip", inputs: ["status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2260
2433
  }
2261
2434
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationsList, decorators: [{
2262
2435
  type: Component,
@@ -2264,11 +2437,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
2264
2437
  CommonModule,
2265
2438
  Avatar,
2266
2439
  Breadcrumb,
2440
+ Card,
2267
2441
  Table,
2268
2442
  TranslocoDirective,
2269
2443
  DelegationStatusChip,
2270
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex flex-col h-full gap-2 p-4\">\n @if (showBreadcrumb()) {\n <mt-breadcrumb [items]=\"breadcrumbItems()\"></mt-breadcrumb>\n }\n\n <div class=\"flex items-center gap-2 border-b border-gray-200\">\n @for (tab of tabs(); track tab.value) {\n <button\n type=\"button\"\n class=\"px-4 py-2 -mb-px border-b-2 text-sm font-medium transition-colors\"\n [class.border-primary]=\"activeTab() === tab.value\"\n [class.text-primary]=\"activeTab() === tab.value\"\n [class.border-transparent]=\"activeTab() !== tab.value\"\n [class.text-gray-500]=\"activeTab() !== tab.value\"\n (click)=\"switchTab(tab.value)\"\n >\n {{ tab.label }}\n </button>\n }\n </div>\n\n <mt-table\n [data]=\"rows()\"\n [columns]=\"tableColumns()\"\n [actions]=\"tableActions()\"\n [rowActions]=\"rowActions()\"\n [freezeActions]=\"true\"\n [loading]=\"isLoading()\"\n >\n <ng-template #statusCol let-row>\n <mt-delegation-status-chip\n [status]=\"row.effectiveStatus\"\n ></mt-delegation-status-chip>\n </ng-template>\n\n <ng-template #userCol let-row>\n @let party = activeTab() === \"my\" ? row.delegatedUser : row.delegator;\n <div class=\"flex items-center gap-2\">\n <mt-avatar icon=\"user.user-01\" styleClass=\"w-8! h-8!\"></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <span class=\"text-sm text-gray-900 truncate\">\n {{ party?.displayName }}\n </span>\n @if (party?.email) {\n <span class=\"text-xs text-gray-500 truncate\">\n {{ party.email }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #scopeCol let-row>\n @let summary = formatScopeSummary(row.scopeSummary);\n <span class=\"text-sm text-gray-700\" [title]=\"summary\">\n {{ summary || \"\u2014\" }}\n </span>\n </ng-template>\n\n <ng-template #daysCol let-row>\n <span class=\"text-sm text-gray-700\">{{ formatDays(row) }}</span>\n </ng-template>\n </mt-table>\n </div>\n</ng-container>\n", styles: [":host{display:block;min-width:0}:host ::ng-deep mt-table .p-datatable-table{min-width:72rem}:host ::ng-deep mt-table .p-datatable-header>div,:host ::ng-deep mt-table .p-datatable-header>div>div{gap:.75rem;min-width:0;flex-wrap:wrap}:host ::ng-deep mt-table .p-datatable-header mt-tabs{display:block;max-width:100%;overflow-x:auto;padding-bottom:.25rem}:host ::ng-deep mt-table .p-datatable-header mt-text-field{display:block;flex:1 1 16rem;min-width:min(100%,16rem)}:host ::ng-deep mt-table .p-datatable-header .p-inputtext,:host ::ng-deep mt-table .p-datatable-header .p-inputwrapper,:host ::ng-deep mt-table .p-datatable-header .p-selectbutton{width:100%;max-width:100%}@media(max-width:1024px){:host ::ng-deep mt-table .p-datatable-header>div{flex-direction:column;align-items:stretch}:host ::ng-deep mt-table .p-datatable-header>div>div{width:100%;justify-content:flex-start}:host ::ng-deep mt-table .p-datatable-header mt-text-field{flex-basis:100%;min-width:0}}@media(max-width:768px){:host ::ng-deep mt-table .p-datatable-table{min-width:64rem}}\n"] }]
2271
- }], propDecorators: { showBreadcrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBreadcrumb", required: false }] }], adminMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "adminMode", required: false }] }], statusCol: [{ type: i0.ViewChild, args: ['statusCol', { isSignal: true }] }], userCol: [{ type: i0.ViewChild, args: ['userCol', { isSignal: true }] }], scopeCol: [{ type: i0.ViewChild, args: ['scopeCol', { isSignal: true }] }], daysCol: [{ type: i0.ViewChild, args: ['daysCol', { isSignal: true }] }] } });
2444
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex h-full flex-col gap-4 p-4\">\n @if (showBreadcrumb()) {\n <mt-breadcrumb [items]=\"breadcrumbItems()\"></mt-breadcrumb>\n }\n\n <mt-card [title]=\"surfaceTitle()\">\n <div class=\"flex flex-col gap-4\">\n @if (!adminMode()) {\n <div class=\"flex items-center gap-2 border-b border-gray-200\">\n @for (tab of tabs(); track tab.value) {\n <button\n type=\"button\"\n class=\"px-4 py-2 -mb-px border-b-2 text-sm font-medium transition-colors\"\n [class.border-primary]=\"activeTab() === tab.value\"\n [class.text-primary]=\"activeTab() === tab.value\"\n [class.border-transparent]=\"activeTab() !== tab.value\"\n [class.text-gray-500]=\"activeTab() !== tab.value\"\n (click)=\"switchTab(tab.value)\"\n >\n {{ tab.label }}\n </button>\n }\n </div>\n }\n\n <mt-table\n [data]=\"rows()\"\n [columns]=\"tableColumns()\"\n [actions]=\"tableActions()\"\n [rowActions]=\"rowActions()\"\n [freezeActions]=\"true\"\n [loading]=\"isLoading()\"\n [noCard]=\"true\"\n >\n <ng-template #statusCol let-row>\n <mt-delegation-status-chip\n [status]=\"row.effectiveStatus\"\n ></mt-delegation-status-chip>\n </ng-template>\n\n <ng-template #userCol let-row>\n @let party = getListedParty(row);\n <div class=\"flex items-center gap-2\">\n <mt-avatar icon=\"user.user-01\" styleClass=\"w-8! h-8!\"></mt-avatar>\n <div class=\"flex min-w-0 flex-col\">\n <span class=\"truncate text-sm text-gray-900\">\n {{ party?.displayName }}\n </span>\n @if (party?.email) {\n <span class=\"truncate text-xs text-gray-500\">\n {{ party.email }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #delegatorCol let-row>\n <div class=\"flex items-center gap-2\">\n <mt-avatar icon=\"user.user-01\" styleClass=\"w-8! h-8!\"></mt-avatar>\n <div class=\"flex min-w-0 flex-col\">\n <span class=\"truncate text-sm text-gray-900\">\n {{ row.delegator?.displayName }}\n </span>\n @if (row.delegator?.email) {\n <span class=\"truncate text-xs text-gray-500\">\n {{ row.delegator.email }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #delegatedUserCol let-row>\n <div class=\"flex items-center gap-2\">\n <mt-avatar icon=\"user.user-01\" styleClass=\"w-8! h-8!\"></mt-avatar>\n <div class=\"flex min-w-0 flex-col\">\n <span class=\"truncate text-sm text-gray-900\">\n {{ row.delegatedUser?.displayName }}\n </span>\n @if (row.delegatedUser?.email) {\n <span class=\"truncate text-xs text-gray-500\">\n {{ row.delegatedUser.email }}\n </span>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #scopeCol let-row>\n @let summary = formatScopeSummary(row.scopeSummary);\n <span class=\"text-sm text-gray-700\" [title]=\"summary\">\n {{ summary || \"--\" }}\n </span>\n </ng-template>\n\n <ng-template #daysCol let-row>\n <span class=\"text-sm text-gray-700\">{{ formatDays(row) }}</span>\n </ng-template>\n\n <ng-template #empty>\n <p class=\"text-sm text-surface-500\">\n {{ t(emptyStateKey()) }}\n </p>\n </ng-template>\n </mt-table>\n </div>\n </mt-card>\n </div>\n</ng-container>\n", styles: [":host{display:block;min-width:0}:host ::ng-deep mt-table .p-datatable-table{min-width:72rem}:host ::ng-deep mt-table .p-datatable-header>div,:host ::ng-deep mt-table .p-datatable-header>div>div{gap:.75rem;min-width:0;flex-wrap:wrap}:host ::ng-deep mt-table .p-datatable-header mt-tabs{display:block;max-width:100%;overflow-x:auto;padding-bottom:.25rem}:host ::ng-deep mt-table .p-datatable-header mt-text-field{display:block;flex:1 1 16rem;min-width:min(100%,16rem)}:host ::ng-deep mt-table .p-datatable-header .p-inputtext,:host ::ng-deep mt-table .p-datatable-header .p-inputwrapper,:host ::ng-deep mt-table .p-datatable-header .p-selectbutton{width:100%;max-width:100%}@media(max-width:1024px){:host ::ng-deep mt-table .p-datatable-header>div{flex-direction:column;align-items:stretch}:host ::ng-deep mt-table .p-datatable-header>div>div{width:100%;justify-content:flex-start}:host ::ng-deep mt-table .p-datatable-header mt-text-field{flex-basis:100%;min-width:0}}@media(max-width:768px){:host ::ng-deep mt-table .p-datatable-table{min-width:64rem}}\n"] }]
2445
+ }], propDecorators: { showBreadcrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBreadcrumb", required: false }] }], adminMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "adminMode", required: false }] }], surfaceTitleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceTitleKey", required: false }] }], assignedTabLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "assignedTabLabelKey", required: false }] }], assignedDecisionTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "assignedDecisionTab", required: false }] }], assignedEmptyStateKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "assignedEmptyStateKey", required: false }] }], assignedStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "assignedStatus", required: false }] }], statusCol: [{ type: i0.ViewChild, args: ['statusCol', { isSignal: true }] }], userCol: [{ type: i0.ViewChild, args: ['userCol', { isSignal: true }] }], delegatorCol: [{ type: i0.ViewChild, args: ['delegatorCol', { isSignal: true }] }], delegatedUserCol: [{ type: i0.ViewChild, args: ['delegatedUserCol', { isSignal: true }] }], scopeCol: [{ type: i0.ViewChild, args: ['scopeCol', { isSignal: true }] }], daysCol: [{ type: i0.ViewChild, args: ['daysCol', { isSignal: true }] }] } });
2272
2446
 
2273
2447
  /**
2274
2448
  * Endpoints that must NEVER carry the `app-delegation` header.
@@ -2301,5 +2475,5 @@ const appDelegationInterceptor = (req, next) => {
2301
2475
  * Generated bundle index. Do not edit.
2302
2476
  */
2303
2477
 
2304
- export { ApproveDelegation, CancelDelegation, ClearDelegationDetail, ClearScopePreview, CreateDelegationLegacy, CreateDelegationV2, DelegationDetailDrawer, DelegationForm, DelegationSessionActionKey, DelegationSessionFacade, DelegationSessionState, DelegationStatusChip, Delegations, DelegationsActionKey, DelegationsFacade, DelegationsList, DelegationsState, EndDelegationSession, GetActiveAssignedDelegations, GetAssignedDelegations, GetDelegationDetail, GetMyDelegations, GetScopeOptions, LoadDelegationCandidates, PreviewScope, RejectDelegation, RejectDelegationDialog, ScopePicker, StartDelegationSession, StartSessionDialog, SwitchDelegationSession, TopbarDelegationMenu, UpdateDelegationLegacy, UpdateDelegationV2, appDelegationInterceptor };
2478
+ export { ApproveDelegation, CancelDelegation, ClearDelegationDetail, ClearScopePreview, CreateDelegationLegacy, CreateDelegationV2, DelegationDetailDrawer, DelegationForm, DelegationSessionActionKey, DelegationSessionFacade, DelegationSessionState, DelegationStatusChip, Delegations, DelegationsActionKey, DelegationsFacade, DelegationsList, DelegationsState, EndDelegationSession, GetActiveAssignedDelegations, GetAdminDelegations, GetAssignedDelegations, GetDelegationDetail, GetMyDelegations, GetScopeOptions, LoadDelegationCandidates, PreviewScope, RejectDelegation, RejectDelegationDialog, ScopePicker, StartDelegationSession, StartSessionDialog, SwitchDelegationSession, TopbarDelegationMenu, UpdateDelegationLegacy, UpdateDelegationV2, appDelegationInterceptor };
2305
2479
  //# sourceMappingURL=masterteam-delegations.mjs.map