@memberjunction/ng-resource-permissions 6.1.4 → 6.2.0-edge.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"resource-share-dialog.component.js","sourceRoot":"","sources":["../../src/lib/resource-share-dialog.component.ts","../../src/lib/resource-share-dialog.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges, ChangeDetectorRef, ViewEncapsulation } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { RunView } from '@memberjunction/core';\nimport { MJUserEntity } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport {\n RESOURCE_SHARE_LEVELS,\n ResourceShareAdapter,\n ResourceShareContext,\n ResourceShareLevel,\n ResourceSharePermissionModel\n} from './resource-share-adapter';\n\n/**\n * Result emitted when {@link GenericShareDialogComponent} closes.\n */\nexport interface ResourceShareDialogResult {\n Action: 'save' | 'cancel';\n}\n\n/**\n * Resource-type-agnostic share dialog. Every resource's sharing UX collapses to\n * three tiers — View / Edit / Owner — so the dialog exposes a single level\n * selector per grantee rather than a grab bag of `Can*` checkboxes. Adapters\n * translate the level to whatever shape their backing entity actually persists.\n */\n@Component({\n standalone: false,\n selector: 'mj-resource-share-dialog',\n templateUrl: './resource-share-dialog.component.html',\n styleUrls: ['./resource-share-dialog.component.css'],\n encapsulation: ViewEncapsulation.None\n})\nexport class GenericShareDialogComponent extends BaseAngularComponent implements OnChanges {\n @Input() Visible = false;\n @Input() Context: ResourceShareContext | null = null;\n @Input() Adapter: ResourceShareAdapter | null = null;\n @Output() Result = new EventEmitter<ResourceShareDialogResult>();\n\n public readonly Levels = RESOURCE_SHARE_LEVELS;\n\n public UserShares: ResourceSharePermissionModel[] = [];\n public AvailableUsers: MJUserEntity[] = [];\n private allUsers: MJUserEntity[] = [];\n\n public IsLoading = false;\n public Error: string | null = null;\n public UserSearchFilter = '';\n\n /** Message for the no-results empty-state, echoing the current search term. */\n public get NoUsersFoundMessage(): string {\n return `No users found matching \"${this.UserSearchFilter}\"`;\n }\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Visible'] && this.Visible && this.Context && this.Adapter) {\n this.resetDialog();\n this.loadData();\n }\n }\n\n private resetDialog(): void {\n this.Error = null;\n this.IsLoading = false;\n this.UserShares = [];\n this.AvailableUsers = [];\n this.UserSearchFilter = '';\n }\n\n private async loadData(): Promise<void> {\n if (!this.Context || !this.Adapter) return;\n\n this.IsLoading = true;\n this.cdr.detectChanges();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const usersResult = await rv.RunView<MJUserEntity>({\n EntityName: 'MJ: Users',\n ExtraFilter: 'IsActive = 1',\n OrderBy: 'Name',\n ResultType: 'entity_object'\n });\n this.allUsers = usersResult.Success ? usersResult.Results : [];\n\n this.UserShares = await this.Adapter.LoadShares(this.Context);\n this.UserShares.forEach((s) => (s._InitialLevel = s.Level));\n this.updateAvailableUsers();\n } catch (error) {\n console.error('Error loading share data:', error);\n this.Error = 'Failed to load sharing data. Please try again.';\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n private updateAvailableUsers(): void {\n if (!this.Context) return;\n const sharedUserIds = new Set(\n this.UserShares.filter((s) => !s.MarkedForRemoval).map((s) => s.User.ID)\n );\n const ownerId = this.Context.OwnerUserID;\n this.AvailableUsers = this.allUsers.filter((user) => {\n if (ownerId && UUIDsEqual(user.ID, ownerId)) return false;\n return !sharedUserIds.has(user.ID);\n });\n }\n\n public get FilteredAvailableUsers(): MJUserEntity[] {\n if (!this.UserSearchFilter.trim()) {\n return this.AvailableUsers.slice(0, 10);\n }\n const filter = this.UserSearchFilter.toLowerCase();\n return this.AvailableUsers\n .filter((u) => u.Name.toLowerCase().includes(filter) || (u.Email && u.Email.toLowerCase().includes(filter)))\n .slice(0, 10);\n }\n\n public get HasChanges(): boolean {\n return this.UserShares.some(\n (s) => s.IsNew || s.MarkedForRemoval || s.Level !== s._InitialLevel\n );\n }\n\n public get ActiveShares(): ResourceSharePermissionModel[] {\n return this.UserShares.filter((s) => !s.MarkedForRemoval);\n }\n\n public get RemovedShares(): ResourceSharePermissionModel[] {\n return this.UserShares.filter((s) => s.MarkedForRemoval);\n }\n\n /** Highlight rows whose level has been changed from their loaded state. */\n public isModified(share: ResourceSharePermissionModel): boolean {\n return !share.IsNew && share.Level !== share._InitialLevel;\n }\n\n public async addUserShare(user: MJUserEntity): Promise<void> {\n if (!this.Context || !this.Adapter) return;\n const row = await this.Adapter.CreateShare(this.Context, user);\n row._InitialLevel = row.Level;\n this.UserShares.push(row);\n this.updateAvailableUsers();\n this.UserSearchFilter = '';\n this.cdr.detectChanges();\n }\n\n public removeUserShare(share: ResourceSharePermissionModel): void {\n if (share.IsNew) {\n this.UserShares = this.UserShares.filter((s) => s !== share);\n } else {\n share.MarkedForRemoval = true;\n }\n this.updateAvailableUsers();\n this.cdr.detectChanges();\n }\n\n public undoRemove(share: ResourceSharePermissionModel): void {\n share.MarkedForRemoval = false;\n this.updateAvailableUsers();\n this.cdr.detectChanges();\n }\n\n public setLevel(share: ResourceSharePermissionModel, level: ResourceShareLevel): void {\n share.Level = level;\n this.cdr.detectChanges();\n }\n\n public async onSave(): Promise<void> {\n if (!this.Adapter || !this.Context) return;\n if (!this.HasChanges) {\n this.onCancel();\n return;\n }\n this.IsLoading = true;\n this.Error = null;\n this.cdr.detectChanges();\n\n try {\n for (const share of this.UserShares.filter((s) => s.MarkedForRemoval && !s.IsNew)) {\n const deleted = await share.PermissionEntity.Delete();\n if (!deleted) {\n throw new Error(\n `Failed to remove share for ${share.User.Name}: ${\n share.PermissionEntity.LatestResult?.Message ?? 'unknown error'\n }`\n );\n }\n }\n\n const dirtyRows = this.UserShares.filter(\n (s) => !s.MarkedForRemoval && (s.IsNew || s.Level !== s._InitialLevel)\n );\n for (const share of dirtyRows) {\n this.Adapter.SyncLevelToEntity(share);\n const saved = await share.PermissionEntity.Save();\n if (!saved) {\n throw new Error(\n `Failed to save share for ${share.User.Name}: ${\n share.PermissionEntity.LatestResult?.Message ?? 'unknown error'\n }`\n );\n }\n }\n\n if (this.Adapter.AfterSave) {\n await this.Adapter.AfterSave(this.Context);\n }\n\n this.Result.emit({ Action: 'save' });\n } catch (error) {\n console.error('Error saving shares:', error);\n this.Error = error instanceof Error ? error.message : 'Failed to save sharing settings.';\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n public onCancel(): void {\n this.Result.emit({ Action: 'cancel' });\n }\n\n public getUserInitials(user: MJUserEntity): string {\n const name = user.Name || user.Email || '?';\n const parts = name.split(' ');\n if (parts.length >= 2) {\n return (parts[0][0] + parts[1][0]).toUpperCase();\n }\n return name.substring(0, 2).toUpperCase();\n }\n}\n","@if (Visible) {\n <mj-window\n [Visible]=\"true\"\n [Width]=\"560\"\n [MinHeight]=\"200\"\n [Resizable]=\"false\"\n [Draggable]=\"true\"\n (Close)=\"onCancel()\"\n class=\"mj-share-dialog-window\">\n <mj-window-titlebar>\n <div class=\"share-dialog-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>Share \"{{ Context?.ResourceName }}\"</span>\n </div>\n </mj-window-titlebar>\n <div class=\"share-dialog-body\">\n @if (Error) {\n <mj-alert Variant=\"error\">{{ Error }}</mj-alert>\n }\n <!-- Add Users Section -->\n <div class=\"share-section\">\n <div class=\"share-search-box\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n type=\"text\"\n placeholder=\"Add people by name or email...\"\n [(ngModel)]=\"UserSearchFilter\"\n [disabled]=\"IsLoading\">\n </div>\n @if (FilteredAvailableUsers.length > 0) {\n <div class=\"share-user-dropdown\">\n @for (user of FilteredAvailableUsers; track user.ID) {\n <button type=\"button\" class=\"share-user-option\" (click)=\"addUserShare(user)\" [disabled]=\"IsLoading\">\n <span class=\"share-avatar\">{{ getUserInitials(user) }}</span>\n <span class=\"share-user-name\">{{ user.Name }}</span>\n @if (user.Email) {\n <span class=\"share-user-email\">{{ user.Email }}</span>\n }\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n }\n </div>\n }\n @if (UserSearchFilter && FilteredAvailableUsers.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-user-slash\"\n [Title]=\"NoUsersFoundMessage\"\n Size=\"compact\" />\n }\n </div>\n <!-- People with Access -->\n <div class=\"share-section\">\n <div class=\"share-section-label\">People with access</div>\n @if (Context?.OwnerDisplayName) {\n <div class=\"share-person share-owner\">\n <span class=\"share-avatar share-avatar-owner\">\n <i class=\"fa-solid fa-crown\"></i>\n </span>\n <div class=\"share-person-info\">\n <span class=\"share-person-name\">{{ Context?.OwnerDisplayName }}</span>\n <span class=\"share-person-role\">Owner</span>\n </div>\n </div>\n }\n @for (share of ActiveShares; track share.User.ID) {\n <div class=\"share-person\" [class.share-person-new]=\"share.IsNew\" [class.share-person-modified]=\"isModified(share)\">\n <span class=\"share-avatar\">{{ getUserInitials(share.User) }}</span>\n <div class=\"share-person-info\">\n <span class=\"share-person-name\">\n {{ share.User.Name }}\n @if (share.IsNew) {\n <span class=\"share-badge-new\">New</span>\n }\n </span>\n @if (share.User.Email) {\n <span class=\"share-person-email\">{{ share.User.Email }}</span>\n }\n </div>\n <div class=\"share-level-select\" role=\"group\" aria-label=\"Permission level\">\n @for (level of Levels; track level) {\n <button type=\"button\"\n class=\"share-level-btn\"\n [class.active]=\"share.Level === level\"\n (click)=\"setLevel(share, level)\"\n [title]=\"level + ' access'\">\n {{ level }}\n </button>\n }\n </div>\n <button type=\"button\" class=\"share-remove-btn\" (click)=\"removeUserShare(share)\" title=\"Remove\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n @if (ActiveShares.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-user-lock\"\n Title=\"Not shared with anyone yet\"\n Size=\"compact\" />\n }\n @if (RemovedShares.length > 0) {\n <div class=\"share-removed-section\">\n @for (share of RemovedShares; track share.User.ID) {\n <div class=\"share-removed-item\">\n <span class=\"share-avatar share-avatar-removed\">{{ getUserInitials(share.User) }}</span>\n <span class=\"share-removed-name\">{{ share.User.Name }}</span>\n <button type=\"button\" class=\"share-undo-btn\" (click)=\"undoRemove(share)\">\n <i class=\"fa-solid fa-undo\"></i> Undo\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"share-footer\">\n @if (HasChanges) {\n <span class=\"share-changes-hint\">\n <i class=\"fa-solid fa-circle\"></i> Unsaved changes\n </span>\n }\n <div class=\"share-footer-actions\">\n <button type=\"button\" class=\"share-btn share-btn-secondary\" (click)=\"onCancel()\">\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"share-btn share-btn-primary\"\n (click)=\"onSave()\"\n [disabled]=\"!HasChanges || IsLoading\">\n @if (IsLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n Save\n }\n </button>\n </div>\n </div>\n </div>\n </mj-window>\n}\n"]}
1
+ {"version":3,"file":"resource-share-dialog.component.js","sourceRoot":"","sources":["../../src/lib/resource-share-dialog.component.ts","../../src/lib/resource-share-dialog.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAA+C,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvI,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EACH,qBAAqB,EAMxB,MAAM,0BAA0B,CAAC;;;;;;;ICK1B,mCAA0B;IAAA,YAAW;IAAA,iBAAW;;;IAAtB,cAAW;IAAX,kCAAW;;;IAGrC,8BAA0B;IACxB,wBAAuC;IACvC,4BAAM;IAAA,YAAY;IACpB,AADoB,iBAAO,EACrB;;;IADE,eAAY;IAAZ,mCAAY;;;IAoBV,gCAA+B;IAAA,YAAgB;IAAA,iBAAO;;;IAAvB,cAAgB;IAAhB,mCAAgB;;;;IAJnD,kCAAoG;IAApD,+OAAS,4BAAkB,KAAC;IAC1E,gCAA2B;IAAA,YAA2B;IAAA,iBAAO;IAC7D,gCAA8B;IAAA,YAAe;IAAA,iBAAO;IACpD,kIAAkB;IAGlB,wBAAgC;IAClC,iBAAS;;;;IAPoE,2CAAsB;IACtE,eAA2B;IAA3B,qDAA2B;IACxB,eAAe;IAAf,kCAAe;IAC7C,cAEC;IAFD,wCAEC;;;IAPP,+BAAiC;IAC/B,+HASC;IACH,iBAAM;;;IAVJ,cASC;IATD,4CASC;;;IAIH,qCAImB;;;IADjB,kDAA6B;;;IAS7B,AADF,+BAAsC,eACU;IAC5C,wBAAiC;IACnC,iBAAO;IAEL,AADF,+BAA+B,eACG;IAAA,YAAsC;IAAA,iBAAO;IAC7E,gCAAgC;IAAA,qBAAK;IAEzC,AADE,AADuC,iBAAO,EACxC,EACF;;;IAH8B,eAAsC;IAAtC,mGAAsC;;;IAYlE,gCAA8B;IAAA,mBAAG;IAAA,iBAAO;;;IAI1C,gCAAiC;IAAA,YAAsB;IAAA,iBAAO;;;IAA7B,cAAsB;IAAtB,yCAAsB;;;IAGvD,gCAAiC;IAAA,YAAuB;IAAA,iBAAO;;;;IAA9B,cAAuB;IAAvB,iDAAuB;;;;IAKxD,kCAIoC;IAD5B,wRAAS,mCAAsB,KAAC;IAEtC,YACF;IAAA,iBAAS;;;;;IAJD,kEAA4C;IAE5C,4CAA2B;IACjC,cACF;IADE,yCACF;;;;IAvBJ,AADF,+BAAmH,eACtF;IAAA,YAAiC;IAAA,iBAAO;IAEjE,AADF,+BAA+B,eACG;IAC9B,YACA;IAAA,oHAAmB;IAGrB,iBAAO;IACP,oHAAwB;IAGxB,oHAAyB;IAG3B,iBAAM;IACN,+BAA2E;IACzE,2IAQC;IACH,iBAAM;IACN,mCAA+F;IAAhD,mOAAS,gCAAsB,KAAC;IAC7E,yBAAiC;IAErC,AADE,iBAAS,EACL;;;;IA9B2D,AAAvC,kDAAsC,sDAAkD;IACrF,eAAiC;IAAjC,2DAAiC;IAGxD,eACA;IADA,mDACA;IAAA,cAEC;IAFD,yCAEC;IAEH,cAEC;IAFD,8CAEC;IACD,cAEC;IAFD,sDAEC;IAGD,eAQC;IARD,4BAQC;;;IAQL,qCAGmB;;;;IAMb,AADF,+BAAgC,eACkB;IAAA,YAAiC;IAAA,iBAAO;IACxF,gCAAiC;IAAA,YAAqB;IAAA,iBAAO;IAC7D,kCAAyE;IAA5B,iPAAS,4BAAiB,KAAC;IACtE,wBAAgC;IAAC,sBACnC;IACF,AADE,iBAAS,EACL;;;;IAL4C,eAAiC;IAAjC,4DAAiC;IAChD,eAAqB;IAArB,yCAAqB;;;IAJ5D,+BAAmC;IACjC,4HAQC;IACH,iBAAM;;;IATJ,cAQC;IARD,mCAQC;;;IAMH,gCAAiC;IAC/B,wBAAkC;IAAC,iCACrC;IAAA,iBAAO;;;IAYH,wBAA2C;IAAC,2BAC9C;;;IACE,sBACF;;;;IA9IV,oCAOiC;IAD/B,kMAAS,iBAAU,KAAC;IAGlB,AADF,0CAAoB,aACe;IAC/B,uBAAuC;IACvC,4BAAM;IAAA,YAAW;IAErB,AADE,AADmB,iBAAO,EACpB,EACa;IACrB,8BAA+B;IAC7B,gHAAa;IAGb,2GAAc;IAQZ,AADF,8BAA2B,cACK;IAC5B,wBAAkC;IAClC,kCAIyB;IADvB,oUAA8B;IAElC,AALE,iBAIyB,EACrB;IACN,8GAAyC;IAczC,yHAA+D;IAOjE,iBAAM;IAGJ,AADF,+BAA2B,eACQ;IAAA,mCAAkB;IAAA,iBAAM;IACzD,8GAAwC;IAWxC,gHAgCC;IACD,yHAAiC;IAMjC,8GAAgC;IAalC,iBAAM;IACN,gCAA0B;IACxB,+GAAkB;IAMhB,AADF,gCAAkC,kBACiD;IAArB,gMAAS,iBAAU,KAAC;IAC9E,yBACF;IAAA,iBAAS;IACT,mCAIwC;IADtC,gMAAS,eAAQ,KAAC;IAIhB,AAFF,mGAAiB,6EAER;IAOnB,AADE,AADE,AADE,AADE,iBAAS,EACL,EACF,EACF,EACI;;;IA9IV,AADA,AADA,AADA,AADA,8BAAgB,cACH,kBACI,oBACE,mBACD;IAMR,eAAW;IAAX,kCAAW;IAInB,eAEC;IAFD,uCAEC;IACD,cAKC;IALD,wCAKC;IAQK,eAA8B;IAA9B,uDAA8B;IAC9B,2CAAsB;IAE1B,cAaC;IAbD,oEAaC;IACD,cAMC;IAND,iGAMC;IAKD,eAUC;IAVD,2GAUC;IACD,cAgCC;IAhCD,kCAgCC;IACD,eAKC;IALD,4DAKC;IACD,cAYC;IAZD,2DAYC;IAGD,eAIC;IAJD,6CAIC;IASG,eAAqC;IAArC,iEAAqC;IACrC,cAIC;IAJD,4CAIC;;AD1Hb;;;;;GAKG;AAQH,MAAM,OAAO,2BAA4B,SAAQ,oBAAoB;IA8C7C;IA7CX,OAAO,GAAG,KAAK,CAAC;IACzB,6EAA6E;IACpE,OAAO,GAAgC,IAAI,CAAC;IACrD,+EAA+E;IACtE,QAAQ,GAAkC,IAAI,CAAC;IAC/C,OAAO,GAAgC,IAAI,CAAC;IACrD,4EAA4E;IACnE,aAAa,GAAG,MAAM,CAAC;IAChC,iFAAiF;IACxE,MAAM,GAAkB,IAAI,CAAC;IAC5B,MAAM,GAAG,IAAI,YAAY,EAA6B,CAAC;IAEjD,MAAM,GAAG,qBAAqB,CAAC;IAExC,MAAM,GAAyB,EAAE,CAAC;IAClC,cAAc,GAAmB,EAAE,CAAC;IACnC,QAAQ,GAAmB,EAAE,CAAC;IAE/B,SAAS,GAAG,KAAK,CAAC;IAClB,KAAK,GAAkB,IAAI,CAAC;IAC5B,gBAAgB,GAAG,EAAE,CAAC;IAE7B,kDAAkD;IAClD,IAAW,cAAc;QACrB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC;QACpE,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,qFAAqF;IACrF,IAAW,cAAc;QACrB,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;QACrC,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtD,CAAC;IAED,IAAW,KAAK;QACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;QACrC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,UAAU,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC;QACxE,OAAO,SAAS,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,aAAa,GAAG,CAAC;IAC7D,CAAC;IAED,+EAA+E;IAC/E,IAAW,mBAAmB;QAC1B,OAAO,4BAA4B,IAAI,CAAC,gBAAgB,GAAG,CAAC;IAChE,CAAC;IAED,YAAoB,GAAsB;QACtC,KAAK,EAAE,CAAC;QADQ,QAAG,GAAH,GAAG,CAAmB;IAC9B,CAAC;IAEb,WAAW,CAAC,OAAsB;QAC9B,IAAI,OAAO,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACvF,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC;IACL,CAAC;IAEO,WAAW;QACf,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;IAC/B,CAAC;IAED,qFAAqF;IAC9E,KAAK,CAAC,MAAM;QACf,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;QACrC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAEnD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAEzB,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;YACvB,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,OAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC5F,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YAC1D,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;YAClD,IAAI,CAAC,KAAK,GAAG,gDAAgD,CAAC;QAClE,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC7B,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,SAAS;QACnB,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC5D,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,OAAO,CAAe;YAC/C,UAAU,EAAE,WAAW;YACvB,WAAW,EAAE,cAAc;YAC3B,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,eAAe;SAC9B,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,CAAC;IAED,8EAA8E;IACtE,eAAe,CACnB,QAAgC,EAChC,WAA6C;QAE7C,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8B,CAAC;QAErD,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAChC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC;YAC9C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACrB,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC;gBAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;oBAC7B,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,IAAI,EAAE,IAAI,GAAG,EAAwC;oBACrD,YAAY,EAAE,GAAG,CAAC,KAAK;oBACvB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,YAAY,EAAE,KAAK;oBACnB,KAAK,EAAE,KAAK;oBACZ,gBAAgB,EAAE,KAAK;iBAC1B,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;gBAChC,IAAI,KAAK,CAAC,YAAY,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC;oBACnC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,iCAAiC;gBAChE,CAAC;gBACD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3B,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,6EAA6E;QAC7E,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YAClC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,YAAY,IAAI,MAAM,CAAC;QAC/C,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,uFAAuF;IAC/E,oBAAoB;QACxB,MAAM,aAAa,GAAG,IAAI,GAAG,CACzB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CACvE,CAAC;QACF,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc;aAC/B,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC;aAC7B,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YAChD,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC3E,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACP,CAAC;IAED,yEAAyE;IACzE,IAAW,sBAAsB;QAC7B,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC,cAAc;aACrB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;aAC3G,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtB,CAAC;IAED,IAAW,UAAU;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC;IACpF,CAAC;IAED,IAAW,YAAY;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC1D,CAAC;IAED,IAAW,aAAa;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;IACzD,CAAC;IAED,6EAA6E;IACtE,UAAU,CAAC,KAAyB;QACvC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,YAAY,CAAC;IAC9C,CAAC;IAED,0EAA0E;IACnE,aAAa,CAAC,KAAyB,EAAE,KAAyB;QACrE,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACrF,OAAO,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC;IACjC,CAAC;IAED;;;OAGG;IACI,UAAU,CAAC,KAAyB;QACvC,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5E,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,8DAA8D;IACvD,KAAK,CAAC,YAAY,CAAC,IAAkB;QACxC,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC9D,IAAI,CAAC,MAAM,GAAG;YACV,GAAG,IAAI,CAAC,MAAM;YACd;gBACI,IAAI,EAAE,IAAI;gBACV,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,IAAI,EAAE,IAAI,GAAG,EAAwC;gBACrD,YAAY,EAAE,IAAI;gBAClB,KAAK,EAAE,MAAM;gBACb,YAAY,EAAE,KAAK;gBACnB,KAAK,EAAE,IAAI;gBACX,gBAAgB,EAAE,KAAK;aAC1B;SACJ,CAAC;QACF,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC;IAEM,eAAe,CAAC,KAAyB;QAC5C,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;QACzD,CAAC;aAAM,CAAC;YACJ,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAClC,CAAC;QACD,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC;IAEM,UAAU,CAAC,KAAyB;QACvC,KAAK,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC;IAED,gFAAgF;IACzE,QAAQ,CAAC,KAAyB,EAAE,KAAyB;QAChE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;QACpB,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC;IAEM,KAAK,CAAC,MAAM;QACf,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACnD,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,OAAO;QACX,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAEzB,IAAI,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5E,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;gBAChG,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC3C,CAAC;YAED,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBACzB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC7B,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBAC1C,CAAC;YACL,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YAC7C,IAAI,CAAC,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC;QAC7F,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC7B,CAAC;IACL,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,aAAa,CAAC,KAAyB;QACjD,KAAK,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YAC/D,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC;YACpD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CACX,8BAA8B,KAAK,CAAC,IAAI,CAAC,IAAI,KACzC,GAAG,CAAC,gBAAgB,CAAC,YAAY,EAAE,eAAe,IAAI,eAC1D,EAAE,CACL,CAAC;YACN,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,UAAU,CAAC,KAAyB,EAAE,QAAgC;QAChF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC7C,IAAI,CAAC,GAAG,EAAE,CAAC;gBACP,GAAG,GAAG,MAAM,IAAI,CAAC,OAAQ,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC3D,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC;gBAC9B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAC5C,CAAC;iBAAM,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC3C,SAAS,CAAC,oCAAoC;YAClD,CAAC;YAED,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;YACxB,IAAI,CAAC,OAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC;YAChD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CACX,4BAA4B,KAAK,CAAC,IAAI,CAAC,IAAI,KACvC,GAAG,CAAC,gBAAgB,CAAC,YAAY,EAAE,eAAe,IAAI,eAC1D,EAAE,CACL,CAAC;YACN,CAAC;YACD,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;QACtB,CAAC;IACL,CAAC;IAEM,QAAQ;QACX,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3C,CAAC;IAEM,eAAe,CAAC,IAAkB;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACrD,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,CAAC;IAED,0CAA0C;IACnC,UAAU,CAAC,KAAyB;QACvC,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,4CAA4C;IACrC,KAAK,CAAC,YAAY,CAAC,IAAkB;QACxC,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,+CAA+C;IACxC,eAAe,CAAC,KAAyB;QAC5C,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,0CAA0C;IACnC,UAAU,CAAC,KAAyB;QACvC,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,wCAAwC;IACjC,QAAQ,CAAC,KAAyB,EAAE,KAAyB;QAChE,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,sCAAsC;IAC/B,KAAK,CAAC,MAAM;QACf,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;IACzB,CAAC;IAED,+CAA+C;IACxC,eAAe,CAAC,IAAkB;QACrC,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;qHAlXQ,2BAA2B;6DAA3B,2BAA2B;YClCxC,qGAAe;;YAAf,sCAqJC;;;iFDnHY,2BAA2B;cAPvC,SAAS;6BACM,KAAK,YACP,0BAA0B,iBAGrB,iBAAiB,CAAC,IAAI;;kBAGpC,KAAK;;kBAEL,KAAK;;kBAEL,KAAK;;kBACL,KAAK;;kBAEL,KAAK;;kBAEL,KAAK;;kBACL,MAAM;;kFAXE,2BAA2B","sourcesContent":["import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges, ChangeDetectorRef, ViewEncapsulation } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { RunView } from '@memberjunction/core';\nimport { MJUserEntity } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport {\n RESOURCE_SHARE_LEVELS,\n ResourceShareAdapter,\n ResourceShareContext,\n ResourceShareGrant,\n ResourceShareLevel,\n ResourceSharePermissionModel\n} from './resource-share-adapter';\n\n/**\n * Result emitted when {@link GenericShareDialogComponent} closes.\n */\nexport interface ResourceShareDialogResult {\n Action: 'save' | 'cancel';\n}\n\n/**\n * Resource-type-agnostic share dialog. Every resource's sharing UX collapses to\n * three tiers — View / Edit / Owner — so the dialog exposes a single level\n * selector per grantee rather than a grab bag of `Can*` checkboxes. Adapters\n * translate the level to whatever shape their backing entity actually persists.\n */\n@Component({\n standalone: false,\n selector: 'mj-resource-share-dialog',\n templateUrl: './resource-share-dialog.component.html',\n styleUrls: ['./resource-share-dialog.component.css'],\n encapsulation: ViewEncapsulation.None\n})\nexport class GenericShareDialogComponent extends BaseAngularComponent implements OnChanges {\n @Input() Visible = false;\n /** The single resource being shared. Ignored when `Contexts` is supplied. */\n @Input() Context: ResourceShareContext | null = null;\n /** Several resources to share at once; every action applies to all of them. */\n @Input() Contexts: ResourceShareContext[] | null = null;\n @Input() Adapter: ResourceShareAdapter | null = null;\n /** Singular noun for the title when sharing several (\"3 conversations\"). */\n @Input() ResourceLabel = 'item';\n /** Optional line shown above the dialog body — e.g. what the caller left out. */\n @Input() Notice: string | null = null;\n @Output() Result = new EventEmitter<ResourceShareDialogResult>();\n\n public readonly Levels = RESOURCE_SHARE_LEVELS;\n\n public Grants: ResourceShareGrant[] = [];\n public AvailableUsers: MJUserEntity[] = [];\n private allUsers: MJUserEntity[] = [];\n\n public IsLoading = false;\n public Error: string | null = null;\n public UserSearchFilter = '';\n\n /** Every resource this dialog is operating on. */\n public get ActiveContexts(): ResourceShareContext[] {\n if (this.Contexts && this.Contexts.length > 0) return this.Contexts;\n return this.Context ? [this.Context] : [];\n }\n\n /** The resource whose owner row is shown — only meaningful for a single resource. */\n public get PrimaryContext(): ResourceShareContext | null {\n const contexts = this.ActiveContexts;\n return contexts.length === 1 ? contexts[0] : null;\n }\n\n public get Title(): string {\n const contexts = this.ActiveContexts;\n if (contexts.length === 1) return `Share \"${contexts[0].ResourceName}\"`;\n return `Share ${contexts.length} ${this.ResourceLabel}s`;\n }\n\n /** Message for the no-results empty-state, echoing the current search term. */\n public get NoUsersFoundMessage(): string {\n return `No users found matching \"${this.UserSearchFilter}\"`;\n }\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Visible'] && this.Visible && this.ActiveContexts.length > 0 && this.Adapter) {\n this.resetDialog();\n void this.Reload();\n }\n }\n\n private resetDialog(): void {\n this.Error = null;\n this.IsLoading = false;\n this.Grants = [];\n this.AvailableUsers = [];\n this.UserSearchFilter = '';\n }\n\n /** Loads the people list and every resource's existing shares, merged per person. */\n public async Reload(): Promise<void> {\n const contexts = this.ActiveContexts;\n if (contexts.length === 0 || !this.Adapter) return;\n\n this.IsLoading = true;\n this.cdr.detectChanges();\n\n try {\n await this.loadUsers();\n const perResource = await Promise.all(contexts.map((ctx) => this.Adapter!.LoadShares(ctx)));\n this.Grants = this.mergeIntoGrants(contexts, perResource);\n this.updateAvailableUsers();\n } catch (error) {\n console.error('Error loading share data:', error);\n this.Error = 'Failed to load sharing data. Please try again.';\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n private async loadUsers(): Promise<void> {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const usersResult = await rv.RunView<MJUserEntity>({\n EntityName: 'MJ: Users',\n ExtraFilter: 'IsActive = 1',\n OrderBy: 'Name',\n ResultType: 'entity_object'\n });\n this.allUsers = usersResult.Success ? usersResult.Results : [];\n }\n\n /** One grant per person, carrying their row on each resource that has one. */\n private mergeIntoGrants(\n contexts: ResourceShareContext[],\n perResource: ResourceSharePermissionModel[][]\n ): ResourceShareGrant[] {\n const byUser = new Map<string, ResourceShareGrant>();\n\n perResource.forEach((rows, index) => {\n const resourceId = contexts[index].ResourceID;\n for (const row of rows) {\n row._InitialLevel = row.Level;\n const key = row.UserID.toLowerCase();\n const grant = byUser.get(key) ?? {\n User: row.User,\n UserID: row.UserID,\n Rows: new Map<string, ResourceSharePermissionModel>(),\n InitialLevel: row.Level,\n Level: row.Level,\n LevelTouched: false,\n IsNew: false,\n MarkedForRemoval: false\n };\n grant.Rows.set(resourceId, row);\n if (grant.InitialLevel !== row.Level) {\n grant.InitialLevel = null; // levels differ across resources\n }\n byUser.set(key, grant);\n }\n });\n\n // A person on some but not all resources has no single level to show either.\n for (const grant of byUser.values()) {\n grant.Level = grant.InitialLevel ?? 'View';\n }\n return Array.from(byUser.values());\n }\n\n /** Everyone who owns none of the resources and doesn't already hold a (live) grant. */\n private updateAvailableUsers(): void {\n const sharedUserIds = new Set(\n this.Grants.filter((g) => !g.MarkedForRemoval).map((g) => g.User.ID)\n );\n const ownerIds = this.ActiveContexts\n .map((ctx) => ctx.OwnerUserID)\n .filter((id): id is string => !!id);\n this.AvailableUsers = this.allUsers.filter((user) => {\n if (ownerIds.some((ownerId) => UUIDsEqual(user.ID, ownerId))) return false;\n return !sharedUserIds.has(user.ID);\n });\n }\n\n /** The first ten matches for the search box, or the first ten people. */\n public get FilteredAvailableUsers(): MJUserEntity[] {\n if (!this.UserSearchFilter.trim()) {\n return this.AvailableUsers.slice(0, 10);\n }\n const filter = this.UserSearchFilter.toLowerCase();\n return this.AvailableUsers\n .filter((u) => u.Name.toLowerCase().includes(filter) || (u.Email && u.Email.toLowerCase().includes(filter)))\n .slice(0, 10);\n }\n\n public get HasChanges(): boolean {\n return this.Grants.some((g) => g.IsNew || g.MarkedForRemoval || g.LevelTouched);\n }\n\n public get ActiveShares(): ResourceShareGrant[] {\n return this.Grants.filter((g) => !g.MarkedForRemoval);\n }\n\n public get RemovedShares(): ResourceShareGrant[] {\n return this.Grants.filter((g) => g.MarkedForRemoval);\n }\n\n /** Highlight grants whose level has been changed from their loaded state. */\n public IsModified(grant: ResourceShareGrant): boolean {\n return !grant.IsNew && grant.LevelTouched;\n }\n\n /** A level button lights up only when the grant has one level to show. */\n public IsLevelActive(grant: ResourceShareGrant, level: ResourceShareLevel): boolean {\n if (!grant.LevelTouched && grant.InitialLevel === null && !grant.IsNew) return false;\n return grant.Level === level;\n }\n\n /**\n * Why a grant does not simply read as \"everyone, one level\": levels that\n * differ across resources, or access held on only some of them.\n */\n public ScopeLabel(grant: ResourceShareGrant): string {\n if (grant.IsNew || this.ActiveContexts.length < 2) return '';\n const parts: string[] = [];\n if (!grant.LevelTouched && grant.InitialLevel === null) parts.push('Mixed');\n if (grant.Rows.size < this.ActiveContexts.length) {\n parts.push(`${grant.Rows.size} of ${this.ActiveContexts.length}`);\n }\n return parts.join(' · ');\n }\n\n /** Adds a person, to every resource the dialog is sharing. */\n public async AddUserShare(user: MJUserEntity): Promise<void> {\n if (this.ActiveContexts.length === 0 || !this.Adapter) return;\n this.Grants = [\n ...this.Grants,\n {\n User: user,\n UserID: user.ID,\n Rows: new Map<string, ResourceSharePermissionModel>(),\n InitialLevel: null,\n Level: 'View',\n LevelTouched: false,\n IsNew: true,\n MarkedForRemoval: false\n }\n ];\n this.updateAvailableUsers();\n this.UserSearchFilter = '';\n this.cdr.detectChanges();\n }\n\n public RemoveUserShare(grant: ResourceShareGrant): void {\n if (grant.IsNew) {\n this.Grants = this.Grants.filter((g) => g !== grant);\n } else {\n grant.MarkedForRemoval = true;\n }\n this.updateAvailableUsers();\n this.cdr.detectChanges();\n }\n\n public UndoRemove(grant: ResourceShareGrant): void {\n grant.MarkedForRemoval = false;\n this.updateAvailableUsers();\n this.cdr.detectChanges();\n }\n\n /** Sets one level for the person across every resource, filling in any gaps. */\n public SetLevel(grant: ResourceShareGrant, level: ResourceShareLevel): void {\n grant.Level = level;\n grant.LevelTouched = true;\n this.cdr.detectChanges();\n }\n\n public async OnSave(): Promise<void> {\n const contexts = this.ActiveContexts;\n if (!this.Adapter || contexts.length === 0) return;\n if (!this.HasChanges) {\n this.onCancel();\n return;\n }\n this.IsLoading = true;\n this.Error = null;\n this.cdr.detectChanges();\n\n try {\n for (const grant of this.Grants.filter((g) => g.MarkedForRemoval && !g.IsNew)) {\n await this.withdrawGrant(grant);\n }\n for (const grant of this.Grants.filter((g) => !g.MarkedForRemoval && (g.IsNew || g.LevelTouched))) {\n await this.applyGrant(grant, contexts);\n }\n\n if (this.Adapter.AfterSave) {\n for (const context of contexts) {\n await this.Adapter.AfterSave(context);\n }\n }\n\n this.Result.emit({ Action: 'save' });\n } catch (error) {\n console.error('Error saving shares:', error);\n this.Error = error instanceof Error ? error.message : 'Failed to save sharing settings.';\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Withdraws a person's access from every resource that granted it. Each row\n * leaves the grant once deleted, so a retry after a failure deletes only the\n * rows still left.\n */\n private async withdrawGrant(grant: ResourceShareGrant): Promise<void> {\n for (const [resourceId, row] of Array.from(grant.Rows.entries())) {\n const deleted = await row.PermissionEntity.Delete();\n if (!deleted) {\n throw new Error(\n `Failed to remove share for ${grant.User.Name}: ${\n row.PermissionEntity.LatestResult?.CompleteMessage ?? 'unknown error'\n }`\n );\n }\n grant.Rows.delete(resourceId);\n }\n }\n\n /**\n * Writes the grant's level to every resource, creating a permission row for\n * the ones this person did not already have access to. A row stays `IsNew`\n * until it saves, so a retry after a failure saves the rows still unsaved.\n */\n private async applyGrant(grant: ResourceShareGrant, contexts: ResourceShareContext[]): Promise<void> {\n for (const context of contexts) {\n let row = grant.Rows.get(context.ResourceID);\n if (!row) {\n row = await this.Adapter!.CreateShare(context, grant.User);\n row._InitialLevel = row.Level;\n grant.Rows.set(context.ResourceID, row);\n } else if (!grant.LevelTouched && !row.IsNew) {\n continue; // nothing changed for this resource\n }\n\n row.Level = grant.Level;\n this.Adapter!.SyncLevelToEntity(row);\n const saved = await row.PermissionEntity.Save();\n if (!saved) {\n throw new Error(\n `Failed to save share for ${grant.User.Name}: ${\n row.PermissionEntity.LatestResult?.CompleteMessage ?? 'unknown error'\n }`\n );\n }\n row.IsNew = false;\n }\n }\n\n public onCancel(): void {\n this.Result.emit({ Action: 'cancel' });\n }\n\n public GetUserInitials(user: MJUserEntity): string {\n const name = user.Name || user.Email || '?';\n const parts = name.split(' ');\n if (parts.length >= 2) {\n return (parts[0][0] + parts[1][0]).toUpperCase();\n }\n return name.substring(0, 2).toUpperCase();\n }\n\n /** @deprecated Use {@link IsModified}. */\n public isModified(grant: ResourceShareGrant): boolean {\n return this.IsModified(grant);\n }\n\n /** @deprecated Use {@link AddUserShare}. */\n public async addUserShare(user: MJUserEntity): Promise<void> {\n return this.AddUserShare(user);\n }\n\n /** @deprecated Use {@link RemoveUserShare}. */\n public removeUserShare(grant: ResourceShareGrant): void {\n return this.RemoveUserShare(grant);\n }\n\n /** @deprecated Use {@link UndoRemove}. */\n public undoRemove(grant: ResourceShareGrant): void {\n return this.UndoRemove(grant);\n }\n\n /** @deprecated Use {@link SetLevel}. */\n public setLevel(grant: ResourceShareGrant, level: ResourceShareLevel): void {\n return this.SetLevel(grant, level);\n }\n\n /** @deprecated Use {@link OnSave}. */\n public async onSave(): Promise<void> {\n return this.OnSave();\n }\n\n /** @deprecated Use {@link GetUserInitials}. */\n public getUserInitials(user: MJUserEntity): string {\n return this.GetUserInitials(user);\n }\n}\n","@if (Visible) {\n <mj-window\n [Visible]=\"true\"\n [Width]=\"560\"\n [MinHeight]=\"200\"\n [Resizable]=\"false\"\n [Draggable]=\"true\"\n (Close)=\"onCancel()\"\n class=\"mj-share-dialog-window\">\n <mj-window-titlebar>\n <div class=\"share-dialog-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>{{ Title }}</span>\n </div>\n </mj-window-titlebar>\n <div class=\"share-dialog-body\">\n @if (Error) {\n <mj-alert Variant=\"error\">{{ Error }}</mj-alert>\n }\n @if (Notice) {\n <div class=\"share-notice\">\n <i class=\"fa-solid fa-circle-info\"></i>\n <span>{{ Notice }}</span>\n </div>\n }\n <!-- Add Users Section -->\n <div class=\"share-section\">\n <div class=\"share-search-box\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n type=\"text\"\n placeholder=\"Add people by name or email...\"\n [(ngModel)]=\"UserSearchFilter\"\n [disabled]=\"IsLoading\">\n </div>\n @if (FilteredAvailableUsers.length > 0) {\n <div class=\"share-user-dropdown\">\n @for (user of FilteredAvailableUsers; track user.ID) {\n <button type=\"button\" class=\"share-user-option\" (click)=\"AddUserShare(user)\" [disabled]=\"IsLoading\">\n <span class=\"share-avatar\">{{ GetUserInitials(user) }}</span>\n <span class=\"share-user-name\">{{ user.Name }}</span>\n @if (user.Email) {\n <span class=\"share-user-email\">{{ user.Email }}</span>\n }\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n }\n </div>\n }\n @if (UserSearchFilter && FilteredAvailableUsers.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-user-slash\"\n [Title]=\"NoUsersFoundMessage\"\n Size=\"compact\" />\n }\n </div>\n <!-- People with Access -->\n <div class=\"share-section\">\n <div class=\"share-section-label\">People with access</div>\n @if (PrimaryContext?.OwnerDisplayName) {\n <div class=\"share-person share-owner\">\n <span class=\"share-avatar share-avatar-owner\">\n <i class=\"fa-solid fa-crown\"></i>\n </span>\n <div class=\"share-person-info\">\n <span class=\"share-person-name\">{{ PrimaryContext?.OwnerDisplayName }}</span>\n <span class=\"share-person-role\">Owner</span>\n </div>\n </div>\n }\n @for (share of ActiveShares; track share.User.ID) {\n <div class=\"share-person\" [class.share-person-new]=\"share.IsNew\" [class.share-person-modified]=\"IsModified(share)\">\n <span class=\"share-avatar\">{{ GetUserInitials(share.User) }}</span>\n <div class=\"share-person-info\">\n <span class=\"share-person-name\">\n {{ share.User.Name }}\n @if (share.IsNew) {\n <span class=\"share-badge-new\">New</span>\n }\n </span>\n @if (share.User.Email) {\n <span class=\"share-person-email\">{{ share.User.Email }}</span>\n }\n @if (ScopeLabel(share)) {\n <span class=\"share-person-scope\">{{ ScopeLabel(share) }}</span>\n }\n </div>\n <div class=\"share-level-select\" role=\"group\" aria-label=\"Permission level\">\n @for (level of Levels; track level) {\n <button type=\"button\"\n class=\"share-level-btn\"\n [class.active]=\"IsLevelActive(share, level)\"\n (click)=\"SetLevel(share, level)\"\n [title]=\"level + ' access'\">\n {{ level }}\n </button>\n }\n </div>\n <button type=\"button\" class=\"share-remove-btn\" (click)=\"RemoveUserShare(share)\" title=\"Remove\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n @if (ActiveShares.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-user-lock\"\n Title=\"Not shared with anyone yet\"\n Size=\"compact\" />\n }\n @if (RemovedShares.length > 0) {\n <div class=\"share-removed-section\">\n @for (share of RemovedShares; track share.User.ID) {\n <div class=\"share-removed-item\">\n <span class=\"share-avatar share-avatar-removed\">{{ GetUserInitials(share.User) }}</span>\n <span class=\"share-removed-name\">{{ share.User.Name }}</span>\n <button type=\"button\" class=\"share-undo-btn\" (click)=\"UndoRemove(share)\">\n <i class=\"fa-solid fa-undo\"></i> Undo\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"share-footer\">\n @if (HasChanges) {\n <span class=\"share-changes-hint\">\n <i class=\"fa-solid fa-circle\"></i> Unsaved changes\n </span>\n }\n <div class=\"share-footer-actions\">\n <button type=\"button\" class=\"share-btn share-btn-secondary\" (click)=\"onCancel()\">\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"share-btn share-btn-primary\"\n (click)=\"OnSave()\"\n [disabled]=\"!HasChanges || IsLoading\">\n @if (IsLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n Save\n }\n </button>\n </div>\n </div>\n </div>\n </mj-window>\n}\n"]}
@@ -10,11 +10,40 @@ export type SharingCenterTab = 'shared-with-me' | 'shared-by-me';
10
10
  * around the same shape.
11
11
  */
12
12
  export interface SharingCenterDomainGroup {
13
+ /**
14
+ * The permission domain's identity: a LOOKUP KEY that drives Revoke resolution,
15
+ * audit-entity mapping, and icon selection in PermissionEngine. Never renamed.
16
+ */
13
17
  DomainName: string;
18
+ /**
19
+ * Business-friendly heading shown to the user (see `GetSharingDomainDisplayLabel`). Optional so
20
+ * consumers that build this shape themselves keep compiling; the template falls back to `DomainName`.
21
+ */
22
+ Label?: string;
14
23
  Icon: string;
15
24
  Rows: NormalizedPermission[];
16
25
  Expanded: boolean;
17
26
  }
27
+ /**
28
+ * Display-only friendly headings for the built-in permission domains, used purely for
29
+ * the Sharing Center section labels. The underlying `DomainName` is a LOOKUP KEY (it
30
+ * drives Revoke resolution, audit-entity mapping, and icon selection in PermissionEngine)
31
+ * and MUST NOT be renamed. This map translates only what the user *reads*, never what
32
+ * the code *matches on*.
33
+ */
34
+ export declare const SharingDomainDisplayLabels: Record<string, string>;
35
+ /**
36
+ * Orders Sharing Center groups by the heading the user reads (`Label`), falling back to
37
+ * `DomainName`. Sorting by `DomainName` put "Rules" (from "Access Control Rules") first once the
38
+ * headings were relabeled. Display order only; `DomainName` stays the lookup key.
39
+ */
40
+ export declare function CompareSharingDomainGroups(a: SharingCenterDomainGroup, b: SharingCenterDomainGroup): number;
41
+ /**
42
+ * Returns a business-friendly heading for a permission domain. Falls back to the domain
43
+ * name with a trailing " Permissions" stripped (so an unmapped custom domain like
44
+ * "Widget Permissions" reads as "Widget"), then to the raw domain name.
45
+ */
46
+ export declare function GetSharingDomainDisplayLabel(domainName: string): string;
18
47
  /**
19
48
  * Default domain → entity-name mapping used by the Sharing Center to load and
20
49
  * delete the underlying permission record on Revoke. Apps with custom permission
@@ -1 +1 @@
1
- {"version":3,"file":"user-sharing-center.component.d.ts","sourceRoot":"","sources":["../../src/lib/user-sharing-center.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,YAAY,EAEZ,MAAM,EAGT,MAAM,eAAe,CAAC;AAEvB,OAAO,EAIH,oBAAoB,EACpB,gBAAgB,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AAErE,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAEjE;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,GAAI,YAAY,MAAM,KAAG,MAAM,GAAG,IAe1E,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAQa,0BAA2B,SAAQ,oBAAqB,YAAW,MAAM;IAClF,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2B;IAIzD,4EAA4E;IACnE,SAAS,EAAE,gBAAgB,CAAoB;IAExD;;;OAGG;IACM,eAAe,UAAQ;IAEhC,yDAAyD;IAChD,kBAAkB,SAAmB;IAE9C;;;;OAIG;IACM,qBAAqB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAgC;IAIrG,+CAA+C;IACrC,eAAe,iCAAwC;IAEjE,+DAA+D;IACrD,eAAe,qCAA4C;IAErE,8FAA8F;IACpF,cAAc,qBAA4B;IAEpD,8DAA8D;IACpD,iBAAiB,qCAA4C;IAEvE,iFAAiF;IACvE,aAAa,uBAA8B;IAIrD,YAAY,EAAE,wBAAwB,EAAE,CAAM;IAC9C,UAAU,EAAE,wBAAwB,EAAE,CAAM;IAE5C,eAAe,UAAS;IACxB,aAAa,UAAS;IAEtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE7B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B,+DAA+D;IAClD,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5D,8CAA8C;IACjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAYrC,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD,UAAU,CAAC,GAAG,EAAE,oBAAoB,GAAG,IAAI;IAI3C,OAAO,IAAI,IAAI;IAIT,QAAQ,CAAC,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCtE;;;OAGG;IACH,qBAAqB,CAAC,KAAK,EAAE,wBAAwB,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IAK/E,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM;IAIjD,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,wBAAwB,GAAG,MAAM;IAIhE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,oBAAoB,GAAG,MAAM;YAM3C,OAAO;YAYP,gBAAgB;YAiBhB,cAAc;IAiB5B,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,aAAa;yCA/NZ,0BAA0B;2CAA1B,0BAA0B;CAsPtC"}
1
+ {"version":3,"file":"user-sharing-center.component.d.ts","sourceRoot":"","sources":["../../src/lib/user-sharing-center.component.ts"],"names":[],"mappings":"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"}
@@ -48,7 +48,7 @@ function UserSharingCenterComponent_Conditional_11_Conditional_2_For_1_ng_templa
48
48
  i0.ɵɵadvance();
49
49
  i0.ɵɵclassMap(group_r4.Icon);
50
50
  i0.ɵɵadvance(2);
51
- i0.ɵɵtextInterpolate(group_r4.DomainName);
51
+ i0.ɵɵtextInterpolate(group_r4.Label ?? group_r4.DomainName);
52
52
  i0.ɵɵadvance(2);
53
53
  i0.ɵɵtextInterpolate(group_r4.Rows.length);
54
54
  } }
@@ -144,7 +144,7 @@ function UserSharingCenterComponent_Conditional_12_Conditional_2_For_1_ng_templa
144
144
  i0.ɵɵadvance();
145
145
  i0.ɵɵclassMap(group_r8.Icon);
146
146
  i0.ɵɵadvance(2);
147
- i0.ɵɵtextInterpolate(group_r8.DomainName);
147
+ i0.ɵɵtextInterpolate(group_r8.Label ?? group_r8.DomainName);
148
148
  i0.ɵɵadvance(2);
149
149
  i0.ɵɵtextInterpolate(group_r8.Rows.length);
150
150
  } }
@@ -223,6 +223,51 @@ function UserSharingCenterComponent_Conditional_12_Template(rf, ctx) { if (rf &
223
223
  const ctx_r1 = i0.ɵɵnextContext();
224
224
  i0.ɵɵconditional(ctx_r1.IsLoadingByMe ? 0 : ctx_r1.SharedByMe.length === 0 ? 1 : 2);
225
225
  } }
226
+ /**
227
+ * Display-only friendly headings for the built-in permission domains, used purely for
228
+ * the Sharing Center section labels. The underlying `DomainName` is a LOOKUP KEY (it
229
+ * drives Revoke resolution, audit-entity mapping, and icon selection in PermissionEngine)
230
+ * and MUST NOT be renamed. This map translates only what the user *reads*, never what
231
+ * the code *matches on*.
232
+ */
233
+ export const SharingDomainDisplayLabels = {
234
+ 'Dashboard Permissions': 'Dashboards',
235
+ 'Artifact Permissions': 'Artifacts',
236
+ 'Collection Permissions': 'Collections',
237
+ 'Access Control Rules': 'Rules',
238
+ 'Resource Permissions': 'Shared Items',
239
+ };
240
+ /**
241
+ * Orders Sharing Center groups by the heading the user reads (`Label`), falling back to
242
+ * `DomainName`. Sorting by `DomainName` put "Rules" (from "Access Control Rules") first once the
243
+ * headings were relabeled. Display order only; `DomainName` stays the lookup key.
244
+ */
245
+ export function CompareSharingDomainGroups(a, b) {
246
+ return (a.Label ?? a.DomainName).localeCompare(b.Label ?? b.DomainName);
247
+ }
248
+ /**
249
+ * Returns a business-friendly heading for a permission domain. Falls back to the domain
250
+ * name with a trailing " Permissions" stripped (so an unmapped custom domain like
251
+ * "Widget Permissions" reads as "Widget"), then to the raw domain name.
252
+ */
253
+ export function GetSharingDomainDisplayLabel(domainName) {
254
+ const trimmed = domainName.trim();
255
+ // Own-property check, not a bare index: DomainName is user-authored for custom domains, and a
256
+ // plain object lookup would return inherited Object.prototype members for names like "constructor".
257
+ if (Object.prototype.hasOwnProperty.call(SharingDomainDisplayLabels, trimmed)) {
258
+ return SharingDomainDisplayLabels[trimmed];
259
+ }
260
+ // Plain string ops rather than /\s+Permissions$/i: a whitespace run before an anchored
261
+ // literal backtracks quadratically on adversarial input (CodeQL js/polynomial-redos).
262
+ const suffix = ' permissions';
263
+ if (trimmed.toLowerCase().endsWith(suffix)) {
264
+ const stripped = trimmed.slice(0, -suffix.length).trimEnd();
265
+ if (stripped) {
266
+ return stripped;
267
+ }
268
+ }
269
+ return trimmed || domainName;
270
+ }
226
271
  /**
227
272
  * Default domain → entity-name mapping used by the Sharing Center to load and
228
273
  * delete the underlying permission record on Revoke. Apps with custom permission
@@ -452,12 +497,13 @@ export class UserSharingCenterComponent extends BaseAngularComponent {
452
497
  for (const [domainName, list] of bucket) {
453
498
  groups.push({
454
499
  DomainName: domainName,
500
+ Label: GetSharingDomainDisplayLabel(domainName),
455
501
  Icon: PermissionEngine.DomainIconFor(domainName),
456
502
  Rows: list.sort((a, b) => (a.ResourceName ?? '').localeCompare(b.ResourceName ?? '')),
457
503
  Expanded: list.length <= 10,
458
504
  });
459
505
  }
460
- return groups.sort((a, b) => a.DomainName.localeCompare(b.DomainName));
506
+ return groups.sort(CompareSharingDomainGroups);
461
507
  }
462
508
  setError(message) {
463
509
  this.ErrorMessage = message;
@@ -519,7 +565,7 @@ export class UserSharingCenterComponent extends BaseAngularComponent {
519
565
  }
520
566
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserSharingCenterComponent, [{
521
567
  type: Component,
522
- args: [{ standalone: true, selector: 'mj-user-sharing-center', imports: [CommonModule, MJEmptyStateComponent, MJAccordionModule], 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 <mj-empty-state class=\"empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"Nothing has been shared directly with you yet.\" />\n } @else {\n @for (group of SharedWithMe; track TrackByDomain($index, group)) {\n <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n [Expanded]=\"group.Expanded\"\n (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n <ng-template mjAccordionTitle>\n <span class=\"group-icon\"><i [class]=\"group.Icon\"></i></span>\n <span class=\"group-name\">{{ group.DomainName }}</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ group.Rows.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\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 </ng-template>\n </mj-accordion-panel>\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 <mj-empty-state class=\"empty\" Size=\"compact\"\n Icon=\"fa-solid fa-paper-plane\"\n Title=\"You haven't shared anything with others yet.\" />\n } @else {\n @for (group of SharedByMe; track TrackByDomain($index, group)) {\n <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n [Expanded]=\"group.Expanded\"\n (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n <ng-template mjAccordionTitle>\n <span class=\"group-icon\"><i [class]=\"group.Icon\"></i></span>\n <span class=\"group-name\">{{ group.DomainName }}</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ group.Rows.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\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 </ng-template>\n </mj-accordion-panel>\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/* Domain groups are now rendered with <mj-accordion-panel>, which owns the panel\n chrome (border, hover, chevron) and the disclosure toggle. The former\n .group / .group-header / .chevron rules were removed as dead. The title-slot\n icon + name + count styles below remain \u2014 they style content projected into\n <ng-template mjAccordionTitle>. */\n.group-icon i {\n color: var(--mj-brand-primary);\n width: 18px;\n text-align: center;\n}\n\n.group-name {\n flex: 1;\n}\n\n/* .count removed \u2014 replaced by the standard .mj-accordion-badge--right. */\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"] }]
568
+ args: [{ standalone: true, selector: 'mj-user-sharing-center', imports: [CommonModule, MJEmptyStateComponent, MJAccordionModule], 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 <mj-empty-state class=\"empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"Nothing has been shared directly with you yet.\" />\n } @else {\n @for (group of SharedWithMe; track TrackByDomain($index, group)) {\n <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n [Expanded]=\"group.Expanded\"\n (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n <ng-template mjAccordionTitle>\n <span class=\"group-icon\"><i [class]=\"group.Icon\"></i></span>\n <span class=\"group-name\">{{ group.Label ?? group.DomainName }}</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ group.Rows.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\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 </ng-template>\n </mj-accordion-panel>\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 <mj-empty-state class=\"empty\" Size=\"compact\"\n Icon=\"fa-solid fa-paper-plane\"\n Title=\"You haven't shared anything with others yet.\" />\n } @else {\n @for (group of SharedByMe; track TrackByDomain($index, group)) {\n <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n [Expanded]=\"group.Expanded\"\n (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n <ng-template mjAccordionTitle>\n <span class=\"group-icon\"><i [class]=\"group.Icon\"></i></span>\n <span class=\"group-name\">{{ group.Label ?? group.DomainName }}</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ group.Rows.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\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 </ng-template>\n </mj-accordion-panel>\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/* Domain groups are now rendered with <mj-accordion-panel>, which owns the panel\n chrome (border, hover, chevron) and the disclosure toggle. The former\n .group / .group-header / .chevron rules were removed as dead. The title-slot\n icon + name + count styles below remain \u2014 they style content projected into\n <ng-template mjAccordionTitle>. */\n.group-icon i {\n color: var(--mj-brand-primary);\n width: 18px;\n text-align: center;\n}\n\n.group-name {\n flex: 1;\n}\n\n/* .count removed \u2014 replaced by the standard .mj-accordion-badge--right. */\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"] }]
523
569
  }], null, { ActiveTab: [{
524
570
  type: Input
525
571
  }], ShowCloseButton: [{
@@ -539,5 +585,5 @@ export class UserSharingCenterComponent extends BaseAngularComponent {
539
585
  }], ErrorOccurred: [{
540
586
  type: Output
541
587
  }] }); })();
