@memberjunction/ng-explorer-core 2.48.0 → 2.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/app-routing.module.js +40 -53
  2. package/dist/app-routing.module.js.map +1 -1
  3. package/dist/generic/Events.types.js +104 -0
  4. package/dist/generic/Events.types.js.map +1 -1
  5. package/dist/generic/Item.types.js +28 -14
  6. package/dist/generic/Item.types.js.map +1 -1
  7. package/dist/generic/PathData.types.js +5 -0
  8. package/dist/generic/PathData.types.js.map +1 -1
  9. package/dist/generic/app-nav-view.types.js +3 -1
  10. package/dist/generic/app-nav-view.types.js.map +1 -1
  11. package/dist/lib/app-view/application-view.component.js +273 -294
  12. package/dist/lib/app-view/application-view.component.js.map +1 -1
  13. package/dist/lib/auth-button/auth-button.component.js +13 -22
  14. package/dist/lib/auth-button/auth-button.component.js.map +1 -1
  15. package/dist/lib/base-browser-component/base-browser-component.js +96 -108
  16. package/dist/lib/base-browser-component/base-browser-component.js.map +1 -1
  17. package/dist/lib/dashboard-browser-component/dashboard-browser.component.js +106 -124
  18. package/dist/lib/dashboard-browser-component/dashboard-browser.component.js.map +1 -1
  19. package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js +257 -281
  20. package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js.map +1 -1
  21. package/dist/lib/data-browser-component/data-browser.component.js +122 -137
  22. package/dist/lib/data-browser-component/data-browser.component.js.map +1 -1
  23. package/dist/lib/expansion-panel-component/expansion-panel-component.js +100 -117
  24. package/dist/lib/expansion-panel-component/expansion-panel-component.js.map +1 -1
  25. package/dist/lib/favorites/favorites.component.js +44 -54
  26. package/dist/lib/favorites/favorites.component.js.map +1 -1
  27. package/dist/lib/files/files.component.js +12 -11
  28. package/dist/lib/files/files.component.js.map +1 -1
  29. package/dist/lib/generic/form-toolbar.js +21 -20
  30. package/dist/lib/generic/form-toolbar.js.map +1 -1
  31. package/dist/lib/generic/resource-container-component.js +23 -20
  32. package/dist/lib/generic/resource-container-component.js.map +1 -1
  33. package/dist/lib/generic-browse-list/generic-browse-list.component.js +48 -46
  34. package/dist/lib/generic-browse-list/generic-browse-list.component.js.map +1 -1
  35. package/dist/lib/generic-browser-list/generic-browser-list.component.js +353 -386
  36. package/dist/lib/generic-browser-list/generic-browser-list.component.js.map +1 -1
  37. package/dist/lib/guards/auth-guard.service.js +4 -2
  38. package/dist/lib/guards/auth-guard.service.js.map +1 -1
  39. package/dist/lib/guards/entities.guard.js +1 -1
  40. package/dist/lib/guards/entities.guard.js.map +1 -1
  41. package/dist/lib/header/MSFT_UserImageService.js +4 -3
  42. package/dist/lib/header/MSFT_UserImageService.js.map +1 -1
  43. package/dist/lib/header/header.component.js +111 -121
  44. package/dist/lib/header/header.component.js.map +1 -1
  45. package/dist/lib/home-component/home.component.js +34 -42
  46. package/dist/lib/home-component/home.component.js.map +1 -1
  47. package/dist/lib/home-wrapper/home-wrapper.component.js +6 -6
  48. package/dist/lib/home-wrapper/home-wrapper.component.js.map +1 -1
  49. package/dist/lib/list-view/list-view.component.js +132 -152
  50. package/dist/lib/list-view/list-view.component.js.map +1 -1
  51. package/dist/lib/navigation/navigation.component.js +568 -615
  52. package/dist/lib/navigation/navigation.component.js.map +1 -1
  53. package/dist/lib/query-browser-component/query-browser.component.js +30 -39
  54. package/dist/lib/query-browser-component/query-browser.component.js.map +1 -1
  55. package/dist/lib/report-browser-component/report-browser.component.js +18 -30
  56. package/dist/lib/report-browser-component/report-browser.component.js.map +1 -1
  57. package/dist/lib/resource-browser/resource-browser.component.js +435 -457
  58. package/dist/lib/resource-browser/resource-browser.component.js.map +1 -1
  59. package/dist/lib/resource-wrappers/dashboard-resource.component.js +12 -25
  60. package/dist/lib/resource-wrappers/dashboard-resource.component.js.map +1 -1
  61. package/dist/lib/resource-wrappers/list-detail-resource.component.js +18 -31
  62. package/dist/lib/resource-wrappers/list-detail-resource.component.js.map +1 -1
  63. package/dist/lib/resource-wrappers/query-resource.component.js +15 -28
  64. package/dist/lib/resource-wrappers/query-resource.component.js.map +1 -1
  65. package/dist/lib/resource-wrappers/record-resource.component.js +35 -47
  66. package/dist/lib/resource-wrappers/record-resource.component.js.map +1 -1
  67. package/dist/lib/resource-wrappers/report-resource.component.js +15 -28
  68. package/dist/lib/resource-wrappers/report-resource.component.js.map +1 -1
  69. package/dist/lib/resource-wrappers/search-results-resource.component.js +21 -34
  70. package/dist/lib/resource-wrappers/search-results-resource.component.js.map +1 -1
  71. package/dist/lib/resource-wrappers/view-resource.component.js +23 -37
  72. package/dist/lib/resource-wrappers/view-resource.component.js.map +1 -1
  73. package/dist/lib/single-application/single-application.component.js +15 -20
  74. package/dist/lib/single-application/single-application.component.js.map +1 -1
  75. package/dist/lib/single-dashboard/Components/add-item/add-item.component.js +81 -95
  76. package/dist/lib/single-dashboard/Components/add-item/add-item.component.js.map +1 -1
  77. package/dist/lib/single-dashboard/Components/delete-item/delete-item.component.js +28 -29
  78. package/dist/lib/single-dashboard/Components/delete-item/delete-item.component.js.map +1 -1
  79. package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.js +51 -64
  80. package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.js.map +1 -1
  81. package/dist/lib/single-dashboard/single-dashboard.component.js +158 -165
  82. package/dist/lib/single-dashboard/single-dashboard.component.js.map +1 -1
  83. package/dist/lib/single-entity/single-entity.component.js +106 -118
  84. package/dist/lib/single-entity/single-entity.component.js.map +1 -1
  85. package/dist/lib/single-list-detail/single-list-detail.component.js +265 -287
  86. package/dist/lib/single-list-detail/single-list-detail.component.js.map +1 -1
  87. package/dist/lib/single-query/single-query.component.js +35 -44
  88. package/dist/lib/single-query/single-query.component.js.map +1 -1
  89. package/dist/lib/single-record/single-record.component.js +64 -73
  90. package/dist/lib/single-record/single-record.component.js.map +1 -1
  91. package/dist/lib/single-report/single-report.component.js +33 -43
  92. package/dist/lib/single-report/single-report.component.js.map +1 -1
  93. package/dist/lib/single-search-result/single-search-result.component.js +18 -30
  94. package/dist/lib/single-search-result/single-search-result.component.js.map +1 -1
  95. package/dist/lib/single-view/single-view.component.js +107 -124
  96. package/dist/lib/single-view/single-view.component.js.map +1 -1
  97. package/dist/lib/tabbed-dashboard/tabbed-dashboard.component.js +197 -210
  98. package/dist/lib/tabbed-dashboard/tabbed-dashboard.component.js.map +1 -1
  99. package/dist/lib/user-notifications/user-notifications.component.js +137 -155
  100. package/dist/lib/user-notifications/user-notifications.component.js.map +1 -1
  101. package/dist/lib/user-profile/user-profile.component.js +10 -8
  102. package/dist/lib/user-profile/user-profile.component.js.map +1 -1
  103. package/dist/module.js +51 -51
  104. package/dist/module.js.map +1 -1
  105. package/package.json +25 -25
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { Component, Input, Output, EventEmitter } from '@angular/core';
11
2
  import { moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
12
3
  import { LogError, Metadata, RunView } from '@memberjunction/core';
@@ -190,122 +181,112 @@ function DashboardPreferencesDialogComponent_Conditional_20_Template(rf, ctx) {
190
181
  i0.ɵɵtext(1, " Save Changes ");
191
182
  } }
