@memberjunction/ng-resource-permissions 5.29.0 → 5.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,536 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { CompositeKey, LogError, Metadata, } from '@memberjunction/core';
4
+ import { PermissionEngine } from '@memberjunction/core-entities';
5
+ import { MJDialogService } from '@memberjunction/ng-ui-components';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@angular/common";
8
+ function UserSharingCenterComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
9
+ const _r1 = i0.ɵɵgetCurrentView();
10
+ i0.ɵɵdomElementStart(0, "button", 8);
11
+ i0.ɵɵdomListener("click", function UserSharingCenterComponent_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnClose()); });
12
+ i0.ɵɵdomElement(1, "i", 9);
13
+ i0.ɵɵdomElementEnd();
14
+ } }
15
+ function UserSharingCenterComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
16
+ i0.ɵɵdomElementStart(0, "div", 7);
17
+ i0.ɵɵdomElement(1, "i", 10);
18
+ i0.ɵɵtext(2);
19
+ i0.ɵɵdomElementEnd();
20
+ } if (rf & 2) {
21
+ const ctx_r1 = i0.ɵɵnextContext();
22
+ i0.ɵɵadvance(2);
23
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.ErrorMessage, " ");
24
+ } }
25
+ function UserSharingCenterComponent_Conditional_11_Conditional_0_Template(rf, ctx) { if (rf & 1) {
26
+ i0.ɵɵdomElementStart(0, "div", 11);
27
+ i0.ɵɵdomElement(1, "i", 13);
28
+ i0.ɵɵtext(2, " Loading\u2026 ");
29
+ i0.ɵɵdomElementEnd();
30
+ } }
31
+ function UserSharingCenterComponent_Conditional_11_Conditional_1_Template(rf, ctx) { if (rf & 1) {
32
+ i0.ɵɵdomElementStart(0, "div", 12);
33
+ i0.ɵɵdomElement(1, "i", 3);
34
+ i0.ɵɵtext(2, " Nothing has been shared directly with you yet. ");
35
+ i0.ɵɵdomElementEnd();
36
+ } }
37
+ function UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Conditional_8_For_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
38
+ i0.ɵɵdomElementStart(0, "span", 25);
39
+ i0.ɵɵtext(1);
40
+ i0.ɵɵpipe(2, "date");
41
+ i0.ɵɵdomElementEnd();
42
+ } if (rf & 2) {
43
+ const row_r6 = i0.ɵɵnextContext().$implicit;
44
+ i0.ɵɵadvance();
45
+ i0.ɵɵtextInterpolate1("expires ", i0.ɵɵpipeBind2(2, 1, row_r6.ExpiresAt, "mediumDate"));
46
+ } }
47
+ function UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Conditional_8_For_2_Template(rf, ctx) { if (rf & 1) {
48
+ const _r5 = i0.ɵɵgetCurrentView();
49
+ i0.ɵɵdomElementStart(0, "button", 21);
50
+ i0.ɵɵdomListener("click", function UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Conditional_8_For_2_Template_button_click_0_listener() { const row_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.OnRowClick(row_r6)); });
51
+ i0.ɵɵdomElementStart(1, "span", 22);
52
+ i0.ɵɵtext(2);
53
+ i0.ɵɵdomElementEnd();
54
+ i0.ɵɵdomElementStart(3, "span", 23);
55
+ i0.ɵɵtext(4);
56
+ i0.ɵɵdomElementEnd();
57
+ i0.ɵɵdomElementStart(5, "span", 24);
58
+ i0.ɵɵtext(6);
59
+ i0.ɵɵdomElementEnd();
60
+ i0.ɵɵconditionalCreate(7, UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Conditional_8_For_2_Conditional_7_Template, 3, 4, "span", 25);
61
+ i0.ɵɵdomElementEnd();
62
+ } if (rf & 2) {
63
+ const row_r6 = ctx.$implicit;
64
+ const ctx_r1 = i0.ɵɵnextContext(5);
65
+ i0.ɵɵadvance(2);
66
+ i0.ɵɵtextInterpolate(row_r6.ResourceName || row_r6.ResourceID);
67
+ i0.ɵɵadvance(2);
68
+ i0.ɵɵtextInterpolate(row_r6.ResourceType);
69
+ i0.ɵɵadvance(2);
70
+ i0.ɵɵtextInterpolate(ctx_r1.ActionsLabel(row_r6.Actions));
71
+ i0.ɵɵadvance();
72
+ i0.ɵɵconditional(row_r6.ExpiresAt ? 7 : -1);
73
+ } }
74
+ function UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Conditional_8_Template(rf, ctx) { if (rf & 1) {
75
+ i0.ɵɵdomElementStart(0, "div", 19);
76
+ i0.ɵɵrepeaterCreate(1, UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Conditional_8_For_2_Template, 8, 4, "button", 20, i0.ɵɵcomponentInstance().TrackByRow, true);
77
+ i0.ɵɵdomElementEnd();
78
+ } if (rf & 2) {
79
+ const group_r4 = i0.ɵɵnextContext().$implicit;
80
+ i0.ɵɵadvance();
81
+ i0.ɵɵrepeater(group_r4.Rows);
82
+ } }
83
+ function UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Template(rf, ctx) { if (rf & 1) {
84
+ const _r3 = i0.ɵɵgetCurrentView();
85
+ i0.ɵɵdomElementStart(0, "div", 14)(1, "button", 15);
86
+ i0.ɵɵdomListener("click", function UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Template_button_click_1_listener() { const group_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ToggleGroup(group_r4)); });
87
+ i0.ɵɵdomElement(2, "i");
88
+ i0.ɵɵdomElementStart(3, "span", 16);
89
+ i0.ɵɵtext(4);
90
+ i0.ɵɵdomElementEnd();
91
+ i0.ɵɵdomElementStart(5, "span", 17);
92
+ i0.ɵɵtext(6);
93
+ i0.ɵɵdomElementEnd();
94
+ i0.ɵɵdomElement(7, "i", 18);
95
+ i0.ɵɵdomElementEnd();
96
+ i0.ɵɵconditionalCreate(8, UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Conditional_8_Template, 3, 0, "div", 19);
97
+ i0.ɵɵdomElementEnd();
98
+ } if (rf & 2) {
99
+ const group_r4 = ctx.$implicit;
100
+ i0.ɵɵadvance(2);
101
+ i0.ɵɵclassMap(group_r4.Icon);
102
+ i0.ɵɵadvance(2);
103
+ i0.ɵɵtextInterpolate(group_r4.DomainName);
104
+ i0.ɵɵadvance(2);
105
+ i0.ɵɵtextInterpolate(group_r4.Rows.length);
106
+ i0.ɵɵadvance();
107
+ i0.ɵɵclassProp("fa-chevron-down", group_r4.Expanded)("fa-chevron-right", !group_r4.Expanded);
108
+ i0.ɵɵadvance();
109
+ i0.ɵɵconditional(group_r4.Expanded ? 8 : -1);
110
+ } }
111
+ function UserSharingCenterComponent_Conditional_11_Conditional_2_Template(rf, ctx) { if (rf & 1) {
112
+ i0.ɵɵrepeaterCreate(0, UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_Template, 9, 9, "div", 14, i0.ɵɵcomponentInstance().TrackByDomain, true);
113
+ } if (rf & 2) {
114
+ const ctx_r1 = i0.ɵɵnextContext(2);
115
+ i0.ɵɵrepeater(ctx_r1.SharedWithMe);
116
+ } }
117
+ function UserSharingCenterComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
118
+ i0.ɵɵconditionalCreate(0, UserSharingCenterComponent_Conditional_11_Conditional_0_Template, 3, 0, "div", 11)(1, UserSharingCenterComponent_Conditional_11_Conditional_1_Template, 3, 0, "div", 12)(2, UserSharingCenterComponent_Conditional_11_Conditional_2_Template, 2, 0);
119
+ } if (rf & 2) {
120
+ const ctx_r1 = i0.ɵɵnextContext();
121
+ i0.ɵɵconditional(ctx_r1.IsLoadingWithMe ? 0 : ctx_r1.SharedWithMe.length === 0 ? 1 : 2);
122
+ } }
123
+ function UserSharingCenterComponent_Conditional_12_Conditional_0_Template(rf, ctx) { if (rf & 1) {
124
+ i0.ɵɵdomElementStart(0, "div", 11);
125
+ i0.ɵɵdomElement(1, "i", 13);
126
+ i0.ɵɵtext(2, " Loading\u2026 ");
127
+ i0.ɵɵdomElementEnd();
128
+ } }
129
+ function UserSharingCenterComponent_Conditional_12_Conditional_1_Template(rf, ctx) { if (rf & 1) {
130
+ i0.ɵɵdomElementStart(0, "div", 12);
131
+ i0.ɵɵdomElement(1, "i", 4);
132
+ i0.ɵɵtext(2, " You haven't shared anything with others yet. ");
133
+ i0.ɵɵdomElementEnd();
134
+ } }
135
+ function UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Conditional_8_For_2_Conditional_10_Template(rf, ctx) { if (rf & 1) {
136
+ i0.ɵɵdomElementStart(0, "span", 25);
137
+ i0.ɵɵtext(1);
138
+ i0.ɵɵpipe(2, "date");
139
+ i0.ɵɵdomElementEnd();
140
+ } if (rf & 2) {
141
+ const row_r10 = i0.ɵɵnextContext().$implicit;
142
+ i0.ɵɵadvance();
143
+ i0.ɵɵtextInterpolate1("expires ", i0.ɵɵpipeBind2(2, 1, row_r10.ExpiresAt, "mediumDate"));
144
+ } }
145
+ function UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Conditional_8_For_2_Template(rf, ctx) { if (rf & 1) {
146
+ const _r9 = i0.ɵɵgetCurrentView();
147
+ i0.ɵɵdomElementStart(0, "div", 26)(1, "span", 22);
148
+ i0.ɵɵtext(2);
149
+ i0.ɵɵdomElementEnd();
150
+ i0.ɵɵdomElementStart(3, "span", 23);
151
+ i0.ɵɵtext(4);
152
+ i0.ɵɵdomElementEnd();
153
+ i0.ɵɵdomElementStart(5, "span", 27);
154
+ i0.ɵɵdomElement(6, "i", 28);
155
+ i0.ɵɵtext(7);
156
+ i0.ɵɵdomElementEnd();
157
+ i0.ɵɵdomElementStart(8, "span", 24);
158
+ i0.ɵɵtext(9);
159
+ i0.ɵɵdomElementEnd();
160
+ i0.ɵɵconditionalCreate(10, UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Conditional_8_For_2_Conditional_10_Template, 3, 4, "span", 25);
161
+ i0.ɵɵdomElementStart(11, "button", 29);
162
+ i0.ɵɵdomListener("click", function UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Conditional_8_For_2_Template_button_click_11_listener($event) { const row_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.OnRevoke(row_r10, $event)); });
163
+ i0.ɵɵdomElement(12, "i", 30);
164
+ i0.ɵɵdomElementEnd()();
165
+ } if (rf & 2) {
166
+ const row_r10 = ctx.$implicit;
167
+ const ctx_r1 = i0.ɵɵnextContext(5);
168
+ i0.ɵɵadvance(2);
169
+ i0.ɵɵtextInterpolate(row_r10.ResourceName || row_r10.ResourceID);
170
+ i0.ɵɵadvance(2);
171
+ i0.ɵɵtextInterpolate(row_r10.ResourceType);
172
+ i0.ɵɵadvance(3);
173
+ i0.ɵɵtextInterpolate1(" ", row_r10.GranteeName || row_r10.GranteeType, " ");
174
+ i0.ɵɵadvance(2);
175
+ i0.ɵɵtextInterpolate(ctx_r1.ActionsLabel(row_r10.Actions));
176
+ i0.ɵɵadvance();
177
+ i0.ɵɵconditional(row_r10.ExpiresAt ? 10 : -1);
178
+ } }
179
+ function UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Conditional_8_Template(rf, ctx) { if (rf & 1) {
180
+ i0.ɵɵdomElementStart(0, "div", 19);
181
+ i0.ɵɵrepeaterCreate(1, UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Conditional_8_For_2_Template, 13, 5, "div", 26, i0.ɵɵcomponentInstance().TrackByRow, true);
182
+ i0.ɵɵdomElementEnd();
183
+ } if (rf & 2) {
184
+ const group_r8 = i0.ɵɵnextContext().$implicit;
185
+ i0.ɵɵadvance();
186
+ i0.ɵɵrepeater(group_r8.Rows);
187
+ } }
188
+ function UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Template(rf, ctx) { if (rf & 1) {
189
+ const _r7 = i0.ɵɵgetCurrentView();
190
+ i0.ɵɵdomElementStart(0, "div", 14)(1, "button", 15);
191
+ i0.ɵɵdomListener("click", function UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Template_button_click_1_listener() { const group_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ToggleGroup(group_r8)); });
192
+ i0.ɵɵdomElement(2, "i");
193
+ i0.ɵɵdomElementStart(3, "span", 16);
194
+ i0.ɵɵtext(4);
195
+ i0.ɵɵdomElementEnd();
196
+ i0.ɵɵdomElementStart(5, "span", 17);
197
+ i0.ɵɵtext(6);
198
+ i0.ɵɵdomElementEnd();
199
+ i0.ɵɵdomElement(7, "i", 18);
200
+ i0.ɵɵdomElementEnd();
201
+ i0.ɵɵconditionalCreate(8, UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Conditional_8_Template, 3, 0, "div", 19);
202
+ i0.ɵɵdomElementEnd();
203
+ } if (rf & 2) {
204
+ const group_r8 = ctx.$implicit;
205
+ i0.ɵɵadvance(2);
206
+ i0.ɵɵclassMap(group_r8.Icon);
207
+ i0.ɵɵadvance(2);
208
+ i0.ɵɵtextInterpolate(group_r8.DomainName);
209
+ i0.ɵɵadvance(2);
210
+ i0.ɵɵtextInterpolate(group_r8.Rows.length);
211
+ i0.ɵɵadvance();
212
+ i0.ɵɵclassProp("fa-chevron-down", group_r8.Expanded)("fa-chevron-right", !group_r8.Expanded);
213
+ i0.ɵɵadvance();
214
+ i0.ɵɵconditional(group_r8.Expanded ? 8 : -1);
215
+ } }
216
+ function UserSharingCenterComponent_Conditional_12_Conditional_2_Template(rf, ctx) { if (rf & 1) {
217
+ i0.ɵɵrepeaterCreate(0, UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_Template, 9, 9, "div", 14, i0.ɵɵcomponentInstance().TrackByDomain, true);
218
+ } if (rf & 2) {
219
+ const ctx_r1 = i0.ɵɵnextContext(2);
220
+ i0.ɵɵrepeater(ctx_r1.SharedByMe);
221
+ } }
222
+ function UserSharingCenterComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
223
+ i0.ɵɵconditionalCreate(0, UserSharingCenterComponent_Conditional_12_Conditional_0_Template, 3, 0, "div", 11)(1, UserSharingCenterComponent_Conditional_12_Conditional_1_Template, 3, 0, "div", 12)(2, UserSharingCenterComponent_Conditional_12_Conditional_2_Template, 2, 0);
224
+ } if (rf & 2) {
225
+ const ctx_r1 = i0.ɵɵnextContext();
226
+ i0.ɵɵconditional(ctx_r1.IsLoadingByMe ? 0 : ctx_r1.SharedByMe.length === 0 ? 1 : 2);
227
+ } }
228
+ /**
229
+ * Default domain → entity-name mapping used by the Sharing Center to load and
230
+ * delete the underlying permission record on Revoke. Apps with custom permission
231
+ * domains can pass a replacement function via `SharingEntityResolver`.
232
+ */
233
+ export const DefaultSharingEntityResolver = (domainName) => {
234
+ switch (domainName) {
235
+ case 'Dashboard Permissions':
236
+ return 'MJ: Dashboard Permissions';
237
+ case 'Artifact Permissions':
238
+ return 'MJ: Artifact Permissions';
239
+ case 'Collection Permissions':
240
+ return 'MJ: Collection Permissions';
241
+ case 'Access Control Rules':
242
+ return 'MJ: Access Control Rules';
243
+ case 'Resource Permissions':
244
+ return 'MJ: Resource Permissions';
245
+ default:
246
+ return null;
247
+ }
248
+ };
249
+ /**
250
+ * **Generic, framework-agnostic Sharing Center.** Renders two tabs:
251
+ *
252
+ * - **Shared with me** — every resource the current user has direct (non-role)
253
+ * access to, grouped by permission domain. Each row is clickable and emits
254
+ * `ResourceClicked` so the embedding app can route to the resource. The Generic
255
+ * component never imports Angular Router / NavigationService — the parent
256
+ * decides how to navigate.
257
+ *
258
+ * - **Shared by me** — every permission record where the current user is the
259
+ * grantor. Each row has a Revoke button that deletes the underlying permission
260
+ * record through `Metadata.GetEntityObject().Delete()` (so audit captures the
261
+ * revoke and BaseEntity event-driven cache invalidation runs).
262
+ *
263
+ * Inputs / Outputs are designed so the component drops cleanly into a dialog,
264
+ * a side panel, an embedded widget, or a full-page route.
265
+ *
266
+ * @example
267
+ * ```html
268
+ * <mj-user-sharing-center
269
+ * [ActiveTab]="tab"
270
+ * (ActiveTabChange)="tab = $event"
271
+ * (ResourceClicked)="OnResourceClicked($event)"
272
+ * (CloseRequested)="dialogRef.Close()">
273
+ * </mj-user-sharing-center>
274
+ * ```
275
+ */
276
+ export class UserSharingCenterComponent {
277
+ cdr = inject(ChangeDetectorRef);
278
+ dialogService = inject(MJDialogService);
279
+ // ─── Inputs ────────────────────────────────────────────────────────────────
280
+ /** Which tab is shown initially. Two-way bindable via `ActiveTabChange`. */
281
+ ActiveTab = 'shared-with-me';
282
+ /**
283
+ * When true, the close button is rendered in the tab strip. Hide it when the
284
+ * embedding container provides its own close affordance.
285
+ */
286
+ ShowCloseButton = true;
287
+ /** Title text displayed in the confirm-revoke dialog. */
288
+ RevokeConfirmTitle = 'Revoke access';
289
+ /**
290
+ * Maps a permission domain name (e.g. `"Dashboard Permissions"`) to the entity
291
+ * name used to load and delete the underlying record on Revoke. Replace to add
292
+ * support for custom domains. Defaults to {@link DefaultSharingEntityResolver}.
293
+ */
294
+ SharingEntityResolver = DefaultSharingEntityResolver;
295
+ // ─── Outputs ───────────────────────────────────────────────────────────────
296
+ /** Two-way binding partner for `ActiveTab`. */
297
+ ActiveTabChange = new EventEmitter();
298
+ /** Fired when a row in the "Shared with me" tab is clicked. */
299
+ ResourceClicked = new EventEmitter();
300
+ /** Fired when the user clicks the close button. Parent should close the host dialog/panel. */
301
+ CloseRequested = new EventEmitter();
302
+ /** Fired after a permission has been successfully revoked. */
303
+ PermissionRevoked = new EventEmitter();
304
+ /** Fired whenever an error is shown to the user. Useful for parent telemetry. */
305
+ ErrorOccurred = new EventEmitter();
306
+ // ─── Public state (read by template) ───────────────────────────────────────
307
+ SharedWithMe = [];
308
+ SharedByMe = [];
309
+ IsLoadingWithMe = false;
310
+ IsLoadingByMe = false;
311
+ ErrorMessage = null;
312
+ async ngOnInit() {
313
+ await this.loadTab(this.ActiveTab);
314
+ }
315
+ // ─── Public methods (callable from parent via @ViewChild) ──────────────────
316
+ /** Switch to a tab and load its data if not already loaded. */
317
+ async SwitchTab(tab) {
318
+ if (this.ActiveTab === tab)
319
+ return;
320
+ this.ActiveTab = tab;
321
+ this.ActiveTabChange.emit(tab);
322
+ await this.loadTab(tab);
323
+ }
324
+ /** Force-refresh the currently active tab. */
325
+ async Refresh() {
326
+ if (this.ActiveTab === 'shared-with-me') {
327
+ this.SharedWithMe = [];
328
+ await this.loadSharedWithMe();
329
+ }
330
+ else {
331
+ this.SharedByMe = [];
332
+ await this.loadSharedByMe();
333
+ }
334
+ }
335
+ // ─── Template event handlers ───────────────────────────────────────────────
336
+ OnTabClick(tab) {
337
+ return this.SwitchTab(tab);
338
+ }
339
+ OnRowClick(row) {
340
+ this.ResourceClicked.emit(row);
341
+ }
342
+ OnClose() {
343
+ this.CloseRequested.emit();
344
+ }
345
+ async OnRevoke(row, event) {
346
+ event.stopPropagation();
347
+ if (!row.SourceRecordID)
348
+ return;
349
+ const entityName = this.SharingEntityResolver(row.DomainName);
350
+ if (!entityName)
351
+ return;
352
+ const confirmed = await this.confirmRevoke(row);
353
+ if (!confirmed)
354
+ return;
355
+ try {
356
+ const md = new Metadata();
357
+ const entity = await md.GetEntityObject(entityName);
358
+ const key = new CompositeKey();
359
+ key.KeyValuePairs.push({ FieldName: 'ID', Value: row.SourceRecordID });
360
+ const loaded = await entity.InnerLoad(key);
361
+ if (!loaded) {
362
+ this.setError('Could not load the permission record.');
363
+ return;
364
+ }
365
+ const deleted = await entity.Delete();
366
+ if (!deleted) {
367
+ this.setError(`Revoke failed: ${entity.LatestResult?.CompleteMessage ?? 'unknown error'}`);
368
+ return;
369
+ }
370
+ this.PermissionRevoked.emit(row);
371
+ await this.Refresh();
372
+ }
373
+ catch (e) {
374
+ this.setError(`Revoke failed: ${e instanceof Error ? e.message : String(e)}`);
375
+ }
376
+ }
377
+ ToggleGroup(group) {
378
+ group.Expanded = !group.Expanded;
379
+ this.cdr.detectChanges();
380
+ }
381
+ ActionsLabel(actions) {
382
+ return actions.join(', ');
383
+ }
384
+ TrackByDomain(_idx, g) {
385
+ return g.DomainName;
386
+ }
387
+ TrackByRow(_idx, r) {
388
+ return r.SourceRecordID ?? `${r.DomainName}|${r.ResourceID ?? ''}|${r.GranteeID ?? ''}`;
389
+ }
390
+ // ─── Internal helpers ──────────────────────────────────────────────────────
391
+ async loadTab(tab) {
392
+ if (tab === 'shared-with-me') {
393
+ if (this.SharedWithMe.length === 0 && !this.IsLoadingWithMe) {
394
+ await this.loadSharedWithMe();
395
+ }
396
+ }
397
+ else {
398
+ if (this.SharedByMe.length === 0 && !this.IsLoadingByMe) {
399
+ await this.loadSharedByMe();
400
+ }
401
+ }
402
+ }
403
+ async loadSharedWithMe() {
404
+ const user = new Metadata().CurrentUser;
405
+ if (!user)
406
+ return;
407
+ this.IsLoadingWithMe = true;
408
+ this.ErrorMessage = null;
409
+ this.cdr.detectChanges();
410
+ try {
411
+ const rows = await PermissionEngine.Instance.GetPermissionsSharedWithUser(user);
412
+ this.SharedWithMe = this.groupByDomain(rows);
413
+ }
414
+ catch (e) {
415
+ this.setError(`Failed to load shares: ${e instanceof Error ? e.message : String(e)}`);
416
+ }
417
+ this.IsLoadingWithMe = false;
418
+ this.cdr.detectChanges();
419
+ }
420
+ async loadSharedByMe() {
421
+ const user = new Metadata().CurrentUser;
422
+ if (!user)
423
+ return;
424
+ this.IsLoadingByMe = true;
425
+ this.ErrorMessage = null;
426
+ this.cdr.detectChanges();
427
+ try {
428
+ const rows = await PermissionEngine.Instance.GetPermissionsGrantedByUser(user);
429
+ this.SharedByMe = this.groupByDomain(rows);
430
+ }
431
+ catch (e) {
432
+ this.setError(`Failed to load grants: ${e instanceof Error ? e.message : String(e)}`);
433
+ }
434
+ this.IsLoadingByMe = false;
435
+ this.cdr.detectChanges();
436
+ }
437
+ groupByDomain(rows) {
438
+ const bucket = new Map();
439
+ for (const r of rows) {
440
+ const list = bucket.get(r.DomainName) ?? [];
441
+ list.push(r);
442
+ bucket.set(r.DomainName, list);
443
+ }
444
+ const groups = [];
445
+ for (const [domainName, list] of bucket) {
446
+ groups.push({
447
+ DomainName: domainName,
448
+ Icon: PermissionEngine.DomainIconFor(domainName),
449
+ Rows: list.sort((a, b) => (a.ResourceName ?? '').localeCompare(b.ResourceName ?? '')),
450
+ Expanded: list.length <= 10,
451
+ });
452
+ }
453
+ return groups.sort((a, b) => a.DomainName.localeCompare(b.DomainName));
454
+ }
455
+ setError(message) {
456
+ this.ErrorMessage = message;
457
+ this.ErrorOccurred.emit(message);
458
+ LogError(message);
459
+ this.cdr.detectChanges();
460
+ }
461
+ confirmRevoke(row) {
462
+ const resourceLabel = row.ResourceName ? `"${row.ResourceName}"` : 'this resource';
463
+ const granteeLabel = row.GranteeName ?? 'this user';
464
+ const message = `Revoke access to ${resourceLabel} for ${granteeLabel}? This cannot be undone.`;
465
+ return new Promise((resolve) => {
466
+ const ref = this.dialogService.open({
467
+ title: this.RevokeConfirmTitle,
468
+ content: message,
469
+ actions: [
470
+ { text: 'Revoke', primary: true, themeColor: 'error' },
471
+ { text: 'Cancel', primary: false },
472
+ ],
473
+ width: 420,
474
+ minWidth: 300,
475
+ });
476
+ ref.Result.subscribe((result) => {
477
+ const action = result;
478
+ resolve(!!action && 'text' in action && action.text === 'Revoke');
479
+ });
480
+ });
481
+ }
482
+ static ɵfac = function UserSharingCenterComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || UserSharingCenterComponent)(); };
483
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserSharingCenterComponent, selectors: [["mj-user-sharing-center"]], inputs: { ActiveTab: "ActiveTab", ShowCloseButton: "ShowCloseButton", RevokeConfirmTitle: "RevokeConfirmTitle", SharingEntityResolver: "SharingEntityResolver" }, outputs: { ActiveTabChange: "ActiveTabChange", ResourceClicked: "ResourceClicked", CloseRequested: "CloseRequested", PermissionRevoked: "PermissionRevoked", ErrorOccurred: "ErrorOccurred" }, decls: 13, vars: 7, consts: [[1, "user-sharing-center"], [1, "tabs"], [1, "tab", 3, "click"], [1, "fa-solid", "fa-inbox"], [1, "fa-solid", "fa-paper-plane"], [1, "spacer"], ["title", "Close", 1, "close"], [1, "error"], ["title", "Close", 1, "close", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "loading"], [1, "empty"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "group"], [1, "group-header", 3, "click"], [1, "group-name"], [1, "count"], [1, "fa-solid", "chevron"], [1, "rows"], [1, "row"], [1, "row", 3, "click"], [1, "resource"], [1, "resource-type"], [1, "actions"], [1, "expires"], [1, "row", "editable"], [1, "grantee"], [1, "fa-solid", "fa-user"], ["title", "Revoke access", 1, "revoke", 3, "click"], [1, "fa-solid", "fa-trash"]], template: function UserSharingCenterComponent_Template(rf, ctx) { if (rf & 1) {
484
+ i0.ɵɵdomElementStart(0, "div", 0)(1, "div", 1)(2, "button", 2);
485
+ i0.ɵɵdomListener("click", function UserSharingCenterComponent_Template_button_click_2_listener() { return ctx.OnTabClick("shared-with-me"); });
486
+ i0.ɵɵdomElement(3, "i", 3);
487
+ i0.ɵɵtext(4, " Shared with me ");
488
+ i0.ɵɵdomElementEnd();
489
+ i0.ɵɵdomElementStart(5, "button", 2);
490
+ i0.ɵɵdomListener("click", function UserSharingCenterComponent_Template_button_click_5_listener() { return ctx.OnTabClick("shared-by-me"); });
491
+ i0.ɵɵdomElement(6, "i", 4);
492
+ i0.ɵɵtext(7, " Shared by me ");
493
+ i0.ɵɵdomElementEnd();
494
+ i0.ɵɵdomElement(8, "div", 5);
495
+ i0.ɵɵconditionalCreate(9, UserSharingCenterComponent_Conditional_9_Template, 2, 0, "button", 6);
496
+ i0.ɵɵdomElementEnd();
497
+ i0.ɵɵconditionalCreate(10, UserSharingCenterComponent_Conditional_10_Template, 3, 1, "div", 7);
498
+ i0.ɵɵconditionalCreate(11, UserSharingCenterComponent_Conditional_11_Template, 3, 1)(12, UserSharingCenterComponent_Conditional_12_Template, 3, 1);
499
+ i0.ɵɵdomElementEnd();
500
+ } if (rf & 2) {
501
+ i0.ɵɵadvance(2);
502
+ i0.ɵɵclassProp("active", ctx.ActiveTab === "shared-with-me");
503
+ i0.ɵɵadvance(3);
504
+ i0.ɵɵclassProp("active", ctx.ActiveTab === "shared-by-me");
505
+ i0.ɵɵadvance(4);
506
+ i0.ɵɵconditional(ctx.ShowCloseButton ? 9 : -1);
507
+ i0.ɵɵadvance();
508
+ i0.ɵɵconditional(ctx.ErrorMessage ? 10 : -1);
509
+ i0.ɵɵadvance();
510
+ i0.ɵɵconditional(ctx.ActiveTab === "shared-with-me" ? 11 : 12);
511
+ } }, dependencies: [CommonModule, i1.DatePipe], styles: [".user-sharing-center[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 480px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.tabs[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.tabs[_ngcontent-%COMP%] .tab[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n}\n\n.tabs[_ngcontent-%COMP%] .tab[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.tabs[_ngcontent-%COMP%] .tab.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.tabs[_ngcontent-%COMP%] .spacer[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.tabs[_ngcontent-%COMP%] .close[_ngcontent-%COMP%] {\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n font-size: 16px;\n}\n\n.tabs[_ngcontent-%COMP%] .close[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.loading[_ngcontent-%COMP%], \n.empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 16px;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.loading[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n}\n\n.error[_ngcontent-%COMP%] {\n margin: 12px;\n padding: 10px 12px;\n border-radius: 4px;\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.group[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.group[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.group-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n color: var(--mj-text-primary);\n font-weight: 600;\n font-size: 13px;\n cursor: pointer;\n text-align: left;\n}\n\n.group-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.group-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child {\n color: var(--mj-brand-primary);\n width: 18px;\n text-align: center;\n}\n\n.group-header[_ngcontent-%COMP%] .group-name[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.group-header[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n padding: 2px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 10px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.group-header[_ngcontent-%COMP%] .chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.rows[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto auto auto;\n align-items: center;\n gap: 12px;\n padding: 8px 16px 8px 44px;\n background: transparent;\n border: none;\n color: var(--mj-text-primary);\n cursor: pointer;\n text-align: left;\n font-size: 13px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.row.editable[_ngcontent-%COMP%] {\n grid-template-columns: minmax(0, 1fr) auto auto auto auto auto;\n cursor: default;\n}\n\n.row.editable[_ngcontent-%COMP%]:hover {\n background: transparent;\n}\n\n.row[_ngcontent-%COMP%] .resource[_ngcontent-%COMP%] {\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.row[_ngcontent-%COMP%] .resource-type[_ngcontent-%COMP%], \n.row[_ngcontent-%COMP%] .grantee[_ngcontent-%COMP%], \n.row[_ngcontent-%COMP%] .actions[_ngcontent-%COMP%], \n.row[_ngcontent-%COMP%] .expires[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n white-space: nowrap;\n}\n\n.row[_ngcontent-%COMP%] .grantee[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 4px;\n}\n\n.row[_ngcontent-%COMP%] .actions[_ngcontent-%COMP%] {\n padding: 2px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n font-family: var(--mj-font-mono, monospace);\n font-size: 11px;\n}\n\n.row[_ngcontent-%COMP%] .revoke[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n border-radius: 4px;\n border: none;\n background: transparent;\n color: var(--mj-status-error);\n cursor: pointer;\n font-size: 13px;\n}\n\n.row[_ngcontent-%COMP%] .revoke[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n}"], changeDetection: 0 });
512
+ }
513
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserSharingCenterComponent, [{
514
+ type: Component,
515
+ args: [{ standalone: true, selector: 'mj-user-sharing-center', imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"user-sharing-center\">\n <div class=\"tabs\">\n <button\n class=\"tab\"\n [class.active]=\"ActiveTab === 'shared-with-me'\"\n (click)=\"OnTabClick('shared-with-me')\">\n <i class=\"fa-solid fa-inbox\"></i>\n Shared with me\n </button>\n <button\n class=\"tab\"\n [class.active]=\"ActiveTab === 'shared-by-me'\"\n (click)=\"OnTabClick('shared-by-me')\">\n <i class=\"fa-solid fa-paper-plane\"></i>\n Shared by me\n </button>\n <div class=\"spacer\"></div>\n @if (ShowCloseButton) {\n <button class=\"close\" (click)=\"OnClose()\" title=\"Close\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n }\n </div>\n\n @if (ErrorMessage) {\n <div class=\"error\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n {{ ErrorMessage }}\n </div>\n }\n\n @if (ActiveTab === 'shared-with-me') {\n @if (IsLoadingWithMe) {\n <div class=\"loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading\u2026\n </div>\n } @else if (SharedWithMe.length === 0) {\n <div class=\"empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n Nothing has been shared directly with you yet.\n </div>\n } @else {\n @for (group of SharedWithMe; track TrackByDomain($index, group)) {\n <div class=\"group\">\n <button class=\"group-header\" (click)=\"ToggleGroup(group)\">\n <i [class]=\"group.Icon\"></i>\n <span class=\"group-name\">{{ group.DomainName }}</span>\n <span class=\"count\">{{ group.Rows.length }}</span>\n <i class=\"fa-solid chevron\" [class.fa-chevron-down]=\"group.Expanded\" [class.fa-chevron-right]=\"!group.Expanded\"></i>\n </button>\n @if (group.Expanded) {\n <div class=\"rows\">\n @for (row of group.Rows; track TrackByRow($index, row)) {\n <button class=\"row\" (click)=\"OnRowClick(row)\">\n <span class=\"resource\">{{ row.ResourceName || row.ResourceID }}</span>\n <span class=\"resource-type\">{{ row.ResourceType }}</span>\n <span class=\"actions\">{{ ActionsLabel(row.Actions) }}</span>\n @if (row.ExpiresAt) {\n <span class=\"expires\">expires {{ row.ExpiresAt | date:'mediumDate' }}</span>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n @if (IsLoadingByMe) {\n <div class=\"loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading\u2026\n </div>\n } @else if (SharedByMe.length === 0) {\n <div class=\"empty\">\n <i class=\"fa-solid fa-paper-plane\"></i>\n You haven't shared anything with others yet.\n </div>\n } @else {\n @for (group of SharedByMe; track TrackByDomain($index, group)) {\n <div class=\"group\">\n <button class=\"group-header\" (click)=\"ToggleGroup(group)\">\n <i [class]=\"group.Icon\"></i>\n <span class=\"group-name\">{{ group.DomainName }}</span>\n <span class=\"count\">{{ group.Rows.length }}</span>\n <i class=\"fa-solid chevron\" [class.fa-chevron-down]=\"group.Expanded\" [class.fa-chevron-right]=\"!group.Expanded\"></i>\n </button>\n @if (group.Expanded) {\n <div class=\"rows\">\n @for (row of group.Rows; track TrackByRow($index, row)) {\n <div class=\"row editable\">\n <span class=\"resource\">{{ row.ResourceName || row.ResourceID }}</span>\n <span class=\"resource-type\">{{ row.ResourceType }}</span>\n <span class=\"grantee\">\n <i class=\"fa-solid fa-user\"></i>\n {{ row.GranteeName || row.GranteeType }}\n </span>\n <span class=\"actions\">{{ ActionsLabel(row.Actions) }}</span>\n @if (row.ExpiresAt) {\n <span class=\"expires\">expires {{ row.ExpiresAt | date:'mediumDate' }}</span>\n }\n <button class=\"revoke\" (click)=\"OnRevoke(row, $event)\" title=\"Revoke access\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n }\n</div>\n", styles: [".user-sharing-center {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 480px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.tabs {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.tabs .tab {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n}\n\n.tabs .tab:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.tabs .tab.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.tabs .spacer {\n flex: 1;\n}\n\n.tabs .close {\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n font-size: 16px;\n}\n\n.tabs .close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.loading,\n.empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 16px;\n gap: 12px;\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.loading i,\n.empty i {\n font-size: 28px;\n}\n\n.error {\n margin: 12px;\n padding: 10px 12px;\n border-radius: 4px;\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.group {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.group:last-child {\n border-bottom: none;\n}\n\n.group-header {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n color: var(--mj-text-primary);\n font-weight: 600;\n font-size: 13px;\n cursor: pointer;\n text-align: left;\n}\n\n.group-header:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.group-header i:first-child {\n color: var(--mj-brand-primary);\n width: 18px;\n text-align: center;\n}\n\n.group-header .group-name {\n flex: 1;\n}\n\n.group-header .count {\n padding: 2px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 10px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.group-header .chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.rows {\n display: flex;\n flex-direction: column;\n}\n\n.row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto auto auto;\n align-items: center;\n gap: 12px;\n padding: 8px 16px 8px 44px;\n background: transparent;\n border: none;\n color: var(--mj-text-primary);\n cursor: pointer;\n text-align: left;\n font-size: 13px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.row.editable {\n grid-template-columns: minmax(0, 1fr) auto auto auto auto auto;\n cursor: default;\n}\n\n.row.editable:hover {\n background: transparent;\n}\n\n.row .resource {\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.row .resource-type,\n.row .grantee,\n.row .actions,\n.row .expires {\n color: var(--mj-text-secondary);\n font-size: 12px;\n white-space: nowrap;\n}\n\n.row .grantee i {\n margin-right: 4px;\n}\n\n.row .actions {\n padding: 2px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 4px;\n font-family: var(--mj-font-mono, monospace);\n font-size: 11px;\n}\n\n.row .revoke {\n width: 28px;\n height: 28px;\n border-radius: 4px;\n border: none;\n background: transparent;\n color: var(--mj-status-error);\n cursor: pointer;\n font-size: 13px;\n}\n\n.row .revoke:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n}\n"] }]
516
+ }], null, { ActiveTab: [{
517
+ type: Input
518
+ }], ShowCloseButton: [{
519
+ type: Input
520
+ }], RevokeConfirmTitle: [{
521
+ type: Input
522
+ }], SharingEntityResolver: [{
523
+ type: Input
524
+ }], ActiveTabChange: [{
525
+ type: Output
526
+ }], ResourceClicked: [{
527
+ type: Output
528
+ }], CloseRequested: [{
529
+ type: Output
530
+ }], PermissionRevoked: [{
531
+ type: Output
532
+ }], ErrorOccurred: [{
533
+ type: Output
534
+ }] }); })();
535
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserSharingCenterComponent, { className: "UserSharingCenterComponent", filePath: "src/lib/user-sharing-center.component.ts", lineNumber: 95 }); })();
536
+ //# sourceMappingURL=user-sharing-center.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-sharing-center.component.js","sourceRoot":"","sources":["../../src/lib/user-sharing-center.component.ts","../../src/lib/user-sharing-center.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n EventEmitter,\n Input,\n OnInit,\n Output,\n inject,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n BaseEntity,\n CompositeKey,\n LogError,\n Metadata,\n NormalizedPermission,\n PermissionAction,\n} from '@memberjunction/core';\nimport { PermissionEngine } from '@memberjunction/core-entities';\nimport { MJDialogAction, MJDialogService } from '@memberjunction/ng-ui-components';\n\n/** Which tab the Sharing Center is currently displaying. */\nexport type SharingCenterTab = 'shared-with-me' | 'shared-by-me';\n\n/**\n * One collapsible domain section rendered by {@link UserSharingCenterComponent}.\n * Exported because consumers occasionally want to render their own custom layout\n * around the same shape.\n */\nexport interface SharingCenterDomainGroup {\n DomainName: string;\n Icon: string;\n Rows: NormalizedPermission[];\n Expanded: boolean;\n}\n\n/**\n * Default domain → entity-name mapping used by the Sharing Center to load and\n * delete the underlying permission record on Revoke. Apps with custom permission\n * domains can pass a replacement function via `SharingEntityResolver`.\n */\nexport const DefaultSharingEntityResolver = (domainName: string): string | null => {\n switch (domainName) {\n case 'Dashboard Permissions':\n return 'MJ: Dashboard Permissions';\n case 'Artifact Permissions':\n return 'MJ: Artifact Permissions';\n case 'Collection Permissions':\n return 'MJ: Collection Permissions';\n case 'Access Control Rules':\n return 'MJ: Access Control Rules';\n case 'Resource Permissions':\n return 'MJ: Resource Permissions';\n default:\n return null;\n }\n};\n\n/**\n * **Generic, framework-agnostic Sharing Center.** Renders two tabs:\n *\n * - **Shared with me** — every resource the current user has direct (non-role)\n * access to, grouped by permission domain. Each row is clickable and emits\n * `ResourceClicked` so the embedding app can route to the resource. The Generic\n * component never imports Angular Router / NavigationService — the parent\n * decides how to navigate.\n *\n * - **Shared by me** — every permission record where the current user is the\n * grantor. Each row has a Revoke button that deletes the underlying permission\n * record through `Metadata.GetEntityObject().Delete()` (so audit captures the\n * revoke and BaseEntity event-driven cache invalidation runs).\n *\n * Inputs / Outputs are designed so the component drops cleanly into a dialog,\n * a side panel, an embedded widget, or a full-page route.\n *\n * @example\n * ```html\n * <mj-user-sharing-center\n * [ActiveTab]=\"tab\"\n * (ActiveTabChange)=\"tab = $event\"\n * (ResourceClicked)=\"OnResourceClicked($event)\"\n * (CloseRequested)=\"dialogRef.Close()\">\n * </mj-user-sharing-center>\n * ```\n */\n@Component({\n standalone: true,\n selector: 'mj-user-sharing-center',\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './user-sharing-center.component.html',\n styleUrls: ['./user-sharing-center.component.css'],\n})\nexport class UserSharingCenterComponent implements OnInit {\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly dialogService = inject(MJDialogService);\n\n // ─── Inputs ────────────────────────────────────────────────────────────────\n\n /** Which tab is shown initially. Two-way bindable via `ActiveTabChange`. */\n @Input() ActiveTab: SharingCenterTab = 'shared-with-me';\n\n /**\n * When true, the close button is rendered in the tab strip. Hide it when the\n * embedding container provides its own close affordance.\n */\n @Input() ShowCloseButton = true;\n\n /** Title text displayed in the confirm-revoke dialog. */\n @Input() RevokeConfirmTitle = 'Revoke access';\n\n /**\n * Maps a permission domain name (e.g. `\"Dashboard Permissions\"`) to the entity\n * name used to load and delete the underlying record on Revoke. Replace to add\n * support for custom domains. Defaults to {@link DefaultSharingEntityResolver}.\n */\n @Input() SharingEntityResolver: (domainName: string) => string | null = DefaultSharingEntityResolver;\n\n // ─── Outputs ───────────────────────────────────────────────────────────────\n\n /** Two-way binding partner for `ActiveTab`. */\n @Output() ActiveTabChange = new EventEmitter<SharingCenterTab>();\n\n /** Fired when a row in the \"Shared with me\" tab is clicked. */\n @Output() ResourceClicked = new EventEmitter<NormalizedPermission>();\n\n /** Fired when the user clicks the close button. Parent should close the host dialog/panel. */\n @Output() CloseRequested = new EventEmitter<void>();\n\n /** Fired after a permission has been successfully revoked. */\n @Output() PermissionRevoked = new EventEmitter<NormalizedPermission>();\n\n /** Fired whenever an error is shown to the user. Useful for parent telemetry. */\n @Output() ErrorOccurred = new EventEmitter<string>();\n\n // ─── Public state (read by template) ───────────────────────────────────────\n\n SharedWithMe: SharingCenterDomainGroup[] = [];\n SharedByMe: SharingCenterDomainGroup[] = [];\n\n IsLoadingWithMe = false;\n IsLoadingByMe = false;\n\n ErrorMessage: string | null = null;\n\n async ngOnInit(): Promise<void> {\n await this.loadTab(this.ActiveTab);\n }\n\n // ─── Public methods (callable from parent via @ViewChild) ──────────────────\n\n /** Switch to a tab and load its data if not already loaded. */\n public async SwitchTab(tab: SharingCenterTab): Promise<void> {\n if (this.ActiveTab === tab) return;\n this.ActiveTab = tab;\n this.ActiveTabChange.emit(tab);\n await this.loadTab(tab);\n }\n\n /** Force-refresh the currently active tab. */\n public async Refresh(): Promise<void> {\n if (this.ActiveTab === 'shared-with-me') {\n this.SharedWithMe = [];\n await this.loadSharedWithMe();\n } else {\n this.SharedByMe = [];\n await this.loadSharedByMe();\n }\n }\n\n // ─── Template event handlers ───────────────────────────────────────────────\n\n OnTabClick(tab: SharingCenterTab): Promise<void> {\n return this.SwitchTab(tab);\n }\n\n OnRowClick(row: NormalizedPermission): void {\n this.ResourceClicked.emit(row);\n }\n\n OnClose(): void {\n this.CloseRequested.emit();\n }\n\n async OnRevoke(row: NormalizedPermission, event: Event): Promise<void> {\n event.stopPropagation();\n if (!row.SourceRecordID) return;\n\n const entityName = this.SharingEntityResolver(row.DomainName);\n if (!entityName) return;\n\n const confirmed = await this.confirmRevoke(row);\n if (!confirmed) return;\n\n try {\n const md = new Metadata();\n const entity = await md.GetEntityObject<BaseEntity>(entityName);\n const key = new CompositeKey();\n key.KeyValuePairs.push({ FieldName: 'ID', Value: row.SourceRecordID });\n const loaded = await entity.InnerLoad(key);\n if (!loaded) {\n this.setError('Could not load the permission record.');\n return;\n }\n const deleted = await entity.Delete();\n if (!deleted) {\n this.setError(`Revoke failed: ${entity.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n return;\n }\n this.PermissionRevoked.emit(row);\n await this.Refresh();\n } catch (e) {\n this.setError(`Revoke failed: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n ToggleGroup(group: SharingCenterDomainGroup): void {\n group.Expanded = !group.Expanded;\n this.cdr.detectChanges();\n }\n\n ActionsLabel(actions: PermissionAction[]): string {\n return actions.join(', ');\n }\n\n TrackByDomain(_idx: number, g: SharingCenterDomainGroup): string {\n return g.DomainName;\n }\n\n TrackByRow(_idx: number, r: NormalizedPermission): string {\n return r.SourceRecordID ?? `${r.DomainName}|${r.ResourceID ?? ''}|${r.GranteeID ?? ''}`;\n }\n\n // ─── Internal helpers ──────────────────────────────────────────────────────\n\n private async loadTab(tab: SharingCenterTab): Promise<void> {\n if (tab === 'shared-with-me') {\n if (this.SharedWithMe.length === 0 && !this.IsLoadingWithMe) {\n await this.loadSharedWithMe();\n }\n } else {\n if (this.SharedByMe.length === 0 && !this.IsLoadingByMe) {\n await this.loadSharedByMe();\n }\n }\n }\n\n private async loadSharedWithMe(): Promise<void> {\n const user = new Metadata().CurrentUser;\n if (!user) return;\n\n this.IsLoadingWithMe = true;\n this.ErrorMessage = null;\n this.cdr.detectChanges();\n try {\n const rows = await PermissionEngine.Instance.GetPermissionsSharedWithUser(user);\n this.SharedWithMe = this.groupByDomain(rows);\n } catch (e) {\n this.setError(`Failed to load shares: ${e instanceof Error ? e.message : String(e)}`);\n }\n this.IsLoadingWithMe = false;\n this.cdr.detectChanges();\n }\n\n private async loadSharedByMe(): Promise<void> {\n const user = new Metadata().CurrentUser;\n if (!user) return;\n\n this.IsLoadingByMe = true;\n this.ErrorMessage = null;\n this.cdr.detectChanges();\n try {\n const rows = await PermissionEngine.Instance.GetPermissionsGrantedByUser(user);\n this.SharedByMe = this.groupByDomain(rows);\n } catch (e) {\n this.setError(`Failed to load grants: ${e instanceof Error ? e.message : String(e)}`);\n }\n this.IsLoadingByMe = false;\n this.cdr.detectChanges();\n }\n\n private groupByDomain(rows: NormalizedPermission[]): SharingCenterDomainGroup[] {\n const bucket = new Map<string, NormalizedPermission[]>();\n for (const r of rows) {\n const list = bucket.get(r.DomainName) ?? [];\n list.push(r);\n bucket.set(r.DomainName, list);\n }\n const groups: SharingCenterDomainGroup[] = [];\n for (const [domainName, list] of bucket) {\n groups.push({\n DomainName: domainName,\n Icon: PermissionEngine.DomainIconFor(domainName),\n Rows: list.sort((a, b) => (a.ResourceName ?? '').localeCompare(b.ResourceName ?? '')),\n Expanded: list.length <= 10,\n });\n }\n return groups.sort((a, b) => a.DomainName.localeCompare(b.DomainName));\n }\n\n private setError(message: string): void {\n this.ErrorMessage = message;\n this.ErrorOccurred.emit(message);\n LogError(message);\n this.cdr.detectChanges();\n }\n\n private confirmRevoke(row: NormalizedPermission): Promise<boolean> {\n const resourceLabel = row.ResourceName ? `\"${row.ResourceName}\"` : 'this resource';\n const granteeLabel = row.GranteeName ?? 'this user';\n const message = `Revoke access to ${resourceLabel} for ${granteeLabel}? This cannot be undone.`;\n\n return new Promise<boolean>((resolve) => {\n const ref = this.dialogService.open({\n title: this.RevokeConfirmTitle,\n content: message,\n actions: [\n { text: 'Revoke', primary: true, themeColor: 'error' },\n { text: 'Cancel', primary: false },\n ],\n width: 420,\n minWidth: 300,\n });\n\n ref.Result.subscribe((result) => {\n const action = result as MJDialogAction | undefined;\n resolve(!!action && 'text' in action && action.text === 'Revoke');\n });\n });\n }\n}\n","<div class=\"user-sharing-center\">\n <div class=\"tabs\">\n <button\n class=\"tab\"\n [class.active]=\"ActiveTab === 'shared-with-me'\"\n (click)=\"OnTabClick('shared-with-me')\">\n <i class=\"fa-solid fa-inbox\"></i>\n Shared with me\n </button>\n <button\n class=\"tab\"\n [class.active]=\"ActiveTab === 'shared-by-me'\"\n (click)=\"OnTabClick('shared-by-me')\">\n <i class=\"fa-solid fa-paper-plane\"></i>\n Shared by me\n </button>\n <div class=\"spacer\"></div>\n @if (ShowCloseButton) {\n <button class=\"close\" (click)=\"OnClose()\" title=\"Close\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n }\n </div>\n\n @if (ErrorMessage) {\n <div class=\"error\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n {{ ErrorMessage }}\n </div>\n }\n\n @if (ActiveTab === 'shared-with-me') {\n @if (IsLoadingWithMe) {\n <div class=\"loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading…\n </div>\n } @else if (SharedWithMe.length === 0) {\n <div class=\"empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n Nothing has been shared directly with you yet.\n </div>\n } @else {\n @for (group of SharedWithMe; track TrackByDomain($index, group)) {\n <div class=\"group\">\n <button class=\"group-header\" (click)=\"ToggleGroup(group)\">\n <i [class]=\"group.Icon\"></i>\n <span class=\"group-name\">{{ group.DomainName }}</span>\n <span class=\"count\">{{ group.Rows.length }}</span>\n <i class=\"fa-solid chevron\" [class.fa-chevron-down]=\"group.Expanded\" [class.fa-chevron-right]=\"!group.Expanded\"></i>\n </button>\n @if (group.Expanded) {\n <div class=\"rows\">\n @for (row of group.Rows; track TrackByRow($index, row)) {\n <button class=\"row\" (click)=\"OnRowClick(row)\">\n <span class=\"resource\">{{ row.ResourceName || row.ResourceID }}</span>\n <span class=\"resource-type\">{{ row.ResourceType }}</span>\n <span class=\"actions\">{{ ActionsLabel(row.Actions) }}</span>\n @if (row.ExpiresAt) {\n <span class=\"expires\">expires {{ row.ExpiresAt | date:'mediumDate' }}</span>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n @if (IsLoadingByMe) {\n <div class=\"loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading…\n </div>\n } @else if (SharedByMe.length === 0) {\n <div class=\"empty\">\n <i class=\"fa-solid fa-paper-plane\"></i>\n You haven't shared anything with others yet.\n </div>\n } @else {\n @for (group of SharedByMe; track TrackByDomain($index, group)) {\n <div class=\"group\">\n <button class=\"group-header\" (click)=\"ToggleGroup(group)\">\n <i [class]=\"group.Icon\"></i>\n <span class=\"group-name\">{{ group.DomainName }}</span>\n <span class=\"count\">{{ group.Rows.length }}</span>\n <i class=\"fa-solid chevron\" [class.fa-chevron-down]=\"group.Expanded\" [class.fa-chevron-right]=\"!group.Expanded\"></i>\n </button>\n @if (group.Expanded) {\n <div class=\"rows\">\n @for (row of group.Rows; track TrackByRow($index, row)) {\n <div class=\"row editable\">\n <span class=\"resource\">{{ row.ResourceName || row.ResourceID }}</span>\n <span class=\"resource-type\">{{ row.ResourceType }}</span>\n <span class=\"grantee\">\n <i class=\"fa-solid fa-user\"></i>\n {{ row.GranteeName || row.GranteeType }}\n </span>\n <span class=\"actions\">{{ ActionsLabel(row.Actions) }}</span>\n @if (row.ExpiresAt) {\n <span class=\"expires\">expires {{ row.ExpiresAt | date:'mediumDate' }}</span>\n }\n <button class=\"revoke\" (click)=\"OnRevoke(row, $event)\" title=\"Revoke access\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n }\n</div>\n"]}