542
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserSharingCenterComponent, { className: "UserSharingCenterComponent", filePath: "src/lib/user-sharing-center.component.ts", lineNumber: 95 }); })();
588
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserSharingCenterComponent, { className: "UserSharingCenterComponent", filePath: "src/lib/user-sharing-center.component.ts", lineNumber: 152 }); })();
543
589
  //# sourceMappingURL=user-sharing-center.component.js.map
@@ -1 +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 NormalizedPermission,\n PermissionAction,\n} from '@memberjunction/core';\nimport { PermissionEngine } from '@memberjunction/core-entities';\nimport { MJAccordionModule, MJDialogAction, MJDialogService, MJEmptyStateComponent } from '@memberjunction/ng-ui-components';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\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, MJEmptyStateComponent, MJAccordionModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './user-sharing-center.component.html',\n styleUrls: ['./user-sharing-center.component.css'],\n})\nexport class UserSharingCenterComponent extends BaseAngularComponent 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 = this.ProviderToUse;\n // `SharingEntityResolver` is an @Input, so a custom domain can map to any entity — resolve the\n // key against that entity's real primary key column(s) rather than assuming `ID`.\n const entityInfo = md.EntityByName(entityName);\n if (!entityInfo) {\n this.setError(`Entity '${entityName}' for domain '${row.DomainName}' was not found in metadata.`);\n return;\n }\n const entity = await md.GetEntityObject<BaseEntity>(entityName, md.CurrentUser);\n const loaded = await entity.InnerLoad(CompositeKey.FromURLSegment(entityInfo, row.SourceRecordID));\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 /**\n * Apply the expand/collapse state emitted by the accordion panel for a domain\n * group. OnPush, so an explicit detectChanges() is required to reflect the change.\n */\n OnGroupExpandedChange(group: SharingCenterDomainGroup, expanded: boolean): void {\n group.Expanded = 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 = this.ProviderToUse.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 = this.ProviderToUse.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 <mj-empty-state class=\"empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"Nothing has been shared directly with you yet.\" />\n } @else {\n @for (group of SharedWithMe; track TrackByDomain($index, group)) {\n <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n [Expanded]=\"group.Expanded\"\n (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n <ng-template mjAccordionTitle>\n <span class=\"group-icon\"><i [class]=\"group.Icon\"></i></span>\n <span class=\"group-name\">{{ group.DomainName }}</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ group.Rows.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\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 </ng-template>\n </mj-accordion-panel>\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 <mj-empty-state class=\"empty\" Size=\"compact\"\n Icon=\"fa-solid fa-paper-plane\"\n Title=\"You haven't shared anything with others yet.\" />\n } @else {\n @for (group of SharedByMe; track TrackByDomain($index, group)) {\n <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n [Expanded]=\"group.Expanded\"\n (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n <ng-template mjAccordionTitle>\n <span class=\"group-icon\"><i [class]=\"group.Icon\"></i></span>\n <span class=\"group-name\">{{ group.DomainName }}</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ group.Rows.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\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 </ng-template>\n </mj-accordion-panel>\n }\n }\n }\n</div>\n"]}
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 NormalizedPermission,\n PermissionAction,\n} from '@memberjunction/core';\nimport { PermissionEngine } from '@memberjunction/core-entities';\nimport { MJAccordionModule, MJDialogAction, MJDialogService, MJEmptyStateComponent } from '@memberjunction/ng-ui-components';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\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 /**\n * The permission domain's identity: a LOOKUP KEY that drives Revoke resolution,\n * audit-entity mapping, and icon selection in PermissionEngine. Never renamed.\n */\n DomainName: string;\n /**\n * Business-friendly heading shown to the user (see `GetSharingDomainDisplayLabel`). Optional so\n * consumers that build this shape themselves keep compiling; the template falls back to `DomainName`.\n */\n Label?: string;\n Icon: string;\n Rows: NormalizedPermission[];\n Expanded: boolean;\n}\n\n/**\n * Display-only friendly headings for the built-in permission domains, used purely for\n * the Sharing Center section labels. The underlying `DomainName` is a LOOKUP KEY (it\n * drives Revoke resolution, audit-entity mapping, and icon selection in PermissionEngine)\n * and MUST NOT be renamed. This map translates only what the user *reads*, never what\n * the code *matches on*.\n */\nexport const SharingDomainDisplayLabels: Record<string, string> = {\n 'Dashboard Permissions': 'Dashboards',\n 'Artifact Permissions': 'Artifacts',\n 'Collection Permissions': 'Collections',\n 'Access Control Rules': 'Rules',\n 'Resource Permissions': 'Shared Items',\n};\n\n/**\n * Orders Sharing Center groups by the heading the user reads (`Label`), falling back to\n * `DomainName`. Sorting by `DomainName` put \"Rules\" (from \"Access Control Rules\") first once the\n * headings were relabeled. Display order only; `DomainName` stays the lookup key.\n */\nexport function CompareSharingDomainGroups(a: SharingCenterDomainGroup, b: SharingCenterDomainGroup): number {\n return (a.Label ?? a.DomainName).localeCompare(b.Label ?? b.DomainName);\n}\n\n/**\n * Returns a business-friendly heading for a permission domain. Falls back to the domain\n * name with a trailing \" Permissions\" stripped (so an unmapped custom domain like\n * \"Widget Permissions\" reads as \"Widget\"), then to the raw domain name.\n */\nexport function GetSharingDomainDisplayLabel(domainName: string): string {\n const trimmed = domainName.trim();\n // Own-property check, not a bare index: DomainName is user-authored for custom domains, and a\n // plain object lookup would return inherited Object.prototype members for names like \"constructor\".\n if (Object.prototype.hasOwnProperty.call(SharingDomainDisplayLabels, trimmed)) {\n return SharingDomainDisplayLabels[trimmed];\n }\n // Plain string ops rather than /\\s+Permissions$/i: a whitespace run before an anchored\n // literal backtracks quadratically on adversarial input (CodeQL js/polynomial-redos).\n const suffix = ' permissions';\n if (trimmed.toLowerCase().endsWith(suffix)) {\n const stripped = trimmed.slice(0, -suffix.length).trimEnd();\n if (stripped) {\n return stripped;\n }\n }\n return trimmed || domainName;\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, MJEmptyStateComponent, MJAccordionModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './user-sharing-center.component.html',\n styleUrls: ['./user-sharing-center.component.css'],\n})\nexport class UserSharingCenterComponent extends BaseAngularComponent 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 = this.ProviderToUse;\n // `SharingEntityResolver` is an @Input, so a custom domain can map to any entity — resolve the\n // key against that entity's real primary key column(s) rather than assuming `ID`.\n const entityInfo = md.EntityByName(entityName);\n if (!entityInfo) {\n this.setError(`Entity '${entityName}' for domain '${row.DomainName}' was not found in metadata.`);\n return;\n }\n const entity = await md.GetEntityObject<BaseEntity>(entityName, md.CurrentUser);\n const loaded = await entity.InnerLoad(CompositeKey.FromURLSegment(entityInfo, row.SourceRecordID));\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 /**\n * Apply the expand/collapse state emitted by the accordion panel for a domain\n * group. OnPush, so an explicit detectChanges() is required to reflect the change.\n */\n OnGroupExpandedChange(group: SharingCenterDomainGroup, expanded: boolean): void {\n group.Expanded = 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 = this.ProviderToUse.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 = this.ProviderToUse.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 Label: GetSharingDomainDisplayLabel(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(CompareSharingDomainGroups);\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 <mj-empty-state class=\"empty\" Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"Nothing has been shared directly with you yet.\" />\n } @else {\n @for (group of SharedWithMe; track TrackByDomain($index, group)) {\n <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n [Expanded]=\"group.Expanded\"\n (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n <ng-template mjAccordionTitle>\n <span class=\"group-icon\"><i [class]=\"group.Icon\"></i></span>\n <span class=\"group-name\">{{ group.Label ?? group.DomainName }}</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ group.Rows.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\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 </ng-template>\n </mj-accordion-panel>\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 <mj-empty-state class=\"empty\" Size=\"compact\"\n Icon=\"fa-solid fa-paper-plane\"\n Title=\"You haven't shared anything with others yet.\" />\n } @else {\n @for (group of SharedByMe; track TrackByDomain($index, group)) {\n <mj-accordion-panel Size=\"sm\" [FlushBody]=\"true\"\n [Expanded]=\"group.Expanded\"\n (ExpandedChange)=\"OnGroupExpandedChange(group, $event)\">\n <ng-template mjAccordionTitle>\n <span class=\"group-icon\"><i [class]=\"group.Icon\"></i></span>\n <span class=\"group-name\">{{ group.Label ?? group.DomainName }}</span>\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ group.Rows.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\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 </ng-template>\n </mj-accordion-panel>\n }\n }\n }\n</div>\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-resource-permissions",
3
- "version": "6.1.4",
3
+ "version": "6.2.0-edge.1",
4
4
  "description": "MemberJunction: Generic Angular components for displaying/editing permissions for a resource",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -13,8 +13,8 @@
13
13
  "devDependencies": {
14
14
  "@angular/compiler": "21.2.22",
15
15
  "@angular/compiler-cli": "21.2.22",
16
- "@memberjunction/core": "6.1.4",
17
- "@memberjunction/ng-test-utils": "6.1.4",
16
+ "@memberjunction/core": "6.2.0-edge.1",
17
+ "@memberjunction/ng-test-utils": "6.2.0-edge.1",
18
18
  "vitest": "^4.0.18"
19
19
  },
20
20
  "peerDependencies": {
@@ -23,15 +23,15 @@
23
23
  "@angular/forms": "^21.2.22"
24
24
  },
25
25
  "dependencies": {
26
- "@memberjunction/core": "6.1.4",
27
- "@memberjunction/core-entities": "6.1.4",
28
- "@memberjunction/global": "6.1.4",
29
- "@memberjunction/ng-base-types": "6.1.4",
30
- "@memberjunction/ng-container-directives": "6.1.4",
31
- "@memberjunction/ng-generic-dialog": "6.1.4",
32
- "@memberjunction/ng-notifications": "6.1.4",
33
- "@memberjunction/ng-shared-generic": "6.1.4",
34
- "@memberjunction/ng-ui-components": "6.1.4",
26
+ "@memberjunction/core": "6.2.0-edge.1",
27
+ "@memberjunction/core-entities": "6.2.0-edge.1",
28
+ "@memberjunction/global": "6.2.0-edge.1",
29
+ "@memberjunction/ng-base-types": "6.2.0-edge.1",
30
+ "@memberjunction/ng-container-directives": "6.2.0-edge.1",
31
+ "@memberjunction/ng-generic-dialog": "6.2.0-edge.1",
32
+ "@memberjunction/ng-notifications": "6.2.0-edge.1",
33
+ "@memberjunction/ng-shared-generic": "6.2.0-edge.1",
34
+ "@memberjunction/ng-ui-components": "6.2.0-edge.1",
35
35
  "ag-grid-angular": "^35.0.1",
36
36
  "ag-grid-community": "^35.0.1",
37
37
  "tslib": "^2.8.1"