@memberjunction/ng-resource-permissions 5.28.0 → 5.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/mj-resource-permission-share-adapter.d.ts +23 -0
- package/dist/lib/mj-resource-permission-share-adapter.d.ts.map +1 -0
- package/dist/lib/mj-resource-permission-share-adapter.js +81 -0
- package/dist/lib/mj-resource-permission-share-adapter.js.map +1 -0
- package/dist/lib/resource-permissions.component.js +4 -4
- package/dist/lib/resource-permissions.component.js.map +1 -1
- package/dist/lib/resource-share-adapter.d.ts +78 -0
- package/dist/lib/resource-share-adapter.d.ts.map +1 -0
- package/dist/lib/resource-share-adapter.js +6 -0
- package/dist/lib/resource-share-adapter.js.map +1 -0
- package/dist/lib/resource-share-dialog.component.d.ts +51 -0
- package/dist/lib/resource-share-dialog.component.d.ts.map +1 -0
- package/dist/lib/resource-share-dialog.component.js +458 -0
- package/dist/lib/resource-share-dialog.component.js.map +1 -0
- package/dist/lib/user-sharing-center.component.d.ts +105 -0
- package/dist/lib/user-sharing-center.component.d.ts.map +1 -0
- package/dist/lib/user-sharing-center.component.js +536 -0
- package/dist/lib/user-sharing-center.component.js.map +1 -0
- package/dist/module.d.ts +9 -8
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +19 -8
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +4 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +4 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +10 -10
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { MJUserEntity } from '@memberjunction/core-entities';
|
|
2
|
+
import { ResourceShareAdapter, ResourceShareContext, ResourceSharePermissionModel } from './resource-share-adapter';
|
|
3
|
+
/**
|
|
4
|
+
* Generic share adapter for any resource whose permissions live in the
|
|
5
|
+
* polymorphic `MJ: Resource Permissions` table (Conversations, Reports, Queries,
|
|
6
|
+
* and anything else seeded in the `MJ: Resource Types` catalog). The entity's
|
|
7
|
+
* `PermissionLevel` column is already a 3-value enum, so the mapping is trivial
|
|
8
|
+
* — `Level` is set and read directly with no translation.
|
|
9
|
+
*
|
|
10
|
+
* Construct with the target `ResourceTypeID`:
|
|
11
|
+
* ```ts
|
|
12
|
+
* const adapter = new MJResourcePermissionShareAdapter(CONVERSATIONS_RESOURCE_TYPE_ID);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare class MJResourcePermissionShareAdapter implements ResourceShareAdapter {
|
|
16
|
+
private readonly resourceTypeId;
|
|
17
|
+
constructor(resourceTypeId: string);
|
|
18
|
+
LoadShares(context: ResourceShareContext): Promise<ResourceSharePermissionModel[]>;
|
|
19
|
+
CreateShare(context: ResourceShareContext, user: MJUserEntity): Promise<ResourceSharePermissionModel>;
|
|
20
|
+
SyncLevelToEntity(row: ResourceSharePermissionModel): void;
|
|
21
|
+
private loadUser;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=mj-resource-permission-share-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mj-resource-permission-share-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/mj-resource-permission-share-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EACH,oBAAoB,EACpB,oBAAoB,EAEpB,4BAA4B,EAC/B,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,qBAAa,gCAAiC,YAAW,oBAAoB;IAC7D,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,MAAM;IAE7C,UAAU,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,4BAA4B,EAAE,CAAC;IA6BlF,WAAW,CAAC,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,4BAA4B,CAAC;IAuB3G,iBAAiB,CAAC,GAAG,EAAE,4BAA4B,GAAG,IAAI;YAK5C,QAAQ;CAMzB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
2
|
+
/**
|
|
3
|
+
* Generic share adapter for any resource whose permissions live in the
|
|
4
|
+
* polymorphic `MJ: Resource Permissions` table (Conversations, Reports, Queries,
|
|
5
|
+
* and anything else seeded in the `MJ: Resource Types` catalog). The entity's
|
|
6
|
+
* `PermissionLevel` column is already a 3-value enum, so the mapping is trivial
|
|
7
|
+
* — `Level` is set and read directly with no translation.
|
|
8
|
+
*
|
|
9
|
+
* Construct with the target `ResourceTypeID`:
|
|
10
|
+
* ```ts
|
|
11
|
+
* const adapter = new MJResourcePermissionShareAdapter(CONVERSATIONS_RESOURCE_TYPE_ID);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export class MJResourcePermissionShareAdapter {
|
|
15
|
+
resourceTypeId;
|
|
16
|
+
constructor(resourceTypeId) {
|
|
17
|
+
this.resourceTypeId = resourceTypeId;
|
|
18
|
+
}
|
|
19
|
+
async LoadShares(context) {
|
|
20
|
+
const rv = new RunView();
|
|
21
|
+
const result = await rv.RunView({
|
|
22
|
+
EntityName: 'MJ: Resource Permissions',
|
|
23
|
+
ExtraFilter: `ResourceTypeID='${this.resourceTypeId}' ` +
|
|
24
|
+
`AND ResourceRecordID='${context.ResourceID}' ` +
|
|
25
|
+
`AND Type='User' AND Status='Approved'`,
|
|
26
|
+
ResultType: 'entity_object'
|
|
27
|
+
});
|
|
28
|
+
if (!result.Success)
|
|
29
|
+
return [];
|
|
30
|
+
const rows = [];
|
|
31
|
+
for (const perm of result.Results) {
|
|
32
|
+
if (!perm.UserID)
|
|
33
|
+
continue;
|
|
34
|
+
const user = await this.loadUser(perm.UserID);
|
|
35
|
+
if (!user)
|
|
36
|
+
continue;
|
|
37
|
+
rows.push({
|
|
38
|
+
PermissionEntity: perm,
|
|
39
|
+
UserID: perm.UserID,
|
|
40
|
+
User: user,
|
|
41
|
+
Level: perm.PermissionLevel ?? 'View',
|
|
42
|
+
IsNew: false,
|
|
43
|
+
MarkedForRemoval: false
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return rows;
|
|
47
|
+
}
|
|
48
|
+
async CreateShare(context, user) {
|
|
49
|
+
const md = new Metadata();
|
|
50
|
+
const perm = await md.GetEntityObject('MJ: Resource Permissions');
|
|
51
|
+
perm.NewRecord();
|
|
52
|
+
perm.ResourceTypeID = this.resourceTypeId;
|
|
53
|
+
perm.ResourceRecordID = context.ResourceID;
|
|
54
|
+
perm.Type = 'User';
|
|
55
|
+
perm.UserID = user.ID;
|
|
56
|
+
perm.PermissionLevel = 'View';
|
|
57
|
+
perm.Status = 'Approved';
|
|
58
|
+
if (context.CurrentUserID) {
|
|
59
|
+
perm.SharedByUserID = context.CurrentUserID;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
PermissionEntity: perm,
|
|
63
|
+
UserID: user.ID,
|
|
64
|
+
User: user,
|
|
65
|
+
Level: 'View',
|
|
66
|
+
IsNew: true,
|
|
67
|
+
MarkedForRemoval: false
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
SyncLevelToEntity(row) {
|
|
71
|
+
const perm = row.PermissionEntity;
|
|
72
|
+
perm.PermissionLevel = row.Level;
|
|
73
|
+
}
|
|
74
|
+
async loadUser(userId) {
|
|
75
|
+
const md = new Metadata();
|
|
76
|
+
const user = await md.GetEntityObject('MJ: Users');
|
|
77
|
+
const loaded = await user.Load(userId);
|
|
78
|
+
return loaded ? user : null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=mj-resource-permission-share-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mj-resource-permission-share-adapter.js","sourceRoot":"","sources":["../../src/lib/mj-resource-permission-share-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { Metadata, RunView } from '@memberjunction/core';\nimport { MJResourcePermissionEntity, MJUserEntity } from '@memberjunction/core-entities';\nimport {\n ResourceShareAdapter,\n ResourceShareContext,\n ResourceShareLevel,\n ResourceSharePermissionModel\n} from './resource-share-adapter';\n\n/**\n * Generic share adapter for any resource whose permissions live in the\n * polymorphic `MJ: Resource Permissions` table (Conversations, Reports, Queries,\n * and anything else seeded in the `MJ: Resource Types` catalog). The entity's\n * `PermissionLevel` column is already a 3-value enum, so the mapping is trivial\n * — `Level` is set and read directly with no translation.\n *\n * Construct with the target `ResourceTypeID`:\n * ```ts\n * const adapter = new MJResourcePermissionShareAdapter(CONVERSATIONS_RESOURCE_TYPE_ID);\n * ```\n */\nexport class MJResourcePermissionShareAdapter implements ResourceShareAdapter {\n constructor(private readonly resourceTypeId: string) {}\n\n async LoadShares(context: ResourceShareContext): Promise<ResourceSharePermissionModel[]> {\n const rv = new RunView();\n const result = await rv.RunView<MJResourcePermissionEntity>({\n EntityName: 'MJ: Resource Permissions',\n ExtraFilter:\n `ResourceTypeID='${this.resourceTypeId}' ` +\n `AND ResourceRecordID='${context.ResourceID}' ` +\n `AND Type='User' AND Status='Approved'`,\n ResultType: 'entity_object'\n });\n if (!result.Success) return [];\n\n const rows: ResourceSharePermissionModel[] = [];\n for (const perm of result.Results) {\n if (!perm.UserID) continue;\n const user = await this.loadUser(perm.UserID);\n if (!user) continue;\n rows.push({\n PermissionEntity: perm,\n UserID: perm.UserID,\n User: user,\n Level: (perm.PermissionLevel as ResourceShareLevel | null) ?? 'View',\n IsNew: false,\n MarkedForRemoval: false\n });\n }\n return rows;\n }\n\n async CreateShare(context: ResourceShareContext, user: MJUserEntity): Promise<ResourceSharePermissionModel> {\n const md = new Metadata();\n const perm = await md.GetEntityObject<MJResourcePermissionEntity>('MJ: Resource Permissions');\n perm.NewRecord();\n perm.ResourceTypeID = this.resourceTypeId;\n perm.ResourceRecordID = context.ResourceID;\n perm.Type = 'User';\n perm.UserID = user.ID;\n perm.PermissionLevel = 'View';\n perm.Status = 'Approved';\n if (context.CurrentUserID) {\n perm.SharedByUserID = context.CurrentUserID;\n }\n return {\n PermissionEntity: perm,\n UserID: user.ID,\n User: user,\n Level: 'View',\n IsNew: true,\n MarkedForRemoval: false\n };\n }\n\n SyncLevelToEntity(row: ResourceSharePermissionModel): void {\n const perm = row.PermissionEntity as MJResourcePermissionEntity;\n perm.PermissionLevel = row.Level;\n }\n\n private async loadUser(userId: string): Promise<MJUserEntity | null> {\n const md = new Metadata();\n const user = await md.GetEntityObject<MJUserEntity>('MJ: Users');\n const loaded = await user.Load(userId);\n return loaded ? user : null;\n }\n}\n"]}
|
|
@@ -120,9 +120,9 @@ function ResourcePermissionsComponent_For_16_Conditional_5_Template(rf, ctx) { i
|
|
|
120
120
|
} }
|
|
121
121
|
function ResourcePermissionsComponent_For_16_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
122
122
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
123
|
-
i0.ɵɵelementStart(0, "td")(1, "button",
|
|
123
|
+
i0.ɵɵelementStart(0, "td")(1, "button", 17);
|
|
124
124
|
i0.ɵɵlistener("click", function ResourcePermissionsComponent_For_16_Conditional_6_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r9); const p_r8 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.deletePermission(p_r8)); });
|
|
125
|
-
i0.ɵɵelement(2, "span",
|
|
125
|
+
i0.ɵɵelement(2, "span", 18);
|
|
126
126
|
i0.ɵɵelementEnd()();
|
|
127
127
|
} }
|
|
128
128
|
function ResourcePermissionsComponent_For_16_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -362,7 +362,7 @@ export class ResourcePermissionsComponent extends BaseAngularComponent {
|
|
|
362
362
|
return ResourcePermissionEngine.GetProviderInstance(this.ProviderToUse, ResourcePermissionEngine);
|
|
363
363
|
}
|
|
364
364
|
static ɵfac = /*@__PURE__*/ (() => { let ɵResourcePermissionsComponent_BaseFactory; return function ResourcePermissionsComponent_Factory(__ngFactoryType__) { return (ɵResourcePermissionsComponent_BaseFactory || (ɵResourcePermissionsComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ResourcePermissionsComponent)))(__ngFactoryType__ || ResourcePermissionsComponent); }; })();
|
|
365
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ResourcePermissionsComponent, selectors: [["mj-resource-permissions"]], inputs: { ResourceTypeID: "ResourceTypeID", ResourceRecordID: "ResourceRecordID", ShowSaveButton: "ShowSaveButton", ShowPermissionLevels: "ShowPermissionLevels", ShowUserErrorMessages: "ShowUserErrorMessages", AllowAddPermissions: "AllowAddPermissions", AllowEditPermissions: "AllowEditPermissions", AllowDeletePermissions: "AllowDeletePermissions", PermissionLevels: "PermissionLevels", PermissionTypes: "PermissionTypes", ExcludedRoleNames: "ExcludedRoleNames", ExcludedUserEmails: "ExcludedUserEmails" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 17, vars: 5, consts: [[1, "container"], ["size", "medium", 3, "showText"], ["mjButton", ""], [1, "table-container"], [1, "add-permission-section"], [1, "resource-table"], ["mjButton", "", 3, "click"], [1, "add-permission-label"], [2, "width", "100px", 3, "ngModelChange", "Data", "ngModel"], ["TextField", "Name", "ValueField", "ID", 2, "width", "225px", 3, "Data", "ngModel"], ["TextField", "Name", "ValueField", "ID", 2, "width", "150px", 3, "Data", "ngModel"], [2, "width", "100px", 3, "Data", "ngModel"], ["mjButton", "", 3, "click", "disabled", "title"], ["TextField", "Name", "ValueField", "ID", 2, "width", "225px", 3, "ngModelChange", "Data", "ngModel"], ["TextField", "Name", "ValueField", "ID", 2, "width", "150px", 3, "ngModelChange", "Data", "ngModel"], [2, "width", "100px", 3, "ngModel", "Data"], [2, "width", "100px", 3, "ngModelChange", "ngModel", "Data"], [1, "fa-solid", "fa-trash-can"]], template: function ResourcePermissionsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
365
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ResourcePermissionsComponent, selectors: [["mj-resource-permissions"]], inputs: { ResourceTypeID: "ResourceTypeID", ResourceRecordID: "ResourceRecordID", ShowSaveButton: "ShowSaveButton", ShowPermissionLevels: "ShowPermissionLevels", ShowUserErrorMessages: "ShowUserErrorMessages", AllowAddPermissions: "AllowAddPermissions", AllowEditPermissions: "AllowEditPermissions", AllowDeletePermissions: "AllowDeletePermissions", PermissionLevels: "PermissionLevels", PermissionTypes: "PermissionTypes", ExcludedRoleNames: "ExcludedRoleNames", ExcludedUserEmails: "ExcludedUserEmails" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 17, vars: 5, consts: [[1, "container"], ["size", "medium", 3, "showText"], ["mjButton", ""], [1, "table-container"], [1, "add-permission-section"], [1, "resource-table"], ["mjButton", "", 3, "click"], [1, "add-permission-label"], [2, "width", "100px", 3, "ngModelChange", "Data", "ngModel"], ["TextField", "Name", "ValueField", "ID", 2, "width", "225px", 3, "Data", "ngModel"], ["TextField", "Name", "ValueField", "ID", 2, "width", "150px", 3, "Data", "ngModel"], [2, "width", "100px", 3, "Data", "ngModel"], ["mjButton", "", 3, "click", "disabled", "title"], ["TextField", "Name", "ValueField", "ID", 2, "width", "225px", 3, "ngModelChange", "Data", "ngModel"], ["TextField", "Name", "ValueField", "ID", 2, "width", "150px", 3, "ngModelChange", "Data", "ngModel"], [2, "width", "100px", 3, "ngModel", "Data"], [2, "width", "100px", 3, "ngModelChange", "ngModel", "Data"], ["mjButton", "", "aria-label", "Delete permission", "title", "Delete permission", 3, "click"], [1, "fa-solid", "fa-trash-can"]], template: function ResourcePermissionsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
366
366
|
i0.ɵɵelementStart(0, "div", 0);
|
|
367
367
|
i0.ɵɵconditionalCreate(1, ResourcePermissionsComponent_Conditional_1_Template, 1, 1, "mj-loading", 1);
|
|
368
368
|
i0.ɵɵconditionalCreate(2, ResourcePermissionsComponent_Conditional_2_Template, 2, 0, "button", 2);
|
|
@@ -397,7 +397,7 @@ export class ResourcePermissionsComponent extends BaseAngularComponent {
|
|
|
397
397
|
}
|
|
398
398
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ResourcePermissionsComponent, [{
|
|
399
399
|
type: Component,
|
|
400
|
-
args: [{ standalone: false, selector: 'mj-resource-permissions', template: "<div class=\"container\">\n @if(_Loading) {\n <mj-loading [showText]=\"false\" size=\"medium\"></mj-loading>\n }\n @if(ShowSaveButton) {\n <button mjButton (click)=\"SavePermissions()\">Save</button>\n }\n <div class=\"table-container\">\n @if(AllowAddPermissions) {\n <div class=\"add-permission-section\">\n <span class=\"add-permission-label\">Add Permission</span>\n <mj-dropdown\n [Data]=\"PermissionTypes\"\n [(ngModel)]=\"SelectedType\"\n style=\"width: 100px;\">\n </mj-dropdown>\n @if (SelectedType === 'User') {\n <mj-dropdown\n [Data]=\"AllUsers\"\n [(ngModel)]=\"SelectedUser\"\n TextField=\"Name\"\n ValueField=\"ID\"\n style=\"width: 225px;\">\n </mj-dropdown>\n }\n @else if (SelectedType === 'Role') {\n <mj-dropdown\n [Data]=\"AllRoles\"\n [(ngModel)]=\"SelectedRole\"\n TextField=\"Name\"\n ValueField=\"ID\"\n style=\"width: 150px;\">\n </mj-dropdown>\n }\n @else {\n SelectedType: {{ SelectedType }}\n }\n @if (ShowPermissionLevels) {\n <mj-dropdown\n [Data]=\"PermissionLevels\"\n [(ngModel)]=\"SelectedPermissionLevel\"\n style=\"width: 100px;\">\n </mj-dropdown>\n }\n <button mjButton (click)=\"addPermission()\" [disabled]=\"permissionAlreadyExists()\" [title]=\"permissionAlreadyExists() ? 'This combination of Type/User/Role already exists below' : ''\" >Add</button>\n </div>\n }\n <table class=\"resource-table\">\n <thead>\n <tr>\n <th>Type</th>\n <th>Name</th>\n @if (ShowPermissionLevels) {\n <th>Level</th>\n }\n @if(AllowDeletePermissions) {\n <th>Actions</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (p of resourcePermissions; track p) {\n <tr>\n <td>{{ p.Type }}</td>\n <td>{{ p.Type === 'User' ? p.User : p.Role }}</td>\n @if (ShowPermissionLevels) {\n <td>\n @if (AllowEditPermissions) {\n <mj-dropdown\n [(ngModel)]=\"p.PermissionLevel\"\n [Data]=\"PermissionLevels\"\n style=\"width: 100px;\">\n </mj-dropdown>\n }\n @else {\n {{ p.PermissionLevel }}\n }\n </td>\n }\n @if(AllowDeletePermissions) {\n <td>\n <button mjButton (click)=\"deletePermission(p)\"><span class=\"fa-solid fa-trash-can\"></span></button>\n </td>\n }\n </tr> \n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: ["/* Container styling */\n.container {\n max-width: 100%;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n/* Table container for vertical scrolling */\n.table-container {\n max-height: 400px;\n /* Adjust as needed */\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* Table styling */\n.resource-table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.resource-table thead {\n background-color: var(--mj-bg-surface-elevated);\n font-weight: var(--mj-font-bold);\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.resource-table th,\n.resource-table td {\n padding: var(--mj-space-3);\n text-align: left;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n\n.resource-table th {\n background-color: var(--mj-bg-surface-elevated);\n color: var(--mj-text-secondary);\n}\n\n.resource-table tbody tr:nth-child(even) {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.resource-table tbody tr:hover {\n background-color: var(--mj-bg-surface-hover);\n}\n\n/* Button styling */\nbutton.k-button {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n border: none;\n padding: var(--mj-space-1) var(--mj-space-2-5);\n border-radius: var(--mj-radius-sm);\n cursor: pointer;\n font-family: var(--mj-font-family);\n}\n\nbutton.k-button:hover {\n background-color: var(--mj-status-error-text);\n}\n\n.add-permission-label {\n margin-left: var(--mj-space-1);\n margin-right: var(--mj-space-1);\n font-weight: var(--mj-font-bold);\n color: var(--mj-text-primary);\n}\n\n.add-permission-section {\n margin-top: var(--mj-space-2-5);\n margin-bottom: var(--mj-space-2-5);\n}"] }]
|
|
400
|
+
args: [{ standalone: false, selector: 'mj-resource-permissions', template: "<div class=\"container\">\n @if(_Loading) {\n <mj-loading [showText]=\"false\" size=\"medium\"></mj-loading>\n }\n @if(ShowSaveButton) {\n <button mjButton (click)=\"SavePermissions()\">Save</button>\n }\n <div class=\"table-container\">\n @if(AllowAddPermissions) {\n <div class=\"add-permission-section\">\n <span class=\"add-permission-label\">Add Permission</span>\n <mj-dropdown\n [Data]=\"PermissionTypes\"\n [(ngModel)]=\"SelectedType\"\n style=\"width: 100px;\">\n </mj-dropdown>\n @if (SelectedType === 'User') {\n <mj-dropdown\n [Data]=\"AllUsers\"\n [(ngModel)]=\"SelectedUser\"\n TextField=\"Name\"\n ValueField=\"ID\"\n style=\"width: 225px;\">\n </mj-dropdown>\n }\n @else if (SelectedType === 'Role') {\n <mj-dropdown\n [Data]=\"AllRoles\"\n [(ngModel)]=\"SelectedRole\"\n TextField=\"Name\"\n ValueField=\"ID\"\n style=\"width: 150px;\">\n </mj-dropdown>\n }\n @else {\n SelectedType: {{ SelectedType }}\n }\n @if (ShowPermissionLevels) {\n <mj-dropdown\n [Data]=\"PermissionLevels\"\n [(ngModel)]=\"SelectedPermissionLevel\"\n style=\"width: 100px;\">\n </mj-dropdown>\n }\n <button mjButton (click)=\"addPermission()\" [disabled]=\"permissionAlreadyExists()\" [title]=\"permissionAlreadyExists() ? 'This combination of Type/User/Role already exists below' : ''\" >Add</button>\n </div>\n }\n <table class=\"resource-table\">\n <thead>\n <tr>\n <th>Type</th>\n <th>Name</th>\n @if (ShowPermissionLevels) {\n <th>Level</th>\n }\n @if(AllowDeletePermissions) {\n <th>Actions</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (p of resourcePermissions; track p) {\n <tr>\n <td>{{ p.Type }}</td>\n <td>{{ p.Type === 'User' ? p.User : p.Role }}</td>\n @if (ShowPermissionLevels) {\n <td>\n @if (AllowEditPermissions) {\n <mj-dropdown\n [(ngModel)]=\"p.PermissionLevel\"\n [Data]=\"PermissionLevels\"\n style=\"width: 100px;\">\n </mj-dropdown>\n }\n @else {\n {{ p.PermissionLevel }}\n }\n </td>\n }\n @if(AllowDeletePermissions) {\n <td>\n <button mjButton aria-label=\"Delete permission\" title=\"Delete permission\" (click)=\"deletePermission(p)\"><span class=\"fa-solid fa-trash-can\"></span></button>\n </td>\n }\n </tr> \n }\n </tbody>\n </table>\n </div>\n</div>\n", styles: ["/* Container styling */\n.container {\n max-width: 100%;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n/* Table container for vertical scrolling */\n.table-container {\n max-height: 400px;\n /* Adjust as needed */\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* Table styling */\n.resource-table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.resource-table thead {\n background-color: var(--mj-bg-surface-elevated);\n font-weight: var(--mj-font-bold);\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.resource-table th,\n.resource-table td {\n padding: var(--mj-space-3);\n text-align: left;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n\n.resource-table th {\n background-color: var(--mj-bg-surface-elevated);\n color: var(--mj-text-secondary);\n}\n\n.resource-table tbody tr:nth-child(even) {\n background-color: var(--mj-bg-surface-sunken);\n}\n\n.resource-table tbody tr:hover {\n background-color: var(--mj-bg-surface-hover);\n}\n\n/* Button styling */\nbutton.k-button {\n background-color: var(--mj-status-error);\n color: var(--mj-text-inverse);\n border: none;\n padding: var(--mj-space-1) var(--mj-space-2-5);\n border-radius: var(--mj-radius-sm);\n cursor: pointer;\n font-family: var(--mj-font-family);\n}\n\nbutton.k-button:hover {\n background-color: var(--mj-status-error-text);\n}\n\n.add-permission-label {\n margin-left: var(--mj-space-1);\n margin-right: var(--mj-space-1);\n font-weight: var(--mj-font-bold);\n color: var(--mj-text-primary);\n}\n\n.add-permission-section {\n margin-top: var(--mj-space-2-5);\n margin-bottom: var(--mj-space-2-5);\n}"] }]
|
|
401
401
|
}], null, { ResourceTypeID: [{
|
|
402
402
|
type: Input
|
|
403
403
|
}], ResourceRecordID: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-permissions.component.js","sourceRoot":"","sources":["../../src/lib/resource-permissions.component.ts","../../src/lib/resource-permissions.component.html"],"names":[],"mappings":"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","sourcesContent":["import { AfterViewInit, Component, Input } from '@angular/core';\nimport { LogError, RoleInfo, RunView } from '@memberjunction/core';\nimport { ResourcePermissionEngine, MJResourcePermissionEntity, MJUserEntity } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\n\n/**\n * Visual component used to display and manage permissions for a resource. You can wrap this in a dialog or display anywhere else within\n * an Angular application or component.\n */\n@Component({\n standalone: false,\n selector: 'mj-resource-permissions',\n templateUrl: './resource-permissions.component.html',\n styleUrls: ['./resource-permissions.component.css']\n})\nexport class ResourcePermissionsComponent extends BaseAngularComponent implements AfterViewInit {\n /**\n * Required: the ID of the resource type record for the specified resource that the permissions are being set for.\n */\n @Input() ResourceTypeID!: string;\n /**\n * Required: the record ID of the resource that the permissions are being set for.\n */ \n @Input() ResourceRecordID!: string;\n /**\n * If set to true, the component will show a Save button to the user and persist the changes to the \n * database when the user clicks the Save button. By default this is off to allow users of the component\n * to wrap the component as desired, and handle the save themselves.\n */\n @Input() ShowSaveButton: boolean = false;\n /**\n * If set to true, the component will show the permission levels to the user. By default this is on. If you have \n * a Resource Type or run-time use case where levels are not relevant, you can turn this off.\n */\n @Input() ShowPermissionLevels: boolean = true;\n /**\n * By default, this component will not show any error messages to the user. \n * If you want to show error messages to the user, set this to true. The component will always throw exceptions when error occur internally.\n */\n @Input() ShowUserErrorMessages: boolean = false;\n /**\n * Allows you to determine if the user is able to add new permissions for the resource.\n */\n @Input() AllowAddPermissions: boolean = true;\n /**\n * Allows you to determine if the user is able to edit existing permissions for the resource.\n */\n @Input() AllowEditPermissions: boolean = true;\n /**\n * Allows you to determine if the user is able to delete existing permissions for the resource.\n */\n @Input() AllowDeletePermissions: boolean = true;\n\n /**\n * List of possible permission levels that can be set for the resource. An array of strings, defaults to ['View', 'Edit', 'Owner']\n */\n @Input() PermissionLevels = ['View', 'Edit', 'Owner']; // these are the possible permission levels\n\n /**\n * Specifies the types of permissions the UI will allow settings for. An array of strings, defaults to ['User', 'Role']\n */\n @Input() PermissionTypes = ['User', 'Role'];\n\n /**\n * This optional input allows you to exclude certain roles from the list of roles that can be selected for permissions. If existing permissions have been created with roles that are in this list they will still be displayed, \n * but the user will not be able to add new permissions with these roles. This is an array of strings with the NAMES of the roles.\n */\n @Input() ExcludedRoleNames: string[] = [];\n\n /**\n * This optional input allows you to exclude certain users from the list of users that can be selected for permissions. If existing permissions have been created with users that are in this list they will still be displayed, \n * but the user will not be able to add new permissions with these users. This is an array of strings with EMAILS.\n */\n @Input() ExcludedUserEmails: string[] = [];\n\n public AllUsers: MJUserEntity[] = [];\n public AllRoles: RoleInfo[] = [];\n\n public SelectedUser: MJUserEntity | null = null;\n public SelectedRole: RoleInfo | null = null;\n public SelectedType: 'User' | 'Role' = 'Role';\n public SelectedPermissionLevel: 'View' | 'Edit' | 'Owner' = 'View';\n\n public _Loading: boolean = false;\n\n public async UpdateResourceRecordID(ResourceRecordID: string) {\n this.ResourceRecordID = ResourceRecordID;\n // now go through all of our permissions and update the ResourceRecordID\n for (const permission of this.resourcePermissions) {\n permission.ResourceRecordID = ResourceRecordID\n }\n }\n\n public resourcePermissions: MJResourcePermissionEntity[] = [];\n async ngAfterViewInit() {\n if (!this.ResourceTypeID || !this.ResourceRecordID) {\n throw new Error('ResourceTypeID and ResourceRecordID must be set');\n }\n\n this._Loading = true;\n // load up the current permissions for the specified ResourceTypeID and ResourceRecordID\n const engine = this.GetEngine();\n await engine.Config(false, this.ProviderToUse.CurrentUser, this.ProviderToUse);\n // now we can get the permissions for the specified resource\n const allResourcePermissions = engine.GetResourcePermissions(this.ResourceTypeID, this.ResourceRecordID);\n this.resourcePermissions = allResourcePermissions.filter((p) => p.Status === 'Approved'); // only include approved permissions in the UI, we don't show requested, rejected, revoked permissions here, just suppress them.\n \n const p = this.ProviderToUse;\n const rv = RunView.FromMetadataProvider(p)\n const result = await rv.RunView<MJUserEntity>({\n EntityName: \"MJ: Users\",\n ResultType: \"entity_object\",\n OrderBy: \"Name\",\n ExtraFilter: \"IsActive=1\"\n });\n // filter out any users that are in the ExcludedUserEmails list\n this.AllUsers = result.Results.filter((u) => !this.ExcludedUserEmails.includes(u.Email));\n // filter out any roles that are in the ExcludedRoleNames list\n this.AllRoles = p.Roles.filter((r) => !this.ExcludedRoleNames.includes(r.Name));\n\n if (this.AllUsers.length > 0)\n this.SelectedUser = this.AllUsers[0];\n if (this.AllRoles.length > 0)\n this.SelectedRole = this.AllRoles[0];\n\n this._Loading = false;\n }\n\n private _pendingDeletes: MJResourcePermissionEntity[] = [];\n public deletePermission(permission: MJResourcePermissionEntity) {\n this._pendingDeletes.push(permission);\n this.resourcePermissions = this.resourcePermissions.filter((p) => p !== permission);\n }\n\n private _pendingAdds: MJResourcePermissionEntity[] = [];\n public async addPermission() {\n const p = this.ProviderToUse;\n const permission = await p.GetEntityObject<MJResourcePermissionEntity>(\"MJ: Resource Permissions\", p.CurrentUser);\n permission.ResourceTypeID = this.ResourceTypeID;\n permission.ResourceRecordID = this.ResourceRecordID;\n permission.Type = this.SelectedType;\n permission.Status = 'Approved';\n permission.PermissionLevel = this.SelectedPermissionLevel;\n if (this.SelectedType === 'User' && this.SelectedUser) {\n permission.UserID = this.SelectedUser.ID;\n permission.Set(\"User\", this.SelectedUser.Name);// set the virtual field for display purposes\n }\n else if (this.SelectedType === 'Role' && this.SelectedRole) { \n permission.RoleID = this.SelectedRole.ID;\n permission.Set(\"Role\", this.SelectedRole.Name); // set the virtual field for display purposes\n }\n else {\n LogError('Invalid permission type or missing user/role');\n return;\n }\n this.resourcePermissions.push(permission);\n }\n\n public permissionAlreadyExists(): boolean {\n // check to see if the selection that the user currently has in place for the combination of TYPE + either USER or ROLE already exists\n // in our list of permissions\n for (const permission of this.resourcePermissions) {\n if (permission.Type === this.SelectedType) {\n if (this.SelectedType === 'User' && UUIDsEqual(permission.UserID, this.SelectedUser?.ID)) {\n return true;\n }\n else if (this.SelectedType === 'Role' && UUIDsEqual(permission.RoleID, this.SelectedRole?.ID)) {\n return true;\n }\n }\n }\n\n // if we get here, then the permission does not already exist\n return false;\n }\n\n public async SavePermissions(): Promise<boolean> {\n // first delete any permissions that were marked for deletion\n this._Loading = true;\n const p = this.ProviderToUse;\n const tg = await p.CreateTransactionGroup();\n for (const permission of this._pendingDeletes) {\n if (permission.IsSaved) {\n // only delete records previously saved, sometimes a user adds a new permission and deletes it before saving it\n permission.TransactionGroup = tg;\n if (!await permission.Delete()) { // we use await here because the promise will resolve before the actual save occurs --- the internals will not call the network until tg.Submit() below\n // validation errors come back here\n if (this.ShowUserErrorMessages)\n MJNotificationService.Instance.CreateSimpleNotification('Error saving permissions', 'error', 2500);\n\n LogError('Error deleting permission record in the transaction group: ' + permission.LatestResult.CompleteMessage);\n return false;\n } \n } \n }\n\n // next add new permissions by saving them in the transaction group\n for (const permission of this._pendingAdds) {\n if (this._pendingDeletes.includes(permission)) {\n // don't save a permission record that is new, if it was also marked for deletion\n permission.TransactionGroup = tg;\n if (!await permission.Save()) { \n // validation errors come back here\n if (this.ShowUserErrorMessages)\n MJNotificationService.Instance.CreateSimpleNotification('Error saving permissions', 'error', 2500);\n\n LogError('Error saving permission record in the transaction group: ' + permission.LatestResult.CompleteMessage); \n return false;\n }\n }\n }\n\n // now save the existing permissions\n for (const permission of this.resourcePermissions) {\n // make sure not in the delete array\n if (!this._pendingDeletes.includes(permission)) {\n permission.TransactionGroup = tg;\n if (!await permission.Save()) { \n // validation errors come back here\n if (this.ShowUserErrorMessages)\n MJNotificationService.Instance.CreateSimpleNotification('Error saving permissions', 'error', 2500);\n\n LogError('Error saving permission record in the transaction group: ' + permission.LatestResult.CompleteMessage);\n return false;\n }\n }\n }\n\n // now save the changes\n if (await tg.Submit()) {\n this._Loading = false;\n this._pendingDeletes = [];\n this._pendingAdds = [];\n const engine = this.GetEngine();\n await engine.RefreshAllItems(); // refresh the permissions cache\n return true;\n }\n else {\n // we had an error, show the user via SharedService\n this._Loading = false;\n if (this.ShowUserErrorMessages)\n MJNotificationService.Instance.CreateSimpleNotification('Error saving permissions', 'error', );\n \n LogError('Error saving permissions in the transaction group');\n return false;\n }\n }\n\n protected GetEngine(): ResourcePermissionEngine {\n return <ResourcePermissionEngine>ResourcePermissionEngine.GetProviderInstance(this.ProviderToUse, ResourcePermissionEngine);\n }\n}\n","<div class=\"container\">\n @if(_Loading) {\n <mj-loading [showText]=\"false\" size=\"medium\"></mj-loading>\n }\n @if(ShowSaveButton) {\n <button mjButton (click)=\"SavePermissions()\">Save</button>\n }\n <div class=\"table-container\">\n @if(AllowAddPermissions) {\n <div class=\"add-permission-section\">\n <span class=\"add-permission-label\">Add Permission</span>\n <mj-dropdown\n [Data]=\"PermissionTypes\"\n [(ngModel)]=\"SelectedType\"\n style=\"width: 100px;\">\n </mj-dropdown>\n @if (SelectedType === 'User') {\n <mj-dropdown\n [Data]=\"AllUsers\"\n [(ngModel)]=\"SelectedUser\"\n TextField=\"Name\"\n ValueField=\"ID\"\n style=\"width: 225px;\">\n </mj-dropdown>\n }\n @else if (SelectedType === 'Role') {\n <mj-dropdown\n [Data]=\"AllRoles\"\n [(ngModel)]=\"SelectedRole\"\n TextField=\"Name\"\n ValueField=\"ID\"\n style=\"width: 150px;\">\n </mj-dropdown>\n }\n @else {\n SelectedType: {{ SelectedType }}\n }\n @if (ShowPermissionLevels) {\n <mj-dropdown\n [Data]=\"PermissionLevels\"\n [(ngModel)]=\"SelectedPermissionLevel\"\n style=\"width: 100px;\">\n </mj-dropdown>\n }\n <button mjButton (click)=\"addPermission()\" [disabled]=\"permissionAlreadyExists()\" [title]=\"permissionAlreadyExists() ? 'This combination of Type/User/Role already exists below' : ''\" >Add</button>\n </div>\n }\n <table class=\"resource-table\">\n <thead>\n <tr>\n <th>Type</th>\n <th>Name</th>\n @if (ShowPermissionLevels) {\n <th>Level</th>\n }\n @if(AllowDeletePermissions) {\n <th>Actions</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (p of resourcePermissions; track p) {\n <tr>\n <td>{{ p.Type }}</td>\n <td>{{ p.Type === 'User' ? p.User : p.Role }}</td>\n @if (ShowPermissionLevels) {\n <td>\n @if (AllowEditPermissions) {\n <mj-dropdown\n [(ngModel)]=\"p.PermissionLevel\"\n [Data]=\"PermissionLevels\"\n style=\"width: 100px;\">\n </mj-dropdown>\n }\n @else {\n {{ p.PermissionLevel }}\n }\n </td>\n }\n @if(AllowDeletePermissions) {\n <td>\n <button mjButton (click)=\"deletePermission(p)\"><span class=\"fa-solid fa-trash-can\"></span></button>\n </td>\n }\n </tr> \n }\n </tbody>\n </table>\n </div>\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"resource-permissions.component.js","sourceRoot":"","sources":["../../src/lib/resource-permissions.component.ts","../../src/lib/resource-permissions.component.html"],"names":[],"mappings":"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","sourcesContent":["import { AfterViewInit, Component, Input } from '@angular/core';\nimport { LogError, RoleInfo, RunView } from '@memberjunction/core';\nimport { ResourcePermissionEngine, MJResourcePermissionEntity, MJUserEntity } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\n\n/**\n * Visual component used to display and manage permissions for a resource. You can wrap this in a dialog or display anywhere else within\n * an Angular application or component.\n */\n@Component({\n standalone: false,\n selector: 'mj-resource-permissions',\n templateUrl: './resource-permissions.component.html',\n styleUrls: ['./resource-permissions.component.css']\n})\nexport class ResourcePermissionsComponent extends BaseAngularComponent implements AfterViewInit {\n /**\n * Required: the ID of the resource type record for the specified resource that the permissions are being set for.\n */\n @Input() ResourceTypeID!: string;\n /**\n * Required: the record ID of the resource that the permissions are being set for.\n */ \n @Input() ResourceRecordID!: string;\n /**\n * If set to true, the component will show a Save button to the user and persist the changes to the \n * database when the user clicks the Save button. By default this is off to allow users of the component\n * to wrap the component as desired, and handle the save themselves.\n */\n @Input() ShowSaveButton: boolean = false;\n /**\n * If set to true, the component will show the permission levels to the user. By default this is on. If you have \n * a Resource Type or run-time use case where levels are not relevant, you can turn this off.\n */\n @Input() ShowPermissionLevels: boolean = true;\n /**\n * By default, this component will not show any error messages to the user. \n * If you want to show error messages to the user, set this to true. The component will always throw exceptions when error occur internally.\n */\n @Input() ShowUserErrorMessages: boolean = false;\n /**\n * Allows you to determine if the user is able to add new permissions for the resource.\n */\n @Input() AllowAddPermissions: boolean = true;\n /**\n * Allows you to determine if the user is able to edit existing permissions for the resource.\n */\n @Input() AllowEditPermissions: boolean = true;\n /**\n * Allows you to determine if the user is able to delete existing permissions for the resource.\n */\n @Input() AllowDeletePermissions: boolean = true;\n\n /**\n * List of possible permission levels that can be set for the resource. An array of strings, defaults to ['View', 'Edit', 'Owner']\n */\n @Input() PermissionLevels = ['View', 'Edit', 'Owner']; // these are the possible permission levels\n\n /**\n * Specifies the types of permissions the UI will allow settings for. An array of strings, defaults to ['User', 'Role']\n */\n @Input() PermissionTypes = ['User', 'Role'];\n\n /**\n * This optional input allows you to exclude certain roles from the list of roles that can be selected for permissions. If existing permissions have been created with roles that are in this list they will still be displayed, \n * but the user will not be able to add new permissions with these roles. This is an array of strings with the NAMES of the roles.\n */\n @Input() ExcludedRoleNames: string[] = [];\n\n /**\n * This optional input allows you to exclude certain users from the list of users that can be selected for permissions. If existing permissions have been created with users that are in this list they will still be displayed, \n * but the user will not be able to add new permissions with these users. This is an array of strings with EMAILS.\n */\n @Input() ExcludedUserEmails: string[] = [];\n\n public AllUsers: MJUserEntity[] = [];\n public AllRoles: RoleInfo[] = [];\n\n public SelectedUser: MJUserEntity | null = null;\n public SelectedRole: RoleInfo | null = null;\n public SelectedType: 'User' | 'Role' = 'Role';\n public SelectedPermissionLevel: 'View' | 'Edit' | 'Owner' = 'View';\n\n public _Loading: boolean = false;\n\n public async UpdateResourceRecordID(ResourceRecordID: string) {\n this.ResourceRecordID = ResourceRecordID;\n // now go through all of our permissions and update the ResourceRecordID\n for (const permission of this.resourcePermissions) {\n permission.ResourceRecordID = ResourceRecordID\n }\n }\n\n public resourcePermissions: MJResourcePermissionEntity[] = [];\n async ngAfterViewInit() {\n if (!this.ResourceTypeID || !this.ResourceRecordID) {\n throw new Error('ResourceTypeID and ResourceRecordID must be set');\n }\n\n this._Loading = true;\n // load up the current permissions for the specified ResourceTypeID and ResourceRecordID\n const engine = this.GetEngine();\n await engine.Config(false, this.ProviderToUse.CurrentUser, this.ProviderToUse);\n // now we can get the permissions for the specified resource\n const allResourcePermissions = engine.GetResourcePermissions(this.ResourceTypeID, this.ResourceRecordID);\n this.resourcePermissions = allResourcePermissions.filter((p) => p.Status === 'Approved'); // only include approved permissions in the UI, we don't show requested, rejected, revoked permissions here, just suppress them.\n \n const p = this.ProviderToUse;\n const rv = RunView.FromMetadataProvider(p)\n const result = await rv.RunView<MJUserEntity>({\n EntityName: \"MJ: Users\",\n ResultType: \"entity_object\",\n OrderBy: \"Name\",\n ExtraFilter: \"IsActive=1\"\n });\n // filter out any users that are in the ExcludedUserEmails list\n this.AllUsers = result.Results.filter((u) => !this.ExcludedUserEmails.includes(u.Email));\n // filter out any roles that are in the ExcludedRoleNames list\n this.AllRoles = p.Roles.filter((r) => !this.ExcludedRoleNames.includes(r.Name));\n\n if (this.AllUsers.length > 0)\n this.SelectedUser = this.AllUsers[0];\n if (this.AllRoles.length > 0)\n this.SelectedRole = this.AllRoles[0];\n\n this._Loading = false;\n }\n\n private _pendingDeletes: MJResourcePermissionEntity[] = [];\n public deletePermission(permission: MJResourcePermissionEntity) {\n this._pendingDeletes.push(permission);\n this.resourcePermissions = this.resourcePermissions.filter((p) => p !== permission);\n }\n\n private _pendingAdds: MJResourcePermissionEntity[] = [];\n public async addPermission() {\n const p = this.ProviderToUse;\n const permission = await p.GetEntityObject<MJResourcePermissionEntity>(\"MJ: Resource Permissions\", p.CurrentUser);\n permission.ResourceTypeID = this.ResourceTypeID;\n permission.ResourceRecordID = this.ResourceRecordID;\n permission.Type = this.SelectedType;\n permission.Status = 'Approved';\n permission.PermissionLevel = this.SelectedPermissionLevel;\n if (this.SelectedType === 'User' && this.SelectedUser) {\n permission.UserID = this.SelectedUser.ID;\n permission.Set(\"User\", this.SelectedUser.Name);// set the virtual field for display purposes\n }\n else if (this.SelectedType === 'Role' && this.SelectedRole) { \n permission.RoleID = this.SelectedRole.ID;\n permission.Set(\"Role\", this.SelectedRole.Name); // set the virtual field for display purposes\n }\n else {\n LogError('Invalid permission type or missing user/role');\n return;\n }\n this.resourcePermissions.push(permission);\n }\n\n public permissionAlreadyExists(): boolean {\n // check to see if the selection that the user currently has in place for the combination of TYPE + either USER or ROLE already exists\n // in our list of permissions\n for (const permission of this.resourcePermissions) {\n if (permission.Type === this.SelectedType) {\n if (this.SelectedType === 'User' && UUIDsEqual(permission.UserID, this.SelectedUser?.ID)) {\n return true;\n }\n else if (this.SelectedType === 'Role' && UUIDsEqual(permission.RoleID, this.SelectedRole?.ID)) {\n return true;\n }\n }\n }\n\n // if we get here, then the permission does not already exist\n return false;\n }\n\n public async SavePermissions(): Promise<boolean> {\n // first delete any permissions that were marked for deletion\n this._Loading = true;\n const p = this.ProviderToUse;\n const tg = await p.CreateTransactionGroup();\n for (const permission of this._pendingDeletes) {\n if (permission.IsSaved) {\n // only delete records previously saved, sometimes a user adds a new permission and deletes it before saving it\n permission.TransactionGroup = tg;\n if (!await permission.Delete()) { // we use await here because the promise will resolve before the actual save occurs --- the internals will not call the network until tg.Submit() below\n // validation errors come back here\n if (this.ShowUserErrorMessages)\n MJNotificationService.Instance.CreateSimpleNotification('Error saving permissions', 'error', 2500);\n\n LogError('Error deleting permission record in the transaction group: ' + permission.LatestResult.CompleteMessage);\n return false;\n } \n } \n }\n\n // next add new permissions by saving them in the transaction group\n for (const permission of this._pendingAdds) {\n if (this._pendingDeletes.includes(permission)) {\n // don't save a permission record that is new, if it was also marked for deletion\n permission.TransactionGroup = tg;\n if (!await permission.Save()) { \n // validation errors come back here\n if (this.ShowUserErrorMessages)\n MJNotificationService.Instance.CreateSimpleNotification('Error saving permissions', 'error', 2500);\n\n LogError('Error saving permission record in the transaction group: ' + permission.LatestResult.CompleteMessage); \n return false;\n }\n }\n }\n\n // now save the existing permissions\n for (const permission of this.resourcePermissions) {\n // make sure not in the delete array\n if (!this._pendingDeletes.includes(permission)) {\n permission.TransactionGroup = tg;\n if (!await permission.Save()) { \n // validation errors come back here\n if (this.ShowUserErrorMessages)\n MJNotificationService.Instance.CreateSimpleNotification('Error saving permissions', 'error', 2500);\n\n LogError('Error saving permission record in the transaction group: ' + permission.LatestResult.CompleteMessage);\n return false;\n }\n }\n }\n\n // now save the changes\n if (await tg.Submit()) {\n this._Loading = false;\n this._pendingDeletes = [];\n this._pendingAdds = [];\n const engine = this.GetEngine();\n await engine.RefreshAllItems(); // refresh the permissions cache\n return true;\n }\n else {\n // we had an error, show the user via SharedService\n this._Loading = false;\n if (this.ShowUserErrorMessages)\n MJNotificationService.Instance.CreateSimpleNotification('Error saving permissions', 'error', );\n \n LogError('Error saving permissions in the transaction group');\n return false;\n }\n }\n\n protected GetEngine(): ResourcePermissionEngine {\n return <ResourcePermissionEngine>ResourcePermissionEngine.GetProviderInstance(this.ProviderToUse, ResourcePermissionEngine);\n }\n}\n","<div class=\"container\">\n @if(_Loading) {\n <mj-loading [showText]=\"false\" size=\"medium\"></mj-loading>\n }\n @if(ShowSaveButton) {\n <button mjButton (click)=\"SavePermissions()\">Save</button>\n }\n <div class=\"table-container\">\n @if(AllowAddPermissions) {\n <div class=\"add-permission-section\">\n <span class=\"add-permission-label\">Add Permission</span>\n <mj-dropdown\n [Data]=\"PermissionTypes\"\n [(ngModel)]=\"SelectedType\"\n style=\"width: 100px;\">\n </mj-dropdown>\n @if (SelectedType === 'User') {\n <mj-dropdown\n [Data]=\"AllUsers\"\n [(ngModel)]=\"SelectedUser\"\n TextField=\"Name\"\n ValueField=\"ID\"\n style=\"width: 225px;\">\n </mj-dropdown>\n }\n @else if (SelectedType === 'Role') {\n <mj-dropdown\n [Data]=\"AllRoles\"\n [(ngModel)]=\"SelectedRole\"\n TextField=\"Name\"\n ValueField=\"ID\"\n style=\"width: 150px;\">\n </mj-dropdown>\n }\n @else {\n SelectedType: {{ SelectedType }}\n }\n @if (ShowPermissionLevels) {\n <mj-dropdown\n [Data]=\"PermissionLevels\"\n [(ngModel)]=\"SelectedPermissionLevel\"\n style=\"width: 100px;\">\n </mj-dropdown>\n }\n <button mjButton (click)=\"addPermission()\" [disabled]=\"permissionAlreadyExists()\" [title]=\"permissionAlreadyExists() ? 'This combination of Type/User/Role already exists below' : ''\" >Add</button>\n </div>\n }\n <table class=\"resource-table\">\n <thead>\n <tr>\n <th>Type</th>\n <th>Name</th>\n @if (ShowPermissionLevels) {\n <th>Level</th>\n }\n @if(AllowDeletePermissions) {\n <th>Actions</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (p of resourcePermissions; track p) {\n <tr>\n <td>{{ p.Type }}</td>\n <td>{{ p.Type === 'User' ? p.User : p.Role }}</td>\n @if (ShowPermissionLevels) {\n <td>\n @if (AllowEditPermissions) {\n <mj-dropdown\n [(ngModel)]=\"p.PermissionLevel\"\n [Data]=\"PermissionLevels\"\n style=\"width: 100px;\">\n </mj-dropdown>\n }\n @else {\n {{ p.PermissionLevel }}\n }\n </td>\n }\n @if(AllowDeletePermissions) {\n <td>\n <button mjButton aria-label=\"Delete permission\" title=\"Delete permission\" (click)=\"deletePermission(p)\"><span class=\"fa-solid fa-trash-can\"></span></button>\n </td>\n }\n </tr> \n }\n </tbody>\n </table>\n </div>\n</div>\n"]}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { BaseEntity } from '@memberjunction/core';
|
|
2
|
+
import { MJUserEntity } from '@memberjunction/core-entities';
|
|
3
|
+
/** Three permission tiers used across every share dialog: view-only, modify, full control. */
|
|
4
|
+
export type ResourceShareLevel = 'View' | 'Edit' | 'Owner';
|
|
5
|
+
/**
|
|
6
|
+
* Ordered list used by the dialog to render the level selector. Exposed so
|
|
7
|
+
* adapters or tests can reference it without re-declaring the enum.
|
|
8
|
+
*/
|
|
9
|
+
export declare const RESOURCE_SHARE_LEVELS: ResourceShareLevel[];
|
|
10
|
+
/**
|
|
11
|
+
* A single share row displayed in {@link GenericShareDialogComponent}. The
|
|
12
|
+
* dialog treats every resource type uniformly with a three-tier permission
|
|
13
|
+
* model — adapters translate the `Level` field to whatever shape their
|
|
14
|
+
* backing entity actually stores (e.g., `MJResourcePermissionEntity.PermissionLevel`
|
|
15
|
+
* is a direct match; `MJDashboardPermissionEntity` maps to a combination of
|
|
16
|
+
* `Can*` booleans).
|
|
17
|
+
*/
|
|
18
|
+
export interface ResourceSharePermissionModel {
|
|
19
|
+
/** BaseEntity instance to persist on save / delete on remove. */
|
|
20
|
+
PermissionEntity: BaseEntity;
|
|
21
|
+
UserID: string;
|
|
22
|
+
User: MJUserEntity;
|
|
23
|
+
/** Current permission tier shown in the dialog. */
|
|
24
|
+
Level: ResourceShareLevel;
|
|
25
|
+
/** `true` if this row was added in the current dialog session (no DB row yet). */
|
|
26
|
+
IsNew: boolean;
|
|
27
|
+
/** `true` if the user clicked the trash icon; will be deleted on save. */
|
|
28
|
+
MarkedForRemoval: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Snapshot of `Level` captured when the row was first created/loaded.
|
|
31
|
+
* Populated by the dialog; used by `HasChanges` to detect user edits.
|
|
32
|
+
*/
|
|
33
|
+
_InitialLevel?: ResourceShareLevel;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Per-resource context passed to every adapter call. Kept small and serializable
|
|
37
|
+
* so the generic dialog can stay resource-type-agnostic.
|
|
38
|
+
*/
|
|
39
|
+
export interface ResourceShareContext {
|
|
40
|
+
/** Primary key of the resource being shared. */
|
|
41
|
+
ResourceID: string;
|
|
42
|
+
/** Display name used in the dialog title (`Share "{{ResourceName}}"`). */
|
|
43
|
+
ResourceName: string;
|
|
44
|
+
/** UserID of the resource owner (excluded from the "add people" list). */
|
|
45
|
+
OwnerUserID?: string | null;
|
|
46
|
+
/** Owner's display name, shown in the static "Owner" row. */
|
|
47
|
+
OwnerDisplayName?: string | null;
|
|
48
|
+
/** UserID of the person currently using the dialog (captured on save as grantor). */
|
|
49
|
+
CurrentUserID?: string | null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Contract implemented by per-resource adapters that plug into
|
|
53
|
+
* {@link GenericShareDialogComponent}. The dialog owns the UX (user search,
|
|
54
|
+
* level selector, mark-for-removal); the adapter owns persistence.
|
|
55
|
+
*/
|
|
56
|
+
export interface ResourceShareAdapter {
|
|
57
|
+
/** Load existing share rows for the resource. Owner is NOT included here. */
|
|
58
|
+
LoadShares(context: ResourceShareContext): Promise<ResourceSharePermissionModel[]>;
|
|
59
|
+
/**
|
|
60
|
+
* Create an un-saved {@link ResourceSharePermissionModel} for `user`, defaulting
|
|
61
|
+
* the level to `View`. The returned row's `PermissionEntity` must be a valid
|
|
62
|
+
* BaseEntity pre-populated with everything except the level.
|
|
63
|
+
*/
|
|
64
|
+
CreateShare(context: ResourceShareContext, user: MJUserEntity): Promise<ResourceSharePermissionModel>;
|
|
65
|
+
/**
|
|
66
|
+
* Apply the current `Level` back onto the adapter's underlying entity shape
|
|
67
|
+
* before the dialog calls `.Save()`. For `MJResourcePermission`-backed
|
|
68
|
+
* resources this is a direct `PermissionLevel =` assignment; for
|
|
69
|
+
* `MJDashboardPermission` it translates to the four `Can*` booleans.
|
|
70
|
+
*/
|
|
71
|
+
SyncLevelToEntity(row: ResourceSharePermissionModel): void;
|
|
72
|
+
/**
|
|
73
|
+
* Called after all saves/deletes succeed — a hook for cache refresh
|
|
74
|
+
* (e.g., `DashboardEngine.Config(true)`). Optional.
|
|
75
|
+
*/
|
|
76
|
+
AfterSave?(context: ResourceShareContext): Promise<void>;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=resource-share-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-share-adapter.d.ts","sourceRoot":"","sources":["../../src/lib/resource-share-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,8FAA8F;AAC9F,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,EAA8B,CAAC;AAErF;;;;;;;GAOG;AACH,MAAM,WAAW,4BAA4B;IACzC,iEAAiE;IACjE,gBAAgB,EAAE,UAAU,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,CAAC;IACnB,mDAAmD;IACnD,KAAK,EAAE,kBAAkB,CAAC;IAC1B,kFAAkF;IAClF,KAAK,EAAE,OAAO,CAAC;IACf,0EAA0E;IAC1E,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACjC,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,6EAA6E;IAC7E,UAAU,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,4BAA4B,EAAE,CAAC,CAAC;IAEnF;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAEtG;;;;;OAKG;IACH,iBAAiB,CAAC,GAAG,EAAE,4BAA4B,GAAG,IAAI,CAAC;IAE3D;;;OAGG;IACH,SAAS,CAAC,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ordered list used by the dialog to render the level selector. Exposed so
|
|
3
|
+
* adapters or tests can reference it without re-declaring the enum.
|
|
4
|
+
*/
|
|
5
|
+
export const RESOURCE_SHARE_LEVELS = ['View', 'Edit', 'Owner'];
|
|
6
|
+
//# sourceMappingURL=resource-share-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-share-adapter.js","sourceRoot":"","sources":["../../src/lib/resource-share-adapter.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import { BaseEntity } from '@memberjunction/core';\nimport { MJUserEntity } from '@memberjunction/core-entities';\n\n/** Three permission tiers used across every share dialog: view-only, modify, full control. */\nexport type ResourceShareLevel = 'View' | 'Edit' | 'Owner';\n\n/**\n * Ordered list used by the dialog to render the level selector. Exposed so\n * adapters or tests can reference it without re-declaring the enum.\n */\nexport const RESOURCE_SHARE_LEVELS: ResourceShareLevel[] = ['View', 'Edit', 'Owner'];\n\n/**\n * A single share row displayed in {@link GenericShareDialogComponent}. The\n * dialog treats every resource type uniformly with a three-tier permission\n * model — adapters translate the `Level` field to whatever shape their\n * backing entity actually stores (e.g., `MJResourcePermissionEntity.PermissionLevel`\n * is a direct match; `MJDashboardPermissionEntity` maps to a combination of\n * `Can*` booleans).\n */\nexport interface ResourceSharePermissionModel {\n /** BaseEntity instance to persist on save / delete on remove. */\n PermissionEntity: BaseEntity;\n UserID: string;\n User: MJUserEntity;\n /** Current permission tier shown in the dialog. */\n Level: ResourceShareLevel;\n /** `true` if this row was added in the current dialog session (no DB row yet). */\n IsNew: boolean;\n /** `true` if the user clicked the trash icon; will be deleted on save. */\n MarkedForRemoval: boolean;\n /**\n * Snapshot of `Level` captured when the row was first created/loaded.\n * Populated by the dialog; used by `HasChanges` to detect user edits.\n */\n _InitialLevel?: ResourceShareLevel;\n}\n\n/**\n * Per-resource context passed to every adapter call. Kept small and serializable\n * so the generic dialog can stay resource-type-agnostic.\n */\nexport interface ResourceShareContext {\n /** Primary key of the resource being shared. */\n ResourceID: string;\n /** Display name used in the dialog title (`Share \"{{ResourceName}}\"`). */\n ResourceName: string;\n /** UserID of the resource owner (excluded from the \"add people\" list). */\n OwnerUserID?: string | null;\n /** Owner's display name, shown in the static \"Owner\" row. */\n OwnerDisplayName?: string | null;\n /** UserID of the person currently using the dialog (captured on save as grantor). */\n CurrentUserID?: string | null;\n}\n\n/**\n * Contract implemented by per-resource adapters that plug into\n * {@link GenericShareDialogComponent}. The dialog owns the UX (user search,\n * level selector, mark-for-removal); the adapter owns persistence.\n */\nexport interface ResourceShareAdapter {\n /** Load existing share rows for the resource. Owner is NOT included here. */\n LoadShares(context: ResourceShareContext): Promise<ResourceSharePermissionModel[]>;\n\n /**\n * Create an un-saved {@link ResourceSharePermissionModel} for `user`, defaulting\n * the level to `View`. The returned row's `PermissionEntity` must be a valid\n * BaseEntity pre-populated with everything except the level.\n */\n CreateShare(context: ResourceShareContext, user: MJUserEntity): Promise<ResourceSharePermissionModel>;\n\n /**\n * Apply the current `Level` back onto the adapter's underlying entity shape\n * before the dialog calls `.Save()`. For `MJResourcePermission`-backed\n * resources this is a direct `PermissionLevel =` assignment; for\n * `MJDashboardPermission` it translates to the four `Can*` booleans.\n */\n SyncLevelToEntity(row: ResourceSharePermissionModel): void;\n\n /**\n * Called after all saves/deletes succeed — a hook for cache refresh\n * (e.g., `DashboardEngine.Config(true)`). Optional.\n */\n AfterSave?(context: ResourceShareContext): Promise<void>;\n}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { EventEmitter, OnChanges, SimpleChanges, ChangeDetectorRef } from '@angular/core';
|
|
2
|
+
import { MJUserEntity } from '@memberjunction/core-entities';
|
|
3
|
+
import { ResourceShareAdapter, ResourceShareContext, ResourceShareLevel, ResourceSharePermissionModel } from './resource-share-adapter';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Result emitted when {@link GenericShareDialogComponent} closes.
|
|
7
|
+
*/
|
|
8
|
+
export interface ResourceShareDialogResult {
|
|
9
|
+
Action: 'save' | 'cancel';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resource-type-agnostic share dialog. Every resource's sharing UX collapses to
|
|
13
|
+
* three tiers — View / Edit / Owner — so the dialog exposes a single level
|
|
14
|
+
* selector per grantee rather than a grab bag of `Can*` checkboxes. Adapters
|
|
15
|
+
* translate the level to whatever shape their backing entity actually persists.
|
|
16
|
+
*/
|
|
17
|
+
export declare class GenericShareDialogComponent implements OnChanges {
|
|
18
|
+
private cdr;
|
|
19
|
+
Visible: boolean;
|
|
20
|
+
Context: ResourceShareContext | null;
|
|
21
|
+
Adapter: ResourceShareAdapter | null;
|
|
22
|
+
Result: EventEmitter<ResourceShareDialogResult>;
|
|
23
|
+
readonly Levels: ResourceShareLevel[];
|
|
24
|
+
UserShares: ResourceSharePermissionModel[];
|
|
25
|
+
AvailableUsers: MJUserEntity[];
|
|
26
|
+
private allUsers;
|
|
27
|
+
IsLoading: boolean;
|
|
28
|
+
Error: string | null;
|
|
29
|
+
UserSearchFilter: string;
|
|
30
|
+
constructor(cdr: ChangeDetectorRef);
|
|
31
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
32
|
+
private resetDialog;
|
|
33
|
+
private loadData;
|
|
34
|
+
private updateAvailableUsers;
|
|
35
|
+
get FilteredAvailableUsers(): MJUserEntity[];
|
|
36
|
+
get HasChanges(): boolean;
|
|
37
|
+
get ActiveShares(): ResourceSharePermissionModel[];
|
|
38
|
+
get RemovedShares(): ResourceSharePermissionModel[];
|
|
39
|
+
/** Highlight rows whose level has been changed from their loaded state. */
|
|
40
|
+
isModified(share: ResourceSharePermissionModel): boolean;
|
|
41
|
+
addUserShare(user: MJUserEntity): Promise<void>;
|
|
42
|
+
removeUserShare(share: ResourceSharePermissionModel): void;
|
|
43
|
+
undoRemove(share: ResourceSharePermissionModel): void;
|
|
44
|
+
setLevel(share: ResourceSharePermissionModel, level: ResourceShareLevel): void;
|
|
45
|
+
onSave(): Promise<void>;
|
|
46
|
+
onCancel(): void;
|
|
47
|
+
getUserInitials(user: MJUserEntity): string;
|
|
48
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<GenericShareDialogComponent, never>;
|
|
49
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<GenericShareDialogComponent, "mj-resource-share-dialog", never, { "Visible": { "alias": "Visible"; "required": false; }; "Context": { "alias": "Context"; "required": false; }; "Adapter": { "alias": "Adapter"; "required": false; }; }, { "Result": "Result"; }, never, never, false, never>;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=resource-share-dialog.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-share-dialog.component.d.ts","sourceRoot":"","sources":["../../src/lib/resource-share-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,iBAAiB,EAAqB,MAAM,eAAe,CAAC;AAEvI,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAEH,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,4BAA4B,EAC/B,MAAM,0BAA0B,CAAC;;AAElC;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACtC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC7B;AAED;;;;;GAKG;AACH,qBAOa,2BAA4B,YAAW,SAAS;IAgB7C,OAAO,CAAC,GAAG;IAfd,OAAO,UAAS;IAChB,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAQ;IAC5C,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAQ;IAC3C,MAAM,0CAAiD;IAEjE,SAAgB,MAAM,uBAAyB;IAExC,UAAU,EAAE,4BAA4B,EAAE,CAAM;IAChD,cAAc,EAAE,YAAY,EAAE,CAAM;IAC3C,OAAO,CAAC,QAAQ,CAAsB;IAE/B,SAAS,UAAS;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC5B,gBAAgB,SAAM;gBAET,GAAG,EAAE,iBAAiB;IAE1C,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAOzC,OAAO,CAAC,WAAW;YAQL,QAAQ;IA4BtB,OAAO,CAAC,oBAAoB;IAY5B,IAAW,sBAAsB,IAAI,YAAY,EAAE,CAQlD;IAED,IAAW,UAAU,IAAI,OAAO,CAI/B;IAED,IAAW,YAAY,IAAI,4BAA4B,EAAE,CAExD;IAED,IAAW,aAAa,IAAI,4BAA4B,EAAE,CAEzD;IAED,2EAA2E;IACpE,UAAU,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO;IAIlD,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrD,eAAe,CAAC,KAAK,EAAE,4BAA4B,GAAG,IAAI;IAU1D,UAAU,CAAC,KAAK,EAAE,4BAA4B,GAAG,IAAI;IAMrD,QAAQ,CAAC,KAAK,EAAE,4BAA4B,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAKxE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAmD7B,QAAQ,IAAI,IAAI;IAIhB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM;yCA5LzC,2BAA2B;2CAA3B,2BAA2B;CAoMvC"}
|