@memberjunction/ng-explorer-settings 6.2.0-edge.0 → 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 +92 -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 +222 -76
  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 +92 -10
  9. package/dist/lib/application-management/application-management.component.d.ts.map +1 -1
  10. package/dist/lib/application-management/application-management.component.js +229 -65
  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 +4 -2
  58. package/dist/lib/user-management/transaction-group-refusals.d.ts.map +1 -1
  59. package/dist/lib/user-management/transaction-group-refusals.js +7 -3
  60. package/dist/lib/user-management/transaction-group-refusals.js.map +1 -1
  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 +121 -47
  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 +480 -171
  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
@@ -179,10 +179,34 @@ function NotificationPreferencesComponent_Conditional_2_Template(rf, ctx) { if (
179
179
  */
180
180
  export class NotificationPreferencesComponent extends BaseAngularComponent {
181
181
  sharedService;
182
- loading = true;
182
+ Loading = true;
183
+ /** @deprecated Use {@link Loading}. */
184
+ get loading() {
185
+ return this.Loading;
186
+ }
187
+ /** @deprecated Use {@link Loading}. */
188
+ set loading(value) {
189
+ this.Loading = value;
190
+ }
183
191
  saving = false;
184
- viewModels = [];
185
- hasChanges = false;
192
+ ViewModels = [];
193
+ /** @deprecated Use {@link ViewModels}. */
194
+ get viewModels() {
195
+ return this.ViewModels;
196
+ }
197
+ /** @deprecated Use {@link ViewModels}. */
198
+ set viewModels(value) {
199
+ this.ViewModels = value;
200
+ }
201
+ HasChanges = false;
202
+ /** @deprecated Use {@link HasChanges}. */
203
+ get hasChanges() {
204
+ return this.HasChanges;
205
+ }
206
+ /** @deprecated Use {@link HasChanges}. */
207
+ set hasChanges(value) {
208
+ this.HasChanges = value;
209
+ }
186
210
  constructor(sharedService) {
187
211
  super();
188
212
  this.sharedService = sharedService;
@@ -201,7 +225,7 @@ export class NotificationPreferencesComponent extends BaseAngularComponent {
201
225
  */
202
226
  async loadData() {
203
227
  try {
204
- this.loading = true;
228
+ this.Loading = true;
205
229
  // UserInfoEngine is auto-configured via @RegisterForStartup()
206
230
  // NotificationEngine (server-side) loads notification types into global cache
207
231
  // UserInfoEngine provides a getter to access them from both client and server
@@ -217,7 +241,7 @@ export class NotificationPreferencesComponent extends BaseAngularComponent {
217
241
  // Get preferences from UserInfoEngine (entity objects - can be mutated)
218
242
  const prefs = UserInfoEngine.Instance.NotificationPreferences;
219
243
  // Build view models from cached data
220
- this.viewModels = types.map((type) => {
244
+ this.ViewModels = types.map((type) => {
221
245
  const existingPref = prefs.find((p) => UUIDsEqual(p.NotificationTypeID, type.ID));
222
246
  // Get channel values: user preference > type default
223
247
  const inAppEnabled = existingPref?.InAppEnabled ?? type.DefaultInApp ?? true;
@@ -235,10 +259,10 @@ export class NotificationPreferencesComponent extends BaseAngularComponent {
235
259
  originalSmsEnabled: smsEnabled,
236
260
  };
237
261
  });
238
- this.loading = false;
262
+ this.Loading = false;
239
263
  }
240
264
  catch (error) {
241
- this.loading = false;
265
+ this.Loading = false;
242
266
  const message = error instanceof Error ? error.message : 'Unknown error';
243
267
  this.sharedService.CreateSimpleNotification(`Failed to load notification preferences: ${message}`, 'error', 3000);
244
268
  }
@@ -249,9 +273,13 @@ export class NotificationPreferencesComponent extends BaseAngularComponent {
249
273
  * Sets the global hasChanges flag to show/hide the save/cancel buttons.
250
274
  * @param vm The view model for the notification type being modified
251
275
  */
252
- onChannelChange(vm) {
276
+ OnChannelChange(vm) {
253
277
  vm.changed = vm.inAppEnabled !== vm.originalInAppEnabled || vm.emailEnabled !== vm.originalEmailEnabled || vm.smsEnabled !== vm.originalSmsEnabled;
254
- this.hasChanges = this.viewModels.some((v) => v.changed);
278
+ this.HasChanges = this.ViewModels.some((v) => v.changed);
279
+ }
280
+ /** @deprecated Use {@link OnChannelChange}. */
281
+ onChannelChange(vm) {
282
+ return this.OnChannelChange(vm);
255
283
  }
256
284
  /**
257
285
  * Saves all changed notification preferences using a transaction group for batch updates.
@@ -268,7 +296,7 @@ export class NotificationPreferencesComponent extends BaseAngularComponent {
268
296
  const transGroup = await md.CreateTransactionGroup();
269
297
  // Queue all saves in transaction group - no need to await individual saves
270
298
  // Transaction group queues them and submits all in one batch
271
- for (const vm of this.viewModels.filter((v) => v.changed)) {
299
+ for (const vm of this.ViewModels.filter((v) => v.changed)) {
272
300
  let pref = vm.preference;
273
301
  if (!pref) {
274
302
  // Create new preference record
@@ -292,13 +320,13 @@ export class NotificationPreferencesComponent extends BaseAngularComponent {
292
320
  if (success) {
293
321
  // Cache refresh happens automatically in MJUserNotificationPreferenceEntityExtended.Save()
294
322
  // Update original values
295
- this.viewModels.forEach((vm) => {
323
+ this.ViewModels.forEach((vm) => {
296
324
  vm.originalInAppEnabled = vm.inAppEnabled;
297
325
  vm.originalEmailEnabled = vm.emailEnabled;
298
326
  vm.originalSmsEnabled = vm.smsEnabled;
299
327
  vm.changed = false;
300
328
  });
301
- this.hasChanges = false;
329
+ this.HasChanges = false;
302
330
  this.sharedService.CreateSimpleNotification('Notification preferences saved successfully', 'success', 2500);
303
331
  }
304
332
  else {
@@ -318,13 +346,13 @@ export class NotificationPreferencesComponent extends BaseAngularComponent {
318
346
  */
319
347
  cancel() {
320
348
  // Revert changes
321
- this.viewModels.forEach((vm) => {
349
+ this.ViewModels.forEach((vm) => {
322
350
  vm.inAppEnabled = vm.originalInAppEnabled;
323
351
  vm.emailEnabled = vm.originalEmailEnabled;
324
352
  vm.smsEnabled = vm.originalSmsEnabled;
325
353
  vm.changed = false;
326
354
  });
327
- this.hasChanges = false;
355
+ this.HasChanges = false;
328
356
  }
329
357
  /**
330
358
  * Gets the Font Awesome icon class for a notification type.
@@ -332,36 +360,52 @@ export class NotificationPreferencesComponent extends BaseAngularComponent {
332
360
  * @param type The notification type entity
333
361
  * @returns Font Awesome icon class (e.g., 'fa-bell'), defaults to 'fa-bell' if not specified
334
362
  */
335
- getTypeIcon(type) {
363
+ GetTypeIcon(type) {
336
364
  return type.Icon || 'fa-bell';
337
365
  }
366
+ /** @deprecated Use {@link GetTypeIcon}. */
367
+ getTypeIcon(type) {
368
+ return this.GetTypeIcon(type);
369
+ }
338
370
  /**
339
371
  * Gets the color hex code for a notification type.
340
372
  * Used for MD3 dynamic color styling (icon background, border accent).
341
373
  * @param type The notification type entity
342
374
  * @returns Hex color code (e.g., '#0076B6'), defaults to '#999' if not specified
343
375
  */
344
- getTypeColor(type) {
376
+ GetTypeColor(type) {
345
377
  return type.Color || '#999';
346
378
  }
379
+ /** @deprecated Use {@link GetTypeColor}. */
380
+ getTypeColor(type) {
381
+ return this.GetTypeColor(type);
382
+ }
347
383
  /**
348
384
  * Gets the auto-expire duration in days for a notification type.
349
385
  * Displayed in the metadata row to inform users about automatic read marking.
350
386
  * @param type The notification type entity
351
387
  * @returns Number of days until auto-expire, or null if not configured
352
388
  */
353
- getTypeAutoExpireDays(type) {
389
+ GetTypeAutoExpireDays(type) {
354
390
  return type.AutoExpireDays || null;
355
391
  }
392
+ /** @deprecated Use {@link GetTypeAutoExpireDays}. */
393
+ getTypeAutoExpireDays(type) {
394
+ return this.GetTypeAutoExpireDays(type);
395
+ }
356
396
  /**
357
397
  * Checks if users are allowed to customize preferences for this notification type.
358
398
  * When false, the delivery channel checkboxes are disabled and an info message is shown.
359
399
  * @param type The notification type entity
360
400
  * @returns True if user customization is allowed (default), false otherwise
361
401
  */
362
- getAllowUserPreference(type) {
402
+ GetAllowUserPreference(type) {
363
403
  return type.AllowUserPreference !== false;
364
404
  }
405
+ /** @deprecated Use {@link GetAllowUserPreference}. */
406
+ getAllowUserPreference(type) {
407
+ return this.GetAllowUserPreference(type);
408
+ }
365
409
  static ɵfac = function NotificationPreferencesComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || NotificationPreferencesComponent)(i0.ɵɵdirectiveInject(i1.SharedService)); };
366
410
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: NotificationPreferencesComponent, selectors: [["mj-notification-preferences"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 3, vars: 1, consts: [[1, "notification-preferences-container"], ["text", "Loading notification preferences..."], [1, "content"], ["Icon", "fa-solid fa-bell-slash", "Title", "No notification types configured yet."], [1, "notification-types-grid"], ["role", "group", "aria-label", "Save or cancel changes", 1, "actions"], ["role", "region", 1, "notification-type-card", 3, "changed"], ["role", "region", 1, "notification-type-card"], [1, "card-header"], [1, "icon-wrapper"], [1, "header-text"], [1, "type-description"], [1, "card-body"], [1, "preference-row"], [1, "delivery-label"], ["role", "group", 1, "delivery-checkboxes"], [1, "channel-checkbox"], ["type", "checkbox", 3, "ngModelChange", "change", "ngModel", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-bell"], ["aria-hidden", "true", 1, "fa-solid", "fa-envelope"], ["aria-hidden", "true", 1, "fa-solid", "fa-mobile"], ["Variant", "info", 1, "info-message"], [1, "metadata-row"], ["aria-hidden", "true", 1, "fa-solid", "fa-clock"], [1, "metadata-text"], ["type", "button", 1, "btn", "btn-secondary", 3, "click", "disabled"], ["type", "button", 1, "btn", "btn-primary", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["aria-hidden", "true", 1, "fa-solid", "fa-save"]], template: function NotificationPreferencesComponent_Template(rf, ctx) { if (rf & 1) {
367
411
  i0.ɵɵelementStart(0, "div", 0);
@@ -1 +1 @@
1
- {"version":3,"file":"notification-preferences.component.js","sourceRoot":"","sources":["../../../src/lib/notification-preferences/notification-preferences.component.ts","../../../src/lib/notification-preferences/notification-preferences.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit } from '@angular/core';\nimport { Metadata } from '@memberjunction/core';\nimport { MJUserNotificationTypeEntity, MJUserNotificationPreferenceEntity, UserInfoEngine } from '@memberjunction/core-entities';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport { UUIDsEqual } from '@memberjunction/global';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n/**\n * View model for managing notification preferences in the UI.\n * Combines notification type definition with user's current preferences and change tracking.\n */\ninterface NotificationPreferenceViewModel {\n /** The notification type definition (read-only) */\n type: MJUserNotificationTypeEntity;\n /** User's existing preference record, or null if not yet set */\n preference: MJUserNotificationPreferenceEntity | null;\n /** Current state: In-app notifications enabled */\n inAppEnabled: boolean;\n /** Current state: Email notifications enabled */\n emailEnabled: boolean;\n /** Current state: SMS notifications enabled */\n smsEnabled: boolean;\n /** Whether this preference has been modified by the user */\n changed: boolean;\n /** Original value for rollback: In-app enabled state */\n originalInAppEnabled: boolean;\n /** Original value for rollback: Email enabled state */\n originalEmailEnabled: boolean;\n /** Original value for rollback: SMS enabled state */\n originalSmsEnabled: boolean;\n}\n\n/**\n * Component for managing user notification preferences.\n *\n * Displays notification types with configurable delivery channels (in-app, email, SMS).\n * Users can customize which channels they want to receive notifications through,\n * unless the notification type restricts user customization.\n *\n * Uses Material Design 3 (MD3) styling principles for consistent, accessible UI.\n *\n * Data flow:\n * - Loads notification types from UserInfoEngine (global cache)\n * - Loads user preferences from UserInfoEngine (per-user cache)\n * - Saves preferences using transaction groups for batch updates\n */\n@Component({\n standalone: false,\n selector: 'mj-notification-preferences',\n templateUrl: './notification-preferences.component.html',\n styleUrls: ['./notification-preferences.component.css'],\n})\nexport class NotificationPreferencesComponent extends BaseAngularComponent implements OnInit {\n loading = true;\n saving = false;\n viewModels: NotificationPreferenceViewModel[] = [];\n hasChanges = false;\n\n constructor(private sharedService: SharedService) {\n super();}\n\n /**\n * Angular lifecycle hook - initializes the component by loading notification preferences.\n */\n async ngOnInit(): Promise<void> {\n await this.loadData();\n }\n\n /**\n * Loads notification types and user preferences from UserInfoEngine.\n * Builds view models by merging type defaults with user preferences.\n * Sorts types by Priority (ascending), then Name (alphabetical).\n * @private\n */\n private async loadData(): Promise<void> {\n try {\n this.loading = true;\n\n // UserInfoEngine is auto-configured via @RegisterForStartup()\n // NotificationEngine (server-side) loads notification types into global cache\n // UserInfoEngine provides a getter to access them from both client and server\n\n // Get notification types from UserInfoEngine, sorted client-side\n const types = [...UserInfoEngine.Instance.NotificationTypes].sort((a, b) => {\n const priorityA = a.Priority ?? 999;\n const priorityB = b.Priority ?? 999;\n if (priorityA !== priorityB) {\n return priorityA - priorityB;\n }\n return a.Name.localeCompare(b.Name);\n });\n\n // Get preferences from UserInfoEngine (entity objects - can be mutated)\n const prefs = UserInfoEngine.Instance.NotificationPreferences;\n\n // Build view models from cached data\n this.viewModels = types.map((type) => {\n const existingPref = prefs.find((p) => UUIDsEqual(p.NotificationTypeID, type.ID));\n\n // Get channel values: user preference > type default\n const inAppEnabled = existingPref?.InAppEnabled ?? type.DefaultInApp ?? true;\n const emailEnabled = existingPref?.EmailEnabled ?? type.DefaultEmail ?? false;\n const smsEnabled = existingPref?.SMSEnabled ?? type.DefaultSMS ?? false;\n\n return {\n type,\n preference: existingPref || null,\n inAppEnabled,\n emailEnabled,\n smsEnabled,\n changed: false,\n originalInAppEnabled: inAppEnabled,\n originalEmailEnabled: emailEnabled,\n originalSmsEnabled: smsEnabled,\n };\n });\n\n this.loading = false;\n } catch (error: unknown) {\n this.loading = false;\n const message = error instanceof Error ? error.message : 'Unknown error';\n this.sharedService.CreateSimpleNotification(`Failed to load notification preferences: ${message}`, 'error', 3000);\n }\n }\n\n /**\n * Called when a user toggles any delivery channel checkbox.\n * Updates the view model's changed flag by comparing current state to original values.\n * Sets the global hasChanges flag to show/hide the save/cancel buttons.\n * @param vm The view model for the notification type being modified\n */\n onChannelChange(vm: NotificationPreferenceViewModel): void {\n vm.changed = vm.inAppEnabled !== vm.originalInAppEnabled || vm.emailEnabled !== vm.originalEmailEnabled || vm.smsEnabled !== vm.originalSmsEnabled;\n this.hasChanges = this.viewModels.some((v) => v.changed);\n }\n\n /**\n * Saves all changed notification preferences using a transaction group for batch updates.\n * Creates new preference records for types that don't have existing preferences.\n * Updates the Enabled field based on whether any channel is enabled.\n * Shows success/error notification on completion.\n * @returns Promise that resolves when save is complete\n */\n async save(): Promise<void> {\n try {\n this.saving = true;\n const md = this.ProviderToUse;\n const currentUser = md.CurrentUser;\n const transGroup = await md.CreateTransactionGroup();\n\n // Queue all saves in transaction group - no need to await individual saves\n // Transaction group queues them and submits all in one batch\n for (const vm of this.viewModels.filter((v) => v.changed)) {\n let pref = vm.preference;\n\n if (!pref) {\n // Create new preference record\n pref = await md.GetEntityObject<MJUserNotificationPreferenceEntity>('MJ: User Notification Preferences');\n pref.UserID = currentUser.ID;\n pref.NotificationTypeID = vm.type.ID;\n vm.preference = pref;\n }\n\n // Set Enabled based on whether any channel is enabled\n pref.Enabled = vm.inAppEnabled || vm.emailEnabled || vm.smsEnabled;\n\n // Set the boolean channel fields\n pref.InAppEnabled = vm.inAppEnabled;\n pref.EmailEnabled = vm.emailEnabled;\n pref.SMSEnabled = vm.smsEnabled;\n pref.TransactionGroup = transGroup;\n // Don't await - Save() with transaction group queues immediately\n pref.Save();\n }\n\n // Submit transaction group - this is where the actual network call happens\n const success = await transGroup.Submit();\n\n if (success) {\n // Cache refresh happens automatically in MJUserNotificationPreferenceEntityExtended.Save()\n\n // Update original values\n this.viewModels.forEach((vm) => {\n vm.originalInAppEnabled = vm.inAppEnabled;\n vm.originalEmailEnabled = vm.emailEnabled;\n vm.originalSmsEnabled = vm.smsEnabled;\n vm.changed = false;\n });\n\n this.hasChanges = false;\n this.sharedService.CreateSimpleNotification('Notification preferences saved successfully', 'success', 2500);\n } else {\n throw new Error('Failed to save preferences');\n }\n\n this.saving = false;\n } catch (error: unknown) {\n this.saving = false;\n const message = error instanceof Error ? error.message : 'Unknown error';\n this.sharedService.CreateSimpleNotification(`Failed to save preferences: ${message}`, 'error', 3000);\n }\n }\n\n /**\n * Cancels all unsaved changes and reverts to original values.\n * Resets the changed flag on all view models and hides the action buttons.\n */\n cancel(): void {\n // Revert changes\n this.viewModels.forEach((vm) => {\n vm.inAppEnabled = vm.originalInAppEnabled;\n vm.emailEnabled = vm.originalEmailEnabled;\n vm.smsEnabled = vm.originalSmsEnabled;\n vm.changed = false;\n });\n this.hasChanges = false;\n }\n\n /**\n * Gets the Font Awesome icon class for a notification type.\n * Used for MD3 dynamic icon styling in the card header.\n * @param type The notification type entity\n * @returns Font Awesome icon class (e.g., 'fa-bell'), defaults to 'fa-bell' if not specified\n */\n getTypeIcon(type: MJUserNotificationTypeEntity): string {\n return type.Icon || 'fa-bell';\n }\n\n /**\n * Gets the color hex code for a notification type.\n * Used for MD3 dynamic color styling (icon background, border accent).\n * @param type The notification type entity\n * @returns Hex color code (e.g., '#0076B6'), defaults to '#999' if not specified\n */\n getTypeColor(type: MJUserNotificationTypeEntity): string {\n return type.Color || '#999';\n }\n\n /**\n * Gets the auto-expire duration in days for a notification type.\n * Displayed in the metadata row to inform users about automatic read marking.\n * @param type The notification type entity\n * @returns Number of days until auto-expire, or null if not configured\n */\n getTypeAutoExpireDays(type: MJUserNotificationTypeEntity): number | null {\n return type.AutoExpireDays || null;\n }\n\n /**\n * Checks if users are allowed to customize preferences for this notification type.\n * When false, the delivery channel checkboxes are disabled and an info message is shown.\n * @param type The notification type entity\n * @returns True if user customization is allowed (default), false otherwise\n */\n getAllowUserPreference(type: MJUserNotificationTypeEntity): boolean {\n return type.AllowUserPreference !== false;\n }\n}\n","<div class=\"notification-preferences-container\">\n @if (loading) {\n <mj-loading text=\"Loading notification preferences...\"></mj-loading>\n } @else {\n <div class=\"content\">\n @if (viewModels.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-bell-slash\"\n Title=\"No notification types configured yet.\" />\n } @else {\n <!-- Notification type cards -->\n <div class=\"notification-types-grid\">\n @for (vm of viewModels; track vm.type.ID) {\n <article class=\"notification-type-card\"\n [class.changed]=\"vm.changed\"\n role=\"region\"\n [attr.aria-label]=\"'Notification settings for ' + vm.type.Name\">\n\n <div class=\"card-header\" [style.border-left-color]=\"getTypeColor(vm.type)\">\n <div class=\"icon-wrapper\" [style.background-color]=\"getTypeColor(vm.type) + '20'\">\n <i [class]=\"'fa-solid ' + getTypeIcon(vm.type)\" [style.color]=\"getTypeColor(vm.type)\" [attr.aria-hidden]=\"true\"></i>\n </div>\n <div class=\"header-text\">\n <h4>{{ vm.type.Name }}</h4>\n <p class=\"type-description\">{{ vm.type.Description }}</p>\n </div>\n </div>\n\n <div class=\"card-body\">\n <!-- Delivery channel checkboxes -->\n <div class=\"preference-row\">\n <label class=\"delivery-label\" [attr.id]=\"'delivery-label-' + vm.type.ID\">Delivery Channels</label>\n\n <div class=\"delivery-checkboxes\" role=\"group\" [attr.aria-labelledby]=\"'delivery-label-' + vm.type.ID\">\n <label class=\"channel-checkbox\">\n <input type=\"checkbox\"\n [(ngModel)]=\"vm.inAppEnabled\"\n (change)=\"onChannelChange(vm)\"\n [disabled]=\"!getAllowUserPreference(vm.type)\"\n [attr.aria-label]=\"'Enable in-app notifications for ' + vm.type.Name\">\n <i class=\"fa-solid fa-bell\" aria-hidden=\"true\"></i>\n <span>In-App</span>\n </label>\n\n <label class=\"channel-checkbox\">\n <input type=\"checkbox\"\n [(ngModel)]=\"vm.emailEnabled\"\n (change)=\"onChannelChange(vm)\"\n [disabled]=\"!getAllowUserPreference(vm.type)\"\n [attr.aria-label]=\"'Enable email notifications for ' + vm.type.Name\">\n <i class=\"fa-solid fa-envelope\" aria-hidden=\"true\"></i>\n <span>Email</span>\n </label>\n\n <label class=\"channel-checkbox\">\n <input type=\"checkbox\"\n [(ngModel)]=\"vm.smsEnabled\"\n (change)=\"onChannelChange(vm)\"\n [disabled]=\"!getAllowUserPreference(vm.type)\"\n [attr.aria-label]=\"'Enable SMS notifications for ' + vm.type.Name\">\n <i class=\"fa-solid fa-mobile\" aria-hidden=\"true\"></i>\n <span>SMS</span>\n </label>\n </div>\n\n @if (!getAllowUserPreference(vm.type)) {\n <mj-alert Variant=\"info\" class=\"info-message\">This notification type's delivery channels cannot be customized.</mj-alert>\n }\n </div>\n\n <!-- Auto-expire info -->\n @if (getTypeAutoExpireDays(vm.type)) {\n <div class=\"metadata-row\">\n <i class=\"fa-solid fa-clock\" aria-hidden=\"true\"></i>\n <span class=\"metadata-text\">\n Auto-marks as read after {{ getTypeAutoExpireDays(vm.type) }} day(s)\n </span>\n </div>\n }\n </div>\n </article>\n }\n </div>\n }\n\n <!-- Action buttons -->\n @if (hasChanges) {\n <div class=\"actions\" role=\"group\" aria-label=\"Save or cancel changes\">\n <button class=\"btn btn-secondary\"\n type=\"button\"\n (click)=\"cancel()\"\n [disabled]=\"saving\"\n [attr.aria-busy]=\"saving\">\n Cancel\n </button>\n <button class=\"btn btn-primary\"\n type=\"button\"\n (click)=\"save()\"\n [disabled]=\"saving\"\n [attr.aria-busy]=\"saving\">\n @if (saving) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-save\" aria-hidden=\"true\"></i>\n }\n <span>{{ saving ? 'Saving...' : 'Save Preferences' }}</span>\n </button>\n </div>\n }\n </div>\n }\n</div>\n"]}
1
+ {"version":3,"file":"notification-preferences.component.js","sourceRoot":"","sources":["../../../src/lib/notification-preferences/notification-preferences.component.ts","../../../src/lib/notification-preferences/notification-preferences.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit } from '@angular/core';\nimport { Metadata } from '@memberjunction/core';\nimport { MJUserNotificationTypeEntity, MJUserNotificationPreferenceEntity, UserInfoEngine } from '@memberjunction/core-entities';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport { UUIDsEqual } from '@memberjunction/global';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n/**\n * View model for managing notification preferences in the UI.\n * Combines notification type definition with user's current preferences and change tracking.\n */\ninterface NotificationPreferenceViewModel {\n /** The notification type definition (read-only) */\n type: MJUserNotificationTypeEntity;\n /** User's existing preference record, or null if not yet set */\n preference: MJUserNotificationPreferenceEntity | null;\n /** Current state: In-app notifications enabled */\n inAppEnabled: boolean;\n /** Current state: Email notifications enabled */\n emailEnabled: boolean;\n /** Current state: SMS notifications enabled */\n smsEnabled: boolean;\n /** Whether this preference has been modified by the user */\n changed: boolean;\n /** Original value for rollback: In-app enabled state */\n originalInAppEnabled: boolean;\n /** Original value for rollback: Email enabled state */\n originalEmailEnabled: boolean;\n /** Original value for rollback: SMS enabled state */\n originalSmsEnabled: boolean;\n}\n\n/**\n * Component for managing user notification preferences.\n *\n * Displays notification types with configurable delivery channels (in-app, email, SMS).\n * Users can customize which channels they want to receive notifications through,\n * unless the notification type restricts user customization.\n *\n * Uses Material Design 3 (MD3) styling principles for consistent, accessible UI.\n *\n * Data flow:\n * - Loads notification types from UserInfoEngine (global cache)\n * - Loads user preferences from UserInfoEngine (per-user cache)\n * - Saves preferences using transaction groups for batch updates\n */\n@Component({\n standalone: false,\n selector: 'mj-notification-preferences',\n templateUrl: './notification-preferences.component.html',\n styleUrls: ['./notification-preferences.component.css'],\n})\nexport class NotificationPreferencesComponent extends BaseAngularComponent implements OnInit {\n Loading = true;\n\n /** @deprecated Use {@link Loading}. */\n get loading() {\n return this.Loading;\n }\n /** @deprecated Use {@link Loading}. */\n set loading(value) {\n this.Loading = value;\n }\n saving = false;\n ViewModels: NotificationPreferenceViewModel[] = [];\n\n /** @deprecated Use {@link ViewModels}. */\n get viewModels(): NotificationPreferenceViewModel[] {\n return this.ViewModels;\n }\n /** @deprecated Use {@link ViewModels}. */\n set viewModels(value: NotificationPreferenceViewModel[]) {\n this.ViewModels = value;\n }\n HasChanges = false;\n\n /** @deprecated Use {@link HasChanges}. */\n get hasChanges() {\n return this.HasChanges;\n }\n /** @deprecated Use {@link HasChanges}. */\n set hasChanges(value) {\n this.HasChanges = value;\n }\n\n constructor(private sharedService: SharedService) {\n super();}\n\n /**\n * Angular lifecycle hook - initializes the component by loading notification preferences.\n */\n async ngOnInit(): Promise<void> {\n await this.loadData();\n }\n\n /**\n * Loads notification types and user preferences from UserInfoEngine.\n * Builds view models by merging type defaults with user preferences.\n * Sorts types by Priority (ascending), then Name (alphabetical).\n * @private\n */\n private async loadData(): Promise<void> {\n try {\n this.Loading = true;\n\n // UserInfoEngine is auto-configured via @RegisterForStartup()\n // NotificationEngine (server-side) loads notification types into global cache\n // UserInfoEngine provides a getter to access them from both client and server\n\n // Get notification types from UserInfoEngine, sorted client-side\n const types = [...UserInfoEngine.Instance.NotificationTypes].sort((a, b) => {\n const priorityA = a.Priority ?? 999;\n const priorityB = b.Priority ?? 999;\n if (priorityA !== priorityB) {\n return priorityA - priorityB;\n }\n return a.Name.localeCompare(b.Name);\n });\n\n // Get preferences from UserInfoEngine (entity objects - can be mutated)\n const prefs = UserInfoEngine.Instance.NotificationPreferences;\n\n // Build view models from cached data\n this.ViewModels = types.map((type) => {\n const existingPref = prefs.find((p) => UUIDsEqual(p.NotificationTypeID, type.ID));\n\n // Get channel values: user preference > type default\n const inAppEnabled = existingPref?.InAppEnabled ?? type.DefaultInApp ?? true;\n const emailEnabled = existingPref?.EmailEnabled ?? type.DefaultEmail ?? false;\n const smsEnabled = existingPref?.SMSEnabled ?? type.DefaultSMS ?? false;\n\n return {\n type,\n preference: existingPref || null,\n inAppEnabled,\n emailEnabled,\n smsEnabled,\n changed: false,\n originalInAppEnabled: inAppEnabled,\n originalEmailEnabled: emailEnabled,\n originalSmsEnabled: smsEnabled,\n };\n });\n\n this.Loading = false;\n } catch (error: unknown) {\n this.Loading = false;\n const message = error instanceof Error ? error.message : 'Unknown error';\n this.sharedService.CreateSimpleNotification(`Failed to load notification preferences: ${message}`, 'error', 3000);\n }\n }\n\n /**\n * Called when a user toggles any delivery channel checkbox.\n * Updates the view model's changed flag by comparing current state to original values.\n * Sets the global hasChanges flag to show/hide the save/cancel buttons.\n * @param vm The view model for the notification type being modified\n */\n OnChannelChange(vm: NotificationPreferenceViewModel): void {\n vm.changed = vm.inAppEnabled !== vm.originalInAppEnabled || vm.emailEnabled !== vm.originalEmailEnabled || vm.smsEnabled !== vm.originalSmsEnabled;\n this.HasChanges = this.ViewModels.some((v) => v.changed);\n }\n\n /** @deprecated Use {@link OnChannelChange}. */\n onChannelChange(vm: NotificationPreferenceViewModel): void {\n return this.OnChannelChange(vm);\n }\n\n /**\n * Saves all changed notification preferences using a transaction group for batch updates.\n * Creates new preference records for types that don't have existing preferences.\n * Updates the Enabled field based on whether any channel is enabled.\n * Shows success/error notification on completion.\n * @returns Promise that resolves when save is complete\n */\n async save(): Promise<void> {\n try {\n this.saving = true;\n const md = this.ProviderToUse;\n const currentUser = md.CurrentUser;\n const transGroup = await md.CreateTransactionGroup();\n\n // Queue all saves in transaction group - no need to await individual saves\n // Transaction group queues them and submits all in one batch\n for (const vm of this.ViewModels.filter((v) => v.changed)) {\n let pref = vm.preference;\n\n if (!pref) {\n // Create new preference record\n pref = await md.GetEntityObject<MJUserNotificationPreferenceEntity>('MJ: User Notification Preferences');\n pref.UserID = currentUser.ID;\n pref.NotificationTypeID = vm.type.ID;\n vm.preference = pref;\n }\n\n // Set Enabled based on whether any channel is enabled\n pref.Enabled = vm.inAppEnabled || vm.emailEnabled || vm.smsEnabled;\n\n // Set the boolean channel fields\n pref.InAppEnabled = vm.inAppEnabled;\n pref.EmailEnabled = vm.emailEnabled;\n pref.SMSEnabled = vm.smsEnabled;\n pref.TransactionGroup = transGroup;\n // Don't await - Save() with transaction group queues immediately\n pref.Save();\n }\n\n // Submit transaction group - this is where the actual network call happens\n const success = await transGroup.Submit();\n\n if (success) {\n // Cache refresh happens automatically in MJUserNotificationPreferenceEntityExtended.Save()\n\n // Update original values\n this.ViewModels.forEach((vm) => {\n vm.originalInAppEnabled = vm.inAppEnabled;\n vm.originalEmailEnabled = vm.emailEnabled;\n vm.originalSmsEnabled = vm.smsEnabled;\n vm.changed = false;\n });\n\n this.HasChanges = false;\n this.sharedService.CreateSimpleNotification('Notification preferences saved successfully', 'success', 2500);\n } else {\n throw new Error('Failed to save preferences');\n }\n\n this.saving = false;\n } catch (error: unknown) {\n this.saving = false;\n const message = error instanceof Error ? error.message : 'Unknown error';\n this.sharedService.CreateSimpleNotification(`Failed to save preferences: ${message}`, 'error', 3000);\n }\n }\n\n /**\n * Cancels all unsaved changes and reverts to original values.\n * Resets the changed flag on all view models and hides the action buttons.\n */\n cancel(): void {\n // Revert changes\n this.ViewModels.forEach((vm) => {\n vm.inAppEnabled = vm.originalInAppEnabled;\n vm.emailEnabled = vm.originalEmailEnabled;\n vm.smsEnabled = vm.originalSmsEnabled;\n vm.changed = false;\n });\n this.HasChanges = false;\n }\n\n /**\n * Gets the Font Awesome icon class for a notification type.\n * Used for MD3 dynamic icon styling in the card header.\n * @param type The notification type entity\n * @returns Font Awesome icon class (e.g., 'fa-bell'), defaults to 'fa-bell' if not specified\n */\n GetTypeIcon(type: MJUserNotificationTypeEntity): string {\n return type.Icon || 'fa-bell';\n }\n\n /** @deprecated Use {@link GetTypeIcon}. */\n getTypeIcon(type: MJUserNotificationTypeEntity): string {\n return this.GetTypeIcon(type);\n }\n\n /**\n * Gets the color hex code for a notification type.\n * Used for MD3 dynamic color styling (icon background, border accent).\n * @param type The notification type entity\n * @returns Hex color code (e.g., '#0076B6'), defaults to '#999' if not specified\n */\n GetTypeColor(type: MJUserNotificationTypeEntity): string {\n return type.Color || '#999';\n }\n\n /** @deprecated Use {@link GetTypeColor}. */\n getTypeColor(type: MJUserNotificationTypeEntity): string {\n return this.GetTypeColor(type);\n }\n\n /**\n * Gets the auto-expire duration in days for a notification type.\n * Displayed in the metadata row to inform users about automatic read marking.\n * @param type The notification type entity\n * @returns Number of days until auto-expire, or null if not configured\n */\n GetTypeAutoExpireDays(type: MJUserNotificationTypeEntity): number | null {\n return type.AutoExpireDays || null;\n }\n\n /** @deprecated Use {@link GetTypeAutoExpireDays}. */\n getTypeAutoExpireDays(type: MJUserNotificationTypeEntity): number | null {\n return this.GetTypeAutoExpireDays(type);\n }\n\n /**\n * Checks if users are allowed to customize preferences for this notification type.\n * When false, the delivery channel checkboxes are disabled and an info message is shown.\n * @param type The notification type entity\n * @returns True if user customization is allowed (default), false otherwise\n */\n GetAllowUserPreference(type: MJUserNotificationTypeEntity): boolean {\n return type.AllowUserPreference !== false;\n }\n\n /** @deprecated Use {@link GetAllowUserPreference}. */\n getAllowUserPreference(type: MJUserNotificationTypeEntity): boolean {\n return this.GetAllowUserPreference(type);\n }\n}\n","<div class=\"notification-preferences-container\">\n @if (loading) {\n <mj-loading text=\"Loading notification preferences...\"></mj-loading>\n } @else {\n <div class=\"content\">\n @if (viewModels.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-bell-slash\"\n Title=\"No notification types configured yet.\" />\n } @else {\n <!-- Notification type cards -->\n <div class=\"notification-types-grid\">\n @for (vm of viewModels; track vm.type.ID) {\n <article class=\"notification-type-card\"\n [class.changed]=\"vm.changed\"\n role=\"region\"\n [attr.aria-label]=\"'Notification settings for ' + vm.type.Name\">\n\n <div class=\"card-header\" [style.border-left-color]=\"getTypeColor(vm.type)\">\n <div class=\"icon-wrapper\" [style.background-color]=\"getTypeColor(vm.type) + '20'\">\n <i [class]=\"'fa-solid ' + getTypeIcon(vm.type)\" [style.color]=\"getTypeColor(vm.type)\" [attr.aria-hidden]=\"true\"></i>\n </div>\n <div class=\"header-text\">\n <h4>{{ vm.type.Name }}</h4>\n <p class=\"type-description\">{{ vm.type.Description }}</p>\n </div>\n </div>\n\n <div class=\"card-body\">\n <!-- Delivery channel checkboxes -->\n <div class=\"preference-row\">\n <label class=\"delivery-label\" [attr.id]=\"'delivery-label-' + vm.type.ID\">Delivery Channels</label>\n\n <div class=\"delivery-checkboxes\" role=\"group\" [attr.aria-labelledby]=\"'delivery-label-' + vm.type.ID\">\n <label class=\"channel-checkbox\">\n <input type=\"checkbox\"\n [(ngModel)]=\"vm.inAppEnabled\"\n (change)=\"onChannelChange(vm)\"\n [disabled]=\"!getAllowUserPreference(vm.type)\"\n [attr.aria-label]=\"'Enable in-app notifications for ' + vm.type.Name\">\n <i class=\"fa-solid fa-bell\" aria-hidden=\"true\"></i>\n <span>In-App</span>\n </label>\n\n <label class=\"channel-checkbox\">\n <input type=\"checkbox\"\n [(ngModel)]=\"vm.emailEnabled\"\n (change)=\"onChannelChange(vm)\"\n [disabled]=\"!getAllowUserPreference(vm.type)\"\n [attr.aria-label]=\"'Enable email notifications for ' + vm.type.Name\">\n <i class=\"fa-solid fa-envelope\" aria-hidden=\"true\"></i>\n <span>Email</span>\n </label>\n\n <label class=\"channel-checkbox\">\n <input type=\"checkbox\"\n [(ngModel)]=\"vm.smsEnabled\"\n (change)=\"onChannelChange(vm)\"\n [disabled]=\"!getAllowUserPreference(vm.type)\"\n [attr.aria-label]=\"'Enable SMS notifications for ' + vm.type.Name\">\n <i class=\"fa-solid fa-mobile\" aria-hidden=\"true\"></i>\n <span>SMS</span>\n </label>\n </div>\n\n @if (!getAllowUserPreference(vm.type)) {\n <mj-alert Variant=\"info\" class=\"info-message\">This notification type's delivery channels cannot be customized.</mj-alert>\n }\n </div>\n\n <!-- Auto-expire info -->\n @if (getTypeAutoExpireDays(vm.type)) {\n <div class=\"metadata-row\">\n <i class=\"fa-solid fa-clock\" aria-hidden=\"true\"></i>\n <span class=\"metadata-text\">\n Auto-marks as read after {{ getTypeAutoExpireDays(vm.type) }} day(s)\n </span>\n </div>\n }\n </div>\n </article>\n }\n </div>\n }\n\n <!-- Action buttons -->\n @if (hasChanges) {\n <div class=\"actions\" role=\"group\" aria-label=\"Save or cancel changes\">\n <button class=\"btn btn-secondary\"\n type=\"button\"\n (click)=\"cancel()\"\n [disabled]=\"saving\"\n [attr.aria-busy]=\"saving\">\n Cancel\n </button>\n <button class=\"btn btn-primary\"\n type=\"button\"\n (click)=\"save()\"\n [disabled]=\"saving\"\n [attr.aria-busy]=\"saving\">\n @if (saving) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-save\" aria-hidden=\"true\"></i>\n }\n <span>{{ saving ? 'Saving...' : 'Save Preferences' }}</span>\n </button>\n </div>\n }\n </div>\n }\n</div>\n"]}
@@ -12,14 +12,34 @@ export interface RoleDialogResult {
12
12
  role?: MJRoleEntity;
13
13
  }
14
14
  export declare class RoleDialogComponent extends BaseAngularComponent implements OnInit, OnDestroy, OnChanges {
15
- data: RoleDialogData | null;
16
- visible: boolean;
15
+ Data: RoleDialogData | null;
16
+ /** @deprecated Use {@link Data}. */
17
+ set data(value: RoleDialogData | null);
18
+ /** @deprecated Use {@link Data}. */
19
+ get data(): RoleDialogData | null;
20
+ Visible: boolean;
21
+ /** @deprecated Use {@link Visible}. */
22
+ set visible(value: RoleDialogComponent['Visible']);
23
+ /** @deprecated Use {@link Visible}. */
24
+ get visible(): RoleDialogComponent['Visible'];
25
+ Result: EventEmitter<RoleDialogResult>;
26
+ /**
27
+ * @deprecated Use {@link Result}.
28
+ *
29
+ * The same emitter under the old binding name, so a template still binding
30
+ * (result) keeps working. Must stay AFTER Result: class fields
31
+ * initialise in order, and the other way round this captures undefined.
32
+ */
17
33
  result: EventEmitter<RoleDialogResult>;
18
34
  private fb;
19
35
  private cdr;
20
36
  private ngZone;
21
37
  private get metadata();
22
- roleForm: FormGroup;
38
+ RoleForm: FormGroup;
39
+ /** @deprecated Use {@link RoleForm}. */
40
+ get roleForm(): FormGroup;
41
+ /** @deprecated Use {@link RoleForm}. */
42
+ set roleForm(value: FormGroup);
23
43
  isLoading: boolean;
24
44
  error: string | null;
25
45
  constructor();
@@ -28,14 +48,22 @@ export declare class RoleDialogComponent extends BaseAngularComponent implements
28
48
  ngOnDestroy(): void;
29
49
  private resetForm;
30
50
  onEscapeKey(event: Event): void;
51
+ get WindowTitle(): string;
52
+ /** @deprecated Use {@link WindowTitle}. */
31
53
  get windowTitle(): string;
54
+ get IsEditMode(): boolean;
55
+ /** @deprecated Use {@link IsEditMode}. */
32
56
  get isEditMode(): boolean;
57
+ get IsSystemRole(): boolean;
58
+ /** @deprecated Use {@link IsSystemRole}. */
33
59
  get isSystemRole(): boolean;
34
60
  private loadRoleData;
61
+ OnSubmit(): Promise<void>;
62
+ /** @deprecated Use {@link OnSubmit}. */
35
63
  onSubmit(): Promise<void>;
36
64
  onCancel(): void;
37
65
  private markFormGroupTouched;
38
66
  static ɵfac: i0.ɵɵFactoryDeclaration<RoleDialogComponent, never>;
39
- static ɵcmp: i0.ɵɵComponentDeclaration<RoleDialogComponent, "mj-role-dialog", never, { "data": { "alias": "data"; "required": false; }; "visible": { "alias": "visible"; "required": false; }; }, { "result": "result"; }, never, never, false, never>;
67
+ static ɵcmp: i0.ɵɵComponentDeclaration<RoleDialogComponent, "mj-role-dialog", never, { "Data": { "alias": "Data"; "required": false; }; "data": { "alias": "data"; "required": false; }; "Visible": { "alias": "Visible"; "required": false; }; "visible": { "alias": "visible"; "required": false; }; }, { "Result": "Result"; "result": "result"; }, never, never, false, never>;
40
68
  }
41
69
  //# sourceMappingURL=role-dialog.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"role-dialog.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/role-management/role-dialog/role-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAsE,MAAM,eAAe,CAAC;AAExL,OAAO,EAAiD,SAAS,EAAc,MAAM,gBAAgB,CAAC;AAEtG,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AACrE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB;AAED,qBAOa,mBAAoB,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS,EAAE,SAAS;IAC1F,IAAI,EAAE,cAAc,GAAG,IAAI,CAAQ;IACnC,OAAO,UAAS;IACf,MAAM,iCAAwC;IAExD,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,KAAK,QAAQ,GAAiC;IAC9C,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,UAAS;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;;IAWnC,QAAQ,IAAI,IAAI;IAIhB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAWzC,WAAW,IAAI,IAAI;IAInB,OAAO,CAAC,SAAS;IAUjB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAM/B,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,IAAW,UAAU,IAAI,OAAO,CAE/B;IAED,IAAW,YAAY,IAAI,OAAO,CAIjC;IAED,OAAO,CAAC,YAAY;IAgBP,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAsD/B,QAAQ,IAAI,IAAI;IAIvB,OAAO,CAAC,oBAAoB;yCAjJjB,mBAAmB;2CAAnB,mBAAmB;CAuJ/B"}
1
+ {"version":3,"file":"role-dialog.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/role-management/role-dialog/role-dialog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAsE,MAAM,eAAe,CAAC;AAExL,OAAO,EAAiD,SAAS,EAAc,MAAM,gBAAgB,CAAC;AAEtG,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AACrE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB;AAED,qBAOa,mBAAoB,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS,EAAE,SAAS;IAC1F,IAAI,EAAE,cAAc,GAAG,IAAI,CAAQ;IAE5C,oCAAoC;IACpC,IAAa,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,EAE7C;IACD,oCAAoC;IACpC,IAAI,IAAI,IAAI,cAAc,GAAG,IAAI,CAEhC;IACQ,OAAO,UAAS;IAEzB,uCAAuC;IACvC,IAAa,OAAO,CAAC,KAAK,EAAE,mBAAmB,CAAC,SAAS,CAAC,EAEzD;IACD,uCAAuC;IACvC,IAAI,OAAO,IAAI,mBAAmB,CAAC,SAAS,CAAC,CAE5C;IACS,MAAM,iCAAwC;IAExD;;;;;;OAMG;IACO,MAAM,iCAAe;IAE/B,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,KAAK,QAAQ,GAAiC;IAC9C,QAAQ,EAAE,SAAS,CAAC;IAE3B,wCAAwC;IACxC,IAAW,QAAQ,IAAI,SAAS,CAE/B;IACD,wCAAwC;IACxC,IAAW,QAAQ,CAAC,KAAK,EAAE,SAAS,EAEnC;IACM,SAAS,UAAS;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;;IAWnC,QAAQ,IAAI,IAAI;IAIhB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAWzC,WAAW,IAAI,IAAI;IAInB,OAAO,CAAC,SAAS;IAUjB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAM/B,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,2CAA2C;IAC3C,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,IAAW,UAAU,IAAI,OAAO,CAE/B;IAED,0CAA0C;IAC1C,IAAW,UAAU,IAAI,OAAO,CAE/B;IAED,IAAW,YAAY,IAAI,OAAO,CAIjC;IAED,4CAA4C;IAC5C,IAAW,YAAY,IAAI,OAAO,CAEjC;IAED,OAAO,CAAC,YAAY;IAgBP,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAsDtC,wCAAwC;IAC3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,QAAQ,IAAI,IAAI;IAIvB,OAAO,CAAC,oBAAoB;yCAzMjB,mBAAmB;2CAAnB,mBAAmB;CA+M/B"}