@memberjunction/ng-explorer-settings 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.
Files changed (77) hide show
  1. package/dist/lib/account-info/account-info.component.d.ts +1 -1
  2. package/dist/lib/account-info/account-info.component.js +2 -2
  3. package/dist/lib/account-info/account-info.component.js.map +1 -1
  4. package/dist/lib/application-management/application-dialog/application-dialog.component.d.ts +93 -10
  5. package/dist/lib/application-management/application-dialog/application-dialog.component.d.ts.map +1 -1
  6. package/dist/lib/application-management/application-dialog/application-dialog.component.js +232 -80
  7. package/dist/lib/application-management/application-dialog/application-dialog.component.js.map +1 -1
  8. package/dist/lib/application-management/application-management.component.d.ts +94 -11
  9. package/dist/lib/application-management/application-management.component.d.ts.map +1 -1
  10. package/dist/lib/application-management/application-management.component.js +231 -67
  11. package/dist/lib/application-management/application-management.component.js.map +1 -1
  12. package/dist/lib/application-settings/application-settings.component.d.ts +4 -4
  13. package/dist/lib/application-settings/application-settings.component.js +10 -10
  14. package/dist/lib/application-settings/application-settings.component.js.map +1 -1
  15. package/dist/lib/entity-permissions/entity-permissions.component.d.ts +88 -10
  16. package/dist/lib/entity-permissions/entity-permissions.component.d.ts.map +1 -1
  17. package/dist/lib/entity-permissions/entity-permissions.component.js +219 -63
  18. package/dist/lib/entity-permissions/entity-permissions.component.js.map +1 -1
  19. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.d.ts +44 -6
  20. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.d.ts.map +1 -1
  21. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js +117 -43
  22. package/dist/lib/entity-permissions/permission-dialog/permission-dialog.component.js.map +1 -1
  23. package/dist/lib/notification-preferences/notification-preferences.component.d.ts +25 -3
  24. package/dist/lib/notification-preferences/notification-preferences.component.d.ts.map +1 -1
  25. package/dist/lib/notification-preferences/notification-preferences.component.js +62 -18
  26. package/dist/lib/notification-preferences/notification-preferences.component.js.map +1 -1
  27. package/dist/lib/role-management/role-dialog/role-dialog.component.d.ts +32 -4
  28. package/dist/lib/role-management/role-dialog/role-dialog.component.d.ts.map +1 -1
  29. package/dist/lib/role-management/role-dialog/role-dialog.component.js +84 -30
  30. package/dist/lib/role-management/role-dialog/role-dialog.component.js.map +1 -1
  31. package/dist/lib/role-management/role-management-agent-context.d.ts +12 -4
  32. package/dist/lib/role-management/role-management-agent-context.d.ts.map +1 -1
  33. package/dist/lib/role-management/role-management-agent-context.js +26 -10
  34. package/dist/lib/role-management/role-management-agent-context.js.map +1 -1
  35. package/dist/lib/role-management/role-management.component.d.ts +95 -11
  36. package/dist/lib/role-management/role-management.component.d.ts.map +1 -1
  37. package/dist/lib/role-management/role-management.component.js +259 -91
  38. package/dist/lib/role-management/role-management.component.js.map +1 -1
  39. package/dist/lib/settings/settings.component.d.ts +87 -11
  40. package/dist/lib/settings/settings.component.d.ts.map +1 -1
  41. package/dist/lib/settings/settings.component.js +211 -65
  42. package/dist/lib/settings/settings.component.js.map +1 -1
  43. package/dist/lib/shared/settings-card.component.d.ts +24 -4
  44. package/dist/lib/shared/settings-card.component.d.ts.map +1 -1
  45. package/dist/lib/shared/settings-card.component.js +46 -6
  46. package/dist/lib/shared/settings-card.component.js.map +1 -1
  47. package/dist/lib/sql-logging/sql-logging.component.d.ts +172 -18
  48. package/dist/lib/sql-logging/sql-logging.component.d.ts.map +1 -1
  49. package/dist/lib/sql-logging/sql-logging.component.js +320 -108
  50. package/dist/lib/sql-logging/sql-logging.component.js.map +1 -1
  51. package/dist/lib/user-app-config/user-app-config-content.component.js +3 -3
  52. package/dist/lib/user-app-config/user-app-config-content.component.js.map +1 -1
  53. package/dist/lib/user-app-config/user-app-config-reorder.d.ts +4 -0
  54. package/dist/lib/user-app-config/user-app-config-reorder.d.ts.map +1 -1
  55. package/dist/lib/user-app-config/user-app-config-reorder.js +11 -3
  56. package/dist/lib/user-app-config/user-app-config-reorder.js.map +1 -1
  57. package/dist/lib/user-management/transaction-group-refusals.d.ts +45 -0
  58. package/dist/lib/user-management/transaction-group-refusals.d.ts.map +1 -0
  59. package/dist/lib/user-management/transaction-group-refusals.js +49 -0
  60. package/dist/lib/user-management/transaction-group-refusals.js.map +1 -0
  61. package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts +44 -6
  62. package/dist/lib/user-management/user-dialog/user-dialog.component.d.ts.map +1 -1
  63. package/dist/lib/user-management/user-dialog/user-dialog.component.js +134 -45
  64. package/dist/lib/user-management/user-dialog/user-dialog.component.js.map +1 -1
  65. package/dist/lib/user-management/user-management-agent-context.d.ts +10 -0
  66. package/dist/lib/user-management/user-management-agent-context.d.ts.map +1 -1
  67. package/dist/lib/user-management/user-management-agent-context.js +26 -6
  68. package/dist/lib/user-management/user-management-agent-context.js.map +1 -1
  69. package/dist/lib/user-management/user-management.component.d.ts +174 -16
  70. package/dist/lib/user-management/user-management.component.d.ts.map +1 -1
  71. package/dist/lib/user-management/user-management.component.js +501 -177
  72. package/dist/lib/user-management/user-management.component.js.map +1 -1
  73. package/dist/lib/user-profile-settings/user-profile-settings.component.d.ts +97 -15
  74. package/dist/lib/user-profile-settings/user-profile-settings.component.d.ts.map +1 -1
  75. package/dist/lib/user-profile-settings/user-profile-settings.component.js +280 -116
  76. package/dist/lib/user-profile-settings/user-profile-settings.component.js.map +1 -1
  77. package/package.json +20 -20
@@ -166,19 +166,51 @@ function RoleDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
166
166
  i0.ɵɵconditional(ctx_r1.isLoading ? 49 : 50);
167
167
  } }