192
183
  export class DashboardPreferencesDialogComponent {
193
- constructor() {
194
- this.applicationId = null;
195
- this.scope = 'Global';
196
- this.result = new EventEmitter();
197
- this.availableDashboards = [];
198
- this.configuredDashboards = [];
199
- this.applicationName = '';
200
- this.loading = true;
201
- this.saving = false;
202
- this.error = null;
203
- this.hasChanges = false;
204
- this.isSysAdmin = false;
205
- this.preferenceMode = 'personal';
206
- this.originalConfiguredIds = [];
207
- this.currentUserPreferences = [];
208
- this.allAvailableDashboards = [];
184
+ applicationId = null;
185
+ scope = 'Global';
186
+ result = new EventEmitter();
187
+ availableDashboards = [];
188
+ configuredDashboards = [];
189
+ applicationName = '';
190
+ loading = true;
191
+ saving = false;
192
+ error = null;
193
+ hasChanges = false;
194
+ isSysAdmin = false;
195
+ preferenceMode = 'personal';
196
+ originalConfiguredIds = [];
197
+ currentUserPreferences = [];
198
+ allAvailableDashboards = [];
199
+ async ngOnInit() {
200
+ try {
201
+ await this.loadData();
202
+ }
203
+ catch (error) {
204
+ LogError('Error initializing dashboard preferences dialog', null, error);
205
+ this.error = 'Failed to load dashboard preferences';
206
+ }
207
+ finally {
208
+ this.loading = false;
209
+ }
209
210
  }
210
- ngOnInit() {
211
- return __awaiter(this, void 0, void 0, function* () {
212
- try {
213
- yield this.loadData();
214
- }
215
- catch (error) {
216
- LogError('Error initializing dashboard preferences dialog', null, error);
217
- this.error = 'Failed to load dashboard preferences';
211
+ async loadData() {
212
+ const md = new Metadata();
213
+ // Check if current user is sysadmin
214
+ this.isSysAdmin = md.CurrentUser.Type.trim().toLowerCase() === 'owner';
215
+ console.log('User is sysadmin:', this.isSysAdmin);
216
+ // Default to personal preferences for all users (including sysadmin)
217
+ this.preferenceMode = 'personal';
218
+ // Load application name if we're in app scope
219
+ if (this.scope === 'App' && this.applicationId) {
220
+ await this.loadApplicationName();
221
+ }
222
+ // Get cached dashboards from MJ_Metadata dataset
223
+ const ds = await md.GetAndCacheDatasetByName("MJ_Metadata");
224
+ if (!ds || !ds.Success) {
225
+ throw new Error(ds?.Status || 'Failed to load metadata dataset');
226
+ }
227
+ const dashList = ds.Results.find(r => r.Code === 'Dashboards');
228
+ if (!dashList) {
229
+ throw new Error('Dashboards dataset not found');
230
+ }
231
+ // Filter dashboards by scope
232
+ const appFilter = this.applicationId ? ` AND ApplicationID='${this.applicationId}'` : ' AND ApplicationID IS NULL';
233
+ this.allAvailableDashboards = dashList.Results.filter((d) => {
234
+ if (this.scope === 'Global') {
235
+ return d.Scope === 'Global' && !d.ApplicationID;
218
236
  }
219
- finally {
220
- this.loading = false;
237
+ else {
238
+ return d.ApplicationID === this.applicationId; // ignore scope for dashboards that match app id, sometimes they have a global scope as they can be shown globally as well as app specific
221
239
  }
222
240
  });
241
+ // Load current user preferences
242
+ await this.loadCurrentPreferences();
243
+ // Split dashboards into available and configured
244
+ this.splitDashboards();
245
+ // Store original state to detect changes
246
+ this.originalConfiguredIds = this.configuredDashboards.map(d => d.ID);
223
247
  }
224
- loadData() {
225
- return __awaiter(this, void 0, void 0, function* () {
248
+ async loadApplicationName() {
249
+ if (!this.applicationId)
250
+ return;
251
+ try {
226
252
  const md = new Metadata();
227
- // Check if current user is sysadmin
228
- this.isSysAdmin = md.CurrentUser.Type.trim().toLowerCase() === 'owner';
229
- console.log('User is sysadmin:', this.isSysAdmin);
230
- // Default to personal preferences for all users (including sysadmin)
231
- this.preferenceMode = 'personal';
232
- // Load application name if we're in app scope
233
- if (this.scope === 'App' && this.applicationId) {
234
- yield this.loadApplicationName();
235
- }
236
- // Get cached dashboards from MJ_Metadata dataset
237
- const ds = yield md.GetAndCacheDatasetByName("MJ_Metadata");
238
- if (!ds || !ds.Success) {
239
- throw new Error((ds === null || ds === void 0 ? void 0 : ds.Status) || 'Failed to load metadata dataset');
240
- }
241
- const dashList = ds.Results.find(r => r.Code === 'Dashboards');
242
- if (!dashList) {
243
- throw new Error('Dashboards dataset not found');
244
- }
245
- // Filter dashboards by scope
246
- const appFilter = this.applicationId ? ` AND ApplicationID='${this.applicationId}'` : ' AND ApplicationID IS NULL';
247
- this.allAvailableDashboards = dashList.Results.filter((d) => {
248
- if (this.scope === 'Global') {
249
- return d.Scope === 'Global' && !d.ApplicationID;
250
- }
251
- else {
252
- return d.ApplicationID === this.applicationId; // ignore scope for dashboards that match app id, sometimes they have a global scope as they can be shown globally as well as app specific
253
- }
254
- });
255
- // Load current user preferences
256
- yield this.loadCurrentPreferences();
257
- // Split dashboards into available and configured
258
- this.splitDashboards();
259
- // Store original state to detect changes
260
- this.originalConfiguredIds = this.configuredDashboards.map(d => d.ID);
261
- });
262
- }
263
- loadApplicationName() {
264
- return __awaiter(this, void 0, void 0, function* () {
265
- if (!this.applicationId)
266
- return;
267
- try {
268
- const md = new Metadata();
269
- const ds = yield md.GetAndCacheDatasetByName("MJ_Metadata");
270
- const appList = ds.Results.find(r => r.Code === 'Applications');
271
- if (appList) {
272
- const app = appList.Results.find((a) => a.ID === this.applicationId);
273
- this.applicationName = (app === null || app === void 0 ? void 0 : app.Name) || 'Unknown Application';
274
- }
253
+ const ds = await md.GetAndCacheDatasetByName("MJ_Metadata");
254
+ const appList = ds.Results.find(r => r.Code === 'Applications');
255
+ if (appList) {
256
+ const app = appList.Results.find((a) => a.ID === this.applicationId);
257
+ this.applicationName = app?.Name || 'Unknown Application';
275
258
  }
276
- catch (error) {
277
- LogError('Error loading application name', null, error);
278
- this.applicationName = 'Unknown Application';
279
- }
280
- });
259
+ }
260
+ catch (error) {
261
+ LogError('Error loading application name', null, error);
262
+ this.applicationName = 'Unknown Application';
263
+ }
281
264
  }
282
- loadCurrentPreferences() {
283
- return __awaiter(this, void 0, void 0, function* () {
284
- const rv = new RunView();
285
- const md = new Metadata();
286
- const appFilter = this.applicationId ? ` AND ApplicationID='${this.applicationId}'` : '';
287
- const baseCondition = `Scope='${this.scope}'${appFilter}`;
288
- let filter;
289
- if (this.isSysAdmin && this.scope === 'Global' && this.preferenceMode === 'system') {
290
- // Load system defaults only (UserID IS NULL)
291
- filter = `UserID IS NULL AND ${baseCondition}`;
292
- }
293
- else {
294
- // Load personal user preferences (including for sysadmin when in personal mode)
295
- // For personal mode, we ONLY load the user's specific preferences, no fallback to system defaults
296
- // This allows sysadmin to see their actual personal preferences vs system defaults
297
- filter = `UserID='${md.CurrentUser.ID}' AND ${baseCondition}`;
298
- }
299
- console.log('Loading preferences with filter:', filter);
300
- const prefsResult = yield rv.RunView({
301
- EntityName: 'MJ: Dashboard User Preferences',
302
- ExtraFilter: filter,
303
- ResultType: 'entity_object',
304
- OrderBy: 'DisplayOrder',
305
- });
306
- this.currentUserPreferences = (prefsResult === null || prefsResult === void 0 ? void 0 : prefsResult.Results) || [];
307
- console.log('Loaded preferences:', this.currentUserPreferences.length);
265
+ async loadCurrentPreferences() {
266
+ const rv = new RunView();
267
+ const md = new Metadata();
268
+ const appFilter = this.applicationId ? ` AND ApplicationID='${this.applicationId}'` : '';
269
+ const baseCondition = `Scope='${this.scope}'${appFilter}`;
270
+ let filter;
271
+ if (this.isSysAdmin && this.scope === 'Global' && this.preferenceMode === 'system') {
272
+ // Load system defaults only (UserID IS NULL)
273
+ filter = `UserID IS NULL AND ${baseCondition}`;
274
+ }
275
+ else {
276
+ // Load personal user preferences (including for sysadmin when in personal mode)
277
+ // For personal mode, we ONLY load the user's specific preferences, no fallback to system defaults
278
+ // This allows sysadmin to see their actual personal preferences vs system defaults
279
+ filter = `UserID='${md.CurrentUser.ID}' AND ${baseCondition}`;
280
+ }
281
+ console.log('Loading preferences with filter:', filter);
282
+ const prefsResult = await rv.RunView({
283
+ EntityName: 'MJ: Dashboard User Preferences',
284
+ ExtraFilter: filter,
285
+ ResultType: 'entity_object',
286
+ OrderBy: 'DisplayOrder',
308
287
  });
288
+ this.currentUserPreferences = prefsResult?.Results || [];
289
+ console.log('Loaded preferences:', this.currentUserPreferences.length);
309
290
  }
310
291
  splitDashboards() {
311
292
  const configuredIds = new Set(this.currentUserPreferences.map(p => p.DashboardID));
@@ -380,25 +361,23 @@ export class DashboardPreferencesDialogComponent {
380
361
  }, 3000);
381
362
  }
382
363
  }
383
- onPreferenceModeChange() {
384
- return __awaiter(this, void 0, void 0, function* () {
385
- try {
386
- this.loading = true;
387
- this.error = null;
388
- // Reload preferences with new mode
389
- yield this.loadCurrentPreferences();
390
- this.splitDashboards();
391
- this.originalConfiguredIds = this.configuredDashboards.map(d => d.ID);
392
- this.hasChanges = false;
393
- }
394
- catch (error) {
395
- LogError('Error changing preference mode', null, error);
396
- this.error = 'Error loading preferences. Please try again.';
397
- }
398
- finally {
399
- this.loading = false;
400
- }
401
- });
364
+ async onPreferenceModeChange() {
365
+ try {
366
+ this.loading = true;
367
+ this.error = null;
368
+ // Reload preferences with new mode
369
+ await this.loadCurrentPreferences();
370
+ this.splitDashboards();
371
+ this.originalConfiguredIds = this.configuredDashboards.map(d => d.ID);
372
+ this.hasChanges = false;
373
+ }
374
+ catch (error) {
375
+ LogError('Error changing preference mode', null, error);
376
+ this.error = 'Error loading preferences. Please try again.';
377
+ }
378
+ finally {
379
+ this.loading = false;
380
+ }
402
381
  }
403
382
  checkForChanges() {
404
383
  try {
@@ -418,166 +397,163 @@ export class DashboardPreferencesDialogComponent {
418
397
  this.hasChanges = false;
419
398
  }
420
399
  }
421
- onSave() {
422
- return __awaiter(this, void 0, void 0, function* () {
423
- var _a, _b, _c, _d, _e, _f;
424
- if (this.saving || !this.hasChanges) {
425
- console.log('Save cancelled:', { saving: this.saving, hasChanges: this.hasChanges });
426
- return;
400
+ async onSave() {
401
+ if (this.saving || !this.hasChanges) {
402
+ console.log('Save cancelled:', { saving: this.saving, hasChanges: this.hasChanges });
403
+ return;
404
+ }
405
+ try {
406
+ this.saving = true;
407
+ console.log('Starting save process with configured dashboards:', this.configuredDashboards.map(d => ({ id: d.ID, name: d.Name })));
408
+ const md = new Metadata();
409
+ const rv = new RunView();
410
+ // Get existing preferences for this scope
411
+ const baseCondition = this.scope === 'Global'
412
+ ? `Scope='Global' AND ApplicationID IS NULL`
413
+ : `Scope='App' AND ApplicationID='${this.applicationId}'`;
414
+ let userFilter;
415
+ if (this.isSysAdmin && this.scope === 'Global' && this.preferenceMode === 'system') {
416
+ // Managing system defaults
417
+ userFilter = `UserID IS NULL AND ${baseCondition}`;
427
418
  }
428
- try {
429
- this.saving = true;
430
- console.log('Starting save process with configured dashboards:', this.configuredDashboards.map(d => ({ id: d.ID, name: d.Name })));
431
- const md = new Metadata();
432
- const rv = new RunView();
433
- // Get existing preferences for this scope
434
- const baseCondition = this.scope === 'Global'
435
- ? `Scope='Global' AND ApplicationID IS NULL`
436
- : `Scope='App' AND ApplicationID='${this.applicationId}'`;
437
- let userFilter;
438
- if (this.isSysAdmin && this.scope === 'Global' && this.preferenceMode === 'system') {
439
- // Managing system defaults
440
- userFilter = `UserID IS NULL AND ${baseCondition}`;
441
- }
442
- else {
443
- // Managing personal preferences
444
- userFilter = `UserID='${md.CurrentUser.ID}' AND ${baseCondition}`;
419
+ else {
420
+ // Managing personal preferences
421
+ userFilter = `UserID='${md.CurrentUser.ID}' AND ${baseCondition}`;
422
+ }
423
+ console.log('Loading existing preferences with filter:', userFilter);
424
+ const existingPrefs = await rv.RunView({
425
+ EntityName: 'MJ: Dashboard User Preferences',
426
+ ExtraFilter: userFilter,
427
+ ResultType: 'entity_object',
428
+ });
429
+ const existingPreferences = existingPrefs?.Results || [];
430
+ console.log('Found existing preferences:', existingPreferences.length);
431
+ // Create maps for efficient lookups
432
+ const existingByDashboardId = new Map();
433
+ existingPreferences.forEach(pref => {
434
+ existingByDashboardId.set(pref.DashboardID, pref);
435
+ });
436
+ const configuredDashboardIds = new Set(this.configuredDashboards.map(d => d.ID));
437
+ // Step 1: Delete preferences that are no longer configured
438
+ const prefsToDelete = existingPreferences.filter(pref => !configuredDashboardIds.has(pref.DashboardID));
439
+ console.log('Preferences to delete:', prefsToDelete.length);
440
+ for (const pref of prefsToDelete) {
441
+ console.log('Deleting preference for dashboard:', pref.DashboardID);
442
+ if (!await pref.Delete()) {
443
+ const errorMsg = pref.LatestResult?.Error || pref.LatestResult?.Message || 'Unknown error';
444
+ throw new Error(`Failed to delete preference: ${errorMsg}`);
445
445
  }
446
- console.log('Loading existing preferences with filter:', userFilter);
447
- const existingPrefs = yield rv.RunView({
448
- EntityName: 'MJ: Dashboard User Preferences',
449
- ExtraFilter: userFilter,
450
- ResultType: 'entity_object',
451
- });
452
- const existingPreferences = (existingPrefs === null || existingPrefs === void 0 ? void 0 : existingPrefs.Results) || [];
453
- console.log('Found existing preferences:', existingPreferences.length);
454
- // Create maps for efficient lookups
455
- const existingByDashboardId = new Map();
456
- existingPreferences.forEach(pref => {
457
- existingByDashboardId.set(pref.DashboardID, pref);
458
- });
459
- const configuredDashboardIds = new Set(this.configuredDashboards.map(d => d.ID));
460
- // Step 1: Delete preferences that are no longer configured
461
- const prefsToDelete = existingPreferences.filter(pref => !configuredDashboardIds.has(pref.DashboardID));
462
- console.log('Preferences to delete:', prefsToDelete.length);
463
- for (const pref of prefsToDelete) {
464
- console.log('Deleting preference for dashboard:', pref.DashboardID);
465
- if (!(yield pref.Delete())) {
466
- const errorMsg = ((_a = pref.LatestResult) === null || _a === void 0 ? void 0 : _a.Error) || ((_b = pref.LatestResult) === null || _b === void 0 ? void 0 : _b.Message) || 'Unknown error';
467
- throw new Error(`Failed to delete preference: ${errorMsg}`);
446
+ }
447
+ // Step 2: Update existing preferences or create new ones
448
+ const newPreferences = [];
449
+ for (let i = 0; i < this.configuredDashboards.length; i++) {
450
+ const dashboard = this.configuredDashboards[i];
451
+ const newDisplayOrder = i + 1;
452
+ let prefEntity = existingByDashboardId.get(dashboard.ID);
453
+ if (prefEntity) {
454
+ // Update existing preference
455
+ console.log(`Updating existing preference for dashboard ${dashboard.Name}, new order: ${newDisplayOrder}`);
456
+ prefEntity.DisplayOrder = newDisplayOrder;
457
+ if (!await prefEntity.Save()) {
458
+ const errorMsg = prefEntity.LatestResult?.Error || prefEntity.LatestResult?.Message || 'Unknown error';
459
+ throw new Error(`Failed to update preference for dashboard ${dashboard.Name}: ${errorMsg}`);
468
460
  }
469
461
  }
470
- // Step 2: Update existing preferences or create new ones
471
- const newPreferences = [];
472
- for (let i = 0; i < this.configuredDashboards.length; i++) {
473
- const dashboard = this.configuredDashboards[i];
474
- const newDisplayOrder = i + 1;
475
- let prefEntity = existingByDashboardId.get(dashboard.ID);
476
- if (prefEntity) {
477
- // Update existing preference
478
- console.log(`Updating existing preference for dashboard ${dashboard.Name}, new order: ${newDisplayOrder}`);
479
- prefEntity.DisplayOrder = newDisplayOrder;
480
- if (!(yield prefEntity.Save())) {
481
- const errorMsg = ((_c = prefEntity.LatestResult) === null || _c === void 0 ? void 0 : _c.Error) || ((_d = prefEntity.LatestResult) === null || _d === void 0 ? void 0 : _d.Message) || 'Unknown error';
482
- throw new Error(`Failed to update preference for dashboard ${dashboard.Name}: ${errorMsg}`);
483
- }
462
+ else {
463
+ // Create new preference
464
+ console.log(`Creating new preference for dashboard ${dashboard.Name}, order: ${newDisplayOrder}`);
465
+ prefEntity = await md.GetEntityObject('MJ: Dashboard User Preferences');
466
+ // Set UserID based on preference mode
467
+ if (this.isSysAdmin && this.scope === 'Global' && this.preferenceMode === 'system') {
468
+ prefEntity.UserID = null; // System default
484
469
  }
485
470
  else {
486
- // Create new preference
487
- console.log(`Creating new preference for dashboard ${dashboard.Name}, order: ${newDisplayOrder}`);
488
- prefEntity = yield md.GetEntityObject('MJ: Dashboard User Preferences');
489
- // Set UserID based on preference mode
490
- if (this.isSysAdmin && this.scope === 'Global' && this.preferenceMode === 'system') {
491
- prefEntity.UserID = null; // System default
492
- }
493
- else {
494
- prefEntity.UserID = md.CurrentUser.ID; // Personal preference
495
- }
496
- prefEntity.DashboardID = dashboard.ID;
497
- prefEntity.DisplayOrder = newDisplayOrder;
498
- prefEntity.Scope = this.scope;
499
- prefEntity.ApplicationID = this.applicationId;
500
- console.log('Creating preference entity:', {
501
- UserID: prefEntity.UserID,
502
- DashboardID: prefEntity.DashboardID,
503
- DisplayOrder: prefEntity.DisplayOrder,
504
- Scope: prefEntity.Scope,
505
- ApplicationID: prefEntity.ApplicationID
506
- });
507
- if (!(yield prefEntity.Save())) {
508
- const errorMsg = ((_e = prefEntity.LatestResult) === null || _e === void 0 ? void 0 : _e.Error) || ((_f = prefEntity.LatestResult) === null || _f === void 0 ? void 0 : _f.Message) || 'Unknown error';
509
- throw new Error(`Failed to create preference for dashboard ${dashboard.Name}: ${errorMsg}`);
510
- }
471
+ prefEntity.UserID = md.CurrentUser.ID; // Personal preference
472
+ }
473
+ prefEntity.DashboardID = dashboard.ID;
474
+ prefEntity.DisplayOrder = newDisplayOrder;
475
+ prefEntity.Scope = this.scope;
476
+ prefEntity.ApplicationID = this.applicationId;
477
+ console.log('Creating preference entity:', {
478
+ UserID: prefEntity.UserID,
479
+ DashboardID: prefEntity.DashboardID,
480
+ DisplayOrder: prefEntity.DisplayOrder,
481
+ Scope: prefEntity.Scope,
482
+ ApplicationID: prefEntity.ApplicationID
483
+ });
484
+ if (!await prefEntity.Save()) {
485
+ const errorMsg = prefEntity.LatestResult?.Error || prefEntity.LatestResult?.Message || 'Unknown error';
486
+ throw new Error(`Failed to create preference for dashboard ${dashboard.Name}: ${errorMsg}`);
511
487
  }
512
- newPreferences.push(prefEntity);
513
488
  }
514
- console.log('Successfully processed', newPreferences.length, 'preferences');
515
- // Emit success result
516
- this.result.emit({
517
- saved: true,
518
- preferences: newPreferences
519
- });
489
+ newPreferences.push(prefEntity);
520
490
  }
521
- catch (error) {
522
- console.error('Save error:', error);
523
- LogError('Error saving dashboard preferences', null, error);
524
- this.error = `Failed to save preferences: ${error instanceof Error ? error.message : 'Unknown error'}`;
525
- // Clear error after 5 seconds
526
- setTimeout(() => {
527
- this.error = null;
528
- }, 5000);
529
- }
530
- finally {
531
- this.saving = false;
532
- }
533
- });
491
+ console.log('Successfully processed', newPreferences.length, 'preferences');
492
+ // Emit success result
493
+ this.result.emit({
494
+ saved: true,
495
+ preferences: newPreferences
496
+ });
497
+ }
498
+ catch (error) {
499
+ console.error('Save error:', error);
500
+ LogError('Error saving dashboard preferences', null, error);
501
+ this.error = `Failed to save preferences: ${error instanceof Error ? error.message : 'Unknown error'}`;
502
+ // Clear error after 5 seconds
503
+ setTimeout(() => {
504
+ this.error = null;
505
+ }, 5000);
506
+ }
507
+ finally {
508
+ this.saving = false;
509
+ }
534
510
  }
535
511
  onCancel() {
536
512
  this.result.emit({ saved: false });
537
513
  }
514
+ static ɵfac = function DashboardPreferencesDialogComponent_Factory(t) { return new (t || DashboardPreferencesDialogComponent)(); };
515
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DashboardPreferencesDialogComponent, selectors: [["mj-dashboard-preferences-dialog"]], inputs: { applicationId: "applicationId", scope: "scope" }, outputs: { result: "result" }, decls: 21, vars: 11, consts: [["availableList", "cdkDropList"], ["configuredList", "cdkDropList"], ["title", "Dashboard Preferences", 3, "close", "width", "height", "minWidth", "minHeight"], [1, "dashboard-preferences-dialog"], [1, "dialog-header"], [1, "fa-solid", "fa-sliders"], [1, "scope-indicator"], [1, "preference-mode-selector"], [1, "dialog-content"], [1, "loading-container"], [1, "error-container"], [1, "preferences-panels"], [1, "dialog-footer"], ["type", "button", 1, "btn", "btn-secondary", 3, "click"], [1, "fa-solid", "fa-times"], ["type", "button", 1, "btn", "btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-globe"], [1, "fa-solid", "fa-layer-group"], ["type", "radio", "name", "preferenceMode", "value", "personal", 3, "ngModelChange", "change", "ngModel"], ["type", "radio", "name", "preferenceMode", "value", "system", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "panel", "available-panel"], [1, "fa-solid", "fa-list"], ["cdkDropList", "", 1, "dashboard-list", 3, "cdkDropListDropped", "cdkDropListData", "cdkDropListConnectedTo"], [1, "empty-state"], ["cdkDrag", "", 1, "dashboard-item", "available-item", 3, "cdkDragData"], [1, "panel", "configured-panel"], [1, "fa-solid", "fa-list-ol"], ["cdkDrag", "", 1, "dashboard-item", "configured-item", 3, "cdkDragData"], [1, "fa-solid", "fa-info-circle"], [1, "dashboard-item-content"], [1, "fa-solid", "fa-grip-vertical", "drag-handle"], [1, "dashboard-info"], [1, "dashboard-name"], [1, "dashboard-description"], ["type", "button", "title", "Add to configured dashboards", 1, "add-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "order-number"], ["type", "button", "title", "Remove from configured dashboards", 1, "remove-button", 3, "click"], ["size", "small"], [1, "fa-solid", "fa-check"]], template: function DashboardPreferencesDialogComponent_Template(rf, ctx) { if (rf & 1) {
516
+ i0.ɵɵelementStart(0, "kendo-dialog", 2);
517
+ i0.ɵɵlistener("close", function DashboardPreferencesDialogComponent_Template_kendo_dialog_close_0_listener() { return ctx.onCancel(); });
518
+ i0.ɵɵelementStart(1, "div", 3)(2, "div", 4)(3, "h3");
519
+ i0.ɵɵelement(4, "i", 5);
520
+ i0.ɵɵtext(5, " Dashboard Preferences");
521
+ i0.ɵɵelementEnd();
522
+ i0.ɵɵelementStart(6, "p", 6);
523
+ i0.ɵɵtemplate(7, DashboardPreferencesDialogComponent_Conditional_7_Template, 2, 0)(8, DashboardPreferencesDialogComponent_Conditional_8_Template, 2, 1);
524
+ i0.ɵɵelementEnd();
525
+ i0.ɵɵtemplate(9, DashboardPreferencesDialogComponent_Conditional_9_Template, 7, 2, "div", 7);
526
+ i0.ɵɵelementEnd();
527
+ i0.ɵɵelementStart(10, "div", 8);
528
+ i0.ɵɵtemplate(11, DashboardPreferencesDialogComponent_Conditional_11_Template, 3, 0, "div", 9)(12, DashboardPreferencesDialogComponent_Conditional_12_Template, 3, 1, "div", 10)(13, DashboardPreferencesDialogComponent_Conditional_13_Template, 19, 10, "div", 11);
529
+ i0.ɵɵelementEnd();
530
+ i0.ɵɵelementStart(14, "div", 12)(15, "button", 13);
531
+ i0.ɵɵlistener("click", function DashboardPreferencesDialogComponent_Template_button_click_15_listener() { return ctx.onCancel(); });
532
+ i0.ɵɵelement(16, "i", 14);
533
+ i0.ɵɵtext(17, " Cancel ");
534
+ i0.ɵɵelementEnd();
535
+ i0.ɵɵelementStart(18, "button", 15);
536
+ i0.ɵɵlistener("click", function DashboardPreferencesDialogComponent_Template_button_click_18_listener() { return ctx.onSave(); });
537
+ i0.ɵɵtemplate(19, DashboardPreferencesDialogComponent_Conditional_19_Template, 2, 0)(20, DashboardPreferencesDialogComponent_Conditional_20_Template, 2, 0);
538
+ i0.ɵɵelementEnd()()()();
539
+ } if (rf & 2) {
540
+ i0.ɵɵproperty("width", 800)("height", 600)("minWidth", 600)("minHeight", 400);
541
+ i0.ɵɵadvance(7);
542
+ i0.ɵɵconditional(ctx.scope === "Global" ? 7 : 8);
543
+ i0.ɵɵadvance(2);
544
+ i0.ɵɵconditional(ctx.isSysAdmin && ctx.scope === "Global" ? 9 : -1);
545
+ i0.ɵɵadvance(2);
546
+ i0.ɵɵconditional(ctx.loading ? 11 : -1);
547
+ i0.ɵɵadvance();
548
+ i0.ɵɵconditional(ctx.error ? 12 : -1);
549
+ i0.ɵɵadvance();
550
+ i0.ɵɵconditional(!ctx.loading && !ctx.error ? 13 : -1);
551
+ i0.ɵɵadvance(5);
552
+ i0.ɵɵproperty("disabled", !ctx.hasChanges || ctx.saving);
553
+ i0.ɵɵadvance();
554
+ i0.ɵɵconditional(ctx.saving ? 19 : 20);
555
+ } }, dependencies: [i1.DefaultValueAccessor, i1.RadioControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.DialogComponent, i3.LoaderComponent, i4.CdkDropList, i4.CdkDrag], styles: [".dashboard-preferences-dialog[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.dialog-header[_ngcontent-%COMP%] {\n padding: 20px 24px 16px;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.dialog-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: #333;\n}\n\n.dialog-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: #666;\n}\n\n.scope-indicator[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: #666;\n}\n\n.scope-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 6px;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] {\n margin-top: 12px;\n display: flex;\n gap: 20px;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 14px;\n color: #495057;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n margin: 0;\n}\n\n.dialog-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n}\n\n.loading-container[_ngcontent-%COMP%], .error-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n flex-direction: column;\n gap: 12px;\n}\n\n.error-container[_ngcontent-%COMP%] {\n color: #dc3545;\n}\n\n.error-container[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n margin-bottom: 8px;\n}\n\n.preferences-panels[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n height: 100%;\n}\n\n.panel[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.panel[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n padding: 12px 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n font-size: 14px;\n font-weight: 600;\n color: #495057;\n}\n\n.panel[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: #6c757d;\n}\n\n.dashboard-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n min-height: 300px;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100px;\n color: #6c757d;\n font-style: italic;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n opacity: 0.5;\n}\n\n.dashboard-item[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n background: white;\n transition: all 0.2s ease;\n cursor: move;\n}\n\n.dashboard-item[_ngcontent-%COMP%]:hover {\n border-color: #007bff;\n box-shadow: 0 2px 4px rgba(0, 123, 255, 0.1);\n}\n\n.dashboard-item.cdk-drag-preview[_ngcontent-%COMP%] {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transform: rotate(2deg);\n}\n\n.dashboard-item.cdk-drag-placeholder[_ngcontent-%COMP%] {\n opacity: 0.3;\n border-style: dashed;\n}\n\n.dashboard-item-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px;\n gap: 12px;\n}\n\n.drag-handle[_ngcontent-%COMP%] {\n color: #adb5bd;\n cursor: move;\n font-size: 14px;\n}\n\n.order-number[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: #007bff;\n color: white;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.dashboard-info[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dashboard-name[_ngcontent-%COMP%] {\n font-weight: 500;\n color: #333;\n font-size: 14px;\n}\n\n.dashboard-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #6c757d;\n line-height: 1.3;\n}\n\n.add-button[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #28a745;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n}\n\n.add-button[_ngcontent-%COMP%]:hover {\n background-color: rgba(40, 167, 69, 0.1);\n opacity: 1;\n}\n\n.remove-button[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #dc3545;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n}\n\n.remove-button[_ngcontent-%COMP%]:hover {\n background-color: rgba(220, 53, 69, 0.1);\n}\n\n.cdk-drop-list-dragging[_ngcontent-%COMP%] .dashboard-item[_ngcontent-%COMP%]:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.dialog-footer[_ngcontent-%COMP%] {\n padding: 16px 24px;\n border-top: 1px solid #e0e0e0;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: #f8f9fa;\n}\n\n.btn[_ngcontent-%COMP%] {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: white;\n border-color: #6c757d;\n color: #6c757d;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #6c757d;\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: #007bff;\n color: white;\n border-color: #007bff;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #0056b3;\n border-color: #0056b3;\n}\n\n\n\n@media (max-width: 768px) {\n .dashboard-preferences-dialog[_ngcontent-%COMP%] {\n width: 95vw;\n max-height: 90vh;\n }\n \n .preferences-panels[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n \n .panel[_ngcontent-%COMP%] {\n min-height: 200px;\n }\n \n .dashboard-list[_ngcontent-%COMP%] {\n min-height: 150px;\n }\n}"] });
538
556
  }
539
- DashboardPreferencesDialogComponent.ɵfac = function DashboardPreferencesDialogComponent_Factory(t) { return new (t || DashboardPreferencesDialogComponent)(); };
540
- DashboardPreferencesDialogComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DashboardPreferencesDialogComponent, selectors: [["mj-dashboard-preferences-dialog"]], inputs: { applicationId: "applicationId", scope: "scope" }, outputs: { result: "result" }, decls: 21, vars: 11, consts: [["availableList", "cdkDropList"], ["configuredList", "cdkDropList"], ["title", "Dashboard Preferences", 3, "close", "width", "height", "minWidth", "minHeight"], [1, "dashboard-preferences-dialog"], [1, "dialog-header"], [1, "fa-solid", "fa-sliders"], [1, "scope-indicator"], [1, "preference-mode-selector"], [1, "dialog-content"], [1, "loading-container"], [1, "error-container"], [1, "preferences-panels"], [1, "dialog-footer"], ["type", "button", 1, "btn", "btn-secondary", 3, "click"], [1, "fa-solid", "fa-times"], ["type", "button", 1, "btn", "btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-globe"], [1, "fa-solid", "fa-layer-group"], ["type", "radio", "name", "preferenceMode", "value", "personal", 3, "ngModelChange", "change", "ngModel"], ["type", "radio", "name", "preferenceMode", "value", "system", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "panel", "available-panel"], [1, "fa-solid", "fa-list"], ["cdkDropList", "", 1, "dashboard-list", 3, "cdkDropListDropped", "cdkDropListData", "cdkDropListConnectedTo"], [1, "empty-state"], ["cdkDrag", "", 1, "dashboard-item", "available-item", 3, "cdkDragData"], [1, "panel", "configured-panel"], [1, "fa-solid", "fa-list-ol"], ["cdkDrag", "", 1, "dashboard-item", "configured-item", 3, "cdkDragData"], [1, "fa-solid", "fa-info-circle"], [1, "dashboard-item-content"], [1, "fa-solid", "fa-grip-vertical", "drag-handle"], [1, "dashboard-info"], [1, "dashboard-name"], [1, "dashboard-description"], ["type", "button", "title", "Add to configured dashboards", 1, "add-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "order-number"], ["type", "button", "title", "Remove from configured dashboards", 1, "remove-button", 3, "click"], ["size", "small"], [1, "fa-solid", "fa-check"]], template: function DashboardPreferencesDialogComponent_Template(rf, ctx) { if (rf & 1) {
541
- i0.ɵɵelementStart(0, "kendo-dialog", 2);
542
- i0.ɵɵlistener("close", function DashboardPreferencesDialogComponent_Template_kendo_dialog_close_0_listener() { return ctx.onCancel(); });
543
- i0.ɵɵelementStart(1, "div", 3)(2, "div", 4)(3, "h3");
544
- i0.ɵɵelement(4, "i", 5);
545
- i0.ɵɵtext(5, " Dashboard Preferences");
546
- i0.ɵɵelementEnd();
547
- i0.ɵɵelementStart(6, "p", 6);
548
- i0.ɵɵtemplate(7, DashboardPreferencesDialogComponent_Conditional_7_Template, 2, 0)(8, DashboardPreferencesDialogComponent_Conditional_8_Template, 2, 1);
549
- i0.ɵɵelementEnd();
550
- i0.ɵɵtemplate(9, DashboardPreferencesDialogComponent_Conditional_9_Template, 7, 2, "div", 7);
551
- i0.ɵɵelementEnd();
552
- i0.ɵɵelementStart(10, "div", 8);
553
- i0.ɵɵtemplate(11, DashboardPreferencesDialogComponent_Conditional_11_Template, 3, 0, "div", 9)(12, DashboardPreferencesDialogComponent_Conditional_12_Template, 3, 1, "div", 10)(13, DashboardPreferencesDialogComponent_Conditional_13_Template, 19, 10, "div", 11);
554
- i0.ɵɵelementEnd();
555
- i0.ɵɵelementStart(14, "div", 12)(15, "button", 13);
556
- i0.ɵɵlistener("click", function DashboardPreferencesDialogComponent_Template_button_click_15_listener() { return ctx.onCancel(); });
557
- i0.ɵɵelement(16, "i", 14);
558
- i0.ɵɵtext(17, " Cancel ");
559
- i0.ɵɵelementEnd();
560
- i0.ɵɵelementStart(18, "button", 15);
561
- i0.ɵɵlistener("click", function DashboardPreferencesDialogComponent_Template_button_click_18_listener() { return ctx.onSave(); });
562
- i0.ɵɵtemplate(19, DashboardPreferencesDialogComponent_Conditional_19_Template, 2, 0)(20, DashboardPreferencesDialogComponent_Conditional_20_Template, 2, 0);
563
- i0.ɵɵelementEnd()()()();
564
- } if (rf & 2) {
565
- i0.ɵɵproperty("width", 800)("height", 600)("minWidth", 600)("minHeight", 400);
566
- i0.ɵɵadvance(7);
567
- i0.ɵɵconditional(ctx.scope === "Global" ? 7 : 8);
568
- i0.ɵɵadvance(2);
569
- i0.ɵɵconditional(ctx.isSysAdmin && ctx.scope === "Global" ? 9 : -1);
570
- i0.ɵɵadvance(2);
571
- i0.ɵɵconditional(ctx.loading ? 11 : -1);
572
- i0.ɵɵadvance();
573
- i0.ɵɵconditional(ctx.error ? 12 : -1);
574
- i0.ɵɵadvance();
575
- i0.ɵɵconditional(!ctx.loading && !ctx.error ? 13 : -1);
576
- i0.ɵɵadvance(5);
577
- i0.ɵɵproperty("disabled", !ctx.hasChanges || ctx.saving);
578
- i0.ɵɵadvance();
579
- i0.ɵɵconditional(ctx.saving ? 19 : 20);
580
- } }, dependencies: [i1.DefaultValueAccessor, i1.RadioControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.DialogComponent, i3.LoaderComponent, i4.CdkDropList, i4.CdkDrag], styles: [".dashboard-preferences-dialog[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.dialog-header[_ngcontent-%COMP%] {\n padding: 20px 24px 16px;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.dialog-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: #333;\n}\n\n.dialog-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: #666;\n}\n\n.scope-indicator[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: #666;\n}\n\n.scope-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 6px;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] {\n margin-top: 12px;\n display: flex;\n gap: 20px;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 14px;\n color: #495057;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n margin: 0;\n}\n\n.dialog-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n}\n\n.loading-container[_ngcontent-%COMP%], .error-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n flex-direction: column;\n gap: 12px;\n}\n\n.error-container[_ngcontent-%COMP%] {\n color: #dc3545;\n}\n\n.error-container[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n margin-bottom: 8px;\n}\n\n.preferences-panels[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n height: 100%;\n}\n\n.panel[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.panel[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n padding: 12px 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n font-size: 14px;\n font-weight: 600;\n color: #495057;\n}\n\n.panel[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: #6c757d;\n}\n\n.dashboard-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n min-height: 300px;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100px;\n color: #6c757d;\n font-style: italic;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n opacity: 0.5;\n}\n\n.dashboard-item[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n background: white;\n transition: all 0.2s ease;\n cursor: move;\n}\n\n.dashboard-item[_ngcontent-%COMP%]:hover {\n border-color: #007bff;\n box-shadow: 0 2px 4px rgba(0, 123, 255, 0.1);\n}\n\n.dashboard-item.cdk-drag-preview[_ngcontent-%COMP%] {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transform: rotate(2deg);\n}\n\n.dashboard-item.cdk-drag-placeholder[_ngcontent-%COMP%] {\n opacity: 0.3;\n border-style: dashed;\n}\n\n.dashboard-item-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px;\n gap: 12px;\n}\n\n.drag-handle[_ngcontent-%COMP%] {\n color: #adb5bd;\n cursor: move;\n font-size: 14px;\n}\n\n.order-number[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: #007bff;\n color: white;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.dashboard-info[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dashboard-name[_ngcontent-%COMP%] {\n font-weight: 500;\n color: #333;\n font-size: 14px;\n}\n\n.dashboard-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #6c757d;\n line-height: 1.3;\n}\n\n.add-button[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #28a745;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n}\n\n.add-button[_ngcontent-%COMP%]:hover {\n background-color: rgba(40, 167, 69, 0.1);\n opacity: 1;\n}\n\n.remove-button[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #dc3545;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n}\n\n.remove-button[_ngcontent-%COMP%]:hover {\n background-color: rgba(220, 53, 69, 0.1);\n}\n\n.cdk-drop-list-dragging[_ngcontent-%COMP%] .dashboard-item[_ngcontent-%COMP%]:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.dialog-footer[_ngcontent-%COMP%] {\n padding: 16px 24px;\n border-top: 1px solid #e0e0e0;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: #f8f9fa;\n}\n\n.btn[_ngcontent-%COMP%] {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: white;\n border-color: #6c757d;\n color: #6c757d;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #6c757d;\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: #007bff;\n color: white;\n border-color: #007bff;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #0056b3;\n border-color: #0056b3;\n}\n\n\n\n@media (max-width: 768px) {\n .dashboard-preferences-dialog[_ngcontent-%COMP%] {\n width: 95vw;\n max-height: 90vh;\n }\n \n .preferences-panels[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n \n .panel[_ngcontent-%COMP%] {\n min-height: 200px;\n }\n \n .dashboard-list[_ngcontent-%COMP%] {\n min-height: 150px;\n }\n}"] });
581
557
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DashboardPreferencesDialogComponent, [{
582
558
  type: Component,
583
559
  args: [{ selector: 'mj-dashboard-preferences-dialog', template: "<kendo-dialog title=\"Dashboard Preferences\" \n [width]=\"800\" \n [height]=\"600\"\n [minWidth]=\"600\"\n [minHeight]=\"400\"\n (close)=\"onCancel()\">\n<div class=\"dashboard-preferences-dialog\">\n <div class=\"dialog-header\">\n <h3><i class=\"fa-solid fa-sliders\"></i> Dashboard Preferences</h3>\n <p class=\"scope-indicator\">\n @if (scope === 'Global') {\n <i class=\"fa-solid fa-globe\"></i> Global Scope\n } @else {\n <i class=\"fa-solid fa-layer-group\"></i> Application: {{ applicationName }}\n }\n </p>\n @if (isSysAdmin && scope === 'Global') {\n <div class=\"preference-mode-selector\">\n <label>\n <input type=\"radio\" \n name=\"preferenceMode\" \n value=\"personal\" \n [(ngModel)]=\"preferenceMode\"\n (change)=\"onPreferenceModeChange()\">\n Personal Preferences\n </label>\n <label>\n <input type=\"radio\" \n name=\"preferenceMode\" \n value=\"system\" \n [(ngModel)]=\"preferenceMode\"\n (change)=\"onPreferenceModeChange()\">\n System Defaults\n </label>\n </div>\n }\n </div>\n\n <div class=\"dialog-content\">\n @if (loading) {\n <div class=\"loading-container\">\n <kendo-loader></kendo-loader>\n Loading dashboards...\n </div>\n }\n\n @if (error) {\n <div class=\"error-container\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ error }}\n </div>\n }\n\n @if (!loading && !error) {\n <div class=\"preferences-panels\">\n <!-- Available Dashboards Panel -->\n <div class=\"panel available-panel\">\n <h4><i class=\"fa-solid fa-list\"></i> Available Dashboards</h4>\n <div class=\"dashboard-list\" \n cdkDropList \n #availableList=\"cdkDropList\"\n [cdkDropListData]=\"availableDashboards\"\n [cdkDropListConnectedTo]=\"[configuredList]\"\n (cdkDropListDropped)=\"onDrop($event)\">\n \n @if (availableDashboards.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-info-circle\"></i>\n All dashboards are configured\n </div>\n }\n\n @for (dashboard of availableDashboards; track dashboard.ID) {\n <div class=\"dashboard-item available-item\" \n cdkDrag\n [cdkDragData]=\"dashboard\">\n <div class=\"dashboard-item-content\">\n <i class=\"fa-solid fa-grip-vertical drag-handle\"></i>\n <div class=\"dashboard-info\">\n <span class=\"dashboard-name\">{{ dashboard.Name }}</span>\n @if (dashboard.Description) {\n <span class=\"dashboard-description\">{{ dashboard.Description }}</span>\n }\n </div>\n <button type=\"button\" \n class=\"add-button\"\n (click)=\"addDashboard(dashboard)\"\n title=\"Add to configured dashboards\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Configured Dashboards Panel -->\n <div class=\"panel configured-panel\">\n <h4><i class=\"fa-solid fa-list-ol\"></i> Configured Dashboards</h4>\n <div class=\"dashboard-list\" \n cdkDropList \n #configuredList=\"cdkDropList\"\n [cdkDropListData]=\"configuredDashboards\"\n [cdkDropListConnectedTo]=\"[availableList]\"\n (cdkDropListDropped)=\"onDrop($event)\">\n \n @if (configuredDashboards.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-info-circle\"></i>\n No dashboards configured\n </div>\n }\n\n @for (dashboard of configuredDashboards; track dashboard.ID; let i = $index) {\n <div class=\"dashboard-item configured-item\" \n cdkDrag\n [cdkDragData]=\"dashboard\">\n <div class=\"dashboard-item-content\">\n <i class=\"fa-solid fa-grip-vertical drag-handle\"></i>\n <span class=\"order-number\">{{ i + 1 }}</span>\n <div class=\"dashboard-info\">\n <span class=\"dashboard-name\">{{ dashboard.Name }}</span>\n @if (dashboard.Description) {\n <span class=\"dashboard-description\">{{ dashboard.Description }}</span>\n }\n </div>\n <button type=\"button\" \n class=\"remove-button\"\n (click)=\"removeDashboard(dashboard)\"\n title=\"Remove from configured dashboards\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n <div class=\"dialog-footer\">\n <button type=\"button\" \n class=\"btn btn-secondary\" \n (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i> Cancel\n </button>\n <button type=\"button\" \n class=\"btn btn-primary\" \n [disabled]=\"!hasChanges || saving\"\n (click)=\"onSave()\">\n @if (saving) {\n <kendo-loader size=\"small\"></kendo-loader>\n Saving...\n } @else {\n <i class=\"fa-solid fa-check\"></i> Save Changes\n }\n </button>\n </div>\n</div>\n</kendo-dialog>", styles: [".dashboard-preferences-dialog {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.dialog-header {\n padding: 20px 24px 16px;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.dialog-header h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: #333;\n}\n\n.dialog-header h3 i {\n margin-right: 8px;\n color: #666;\n}\n\n.scope-indicator {\n margin: 0;\n font-size: 14px;\n color: #666;\n}\n\n.scope-indicator i {\n margin-right: 6px;\n}\n\n.preference-mode-selector {\n margin-top: 12px;\n display: flex;\n gap: 20px;\n}\n\n.preference-mode-selector label {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 14px;\n color: #495057;\n}\n\n.preference-mode-selector input[type=\"radio\"] {\n margin: 0;\n}\n\n.dialog-content {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n}\n\n.loading-container, .error-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n flex-direction: column;\n gap: 12px;\n}\n\n.error-container {\n color: #dc3545;\n}\n\n.error-container i {\n font-size: 24px;\n margin-bottom: 8px;\n}\n\n.preferences-panels {\n display: flex;\n gap: 20px;\n height: 100%;\n}\n\n.panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.panel h4 {\n margin: 0;\n padding: 12px 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n font-size: 14px;\n font-weight: 600;\n color: #495057;\n}\n\n.panel h4 i {\n margin-right: 8px;\n color: #6c757d;\n}\n\n.dashboard-list {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n min-height: 300px;\n}\n\n.empty-state {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100px;\n color: #6c757d;\n font-style: italic;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-state i {\n font-size: 24px;\n opacity: 0.5;\n}\n\n.dashboard-item {\n margin-bottom: 8px;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n background: white;\n transition: all 0.2s ease;\n cursor: move;\n}\n\n.dashboard-item:hover {\n border-color: #007bff;\n box-shadow: 0 2px 4px rgba(0, 123, 255, 0.1);\n}\n\n.dashboard-item.cdk-drag-preview {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transform: rotate(2deg);\n}\n\n.dashboard-item.cdk-drag-placeholder {\n opacity: 0.3;\n border-style: dashed;\n}\n\n.dashboard-item-content {\n display: flex;\n align-items: center;\n padding: 12px;\n gap: 12px;\n}\n\n.drag-handle {\n color: #adb5bd;\n cursor: move;\n font-size: 14px;\n}\n\n.order-number {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: #007bff;\n color: white;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.dashboard-info {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dashboard-name {\n font-weight: 500;\n color: #333;\n font-size: 14px;\n}\n\n.dashboard-description {\n font-size: 12px;\n color: #6c757d;\n line-height: 1.3;\n}\n\n.add-button {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #28a745;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n}\n\n.add-button:hover {\n background-color: rgba(40, 167, 69, 0.1);\n opacity: 1;\n}\n\n.remove-button {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #dc3545;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n}\n\n.remove-button:hover {\n background-color: rgba(220, 53, 69, 0.1);\n}\n\n.cdk-drop-list-dragging .dashboard-item:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.dialog-footer {\n padding: 16px 24px;\n border-top: 1px solid #e0e0e0;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: #f8f9fa;\n}\n\n.btn {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-secondary {\n background: white;\n border-color: #6c757d;\n color: #6c757d;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: #6c757d;\n color: white;\n}\n\n.btn-primary {\n background: #007bff;\n color: white;\n border-color: #007bff;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: #0056b3;\n border-color: #0056b3;\n}\n\n/* Responsive design */\n@media (max-width: 768px) {\n .dashboard-preferences-dialog {\n width: 95vw;\n max-height: 90vh;\n }\n \n .preferences-panels {\n flex-direction: column;\n gap: 16px;\n }\n \n .panel {\n min-height: 200px;\n }\n \n .dashboard-list {\n min-height: 150px;\n }\n}"] }]