@masterteam/delegations 0.0.23 → 0.0.25
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.
|
@@ -557,9 +557,11 @@ class GetActiveAssignedDelegations {
|
|
|
557
557
|
}
|
|
558
558
|
class GetDelegationDetail {
|
|
559
559
|
id;
|
|
560
|
+
asAdmin;
|
|
560
561
|
static type = '[Delegations] Get Delegation Detail';
|
|
561
|
-
constructor(id) {
|
|
562
|
+
constructor(id, asAdmin = false) {
|
|
562
563
|
this.id = id;
|
|
564
|
+
this.asAdmin = asAdmin;
|
|
563
565
|
}
|
|
564
566
|
}
|
|
565
567
|
class ClearDelegationDetail {
|
|
@@ -570,16 +572,20 @@ class ClearDelegationDetail {
|
|
|
570
572
|
// ---------------------------------------------------------------------------
|
|
571
573
|
class GetScopeOptions {
|
|
572
574
|
delegatorUserId;
|
|
575
|
+
asAdmin;
|
|
573
576
|
static type = '[Delegations] Get Scope Options';
|
|
574
|
-
constructor(delegatorUserId) {
|
|
577
|
+
constructor(delegatorUserId, asAdmin = false) {
|
|
575
578
|
this.delegatorUserId = delegatorUserId;
|
|
579
|
+
this.asAdmin = asAdmin;
|
|
576
580
|
}
|
|
577
581
|
}
|
|
578
582
|
class PreviewScope {
|
|
579
|
-
|
|
583
|
+
request;
|
|
584
|
+
asAdmin;
|
|
580
585
|
static type = '[Delegations] Preview Scope';
|
|
581
|
-
constructor(
|
|
582
|
-
this.
|
|
586
|
+
constructor(request, asAdmin = false) {
|
|
587
|
+
this.request = request;
|
|
588
|
+
this.asAdmin = asAdmin;
|
|
583
589
|
}
|
|
584
590
|
}
|
|
585
591
|
class ClearScopePreview {
|
|
@@ -597,9 +603,11 @@ class CreateDelegationLegacy {
|
|
|
597
603
|
}
|
|
598
604
|
class CreateDelegationV2 {
|
|
599
605
|
request;
|
|
606
|
+
asAdmin;
|
|
600
607
|
static type = '[Delegations] Create Delegation (v2)';
|
|
601
|
-
constructor(request) {
|
|
608
|
+
constructor(request, asAdmin = false) {
|
|
602
609
|
this.request = request;
|
|
610
|
+
this.asAdmin = asAdmin;
|
|
603
611
|
}
|
|
604
612
|
}
|
|
605
613
|
class UpdateDelegationLegacy {
|
|
@@ -614,10 +622,12 @@ class UpdateDelegationLegacy {
|
|
|
614
622
|
class UpdateDelegationV2 {
|
|
615
623
|
id;
|
|
616
624
|
request;
|
|
625
|
+
asAdmin;
|
|
617
626
|
static type = '[Delegations] Update Delegation (v2)';
|
|
618
|
-
constructor(id, request) {
|
|
627
|
+
constructor(id, request, asAdmin = false) {
|
|
619
628
|
this.id = id;
|
|
620
629
|
this.request = request;
|
|
630
|
+
this.asAdmin = asAdmin;
|
|
621
631
|
}
|
|
622
632
|
}
|
|
623
633
|
// ---------------------------------------------------------------------------
|
|
@@ -776,8 +786,9 @@ let DelegationsState = class DelegationsState {
|
|
|
776
786
|
onSuccess: (response) => ({ active: response.data }),
|
|
777
787
|
});
|
|
778
788
|
}
|
|
779
|
-
getDetail(ctx, { id }) {
|
|
780
|
-
const
|
|
789
|
+
getDetail(ctx, { id, asAdmin }) {
|
|
790
|
+
const path = asAdmin ? `${BASE}/Admin/${id}` : `${BASE}/${id}`;
|
|
791
|
+
const req$ = this.http.get(path);
|
|
781
792
|
return handleApiRequest({
|
|
782
793
|
ctx,
|
|
783
794
|
key: DelegationsActionKey.GetDetail,
|
|
@@ -791,12 +802,17 @@ let DelegationsState = class DelegationsState {
|
|
|
791
802
|
// ============================================================================
|
|
792
803
|
// Scope
|
|
793
804
|
// ============================================================================
|
|
794
|
-
getScopeOptions(ctx, { delegatorUserId }) {
|
|
805
|
+
getScopeOptions(ctx, { delegatorUserId, asAdmin }) {
|
|
795
806
|
ctx.patchState({ scopeOptions: null, scopePreview: null });
|
|
796
807
|
let params = new HttpParams();
|
|
797
808
|
if (delegatorUserId)
|
|
798
809
|
params = params.set('delegatorUserId', delegatorUserId);
|
|
799
|
-
const
|
|
810
|
+
const path = asAdmin
|
|
811
|
+
? `${BASE}/Admin/scope/options`
|
|
812
|
+
: `${BASE}/scope/options`;
|
|
813
|
+
const req$ = this.http.get(path, {
|
|
814
|
+
params,
|
|
815
|
+
});
|
|
800
816
|
return handleApiRequest({
|
|
801
817
|
ctx,
|
|
802
818
|
key: DelegationsActionKey.GetScopeOptions,
|
|
@@ -804,8 +820,11 @@ let DelegationsState = class DelegationsState {
|
|
|
804
820
|
onSuccess: (response) => ({ scopeOptions: response.data ?? null }),
|
|
805
821
|
});
|
|
806
822
|
}
|
|
807
|
-
previewScope(ctx, {
|
|
808
|
-
const
|
|
823
|
+
previewScope(ctx, { request, asAdmin }) {
|
|
824
|
+
const path = asAdmin
|
|
825
|
+
? `${BASE}/Admin/scope/preview`
|
|
826
|
+
: `${BASE}/scope/preview`;
|
|
827
|
+
const req$ = this.http.post(path, this.buildScopePreviewRequest(request, asAdmin));
|
|
809
828
|
return handleApiRequest({
|
|
810
829
|
ctx,
|
|
811
830
|
key: DelegationsActionKey.PreviewScope,
|
|
@@ -828,8 +847,12 @@ let DelegationsState = class DelegationsState {
|
|
|
828
847
|
onSuccess: () => ({}),
|
|
829
848
|
});
|
|
830
849
|
}
|
|
831
|
-
createV2(ctx, { request }) {
|
|
832
|
-
const
|
|
850
|
+
createV2(ctx, { request, asAdmin }) {
|
|
851
|
+
const path = asAdmin ? `${BASE}/Admin/v2` : `${BASE}/v2`;
|
|
852
|
+
const body = asAdmin
|
|
853
|
+
? this.buildAdminSaveRequest(request)
|
|
854
|
+
: request;
|
|
855
|
+
const req$ = this.http.post(path, body);
|
|
833
856
|
return handleApiRequest({
|
|
834
857
|
ctx,
|
|
835
858
|
key: DelegationsActionKey.Create,
|
|
@@ -846,8 +869,12 @@ let DelegationsState = class DelegationsState {
|
|
|
846
869
|
onSuccess: () => ({}),
|
|
847
870
|
});
|
|
848
871
|
}
|
|
849
|
-
updateV2(ctx, { id, request }) {
|
|
850
|
-
const
|
|
872
|
+
updateV2(ctx, { id, request, asAdmin }) {
|
|
873
|
+
const path = asAdmin ? `${BASE}/Admin/v2/${id}` : `${BASE}/v2/${id}`;
|
|
874
|
+
const body = asAdmin
|
|
875
|
+
? this.buildAdminSaveRequest(request)
|
|
876
|
+
: request;
|
|
877
|
+
const req$ = this.http.put(path, body);
|
|
851
878
|
return handleApiRequest({
|
|
852
879
|
ctx,
|
|
853
880
|
key: DelegationsActionKey.Update,
|
|
@@ -888,6 +915,21 @@ let DelegationsState = class DelegationsState {
|
|
|
888
915
|
onSuccess: () => ({}),
|
|
889
916
|
});
|
|
890
917
|
}
|
|
918
|
+
buildScopePreviewRequest(request, asAdmin) {
|
|
919
|
+
if (!asAdmin) {
|
|
920
|
+
return { scope: request.scope };
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
delegatorUserId: request.delegatorUserId ?? null,
|
|
924
|
+
scope: request.scope,
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
buildAdminSaveRequest(request) {
|
|
928
|
+
return {
|
|
929
|
+
...request,
|
|
930
|
+
specificDays: request.specificDays ?? [],
|
|
931
|
+
};
|
|
932
|
+
}
|
|
891
933
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationsState, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
892
934
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationsState });
|
|
893
935
|
};
|
|
@@ -1048,17 +1090,21 @@ class DelegationsFacade {
|
|
|
1048
1090
|
getActive(query = {}) {
|
|
1049
1091
|
return this.store.dispatch(new GetActiveAssignedDelegations(query));
|
|
1050
1092
|
}
|
|
1051
|
-
getDetail(id) {
|
|
1052
|
-
return this.store.dispatch(new GetDelegationDetail(id));
|
|
1093
|
+
getDetail(id, asAdmin = false) {
|
|
1094
|
+
return this.store.dispatch(new GetDelegationDetail(id, asAdmin));
|
|
1053
1095
|
}
|
|
1054
1096
|
clearDetail() {
|
|
1055
1097
|
return this.store.dispatch(new ClearDelegationDetail());
|
|
1056
1098
|
}
|
|
1057
|
-
loadScopeOptions(delegatorUserId) {
|
|
1058
|
-
return this.store.dispatch(new GetScopeOptions(delegatorUserId));
|
|
1099
|
+
loadScopeOptions(delegatorUserId, asAdmin = false) {
|
|
1100
|
+
return this.store.dispatch(new GetScopeOptions(delegatorUserId, asAdmin));
|
|
1059
1101
|
}
|
|
1060
|
-
previewScope(scope) {
|
|
1061
|
-
|
|
1102
|
+
previewScope(scope, options) {
|
|
1103
|
+
const request = {
|
|
1104
|
+
delegatorUserId: options?.delegatorUserId,
|
|
1105
|
+
scope,
|
|
1106
|
+
};
|
|
1107
|
+
return this.store.dispatch(new PreviewScope(request, options?.asAdmin ?? false));
|
|
1062
1108
|
}
|
|
1063
1109
|
clearScopePreview() {
|
|
1064
1110
|
return this.store.dispatch(new ClearScopePreview());
|
|
@@ -1066,14 +1112,14 @@ class DelegationsFacade {
|
|
|
1066
1112
|
createLegacy(request) {
|
|
1067
1113
|
return this.store.dispatch(new CreateDelegationLegacy(request));
|
|
1068
1114
|
}
|
|
1069
|
-
createV2(request) {
|
|
1070
|
-
return this.store.dispatch(new CreateDelegationV2(request));
|
|
1115
|
+
createV2(request, asAdmin = false) {
|
|
1116
|
+
return this.store.dispatch(new CreateDelegationV2(request, asAdmin));
|
|
1071
1117
|
}
|
|
1072
1118
|
updateLegacy(id, request) {
|
|
1073
1119
|
return this.store.dispatch(new UpdateDelegationLegacy(id, request));
|
|
1074
1120
|
}
|
|
1075
|
-
updateV2(id, request) {
|
|
1076
|
-
return this.store.dispatch(new UpdateDelegationV2(id, request));
|
|
1121
|
+
updateV2(id, request, asAdmin = false) {
|
|
1122
|
+
return this.store.dispatch(new UpdateDelegationV2(id, request, asAdmin));
|
|
1077
1123
|
}
|
|
1078
1124
|
approve(id, request) {
|
|
1079
1125
|
return this.store.dispatch(new ApproveDelegation(id, request));
|
|
@@ -1551,6 +1597,7 @@ function sameSelectionKeys(left, right) {
|
|
|
1551
1597
|
class ScopePicker {
|
|
1552
1598
|
scope = model(EMPTY_SCOPE$1, ...(ngDevMode ? [{ debugName: "scope" }] : /* istanbul ignore next */ []));
|
|
1553
1599
|
readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
1600
|
+
adminMode = input(false, ...(ngDevMode ? [{ debugName: "adminMode" }] : /* istanbul ignore next */ []));
|
|
1554
1601
|
/**
|
|
1555
1602
|
* Delegator whose grantable scope is loaded. Undefined = current user
|
|
1556
1603
|
* (self-service). In admin mode the host rebinds this as the selected
|
|
@@ -1589,7 +1636,8 @@ class ScopePicker {
|
|
|
1589
1636
|
let lastDelegatorUserId;
|
|
1590
1637
|
effect(() => {
|
|
1591
1638
|
const delegator = this.delegatorUserId();
|
|
1592
|
-
|
|
1639
|
+
const asAdmin = this.adminMode();
|
|
1640
|
+
untracked(() => this.facade.loadScopeOptions(delegator, asAdmin));
|
|
1593
1641
|
if (!initialized) {
|
|
1594
1642
|
initialized = true;
|
|
1595
1643
|
lastDelegatorUserId = delegator;
|
|
@@ -1605,6 +1653,8 @@ class ScopePicker {
|
|
|
1605
1653
|
let timer = null;
|
|
1606
1654
|
effect(() => {
|
|
1607
1655
|
const s = this.scope();
|
|
1656
|
+
const delegator = this.delegatorUserId();
|
|
1657
|
+
const asAdmin = this.adminMode();
|
|
1608
1658
|
untracked(() => {
|
|
1609
1659
|
if (!s.grants.length) {
|
|
1610
1660
|
this.facade.clearScopePreview();
|
|
@@ -1612,7 +1662,10 @@ class ScopePicker {
|
|
|
1612
1662
|
}
|
|
1613
1663
|
if (timer)
|
|
1614
1664
|
clearTimeout(timer);
|
|
1615
|
-
timer = setTimeout(() => this.facade.previewScope(s
|
|
1665
|
+
timer = setTimeout(() => this.facade.previewScope(s, {
|
|
1666
|
+
delegatorUserId: delegator,
|
|
1667
|
+
asAdmin,
|
|
1668
|
+
}), 300);
|
|
1616
1669
|
});
|
|
1617
1670
|
});
|
|
1618
1671
|
effect(() => {
|
|
@@ -1648,11 +1701,17 @@ class ScopePicker {
|
|
|
1648
1701
|
formatDeniedTarget(value) {
|
|
1649
1702
|
return humanizeDelegationKey(value);
|
|
1650
1703
|
}
|
|
1704
|
+
groupTargetCount(group) {
|
|
1705
|
+
return group.targets.length;
|
|
1706
|
+
}
|
|
1707
|
+
targetGrantCount(targetGroup) {
|
|
1708
|
+
return targetGroup.grants.length;
|
|
1709
|
+
}
|
|
1651
1710
|
buildTreeNodes(groups) {
|
|
1652
1711
|
return groups.map((group) => ({
|
|
1653
1712
|
key: `group:${group.key}`,
|
|
1654
|
-
label: this.getGroupLabel(group)
|
|
1655
|
-
selectable:
|
|
1713
|
+
label: `${this.getGroupLabel(group)} (${this.groupTargetCount(group)})`,
|
|
1714
|
+
selectable: !this.readonly(),
|
|
1656
1715
|
expanded: true,
|
|
1657
1716
|
children: group.targets.map((targetGroup) => this.buildTargetNode(targetGroup)),
|
|
1658
1717
|
}));
|
|
@@ -1660,8 +1719,8 @@ class ScopePicker {
|
|
|
1660
1719
|
buildTargetNode(targetGroup) {
|
|
1661
1720
|
return {
|
|
1662
1721
|
key: `target:${targetGroup.key}`,
|
|
1663
|
-
label: this.getTargetLabel(targetGroup)
|
|
1664
|
-
selectable:
|
|
1722
|
+
label: `${this.getTargetLabel(targetGroup)} (${this.targetGrantCount(targetGroup)})`,
|
|
1723
|
+
selectable: !this.readonly(),
|
|
1665
1724
|
expanded: true,
|
|
1666
1725
|
children: targetGroup.grants.map((grant) => ({
|
|
1667
1726
|
key: grantKey(grant),
|
|
@@ -1685,12 +1744,12 @@ class ScopePicker {
|
|
|
1685
1744
|
return this.activeLang() ?? this.transloco.getActiveLang();
|
|
1686
1745
|
}
|
|
1687
1746
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ScopePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1688
|
-
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=\"flex flex-col gap-4\">\n @if (isLoadingOptions()) {\n <p-skeleton height=\"
|
|
1747
|
+
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 }, adminMode: { classPropertyName: "adminMode", publicName: "adminMode", 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=\"flex flex-col gap-4\">\n @if (isLoadingOptions()) {\n <div class=\"grid gap-4 2xl:grid-cols-[minmax(0,1fr)_20rem]\">\n <section\n class=\"flex flex-col gap-4 rounded-3xl border border-surface-200 bg-surface-0 p-4 shadow-xs\"\n >\n <div class=\"flex flex-col gap-2\">\n <p-skeleton width=\"9rem\" height=\"1rem\"></p-skeleton>\n <p-skeleton width=\"20rem\" height=\"0.9rem\"></p-skeleton>\n </div>\n\n <p-skeleton height=\"3rem\"></p-skeleton>\n\n <div class=\"grid gap-3\">\n @for (item of [0, 1, 2, 3]; track item) {\n <div class=\"rounded-2xl border border-surface-200 p-4\">\n <div class=\"flex items-center justify-between gap-3\">\n <p-skeleton width=\"12rem\" height=\"1rem\"></p-skeleton>\n <p-skeleton width=\"1.5rem\" height=\"1.5rem\"></p-skeleton>\n </div>\n </div>\n }\n </div>\n </section>\n\n <section\n class=\"flex flex-col gap-4 rounded-3xl border border-dashed border-surface-300 bg-surface-50 p-4\"\n >\n <div class=\"flex flex-col gap-2\">\n <p-skeleton width=\"8rem\" height=\"1rem\"></p-skeleton>\n <p-skeleton width=\"100%\" height=\"0.85rem\"></p-skeleton>\n </div>\n\n <div class=\"flex flex-col gap-3\">\n @for (item of [0, 1, 2]; track item) {\n <p-skeleton height=\"1rem\"></p-skeleton>\n }\n </div>\n </section>\n </div>\n } @else {\n <section class=\"flex flex-col gap-3\">\n @if (errorOptions(); as errorMessage) {\n <div\n class=\"rounded-2xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n >\n {{ errorMessage }}\n </div>\n }\n\n @if (groups().length === 0 && !errorOptions()) {\n <div\n class=\"flex min-h-72 flex-col items-center justify-center gap-4 rounded-3xl border border-dashed border-surface-300 bg-surface-50 px-6 py-8 text-center\"\n >\n <div\n class=\"flex size-18 items-center justify-center rounded-3xl bg-surface-0 text-primary shadow-sm\"\n >\n <svg\n viewBox=\"0 0 64 64\"\n class=\"size-10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"10\"\n y=\"12\"\n width=\"44\"\n height=\"38\"\n rx=\"12\"\n class=\"fill-primary/10 stroke-primary/35\"\n stroke-width=\"2\"\n />\n <path\n d=\"M21 27H43\"\n class=\"stroke-primary\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M21 35H37\"\n class=\"stroke-primary/70\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n <circle\n cx=\"46\"\n cy=\"19\"\n r=\"6\"\n class=\"fill-surface-0 stroke-primary\"\n stroke-width=\"2\"\n />\n <path\n d=\"M43 16L49 22\"\n class=\"stroke-primary\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M49 16L43 22\"\n class=\"stroke-primary\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n\n <div class=\"space-y-1\">\n <p class=\"text-base font-medium text-surface-900\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </p>\n <p class=\"text-sm text-surface-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </p>\n </div>\n </div>\n }\n\n @if (groups().length > 0) {\n <div\n class=\"rounded-3xl border border-surface-200 bg-surface-0 p-3 shadow-xs\"\n >\n <mt-tree\n [value]=\"treeNodes()\"\n [(selection)]=\"treeSelection\"\n selectionMode=\"checkbox\"\n [loading]=\"isLoadingOptions()\"\n [propagateSelectionDown]=\"true\"\n [propagateSelectionUp]=\"true\"\n (action)=\"onTreeAction($event)\"\n [filter]=\"true\"\n filterMode=\"lenient\"\n scrollHeight=\"28rem\"\n [virtualScroll]=\"true\"\n [virtualScrollItemSize]=\"72\"\n />\n </div>\n }\n </section>\n\n <section\n class=\"flex flex-col gap-3 rounded-3xl border border-dashed border-surface-300 bg-surface-50 px-4 py-4\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"text-base font-medium text-surface-800\">\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 font-medium text-surface-900\">\n {{\n getPreviewSummary(p.summary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n } @else {\n <div class=\"text-sm font-medium text-red-700\">\n {{ t(\"delegations.scope.previewInvalid\") }}\n </div>\n }\n @if (p.warnings.length > 0) {\n <ul class=\"list-inside list-disc space-y-1 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 space-y-1 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-surface-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </div>\n }\n </section>\n }\n </div>\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Tree, selector: "mt-tree", inputs: ["value", "selection", "selectionMode", "nodeIcon", "propagateSelectionUp", "propagateSelectionDown", "checkAllChildren", "loading", "emptyMessage", "checkAllLabel", "filterPlaceholder", "dataKey", "filter", "filterMode", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "styleClass", "style", "pInputs", "nodeActions", "nodeContextmenuActions", "contextMenuSelection"], outputs: ["selectionChange", "contextMenuSelectionChange", "action"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1689
1748
|
}
|
|
1690
1749
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ScopePicker, decorators: [{
|
|
1691
1750
|
type: Component,
|
|
1692
|
-
args: [{ selector: 'mt-scope-picker', imports: [CommonModule, Tree, SkeletonModule, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex flex-col gap-4\">\n @if (isLoadingOptions()) {\n <p-skeleton height=\"
|
|
1693
|
-
}], 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 }] }] } });
|
|
1751
|
+
args: [{ selector: 'mt-scope-picker', imports: [CommonModule, Tree, SkeletonModule, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex flex-col gap-4\">\n @if (isLoadingOptions()) {\n <div class=\"grid gap-4 2xl:grid-cols-[minmax(0,1fr)_20rem]\">\n <section\n class=\"flex flex-col gap-4 rounded-3xl border border-surface-200 bg-surface-0 p-4 shadow-xs\"\n >\n <div class=\"flex flex-col gap-2\">\n <p-skeleton width=\"9rem\" height=\"1rem\"></p-skeleton>\n <p-skeleton width=\"20rem\" height=\"0.9rem\"></p-skeleton>\n </div>\n\n <p-skeleton height=\"3rem\"></p-skeleton>\n\n <div class=\"grid gap-3\">\n @for (item of [0, 1, 2, 3]; track item) {\n <div class=\"rounded-2xl border border-surface-200 p-4\">\n <div class=\"flex items-center justify-between gap-3\">\n <p-skeleton width=\"12rem\" height=\"1rem\"></p-skeleton>\n <p-skeleton width=\"1.5rem\" height=\"1.5rem\"></p-skeleton>\n </div>\n </div>\n }\n </div>\n </section>\n\n <section\n class=\"flex flex-col gap-4 rounded-3xl border border-dashed border-surface-300 bg-surface-50 p-4\"\n >\n <div class=\"flex flex-col gap-2\">\n <p-skeleton width=\"8rem\" height=\"1rem\"></p-skeleton>\n <p-skeleton width=\"100%\" height=\"0.85rem\"></p-skeleton>\n </div>\n\n <div class=\"flex flex-col gap-3\">\n @for (item of [0, 1, 2]; track item) {\n <p-skeleton height=\"1rem\"></p-skeleton>\n }\n </div>\n </section>\n </div>\n } @else {\n <section class=\"flex flex-col gap-3\">\n @if (errorOptions(); as errorMessage) {\n <div\n class=\"rounded-2xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\n >\n {{ errorMessage }}\n </div>\n }\n\n @if (groups().length === 0 && !errorOptions()) {\n <div\n class=\"flex min-h-72 flex-col items-center justify-center gap-4 rounded-3xl border border-dashed border-surface-300 bg-surface-50 px-6 py-8 text-center\"\n >\n <div\n class=\"flex size-18 items-center justify-center rounded-3xl bg-surface-0 text-primary shadow-sm\"\n >\n <svg\n viewBox=\"0 0 64 64\"\n class=\"size-10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"10\"\n y=\"12\"\n width=\"44\"\n height=\"38\"\n rx=\"12\"\n class=\"fill-primary/10 stroke-primary/35\"\n stroke-width=\"2\"\n />\n <path\n d=\"M21 27H43\"\n class=\"stroke-primary\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M21 35H37\"\n class=\"stroke-primary/70\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n <circle\n cx=\"46\"\n cy=\"19\"\n r=\"6\"\n class=\"fill-surface-0 stroke-primary\"\n stroke-width=\"2\"\n />\n <path\n d=\"M43 16L49 22\"\n class=\"stroke-primary\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M49 16L43 22\"\n class=\"stroke-primary\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n\n <div class=\"space-y-1\">\n <p class=\"text-base font-medium text-surface-900\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </p>\n <p class=\"text-sm text-surface-500\">\n {{ t(\"delegations.scope.noGrantableOptions\") }}\n </p>\n </div>\n </div>\n }\n\n @if (groups().length > 0) {\n <div\n class=\"rounded-3xl border border-surface-200 bg-surface-0 p-3 shadow-xs\"\n >\n <mt-tree\n [value]=\"treeNodes()\"\n [(selection)]=\"treeSelection\"\n selectionMode=\"checkbox\"\n [loading]=\"isLoadingOptions()\"\n [propagateSelectionDown]=\"true\"\n [propagateSelectionUp]=\"true\"\n (action)=\"onTreeAction($event)\"\n [filter]=\"true\"\n filterMode=\"lenient\"\n scrollHeight=\"28rem\"\n [virtualScroll]=\"true\"\n [virtualScrollItemSize]=\"72\"\n />\n </div>\n }\n </section>\n\n <section\n class=\"flex flex-col gap-3 rounded-3xl border border-dashed border-surface-300 bg-surface-50 px-4 py-4\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"text-base font-medium text-surface-800\">\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 font-medium text-surface-900\">\n {{\n getPreviewSummary(p.summary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n } @else {\n <div class=\"text-sm font-medium text-red-700\">\n {{ t(\"delegations.scope.previewInvalid\") }}\n </div>\n }\n @if (p.warnings.length > 0) {\n <ul class=\"list-inside list-disc space-y-1 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 space-y-1 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-surface-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </div>\n }\n </section>\n }\n </div>\n</ng-container>\n" }]
|
|
1752
|
+
}], 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 }] }], adminMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "adminMode", required: false }] }], delegatorUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "delegatorUserId", required: false }] }] } });
|
|
1694
1753
|
function humanizeDelegationDisplay(value, language) {
|
|
1695
1754
|
return (formatDelegationScopeSummary(value, language) ||
|
|
1696
1755
|
humanizeDelegationKey(typeof value === 'string' ? value : null));
|
|
@@ -1967,7 +2026,7 @@ class DelegationForm {
|
|
|
1967
2026
|
ngOnInit() {
|
|
1968
2027
|
const editing = this.delegationForEdit();
|
|
1969
2028
|
if (editing) {
|
|
1970
|
-
this.facade.getDetail(editing.delegationId);
|
|
2029
|
+
this.facade.getDetail(editing.delegationId, this.adminMode());
|
|
1971
2030
|
}
|
|
1972
2031
|
}
|
|
1973
2032
|
canSubmit = computed(() => !this.readonly() &&
|
|
@@ -1980,23 +2039,59 @@ class DelegationForm {
|
|
|
1980
2039
|
return;
|
|
1981
2040
|
if (!this.canSubmit())
|
|
1982
2041
|
return;
|
|
1983
|
-
const
|
|
2042
|
+
const value = this.delegationFormControl.getRawValue();
|
|
2043
|
+
const scope = this.scope();
|
|
2044
|
+
const delegationDaysType = (value?.delegationDaysType ?? 'FullRange');
|
|
2045
|
+
const specificDays = delegationDaysType === 'SpecificDays' ? (value?.specificDays ?? []) : [];
|
|
2046
|
+
const description = value?.description;
|
|
2047
|
+
const delegateFromDateTime = value?.delegateFromDateTime;
|
|
2048
|
+
const delegateToDateTime = value?.delegateToDateTime;
|
|
2049
|
+
const requiresApproval = !!value?.requiresApproval;
|
|
2050
|
+
const delegatedUserId = extractUserId(value?.delegateTo) ?? '';
|
|
2051
|
+
const selectedDelegatorId = this.selectedDelegatorId();
|
|
2052
|
+
const editing = this.delegationForEdit();
|
|
2053
|
+
if (this.adminMode()) {
|
|
2054
|
+
if (!selectedDelegatorId || !delegatedUserId) {
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
const base = {
|
|
2058
|
+
delegatorUserId: selectedDelegatorId,
|
|
2059
|
+
delegatedUserId,
|
|
2060
|
+
description,
|
|
2061
|
+
delegateFromDateTime,
|
|
2062
|
+
delegateToDateTime,
|
|
2063
|
+
delegationDaysType,
|
|
2064
|
+
specificDays,
|
|
2065
|
+
requiresApproval,
|
|
2066
|
+
scope,
|
|
2067
|
+
};
|
|
2068
|
+
if (editing) {
|
|
2069
|
+
const latestRowVersion = this.detail()?.row?.rowVersion ?? editing.rowVersion;
|
|
2070
|
+
const req = {
|
|
2071
|
+
...base,
|
|
2072
|
+
rowVersion: latestRowVersion,
|
|
2073
|
+
};
|
|
2074
|
+
this.facade.updateV2(editing.delegationId, req, true).subscribe({
|
|
2075
|
+
next: () => this.ref.close(true),
|
|
2076
|
+
});
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
this.facade.createV2(base, true).subscribe({
|
|
2080
|
+
next: () => this.ref.close(true),
|
|
2081
|
+
});
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
1984
2084
|
const base = {
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
delegationDaysType: (v?.delegationDaysType ?? 'FullRange'),
|
|
1995
|
-
specificDays: v?.delegationDaysType === 'SpecificDays' ? (v?.specificDays ?? []) : [],
|
|
1996
|
-
requiresApproval: !!v?.requiresApproval,
|
|
1997
|
-
scope: this.scope(),
|
|
2085
|
+
delegateFrom: null,
|
|
2086
|
+
delegateTo: delegatedUserId,
|
|
2087
|
+
description,
|
|
2088
|
+
delegateFromDateTime,
|
|
2089
|
+
delegateToDateTime,
|
|
2090
|
+
delegationDaysType,
|
|
2091
|
+
specificDays,
|
|
2092
|
+
requiresApproval,
|
|
2093
|
+
scope,
|
|
1998
2094
|
};
|
|
1999
|
-
const editing = this.delegationForEdit();
|
|
2000
2095
|
if (editing) {
|
|
2001
2096
|
// Prefer the freshest rowVersion from the loaded detail (the form loads
|
|
2002
2097
|
// detail on open); fall back to the list row only if detail is absent.
|
|
@@ -2028,7 +2123,7 @@ class DelegationForm {
|
|
|
2028
2123
|
};
|
|
2029
2124
|
}
|
|
2030
2125
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2031
|
-
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 'flex h-full min-h-0 min-w-0 flex-col overflow-hidden ' +\n modal.contentClass\n \"\n >\n <div\n class=\"
|
|
2126
|
+
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 'flex h-full min-h-0 min-w-0 flex-col overflow-hidden ' +\n modal.contentClass\n \"\n >\n <div\n class=\"grid min-h-0 flex-1 gap-4 overflow-y-auto p-4 max-[640px]:p-3 lg:grid-cols-[minmax(0,28rem)_minmax(0,1fr)] lg:items-start\"\n >\n <section\n class=\"flex flex-col gap-4 rounded-3xl border border-surface-200 bg-surface-0 p-4 shadow-xs lg:sticky lg:top-0\"\n >\n <mt-dynamic-form\n [formConfig]=\"formConfig()\"\n [formControl]=\"delegationFormControl\"\n />\n </section>\n\n <section\n class=\"flex min-h-0 flex-col gap-4 rounded-3xl border border-surface-200 bg-surface-0 p-4 shadow-xs\"\n >\n <div class=\"flex flex-col gap-2\">\n <div\n class=\"inline-flex w-fit items-center gap-2 rounded-full bg-primary-50 px-3 py-1 text-xs font-medium text-primary-700\"\n >\n <span class=\"inline-flex size-2 rounded-full bg-primary-500\"></span>\n {{ t(\"delegations.scope.previewTitle\") }}\n </div>\n <h3 class=\"text-xl font-semibold text-surface-900\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </h3>\n @if (adminMode() && !showScopePicker()) {\n <p class=\"text-sm text-surface-500\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </p>\n } @else {\n <p class=\"text-sm text-surface-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </p>\n }\n </div>\n\n @if (showScopePicker()) {\n <mt-scope-picker\n [(scope)]=\"scope\"\n [readonly]=\"readonly()\"\n [adminMode]=\"adminMode()\"\n [delegatorUserId]=\"selectedDelegatorId()\"\n ></mt-scope-picker>\n } @else {\n <div\n class=\"flex min-h-72 flex-col items-center justify-center gap-4 rounded-3xl border border-dashed border-surface-300 bg-surface-50 px-6 py-8 text-center\"\n >\n <div\n class=\"flex size-18 items-center justify-center rounded-3xl bg-surface-0 text-primary shadow-sm\"\n >\n <svg\n viewBox=\"0 0 64 64\"\n class=\"size-10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"10\"\n y=\"12\"\n width=\"44\"\n height=\"40\"\n rx=\"12\"\n class=\"fill-primary/10 stroke-primary/35\"\n stroke-width=\"2\"\n />\n <path\n d=\"M22 28H42\"\n class=\"stroke-primary\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M22 36H34\"\n class=\"stroke-primary/70\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n <circle\n cx=\"45\"\n cy=\"20\"\n r=\"7\"\n class=\"fill-surface-0 stroke-primary\"\n stroke-width=\"2\"\n />\n <path\n d=\"M45 17V23\"\n class=\"stroke-primary\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M42 20H48\"\n class=\"stroke-primary\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n <div class=\"space-y-1\">\n <p class=\"text-base font-medium text-surface-900\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </p>\n <p class=\"text-sm text-surface-500\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </p>\n </div>\n </div>\n }\n </section>\n </div>\n\n <div [class]=\"modal.footerClass\">\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 </div>\n</ng-container>\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", "adminMode", "delegatorUserId"], outputs: ["scopeChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2032
2127
|
}
|
|
2033
2128
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationForm, decorators: [{
|
|
2034
2129
|
type: Component,
|
|
@@ -2039,7 +2134,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2039
2134
|
ReactiveFormsModule,
|
|
2040
2135
|
ScopePicker,
|
|
2041
2136
|
TranslocoDirective,
|
|
2042
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n 'flex h-full min-h-0 min-w-0 flex-col overflow-hidden ' +\n modal.contentClass\n \"\n >\n <div\n class=\"
|
|
2137
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n 'flex h-full min-h-0 min-w-0 flex-col overflow-hidden ' +\n modal.contentClass\n \"\n >\n <div\n class=\"grid min-h-0 flex-1 gap-4 overflow-y-auto p-4 max-[640px]:p-3 lg:grid-cols-[minmax(0,28rem)_minmax(0,1fr)] lg:items-start\"\n >\n <section\n class=\"flex flex-col gap-4 rounded-3xl border border-surface-200 bg-surface-0 p-4 shadow-xs lg:sticky lg:top-0\"\n >\n <mt-dynamic-form\n [formConfig]=\"formConfig()\"\n [formControl]=\"delegationFormControl\"\n />\n </section>\n\n <section\n class=\"flex min-h-0 flex-col gap-4 rounded-3xl border border-surface-200 bg-surface-0 p-4 shadow-xs\"\n >\n <div class=\"flex flex-col gap-2\">\n <div\n class=\"inline-flex w-fit items-center gap-2 rounded-full bg-primary-50 px-3 py-1 text-xs font-medium text-primary-700\"\n >\n <span class=\"inline-flex size-2 rounded-full bg-primary-500\"></span>\n {{ t(\"delegations.scope.previewTitle\") }}\n </div>\n <h3 class=\"text-xl font-semibold text-surface-900\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </h3>\n @if (adminMode() && !showScopePicker()) {\n <p class=\"text-sm text-surface-500\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </p>\n } @else {\n <p class=\"text-sm text-surface-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </p>\n }\n </div>\n\n @if (showScopePicker()) {\n <mt-scope-picker\n [(scope)]=\"scope\"\n [readonly]=\"readonly()\"\n [adminMode]=\"adminMode()\"\n [delegatorUserId]=\"selectedDelegatorId()\"\n ></mt-scope-picker>\n } @else {\n <div\n class=\"flex min-h-72 flex-col items-center justify-center gap-4 rounded-3xl border border-dashed border-surface-300 bg-surface-50 px-6 py-8 text-center\"\n >\n <div\n class=\"flex size-18 items-center justify-center rounded-3xl bg-surface-0 text-primary shadow-sm\"\n >\n <svg\n viewBox=\"0 0 64 64\"\n class=\"size-10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"10\"\n y=\"12\"\n width=\"44\"\n height=\"40\"\n rx=\"12\"\n class=\"fill-primary/10 stroke-primary/35\"\n stroke-width=\"2\"\n />\n <path\n d=\"M22 28H42\"\n class=\"stroke-primary\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M22 36H34\"\n class=\"stroke-primary/70\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n <circle\n cx=\"45\"\n cy=\"20\"\n r=\"7\"\n class=\"fill-surface-0 stroke-primary\"\n stroke-width=\"2\"\n />\n <path\n d=\"M45 17V23\"\n class=\"stroke-primary\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M42 20H48\"\n class=\"stroke-primary\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n <div class=\"space-y-1\">\n <p class=\"text-base font-medium text-surface-900\">\n {{ t(\"delegations.scope.permissionsTitle\") }}\n </p>\n <p class=\"text-sm text-surface-500\">\n {{ t(\"delegations.form.selectDelegatorFirst\") }}\n </p>\n </div>\n </div>\n }\n </section>\n </div>\n\n <div [class]=\"modal.footerClass\">\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 </div>\n</ng-container>\n" }]
|
|
2043
2138
|
}], 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 }] }] } });
|
|
2044
2139
|
|
|
2045
2140
|
/**
|
|
@@ -2047,6 +2142,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2047
2142
|
*/
|
|
2048
2143
|
class DelegationDetailDrawer {
|
|
2049
2144
|
delegationId = input.required(...(ngDevMode ? [{ debugName: "delegationId" }] : /* istanbul ignore next */ []));
|
|
2145
|
+
adminMode = input(false, ...(ngDevMode ? [{ debugName: "adminMode" }] : /* istanbul ignore next */ []));
|
|
2050
2146
|
facade = inject(DelegationsFacade);
|
|
2051
2147
|
transloco = inject(TranslocoService);
|
|
2052
2148
|
ref = inject(ModalRef);
|
|
@@ -2059,7 +2155,7 @@ class DelegationDetailDrawer {
|
|
|
2059
2155
|
detail = this.facade.detail;
|
|
2060
2156
|
row = computed(() => this.detail()?.row ?? null, ...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
|
|
2061
2157
|
ngOnInit() {
|
|
2062
|
-
this.facade.getDetail(this.delegationId());
|
|
2158
|
+
this.facade.getDetail(this.delegationId(), this.adminMode());
|
|
2063
2159
|
}
|
|
2064
2160
|
setTab(tab) {
|
|
2065
2161
|
this.activeTab.set(tab);
|
|
@@ -2078,7 +2174,7 @@ class DelegationDetailDrawer {
|
|
|
2078
2174
|
return formatDelegationScopeSummary(summary, this.transloco.getActiveLang());
|
|
2079
2175
|
}
|
|
2080
2176
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationDetailDrawer, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2081
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationDetailDrawer, isStandalone: true, selector: "mt-delegation-detail-drawer", inputs: { delegationId: { classPropertyName: "delegationId", publicName: "delegationId", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex flex-col h-full\">\n <!-- Tabs -->\n <div class=\"flex border-b border-gray-200 px-4\">\n @for (tab of tabs; track tab.key) {\n <button\n type=\"button\"\n class=\"px-3 py-2 -mb-px border-b-2 text-sm font-medium transition-colors\"\n [class.border-primary]=\"activeTab() === tab.key\"\n [class.text-primary]=\"activeTab() === tab.key\"\n [class.border-transparent]=\"activeTab() !== tab.key\"\n [class.text-gray-500]=\"activeTab() !== tab.key\"\n (click)=\"setTab(tab.key)\"\n >\n {{ t(tab.i18n) }}\n </button>\n }\n </div>\n\n <!-- Body -->\n <div class=\"flex-1 overflow-y-auto p-4\">\n @if (isLoading() && !detail()) {\n <p-skeleton height=\"2rem\" class=\"mb-3\"></p-skeleton>\n <p-skeleton height=\"6rem\" class=\"mb-3\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n } @else if (detail(); as d) {\n @if (activeTab() === \"overview\") {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex items-center gap-3 min-w-0\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-12! h-12! text-lg!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.delegatorName\") }}\n </div>\n <div class=\"text-base font-medium text-gray-900 truncate\">\n {{ d.row.delegator.displayName }}\n </div>\n @if (d.row.delegator.email) {\n <div class=\"text-xs text-gray-500 truncate\">\n {{ d.row.delegator.email }}\n </div>\n }\n </div>\n </div>\n <mt-delegation-status-chip\n [status]=\"d.status.effectiveStatus\"\n ></mt-delegation-status-chip>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4\">\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.delegatedTo\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.delegatedUser.displayName }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.approval\") }}\n </span>\n <span class=\"text-sm text-gray-900\">{{ approvalLabel() }}</span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.startDate\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.startsAtUtc | date: \"medium\" }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.endDate\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.endsAtUtc | date: \"medium\" }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.form.timeZone\") }}\n </span>\n <span class=\"text-sm text-gray-900\">{{\n d.row.timeZoneId\n }}</span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.days\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n @if (d.row.dayRuleMode === \"FullRange\") {\n {{ t(\"delegations.form.fullRange\") }}\n } @else {\n {{ d.row.specificDays.join(\", \") }}\n }\n </span>\n </div>\n </div>\n\n @if (d.row.cancellation?.cancellationReason) {\n <div\n class=\"rounded-md border border-gray-200 bg-surface-50 p-3 text-sm text-gray-800\"\n >\n <div class=\"font-medium\">\n {{ t(\"delegations.form.cancellationReason\") }}\n </div>\n <div>{{ d.row.cancellation.cancellationReason }}</div>\n </div>\n }\n </div>\n } @else {\n <!-- Scope tab -->\n <div class=\"flex flex-col gap-3\">\n <div class=\"text-sm text-gray-900\">\n {{\n formatScopeSummary(d.row.scopeSummary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n <div class=\"flex flex-col gap-2\">\n @for (grant of d.scope.grants; track $index) {\n <div\n class=\"border border-gray-200 rounded-md px-3 py-2 flex flex-col gap-1\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-sm font-medium text-gray-900\">\n {{ getScopeTargetLabel(grant.target) }}\n </span>\n <span class=\"text-xs text-gray-500\">\n {{ grant.target.targetType }}\n </span>\n </div>\n <span\n class=\"text-xs px-2 py-0.5 rounded-md bg-primary-50 text-primary w-fit\"\n >\n {{ getScopeActionLabel(grant.action) }}\n </span>\n </div>\n }\n @if (d.scope.grants.length === 0) {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </p>\n }\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Footer -->\n <div\n class=\"border-t border-gray-200 px-4 py-3 flex items-center justify-end\"\n >\n <mt-button\n [label]=\"t('delegations.common.cancel')\"\n variant=\"outlined\"\n (click)=\"ref.close()\"\n ></mt-button>\n </div>\n </div>\n</ng-container>\n", styles: [":host{display:block;height:100%}\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: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { 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"] }, { kind: "pipe", type: i2.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2177
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationDetailDrawer, isStandalone: true, selector: "mt-delegation-detail-drawer", inputs: { delegationId: { classPropertyName: "delegationId", publicName: "delegationId", isSignal: true, isRequired: true, transformFunction: null }, adminMode: { classPropertyName: "adminMode", publicName: "adminMode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex flex-col h-full\">\n <!-- Tabs -->\n <div class=\"flex border-b border-gray-200 px-4\">\n @for (tab of tabs; track tab.key) {\n <button\n type=\"button\"\n class=\"px-3 py-2 -mb-px border-b-2 text-sm font-medium transition-colors\"\n [class.border-primary]=\"activeTab() === tab.key\"\n [class.text-primary]=\"activeTab() === tab.key\"\n [class.border-transparent]=\"activeTab() !== tab.key\"\n [class.text-gray-500]=\"activeTab() !== tab.key\"\n (click)=\"setTab(tab.key)\"\n >\n {{ t(tab.i18n) }}\n </button>\n }\n </div>\n\n <!-- Body -->\n <div class=\"flex-1 overflow-y-auto p-4\">\n @if (isLoading() && !detail()) {\n <p-skeleton height=\"2rem\" class=\"mb-3\"></p-skeleton>\n <p-skeleton height=\"6rem\" class=\"mb-3\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n } @else if (detail(); as d) {\n @if (activeTab() === \"overview\") {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex items-center gap-3 min-w-0\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-12! h-12! text-lg!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.delegatorName\") }}\n </div>\n <div class=\"text-base font-medium text-gray-900 truncate\">\n {{ d.row.delegator.displayName }}\n </div>\n @if (d.row.delegator.email) {\n <div class=\"text-xs text-gray-500 truncate\">\n {{ d.row.delegator.email }}\n </div>\n }\n </div>\n </div>\n <mt-delegation-status-chip\n [status]=\"d.status.effectiveStatus\"\n ></mt-delegation-status-chip>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4\">\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.delegatedTo\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.delegatedUser.displayName }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.approval\") }}\n </span>\n <span class=\"text-sm text-gray-900\">{{ approvalLabel() }}</span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.startDate\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.startsAtUtc | date: \"medium\" }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.endDate\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.endsAtUtc | date: \"medium\" }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.form.timeZone\") }}\n </span>\n <span class=\"text-sm text-gray-900\">{{\n d.row.timeZoneId\n }}</span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.days\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n @if (d.row.dayRuleMode === \"FullRange\") {\n {{ t(\"delegations.form.fullRange\") }}\n } @else {\n {{ d.row.specificDays.join(\", \") }}\n }\n </span>\n </div>\n </div>\n\n @if (d.row.cancellation?.cancellationReason) {\n <div\n class=\"rounded-md border border-gray-200 bg-surface-50 p-3 text-sm text-gray-800\"\n >\n <div class=\"font-medium\">\n {{ t(\"delegations.form.cancellationReason\") }}\n </div>\n <div>{{ d.row.cancellation.cancellationReason }}</div>\n </div>\n }\n </div>\n } @else {\n <!-- Scope tab -->\n <div class=\"flex flex-col gap-3\">\n <div class=\"text-sm text-gray-900\">\n {{\n formatScopeSummary(d.row.scopeSummary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n <div class=\"flex flex-col gap-2\">\n @for (grant of d.scope.grants; track $index) {\n <div\n class=\"border border-gray-200 rounded-md px-3 py-2 flex flex-col gap-1\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-sm font-medium text-gray-900\">\n {{ getScopeTargetLabel(grant.target) }}\n </span>\n <span class=\"text-xs text-gray-500\">\n {{ grant.target.targetType }}\n </span>\n </div>\n <span\n class=\"text-xs px-2 py-0.5 rounded-md bg-primary-50 text-primary w-fit\"\n >\n {{ getScopeActionLabel(grant.action) }}\n </span>\n </div>\n }\n @if (d.scope.grants.length === 0) {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </p>\n }\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Footer -->\n <div\n class=\"border-t border-gray-200 px-4 py-3 flex items-center justify-end\"\n >\n <mt-button\n [label]=\"t('delegations.common.cancel')\"\n variant=\"outlined\"\n (click)=\"ref.close()\"\n ></mt-button>\n </div>\n </div>\n</ng-container>\n", styles: [":host{display:block;height:100%}\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: "ngmodule", type: SkeletonModule }, { kind: "component", type: i1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { 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"] }, { kind: "pipe", type: i2.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2082
2178
|
}
|
|
2083
2179
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationDetailDrawer, decorators: [{
|
|
2084
2180
|
type: Component,
|
|
@@ -2090,7 +2186,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2090
2186
|
TranslocoDirective,
|
|
2091
2187
|
DelegationStatusChip,
|
|
2092
2188
|
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex flex-col h-full\">\n <!-- Tabs -->\n <div class=\"flex border-b border-gray-200 px-4\">\n @for (tab of tabs; track tab.key) {\n <button\n type=\"button\"\n class=\"px-3 py-2 -mb-px border-b-2 text-sm font-medium transition-colors\"\n [class.border-primary]=\"activeTab() === tab.key\"\n [class.text-primary]=\"activeTab() === tab.key\"\n [class.border-transparent]=\"activeTab() !== tab.key\"\n [class.text-gray-500]=\"activeTab() !== tab.key\"\n (click)=\"setTab(tab.key)\"\n >\n {{ t(tab.i18n) }}\n </button>\n }\n </div>\n\n <!-- Body -->\n <div class=\"flex-1 overflow-y-auto p-4\">\n @if (isLoading() && !detail()) {\n <p-skeleton height=\"2rem\" class=\"mb-3\"></p-skeleton>\n <p-skeleton height=\"6rem\" class=\"mb-3\"></p-skeleton>\n <p-skeleton height=\"6rem\"></p-skeleton>\n } @else if (detail(); as d) {\n @if (activeTab() === \"overview\") {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex items-center gap-3 min-w-0\">\n <mt-avatar\n icon=\"user.user-01\"\n styleClass=\"w-12! h-12! text-lg!\"\n ></mt-avatar>\n <div class=\"flex flex-col min-w-0\">\n <div class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.delegatorName\") }}\n </div>\n <div class=\"text-base font-medium text-gray-900 truncate\">\n {{ d.row.delegator.displayName }}\n </div>\n @if (d.row.delegator.email) {\n <div class=\"text-xs text-gray-500 truncate\">\n {{ d.row.delegator.email }}\n </div>\n }\n </div>\n </div>\n <mt-delegation-status-chip\n [status]=\"d.status.effectiveStatus\"\n ></mt-delegation-status-chip>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4\">\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.delegatedTo\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.delegatedUser.displayName }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.approval\") }}\n </span>\n <span class=\"text-sm text-gray-900\">{{ approvalLabel() }}</span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.startDate\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.startsAtUtc | date: \"medium\" }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.endDate\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n {{ d.row.endsAtUtc | date: \"medium\" }}\n </span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.form.timeZone\") }}\n </span>\n <span class=\"text-sm text-gray-900\">{{\n d.row.timeZoneId\n }}</span>\n </div>\n <div class=\"flex flex-col\">\n <span class=\"text-xs text-gray-500\">\n {{ t(\"delegations.column.days\") }}\n </span>\n <span class=\"text-sm text-gray-900\">\n @if (d.row.dayRuleMode === \"FullRange\") {\n {{ t(\"delegations.form.fullRange\") }}\n } @else {\n {{ d.row.specificDays.join(\", \") }}\n }\n </span>\n </div>\n </div>\n\n @if (d.row.cancellation?.cancellationReason) {\n <div\n class=\"rounded-md border border-gray-200 bg-surface-50 p-3 text-sm text-gray-800\"\n >\n <div class=\"font-medium\">\n {{ t(\"delegations.form.cancellationReason\") }}\n </div>\n <div>{{ d.row.cancellation.cancellationReason }}</div>\n </div>\n }\n </div>\n } @else {\n <!-- Scope tab -->\n <div class=\"flex flex-col gap-3\">\n <div class=\"text-sm text-gray-900\">\n {{\n formatScopeSummary(d.row.scopeSummary) ||\n t(\"delegations.column.scopeSummary\")\n }}\n </div>\n <div class=\"flex flex-col gap-2\">\n @for (grant of d.scope.grants; track $index) {\n <div\n class=\"border border-gray-200 rounded-md px-3 py-2 flex flex-col gap-1\"\n >\n <div class=\"flex items-center justify-between gap-2\">\n <span class=\"text-sm font-medium text-gray-900\">\n {{ getScopeTargetLabel(grant.target) }}\n </span>\n <span class=\"text-xs text-gray-500\">\n {{ grant.target.targetType }}\n </span>\n </div>\n <span\n class=\"text-xs px-2 py-0.5 rounded-md bg-primary-50 text-primary w-fit\"\n >\n {{ getScopeActionLabel(grant.action) }}\n </span>\n </div>\n }\n @if (d.scope.grants.length === 0) {\n <p class=\"text-xs text-gray-500\">\n {{ t(\"delegations.scope.noSelection\") }}\n </p>\n }\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Footer -->\n <div\n class=\"border-t border-gray-200 px-4 py-3 flex items-center justify-end\"\n >\n <mt-button\n [label]=\"t('delegations.common.cancel')\"\n variant=\"outlined\"\n (click)=\"ref.close()\"\n ></mt-button>\n </div>\n </div>\n</ng-container>\n", styles: [":host{display:block;height:100%}\n"] }]
|
|
2093
|
-
}], propDecorators: { delegationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "delegationId", required: true }] }] } });
|
|
2189
|
+
}], propDecorators: { delegationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "delegationId", required: true }] }], adminMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "adminMode", required: false }] }] } });
|
|
2094
2190
|
|
|
2095
2191
|
/**
|
|
2096
2192
|
* Delegations portal page (doc 02, 09): two lists — My Delegations (current user
|
|
@@ -2176,7 +2272,7 @@ class DelegationsList {
|
|
|
2176
2272
|
if (this.adminMode())
|
|
2177
2273
|
return true;
|
|
2178
2274
|
if (this.isLoadingScopeOptions())
|
|
2179
|
-
return
|
|
2275
|
+
return false;
|
|
2180
2276
|
return hasDelegationGrantableScope(this.scopeOptions());
|
|
2181
2277
|
}, ...(ngDevMode ? [{ debugName: "canCreate" }] : /* istanbul ignore next */ []));
|
|
2182
2278
|
tableActions = computed(() => this.canCreate()
|
|
@@ -2382,15 +2478,18 @@ class DelegationsList {
|
|
|
2382
2478
|
appendTo: 'page-content',
|
|
2383
2479
|
dismissableMask: true,
|
|
2384
2480
|
dismissible: true,
|
|
2385
|
-
inputValues: {
|
|
2481
|
+
inputValues: {
|
|
2482
|
+
delegationId: row.delegationId,
|
|
2483
|
+
adminMode: this.adminMode(),
|
|
2484
|
+
},
|
|
2386
2485
|
});
|
|
2387
2486
|
}
|
|
2388
2487
|
openForm(row) {
|
|
2389
2488
|
const ref = this.modal.openModal(DelegationForm, row ? 'drawer' : 'dialog', {
|
|
2390
2489
|
header: this.transloco.translate(row ? 'delegations.action.edit' : 'delegations.action.create'),
|
|
2391
2490
|
styleClass: row
|
|
2392
|
-
? '!absolute !shadow-none !w-full !max-w-full sm:!w-[
|
|
2393
|
-
: '!w-[min(
|
|
2491
|
+
? '!absolute !shadow-none !w-full !max-w-full sm:!w-[56rem] xl:!w-[68rem]'
|
|
2492
|
+
: '!w-[min(98vw,88rem)] !max-w-[98vw] !h-[min(94vh,56rem)] !max-h-[94vh] !overflow-hidden',
|
|
2394
2493
|
position: row ? 'end' : '',
|
|
2395
2494
|
appendTo: row ? 'page-content' : 'body',
|
|
2396
2495
|
dismissableMask: true,
|