168
168
  export class RoleDialogComponent extends BaseAngularComponent {
169
- data = null;
170
- visible = false;
171
- result = new EventEmitter();
169
+ Data = null;
170
+ /** @deprecated Use {@link Data}. */
171
+ set data(value) {
172
+ this.Data = value;
173
+ }
174
+ /** @deprecated Use {@link Data}. */
175
+ get data() {
176
+ return this.Data;
177
+ }
178
+ Visible = false;
179
+ /** @deprecated Use {@link Visible}. */
180
+ set visible(value) {
181
+ this.Visible = value;
182
+ }
183
+ /** @deprecated Use {@link Visible}. */
184
+ get visible() {
185
+ return this.Visible;
186
+ }
187
+ Result = new EventEmitter();
188
+ /**
189
+ * @deprecated Use {@link Result}.
190
+ *
191
+ * The same emitter under the old binding name, so a template still binding
192
+ * (result) keeps working. Must stay AFTER Result: class fields
193
+ * initialise in order, and the other way round this captures undefined.
194
+ */
195
+ result = this.Result;
172
196
  fb = inject(FormBuilder);
173
197
  cdr = inject(ChangeDetectorRef);
174
198
  ngZone = inject(NgZone);
175
199
  get metadata() { return this.ProviderToUse; }
176
- roleForm;
200
+ RoleForm;
201
+ /** @deprecated Use {@link RoleForm}. */
202
+ get roleForm() {
203
+ return this.RoleForm;
204
+ }
205
+ /** @deprecated Use {@link RoleForm}. */
206
+ set roleForm(value) {
207
+ this.RoleForm = value;
208
+ }
177
209
  isLoading = false;
178
210
  error = null;
179
211
  constructor() {
180
212
  super();
181
- this.roleForm = this.fb.group({
213
+ this.RoleForm = this.fb.group({
182
214
  name: ['', [Validators.required, Validators.maxLength(50)]],
183
215
  description: [''],
184
216
  directoryId: ['']
@@ -188,11 +220,11 @@ export class RoleDialogComponent extends BaseAngularComponent {
188
220
  // Initial setup
189
221
  }
190
222
  ngOnChanges(changes) {
191
- if (changes['data'] && this.data?.role && this.isEditMode) {
223
+ if (changes['data'] && this.Data?.role && this.IsEditMode) {
192
224
  this.loadRoleData();
193
225
  }
194
226
  // Reset form if switching to create mode or dialog becomes visible
195
- if (changes['visible'] && this.visible && !this.isEditMode) {
227
+ if (changes['visible'] && this.Visible && !this.IsEditMode) {
196
228
  this.resetForm();
197
229
  }
198
230
  }
@@ -200,7 +232,7 @@ export class RoleDialogComponent extends BaseAngularComponent {
200
232
  // Cleanup if needed
201
233
  }
202
234
  resetForm() {
203
- this.roleForm.reset({
235
+ this.RoleForm.reset({
204
236
  name: '',
205
237
  description: '',
206
238
  directoryId: ''
@@ -208,48 +240,60 @@ export class RoleDialogComponent extends BaseAngularComponent {
208
240
  this.error = null;
209
241
  }
210
242
  onEscapeKey(event) {
211
- if (this.visible) {
243
+ if (this.Visible) {
212
244
  this.onCancel();
213
245
  }
214
246
  }
247
+ get WindowTitle() {
248
+ return this.IsEditMode ? 'Edit Role' : 'Create New Role';
249
+ }
250
+ /** @deprecated Use {@link WindowTitle}. */
215
251
  get windowTitle() {
216
- return this.isEditMode ? 'Edit Role' : 'Create New Role';
252
+ return this.WindowTitle;
217
253
  }
254
+ get IsEditMode() {
255
+ return this.Data?.mode === 'edit';
256
+ }
257
+ /** @deprecated Use {@link IsEditMode}. */
218
258
  get isEditMode() {
219
- return this.data?.mode === 'edit';
259
+ return this.IsEditMode;
220
260
  }
221
- get isSystemRole() {
222
- if (!this.data?.role)
261
+ get IsSystemRole() {
262
+ if (!this.Data?.role)
223
263
  return false;
224
264
  const systemRoleNames = ['Administrator', 'User', 'Guest', 'Developer'];
225
- return systemRoleNames.includes(this.data.role.Name || '');
265
+ return systemRoleNames.includes(this.Data.role.Name || '');
266
+ }
267
+ /** @deprecated Use {@link IsSystemRole}. */
268
+ get isSystemRole() {
269
+ return this.IsSystemRole;
226
270
  }
227
271
  loadRoleData() {
228
- if (!this.data?.role)
272
+ if (!this.Data?.role)
229
273
  return;
230
- const role = this.data.role;
231
- this.roleForm.patchValue({
274
+ const role = this.Data.role;
275
+ this.RoleForm.patchValue({
232
276
  name: role.Name,
233
277
  description: role.Description,
234
278
  directoryId: role.DirectoryID
235
279
  });
236
280
  // Disable name editing for system roles
237
- if (this.isSystemRole) {
238
- this.roleForm.get('name')?.disable();
281
+ if (this.IsSystemRole) {
282
+ this.RoleForm.get('name')?.disable();
239
283
  }
240
284
  }
241
- async onSubmit() {
242
- if (this.roleForm.invalid) {
243
- this.markFormGroupTouched(this.roleForm);
285
+ async OnSubmit() {
286
+ if (this.RoleForm.invalid) {
287
+ this.markFormGroupTouched(this.RoleForm);
244
288
  return;
245
289
  }
246
290
  this.isLoading = true;
247
291
  this.error = null;
248
292
  try {
249
293
  let role;
250
- if (this.isEditMode && this.data?.role) {
294
+ if (this.IsEditMode && this.Data?.role) {
251
295
  // Edit existing role
252
- role = this.data.role;
296
+ role = this.Data.role;
253
297
  }
254
298
  else {
255
299
  // Create new role
@@ -257,9 +301,9 @@ export class RoleDialogComponent extends BaseAngularComponent {
257
301
  role.NewRecord();
258
302
  }
259
303
  // Update role properties
260
- const formValue = this.roleForm.value;
304
+ const formValue = this.RoleForm.value;
261
305
  // Only update name if not a system role
262
- if (!this.isSystemRole) {
306
+ if (!this.IsSystemRole) {
263
307
  role.Name = formValue.name;
264
308
  }
265
309
  role.Description = formValue.description;
@@ -269,7 +313,7 @@ export class RoleDialogComponent extends BaseAngularComponent {
269
313
  if (!saveResult) {
270
314
  throw new Error(role.LatestResult?.Message || 'Failed to save role');
271
315
  }
272
- this.result.emit({ action: 'save', role });
316
+ this.Result.emit({ action: 'save', role });
273
317
  }
274
318
  catch (error) {
275
319
  console.error('Error saving role:', error);
@@ -285,8 +329,12 @@ export class RoleDialogComponent extends BaseAngularComponent {
285
329
  });
286
330
  }
287
331
  }
332
+ /** @deprecated Use {@link OnSubmit}. */
333
+ async onSubmit() {
334
+ return this.OnSubmit();
335
+ }
288
336
  onCancel() {
289
- this.result.emit({ action: 'cancel' });
337
+ this.Result.emit({ action: 'cancel' });
290
338
  }
291
339
  markFormGroupTouched(formGroup) {
292
340
  Object.keys(formGroup.controls).forEach(key => {
@@ -297,7 +345,7 @@ export class RoleDialogComponent extends BaseAngularComponent {
297
345
  static ɵfac = function RoleDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RoleDialogComponent)(); };
298
346
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RoleDialogComponent, selectors: [["mj-role-dialog"]], hostBindings: function RoleDialogComponent_HostBindings(rf, ctx) { if (rf & 1) {
299
347
  i0.ɵɵlistener("keydown.escape", function RoleDialogComponent_keydown_escape_HostBindingHandler($event) { return ctx.onEscapeKey($event); }, i0.ɵɵresolveDocument);
300
- } }, inputs: { data: "data", visible: "visible" }, outputs: { result: "result" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [[1, "modal-backdrop"], [1, "modal-backdrop", 3, "click"], [1, "modal-dialog", 3, "click"], [1, "modal-header"], [1, "dialog-header"], [1, "dialog-title"], [1, "fa-solid", "fa-shield-halved"], [1, "dialog-subtitle"], ["type", "button", "aria-label", "Close dialog", 1, "modal-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "modal-body"], [3, "ngSubmit", "formGroup"], [1, "content-section"], [1, "form-section"], [1, "section-header"], [1, "section-title"], [1, "section-description"], [1, "form-grid"], [1, "form-field"], ["for", "name", 1, "field-label", "required"], ["id", "name", "type", "text", "formControlName", "name", "placeholder", "Sales Manager", 1, "field-input"], [1, "field-error"], ["for", "description", 1, "field-label"], ["id", "description", "formControlName", "description", "placeholder", "Describe the role's purpose and responsibilities...", "rows", "4", 1, "field-textarea"], [1, "field-hint"], [1, "fa-solid", "fa-cog"], ["Variant", "warning", "Title", "System Role", "Message", "This is a system-defined role. Some properties may be limited for editing to maintain system integrity."], ["Variant", "info", "Title", "Custom Role", "Message", "This is a custom role that can be fully configured and modified."], [1, "modal-footer"], ["type", "submit", 1, "btn", "btn-primary", 3, "disabled"], ["type", "button", 1, "btn", "btn-secondary", 3, "click"], ["Variant", "error", 3, "Message"], [1, "fa-solid", "fa-exclamation-circle"], ["for", "directoryId", 1, "field-label"], ["id", "directoryId", "type", "text", "formControlName", "directoryId", "placeholder", "External directory identifier", 1, "field-input"], [1, "fa-solid", "fa-key"], ["Variant", "info", "Title", "Permission Management"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-save"]], template: function RoleDialogComponent_Template(rf, ctx) { if (rf & 1) {
348
+ } }, inputs: { Data: "Data", data: "data", Visible: "Visible", visible: "visible" }, outputs: { Result: "Result", result: "result" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [[1, "modal-backdrop"], [1, "modal-backdrop", 3, "click"], [1, "modal-dialog", 3, "click"], [1, "modal-header"], [1, "dialog-header"], [1, "dialog-title"], [1, "fa-solid", "fa-shield-halved"], [1, "dialog-subtitle"], ["type", "button", "aria-label", "Close dialog", 1, "modal-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "modal-body"], [3, "ngSubmit", "formGroup"], [1, "content-section"], [1, "form-section"], [1, "section-header"], [1, "section-title"], [1, "section-description"], [1, "form-grid"], [1, "form-field"], ["for", "name", 1, "field-label", "required"], ["id", "name", "type", "text", "formControlName", "name", "placeholder", "Sales Manager", 1, "field-input"], [1, "field-error"], ["for", "description", 1, "field-label"], ["id", "description", "formControlName", "description", "placeholder", "Describe the role's purpose and responsibilities...", "rows", "4", 1, "field-textarea"], [1, "field-hint"], [1, "fa-solid", "fa-cog"], ["Variant", "warning", "Title", "System Role", "Message", "This is a system-defined role. Some properties may be limited for editing to maintain system integrity."], ["Variant", "info", "Title", "Custom Role", "Message", "This is a custom role that can be fully configured and modified."], [1, "modal-footer"], ["type", "submit", 1, "btn", "btn-primary", 3, "disabled"], ["type", "button", 1, "btn", "btn-secondary", 3, "click"], ["Variant", "error", 3, "Message"], [1, "fa-solid", "fa-exclamation-circle"], ["for", "directoryId", 1, "field-label"], ["id", "directoryId", "type", "text", "formControlName", "directoryId", "placeholder", "External directory identifier", 1, "field-input"], [1, "fa-solid", "fa-key"], ["Variant", "info", "Title", "Permission Management"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-save"]], template: function RoleDialogComponent_Template(rf, ctx) { if (rf & 1) {
301
349
  i0.ɵɵconditionalCreate(0, RoleDialogComponent_Conditional_0_Template, 54, 12, "div", 0);
302
350
  } if (rf & 2) {
303
351
  i0.ɵɵconditional(ctx.visible ? 0 : -1);
@@ -306,10 +354,16 @@ export class RoleDialogComponent extends BaseAngularComponent {
306
354
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RoleDialogComponent, [{
307
355
  type: Component,
308
356
  args: [{ standalone: false, selector: 'mj-role-dialog', encapsulation: ViewEncapsulation.None, template: "<!-- MD3 Modal Dialog -->\n@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Modal Header with MJ Blue -->\n <div class=\"modal-header\">\n <div class=\"dialog-header\">\n <h2 class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n {{ isEditMode ? 'Edit Role' : 'Create New Role' }}\n </h2>\n <p class=\"dialog-subtitle\">\n {{ isEditMode ? 'Update role information and permissions' : 'Add a new role to the system' }}\n </p>\n </div>\n <button type=\"button\" class=\"modal-close\" (click)=\"onCancel()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"roleForm\" (ngSubmit)=\"onSubmit()\">\n @if (error) {\n <div class=\"content-section\">\n <mj-alert Variant=\"error\" [Message]=\"error\" />\n </div>\n }\n <!-- Basic Information Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n Role Information\n </h3>\n <p class=\"section-description\">Define the role's basic properties and purpose</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"name\">Role Name</label>\n <input\n id=\"name\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"Sales Manager\"\n [class.error]=\"roleForm.get('name')?.invalid && roleForm.get('name')?.touched\"\n />\n @if (roleForm.get('name')?.invalid && roleForm.get('name')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (roleForm.get('name')?.errors?.['required']) {\n Role name is required\n }\n @if (roleForm.get('name')?.errors?.['maxlength']) {\n Role name cannot exceed 50 characters\n }\n </div>\n }\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"description\">Description</label>\n <textarea\n id=\"description\"\n class=\"field-textarea\"\n formControlName=\"description\"\n placeholder=\"Describe the role's purpose and responsibilities...\"\n rows=\"4\"\n ></textarea>\n <div class=\"field-hint\">\n Provide a clear description of what this role is for and what permissions it should have.\n </div>\n </div>\n @if (isEditMode) {\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"directoryId\">Directory ID</label>\n <input\n id=\"directoryId\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"directoryId\"\n placeholder=\"External directory identifier\"\n />\n <div class=\"field-hint\">\n External directory identifier for syncing with Active Directory or other systems.\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Role Type Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n Role Type\n </h3>\n <p class=\"section-description\">System or custom role classification</p>\n </div>\n <div class=\"form-grid\">\n @if (isSystemRole) {\n <mj-alert Variant=\"warning\" Title=\"System Role\" Message=\"This is a system-defined role. Some properties may be limited for editing to maintain system integrity.\" />\n } @else {\n <mj-alert Variant=\"info\" Title=\"Custom Role\" Message=\"This is a custom role that can be fully configured and modified.\" />\n }\n </div>\n </div>\n </div>\n <!-- Permissions Preview Section -->\n @if (isEditMode) {\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-key\"></i>\n Permissions\n </h3>\n <p class=\"section-description\">Manage role permissions and access rights</p>\n </div>\n <div class=\"form-grid\">\n <mj-alert Variant=\"info\" Title=\"Permission Management\">\n Role permissions can be managed in the <strong>Permissions</strong> tab of the settings dashboard. Use that interface to configure specific access rights for this role.\n </mj-alert>\n </div>\n </div>\n </div>\n }\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"roleForm.invalid || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i>\n {{ isEditMode ? 'Update Role' : 'Create Role' }}\n }\n </button>\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n Cancel\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n", styles: ["/* ============================================\n Role Dialog Component\n Uses MJ Design Tokens (--mj-*)\n ============================================ */\n\n/* ============================================\n Modal Backdrop & Container\n ============================================ */\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1050;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-width: 850px;\n max-height: calc(100vh - 2rem);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: scale(0.95) translateY(20px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* ============================================\n Modal Header (MJ Blue)\n ============================================ */\n\n.modal-header {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n padding: 24px 32px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n flex-shrink: 0;\n}\n\n.dialog-header {\n flex: 1;\n min-width: 0;\n}\n\n.dialog-title {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.3;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n color: var(--mj-brand-on-primary);\n}\n\n.dialog-title i {\n font-size: 1.25rem;\n opacity: 0.95;\n}\n\n.dialog-subtitle {\n margin: 0.5rem 0 0 0;\n font-size: 0.875rem;\n opacity: 0.9;\n font-weight: 400;\n line-height: 1.4;\n}\n\n.modal-close {\n background: transparent;\n border: none;\n color: var(--mj-brand-on-primary);\n cursor: pointer;\n padding: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 40px;\n height: 40px;\n flex-shrink: 0;\n}\n\n.modal-close:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.modal-close:active {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(0.95);\n}\n\n.modal-close i {\n font-size: 1.25rem;\n}\n\n/* ============================================\n Modal Body\n ============================================ */\n\n.modal-body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 0;\n background: var(--mj-bg-page);\n}\n\n.modal-body::-webkit-scrollbar {\n width: 8px;\n}\n\n.modal-body::-webkit-scrollbar-track {\n background: var(--mj-bg-surface-sunken);\n}\n\n.modal-body::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n}\n\n.modal-body::-webkit-scrollbar-thumb:hover {\n background: var(--mj-color-neutral-400);\n}\n\n/* ============================================\n Form Structure\n ============================================ */\n\n.content-section {\n padding: 1.5rem 2rem;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.content-section:last-child {\n border-bottom: none;\n}\n\n.form-section {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.section-header {\n margin-bottom: 1rem;\n}\n\n.section-title {\n margin: 0 0 0.5rem 0;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.section-title i {\n font-size: 1.25rem;\n color: var(--mj-brand-primary);\n}\n\n.section-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* ============================================\n Form Grid Layout\n ============================================ */\n\n.form-grid {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n/* ============================================\n Form Fields\n ============================================ */\n\n.form-field {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.field-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.field-label.required::after {\n content: '*';\n color: var(--mj-status-error);\n margin-left: 0.25rem;\n}\n\n.field-input,\n.field-textarea {\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 0.875rem 1rem;\n font-size: 1rem;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: var(--mj-bg-page);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n width: 100%;\n box-sizing: border-box;\n}\n\n.field-input:hover:not(:disabled),\n.field-textarea:hover:not(:disabled) {\n border-color: var(--mj-color-neutral-400);\n}\n\n.field-input:focus,\n.field-textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-focus-ring);\n}\n\n.field-input:disabled,\n.field-textarea:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.field-input.error,\n.field-textarea.error {\n border-color: var(--mj-status-error);\n}\n\n.field-input.error:focus,\n.field-textarea.error:focus {\n --mj-ring-color: var(--mj-status-error);\n box-shadow: var(--mj-focus-ring);\n}\n\n.field-textarea {\n resize: vertical;\n min-height: 100px;\n line-height: 1.5;\n}\n\n.field-hint {\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n margin-top: 0.25rem;\n}\n\n.field-error {\n font-size: 0.75rem;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n}\n\n.field-error i {\n font-size: 0.875rem;\n}\n\n/* ============================================\n Modal Footer (Buttons)\n ============================================ */\n\n.modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 1rem;\n padding: 1.5rem 2rem;\n background: var(--mj-bg-surface-sunken);\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n/* ============================================\n Buttons\n ============================================ */\n\n.btn {\n padding: 0.75rem 1.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: var(--mj-radius-full);\n border: none;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n font-family: inherit;\n text-transform: none;\n letter-spacing: 0.01em;\n}\n\n.btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.btn:active:not(:disabled) {\n transform: scale(0.98);\n}\n\n.btn i {\n font-size: 1rem;\n}\n\n.btn i.fa-spinner {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Primary Button (MJ Blue - Dark Button) */\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-light);\n box-shadow: var(--mj-shadow-md);\n}\n\n.btn-primary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n box-shadow: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Secondary Button (Light Button) */\n.btn-secondary {\n background: var(--mj-bg-page);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-color-neutral-400);\n box-shadow: none;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.btn-secondary:disabled {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* ============================================\n Responsive Design\n ============================================ */\n\n@media (max-width: 768px) {\n .modal-backdrop {\n padding: 0;\n }\n\n .modal-dialog {\n max-width: 100%;\n max-height: 100vh;\n border-radius: 0;\n animation: slideInMobile 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideInMobile {\n from {\n opacity: 0;\n transform: translateY(100%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .modal-header {\n padding: 20px 16px;\n border-radius: 0;\n }\n\n .dialog-title {\n font-size: 1.25rem;\n }\n\n .dialog-subtitle {\n font-size: 0.8125rem;\n }\n\n .content-section {\n padding: 1.25rem 1rem;\n }\n\n .section-title {\n font-size: 1.125rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n .btn {\n width: 100%;\n justify-content: center;\n }\n}\n\n@media (max-width: 480px) {\n .modal-header {\n padding: 16px 12px;\n }\n\n .dialog-title {\n font-size: 1.125rem;\n gap: 0.5rem;\n }\n\n .dialog-title i {\n font-size: 1rem;\n }\n\n .dialog-subtitle {\n font-size: 0.75rem;\n margin-top: 0.25rem;\n }\n\n .content-section {\n padding: 1rem 0.75rem;\n }\n\n .section-title {\n font-size: 1rem;\n gap: 0.5rem;\n }\n\n .field-input,\n .field-textarea {\n padding: 0.75rem;\n font-size: 0.875rem;\n }\n\n .modal-footer {\n padding: 0.75rem;\n }\n\n .btn {\n padding: 0.625rem 1.25rem;\n font-size: 0.8125rem;\n }\n}\n\n/* ============================================\n Accessibility\n ============================================ */\n\n/* Focus Visible Styles */\n*:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* Reduced Motion Support */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n\n/* High Contrast Mode Support */\n@media (prefers-contrast: high) {\n .modal-dialog {\n border: 2px solid var(--mj-border-default);\n }\n\n .btn {\n border: 2px solid currentColor;\n }\n\n .field-input,\n .field-textarea {\n border-width: 3px;\n }\n}\n\n/* ============================================\n Print Styles\n ============================================ */\n\n@media print {\n .modal-backdrop {\n display: none;\n }\n}\n"] }]
309
- }], () => [], { data: [{
357
+ }], () => [], { Data: [{
358
+ type: Input
359
+ }], data: [{
360
+ type: Input
361
+ }], Visible: [{
310
362
  type: Input
311
363
  }], visible: [{
312
364
  type: Input
365
+ }], Result: [{
366
+ type: Output
313
367
  }], result: [{
314
368
  type: Output
315
369
  }], onEscapeKey: [{
@@ -1 +1 @@
1
- {"version":3,"file":"role-dialog.component.js","sourceRoot":"","sources":["../../../../src/lib/role-management/role-dialog/role-dialog.component.ts","../../../../src/lib/role-management/role-dialog/role-dialog.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, OnChanges, SimpleChanges, inject, HostListener, ViewEncapsulation, ChangeDetectorRef, NgZone } from '@angular/core';\n\nimport { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';\nimport { Metadata } from '@memberjunction/core';\nimport { MJRoleEntity } from '@memberjunction/core-entities';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nexport interface RoleDialogData {\n role?: MJRoleEntity;\n mode: 'create' | 'edit';\n}\n\nexport interface RoleDialogResult {\n action: 'save' | 'cancel';\n role?: MJRoleEntity;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-role-dialog',\n encapsulation: ViewEncapsulation.None,\n templateUrl: './role-dialog.component.html',\n styleUrls: ['./role-dialog.component.css']\n})\nexport class RoleDialogComponent extends BaseAngularComponent implements OnInit, OnDestroy, OnChanges {\n @Input() data: RoleDialogData | null = null;\n @Input() visible = false;\n @Output() result = new EventEmitter<RoleDialogResult>();\n\n private fb = inject(FormBuilder);\n private cdr = inject(ChangeDetectorRef);\n private ngZone = inject(NgZone);\n private get metadata() { return this.ProviderToUse; }\n public roleForm: FormGroup;\n public isLoading = false;\n public error: string | null = null;\n\n constructor() {\n super();\n this.roleForm = this.fb.group({\n name: ['', [Validators.required, Validators.maxLength(50)]],\n description: [''],\n directoryId: ['']\n });\n }\n\n ngOnInit(): void {\n // Initial setup\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['data'] && this.data?.role && this.isEditMode) {\n this.loadRoleData();\n }\n \n // Reset form if switching to create mode or dialog becomes visible\n if (changes['visible'] && this.visible && !this.isEditMode) {\n this.resetForm();\n }\n }\n\n ngOnDestroy(): void {\n // Cleanup if needed\n }\n\n private resetForm(): void {\n this.roleForm.reset({\n name: '',\n description: '',\n directoryId: ''\n });\n this.error = null;\n }\n\n @HostListener('document:keydown.escape', ['$event'])\n onEscapeKey(event: Event): void {\n if (this.visible) {\n this.onCancel();\n }\n }\n\n public get windowTitle(): string {\n return this.isEditMode ? 'Edit Role' : 'Create New Role';\n }\n\n public get isEditMode(): boolean {\n return this.data?.mode === 'edit';\n }\n\n public get isSystemRole(): boolean {\n if (!this.data?.role) return false;\n const systemRoleNames = ['Administrator', 'User', 'Guest', 'Developer'];\n return systemRoleNames.includes(this.data.role.Name || '');\n }\n\n private loadRoleData(): void {\n if (!this.data?.role) return;\n\n const role = this.data.role;\n this.roleForm.patchValue({\n name: role.Name,\n description: role.Description,\n directoryId: role.DirectoryID\n });\n\n // Disable name editing for system roles\n if (this.isSystemRole) {\n this.roleForm.get('name')?.disable();\n }\n }\n\n public async onSubmit(): Promise<void> {\n if (this.roleForm.invalid) {\n this.markFormGroupTouched(this.roleForm);\n return;\n }\n\n this.isLoading = true;\n this.error = null;\n\n try {\n let role: MJRoleEntity;\n\n if (this.isEditMode && this.data?.role) {\n // Edit existing role\n role = this.data.role;\n } else {\n // Create new role\n role = await this.metadata.GetEntityObject<MJRoleEntity>('MJ: Roles');\n role.NewRecord();\n }\n\n // Update role properties\n const formValue = this.roleForm.value;\n \n // Only update name if not a system role\n if (!this.isSystemRole) {\n role.Name = formValue.name;\n }\n \n role.Description = formValue.description;\n role.DirectoryID = formValue.directoryId || null;\n\n // Save role\n const saveResult = await role.Save();\n if (!saveResult) {\n throw new Error(role.LatestResult?.Message || 'Failed to save role');\n }\n\n this.result.emit({ action: 'save', role });\n\n } catch (error: unknown) {\n console.error('Error saving role:', error);\n this.ngZone.run(() => {\n this.error = error instanceof Error ? error.message : 'An unexpected error occurred';\n this.cdr.markForCheck();\n });\n } finally {\n this.ngZone.run(() => {\n this.isLoading = false;\n this.cdr.markForCheck();\n });\n }\n }\n\n public onCancel(): void {\n this.result.emit({ action: 'cancel' });\n }\n\n private markFormGroupTouched(formGroup: FormGroup): void {\n Object.keys(formGroup.controls).forEach(key => {\n const control = formGroup.get(key);\n control?.markAsTouched();\n });\n }\n}","<!-- MD3 Modal Dialog -->\n@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Modal Header with MJ Blue -->\n <div class=\"modal-header\">\n <div class=\"dialog-header\">\n <h2 class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n {{ isEditMode ? 'Edit Role' : 'Create New Role' }}\n </h2>\n <p class=\"dialog-subtitle\">\n {{ isEditMode ? 'Update role information and permissions' : 'Add a new role to the system' }}\n </p>\n </div>\n <button type=\"button\" class=\"modal-close\" (click)=\"onCancel()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"roleForm\" (ngSubmit)=\"onSubmit()\">\n @if (error) {\n <div class=\"content-section\">\n <mj-alert Variant=\"error\" [Message]=\"error\" />\n </div>\n }\n <!-- Basic Information Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n Role Information\n </h3>\n <p class=\"section-description\">Define the role's basic properties and purpose</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"name\">Role Name</label>\n <input\n id=\"name\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"Sales Manager\"\n [class.error]=\"roleForm.get('name')?.invalid && roleForm.get('name')?.touched\"\n />\n @if (roleForm.get('name')?.invalid && roleForm.get('name')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (roleForm.get('name')?.errors?.['required']) {\n Role name is required\n }\n @if (roleForm.get('name')?.errors?.['maxlength']) {\n Role name cannot exceed 50 characters\n }\n </div>\n }\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"description\">Description</label>\n <textarea\n id=\"description\"\n class=\"field-textarea\"\n formControlName=\"description\"\n placeholder=\"Describe the role's purpose and responsibilities...\"\n rows=\"4\"\n ></textarea>\n <div class=\"field-hint\">\n Provide a clear description of what this role is for and what permissions it should have.\n </div>\n </div>\n @if (isEditMode) {\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"directoryId\">Directory ID</label>\n <input\n id=\"directoryId\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"directoryId\"\n placeholder=\"External directory identifier\"\n />\n <div class=\"field-hint\">\n External directory identifier for syncing with Active Directory or other systems.\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Role Type Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n Role Type\n </h3>\n <p class=\"section-description\">System or custom role classification</p>\n </div>\n <div class=\"form-grid\">\n @if (isSystemRole) {\n <mj-alert Variant=\"warning\" Title=\"System Role\" Message=\"This is a system-defined role. Some properties may be limited for editing to maintain system integrity.\" />\n } @else {\n <mj-alert Variant=\"info\" Title=\"Custom Role\" Message=\"This is a custom role that can be fully configured and modified.\" />\n }\n </div>\n </div>\n </div>\n <!-- Permissions Preview Section -->\n @if (isEditMode) {\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-key\"></i>\n Permissions\n </h3>\n <p class=\"section-description\">Manage role permissions and access rights</p>\n </div>\n <div class=\"form-grid\">\n <mj-alert Variant=\"info\" Title=\"Permission Management\">\n Role permissions can be managed in the <strong>Permissions</strong> tab of the settings dashboard. Use that interface to configure specific access rights for this role.\n </mj-alert>\n </div>\n </div>\n </div>\n }\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"roleForm.invalid || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i>\n {{ isEditMode ? 'Update Role' : 'Create Role' }}\n }\n </button>\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n Cancel\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n"]}
1
+ {"version":3,"file":"role-dialog.component.js","sourceRoot":"","sources":["../../../../src/lib/role-management/role-dialog/role-dialog.component.ts","../../../../src/lib/role-management/role-dialog/role-dialog.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAA+C,MAAM,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAExL,OAAO,EAAoC,WAAW,EAAa,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAItG,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;;;;ICiBzD,+BAA6B;IAC3B,+BAA8C;IAChD,iBAAM;;;IADsB,cAAiB;IAAjB,sCAAiB;;;IA4BjC,uCACF;;;IAEE,uDACF;;;IAPF,+BAAyB;IACvB,wBAA8C;IAC9C,wGAAkD;IAGlD,wGAAmD;IAGrD,iBAAM;;;;;IANJ,eAEC;IAFD,gJAEC;IACD,cAEC;IAFD,iJAEC;;;IAmBH,AADF,+BAAwB,gBACuB;IAAA,4BAAY;IAAA,iBAAQ;IACjE,4BAMI;IACJ,+BAAwB;IACtB,mGACF;IACF,AADE,iBAAM,EACF;;;IAiBN,+BAAoK;;;IAEpK,+BAA0H;;;IAU1H,AADF,AADF,AADF,+BAA6B,cACD,cACI,aACA;IACxB,wBAA+B;IAC/B,6BACF;IAAA,iBAAK;IACL,6BAA+B;IAAA,yDAAyC;IAC1E,AAD0E,iBAAI,EACxE;IAEJ,AADF,+BAAuB,mBACkC;IACrD,yDAAuC;IAAA,+BAAQ;IAAA,4BAAW;IAAA,iBAAS;IAAC,uHACtE;IAGN,AADE,AADE,AADE,iBAAW,EACP,EACF,EACF;;;IAUF,wBAA2C;IAC3C,2BACF;;;IACE,wBAAgC;IAChC,YACF;;;IADE,cACF;IADE,kFACF;;;;IA5IZ,8BAAiD;IAArB,oLAAS,iBAAU,KAAC;IAC9C,8BAA6D;IAAnC,iHAAS,wBAAwB,IAAC;IAItD,AADF,AADF,8BAA0B,aACG,YACA;IACvB,uBAAyC;IACzC,YACF;IAAA,iBAAK;IACL,4BAA2B;IACzB,YACF;IACF,AADE,iBAAI,EACA;IACN,iCAAyF;IAA/C,uLAAS,iBAAU,KAAC;IAC5D,wBAAiC;IAErC,AADE,iBAAS,EACL;IAGJ,AADF,gCAAwB,gBAC+B;IAAxB,4LAAY,iBAAU,KAAC;IAClD,sGAAa;IASP,AADF,AADF,AADF,gCAA6B,eACD,eACI,cACA;IACxB,wBAAyC;IACzC,mCACF;IAAA,iBAAK;IACL,8BAA+B;IAAA,+DAA8C;IAC/E,AAD+E,iBAAI,EAC7E;IAGF,AADF,AADF,gCAAuB,eACG,iBACyB;IAAA,0BAAS;IAAA,iBAAQ;IAChE,6BAOI;IACJ,sGAAsE;IAWxE,iBAAM;IAEJ,AADF,gCAAwB,iBACuB;IAAA,4BAAW;IAAA,iBAAQ;IAChE,gCAMY;IACZ,gCAAwB;IACtB,4GACF;IACF,AADE,iBAAM,EACF;IACN,sGAAkB;IAiBxB,AADE,AADE,iBAAM,EACF,EACF;IAKA,AADF,AADF,AADF,gCAA6B,eACD,eACI,cACA;IACxB,yBAA+B;IAC/B,4BACF;IAAA,iBAAK;IACL,8BAA+B;IAAA,qDAAoC;IACrE,AADqE,iBAAI,EACnE;IACN,gCAAuB;IAGnB,AAFF,2GAAoB,qFAEX;IAKf,AADE,AADE,iBAAM,EACF,EACF;IAEN,uGAAkB;IAoBhB,AADF,gCAA0B,kBAKrB;IAIC,AAHF,2FAAiB,qEAGR;IAIX,iBAAS;IACT,mCAAqE;IAArB,wLAAS,iBAAU,KAAC;IAClE,wBAAiC;IACjC,yBACF;IAKV,AADE,AADE,AADE,AADE,AADE,iBAAS,EACL,EACD,EACH,EACF,EACF;;;;;IA/II,eACF;IADE,oFACF;IAEE,eACF;IADE,+HACF;IAQI,eAAsB;IAAtB,2CAAsB;IAC1B,cAIC;IAJD,wCAIC;IAoBS,gBAA8E;IAA9E,iLAA8E;IAEhF,cAUC;IAVD,oLAUC;IAeH,eAcC;IAdD,6CAcC;IAeD,gBAIC;IAJD,+CAIC;IAKP,eAiBC;IAjBD,6CAiBC;IAMG,eAA0C;IAA1C,sEAA0C;IAE1C,cAMC;IAND,4CAMC;;ADtHf,MAAM,OAAO,mBAAoB,SAAQ,oBAAoB;IAClD,IAAI,GAA0B,IAAI,CAAC;IAE5C,oCAAoC;IACpC,IAAa,IAAI,CAAC,KAA4B;QAC5C,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IACpB,CAAC;IACD,oCAAoC;IACpC,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IACQ,OAAO,GAAG,KAAK,CAAC;IAEzB,uCAAuC;IACvC,IAAa,OAAO,CAAC,KAAqC;QACxD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IACD,uCAAuC;IACvC,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACS,MAAM,GAAG,IAAI,YAAY,EAAoB,CAAC;IAExD;;;;;;OAMG;IACO,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAEvB,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACzB,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAChC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAChC,IAAY,QAAQ,KAAK,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IAC9C,QAAQ,CAAY;IAE3B,wCAAwC;IACxC,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IACD,wCAAwC;IACxC,IAAW,QAAQ,CAAC,KAAgB;QAClC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACxB,CAAC;IACM,SAAS,GAAG,KAAK,CAAC;IAClB,KAAK,GAAkB,IAAI,CAAC;IAEnC;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC;YAC5B,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3D,WAAW,EAAE,CAAC,EAAE,CAAC;YACjB,WAAW,EAAE,CAAC,EAAE,CAAC;SAClB,CAAC,CAAC;IACL,CAAC;IAED,QAAQ;QACN,gBAAgB;IAClB,CAAC;IAED,WAAW,CAAC,OAAsB;QAChC,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1D,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC;QAED,mEAAmE;QACnE,IAAI,OAAO,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3D,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IAED,WAAW;QACT,oBAAoB;IACtB,CAAC;IAEO,SAAS;QACf,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAClB,IAAI,EAAE,EAAE;YACR,WAAW,EAAE,EAAE;YACf,WAAW,EAAE,EAAE;SAChB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAGD,WAAW,CAAC,KAAY;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAED,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAC3D,CAAC;IAED,2CAA2C;IAC3C,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,IAAW,UAAU;QACnB,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;IACpC,CAAC;IAED,0CAA0C;IAC1C,IAAW,UAAU;QACnB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,IAAW,YAAY;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI;YAAE,OAAO,KAAK,CAAC;QACnC,MAAM,eAAe,GAAG,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QACxE,OAAO,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,4CAA4C;IAC5C,IAAW,YAAY;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAEO,YAAY;QAClB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI;YAAE,OAAO;QAE7B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC,CAAC;QAEH,wCAAwC;QACxC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;QACvC,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,QAAQ;QACnB,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,IAAI,CAAC;YACH,IAAI,IAAkB,CAAC;YAEvB,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;gBACvC,qBAAqB;gBACrB,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,kBAAkB;gBAClB,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAe,WAAW,CAAC,CAAC;gBACtE,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,CAAC;YAED,yBAAyB;YACzB,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAEtC,wCAAwC;YACxC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;YAC7B,CAAC;YAED,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;YACzC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,WAAW,IAAI,IAAI,CAAC;YAEjD,YAAY;YACZ,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YACrC,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,IAAI,qBAAqB,CAAC,CAAC;YACvE,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAE7C,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE;gBACnB,IAAI,CAAC,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;gBACrF,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YAC1B,CAAC,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE;gBACnB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;gBACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YAC1B,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,wCAAwC;IACjC,KAAK,CAAC,QAAQ;QACnB,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;IACzB,CAAC;IAEM,QAAQ;QACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzC,CAAC;IAEO,oBAAoB,CAAC,SAAoB;QAC/C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YAC5C,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACnC,OAAO,EAAE,aAAa,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC;6GA9MU,mBAAmB;6DAAnB,mBAAmB;YAAnB,gHAAA,uBAAmB,0BAAA;;YCvBhC,uFAAe;;YAAf,sCAwJC;;;iFDjIY,mBAAmB;cAP/B,SAAS;6BACI,KAAK,YACP,gBAAgB,iBACX,iBAAiB,CAAC,IAAI;;kBAKpC,KAAK;;kBAGL,KAAK;;kBAOL,KAAK;;kBAGL,KAAK;;kBAOL,MAAM;;kBASN,MAAM;;kBAwDN,YAAY;mBAAC,yBAAyB,EAAE,CAAC,QAAQ,CAAC;;kFAtFxC,mBAAmB","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, OnChanges, SimpleChanges, inject, HostListener, ViewEncapsulation, ChangeDetectorRef, NgZone } from '@angular/core';\n\nimport { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';\nimport { Metadata } from '@memberjunction/core';\nimport { MJRoleEntity } from '@memberjunction/core-entities';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nexport interface RoleDialogData {\n role?: MJRoleEntity;\n mode: 'create' | 'edit';\n}\n\nexport interface RoleDialogResult {\n action: 'save' | 'cancel';\n role?: MJRoleEntity;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-role-dialog',\n encapsulation: ViewEncapsulation.None,\n templateUrl: './role-dialog.component.html',\n styleUrls: ['./role-dialog.component.css']\n})\nexport class RoleDialogComponent extends BaseAngularComponent implements OnInit, OnDestroy, OnChanges {\n @Input() Data: RoleDialogData | null = null;\n\n /** @deprecated Use {@link Data}. */\n @Input() set data(value: RoleDialogData | null) {\n this.Data = value;\n }\n /** @deprecated Use {@link Data}. */\n get data(): RoleDialogData | null {\n return this.Data;\n }\n @Input() Visible = false;\n\n /** @deprecated Use {@link Visible}. */\n @Input() set visible(value: RoleDialogComponent['Visible']) {\n this.Visible = value;\n }\n /** @deprecated Use {@link Visible}. */\n get visible(): RoleDialogComponent['Visible'] {\n return this.Visible;\n }\n @Output() Result = new EventEmitter<RoleDialogResult>();\n\n /**\n * @deprecated Use {@link Result}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (result) keeps working. Must stay AFTER Result: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() result = this.Result;\n\n private fb = inject(FormBuilder);\n private cdr = inject(ChangeDetectorRef);\n private ngZone = inject(NgZone);\n private get metadata() { return this.ProviderToUse; }\n public RoleForm: FormGroup;\n\n /** @deprecated Use {@link RoleForm}. */\n public get roleForm(): FormGroup {\n return this.RoleForm;\n }\n /** @deprecated Use {@link RoleForm}. */\n public set roleForm(value: FormGroup) {\n this.RoleForm = value;\n }\n public isLoading = false;\n public error: string | null = null;\n\n constructor() {\n super();\n this.RoleForm = this.fb.group({\n name: ['', [Validators.required, Validators.maxLength(50)]],\n description: [''],\n directoryId: ['']\n });\n }\n\n ngOnInit(): void {\n // Initial setup\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['data'] && this.Data?.role && this.IsEditMode) {\n this.loadRoleData();\n }\n \n // Reset form if switching to create mode or dialog becomes visible\n if (changes['visible'] && this.Visible && !this.IsEditMode) {\n this.resetForm();\n }\n }\n\n ngOnDestroy(): void {\n // Cleanup if needed\n }\n\n private resetForm(): void {\n this.RoleForm.reset({\n name: '',\n description: '',\n directoryId: ''\n });\n this.error = null;\n }\n\n @HostListener('document:keydown.escape', ['$event'])\n onEscapeKey(event: Event): void {\n if (this.Visible) {\n this.onCancel();\n }\n }\n\n public get WindowTitle(): string {\n return this.IsEditMode ? 'Edit Role' : 'Create New Role';\n }\n\n /** @deprecated Use {@link WindowTitle}. */\n public get windowTitle(): string {\n return this.WindowTitle;\n }\n\n public get IsEditMode(): boolean {\n return this.Data?.mode === 'edit';\n }\n\n /** @deprecated Use {@link IsEditMode}. */\n public get isEditMode(): boolean {\n return this.IsEditMode;\n }\n\n public get IsSystemRole(): boolean {\n if (!this.Data?.role) return false;\n const systemRoleNames = ['Administrator', 'User', 'Guest', 'Developer'];\n return systemRoleNames.includes(this.Data.role.Name || '');\n }\n\n /** @deprecated Use {@link IsSystemRole}. */\n public get isSystemRole(): boolean {\n return this.IsSystemRole;\n }\n\n private loadRoleData(): void {\n if (!this.Data?.role) return;\n\n const role = this.Data.role;\n this.RoleForm.patchValue({\n name: role.Name,\n description: role.Description,\n directoryId: role.DirectoryID\n });\n\n // Disable name editing for system roles\n if (this.IsSystemRole) {\n this.RoleForm.get('name')?.disable();\n }\n }\n\n public async OnSubmit(): Promise<void> {\n if (this.RoleForm.invalid) {\n this.markFormGroupTouched(this.RoleForm);\n return;\n }\n\n this.isLoading = true;\n this.error = null;\n\n try {\n let role: MJRoleEntity;\n\n if (this.IsEditMode && this.Data?.role) {\n // Edit existing role\n role = this.Data.role;\n } else {\n // Create new role\n role = await this.metadata.GetEntityObject<MJRoleEntity>('MJ: Roles');\n role.NewRecord();\n }\n\n // Update role properties\n const formValue = this.RoleForm.value;\n \n // Only update name if not a system role\n if (!this.IsSystemRole) {\n role.Name = formValue.name;\n }\n \n role.Description = formValue.description;\n role.DirectoryID = formValue.directoryId || null;\n\n // Save role\n const saveResult = await role.Save();\n if (!saveResult) {\n throw new Error(role.LatestResult?.Message || 'Failed to save role');\n }\n\n this.Result.emit({ action: 'save', role });\n\n } catch (error: unknown) {\n console.error('Error saving role:', error);\n this.ngZone.run(() => {\n this.error = error instanceof Error ? error.message : 'An unexpected error occurred';\n this.cdr.markForCheck();\n });\n } finally {\n this.ngZone.run(() => {\n this.isLoading = false;\n this.cdr.markForCheck();\n });\n }\n }\n\n /** @deprecated Use {@link OnSubmit}. */\n public async onSubmit(): Promise<void> {\n return this.OnSubmit();\n }\n\n public onCancel(): void {\n this.Result.emit({ action: 'cancel' });\n }\n\n private markFormGroupTouched(formGroup: FormGroup): void {\n Object.keys(formGroup.controls).forEach(key => {\n const control = formGroup.get(key);\n control?.markAsTouched();\n });\n }\n}","<!-- MD3 Modal Dialog -->\n@if (visible) {\n <div class=\"modal-backdrop\" (click)=\"onCancel()\">\n <div class=\"modal-dialog\" (click)=\"$event.stopPropagation()\">\n <!-- Modal Header with MJ Blue -->\n <div class=\"modal-header\">\n <div class=\"dialog-header\">\n <h2 class=\"dialog-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n {{ isEditMode ? 'Edit Role' : 'Create New Role' }}\n </h2>\n <p class=\"dialog-subtitle\">\n {{ isEditMode ? 'Update role information and permissions' : 'Add a new role to the system' }}\n </p>\n </div>\n <button type=\"button\" class=\"modal-close\" (click)=\"onCancel()\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <form [formGroup]=\"roleForm\" (ngSubmit)=\"onSubmit()\">\n @if (error) {\n <div class=\"content-section\">\n <mj-alert Variant=\"error\" [Message]=\"error\" />\n </div>\n }\n <!-- Basic Information Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n Role Information\n </h3>\n <p class=\"section-description\">Define the role's basic properties and purpose</p>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-field\">\n <label class=\"field-label required\" for=\"name\">Role Name</label>\n <input\n id=\"name\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"name\"\n placeholder=\"Sales Manager\"\n [class.error]=\"roleForm.get('name')?.invalid && roleForm.get('name')?.touched\"\n />\n @if (roleForm.get('name')?.invalid && roleForm.get('name')?.touched) {\n <div class=\"field-error\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n @if (roleForm.get('name')?.errors?.['required']) {\n Role name is required\n }\n @if (roleForm.get('name')?.errors?.['maxlength']) {\n Role name cannot exceed 50 characters\n }\n </div>\n }\n </div>\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"description\">Description</label>\n <textarea\n id=\"description\"\n class=\"field-textarea\"\n formControlName=\"description\"\n placeholder=\"Describe the role's purpose and responsibilities...\"\n rows=\"4\"\n ></textarea>\n <div class=\"field-hint\">\n Provide a clear description of what this role is for and what permissions it should have.\n </div>\n </div>\n @if (isEditMode) {\n <div class=\"form-field\">\n <label class=\"field-label\" for=\"directoryId\">Directory ID</label>\n <input\n id=\"directoryId\"\n type=\"text\"\n class=\"field-input\"\n formControlName=\"directoryId\"\n placeholder=\"External directory identifier\"\n />\n <div class=\"field-hint\">\n External directory identifier for syncing with Active Directory or other systems.\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Role Type Section -->\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n Role Type\n </h3>\n <p class=\"section-description\">System or custom role classification</p>\n </div>\n <div class=\"form-grid\">\n @if (isSystemRole) {\n <mj-alert Variant=\"warning\" Title=\"System Role\" Message=\"This is a system-defined role. Some properties may be limited for editing to maintain system integrity.\" />\n } @else {\n <mj-alert Variant=\"info\" Title=\"Custom Role\" Message=\"This is a custom role that can be fully configured and modified.\" />\n }\n </div>\n </div>\n </div>\n <!-- Permissions Preview Section -->\n @if (isEditMode) {\n <div class=\"content-section\">\n <div class=\"form-section\">\n <div class=\"section-header\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-key\"></i>\n Permissions\n </h3>\n <p class=\"section-description\">Manage role permissions and access rights</p>\n </div>\n <div class=\"form-grid\">\n <mj-alert Variant=\"info\" Title=\"Permission Management\">\n Role permissions can be managed in the <strong>Permissions</strong> tab of the settings dashboard. Use that interface to configure specific access rights for this role.\n </mj-alert>\n </div>\n </div>\n </div>\n }\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"roleForm.invalid || isLoading\"\n >\n @if (isLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Saving...\n } @else {\n <i class=\"fa-solid fa-save\"></i>\n {{ isEditMode ? 'Update Role' : 'Create Role' }}\n }\n </button>\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i>\n Cancel\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n"]}
@@ -18,8 +18,12 @@ export type RoleTypeFilter = (typeof VALID_ROLE_TYPE_FILTERS)[number];
18
18
  */
19
19
  export declare const ROLE_AGENT_CONTEXT_NAME_LIST_CAP = 25;
20
20
  /** Type-guard for a role-type filter string. Keeps the FilterRolesByType tool tolerant. */
21
+ export declare function IsValidRoleTypeFilter(value: unknown): value is RoleTypeFilter;
22
+ /** @deprecated Use {@link IsValidRoleTypeFilter}. */
21
23
  export declare function isValidRoleTypeFilter(value: unknown): value is RoleTypeFilter;
22
24
  /** Cap a list of names to {@link ROLE_AGENT_CONTEXT_NAME_LIST_CAP}. Pure + deterministic. */
25
+ export declare function CapRoleNames(names: readonly string[]): string[];
26
+ /** @deprecated Use {@link CapRoleNames}. */
23
27
  export declare function capRoleNames(names: readonly string[]): string[];
24
28
  /** A minimal descriptor of a role (id + display name) supplied by the component. */
25
29
  export interface RoleNameCandidate {
@@ -28,11 +32,11 @@ export interface RoleNameCandidate {
28
32
  }
29
33
  /** Outcome of a tolerant id→name→contains role resolution. */
30
34
  export type RoleLookupResult = {
31
- ok: true;
32
- match: RoleNameCandidate;
35
+ Ok: true;
36
+ Match: RoleNameCandidate;
33
37
  } | {
34
- ok: false;
35
- error: string;
38
+ Ok: false;
39
+ Error: string;
36
40
  };
37
41
  /**
38
42
  * Resolve an agent-supplied role reference against the loaded roles, tolerantly:
@@ -43,6 +47,8 @@ export type RoleLookupResult = {
43
47
  * Pure + deterministic. On a miss, returns a clear error listing a sample of available role
44
48
  * names so the agent can correct itself.
45
49
  */
50
+ export declare function ResolveRoleByIDOrName(input: string, candidates: readonly RoleNameCandidate[]): RoleLookupResult;
51
+ /** @deprecated Use {@link ResolveRoleByIDOrName}. */
46
52
  export declare function resolveRoleByIDOrName(input: string, candidates: readonly RoleNameCandidate[]): RoleLookupResult;
47
53
  /**
48
54
  * Read-only permission summary for the selected role, derived from the role's
@@ -92,5 +98,7 @@ export interface RoleManagementAgentContextInput {
92
98
  * role-name list and emits a companion total-count when truncated; surfaces the read-only
93
99
  * permission summary only when a role is selected and its permissions have been loaded.
94
100
  */
101
+ export declare function BuildRoleManagementAgentContext(input: RoleManagementAgentContextInput): Record<string, unknown>;
102
+ /** @deprecated Use {@link BuildRoleManagementAgentContext}. */
95
103
  export declare function buildRoleManagementAgentContext(input: RoleManagementAgentContextInput): Record<string, unknown>;
96
104
  //# sourceMappingURL=role-management-agent-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"role-management-agent-context.d.ts","sourceRoot":"","sources":["../../../src/lib/role-management/role-management-agent-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB,sCAAuC,CAAC;AAC5E,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAEnD,2FAA2F;AAC3F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAE7E;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAE/D;AAED,oFAAoF;AACpF,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,8DAA8D;AAC9D,MAAM,MAAM,gBAAgB,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,iBAAiB,EAAE,GAAG,gBAAgB,CAmB/G;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IAClC,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,+BAA+B;IAC5C,uCAAuC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yDAAyD;IACzD,eAAe,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,eAAe,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,UAAU,EAAE,cAAc,CAAC;IAC3B,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mGAAmG;IACnG,uBAAuB,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,+BAA+B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA0B/G"}
1
+ {"version":3,"file":"role-management-agent-context.d.ts","sourceRoot":"","sources":["../../../src/lib/role-management/role-management-agent-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB,sCAAuC,CAAC;AAC5E,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAEnD,2FAA2F;AAC3F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAE7E;AAED,qDAAqD;AACrD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAE7E;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAE/D;AAED,4CAA4C;AAC5C,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAE/D;AAED,oFAAoF;AACpF,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,8DAA8D;AAC9D,MAAM,MAAM,gBAAgB,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,iBAAiB,EAAE,GAAG,gBAAgB,CAmB/G;AAED,qDAAqD;AACrD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,iBAAiB,EAAE,GAAG,gBAAgB,CAE/G;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IAClC,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,+BAA+B;IAC5C,uCAAuC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yDAAyD;IACzD,eAAe,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,eAAe,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,UAAU,EAAE,cAAc,CAAC;IAC3B,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mGAAmG;IACnG,uBAAuB,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,+BAA+B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA0B/G;AAED,+DAA+D;AAC/D,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,+BAA+B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE/G"}
@@ -17,13 +17,21 @@ export const VALID_ROLE_TYPE_FILTERS = ['all', 'system', 'custom'];
17
17
  */
18
18
  export const ROLE_AGENT_CONTEXT_NAME_LIST_CAP = 25;
19
19
  /** Type-guard for a role-type filter string. Keeps the FilterRolesByType tool tolerant. */
20
- export function isValidRoleTypeFilter(value) {
20
+ export function IsValidRoleTypeFilter(value) {
21
21
  return typeof value === 'string' && VALID_ROLE_TYPE_FILTERS.includes(value);
22
22
  }
23
+ /** @deprecated Use {@link IsValidRoleTypeFilter}. */
24
+ export function isValidRoleTypeFilter(value) {
25
+ return IsValidRoleTypeFilter(value);
26
+ }
23
27
  /** Cap a list of names to {@link ROLE_AGENT_CONTEXT_NAME_LIST_CAP}. Pure + deterministic. */
24
- export function capRoleNames(names) {
28
+ export function CapRoleNames(names) {
25
29
  return names.slice(0, ROLE_AGENT_CONTEXT_NAME_LIST_CAP);
26
30
  }
31
+ /** @deprecated Use {@link CapRoleNames}. */
32
+ export function capRoleNames(names) {
33
+ return CapRoleNames(names);
34
+ }
27
35
  /**
28
36
  * Resolve an agent-supplied role reference against the loaded roles, tolerantly:
29
37
  * 1. exact ID match (case-insensitive)
@@ -33,32 +41,36 @@ export function capRoleNames(names) {
33
41
  * Pure + deterministic. On a miss, returns a clear error listing a sample of available role
34
42
  * names so the agent can correct itself.
35
43
  */
36
- export function resolveRoleByIDOrName(input, candidates) {
44
+ export function ResolveRoleByIDOrName(input, candidates) {
37
45
  const needle = input.trim().toLowerCase();
38
46
  if (!needle) {
39
- return { ok: false, error: 'Provide a role ID or name to select.' };
47
+ return { Ok: false, Error: 'Provide a role ID or name to select.' };
40
48
  }
41
49
  const byId = candidates.find(c => c.ID.toLowerCase() === needle);
42
50
  if (byId) {
43
- return { ok: true, match: byId };
51
+ return { Ok: true, Match: byId };
44
52
  }
45
53
  const exact = candidates.find(c => c.Name.toLowerCase() === needle);
46
54
  if (exact) {
47
- return { ok: true, match: exact };
55
+ return { Ok: true, Match: exact };
48
56
  }
49
57
  const contains = candidates.find(c => c.Name.toLowerCase().includes(needle));
50
58
  if (contains) {
51
- return { ok: true, match: contains };
59
+ return { Ok: true, Match: contains };
52
60
  }
53
61
  const sample = candidates.slice(0, 8).map(c => c.Name).join(', ');
54
- return { ok: false, error: `No role matches "${input}". Available roles: ${sample || '(none loaded)'}.` };
62
+ return { Ok: false, Error: `No role matches "${input}". Available roles: ${sample || '(none loaded)'}.` };
63
+ }
64
+ /** @deprecated Use {@link ResolveRoleByIDOrName}. */
65
+ export function resolveRoleByIDOrName(input, candidates) {
66
+ return ResolveRoleByIDOrName(input, candidates);
55
67
  }
56
68
  /**
57
69
  * Build the agent-visible context object for Role Management. Pure (no `this`). Bounds the
58
70
  * role-name list and emits a companion total-count when truncated; surfaces the read-only
59
71
  * permission summary only when a role is selected and its permissions have been loaded.
60
72
  */
61
- export function buildRoleManagementAgentContext(input) {
73
+ export function BuildRoleManagementAgentContext(input) {
62
74
  const context = {
63
75
  TotalRoleCount: input.TotalRoleCount,
64
76
  FilteredRoleCount: input.FilteredRoleCount,
@@ -70,7 +82,7 @@ export function buildRoleManagementAgentContext(input) {
70
82
  SelectedRoleName: input.SelectedRoleName,
71
83
  };
72
84
  if (input.VisibleRoleNames.length > 0) {
73
- context['VisibleRoleNames'] = capRoleNames(input.VisibleRoleNames);
85
+ context['VisibleRoleNames'] = CapRoleNames(input.VisibleRoleNames);
74
86
  if (input.VisibleRoleNames.length > ROLE_AGENT_CONTEXT_NAME_LIST_CAP) {
75
87
  context['VisibleRoleCount'] = input.VisibleRoleNames.length;
76
88
  }
@@ -82,4 +94,8 @@ export function buildRoleManagementAgentContext(input) {
82
94
  }
83
95
  return context;
84
96
  }
97
+ /** @deprecated Use {@link BuildRoleManagementAgentContext}. */
98
+ export function buildRoleManagementAgentContext(input) {
99
+ return BuildRoleManagementAgentContext(input);
100
+ }
85
101
  //# sourceMappingURL=role-management-agent-context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"role-management-agent-context.js","sourceRoot":"","sources":["../../../src/lib/role-management/role-management-agent-context.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Pure helpers for the Role Management admin surface's AI-agent integration.\n *\n * 🔒 READ-ONLY / GOVERNANCE SURFACE. These helpers shape a non-sensitive snapshot of the\n * role-management screen into the key-value `AgentContext` object and back agent-supplied\n * role references with tolerant id→name→contains resolution. They are intentionally free of\n * Angular / component dependencies so they can be unit-tested in isolation (mirrors the\n * Data Explorer agent-context pattern). Permission information is surfaced as a READ-ONLY\n * summary (counts only) — no grant/revoke surface, no secrets.\n */\n\n/** The three role-type filter values the surface supports. */\nexport const VALID_ROLE_TYPE_FILTERS = ['all', 'system', 'custom'] as const;\nexport type RoleTypeFilter = (typeof VALID_ROLE_TYPE_FILTERS)[number];\n\n/**\n * Upper bound on how many role names we publish in a name-list context field\n * (VisibleRoleNames). Keeps the streamed note bounded; a companion total-count field reports\n * the true number when the list is truncated.\n */\nexport const ROLE_AGENT_CONTEXT_NAME_LIST_CAP = 25;\n\n/** Type-guard for a role-type filter string. Keeps the FilterRolesByType tool tolerant. */\nexport function isValidRoleTypeFilter(value: unknown): value is RoleTypeFilter {\n return typeof value === 'string' && (VALID_ROLE_TYPE_FILTERS as readonly string[]).includes(value);\n}\n\n/** Cap a list of names to {@link ROLE_AGENT_CONTEXT_NAME_LIST_CAP}. Pure + deterministic. */\nexport function capRoleNames(names: readonly string[]): string[] {\n return names.slice(0, ROLE_AGENT_CONTEXT_NAME_LIST_CAP);\n}\n\n/** A minimal descriptor of a role (id + display name) supplied by the component. */\nexport interface RoleNameCandidate {\n ID: string;\n Name: string;\n}\n\n/** Outcome of a tolerant id→name→contains role resolution. */\nexport type RoleLookupResult =\n | { ok: true; match: RoleNameCandidate }\n | { ok: false; error: string };\n\n/**\n * Resolve an agent-supplied role reference against the loaded roles, tolerantly:\n * 1. exact ID match (case-insensitive)\n * 2. exact display-name match (case-insensitive)\n * 3. first case-insensitive *contains* match on name\n *\n * Pure + deterministic. On a miss, returns a clear error listing a sample of available role\n * names so the agent can correct itself.\n */\nexport function resolveRoleByIDOrName(input: string, candidates: readonly RoleNameCandidate[]): RoleLookupResult {\n const needle = input.trim().toLowerCase();\n if (!needle) {\n return { ok: false, error: 'Provide a role ID or name to select.' };\n }\n const byId = candidates.find(c => c.ID.toLowerCase() === needle);\n if (byId) {\n return { ok: true, match: byId };\n }\n const exact = candidates.find(c => c.Name.toLowerCase() === needle);\n if (exact) {\n return { ok: true, match: exact };\n }\n const contains = candidates.find(c => c.Name.toLowerCase().includes(needle));\n if (contains) {\n return { ok: true, match: contains };\n }\n const sample = candidates.slice(0, 8).map(c => c.Name).join(', ');\n return { ok: false, error: `No role matches \"${input}\". Available roles: ${sample || '(none loaded)'}.` };\n}\n\n/**\n * Read-only permission summary for the selected role, derived from the role's\n * entity-permission rows. Counts only — describes the breadth of access the role has been\n * granted without exposing any mutation surface.\n */\nexport interface RolePermissionSummary {\n /** Number of entities for which the role has at least one permission row. */\n EntityCount: number;\n /** Number of entities the role can read. */\n ReadCount: number;\n /** Number of entities the role can create. */\n CreateCount: number;\n /** Number of entities the role can update. */\n UpdateCount: number;\n /** Number of entities the role can delete. */\n DeleteCount: number;\n}\n\n/**\n * The plain, component-supplied snapshot used to build the role-management agent context.\n * NON-SENSITIVE by construction — counts, filter state, and on-screen display values only.\n */\nexport interface RoleManagementAgentContextInput {\n /** Total roles loaded (unfiltered). */\n TotalRoleCount: number;\n /** Roles currently visible after type/search filters. */\n FilteredRoleCount: number;\n /** Count of system roles (across the unfiltered set). */\n SystemRoleCount: number;\n /** Count of custom roles (across the unfiltered set). */\n CustomRoleCount: number;\n /** Active role-type filter. */\n TypeFilter: RoleTypeFilter;\n /** Current free-text search string. */\n SearchText: string;\n /** ID of the currently selected (expanded) role, or null. */\n SelectedRoleId: string | null;\n /** Display name of the currently selected role, or null. */\n SelectedRoleName: string | null;\n /** Display names of the currently visible (filtered) roles, in list order. */\n VisibleRoleNames: string[];\n /** Read-only permission summary for the selected role, or null when none selected / not loaded. */\n SelectedRolePermissions: RolePermissionSummary | null;\n}\n\n/**\n * Build the agent-visible context object for Role Management. Pure (no `this`). Bounds the\n * role-name list and emits a companion total-count when truncated; surfaces the read-only\n * permission summary only when a role is selected and its permissions have been loaded.\n */\nexport function buildRoleManagementAgentContext(input: RoleManagementAgentContextInput): Record<string, unknown> {\n const context: Record<string, unknown> = {\n TotalRoleCount: input.TotalRoleCount,\n FilteredRoleCount: input.FilteredRoleCount,\n SystemRoleCount: input.SystemRoleCount,\n CustomRoleCount: input.CustomRoleCount,\n TypeFilter: input.TypeFilter,\n SearchText: input.SearchText,\n SelectedRoleId: input.SelectedRoleId,\n SelectedRoleName: input.SelectedRoleName,\n };\n\n if (input.VisibleRoleNames.length > 0) {\n context['VisibleRoleNames'] = capRoleNames(input.VisibleRoleNames);\n if (input.VisibleRoleNames.length > ROLE_AGENT_CONTEXT_NAME_LIST_CAP) {\n context['VisibleRoleCount'] = input.VisibleRoleNames.length;\n }\n }\n\n // Read-only permission summary — surfaced ONLY when a role is selected AND its\n // permissions have been loaded (never fabricated zeros for an unselected role).\n if (input.SelectedRolePermissions) {\n context['SelectedRolePermissions'] = { ...input.SelectedRolePermissions };\n }\n\n return context;\n}\n"]}
1
+ {"version":3,"file":"role-management-agent-context.js","sourceRoot":"","sources":["../../../src/lib/role-management/role-management-agent-context.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Pure helpers for the Role Management admin surface's AI-agent integration.\n *\n * 🔒 READ-ONLY / GOVERNANCE SURFACE. These helpers shape a non-sensitive snapshot of the\n * role-management screen into the key-value `AgentContext` object and back agent-supplied\n * role references with tolerant id→name→contains resolution. They are intentionally free of\n * Angular / component dependencies so they can be unit-tested in isolation (mirrors the\n * Data Explorer agent-context pattern). Permission information is surfaced as a READ-ONLY\n * summary (counts only) — no grant/revoke surface, no secrets.\n */\n\n/** The three role-type filter values the surface supports. */\nexport const VALID_ROLE_TYPE_FILTERS = ['all', 'system', 'custom'] as const;\nexport type RoleTypeFilter = (typeof VALID_ROLE_TYPE_FILTERS)[number];\n\n/**\n * Upper bound on how many role names we publish in a name-list context field\n * (VisibleRoleNames). Keeps the streamed note bounded; a companion total-count field reports\n * the true number when the list is truncated.\n */\nexport const ROLE_AGENT_CONTEXT_NAME_LIST_CAP = 25;\n\n/** Type-guard for a role-type filter string. Keeps the FilterRolesByType tool tolerant. */\nexport function IsValidRoleTypeFilter(value: unknown): value is RoleTypeFilter {\n return typeof value === 'string' && (VALID_ROLE_TYPE_FILTERS as readonly string[]).includes(value);\n}\n\n/** @deprecated Use {@link IsValidRoleTypeFilter}. */\nexport function isValidRoleTypeFilter(value: unknown): value is RoleTypeFilter {\n return IsValidRoleTypeFilter(value);\n}\n\n/** Cap a list of names to {@link ROLE_AGENT_CONTEXT_NAME_LIST_CAP}. Pure + deterministic. */\nexport function CapRoleNames(names: readonly string[]): string[] {\n return names.slice(0, ROLE_AGENT_CONTEXT_NAME_LIST_CAP);\n}\n\n/** @deprecated Use {@link CapRoleNames}. */\nexport function capRoleNames(names: readonly string[]): string[] {\n return CapRoleNames(names);\n}\n\n/** A minimal descriptor of a role (id + display name) supplied by the component. */\nexport interface RoleNameCandidate {\n ID: string;\n Name: string;\n}\n\n/** Outcome of a tolerant id→name→contains role resolution. */\nexport type RoleLookupResult =\n | { Ok: true; Match: RoleNameCandidate }\n | { Ok: false; Error: string };\n\n/**\n * Resolve an agent-supplied role reference against the loaded roles, tolerantly:\n * 1. exact ID match (case-insensitive)\n * 2. exact display-name match (case-insensitive)\n * 3. first case-insensitive *contains* match on name\n *\n * Pure + deterministic. On a miss, returns a clear error listing a sample of available role\n * names so the agent can correct itself.\n */\nexport function ResolveRoleByIDOrName(input: string, candidates: readonly RoleNameCandidate[]): RoleLookupResult {\n const needle = input.trim().toLowerCase();\n if (!needle) {\n return { Ok: false, Error: 'Provide a role ID or name to select.' };\n }\n const byId = candidates.find(c => c.ID.toLowerCase() === needle);\n if (byId) {\n return { Ok: true, Match: byId };\n }\n const exact = candidates.find(c => c.Name.toLowerCase() === needle);\n if (exact) {\n return { Ok: true, Match: exact };\n }\n const contains = candidates.find(c => c.Name.toLowerCase().includes(needle));\n if (contains) {\n return { Ok: true, Match: contains };\n }\n const sample = candidates.slice(0, 8).map(c => c.Name).join(', ');\n return { Ok: false, Error: `No role matches \"${input}\". Available roles: ${sample || '(none loaded)'}.` };\n}\n\n/** @deprecated Use {@link ResolveRoleByIDOrName}. */\nexport function resolveRoleByIDOrName(input: string, candidates: readonly RoleNameCandidate[]): RoleLookupResult {\n return ResolveRoleByIDOrName(input, candidates);\n}\n\n/**\n * Read-only permission summary for the selected role, derived from the role's\n * entity-permission rows. Counts only — describes the breadth of access the role has been\n * granted without exposing any mutation surface.\n */\nexport interface RolePermissionSummary {\n /** Number of entities for which the role has at least one permission row. */\n EntityCount: number;\n /** Number of entities the role can read. */\n ReadCount: number;\n /** Number of entities the role can create. */\n CreateCount: number;\n /** Number of entities the role can update. */\n UpdateCount: number;\n /** Number of entities the role can delete. */\n DeleteCount: number;\n}\n\n/**\n * The plain, component-supplied snapshot used to build the role-management agent context.\n * NON-SENSITIVE by construction — counts, filter state, and on-screen display values only.\n */\nexport interface RoleManagementAgentContextInput {\n /** Total roles loaded (unfiltered). */\n TotalRoleCount: number;\n /** Roles currently visible after type/search filters. */\n FilteredRoleCount: number;\n /** Count of system roles (across the unfiltered set). */\n SystemRoleCount: number;\n /** Count of custom roles (across the unfiltered set). */\n CustomRoleCount: number;\n /** Active role-type filter. */\n TypeFilter: RoleTypeFilter;\n /** Current free-text search string. */\n SearchText: string;\n /** ID of the currently selected (expanded) role, or null. */\n SelectedRoleId: string | null;\n /** Display name of the currently selected role, or null. */\n SelectedRoleName: string | null;\n /** Display names of the currently visible (filtered) roles, in list order. */\n VisibleRoleNames: string[];\n /** Read-only permission summary for the selected role, or null when none selected / not loaded. */\n SelectedRolePermissions: RolePermissionSummary | null;\n}\n\n/**\n * Build the agent-visible context object for Role Management. Pure (no `this`). Bounds the\n * role-name list and emits a companion total-count when truncated; surfaces the read-only\n * permission summary only when a role is selected and its permissions have been loaded.\n */\nexport function BuildRoleManagementAgentContext(input: RoleManagementAgentContextInput): Record<string, unknown> {\n const context: Record<string, unknown> = {\n TotalRoleCount: input.TotalRoleCount,\n FilteredRoleCount: input.FilteredRoleCount,\n SystemRoleCount: input.SystemRoleCount,\n CustomRoleCount: input.CustomRoleCount,\n TypeFilter: input.TypeFilter,\n SearchText: input.SearchText,\n SelectedRoleId: input.SelectedRoleId,\n SelectedRoleName: input.SelectedRoleName,\n };\n\n if (input.VisibleRoleNames.length > 0) {\n context['VisibleRoleNames'] = CapRoleNames(input.VisibleRoleNames);\n if (input.VisibleRoleNames.length > ROLE_AGENT_CONTEXT_NAME_LIST_CAP) {\n context['VisibleRoleCount'] = input.VisibleRoleNames.length;\n }\n }\n\n // Read-only permission summary — surfaced ONLY when a role is selected AND its\n // permissions have been loaded (never fabricated zeros for an unselected role).\n if (input.SelectedRolePermissions) {\n context['SelectedRolePermissions'] = { ...input.SelectedRolePermissions };\n }\n\n return context;\n}\n\n/** @deprecated Use {@link BuildRoleManagementAgentContext}. */\nexport function buildRoleManagementAgentContext(input: RoleManagementAgentContextInput): Record<string, unknown> {\n return BuildRoleManagementAgentContext(input);\n}\n"]}