@masterteam/delegations 0.0.55 → 0.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/delegations.css +1 -1
- package/assets/i18n/ar.json +175 -167
- package/assets/i18n/en.json +175 -167
- package/fesm2022/masterteam-delegations.mjs +357 -148
- package/fesm2022/masterteam-delegations.mjs.map +1 -1
- package/package.json +3 -3
- package/types/masterteam-delegations.d.ts +119 -23
|
@@ -2,22 +2,22 @@ import * as i1 from '@angular/common';
|
|
|
2
2
|
import { DOCUMENT, CommonModule, Location } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { InjectionToken, makeEnvironmentProviders, inject, Injectable, signal, computed, input, ChangeDetectionStrategy, Component, output, DestroyRef, viewChild, effect, model, untracked, booleanAttribute, numberAttribute, linkedSignal } from '@angular/core';
|
|
5
|
+
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
5
6
|
import { TranslocoService, TranslocoDirective } from '@jsverse/transloco';
|
|
7
|
+
import { Actions, Store, ofActionSuccessful, ofActionDispatched, Action, Selector, State, select } from '@ngxs/store';
|
|
6
8
|
import { Avatar } from '@masterteam/components/avatar';
|
|
7
9
|
import { ModalService } from '@masterteam/components/modal';
|
|
10
|
+
import { ToastService } from '@masterteam/components/toast';
|
|
8
11
|
import { Icon } from '@masterteam/icons';
|
|
9
12
|
import { Popover } from 'primeng/popover';
|
|
10
|
-
import {
|
|
11
|
-
import { switchMap, from, EMPTY, finalize, shareReplay, filter, catchError, throwError } from 'rxjs';
|
|
13
|
+
import { EMPTY, switchMap, from, finalize, shareReplay, filter, catchError, throwError } from 'rxjs';
|
|
12
14
|
import { HttpContextToken, HttpContext, HttpClient, HttpParams, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
|
|
13
15
|
import { handleApiRequest, REQUEST_CONTEXT, UserSearchFieldConfig, TextareaFieldConfig, DateFieldConfig, RadioButtonFieldConfig, MultiSelectFieldConfig, ToggleFieldConfig, ValidatorConfig } from '@masterteam/components';
|
|
14
16
|
import { Button } from '@masterteam/components/button';
|
|
15
17
|
import { ModalRef } from '@masterteam/components/dialog';
|
|
16
18
|
import { EntityPreview } from '@masterteam/components/entities';
|
|
17
|
-
import { ToastService } from '@masterteam/components/toast';
|
|
18
19
|
import { RouterLink, ActivatedRoute, Router, NavigationEnd, RouterOutlet } from '@angular/router';
|
|
19
20
|
import { Chip } from '@masterteam/components/chip';
|
|
20
|
-
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
21
21
|
import { Page } from '@masterteam/components/page';
|
|
22
22
|
import { Breadcrumb } from '@masterteam/components/breadcrumb';
|
|
23
23
|
import { Card } from '@masterteam/components/card';
|
|
@@ -32,6 +32,54 @@ import { TextField } from '@masterteam/components/text-field';
|
|
|
32
32
|
import * as i4 from 'primeng/skeleton';
|
|
33
33
|
import { SkeletonModule } from 'primeng/skeleton';
|
|
34
34
|
|
|
35
|
+
/** Fetch the active delegations the current user may start (user/activedelegations). */
|
|
36
|
+
class LoadDelegationCandidates {
|
|
37
|
+
page;
|
|
38
|
+
pageSize;
|
|
39
|
+
append;
|
|
40
|
+
static type = '[DelegationSession] Load Candidates';
|
|
41
|
+
constructor(page = 1, pageSize = 25, append = false) {
|
|
42
|
+
this.page = page;
|
|
43
|
+
this.pageSize = pageSize;
|
|
44
|
+
this.append = append;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Start a delegated session for the given assignment row. */
|
|
48
|
+
class StartDelegationSession {
|
|
49
|
+
delegation;
|
|
50
|
+
static type = '[DelegationSession] Start';
|
|
51
|
+
constructor(delegation) {
|
|
52
|
+
this.delegation = delegation;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Re-mint the session the user was in before they reloaded the page. Dispatched
|
|
57
|
+
* by the state itself from the persisted delegation id — never a token.
|
|
58
|
+
*/
|
|
59
|
+
class ResumeDelegationSession {
|
|
60
|
+
delegation;
|
|
61
|
+
static type = '[DelegationSession] Resume';
|
|
62
|
+
constructor(delegation) {
|
|
63
|
+
this.delegation = delegation;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** End the current delegated session. Client-local only (doc 05). */
|
|
67
|
+
class EndDelegationSession {
|
|
68
|
+
reason;
|
|
69
|
+
static type = '[DelegationSession] End';
|
|
70
|
+
constructor(reason = 'Manual') {
|
|
71
|
+
this.reason = reason;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Switch directly from the current session to another delegation. */
|
|
75
|
+
class SwitchDelegationSession {
|
|
76
|
+
delegation;
|
|
77
|
+
static type = '[DelegationSession] Switch';
|
|
78
|
+
constructor(delegation) {
|
|
79
|
+
this.delegation = delegation;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
35
83
|
const DEFAULT_CONFIG = {
|
|
36
84
|
resolveApplicationApiBaseUrl: () => '',
|
|
37
85
|
resolvePromptNamespace: () => ({
|
|
@@ -58,7 +106,7 @@ function withDelegatedRuntime(context = new HttpContext()) {
|
|
|
58
106
|
return context.set(DELEGATED_RUNTIME_REQUEST, true);
|
|
59
107
|
}
|
|
60
108
|
|
|
61
|
-
const STORAGE_KEY = 'mt.delegation.prompt-receipts.v1';
|
|
109
|
+
const STORAGE_KEY$1 = 'mt.delegation.prompt-receipts.v1';
|
|
62
110
|
const MAX_RECEIPTS = 100;
|
|
63
111
|
class DelegationPromptReceiptService {
|
|
64
112
|
document = inject(DOCUMENT);
|
|
@@ -103,7 +151,7 @@ class DelegationPromptReceiptService {
|
|
|
103
151
|
}
|
|
104
152
|
read() {
|
|
105
153
|
try {
|
|
106
|
-
const raw = this.document.defaultView?.localStorage.getItem(STORAGE_KEY);
|
|
154
|
+
const raw = this.document.defaultView?.localStorage.getItem(STORAGE_KEY$1);
|
|
107
155
|
const parsed = raw ? JSON.parse(raw) : [];
|
|
108
156
|
return Array.isArray(parsed)
|
|
109
157
|
? parsed.filter((item) => typeof item === 'string')
|
|
@@ -116,7 +164,7 @@ class DelegationPromptReceiptService {
|
|
|
116
164
|
write(receipts) {
|
|
117
165
|
try {
|
|
118
166
|
const bounded = [...new Set(receipts)].slice(-MAX_RECEIPTS);
|
|
119
|
-
this.document.defaultView?.localStorage.setItem(STORAGE_KEY, JSON.stringify(bounded));
|
|
167
|
+
this.document.defaultView?.localStorage.setItem(STORAGE_KEY$1, JSON.stringify(bounded));
|
|
120
168
|
}
|
|
121
169
|
catch {
|
|
122
170
|
// Storage can be unavailable; the in-memory claim still coalesces dialogs.
|
|
@@ -130,49 +178,99 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
130
178
|
args: [{ providedIn: 'root' }]
|
|
131
179
|
}] });
|
|
132
180
|
|
|
133
|
-
/** Fetch the active delegations the current user may start (user/activedelegations). */
|
|
134
|
-
class LoadDelegationCandidates {
|
|
135
|
-
page;
|
|
136
|
-
pageSize;
|
|
137
|
-
append;
|
|
138
|
-
static type = '[DelegationSession] Load Candidates';
|
|
139
|
-
constructor(page = 1, pageSize = 25, append = false) {
|
|
140
|
-
this.page = page;
|
|
141
|
-
this.pageSize = pageSize;
|
|
142
|
-
this.append = append;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
/** Start a delegated session for the given assignment row. */
|
|
146
|
-
class StartDelegationSession {
|
|
147
|
-
delegation;
|
|
148
|
-
static type = '[DelegationSession] Start';
|
|
149
|
-
constructor(delegation) {
|
|
150
|
-
this.delegation = delegation;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
/** End the current delegated session. Client-local only (doc 05). */
|
|
154
|
-
class EndDelegationSession {
|
|
155
|
-
reason;
|
|
156
|
-
static type = '[DelegationSession] End';
|
|
157
|
-
constructor(reason = 'Manual') {
|
|
158
|
-
this.reason = reason;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
/** Switch directly from the current session to another delegation. */
|
|
162
|
-
class SwitchDelegationSession {
|
|
163
|
-
delegation;
|
|
164
|
-
static type = '[DelegationSession] Switch';
|
|
165
|
-
constructor(delegation) {
|
|
166
|
-
this.delegation = delegation;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
181
|
var DelegationSessionActionKey;
|
|
171
182
|
(function (DelegationSessionActionKey) {
|
|
172
183
|
DelegationSessionActionKey["LoadCandidates"] = "loadCandidates";
|
|
173
184
|
DelegationSessionActionKey["StartSession"] = "startSession";
|
|
174
185
|
})(DelegationSessionActionKey || (DelegationSessionActionKey = {}));
|
|
175
186
|
|
|
187
|
+
const STORAGE_KEY = 'mt.delegation.session-resume.v1';
|
|
188
|
+
/**
|
|
189
|
+
* Lets a delegated session survive a page reload **without persisting the
|
|
190
|
+
* token**.
|
|
191
|
+
*
|
|
192
|
+
* Doc 05 is unambiguous: the delegation access token is memory-only, and it
|
|
193
|
+
* stays that way — this store keeps a single opaque `delegationId` plus the
|
|
194
|
+
* owning user/app/tenant namespace. On the next boot the runtime calls
|
|
195
|
+
* `POST identity/delegations/{id}/session` again and mints a *fresh* token,
|
|
196
|
+
* which is what doc 09 already prescribes for restarting a session ("use the
|
|
197
|
+
* newly returned token because the scope hash or delegation version may have
|
|
198
|
+
* changed"). The backend re-authorizes from scratch every time, so a delegation
|
|
199
|
+
* that expired, was cancelled, or had its scope revoked while the tab was shut
|
|
200
|
+
* simply fails to resume and the user stays themselves.
|
|
201
|
+
*
|
|
202
|
+
* Never holds a token, a candidate record, a name, or an email.
|
|
203
|
+
*/
|
|
204
|
+
class DelegationSessionResumeStore {
|
|
205
|
+
document = inject(DOCUMENT);
|
|
206
|
+
config = inject(DELEGATION_RUNTIME_CONFIG);
|
|
207
|
+
remember(delegationId) {
|
|
208
|
+
this.write({ ns: this.namespace(), delegationId });
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* The delegation to resume for the *current* user/app/tenant, or `null`. A
|
|
212
|
+
* marker left by a different actor is dropped rather than honoured, so
|
|
213
|
+
* signing in as someone else on a shared browser never resumes their
|
|
214
|
+
* delegation.
|
|
215
|
+
*/
|
|
216
|
+
pending() {
|
|
217
|
+
const marker = this.read();
|
|
218
|
+
if (!marker) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
if (marker.ns !== this.namespace()) {
|
|
222
|
+
this.clear();
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
return marker.delegationId;
|
|
226
|
+
}
|
|
227
|
+
clear() {
|
|
228
|
+
try {
|
|
229
|
+
this.storage()?.removeItem(STORAGE_KEY);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// Storage can be unavailable (private mode, blocked cookies).
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
namespace() {
|
|
236
|
+
const { userId, applicationKey, tenantKey } = this.config.resolvePromptNamespace();
|
|
237
|
+
return [userId, applicationKey, tenantKey ?? ''].join('|');
|
|
238
|
+
}
|
|
239
|
+
read() {
|
|
240
|
+
try {
|
|
241
|
+
const raw = this.storage()?.getItem(STORAGE_KEY);
|
|
242
|
+
const parsed = raw ? JSON.parse(raw) : null;
|
|
243
|
+
if (typeof parsed !== 'object' ||
|
|
244
|
+
parsed === null ||
|
|
245
|
+
typeof parsed.ns !== 'string' ||
|
|
246
|
+
typeof parsed.delegationId !== 'number') {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
return parsed;
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
write(marker) {
|
|
256
|
+
try {
|
|
257
|
+
this.storage()?.setItem(STORAGE_KEY, JSON.stringify(marker));
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// Storage can be unavailable; delegated mode then simply ends on reload.
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
storage() {
|
|
264
|
+
return this.document.defaultView?.localStorage ?? null;
|
|
265
|
+
}
|
|
266
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationSessionResumeStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
267
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationSessionResumeStore, providedIn: 'root' });
|
|
268
|
+
}
|
|
269
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationSessionResumeStore, decorators: [{
|
|
270
|
+
type: Injectable,
|
|
271
|
+
args: [{ providedIn: 'root' }]
|
|
272
|
+
}] });
|
|
273
|
+
|
|
176
274
|
/** Package-private: raw delegated credentials never enter NGXS or public models. */
|
|
177
275
|
class DelegationTokenVault {
|
|
178
276
|
value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
@@ -255,6 +353,9 @@ let DelegationSessionState = class DelegationSessionState {
|
|
|
255
353
|
* or open the availability prompt — after sign-out.
|
|
256
354
|
*/
|
|
257
355
|
candidatesGeneration = 0;
|
|
356
|
+
resumeStore = inject(DelegationSessionResumeStore);
|
|
357
|
+
/** One resume attempt per page load — a dead delegation must not retry. */
|
|
358
|
+
resumeAttempted = false;
|
|
258
359
|
constructor() {
|
|
259
360
|
this.actions$
|
|
260
361
|
.pipe(ofActionSuccessful(GatewayLoginSuccessShell))
|
|
@@ -323,6 +424,9 @@ let DelegationSessionState = class DelegationSessionState {
|
|
|
323
424
|
(response.data?.totalCount ?? 0) <= pageSize) {
|
|
324
425
|
queueMicrotask(() => this.store.dispatch(new EndDelegationSession('ScopeChanged')));
|
|
325
426
|
}
|
|
427
|
+
if (!active && page === 1) {
|
|
428
|
+
this.tryResume(candidates);
|
|
429
|
+
}
|
|
326
430
|
return {
|
|
327
431
|
candidates,
|
|
328
432
|
candidatesPage: response.data?.page ?? page,
|
|
@@ -332,6 +436,39 @@ let DelegationSessionState = class DelegationSessionState {
|
|
|
332
436
|
},
|
|
333
437
|
});
|
|
334
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* Re-mints the delegated session the user was in before they reloaded.
|
|
441
|
+
*
|
|
442
|
+
* The token itself was never persisted (doc 05); only the delegation id was,
|
|
443
|
+
* so this is a full `POST .../session` and the backend re-authorizes from
|
|
444
|
+
* scratch. Attempted at most once per page load — a delegation that has since
|
|
445
|
+
* expired or been revoked must not retry on every candidate refresh.
|
|
446
|
+
*/
|
|
447
|
+
tryResume(candidates) {
|
|
448
|
+
if (this.resumeAttempted) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const delegationId = this.resumeStore.pending();
|
|
452
|
+
if (delegationId == null) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const row = candidates.find((candidate) => candidate.delegationId === delegationId);
|
|
456
|
+
this.resumeAttempted = true;
|
|
457
|
+
if (!row) {
|
|
458
|
+
// No longer startable (expired, cancelled, scope revoked) — forget it.
|
|
459
|
+
this.resumeStore.clear();
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
queueMicrotask(() => this.store.dispatch(new ResumeDelegationSession(row)).subscribe({
|
|
463
|
+
error: () => this.resumeStore.clear(),
|
|
464
|
+
}));
|
|
465
|
+
}
|
|
466
|
+
resume(ctx, { delegation }) {
|
|
467
|
+
if (ctx.getState().active) {
|
|
468
|
+
return EMPTY;
|
|
469
|
+
}
|
|
470
|
+
return this.startSession(ctx, delegation, null, 'ResumeSession');
|
|
471
|
+
}
|
|
335
472
|
start(ctx, { delegation }) {
|
|
336
473
|
const previous = ctx.getState().active;
|
|
337
474
|
return this.startSession(ctx, delegation, previous, 'StartSession');
|
|
@@ -352,6 +489,9 @@ let DelegationSessionState = class DelegationSessionState {
|
|
|
352
489
|
delegationVersion: response.data.delegationVersion,
|
|
353
490
|
};
|
|
354
491
|
this.scheduleExpiry(active);
|
|
492
|
+
// Id only — see `DelegationSessionResumeStore`. Never the token.
|
|
493
|
+
this.resumeStore.remember(delegation.delegationId);
|
|
494
|
+
this.resumeAttempted = true;
|
|
355
495
|
return { active };
|
|
356
496
|
},
|
|
357
497
|
}).pipe(switchMap(() => from(Promise.resolve(this.runtime.onContextChanged({
|
|
@@ -364,6 +504,10 @@ let DelegationSessionState = class DelegationSessionState {
|
|
|
364
504
|
// Client-local only — there is no server end-session endpoint (doc 05).
|
|
365
505
|
const previous = ctx.getState().active;
|
|
366
506
|
const clearCandidates = shouldClearCandidates(reason);
|
|
507
|
+
// Whatever the reason, delegated mode is over — a reload must not bring it
|
|
508
|
+
// back. Also blocks a resume that is still queued behind this action.
|
|
509
|
+
this.resumeStore.clear();
|
|
510
|
+
this.resumeAttempted = true;
|
|
367
511
|
// Logout / user / tenant / app switch must always drop the candidate list,
|
|
368
512
|
// even when no delegated session was ever started. Leaving it behind kept
|
|
369
513
|
// the previous actor's delegators in memory across sign-out, which is both
|
|
@@ -416,6 +560,9 @@ let DelegationSessionState = class DelegationSessionState {
|
|
|
416
560
|
__decorate$1([
|
|
417
561
|
Action(LoadDelegationCandidates)
|
|
418
562
|
], DelegationSessionState.prototype, "loadCandidates", null);
|
|
563
|
+
__decorate$1([
|
|
564
|
+
Action(ResumeDelegationSession)
|
|
565
|
+
], DelegationSessionState.prototype, "resume", null);
|
|
419
566
|
__decorate$1([
|
|
420
567
|
Action(StartDelegationSession)
|
|
421
568
|
], DelegationSessionState.prototype, "start", null);
|
|
@@ -459,7 +606,7 @@ DelegationSessionState = __decorate$1([
|
|
|
459
606
|
], DelegationSessionState);
|
|
460
607
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationSessionState, decorators: [{
|
|
461
608
|
type: Injectable
|
|
462
|
-
}], ctorParameters: () => [], propDecorators: { loadCandidates: [], start: [], end: [], switch: [] } });
|
|
609
|
+
}], ctorParameters: () => [], propDecorators: { loadCandidates: [], resume: [], start: [], end: [], switch: [] } });
|
|
463
610
|
|
|
464
611
|
class DelegationSessionFacade {
|
|
465
612
|
store = inject(Store);
|
|
@@ -478,8 +625,15 @@ class DelegationSessionFacade {
|
|
|
478
625
|
// ---------------------------------------------------------------------------
|
|
479
626
|
/** On-behalf-of (delegator). */
|
|
480
627
|
onBehalfOf = computed(() => this.active()?.delegation.delegator ?? null, ...(ngDevMode ? [{ debugName: "onBehalfOf" }] : /* istanbul ignore next */ []));
|
|
481
|
-
/**
|
|
482
|
-
|
|
628
|
+
/**
|
|
629
|
+
* Executed-by (the real signed-in user), known whether or not a session is
|
|
630
|
+
* active: every assigned row carries the current user as its `delegatedUser`,
|
|
631
|
+
* so the account switcher can list "you" alongside the delegators without the
|
|
632
|
+
* package depending on the host's auth state.
|
|
633
|
+
*/
|
|
634
|
+
executedBy = computed(() => this.active()?.delegation.delegatedUser ??
|
|
635
|
+
this.candidates()[0]?.delegatedUser ??
|
|
636
|
+
null, ...(ngDevMode ? [{ debugName: "executedBy" }] : /* istanbul ignore next */ []));
|
|
483
637
|
hasCandidates = computed(() => this.candidates().length > 0, ...(ngDevMode ? [{ debugName: "hasCandidates" }] : /* istanbul ignore next */ []));
|
|
484
638
|
hasMoreCandidates = computed(() => this.candidates().length < this.candidatesTotalCount(), ...(ngDevMode ? [{ debugName: "hasMoreCandidates" }] : /* istanbul ignore next */ []));
|
|
485
639
|
isStarting = computed(() => this.loadingActive().includes(DelegationSessionActionKey.StartSession), ...(ngDevMode ? [{ debugName: "isStarting" }] : /* istanbul ignore next */ []));
|
|
@@ -591,11 +745,11 @@ class StartSessionDialog {
|
|
|
591
745
|
this.ref.close(false);
|
|
592
746
|
}
|
|
593
747
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: StartSessionDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
594
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: StartSessionDialog, isStandalone: true, selector: "mt-start-session-dialog", inputs: { delegation: { classPropertyName: "delegation", publicName: "delegation", isSignal: true, isRequired: true, transformFunction: null }, intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\n >\n <mt-entity-preview\n [data]=\"userEntity(delegation().delegator)\"\n ></mt-entity-preview>\n\n <p class=\"text-sm leading-relaxed text-surface-600\">\n {{ t(bodyKey()) }}\n </p>\n </div>\n\n <div [class]=\"modal.footerClass\">\n <mt-button\n variant=\"outlined\"\n color=\"secondary\"\n [label]=\"t('delegations.common.cancel')\"\n [disabled]=\"isBusy()\"\n (click)=\"cancel()\"\n ></mt-button>\n <mt-button\n color=\"primary\"\n icon=\"user.users-check\"\n [label]=\"t(confirmLabelKey())\"\n [loading]=\"isBusy()\"\n (click)=\"confirm()\"\n ></mt-button>\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", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
748
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: StartSessionDialog, isStandalone: true, selector: "mt-start-session-dialog", inputs: { delegation: { classPropertyName: "delegation", publicName: "delegation", isSignal: true, isRequired: true, transformFunction: null }, intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n <div\r\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\r\n >\r\n <mt-entity-preview\r\n [data]=\"userEntity(delegation().delegator)\"\r\n ></mt-entity-preview>\r\n\r\n <p class=\"text-sm leading-relaxed text-surface-600\">\r\n {{ t(bodyKey()) }}\r\n </p>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n color=\"secondary\"\r\n [label]=\"t('delegations.common.cancel')\"\r\n [disabled]=\"isBusy()\"\r\n (click)=\"cancel()\"\r\n ></mt-button>\r\n <mt-button\r\n color=\"primary\"\r\n icon=\"user.users-check\"\r\n [label]=\"t(confirmLabelKey())\"\r\n [loading]=\"isBusy()\"\r\n (click)=\"confirm()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\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", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
595
749
|
}
|
|
596
750
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: StartSessionDialog, decorators: [{
|
|
597
751
|
type: Component,
|
|
598
|
-
args: [{ selector: 'mt-start-session-dialog', imports: [CommonModule, Button, EntityPreview, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\n >\n <mt-entity-preview\n [data]=\"userEntity(delegation().delegator)\"\n ></mt-entity-preview>\n\n <p class=\"text-sm leading-relaxed text-surface-600\">\n {{ t(bodyKey()) }}\n </p>\n </div>\n\n <div [class]=\"modal.footerClass\">\n <mt-button\n variant=\"outlined\"\n color=\"secondary\"\n [label]=\"t('delegations.common.cancel')\"\n [disabled]=\"isBusy()\"\n (click)=\"cancel()\"\n ></mt-button>\n <mt-button\n color=\"primary\"\n icon=\"user.users-check\"\n [label]=\"t(confirmLabelKey())\"\n [loading]=\"isBusy()\"\n (click)=\"confirm()\"\n ></mt-button>\n </div>\n</ng-container>\n" }]
|
|
752
|
+
args: [{ selector: 'mt-start-session-dialog', imports: [CommonModule, Button, EntityPreview, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n <div\r\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\r\n >\r\n <mt-entity-preview\r\n [data]=\"userEntity(delegation().delegator)\"\r\n ></mt-entity-preview>\r\n\r\n <p class=\"text-sm leading-relaxed text-surface-600\">\r\n {{ t(bodyKey()) }}\r\n </p>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n color=\"secondary\"\r\n [label]=\"t('delegations.common.cancel')\"\r\n [disabled]=\"isBusy()\"\r\n (click)=\"cancel()\"\r\n ></mt-button>\r\n <mt-button\r\n color=\"primary\"\r\n icon=\"user.users-check\"\r\n [label]=\"t(confirmLabelKey())\"\r\n [loading]=\"isBusy()\"\r\n (click)=\"confirm()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\n" }]
|
|
599
753
|
}], propDecorators: { delegation: [{ type: i0.Input, args: [{ isSignal: true, alias: "delegation", required: true }] }], intent: [{ type: i0.Input, args: [{ isSignal: true, alias: "intent", required: false }] }] } });
|
|
600
754
|
|
|
601
755
|
/**
|
|
@@ -617,74 +771,25 @@ class DelegationCandidatesPromptDialog {
|
|
|
617
771
|
this.ref.close(null);
|
|
618
772
|
}
|
|
619
773
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationCandidatesPromptDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
620
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationCandidatesPromptDialog, isStandalone: true, selector: "mt-delegation-candidates-prompt-dialog", inputs: { candidates: { classPropertyName: "candidates", publicName: "candidates", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\n >\n <p class=\"text-sm leading-relaxed text-surface-600\">\n {{ t(\"delegations.session.promptBody\") }}\n </p>\n\n <div class=\"flex flex-col gap-2\">\n @for (cand of candidates(); track cand.delegationId) {\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center justify-between gap-3 rounded-lg border border-solid border-surface-200 bg-surface-0 px-3 py-2.5 text-start transition-colors hover:border-primary-300 hover:bg-primary-50/50 focus-visible:border-primary-400 focus-visible:outline-none\"\n [attr.aria-label]=\"\n t('delegations.session.promptStartAria', {\n delegatorName: cand.delegator.displayName,\n })\n \"\n (click)=\"select(cand)\"\n >\n <span class=\"flex min-w-0 items-center gap-3\">\n <mt-entity-preview\n [data]=\"userEntity(cand.delegator)\"\n ></mt-entity-preview>\n </span>\n <span\n class=\"inline-flex shrink-0 items-center gap-1.5 text-sm font-medium text-primary\"\n >\n <span class=\"hidden sm:inline\">\n {{ t(\"delegations.action.startSession\") }}\n </span>\n <mt-icon icon=\"arrow.arrow-right\" class=\"text-base\"></mt-icon>\n </span>\n </button>\n }\n </div>\n </div>\n\n <div [class]=\"modal.footerClass\">\n <mt-button\n variant=\"outlined\"\n color=\"secondary\"\n [label]=\"t('delegations.common.close')\"\n (click)=\"close()\"\n ></mt-button>\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", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
774
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationCandidatesPromptDialog, isStandalone: true, selector: "mt-delegation-candidates-prompt-dialog", inputs: { candidates: { classPropertyName: "candidates", publicName: "candidates", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n <div\r\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\r\n >\r\n <p class=\"text-sm leading-relaxed text-surface-600\">\r\n {{ t(\"delegations.session.promptBody\") }}\r\n </p>\r\n\r\n <div class=\"flex flex-col gap-2\">\r\n @for (cand of candidates(); track cand.delegationId) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-center justify-between gap-3 rounded-lg border border-solid border-surface-200 bg-surface-0 px-3 py-2.5 text-start transition-colors hover:border-primary-300 hover:bg-primary-50/50 focus-visible:border-primary-400 focus-visible:outline-none\"\r\n [attr.aria-label]=\"\r\n t('delegations.session.promptStartAria', {\r\n delegatorName: cand.delegator.displayName,\r\n })\r\n \"\r\n (click)=\"select(cand)\"\r\n >\r\n <span class=\"flex min-w-0 items-center gap-3\">\r\n <mt-entity-preview\r\n [data]=\"userEntity(cand.delegator)\"\r\n ></mt-entity-preview>\r\n </span>\r\n <span\r\n class=\"inline-flex shrink-0 items-center gap-1.5 text-sm font-medium text-primary\"\r\n >\r\n <span class=\"hidden sm:inline\">\r\n {{ t(\"delegations.action.startSession\") }}\r\n </span>\r\n <mt-icon icon=\"arrow.arrow-right\" class=\"text-base\"></mt-icon>\r\n </span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n color=\"secondary\"\r\n [label]=\"t('delegations.common.close')\"\r\n (click)=\"close()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\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", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
621
775
|
}
|
|
622
776
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationCandidatesPromptDialog, decorators: [{
|
|
623
777
|
type: Component,
|
|
624
|
-
args: [{ selector: 'mt-delegation-candidates-prompt-dialog', imports: [CommonModule, Button, EntityPreview, Icon, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\n >\n <p class=\"text-sm leading-relaxed text-surface-600\">\n {{ t(\"delegations.session.promptBody\") }}\n </p>\n\n <div class=\"flex flex-col gap-2\">\n @for (cand of candidates(); track cand.delegationId) {\n <button\n type=\"button\"\n class=\"flex w-full cursor-pointer items-center justify-between gap-3 rounded-lg border border-solid border-surface-200 bg-surface-0 px-3 py-2.5 text-start transition-colors hover:border-primary-300 hover:bg-primary-50/50 focus-visible:border-primary-400 focus-visible:outline-none\"\n [attr.aria-label]=\"\n t('delegations.session.promptStartAria', {\n delegatorName: cand.delegator.displayName,\n })\n \"\n (click)=\"select(cand)\"\n >\n <span class=\"flex min-w-0 items-center gap-3\">\n <mt-entity-preview\n [data]=\"userEntity(cand.delegator)\"\n ></mt-entity-preview>\n </span>\n <span\n class=\"inline-flex shrink-0 items-center gap-1.5 text-sm font-medium text-primary\"\n >\n <span class=\"hidden sm:inline\">\n {{ t(\"delegations.action.startSession\") }}\n </span>\n <mt-icon icon=\"arrow.arrow-right\" class=\"text-base\"></mt-icon>\n </span>\n </button>\n }\n </div>\n </div>\n\n <div [class]=\"modal.footerClass\">\n <mt-button\n variant=\"outlined\"\n color=\"secondary\"\n [label]=\"t('delegations.common.close')\"\n (click)=\"close()\"\n ></mt-button>\n </div>\n</ng-container>\n" }]
|
|
778
|
+
args: [{ selector: 'mt-delegation-candidates-prompt-dialog', imports: [CommonModule, Button, EntityPreview, Icon, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n <div\r\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\r\n >\r\n <p class=\"text-sm leading-relaxed text-surface-600\">\r\n {{ t(\"delegations.session.promptBody\") }}\r\n </p>\r\n\r\n <div class=\"flex flex-col gap-2\">\r\n @for (cand of candidates(); track cand.delegationId) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-center justify-between gap-3 rounded-lg border border-solid border-surface-200 bg-surface-0 px-3 py-2.5 text-start transition-colors hover:border-primary-300 hover:bg-primary-50/50 focus-visible:border-primary-400 focus-visible:outline-none\"\r\n [attr.aria-label]=\"\r\n t('delegations.session.promptStartAria', {\r\n delegatorName: cand.delegator.displayName,\r\n })\r\n \"\r\n (click)=\"select(cand)\"\r\n >\r\n <span class=\"flex min-w-0 items-center gap-3\">\r\n <mt-entity-preview\r\n [data]=\"userEntity(cand.delegator)\"\r\n ></mt-entity-preview>\r\n </span>\r\n <span\r\n class=\"inline-flex shrink-0 items-center gap-1.5 text-sm font-medium text-primary\"\r\n >\r\n <span class=\"hidden sm:inline\">\r\n {{ t(\"delegations.action.startSession\") }}\r\n </span>\r\n <mt-icon icon=\"arrow.arrow-right\" class=\"text-base\"></mt-icon>\r\n </span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n color=\"secondary\"\r\n [label]=\"t('delegations.common.close')\"\r\n (click)=\"close()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\n" }]
|
|
625
779
|
}], propDecorators: { candidates: [{ type: i0.Input, args: [{ isSignal: true, alias: "candidates", required: true }] }] } });
|
|
626
780
|
|
|
627
|
-
const STATUS_VISUAL = {
|
|
628
|
-
Active: {
|
|
629
|
-
i18nKey: 'delegations.status.active',
|
|
630
|
-
styleClass: 'mt-status-chip mt-status-chip--active',
|
|
631
|
-
},
|
|
632
|
-
Scheduled: {
|
|
633
|
-
i18nKey: 'delegations.status.scheduled',
|
|
634
|
-
styleClass: 'mt-status-chip mt-status-chip--scheduled',
|
|
635
|
-
},
|
|
636
|
-
PendingApproval: {
|
|
637
|
-
i18nKey: 'delegations.status.pendingApproval',
|
|
638
|
-
styleClass: 'mt-status-chip mt-status-chip--pending',
|
|
639
|
-
},
|
|
640
|
-
InactiveToday: {
|
|
641
|
-
i18nKey: 'delegations.status.inactiveToday',
|
|
642
|
-
styleClass: 'mt-status-chip mt-status-chip--scheduled',
|
|
643
|
-
},
|
|
644
|
-
Expired: {
|
|
645
|
-
i18nKey: 'delegations.status.expired',
|
|
646
|
-
styleClass: 'mt-status-chip mt-status-chip--expired',
|
|
647
|
-
},
|
|
648
|
-
Rejected: {
|
|
649
|
-
i18nKey: 'delegations.status.rejected',
|
|
650
|
-
styleClass: 'mt-status-chip mt-status-chip--rejected',
|
|
651
|
-
},
|
|
652
|
-
Cancelled: {
|
|
653
|
-
i18nKey: 'delegations.status.cancelled',
|
|
654
|
-
styleClass: 'mt-status-chip mt-status-chip--cancelled',
|
|
655
|
-
},
|
|
656
|
-
};
|
|
657
|
-
class DelegationStatusChip {
|
|
658
|
-
status = input.required(...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
659
|
-
reasonCode = input(null, ...(ngDevMode ? [{ debugName: "reasonCode" }] : /* istanbul ignore next */ []));
|
|
660
|
-
visual = computed(() => STATUS_VISUAL[this.status() === 'Scheduled' && this.reasonCode() === 'InactiveToday'
|
|
661
|
-
? 'InactiveToday'
|
|
662
|
-
: this.status()] ?? STATUS_VISUAL.Scheduled, ...(ngDevMode ? [{ debugName: "visual" }] : /* istanbul ignore next */ []));
|
|
663
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationStatusChip, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
664
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: DelegationStatusChip, isStandalone: true, selector: "mt-delegation-status-chip", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: true, transformFunction: null }, reasonCode: { classPropertyName: "reasonCode", publicName: "reasonCode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
665
|
-
<ng-container *transloco="let t">
|
|
666
|
-
@let v = visual();
|
|
667
|
-
<mt-chip [label]="t(v.i18nKey)" [styleClass]="v.styleClass"></mt-chip>
|
|
668
|
-
</ng-container>
|
|
669
|
-
`, isInline: true, styles: [":host{display:inline-flex}:host ::ng-deep .mt-status-chip{font-weight:500;font-size:.75rem;border-radius:9999px;padding-inline:.625rem;padding-block:.125rem}:host ::ng-deep .mt-status-chip--active{background-color:#dcfce7;color:#166534}:host ::ng-deep .mt-status-chip--scheduled{background-color:#dbeafe;color:#1e40af}:host ::ng-deep .mt-status-chip--pending{background-color:#fef9c3;color:#854d0e}:host ::ng-deep .mt-status-chip--expired{background-color:#f3f4f6;color:#4b5563}:host ::ng-deep .mt-status-chip--rejected{background-color:#fee2e2;color:#991b1b}:host ::ng-deep .mt-status-chip--cancelled{background-color:#e5e7eb;color:#374151}:host-context(.dark) ::ng-deep .mt-status-chip--active{background-color:#22c55e33;color:#86efac}:host-context(.dark) ::ng-deep .mt-status-chip--scheduled{background-color:#3b82f633;color:#93c5fd}:host-context(.dark) ::ng-deep .mt-status-chip--pending{background-color:#eab30833;color:#fde047}:host-context(.dark) ::ng-deep .mt-status-chip--expired{background-color:#94a3b833;color:#cbd5e1}:host-context(.dark) ::ng-deep .mt-status-chip--rejected{background-color:#ef444433;color:#fca5a5}:host-context(.dark) ::ng-deep .mt-status-chip--cancelled{background-color:#94a3b826;color:#cbd5e1}\n"], dependencies: [{ kind: "component", type: Chip, selector: "mt-chip", inputs: ["label", "icon", "image", "removable", "removeIcon", "styleClass", "size"], outputs: ["onRemove", "onImageError"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
|
|
670
|
-
}
|
|
671
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationStatusChip, decorators: [{
|
|
672
|
-
type: Component,
|
|
673
|
-
args: [{ selector: 'mt-delegation-status-chip', standalone: true, imports: [Chip, TranslocoDirective], template: `
|
|
674
|
-
<ng-container *transloco="let t">
|
|
675
|
-
@let v = visual();
|
|
676
|
-
<mt-chip [label]="t(v.i18nKey)" [styleClass]="v.styleClass"></mt-chip>
|
|
677
|
-
</ng-container>
|
|
678
|
-
`, styles: [":host{display:inline-flex}:host ::ng-deep .mt-status-chip{font-weight:500;font-size:.75rem;border-radius:9999px;padding-inline:.625rem;padding-block:.125rem}:host ::ng-deep .mt-status-chip--active{background-color:#dcfce7;color:#166534}:host ::ng-deep .mt-status-chip--scheduled{background-color:#dbeafe;color:#1e40af}:host ::ng-deep .mt-status-chip--pending{background-color:#fef9c3;color:#854d0e}:host ::ng-deep .mt-status-chip--expired{background-color:#f3f4f6;color:#4b5563}:host ::ng-deep .mt-status-chip--rejected{background-color:#fee2e2;color:#991b1b}:host ::ng-deep .mt-status-chip--cancelled{background-color:#e5e7eb;color:#374151}:host-context(.dark) ::ng-deep .mt-status-chip--active{background-color:#22c55e33;color:#86efac}:host-context(.dark) ::ng-deep .mt-status-chip--scheduled{background-color:#3b82f633;color:#93c5fd}:host-context(.dark) ::ng-deep .mt-status-chip--pending{background-color:#eab30833;color:#fde047}:host-context(.dark) ::ng-deep .mt-status-chip--expired{background-color:#94a3b833;color:#cbd5e1}:host-context(.dark) ::ng-deep .mt-status-chip--rejected{background-color:#ef444433;color:#fca5a5}:host-context(.dark) ::ng-deep .mt-status-chip--cancelled{background-color:#94a3b826;color:#cbd5e1}\n"] }]
|
|
679
|
-
}], propDecorators: { status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: true }] }], reasonCode: [{ type: i0.Input, args: [{ isSignal: true, alias: "reasonCode", required: false }] }] } });
|
|
680
|
-
|
|
681
781
|
/**
|
|
682
|
-
* Embeddable
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
782
|
+
* Embeddable "acting as" account switcher (doc 05, 09).
|
|
783
|
+
*
|
|
784
|
+
* Renders one row per identity the user can operate as — themselves first, then
|
|
785
|
+
* every delegator who has an active delegation assigned to them — with the
|
|
786
|
+
* current one checked. Picking a row starts, switches, or ends the delegated
|
|
787
|
+
* session; the {@link StartSessionDialog} still takes explicit consent before
|
|
788
|
+
* any session begins, so this list never changes authority on its own.
|
|
789
|
+
*
|
|
790
|
+
* Designed to be dropped inside a host menu (e.g. the user-avatar dropdown) or
|
|
791
|
+
* the topbar popover. Candidate loading + the post-login prompt stay in the
|
|
792
|
+
* always-mounted `TopbarDelegationMenu` controller.
|
|
688
793
|
*
|
|
689
794
|
* Emits `closeRequested` after any action so the host overlay can dismiss.
|
|
690
795
|
*/
|
|
@@ -692,25 +797,57 @@ class DelegationMenuPanel {
|
|
|
692
797
|
/** Path to the management page, e.g. `/control-panel/delegations` or `/delegations`. */
|
|
693
798
|
managePath = input('/delegations', ...(ngDevMode ? [{ debugName: "managePath" }] : /* istanbul ignore next */ []));
|
|
694
799
|
showManageLink = input(true, ...(ngDevMode ? [{ debugName: "showManageLink" }] : /* istanbul ignore next */ []));
|
|
800
|
+
/**
|
|
801
|
+
* Optional richer profile for the "you" row. Falls back to the current user
|
|
802
|
+
* carried on the assigned delegation rows, so the host may omit it.
|
|
803
|
+
*/
|
|
804
|
+
currentUser = input(null, ...(ngDevMode ? [{ debugName: "currentUser" }] : /* istanbul ignore next */ []));
|
|
695
805
|
closeRequested = output();
|
|
696
806
|
facade = inject(DelegationSessionFacade);
|
|
697
807
|
modal = inject(ModalService);
|
|
698
808
|
transloco = inject(TranslocoService);
|
|
809
|
+
toast = inject(ToastService);
|
|
699
810
|
active = this.facade.active;
|
|
700
811
|
candidates = this.facade.candidates;
|
|
701
812
|
hasCandidates = this.facade.hasCandidates;
|
|
702
813
|
hasMoreCandidates = this.facade.hasMoreCandidates;
|
|
703
814
|
isLoadingCandidates = this.facade.isLoadingCandidates;
|
|
815
|
+
isBusy = this.facade.isStarting;
|
|
704
816
|
onBehalfOf = this.facade.onBehalfOf;
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
817
|
+
/** The real signed-in user — host-supplied when available, derived otherwise. */
|
|
818
|
+
self = computed(() => this.currentUser() ?? this.facade.executedBy(), ...(ngDevMode ? [{ debugName: "self" }] : /* istanbul ignore next */ []));
|
|
819
|
+
/** Nothing to switch between and no session running — render nothing. */
|
|
820
|
+
visible = computed(() => !!this.active() || this.hasCandidates(), ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
821
|
+
/** "You", then every delegator. The active identity carries the checkmark. */
|
|
822
|
+
identities = computed(() => {
|
|
823
|
+
const activeSession = this.active();
|
|
824
|
+
const activeId = activeSession?.delegation.delegationId ?? null;
|
|
825
|
+
const self = this.self();
|
|
826
|
+
const candidates = this.candidates();
|
|
827
|
+
// The identity in force is always listed, even if it has fallen off the
|
|
828
|
+
// first page of candidates — a switcher that cannot show who you currently
|
|
829
|
+
// are is worse than one extra row.
|
|
830
|
+
const rows = activeSession && !candidates.some((row) => row.delegationId === activeId)
|
|
831
|
+
? [activeSession.delegation, ...candidates]
|
|
832
|
+
: candidates;
|
|
833
|
+
return [
|
|
834
|
+
{
|
|
835
|
+
row: null,
|
|
836
|
+
party: self,
|
|
837
|
+
isSelf: true,
|
|
838
|
+
isActive: activeId === null,
|
|
839
|
+
initials: this.initials(self),
|
|
840
|
+
},
|
|
841
|
+
...rows.map((row) => ({
|
|
842
|
+
row,
|
|
843
|
+
party: row.delegator,
|
|
844
|
+
isSelf: false,
|
|
845
|
+
isActive: row.delegationId === activeId,
|
|
846
|
+
initials: this.initials(row.delegator),
|
|
847
|
+
})),
|
|
848
|
+
];
|
|
849
|
+
}, ...(ngDevMode ? [{ debugName: "identities" }] : /* istanbul ignore next */ []));
|
|
850
|
+
/** Two-letter initials for an avatar (matches the user-menu pattern). */
|
|
714
851
|
initials(party) {
|
|
715
852
|
const name = party?.displayName?.trim() || party?.email?.trim() || '';
|
|
716
853
|
const parts = name.split(/\s+/).filter(Boolean);
|
|
@@ -721,20 +858,24 @@ class DelegationMenuPanel {
|
|
|
721
858
|
}
|
|
722
859
|
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
723
860
|
}
|
|
724
|
-
|
|
725
|
-
event.stopPropagation();
|
|
726
|
-
this.closeRequested.emit();
|
|
727
|
-
this.openConfirm(row, 'start');
|
|
728
|
-
}
|
|
729
|
-
switchTo(row, event) {
|
|
730
|
-
event.stopPropagation();
|
|
731
|
-
this.closeRequested.emit();
|
|
732
|
-
this.openConfirm(row, 'switch');
|
|
733
|
-
}
|
|
734
|
-
endSession(event) {
|
|
861
|
+
select(option, event) {
|
|
735
862
|
event.stopPropagation();
|
|
863
|
+
if (option.isActive || this.isBusy()) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
736
866
|
this.closeRequested.emit();
|
|
737
|
-
|
|
867
|
+
if (option.isSelf) {
|
|
868
|
+
// Back to your own authority. There is no server call (doc 05) — ending
|
|
869
|
+
// is local — so no confirmation dialog stands between the user and it.
|
|
870
|
+
this.facade.endSession('Manual').subscribe({
|
|
871
|
+
next: () => this.toast.success(this.transloco.translate('delegations.session.ended')),
|
|
872
|
+
});
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (!option.row) {
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
this.openConfirm(option.row, this.active() ? 'switch' : 'start');
|
|
738
879
|
}
|
|
739
880
|
onManage() {
|
|
740
881
|
this.closeRequested.emit();
|
|
@@ -755,19 +896,12 @@ class DelegationMenuPanel {
|
|
|
755
896
|
});
|
|
756
897
|
}
|
|
757
898
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationMenuPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
758
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationMenuPanel, isStandalone: true, selector: "mt-delegation-menu-panel", inputs: { managePath: { classPropertyName: "managePath", publicName: "managePath", isSignal: true, isRequired: false, transformFunction: null }, showManageLink: { classPropertyName: "showManageLink", publicName: "showManageLink", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeRequested: "closeRequested" }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\
|
|
899
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: DelegationMenuPanel, isStandalone: true, selector: "mt-delegation-menu-panel", inputs: { managePath: { classPropertyName: "managePath", publicName: "managePath", isSignal: true, isRequired: false, transformFunction: null }, showManageLink: { classPropertyName: "showManageLink", publicName: "showManageLink", isSignal: true, isRequired: false, transformFunction: null }, currentUser: { classPropertyName: "currentUser", publicName: "currentUser", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeRequested: "closeRequested" }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n @if (visible()) {\n <div class=\"mt-delegation-switcher flex w-full flex-col\">\n <!-- Header: what this list is, and the current mode at a glance -->\n <div class=\"flex flex-col gap-0.5 px-4 pb-2 pt-3\">\n <span\n class=\"text-[0.6875rem] font-semibold uppercase tracking-wide text-surface-400\"\n >\n {{ t(\"delegations.session.actingAs\") }}\n </span>\n @if (active()) {\n <span class=\"text-xs text-surface-500\">\n {{\n t(\"delegations.session.switchBackHint\", {\n actualUserName: self()?.displayName,\n })\n }}\n </span>\n } @else {\n <span class=\"text-xs text-surface-500\">\n {{ t(\"delegations.session.chooseDelegatorHint\") }}\n </span>\n }\n </div>\n\n <!-- Identity list: you first, then everyone who delegated to you -->\n <div\n class=\"mt-delegation-switcher__list flex max-h-80 flex-col gap-0.5 overflow-y-auto px-1.5 pb-1.5\"\n role=\"listbox\"\n [attr.aria-label]=\"t('delegations.session.actingAs')\"\n >\n @for (\n option of identities();\n track option.row?.delegationId ?? \"self\"\n ) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"mt-delegation-switcher__row\"\n [class.mt-delegation-switcher__row--active]=\"option.isActive\"\n [attr.aria-selected]=\"option.isActive\"\n [disabled]=\"isBusy() || option.isActive\"\n [attr.aria-label]=\"\n option.isSelf\n ? t('delegations.session.actAsSelfAria', {\n actualUserName: option.party?.displayName,\n })\n : t('delegations.session.promptStartAria', {\n delegatorName: option.party?.displayName,\n })\n \"\n (click)=\"select(option, $event)\"\n >\n <span class=\"relative shrink-0\">\n <mt-avatar\n [label]=\"option.initials\"\n shape=\"circle\"\n [styleClass]=\"\n option.isActive\n ? '!size-9 !text-xs !bg-primary-100 !text-primary-700'\n : '!size-9 !text-xs !bg-surface-100 !text-surface-600'\n \"\n ></mt-avatar>\n @if (option.isActive && !option.isSelf) {\n <span\n class=\"absolute -bottom-0.5 -end-0.5 flex size-4 items-center justify-center rounded-full bg-primary ring-2 ring-surface-0\"\n aria-hidden=\"true\"\n >\n <mt-icon\n icon=\"user.users-check\"\n styleClass=\"text-[0.55rem] text-white\"\n ></mt-icon>\n </span>\n }\n </span>\n\n <span class=\"flex min-w-0 flex-1 flex-col text-start\">\n <span class=\"flex min-w-0 items-center gap-1.5\">\n <span\n class=\"truncate text-sm font-semibold text-surface-800\"\n [class.text-primary-700]=\"option.isActive\"\n >\n {{ option.party?.displayName }}\n </span>\n @if (option.isSelf) {\n <span class=\"mt-delegation-switcher__badge\">\n {{ t(\"delegations.session.you\") }}\n </span>\n }\n </span>\n <span class=\"truncate text-xs text-surface-500\">\n @if (option.isSelf) {\n {{\n option.party?.email ||\n t(\"delegations.session.ownAccountHint\")\n }}\n } @else {\n {{\n t(\"delegations.session.until\", {\n date: option.row?.endsAtUtc | date: \"mediumDate\",\n })\n }}\n }\n </span>\n </span>\n\n @if (option.isActive) {\n <mt-icon\n icon=\"general.check\"\n styleClass=\"text-base text-primary shrink-0\"\n ></mt-icon>\n } @else {\n <mt-icon\n icon=\"arrow.chevron-right\"\n styleClass=\"mt-delegation-switcher__chevron text-base text-surface-400 shrink-0\"\n ></mt-icon>\n }\n </button>\n }\n\n @if (hasMoreCandidates()) {\n <button\n type=\"button\"\n class=\"mx-1.5 my-1 rounded-lg px-3 py-2 text-sm font-medium text-primary hover:bg-primary-50 disabled:opacity-60\"\n [disabled]=\"isLoadingCandidates()\"\n (click)=\"loadMore($event)\"\n >\n {{ t(\"delegations.session.loadMore\") }}\n </button>\n }\n </div>\n\n @if (showManageLink()) {\n <div class=\"border-t border-surface p-1.5\">\n <a\n [routerLink]=\"managePath()\"\n (click)=\"onManage()\"\n class=\"flex cursor-pointer items-center gap-3 rounded-lg px-3 py-2 text-sm text-surface-700 hover:bg-surface-100\"\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 }\n</ng-container>\n", styles: [":host{display:block;min-width:0}.mt-delegation-switcher{min-width:15rem}.mt-delegation-switcher__row{display:flex;width:100%;align-items:center;gap:.75rem;padding:.5rem .625rem;border:1px solid transparent;border-radius:.5rem;background:transparent;cursor:pointer;text-align:start;transition:background-color .12s ease-out,border-color .12s ease-out}.mt-delegation-switcher__row:hover:not(:disabled){background-color:var(--p-surface-100)}.mt-delegation-switcher__row:focus-visible{outline:none;border-color:var(--p-primary-400);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-color) 22%,transparent)}.mt-delegation-switcher__row--active,.mt-delegation-switcher__row--active:hover{background-color:var(--p-primary-50);border-color:var(--p-primary-200)}.mt-delegation-switcher__row:disabled{cursor:default}.mt-delegation-switcher__row--active:disabled{opacity:1}.mt-delegation-switcher__row:disabled:not(.mt-delegation-switcher__row--active){opacity:.55}.mt-delegation-switcher__chevron{opacity:0;transition:opacity .12s ease-out}.mt-delegation-switcher__row:hover:not(:disabled) .mt-delegation-switcher__chevron,.mt-delegation-switcher__row:focus-visible .mt-delegation-switcher__chevron{opacity:1}.mt-delegation-switcher__badge{flex-shrink:0;border-radius:999px;background-color:var(--p-surface-200);color:var(--p-surface-600);font-size:.625rem;font-weight:600;line-height:1rem;padding-inline:.375rem;text-transform:uppercase;letter-spacing:.02em}:host-context([dir=\"rtl\"]) .mt-delegation-switcher__chevron{transform:scaleX(-1)}\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: Icon, selector: "mt-icon", inputs: ["icon"] }, { 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: "pipe", type: i1.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
759
900
|
}
|
|
760
901
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationMenuPanel, decorators: [{
|
|
761
902
|
type: Component,
|
|
762
|
-
args: [{ selector: 'mt-delegation-menu-panel', standalone: true, imports: [
|
|
763
|
-
|
|
764
|
-
Avatar,
|
|
765
|
-
Icon,
|
|
766
|
-
RouterLink,
|
|
767
|
-
TranslocoDirective,
|
|
768
|
-
DelegationStatusChip,
|
|
769
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n @if (mode() !== \"hidden\") {\r\n <div class=\"flex w-full flex-col\">\r\n @if (mode() === \"active\" && active(); as session) {\r\n <!-- Active session -->\r\n <div class=\"flex items-center gap-3 border-b border-surface px-4 py-3\">\r\n <mt-avatar\r\n [label]=\"initials(onBehalfOf())\"\r\n shape=\"circle\"\r\n styleClass=\"!size-9 !text-sm !bg-primary-100 !text-primary-700\"\r\n ></mt-avatar>\r\n <div class=\"flex min-w-0 flex-1 flex-col\">\r\n <span\r\n class=\"text-[0.625rem] font-medium uppercase text-surface-500\"\r\n >\r\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\r\n </span>\r\n <span class=\"truncate text-sm font-semibold text-surface-900\">\r\n {{ onBehalfOf()?.displayName }}\r\n </span>\r\n <span class=\"truncate text-xs text-surface-500\">\r\n {{\r\n t(\"delegations.session.executedBy\", {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n }}\r\n </span>\r\n </div>\r\n <mt-delegation-status-chip\r\n status=\"Active\"\r\n ></mt-delegation-status-chip>\r\n </div>\r\n\r\n <div class=\"flex flex-col p-1.5\">\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-surface-700 hover:bg-surface-100\"\r\n (click)=\"endSession($event)\"\r\n >\r\n <mt-icon icon=\"arrow.arrow-left\" styleClass=\"text-base\"></mt-icon>\r\n <span>{{ t(\"delegations.action.endSession\") }}</span>\r\n </button>\r\n </div>\r\n\r\n @if (candidates().length > 1) {\r\n <div class=\"border-t border-surface p-1.5\">\r\n <div\r\n class=\"px-2 pb-1 text-[0.625rem] font-medium uppercase text-surface-400\"\r\n >\r\n {{ t(\"delegations.session.switchToAnother\") }}\r\n </div>\r\n @for (cand of candidates(); track cand.delegationId) {\r\n @if (cand.delegationId !== session.delegation.delegationId) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-lg px-2 py-2 text-start hover:bg-surface-100\"\r\n [attr.aria-label]=\"\r\n t('delegations.action.switchSession') +\r\n ': ' +\r\n cand.delegator.displayName\r\n \"\r\n (click)=\"switchTo(cand, $event)\"\r\n >\r\n <mt-avatar\r\n [label]=\"initials(cand.delegator)\"\r\n shape=\"circle\"\r\n styleClass=\"!size-8 !text-xs !bg-surface-100 !text-surface-600\"\r\n ></mt-avatar>\r\n <span\r\n class=\"min-w-0 flex-1 truncate text-sm font-medium text-surface-800\"\r\n >\r\n {{ cand.delegator.displayName }}\r\n </span>\r\n <mt-icon\r\n icon=\"arrow.switch-horizontal-01\"\r\n styleClass=\"text-base text-surface-400\"\r\n ></mt-icon>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n } @else if (mode() === \"candidates\") {\r\n <!-- Candidates available -->\r\n <div class=\"border-b border-surface px-4 py-3\">\r\n <div class=\"text-sm font-semibold text-surface-900\">\r\n {{ t(\"delegations.session.youCanActAs\") }}\r\n </div>\r\n <div class=\"mt-0.5 text-xs text-surface-500\">\r\n {{ t(\"delegations.session.chooseDelegatorHint\") }}\r\n </div>\r\n </div>\r\n <div class=\"flex max-h-72 flex-col overflow-y-auto p-1.5\">\r\n @for (cand of candidates(); track cand.delegationId) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-center gap-3 rounded-lg px-2 py-2 text-start hover:bg-surface-100\"\r\n [attr.aria-label]=\"\r\n t('delegations.action.startSession') +\r\n ': ' +\r\n cand.delegator.displayName\r\n \"\r\n (click)=\"start(cand, $event)\"\r\n >\r\n <mt-avatar\r\n [label]=\"initials(cand.delegator)\"\r\n shape=\"circle\"\r\n styleClass=\"!size-8 !text-xs !bg-primary-100 !text-primary-700\"\r\n ></mt-avatar>\r\n <span class=\"flex min-w-0 flex-1 flex-col\">\r\n <span class=\"truncate text-sm font-medium text-surface-800\">\r\n {{ cand.delegator.displayName }}\r\n </span>\r\n @if (cand.delegator.email) {\r\n <span class=\"truncate text-xs text-surface-500\">\r\n {{ cand.delegator.email }}\r\n </span>\r\n }\r\n </span>\r\n <mt-icon\r\n icon=\"arrow.arrow-right\"\r\n styleClass=\"text-base text-surface-400\"\r\n ></mt-icon>\r\n </button>\r\n }\r\n @if (hasMoreCandidates()) {\r\n <button\r\n type=\"button\"\r\n class=\"mx-2 my-1 rounded-lg px-3 py-2 text-sm font-medium text-primary hover:bg-primary-50 disabled:opacity-60\"\r\n [disabled]=\"isLoadingCandidates()\"\r\n (click)=\"loadMore($event)\"\r\n >\r\n {{ t(\"delegations.session.loadMore\") }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n @if (showManageLink()) {\r\n <div class=\"border-t border-surface p-1.5\">\r\n <a\r\n [routerLink]=\"managePath()\"\r\n (click)=\"onManage()\"\r\n class=\"flex cursor-pointer items-center gap-3 rounded-lg px-3 py-2 text-sm text-surface-700 hover:bg-surface-100\"\r\n >\r\n <mt-icon\r\n icon=\"general.settings-02\"\r\n styleClass=\"text-base\"\r\n ></mt-icon>\r\n <span>{{ t(\"delegations.session.manage\") }}</span>\r\n </a>\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-container>\r\n" }]
|
|
770
|
-
}], propDecorators: { managePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "managePath", required: false }] }], showManageLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "showManageLink", required: false }] }], closeRequested: [{ type: i0.Output, args: ["closeRequested"] }] } });
|
|
903
|
+
args: [{ selector: 'mt-delegation-menu-panel', standalone: true, imports: [CommonModule, Avatar, Icon, RouterLink, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n @if (visible()) {\n <div class=\"mt-delegation-switcher flex w-full flex-col\">\n <!-- Header: what this list is, and the current mode at a glance -->\n <div class=\"flex flex-col gap-0.5 px-4 pb-2 pt-3\">\n <span\n class=\"text-[0.6875rem] font-semibold uppercase tracking-wide text-surface-400\"\n >\n {{ t(\"delegations.session.actingAs\") }}\n </span>\n @if (active()) {\n <span class=\"text-xs text-surface-500\">\n {{\n t(\"delegations.session.switchBackHint\", {\n actualUserName: self()?.displayName,\n })\n }}\n </span>\n } @else {\n <span class=\"text-xs text-surface-500\">\n {{ t(\"delegations.session.chooseDelegatorHint\") }}\n </span>\n }\n </div>\n\n <!-- Identity list: you first, then everyone who delegated to you -->\n <div\n class=\"mt-delegation-switcher__list flex max-h-80 flex-col gap-0.5 overflow-y-auto px-1.5 pb-1.5\"\n role=\"listbox\"\n [attr.aria-label]=\"t('delegations.session.actingAs')\"\n >\n @for (\n option of identities();\n track option.row?.delegationId ?? \"self\"\n ) {\n <button\n type=\"button\"\n role=\"option\"\n class=\"mt-delegation-switcher__row\"\n [class.mt-delegation-switcher__row--active]=\"option.isActive\"\n [attr.aria-selected]=\"option.isActive\"\n [disabled]=\"isBusy() || option.isActive\"\n [attr.aria-label]=\"\n option.isSelf\n ? t('delegations.session.actAsSelfAria', {\n actualUserName: option.party?.displayName,\n })\n : t('delegations.session.promptStartAria', {\n delegatorName: option.party?.displayName,\n })\n \"\n (click)=\"select(option, $event)\"\n >\n <span class=\"relative shrink-0\">\n <mt-avatar\n [label]=\"option.initials\"\n shape=\"circle\"\n [styleClass]=\"\n option.isActive\n ? '!size-9 !text-xs !bg-primary-100 !text-primary-700'\n : '!size-9 !text-xs !bg-surface-100 !text-surface-600'\n \"\n ></mt-avatar>\n @if (option.isActive && !option.isSelf) {\n <span\n class=\"absolute -bottom-0.5 -end-0.5 flex size-4 items-center justify-center rounded-full bg-primary ring-2 ring-surface-0\"\n aria-hidden=\"true\"\n >\n <mt-icon\n icon=\"user.users-check\"\n styleClass=\"text-[0.55rem] text-white\"\n ></mt-icon>\n </span>\n }\n </span>\n\n <span class=\"flex min-w-0 flex-1 flex-col text-start\">\n <span class=\"flex min-w-0 items-center gap-1.5\">\n <span\n class=\"truncate text-sm font-semibold text-surface-800\"\n [class.text-primary-700]=\"option.isActive\"\n >\n {{ option.party?.displayName }}\n </span>\n @if (option.isSelf) {\n <span class=\"mt-delegation-switcher__badge\">\n {{ t(\"delegations.session.you\") }}\n </span>\n }\n </span>\n <span class=\"truncate text-xs text-surface-500\">\n @if (option.isSelf) {\n {{\n option.party?.email ||\n t(\"delegations.session.ownAccountHint\")\n }}\n } @else {\n {{\n t(\"delegations.session.until\", {\n date: option.row?.endsAtUtc | date: \"mediumDate\",\n })\n }}\n }\n </span>\n </span>\n\n @if (option.isActive) {\n <mt-icon\n icon=\"general.check\"\n styleClass=\"text-base text-primary shrink-0\"\n ></mt-icon>\n } @else {\n <mt-icon\n icon=\"arrow.chevron-right\"\n styleClass=\"mt-delegation-switcher__chevron text-base text-surface-400 shrink-0\"\n ></mt-icon>\n }\n </button>\n }\n\n @if (hasMoreCandidates()) {\n <button\n type=\"button\"\n class=\"mx-1.5 my-1 rounded-lg px-3 py-2 text-sm font-medium text-primary hover:bg-primary-50 disabled:opacity-60\"\n [disabled]=\"isLoadingCandidates()\"\n (click)=\"loadMore($event)\"\n >\n {{ t(\"delegations.session.loadMore\") }}\n </button>\n }\n </div>\n\n @if (showManageLink()) {\n <div class=\"border-t border-surface p-1.5\">\n <a\n [routerLink]=\"managePath()\"\n (click)=\"onManage()\"\n class=\"flex cursor-pointer items-center gap-3 rounded-lg px-3 py-2 text-sm text-surface-700 hover:bg-surface-100\"\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 }\n</ng-container>\n", styles: [":host{display:block;min-width:0}.mt-delegation-switcher{min-width:15rem}.mt-delegation-switcher__row{display:flex;width:100%;align-items:center;gap:.75rem;padding:.5rem .625rem;border:1px solid transparent;border-radius:.5rem;background:transparent;cursor:pointer;text-align:start;transition:background-color .12s ease-out,border-color .12s ease-out}.mt-delegation-switcher__row:hover:not(:disabled){background-color:var(--p-surface-100)}.mt-delegation-switcher__row:focus-visible{outline:none;border-color:var(--p-primary-400);box-shadow:0 0 0 2px color-mix(in srgb,var(--p-primary-color) 22%,transparent)}.mt-delegation-switcher__row--active,.mt-delegation-switcher__row--active:hover{background-color:var(--p-primary-50);border-color:var(--p-primary-200)}.mt-delegation-switcher__row:disabled{cursor:default}.mt-delegation-switcher__row--active:disabled{opacity:1}.mt-delegation-switcher__row:disabled:not(.mt-delegation-switcher__row--active){opacity:.55}.mt-delegation-switcher__chevron{opacity:0;transition:opacity .12s ease-out}.mt-delegation-switcher__row:hover:not(:disabled) .mt-delegation-switcher__chevron,.mt-delegation-switcher__row:focus-visible .mt-delegation-switcher__chevron{opacity:1}.mt-delegation-switcher__badge{flex-shrink:0;border-radius:999px;background-color:var(--p-surface-200);color:var(--p-surface-600);font-size:.625rem;font-weight:600;line-height:1rem;padding-inline:.375rem;text-transform:uppercase;letter-spacing:.02em}:host-context([dir=\"rtl\"]) .mt-delegation-switcher__chevron{transform:scaleX(-1)}\n"] }]
|
|
904
|
+
}], propDecorators: { managePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "managePath", required: false }] }], showManageLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "showManageLink", required: false }] }], currentUser: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUser", required: false }] }], closeRequested: [{ type: i0.Output, args: ["closeRequested"] }] } });
|
|
771
905
|
|
|
772
906
|
/**
|
|
773
907
|
* Topbar surface + controller for the delegation runtime (doc 05, 09).
|
|
@@ -795,10 +929,18 @@ class TopbarDelegationMenu {
|
|
|
795
929
|
* e.g. embedded in the user-avatar dropdown via {@link DelegationMenuPanel}.
|
|
796
930
|
*/
|
|
797
931
|
headless = input(false, ...(ngDevMode ? [{ debugName: "headless" }] : /* istanbul ignore next */ []));
|
|
932
|
+
/**
|
|
933
|
+
* Optional richer profile for the "you" row of the switcher. Forwarded to
|
|
934
|
+
* {@link DelegationMenuPanel}; omit it and the current user is derived from
|
|
935
|
+
* the assigned delegation rows.
|
|
936
|
+
*/
|
|
937
|
+
currentUser = input(null, ...(ngDevMode ? [{ debugName: "currentUser" }] : /* istanbul ignore next */ []));
|
|
798
938
|
facade = inject(DelegationSessionFacade);
|
|
799
939
|
modal = inject(ModalService);
|
|
800
940
|
transloco = inject(TranslocoService);
|
|
801
941
|
destroyRef = inject(DestroyRef);
|
|
942
|
+
actions$ = inject(Actions);
|
|
943
|
+
toast = inject(ToastService);
|
|
802
944
|
popover = viewChild('popover', ...(ngDevMode ? [{ debugName: "popover" }] : /* istanbul ignore next */ []));
|
|
803
945
|
active = this.facade.active;
|
|
804
946
|
candidates = this.facade.candidates;
|
|
@@ -842,6 +984,19 @@ class TopbarDelegationMenu {
|
|
|
842
984
|
this.closePromptFlow();
|
|
843
985
|
}
|
|
844
986
|
});
|
|
987
|
+
// A resumed session is the one state change the user did not just ask for
|
|
988
|
+
// — it happens silently on page load. Say so, or "acting as someone else"
|
|
989
|
+
// looks like the app forgot who they are.
|
|
990
|
+
this.actions$
|
|
991
|
+
.pipe(ofActionSuccessful(ResumeDelegationSession), takeUntilDestroyed())
|
|
992
|
+
.subscribe(() => {
|
|
993
|
+
const delegatorName = this.onBehalfOf()?.displayName;
|
|
994
|
+
if (delegatorName) {
|
|
995
|
+
this.toast.info(this.transloco.translate('delegations.session.resumed', {
|
|
996
|
+
delegatorName,
|
|
997
|
+
}));
|
|
998
|
+
}
|
|
999
|
+
});
|
|
845
1000
|
this.destroyRef.onDestroy(() => {
|
|
846
1001
|
this.destroyed = true;
|
|
847
1002
|
this.closePromptFlow();
|
|
@@ -964,7 +1119,7 @@ class TopbarDelegationMenu {
|
|
|
964
1119
|
}
|
|
965
1120
|
}
|
|
966
1121
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TopbarDelegationMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
967
|
-
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 }, promptOnCandidates: { classPropertyName: "promptOnCandidates", publicName: "promptOnCandidates", isSignal: true, isRequired: false, transformFunction: null }, headless: { classPropertyName: "headless", publicName: "headless", 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\">\r\n <!-- Headless = controller only (no topbar UI); the menu is surfaced in the\r\n host user dropdown via <mt-delegation-menu-panel>. -->\r\n @if (!headless() && mode() !== \"hidden\") {\r\n @if (mode() === \"active\") {\r\n <span class=\"sr-only\" role=\"status\" aria-live=\"polite\">\r\n {{\r\n t(\"delegations.session.banner\", {\r\n delegatorName: onBehalfOf()?.displayName,\r\n })\r\n }}.\r\n {{\r\n t(\"delegations.session.executedBy\", {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n }}\r\n </span>\r\n }\r\n\r\n <div class=\"mt-delegation-trigger flex items-center\">\r\n @if (mode() === \"active\") {\r\n <!-- Active: show the delegator like a user identity, with a switcher caret -->\r\n <button\r\n type=\"button\"\r\n class=\"mt-delegation-trigger__button mt-delegation-trigger__button--active flex min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-full p-1 pe-2 text-current\"\r\n [attr.aria-label]=\"\r\n t('delegations.session.banner', {\r\n delegatorName: onBehalfOf()?.displayName,\r\n }) +\r\n '. ' +\r\n t('delegations.session.executedBy', {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n \"\r\n [attr.aria-expanded]=\"popoverOpen()\"\r\n aria-haspopup=\"dialog\"\r\n (click)=\"togglePopover($event)\"\r\n >\r\n <span class=\"relative shrink-0\">\r\n <mt-avatar\r\n [label]=\"initials(onBehalfOf())\"\r\n shape=\"circle\"\r\n styleClass=\"!size-7 !text-[0.7rem] !bg-primary-100 !text-primary-700\"\r\n ></mt-avatar>\r\n <span\r\n class=\"absolute -bottom-0.5 -end-0.5 flex size-3.5 items-center justify-center rounded-full bg-emerald-500 ring-2 ring-white\"\r\n aria-hidden=\"true\"\r\n >\r\n <mt-icon\r\n icon=\"user.users-check\"\r\n styleClass=\"text-[0.55rem] text-white\"\r\n ></mt-icon>\r\n </span>\r\n </span>\r\n @if (!compact()) {\r\n <span\r\n class=\"mt-delegation-trigger__label hidden min-w-0 flex-col text-start leading-tight md:flex\"\r\n >\r\n <span class=\"text-[0.625rem] font-medium uppercase opacity-60\">\r\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\r\n </span>\r\n <span class=\"truncate text-sm font-semibold\">\r\n {{ onBehalfOf()?.displayName }}\r\n </span>\r\n </span>\r\n }\r\n <mt-icon\r\n icon=\"arrow.chevron-down\"\r\n styleClass=\"text-sm opacity-70\"\r\n ></mt-icon>\r\n </button>\r\n } @else {\r\n <!-- Candidates: plain icon button matching the other topbar icons -->\r\n <button\r\n type=\"button\"\r\n class=\"mt-delegation-trigger__icon relative flex size-9 cursor-pointer items-center justify-center rounded-full text-current\"\r\n [attr.aria-label]=\"t('delegations.session.availableTitle')\"\r\n [attr.aria-expanded]=\"popoverOpen()\"\r\n aria-haspopup=\"dialog\"\r\n (click)=\"togglePopover($event)\"\r\n >\r\n <mt-icon icon=\"user.users-plus\" styleClass=\"text-xl\"></mt-icon>\r\n @if (candidates().length > 0) {\r\n <span\r\n class=\"absolute -top-0.5 -end-0.5 inline-flex min-w-[1.05rem] items-center justify-center rounded-full bg-primary px-1 text-[0.625rem] font-bold leading-4 text-white ring-2 ring-white\"\r\n >\r\n {{ candidates().length }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <p-popover\r\n #popover\r\n [pt]=\"{ content: { class: 'p-0!' } }\"\r\n (onShow)=\"popoverOpen.set(true)\"\r\n (onHide)=\"popoverOpen.set(false)\"\r\n >\r\n <div class=\"w-
|
|
1122
|
+
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 }, promptOnCandidates: { classPropertyName: "promptOnCandidates", publicName: "promptOnCandidates", isSignal: true, isRequired: false, transformFunction: null }, headless: { classPropertyName: "headless", publicName: "headless", isSignal: true, isRequired: false, transformFunction: null }, currentUser: { classPropertyName: "currentUser", publicName: "currentUser", 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\">\r\n <!-- Headless = controller only (no topbar UI); the menu is surfaced in the\r\n host user dropdown via <mt-delegation-menu-panel>. -->\r\n @if (!headless() && mode() !== \"hidden\") {\r\n @if (mode() === \"active\") {\r\n <span class=\"sr-only\" role=\"status\" aria-live=\"polite\">\r\n {{\r\n t(\"delegations.session.banner\", {\r\n delegatorName: onBehalfOf()?.displayName,\r\n })\r\n }}.\r\n {{\r\n t(\"delegations.session.executedBy\", {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n }}\r\n </span>\r\n }\r\n\r\n <div class=\"mt-delegation-trigger flex items-center\">\r\n @if (mode() === \"active\") {\r\n <!-- Active: show the delegator like a user identity, with a switcher caret -->\r\n <button\r\n type=\"button\"\r\n class=\"mt-delegation-trigger__button mt-delegation-trigger__button--active flex min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-full p-1 pe-2 text-current\"\r\n [attr.aria-label]=\"\r\n t('delegations.session.banner', {\r\n delegatorName: onBehalfOf()?.displayName,\r\n }) +\r\n '. ' +\r\n t('delegations.session.executedBy', {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n \"\r\n [attr.aria-expanded]=\"popoverOpen()\"\r\n aria-haspopup=\"dialog\"\r\n (click)=\"togglePopover($event)\"\r\n >\r\n <span class=\"relative shrink-0\">\r\n <mt-avatar\r\n [label]=\"initials(onBehalfOf())\"\r\n shape=\"circle\"\r\n styleClass=\"!size-7 !text-[0.7rem] !bg-primary-100 !text-primary-700\"\r\n ></mt-avatar>\r\n <span\r\n class=\"absolute -bottom-0.5 -end-0.5 flex size-3.5 items-center justify-center rounded-full bg-emerald-500 ring-2 ring-white\"\r\n aria-hidden=\"true\"\r\n >\r\n <mt-icon\r\n icon=\"user.users-check\"\r\n styleClass=\"text-[0.55rem] text-white\"\r\n ></mt-icon>\r\n </span>\r\n </span>\r\n @if (!compact()) {\r\n <span\r\n class=\"mt-delegation-trigger__label hidden min-w-0 flex-col text-start leading-tight md:flex\"\r\n >\r\n <span class=\"text-[0.625rem] font-medium uppercase opacity-60\">\r\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\r\n </span>\r\n <span class=\"truncate text-sm font-semibold\">\r\n {{ onBehalfOf()?.displayName }}\r\n </span>\r\n </span>\r\n }\r\n <mt-icon\r\n icon=\"arrow.chevron-down\"\r\n styleClass=\"text-sm opacity-70\"\r\n ></mt-icon>\r\n </button>\r\n } @else {\r\n <!-- Candidates: plain icon button matching the other topbar icons -->\r\n <button\r\n type=\"button\"\r\n class=\"mt-delegation-trigger__icon relative flex size-9 cursor-pointer items-center justify-center rounded-full text-current\"\r\n [attr.aria-label]=\"t('delegations.session.availableTitle')\"\r\n [attr.aria-expanded]=\"popoverOpen()\"\r\n aria-haspopup=\"dialog\"\r\n (click)=\"togglePopover($event)\"\r\n >\r\n <mt-icon icon=\"user.users-plus\" styleClass=\"text-xl\"></mt-icon>\r\n @if (candidates().length > 0) {\r\n <span\r\n class=\"absolute -top-0.5 -end-0.5 inline-flex min-w-[1.05rem] items-center justify-center rounded-full bg-primary px-1 text-[0.625rem] font-bold leading-4 text-white ring-2 ring-white\"\r\n >\r\n {{ candidates().length }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <p-popover\r\n #popover\r\n [pt]=\"{ content: { class: 'p-0!' } }\"\r\n (onShow)=\"popoverOpen.set(true)\"\r\n (onHide)=\"popoverOpen.set(false)\"\r\n >\r\n <div class=\"w-80 max-w-[92vw]\">\r\n <mt-delegation-menu-panel\r\n [managePath]=\"managePath()\"\r\n [showManageLink]=\"showManageLink()\"\r\n [currentUser]=\"currentUser()\"\r\n (closeRequested)=\"closePopover()\"\r\n ></mt-delegation-menu-panel>\r\n </div>\r\n </p-popover>\r\n }\r\n</ng-container>\r\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,.mt-delegation-trigger__icon{transition:background-color .15s ease-out;border:1px solid transparent}.mt-delegation-trigger__button:hover,.mt-delegation-trigger__icon:hover{background-color:var(--p-surface-100, rgba(0, 0, 0, .05))}.mt-delegation-trigger__button--active{background-color:var(--p-surface-100, rgba(0, 0, 0, .05));border-color:var(--p-surface-200, rgba(0, 0, 0, .08))}.mt-delegation-trigger__button--active:hover{background-color:var(--p-surface-200, rgba(0, 0, 0, .08))}.mt-delegation-trigger__label{max-width:min(12rem,20vw);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(max-width:1280px){.mt-delegation-trigger__label{max-width:8rem}}\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: 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: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: DelegationMenuPanel, selector: "mt-delegation-menu-panel", inputs: ["managePath", "showManageLink", "currentUser"], outputs: ["closeRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
968
1123
|
}
|
|
969
1124
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TopbarDelegationMenu, decorators: [{
|
|
970
1125
|
type: Component,
|
|
@@ -975,8 +1130,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
975
1130
|
Popover,
|
|
976
1131
|
TranslocoDirective,
|
|
977
1132
|
DelegationMenuPanel,
|
|
978
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n <!-- Headless = controller only (no topbar UI); the menu is surfaced in the\r\n host user dropdown via <mt-delegation-menu-panel>. -->\r\n @if (!headless() && mode() !== \"hidden\") {\r\n @if (mode() === \"active\") {\r\n <span class=\"sr-only\" role=\"status\" aria-live=\"polite\">\r\n {{\r\n t(\"delegations.session.banner\", {\r\n delegatorName: onBehalfOf()?.displayName,\r\n })\r\n }}.\r\n {{\r\n t(\"delegations.session.executedBy\", {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n }}\r\n </span>\r\n }\r\n\r\n <div class=\"mt-delegation-trigger flex items-center\">\r\n @if (mode() === \"active\") {\r\n <!-- Active: show the delegator like a user identity, with a switcher caret -->\r\n <button\r\n type=\"button\"\r\n class=\"mt-delegation-trigger__button mt-delegation-trigger__button--active flex min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-full p-1 pe-2 text-current\"\r\n [attr.aria-label]=\"\r\n t('delegations.session.banner', {\r\n delegatorName: onBehalfOf()?.displayName,\r\n }) +\r\n '. ' +\r\n t('delegations.session.executedBy', {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n \"\r\n [attr.aria-expanded]=\"popoverOpen()\"\r\n aria-haspopup=\"dialog\"\r\n (click)=\"togglePopover($event)\"\r\n >\r\n <span class=\"relative shrink-0\">\r\n <mt-avatar\r\n [label]=\"initials(onBehalfOf())\"\r\n shape=\"circle\"\r\n styleClass=\"!size-7 !text-[0.7rem] !bg-primary-100 !text-primary-700\"\r\n ></mt-avatar>\r\n <span\r\n class=\"absolute -bottom-0.5 -end-0.5 flex size-3.5 items-center justify-center rounded-full bg-emerald-500 ring-2 ring-white\"\r\n aria-hidden=\"true\"\r\n >\r\n <mt-icon\r\n icon=\"user.users-check\"\r\n styleClass=\"text-[0.55rem] text-white\"\r\n ></mt-icon>\r\n </span>\r\n </span>\r\n @if (!compact()) {\r\n <span\r\n class=\"mt-delegation-trigger__label hidden min-w-0 flex-col text-start leading-tight md:flex\"\r\n >\r\n <span class=\"text-[0.625rem] font-medium uppercase opacity-60\">\r\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\r\n </span>\r\n <span class=\"truncate text-sm font-semibold\">\r\n {{ onBehalfOf()?.displayName }}\r\n </span>\r\n </span>\r\n }\r\n <mt-icon\r\n icon=\"arrow.chevron-down\"\r\n styleClass=\"text-sm opacity-70\"\r\n ></mt-icon>\r\n </button>\r\n } @else {\r\n <!-- Candidates: plain icon button matching the other topbar icons -->\r\n <button\r\n type=\"button\"\r\n class=\"mt-delegation-trigger__icon relative flex size-9 cursor-pointer items-center justify-center rounded-full text-current\"\r\n [attr.aria-label]=\"t('delegations.session.availableTitle')\"\r\n [attr.aria-expanded]=\"popoverOpen()\"\r\n aria-haspopup=\"dialog\"\r\n (click)=\"togglePopover($event)\"\r\n >\r\n <mt-icon icon=\"user.users-plus\" styleClass=\"text-xl\"></mt-icon>\r\n @if (candidates().length > 0) {\r\n <span\r\n class=\"absolute -top-0.5 -end-0.5 inline-flex min-w-[1.05rem] items-center justify-center rounded-full bg-primary px-1 text-[0.625rem] font-bold leading-4 text-white ring-2 ring-white\"\r\n >\r\n {{ candidates().length }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <p-popover\r\n #popover\r\n [pt]=\"{ content: { class: 'p-0!' } }\"\r\n (onShow)=\"popoverOpen.set(true)\"\r\n (onHide)=\"popoverOpen.set(false)\"\r\n >\r\n <div class=\"w-
|
|
979
|
-
}], ctorParameters: () => [], 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 }] }], promptOnCandidates: [{ type: i0.Input, args: [{ isSignal: true, alias: "promptOnCandidates", required: false }] }], headless: [{ type: i0.Input, args: [{ isSignal: true, alias: "headless", required: false }] }], popover: [{ type: i0.ViewChild, args: ['popover', { isSignal: true }] }] } });
|
|
1133
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n <!-- Headless = controller only (no topbar UI); the menu is surfaced in the\r\n host user dropdown via <mt-delegation-menu-panel>. -->\r\n @if (!headless() && mode() !== \"hidden\") {\r\n @if (mode() === \"active\") {\r\n <span class=\"sr-only\" role=\"status\" aria-live=\"polite\">\r\n {{\r\n t(\"delegations.session.banner\", {\r\n delegatorName: onBehalfOf()?.displayName,\r\n })\r\n }}.\r\n {{\r\n t(\"delegations.session.executedBy\", {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n }}\r\n </span>\r\n }\r\n\r\n <div class=\"mt-delegation-trigger flex items-center\">\r\n @if (mode() === \"active\") {\r\n <!-- Active: show the delegator like a user identity, with a switcher caret -->\r\n <button\r\n type=\"button\"\r\n class=\"mt-delegation-trigger__button mt-delegation-trigger__button--active flex min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-full p-1 pe-2 text-current\"\r\n [attr.aria-label]=\"\r\n t('delegations.session.banner', {\r\n delegatorName: onBehalfOf()?.displayName,\r\n }) +\r\n '. ' +\r\n t('delegations.session.executedBy', {\r\n actualUserName: executedBy()?.displayName,\r\n })\r\n \"\r\n [attr.aria-expanded]=\"popoverOpen()\"\r\n aria-haspopup=\"dialog\"\r\n (click)=\"togglePopover($event)\"\r\n >\r\n <span class=\"relative shrink-0\">\r\n <mt-avatar\r\n [label]=\"initials(onBehalfOf())\"\r\n shape=\"circle\"\r\n styleClass=\"!size-7 !text-[0.7rem] !bg-primary-100 !text-primary-700\"\r\n ></mt-avatar>\r\n <span\r\n class=\"absolute -bottom-0.5 -end-0.5 flex size-3.5 items-center justify-center rounded-full bg-emerald-500 ring-2 ring-white\"\r\n aria-hidden=\"true\"\r\n >\r\n <mt-icon\r\n icon=\"user.users-check\"\r\n styleClass=\"text-[0.55rem] text-white\"\r\n ></mt-icon>\r\n </span>\r\n </span>\r\n @if (!compact()) {\r\n <span\r\n class=\"mt-delegation-trigger__label hidden min-w-0 flex-col text-start leading-tight md:flex\"\r\n >\r\n <span class=\"text-[0.625rem] font-medium uppercase opacity-60\">\r\n {{ t(\"delegations.session.actingOnBehalfOf\") }}\r\n </span>\r\n <span class=\"truncate text-sm font-semibold\">\r\n {{ onBehalfOf()?.displayName }}\r\n </span>\r\n </span>\r\n }\r\n <mt-icon\r\n icon=\"arrow.chevron-down\"\r\n styleClass=\"text-sm opacity-70\"\r\n ></mt-icon>\r\n </button>\r\n } @else {\r\n <!-- Candidates: plain icon button matching the other topbar icons -->\r\n <button\r\n type=\"button\"\r\n class=\"mt-delegation-trigger__icon relative flex size-9 cursor-pointer items-center justify-center rounded-full text-current\"\r\n [attr.aria-label]=\"t('delegations.session.availableTitle')\"\r\n [attr.aria-expanded]=\"popoverOpen()\"\r\n aria-haspopup=\"dialog\"\r\n (click)=\"togglePopover($event)\"\r\n >\r\n <mt-icon icon=\"user.users-plus\" styleClass=\"text-xl\"></mt-icon>\r\n @if (candidates().length > 0) {\r\n <span\r\n class=\"absolute -top-0.5 -end-0.5 inline-flex min-w-[1.05rem] items-center justify-center rounded-full bg-primary px-1 text-[0.625rem] font-bold leading-4 text-white ring-2 ring-white\"\r\n >\r\n {{ candidates().length }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <p-popover\r\n #popover\r\n [pt]=\"{ content: { class: 'p-0!' } }\"\r\n (onShow)=\"popoverOpen.set(true)\"\r\n (onHide)=\"popoverOpen.set(false)\"\r\n >\r\n <div class=\"w-80 max-w-[92vw]\">\r\n <mt-delegation-menu-panel\r\n [managePath]=\"managePath()\"\r\n [showManageLink]=\"showManageLink()\"\r\n [currentUser]=\"currentUser()\"\r\n (closeRequested)=\"closePopover()\"\r\n ></mt-delegation-menu-panel>\r\n </div>\r\n </p-popover>\r\n }\r\n</ng-container>\r\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,.mt-delegation-trigger__icon{transition:background-color .15s ease-out;border:1px solid transparent}.mt-delegation-trigger__button:hover,.mt-delegation-trigger__icon:hover{background-color:var(--p-surface-100, rgba(0, 0, 0, .05))}.mt-delegation-trigger__button--active{background-color:var(--p-surface-100, rgba(0, 0, 0, .05));border-color:var(--p-surface-200, rgba(0, 0, 0, .08))}.mt-delegation-trigger__button--active:hover{background-color:var(--p-surface-200, rgba(0, 0, 0, .08))}.mt-delegation-trigger__label{max-width:min(12rem,20vw);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(max-width:1280px){.mt-delegation-trigger__label{max-width:8rem}}\n"] }]
|
|
1134
|
+
}], ctorParameters: () => [], 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 }] }], promptOnCandidates: [{ type: i0.Input, args: [{ isSignal: true, alias: "promptOnCandidates", required: false }] }], headless: [{ type: i0.Input, args: [{ isSignal: true, alias: "headless", required: false }] }], currentUser: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUser", required: false }] }], popover: [{ type: i0.ViewChild, args: ['popover', { isSignal: true }] }] } });
|
|
1135
|
+
|
|
1136
|
+
const STATUS_VISUAL = {
|
|
1137
|
+
Active: {
|
|
1138
|
+
i18nKey: 'delegations.status.active',
|
|
1139
|
+
styleClass: 'mt-status-chip mt-status-chip--active',
|
|
1140
|
+
},
|
|
1141
|
+
Scheduled: {
|
|
1142
|
+
i18nKey: 'delegations.status.scheduled',
|
|
1143
|
+
styleClass: 'mt-status-chip mt-status-chip--scheduled',
|
|
1144
|
+
},
|
|
1145
|
+
PendingApproval: {
|
|
1146
|
+
i18nKey: 'delegations.status.pendingApproval',
|
|
1147
|
+
styleClass: 'mt-status-chip mt-status-chip--pending',
|
|
1148
|
+
},
|
|
1149
|
+
InactiveToday: {
|
|
1150
|
+
i18nKey: 'delegations.status.inactiveToday',
|
|
1151
|
+
styleClass: 'mt-status-chip mt-status-chip--scheduled',
|
|
1152
|
+
},
|
|
1153
|
+
Expired: {
|
|
1154
|
+
i18nKey: 'delegations.status.expired',
|
|
1155
|
+
styleClass: 'mt-status-chip mt-status-chip--expired',
|
|
1156
|
+
},
|
|
1157
|
+
Rejected: {
|
|
1158
|
+
i18nKey: 'delegations.status.rejected',
|
|
1159
|
+
styleClass: 'mt-status-chip mt-status-chip--rejected',
|
|
1160
|
+
},
|
|
1161
|
+
Cancelled: {
|
|
1162
|
+
i18nKey: 'delegations.status.cancelled',
|
|
1163
|
+
styleClass: 'mt-status-chip mt-status-chip--cancelled',
|
|
1164
|
+
},
|
|
1165
|
+
};
|
|
1166
|
+
class DelegationStatusChip {
|
|
1167
|
+
status = input.required(...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
1168
|
+
reasonCode = input(null, ...(ngDevMode ? [{ debugName: "reasonCode" }] : /* istanbul ignore next */ []));
|
|
1169
|
+
visual = computed(() => STATUS_VISUAL[this.status() === 'Scheduled' && this.reasonCode() === 'InactiveToday'
|
|
1170
|
+
? 'InactiveToday'
|
|
1171
|
+
: this.status()] ?? STATUS_VISUAL.Scheduled, ...(ngDevMode ? [{ debugName: "visual" }] : /* istanbul ignore next */ []));
|
|
1172
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationStatusChip, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1173
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: DelegationStatusChip, isStandalone: true, selector: "mt-delegation-status-chip", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: true, transformFunction: null }, reasonCode: { classPropertyName: "reasonCode", publicName: "reasonCode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
1174
|
+
<ng-container *transloco="let t">
|
|
1175
|
+
@let v = visual();
|
|
1176
|
+
<mt-chip [label]="t(v.i18nKey)" [styleClass]="v.styleClass"></mt-chip>
|
|
1177
|
+
</ng-container>
|
|
1178
|
+
`, isInline: true, styles: [":host{display:inline-flex}:host ::ng-deep .mt-status-chip{font-weight:500;font-size:.75rem;border-radius:9999px;padding-inline:.625rem;padding-block:.125rem}:host ::ng-deep .mt-status-chip--active{background-color:#dcfce7;color:#166534}:host ::ng-deep .mt-status-chip--scheduled{background-color:#dbeafe;color:#1e40af}:host ::ng-deep .mt-status-chip--pending{background-color:#fef9c3;color:#854d0e}:host ::ng-deep .mt-status-chip--expired{background-color:#f3f4f6;color:#4b5563}:host ::ng-deep .mt-status-chip--rejected{background-color:#fee2e2;color:#991b1b}:host ::ng-deep .mt-status-chip--cancelled{background-color:#e5e7eb;color:#374151}:host-context(.dark) ::ng-deep .mt-status-chip--active{background-color:#22c55e33;color:#86efac}:host-context(.dark) ::ng-deep .mt-status-chip--scheduled{background-color:#3b82f633;color:#93c5fd}:host-context(.dark) ::ng-deep .mt-status-chip--pending{background-color:#eab30833;color:#fde047}:host-context(.dark) ::ng-deep .mt-status-chip--expired{background-color:#94a3b833;color:#cbd5e1}:host-context(.dark) ::ng-deep .mt-status-chip--rejected{background-color:#ef444433;color:#fca5a5}:host-context(.dark) ::ng-deep .mt-status-chip--cancelled{background-color:#94a3b826;color:#cbd5e1}\n"], dependencies: [{ kind: "component", type: Chip, selector: "mt-chip", inputs: ["label", "icon", "image", "removable", "removeIcon", "styleClass", "size"], outputs: ["onRemove", "onImageError"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] });
|
|
1179
|
+
}
|
|
1180
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: DelegationStatusChip, decorators: [{
|
|
1181
|
+
type: Component,
|
|
1182
|
+
args: [{ selector: 'mt-delegation-status-chip', standalone: true, imports: [Chip, TranslocoDirective], template: `
|
|
1183
|
+
<ng-container *transloco="let t">
|
|
1184
|
+
@let v = visual();
|
|
1185
|
+
<mt-chip [label]="t(v.i18nKey)" [styleClass]="v.styleClass"></mt-chip>
|
|
1186
|
+
</ng-container>
|
|
1187
|
+
`, styles: [":host{display:inline-flex}:host ::ng-deep .mt-status-chip{font-weight:500;font-size:.75rem;border-radius:9999px;padding-inline:.625rem;padding-block:.125rem}:host ::ng-deep .mt-status-chip--active{background-color:#dcfce7;color:#166534}:host ::ng-deep .mt-status-chip--scheduled{background-color:#dbeafe;color:#1e40af}:host ::ng-deep .mt-status-chip--pending{background-color:#fef9c3;color:#854d0e}:host ::ng-deep .mt-status-chip--expired{background-color:#f3f4f6;color:#4b5563}:host ::ng-deep .mt-status-chip--rejected{background-color:#fee2e2;color:#991b1b}:host ::ng-deep .mt-status-chip--cancelled{background-color:#e5e7eb;color:#374151}:host-context(.dark) ::ng-deep .mt-status-chip--active{background-color:#22c55e33;color:#86efac}:host-context(.dark) ::ng-deep .mt-status-chip--scheduled{background-color:#3b82f633;color:#93c5fd}:host-context(.dark) ::ng-deep .mt-status-chip--pending{background-color:#eab30833;color:#fde047}:host-context(.dark) ::ng-deep .mt-status-chip--expired{background-color:#94a3b833;color:#cbd5e1}:host-context(.dark) ::ng-deep .mt-status-chip--rejected{background-color:#ef444433;color:#fca5a5}:host-context(.dark) ::ng-deep .mt-status-chip--cancelled{background-color:#94a3b826;color:#cbd5e1}\n"] }]
|
|
1188
|
+
}], propDecorators: { status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: true }] }], reasonCode: [{ type: i0.Input, args: [{ isSignal: true, alias: "reasonCode", required: false }] }] } });
|
|
980
1189
|
|
|
981
1190
|
// ---------------------------------------------------------------------------
|
|
982
1191
|
// Lists / detail
|
|
@@ -1729,11 +1938,11 @@ class RejectDelegationDialog {
|
|
|
1729
1938
|
this.ref.close(false);
|
|
1730
1939
|
}
|
|
1731
1940
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: RejectDelegationDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1732
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: RejectDelegationDialog, isStandalone: true, selector: "mt-reject-delegation-dialog", inputs: { delegation: { classPropertyName: "delegation", publicName: "delegation", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\n >\n <div class=\"flex flex-col gap-1\">\n <div class=\"text-sm text-surface-700\">\n {{ t(\"delegations.confirm.reject\") }}\n </div>\n <mt-entity-preview\n [data]=\"userEntity(delegation().delegator)\"\n ></mt-entity-preview>\n </div>\n\n <div class=\"flex flex-col gap-1\">\n <label\n class=\"text-sm font-medium text-surface-800\"\n for=\"mt-reject-reason\"\n >\n {{ t(\"delegations.form.rejectionReason\") }}\n <span class=\"text-red-600\">*</span>\n </label>\n <textarea\n id=\"mt-reject-reason\"\n rows=\"3\"\n class=\"w-full rounded-md border border-surface-300 px-3 py-2 text-sm focus:border-primary focus:outline-none\"\n [class.border-red-400]=\"submitted() && !isValid()\"\n [value]=\"reason()\"\n (input)=\"onReasonInput($event)\"\n [attr.aria-invalid]=\"submitted() && !isValid()\"\n [placeholder]=\"t('delegations.form.rejectionReason')\"\n ></textarea>\n @if (submitted() && !isValid()) {\n <span class=\"text-xs text-red-600\">\n {{ t(\"delegations.form.rejectReasonRequired\") }}\n </span>\n }\n </div>\n </div>\n\n <div [class]=\"modal.footerClass\">\n <mt-button\n variant=\"outlined\"\n color=\"secondary\"\n [label]=\"t('delegations.common.cancel')\"\n [disabled]=\"isBusy()\"\n (click)=\"cancel()\"\n ></mt-button>\n <mt-button\n color=\"danger\"\n icon=\"general.x-close\"\n [label]=\"t('delegations.action.reject')\"\n [loading]=\"isBusy()\"\n [disabled]=\"!isValid()\"\n (click)=\"confirm()\"\n ></mt-button>\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", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1941
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: RejectDelegationDialog, isStandalone: true, selector: "mt-reject-delegation-dialog", inputs: { delegation: { classPropertyName: "delegation", publicName: "delegation", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\r\n <div\r\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\r\n >\r\n <div class=\"flex flex-col gap-1\">\r\n <div class=\"text-sm text-surface-700\">\r\n {{ t(\"delegations.confirm.reject\") }}\r\n </div>\r\n <mt-entity-preview\r\n [data]=\"userEntity(delegation().delegator)\"\r\n ></mt-entity-preview>\r\n </div>\r\n\r\n <div class=\"flex flex-col gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-800\"\r\n for=\"mt-reject-reason\"\r\n >\r\n {{ t(\"delegations.form.rejectionReason\") }}\r\n <span class=\"text-red-600\">*</span>\r\n </label>\r\n <textarea\r\n id=\"mt-reject-reason\"\r\n rows=\"3\"\r\n class=\"w-full rounded-md border border-surface-300 px-3 py-2 text-sm focus:border-primary focus:outline-none\"\r\n [class.border-red-400]=\"submitted() && !isValid()\"\r\n [value]=\"reason()\"\r\n (input)=\"onReasonInput($event)\"\r\n [attr.aria-invalid]=\"submitted() && !isValid()\"\r\n [placeholder]=\"t('delegations.form.rejectionReason')\"\r\n ></textarea>\r\n @if (submitted() && !isValid()) {\r\n <span class=\"text-xs text-red-600\">\r\n {{ t(\"delegations.form.rejectReasonRequired\") }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n color=\"secondary\"\r\n [label]=\"t('delegations.common.cancel')\"\r\n [disabled]=\"isBusy()\"\r\n (click)=\"cancel()\"\r\n ></mt-button>\r\n <mt-button\r\n color=\"danger\"\r\n icon=\"general.x-close\"\r\n [label]=\"t('delegations.action.reject')\"\r\n [loading]=\"isBusy()\"\r\n [disabled]=\"!isValid()\"\r\n (click)=\"confirm()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\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", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1733
1942
|
}
|
|
1734
1943
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: RejectDelegationDialog, decorators: [{
|
|
1735
1944
|
type: Component,
|
|
1736
|
-
args: [{ selector: 'mt-reject-delegation-dialog', imports: [CommonModule, Button, EntityPreview, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\n >\n <div class=\"flex flex-col gap-1\">\n <div class=\"text-sm text-surface-700\">\n {{ t(\"delegations.confirm.reject\") }}\n </div>\n <mt-entity-preview\n [data]=\"userEntity(delegation().delegator)\"\n ></mt-entity-preview>\n </div>\n\n <div class=\"flex flex-col gap-1\">\n <label\n class=\"text-sm font-medium text-surface-800\"\n for=\"mt-reject-reason\"\n >\n {{ t(\"delegations.form.rejectionReason\") }}\n <span class=\"text-red-600\">*</span>\n </label>\n <textarea\n id=\"mt-reject-reason\"\n rows=\"3\"\n class=\"w-full rounded-md border border-surface-300 px-3 py-2 text-sm focus:border-primary focus:outline-none\"\n [class.border-red-400]=\"submitted() && !isValid()\"\n [value]=\"reason()\"\n (input)=\"onReasonInput($event)\"\n [attr.aria-invalid]=\"submitted() && !isValid()\"\n [placeholder]=\"t('delegations.form.rejectionReason')\"\n ></textarea>\n @if (submitted() && !isValid()) {\n <span class=\"text-xs text-red-600\">\n {{ t(\"delegations.form.rejectReasonRequired\") }}\n </span>\n }\n </div>\n </div>\n\n <div [class]=\"modal.footerClass\">\n <mt-button\n variant=\"outlined\"\n color=\"secondary\"\n [label]=\"t('delegations.common.cancel')\"\n [disabled]=\"isBusy()\"\n (click)=\"cancel()\"\n ></mt-button>\n <mt-button\n color=\"danger\"\n icon=\"general.x-close\"\n [label]=\"t('delegations.action.reject')\"\n [loading]=\"isBusy()\"\n [disabled]=\"!isValid()\"\n (click)=\"confirm()\"\n ></mt-button>\n </div>\n</ng-container>\n" }]
|
|
1945
|
+
args: [{ selector: 'mt-reject-delegation-dialog', imports: [CommonModule, Button, EntityPreview, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t\">\r\n <div\r\n [class]=\"modal.contentClass + ' flex flex-col gap-4 overflow-y-auto p-5'\"\r\n >\r\n <div class=\"flex flex-col gap-1\">\r\n <div class=\"text-sm text-surface-700\">\r\n {{ t(\"delegations.confirm.reject\") }}\r\n </div>\r\n <mt-entity-preview\r\n [data]=\"userEntity(delegation().delegator)\"\r\n ></mt-entity-preview>\r\n </div>\r\n\r\n <div class=\"flex flex-col gap-1\">\r\n <label\r\n class=\"text-sm font-medium text-surface-800\"\r\n for=\"mt-reject-reason\"\r\n >\r\n {{ t(\"delegations.form.rejectionReason\") }}\r\n <span class=\"text-red-600\">*</span>\r\n </label>\r\n <textarea\r\n id=\"mt-reject-reason\"\r\n rows=\"3\"\r\n class=\"w-full rounded-md border border-surface-300 px-3 py-2 text-sm focus:border-primary focus:outline-none\"\r\n [class.border-red-400]=\"submitted() && !isValid()\"\r\n [value]=\"reason()\"\r\n (input)=\"onReasonInput($event)\"\r\n [attr.aria-invalid]=\"submitted() && !isValid()\"\r\n [placeholder]=\"t('delegations.form.rejectionReason')\"\r\n ></textarea>\r\n @if (submitted() && !isValid()) {\r\n <span class=\"text-xs text-red-600\">\r\n {{ t(\"delegations.form.rejectReasonRequired\") }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div [class]=\"modal.footerClass\">\r\n <mt-button\r\n variant=\"outlined\"\r\n color=\"secondary\"\r\n [label]=\"t('delegations.common.cancel')\"\r\n [disabled]=\"isBusy()\"\r\n (click)=\"cancel()\"\r\n ></mt-button>\r\n <mt-button\r\n color=\"danger\"\r\n icon=\"general.x-close\"\r\n [label]=\"t('delegations.action.reject')\"\r\n [loading]=\"isBusy()\"\r\n [disabled]=\"!isValid()\"\r\n (click)=\"confirm()\"\r\n ></mt-button>\r\n </div>\r\n</ng-container>\r\n" }]
|
|
1737
1946
|
}], propDecorators: { delegation: [{ type: i0.Input, args: [{ isSignal: true, alias: "delegation", required: true }] }] } });
|
|
1738
1947
|
|
|
1739
1948
|
class Delegations {
|
|
@@ -4146,5 +4355,5 @@ const appDelegationInterceptor = (req, next) => {
|
|
|
4146
4355
|
* Generated bundle index. Do not edit.
|
|
4147
4356
|
*/
|
|
4148
4357
|
|
|
4149
|
-
export { ApproveDelegation, CancelDelegation, ClearDelegationDetail, ClearScopePreview, CreateDelegationLegacy, CreateDelegationV2, DELEGATED_RUNTIME_REQUEST, DELEGATION_RUNTIME_CONFIG, DelegationDetailDrawer, DelegationForm, DelegationMenuPanel, DelegationSessionActionKey, DelegationSessionFacade, DelegationSessionState, DelegationStatusChip, Delegations, DelegationsActionKey, DelegationsFacade, DelegationsList, DelegationsState, EndDelegationSession, GetActiveAssignedDelegations, GetAdminDelegations, GetApprovalDelegations, GetAssignedDelegations, GetDelegationDetail, GetMyDelegations, GetScopeOptions, LoadDelegationCandidates, PreviewScope, RejectDelegation, RejectDelegationDialog, ScopePicker, StartDelegationSession, StartSessionDialog, SwitchDelegationSession, TopbarDelegationMenu, UpdateDelegationLegacy, UpdateDelegationV2, appDelegationInterceptor, provideDelegationRuntime, withDelegatedRuntime };
|
|
4358
|
+
export { ApproveDelegation, CancelDelegation, ClearDelegationDetail, ClearScopePreview, CreateDelegationLegacy, CreateDelegationV2, DELEGATED_RUNTIME_REQUEST, DELEGATION_RUNTIME_CONFIG, DelegationDetailDrawer, DelegationForm, DelegationMenuPanel, DelegationSessionActionKey, DelegationSessionFacade, DelegationSessionResumeStore, DelegationSessionState, DelegationStatusChip, Delegations, DelegationsActionKey, DelegationsFacade, DelegationsList, DelegationsState, EndDelegationSession, GetActiveAssignedDelegations, GetAdminDelegations, GetApprovalDelegations, GetAssignedDelegations, GetDelegationDetail, GetMyDelegations, GetScopeOptions, LoadDelegationCandidates, PreviewScope, RejectDelegation, RejectDelegationDialog, ResumeDelegationSession, ScopePicker, StartDelegationSession, StartSessionDialog, SwitchDelegationSession, TopbarDelegationMenu, UpdateDelegationLegacy, UpdateDelegationV2, appDelegationInterceptor, provideDelegationRuntime, withDelegatedRuntime };
|
|
4150
4359
|
//# sourceMappingURL=masterteam-delegations.mjs.map
|