@memberjunction/ng-dashboard-viewer 6.1.4 → 6.2.0-edge.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/lib/config-dialogs/confirm-dialog.component.d.ts +58 -8
  2. package/dist/lib/config-dialogs/confirm-dialog.component.d.ts.map +1 -1
  3. package/dist/lib/config-dialogs/confirm-dialog.component.js +119 -17
  4. package/dist/lib/config-dialogs/confirm-dialog.component.js.map +1 -1
  5. package/dist/lib/config-panels/artifact-config-panel.component.d.ts +63 -11
  6. package/dist/lib/config-panels/artifact-config-panel.component.d.ts.map +1 -1
  7. package/dist/lib/config-panels/artifact-config-panel.component.js +152 -48
  8. package/dist/lib/config-panels/artifact-config-panel.component.js.map +1 -1
  9. package/dist/lib/config-panels/query-config-panel.component.d.ts +57 -9
  10. package/dist/lib/config-panels/query-config-panel.component.d.ts.map +1 -1
  11. package/dist/lib/config-panels/query-config-panel.component.js +142 -46
  12. package/dist/lib/config-panels/query-config-panel.component.js.map +1 -1
  13. package/dist/lib/config-panels/view-config-panel.component.d.ts +69 -11
  14. package/dist/lib/config-panels/view-config-panel.component.d.ts.map +1 -1
  15. package/dist/lib/config-panels/view-config-panel.component.js +165 -49
  16. package/dist/lib/config-panels/view-config-panel.component.js.map +1 -1
  17. package/dist/lib/config-panels/weburl-config-panel.component.d.ts +42 -6
  18. package/dist/lib/config-panels/weburl-config-panel.component.d.ts.map +1 -1
  19. package/dist/lib/config-panels/weburl-config-panel.component.js +113 -41
  20. package/dist/lib/config-panels/weburl-config-panel.component.js.map +1 -1
  21. package/dist/lib/dashboard-browser/dashboard-browser.component.d.ts.map +1 -1
  22. package/dist/lib/dashboard-browser/dashboard-browser.component.js +7 -4
  23. package/dist/lib/dashboard-browser/dashboard-browser.component.js.map +1 -1
  24. package/dist/lib/dashboard-viewer/dashboard-viewer.component.d.ts +163 -12
  25. package/dist/lib/dashboard-viewer/dashboard-viewer.component.d.ts.map +1 -1
  26. package/dist/lib/dashboard-viewer/dashboard-viewer.component.js +332 -78
  27. package/dist/lib/dashboard-viewer/dashboard-viewer.component.js.map +1 -1
  28. package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.d.ts +63 -9
  29. package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.d.ts.map +1 -1
  30. package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.js +172 -66
  31. package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.js.map +1 -1
  32. package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.d.ts +11 -1
  33. package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.d.ts.map +1 -1
  34. package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.js +30 -10
  35. package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.js.map +1 -1
  36. package/dist/lib/models/dashboard-types.d.ts +8 -0
  37. package/dist/lib/models/dashboard-types.d.ts.map +1 -1
  38. package/dist/lib/models/dashboard-types.js +21 -5
  39. package/dist/lib/models/dashboard-types.js.map +1 -1
  40. package/dist/lib/parts/artifact-part.component.d.ts +63 -7
  41. package/dist/lib/parts/artifact-part.component.d.ts.map +1 -1
  42. package/dist/lib/parts/artifact-part.component.js +98 -22
  43. package/dist/lib/parts/artifact-part.component.js.map +1 -1
  44. package/dist/lib/parts/query-part.component.d.ts +26 -4
  45. package/dist/lib/parts/query-part.component.d.ts.map +1 -1
  46. package/dist/lib/parts/query-part.component.js +62 -18
  47. package/dist/lib/parts/query-part.component.js.map +1 -1
  48. package/dist/lib/parts/view-part.component.d.ts +21 -3
  49. package/dist/lib/parts/view-part.component.d.ts.map +1 -1
  50. package/dist/lib/parts/view-part.component.js +55 -19
  51. package/dist/lib/parts/view-part.component.js.map +1 -1
  52. package/dist/lib/parts/weburl-part.component.d.ts +29 -5
  53. package/dist/lib/parts/weburl-part.component.d.ts.map +1 -1
  54. package/dist/lib/parts/weburl-part.component.js +63 -15
  55. package/dist/lib/parts/weburl-part.component.js.map +1 -1
  56. package/dist/lib/services/golden-layout-wrapper.service.d.ts +65 -5
  57. package/dist/lib/services/golden-layout-wrapper.service.d.ts.map +1 -1
  58. package/dist/lib/services/golden-layout-wrapper.service.js +135 -27
  59. package/dist/lib/services/golden-layout-wrapper.service.js.map +1 -1
  60. package/package.json +13 -13
@@ -4,7 +4,7 @@ import { takeUntil } from 'rxjs/operators';
4
4
  import { MJGlobal, UUIDsEqual, EscapeHTML } from '@memberjunction/global';
5
5
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
6
6
  import { DashboardEngine } from '@memberjunction/core-entities';
7
- import { createDefaultDashboardConfig, generatePanelId, extractPanelsFromLayout, findPanelInLayout } from '../models/dashboard-types';
7
+ import { CreateDefaultDashboardConfig, GeneratePanelId, ExtractPanelsFromLayout, FindPanelInLayout } from '../models/dashboard-types';
8
8
  import { GoldenLayoutWrapperService } from '../services/golden-layout-wrapper.service';
9
9
  import { BaseDashboardPart } from '../parts/base-dashboard-part';
10
10
  import * as i0 from "@angular/core";
@@ -135,30 +135,46 @@ export class DashboardViewerComponent extends BaseAngularComponent {
135
135
  _dashboard = null;
136
136
  _dashboardId = null;
137
137
  /** The dashboard entity to display */
138
- set dashboard(value) {
138
+ set Dashboard(value) {
139
139
  const previous = this._dashboard;
140
140
  this._dashboard = value;
141
141
  if (value && value !== previous) {
142
142
  this.onDashboardChanged();
143
143
  }
144
144
  }
145
- get dashboard() {
145
+ get Dashboard() {
146
146
  return this._dashboard;
147
147
  }
148
+ /** @deprecated Use {@link Dashboard}. */
149
+ get dashboard() {
150
+ return this.Dashboard;
151
+ }
152
+ /** @deprecated Use {@link Dashboard}. */
153
+ set dashboard(value) {
154
+ this.Dashboard = value;
155
+ }
148
156
  /** Alternative: Load dashboard by ID */
149
- set dashboardId(value) {
157
+ set DashboardId(value) {
150
158
  const previous = this._dashboardId;
151
159
  this._dashboardId = value;
152
160
  if (value && value !== previous) {
153
161
  this.loadDashboardById(value);
154
162
  }
155
163
  }
156
- get dashboardId() {
164
+ get DashboardId() {
157
165
  return this._dashboardId;
158
166
  }
167
+ /** @deprecated Use {@link DashboardId}. */
168
+ get dashboardId() {
169
+ return this.DashboardId;
170
+ }
171
+ /** @deprecated Use {@link DashboardId}. */
172
+ set dashboardId(value) {
173
+ this.DashboardId = value;
174
+ }
159
175
  /** Whether the dashboard is in edit mode */
160
176
  _isEditing = false;
161
- set isEditing(value) {
177
+ set IsEditing(value) {
162
178
  const previous = this._isEditing;
163
179
  this._isEditing = value;
164
180
  // When isEditing changes (and layout exists), reinitialize to apply GL settings
@@ -167,43 +183,95 @@ export class DashboardViewerComponent extends BaseAngularComponent {
167
183
  this.updatePanelEditModes();
168
184
  }
169
185
  }
170
- get isEditing() {
186
+ get IsEditing() {
171
187
  return this._isEditing;
172
188
  }
189
+ /** @deprecated Use {@link IsEditing}. */
190
+ get isEditing() {
191
+ return this.IsEditing;
192
+ }
193
+ /** @deprecated Use {@link IsEditing}. */
194
+ set isEditing(value) {
195
+ this.IsEditing = value;
196
+ }
173
197
  /** Whether to show the toolbar */
174
198
  _showToolbar = true;
175
- set showToolbar(value) {
199
+ set ShowToolbar(value) {
176
200
  this._showToolbar = value;
177
201
  }
178
- get showToolbar() {
202
+ get ShowToolbar() {
179
203
  return this._showToolbar;
180
204
  }
205
+ /** @deprecated Use {@link ShowToolbar}. */
206
+ get showToolbar() {
207
+ return this.ShowToolbar;
208
+ }
209
+ /** @deprecated Use {@link ShowToolbar}. */
210
+ set showToolbar(value) {
211
+ this.ShowToolbar = value;
212
+ }
181
213
  /** Whether to auto-save layout changes */
182
214
  _autoSave = false;
183
- set autoSave(value) {
215
+ set AutoSave(value) {
184
216
  this._autoSave = value;
185
217
  }
186
- get autoSave() {
218
+ get AutoSave() {
187
219
  return this._autoSave;
188
220
  }
221
+ /** @deprecated Use {@link AutoSave}. */
222
+ get autoSave() {
223
+ return this.AutoSave;
224
+ }
225
+ /** @deprecated Use {@link AutoSave}. */
226
+ set autoSave(value) {
227
+ this.AutoSave = value;
228
+ }
189
229
  /** Whether to show the breadcrumb navigation */
190
- showBreadcrumb = true;
230
+ ShowBreadcrumb = true;
231
+ /** @deprecated Use {@link ShowBreadcrumb}. */
232
+ set showBreadcrumb(value) {
233
+ this.ShowBreadcrumb = value;
234
+ }
235
+ /** @deprecated Use {@link ShowBreadcrumb}. */
236
+ get showBreadcrumb() {
237
+ return this.ShowBreadcrumb;
238
+ }
191
239
  /** Whether to show the "Open in Tab" button (for embedded dashboards) */
192
- showOpenInTabButton = false;
240
+ ShowOpenInTabButton = false;
241
+ /** @deprecated Use {@link ShowOpenInTabButton}. */
242
+ set showOpenInTabButton(value) {
243
+ this.ShowOpenInTabButton = value;
244
+ }
245
+ /** @deprecated Use {@link ShowOpenInTabButton}. */
246
+ get showOpenInTabButton() {
247
+ return this.ShowOpenInTabButton;
248
+ }
193
249
  /** Whether to show the Edit button */
194
- showEditButton = true;
250
+ ShowEditButton = true;
251
+ /** @deprecated Use {@link ShowEditButton}. */
252
+ set showEditButton(value) {
253
+ this.ShowEditButton = value;
254
+ }
255
+ /** @deprecated Use {@link ShowEditButton}. */
256
+ get showEditButton() {
257
+ return this.ShowEditButton;
258
+ }
195
259
  /** All categories for breadcrumb path resolution */
196
260
  Categories = [];
197
261
  /**
198
262
  * Computed: Should the toolbar be visible?
199
263
  * Auto-hides when showToolbar=false OR when all toolbar elements are disabled
200
264
  */
201
- get shouldShowToolbar() {
265
+ get ShouldShowToolbar() {
202
266
  if (!this._showToolbar) {
203
267
  return false;
204
268
  }
205
269
  // If all elements are hidden, hide the toolbar entirely
206
- return this.showBreadcrumb || this.showOpenInTabButton || this.showEditButton;
270
+ return this.ShowBreadcrumb || this.ShowOpenInTabButton || this.ShowEditButton;
271
+ }
272
+ /** @deprecated Use {@link ShouldShowToolbar}. */
273
+ get shouldShowToolbar() {
274
+ return this.ShouldShowToolbar;
207
275
  }
208
276
  // ========================================
209
277
  // Outputs
@@ -211,42 +279,142 @@ export class DashboardViewerComponent extends BaseAngularComponent {
211
279
  /** Emitted when dashboard configuration changes */
212
280
  configChanged = new EventEmitter();
213
281
  /** Emitted when a panel requests navigation to another resource */
214
- navigationRequested = new EventEmitter();
282
+ NavigationRequested = new EventEmitter();
283
+ /**
284
+ * @deprecated Use {@link NavigationRequested}.
285
+ *
286
+ * The same emitter under the old binding name, so a template still binding
287
+ * (navigationRequested) keeps working. Must stay AFTER NavigationRequested: class fields
288
+ * initialise in order, and the other way round this captures undefined.
289
+ */
290
+ navigationRequested = this.NavigationRequested;
215
291
  /** Emitted when a panel interaction occurs */
216
- panelInteraction = new EventEmitter();
292
+ PanelInteraction = new EventEmitter();
293
+ /**
294
+ * @deprecated Use {@link PanelInteraction}.
295
+ *
296
+ * The same emitter under the old binding name, so a template still binding
297
+ * (panelInteraction) keeps working. Must stay AFTER PanelInteraction: class fields
298
+ * initialise in order, and the other way round this captures undefined.
299
+ */
300
+ panelInteraction = this.PanelInteraction;
217
301
  /** Emitted when the dashboard is saved */
218
- dashboardSaved = new EventEmitter();
302
+ DashboardSaved = new EventEmitter();
303
+ /**
304
+ * @deprecated Use {@link DashboardSaved}.
305
+ *
306
+ * The same emitter under the old binding name, so a template still binding
307
+ * (dashboardSaved) keeps working. Must stay AFTER DashboardSaved: class fields
308
+ * initialise in order, and the other way round this captures undefined.
309
+ */
310
+ dashboardSaved = this.DashboardSaved;
219
311
  /** Emitted when an error occurs */
220
312
  error = new EventEmitter();
221
313
  /** Emitted when edit mode changes */
222
- editModeChanged = new EventEmitter();
314
+ EditModeChanged = new EventEmitter();
315
+ /**
316
+ * @deprecated Use {@link EditModeChanged}.
317
+ *
318
+ * The same emitter under the old binding name, so a template still binding
319
+ * (editModeChanged) keeps working. Must stay AFTER EditModeChanged: class fields
320
+ * initialise in order, and the other way round this captures undefined.
321
+ */
322
+ editModeChanged = this.EditModeChanged;
223
323
  /** Emitted when user navigates via breadcrumb */
224
- breadcrumbNavigate = new EventEmitter();
324
+ BreadcrumbNavigate = new EventEmitter();
325
+ /**
326
+ * @deprecated Use {@link BreadcrumbNavigate}.
327
+ *
328
+ * The same emitter under the old binding name, so a template still binding
329
+ * (breadcrumbNavigate) keeps working. Must stay AFTER BreadcrumbNavigate: class fields
330
+ * initialise in order, and the other way round this captures undefined.
331
+ */
332
+ breadcrumbNavigate = this.BreadcrumbNavigate;
225
333
  /** Emitted when user clicks "Open in Tab" button */
226
- openInTab = new EventEmitter();
334
+ OpenInTab = new EventEmitter();
335
+ /**
336
+ * @deprecated Use {@link OpenInTab}.
337
+ *
338
+ * The same emitter under the old binding name, so a template still binding
339
+ * (openInTab) keeps working. Must stay AFTER OpenInTab: class fields
340
+ * initialise in order, and the other way round this captures undefined.
341
+ */
342
+ openInTab = this.OpenInTab;
227
343
  /** Emitted as the Golden Layout viewer moves through dashboard/layout readiness states. */
228
- layoutLifecycle = new EventEmitter();
344
+ LayoutLifecycle = new EventEmitter();
345
+ /**
346
+ * @deprecated Use {@link LayoutLifecycle}.
347
+ *
348
+ * The same emitter under the old binding name, so a template still binding
349
+ * (layoutLifecycle) keeps working. Must stay AFTER LayoutLifecycle: class fields
350
+ * initialise in order, and the other way round this captures undefined.
351
+ */
352
+ layoutLifecycle = this.LayoutLifecycle;
229
353
  /** Emitted once Golden Layout has initialized with a non-zero container and updated its size. */
230
- layoutReady = new EventEmitter();
354
+ LayoutReady = new EventEmitter();
355
+ /**
356
+ * @deprecated Use {@link LayoutReady}.
357
+ *
358
+ * The same emitter under the old binding name, so a template still binding
359
+ * (layoutReady) keeps working. Must stay AFTER LayoutReady: class fields
360
+ * initialise in order, and the other way round this captures undefined.
361
+ */
362
+ layoutReady = this.LayoutReady;
231
363
  /** Emitted when layout initialization is deferred because the container cannot be initialized yet. */
232
- layoutDeferred = new EventEmitter();
364
+ LayoutDeferred = new EventEmitter();
365
+ /**
366
+ * @deprecated Use {@link LayoutDeferred}.
367
+ *
368
+ * The same emitter under the old binding name, so a template still binding
369
+ * (layoutDeferred) keeps working. Must stay AFTER LayoutDeferred: class fields
370
+ * initialise in order, and the other way round this captures undefined.
371
+ */
372
+ layoutDeferred = this.LayoutDeferred;
233
373
  // ========================================
234
374
  // View Children
235
375
  // ========================================
236
- layoutContainer;
376
+ LayoutContainer;
377
+ /** @deprecated Use {@link LayoutContainer}. */
378
+ get layoutContainer() {
379
+ return this.LayoutContainer;
380
+ }
381
+ /** @deprecated Use {@link LayoutContainer}. */
382
+ set layoutContainer(value) {
383
+ this.LayoutContainer = value;
384
+ }
237
385
  // ========================================
238
386
  // State
239
387
  // ========================================
240
388
  isLoading = false;
241
389
  config = null;
242
- partTypes = [];
243
- hasUnsavedChanges = false;
390
+ PartTypes = [];
391
+ /** @deprecated Use {@link PartTypes}. */
392
+ get partTypes() {
393
+ return this.PartTypes;
394
+ }
395
+ /** @deprecated Use {@link PartTypes}. */
396
+ set partTypes(value) {
397
+ this.PartTypes = value;
398
+ }
399
+ HasUnsavedChanges = false;
400
+ /** @deprecated Use {@link HasUnsavedChanges}. */
401
+ get hasUnsavedChanges() {
402
+ return this.HasUnsavedChanges;
403
+ }
404
+ /** @deprecated Use {@link HasUnsavedChanges}. */
405
+ set hasUnsavedChanges(value) {
406
+ this.HasUnsavedChanges = value;
407
+ }
244
408
  /**
245
409
  * Helper to check if layout has any panels (for template use).
246
410
  * Panels are stored in componentState within the layout tree.
247
411
  */
412
+ get HasPanels() {
413
+ return ExtractPanelsFromLayout(this.config?.layout ?? null).length > 0;
414
+ }
415
+ /** @deprecated Use {@link HasPanels}. */
248
416
  get hasPanels() {
249
- return extractPanelsFromLayout(this.config?.layout ?? null).length > 0;
417
+ return this.HasPanels;
250
418
  }
251
419
  _destroy$ = new Subject();
252
420
  _panelComponents = new Map();
@@ -292,26 +460,30 @@ export class DashboardViewerComponent extends BaseAngularComponent {
292
460
  /**
293
461
  * Toggle edit mode
294
462
  */
295
- toggleEditMode() {
296
- this.isEditing = !this.isEditing;
297
- this.editModeChanged.emit(this.isEditing);
463
+ ToggleEditMode() {
464
+ this.IsEditing = !this.IsEditing;
465
+ this.EditModeChanged.emit(this.IsEditing);
298
466
  this.updatePanelEditModes();
299
467
  }
468
+ /** @deprecated Use {@link ToggleEditMode}. */
469
+ toggleEditMode() {
470
+ return this.ToggleEditMode();
471
+ }
300
472
  /**
301
473
  * Add a new panel to the dashboard.
302
474
  * The panel is stored in GL's componentState - no separate panels array.
303
475
  */
304
- async addPanel(partTypeId, panelConfig, title, icon, location) {
476
+ async AddPanel(partTypeId, panelConfig, title, icon, location) {
305
477
  if (!this.config || !this._glService) {
306
478
  return;
307
479
  }
308
- const partType = this.partTypes.find(pt => UUIDsEqual(pt.ID, partTypeId));
480
+ const partType = this.PartTypes.find(pt => UUIDsEqual(pt.ID, partTypeId));
309
481
  if (!partType) {
310
482
  this.error.emit({ message: `Unknown panel type: ${partTypeId}` });
311
483
  return;
312
484
  }
313
485
  const panel = {
314
- id: generatePanelId(),
486
+ id: GeneratePanelId(),
315
487
  partTypeId,
316
488
  title,
317
489
  icon: icon || partType.Icon || 'fa-solid fa-window-maximize',
@@ -327,11 +499,15 @@ export class DashboardViewerComponent extends BaseAngularComponent {
327
499
  }
328
500
  this.markDirty();
329
501
  }
502
+ /** @deprecated Use {@link AddPanel}. */
503
+ async addPanel(partTypeId, panelConfig, title, icon, location) {
504
+ return this.AddPanel(partTypeId, panelConfig, title, icon, location);
505
+ }
330
506
  /**
331
507
  * Remove a panel from the dashboard.
332
508
  * Panels live in GL's componentState, so removing from GL removes the panel.
333
509
  */
334
- removePanel(panelId) {
510
+ RemovePanel(panelId) {
335
511
  if (!this.config || !this._glService)
336
512
  return;
337
513
  // Remove from layout (panel data is in componentState)
@@ -345,6 +521,10 @@ export class DashboardViewerComponent extends BaseAngularComponent {
345
521
  this.destroyPanelComponent(panelId);
346
522
  this.markDirty();
347
523
  }
524
+ /** @deprecated Use {@link RemovePanel}. */
525
+ removePanel(panelId) {
526
+ return this.RemovePanel(panelId);
527
+ }
348
528
  /**
349
529
  * Save the current dashboard configuration
350
530
  */
@@ -365,8 +545,8 @@ export class DashboardViewerComponent extends BaseAngularComponent {
365
545
  this._dashboard.UIConfigDetails = JSON.stringify(this.config);
366
546
  const saved = await this._dashboard.Save();
367
547
  if (saved) {
368
- this.hasUnsavedChanges = false;
369
- this.dashboardSaved.emit(this._dashboard);
548
+ this.HasUnsavedChanges = false;
549
+ this.DashboardSaved.emit(this._dashboard);
370
550
  }
371
551
  return saved;
372
552
  }
@@ -383,19 +563,27 @@ export class DashboardViewerComponent extends BaseAngularComponent {
383
563
  /**
384
564
  * Refresh all panels
385
565
  */
386
- async refreshAllPanels() {
566
+ async RefreshAllPanels() {
387
567
  // For placeholder implementation, reinitialize the layout
388
568
  if (this._glService) {
389
569
  await this.initializeLayout();
390
570
  }
391
571
  }
572
+ /** @deprecated Use {@link RefreshAllPanels}. */
573
+ async refreshAllPanels() {
574
+ return this.RefreshAllPanels();
575
+ }
392
576
  /**
393
577
  * Resolves when the current dashboard's Golden Layout instance has initialized
394
578
  * against a non-zero container and completed its first size update.
395
579
  */
396
- waitForLayoutReady() {
580
+ WaitForLayoutReady() {
397
581
  return this._layoutReadyPromise;
398
582
  }
583
+ /** @deprecated Use {@link WaitForLayoutReady}. */
584
+ waitForLayoutReady() {
585
+ return this.WaitForLayoutReady();
586
+ }
399
587
  /**
400
588
  * Get the current configuration
401
589
  */
@@ -405,31 +593,43 @@ export class DashboardViewerComponent extends BaseAngularComponent {
405
593
  /**
406
594
  * Get available part types
407
595
  */
596
+ GetPartTypes() {
597
+ return this.PartTypes;
598
+ }
599
+ /** @deprecated Use {@link GetPartTypes}. */
408
600
  getPartTypes() {
409
- return this.partTypes;
601
+ return this.GetPartTypes();
410
602
  }
411
603
  /**
412
604
  * Get a panel by ID.
413
605
  * Extracts panel from the layout's componentState (single source of truth).
414
606
  */
607
+ GetPanel(panelId) {
608
+ return FindPanelInLayout(this.config?.layout ?? null, panelId);
609
+ }
610
+ /** @deprecated Use {@link GetPanel}. */
415
611
  getPanel(panelId) {
416
- return findPanelInLayout(this.config?.layout ?? null, panelId);
612
+ return this.GetPanel(panelId);
417
613
  }
418
614
  /**
419
615
  * Get the part type for a panel
420
616
  */
421
- getPartTypeForPanel(panelId) {
422
- const panel = this.getPanel(panelId);
617
+ GetPartTypeForPanel(panelId) {
618
+ const panel = this.GetPanel(panelId);
423
619
  if (!panel)
424
620
  return null;
425
- return this.partTypes.find(pt => UUIDsEqual(pt.ID, panel.partTypeId)) ?? null;
621
+ return this.PartTypes.find(pt => UUIDsEqual(pt.ID, panel.partTypeId)) ?? null;
622
+ }
623
+ /** @deprecated Use {@link GetPartTypeForPanel}. */
624
+ getPartTypeForPanel(panelId) {
625
+ return this.GetPartTypeForPanel(panelId);
426
626
  }
427
627
  /**
428
628
  * Update a panel's configuration.
429
629
  * Since panels live in componentState within the layout, we need to
430
630
  * update the layout tree directly or reinitialize with updated data.
431
631
  */
432
- updatePanelConfig(panelId, newConfig, title, icon) {
632
+ UpdatePanelConfig(panelId, newConfig, title, icon) {
433
633
  if (!this.config || !this._glService)
434
634
  return;
435
635
  // Get current layout which contains all panel data
@@ -443,6 +643,10 @@ export class DashboardViewerComponent extends BaseAngularComponent {
443
643
  // Reinitialize layout to reflect the updated panel
444
644
  this.initializeLayout();
445
645
  }
646
+ /** @deprecated Use {@link UpdatePanelConfig}. */
647
+ updatePanelConfig(panelId, newConfig, title, icon) {
648
+ return this.UpdatePanelConfig(panelId, newConfig, title, icon);
649
+ }
446
650
  /**
447
651
  * Recursively update a panel's config within the layout tree
448
652
  */
@@ -478,31 +682,43 @@ export class DashboardViewerComponent extends BaseAngularComponent {
478
682
  /**
479
683
  * Handle add panel button click - emits event for parent to show dialog
480
684
  */
481
- onAddPanelClick() {
685
+ OnAddPanelClick() {
482
686
  // Emit interaction event for parent to handle
483
687
  // Parent should show AddPanelDialog and call addPanel() with result
484
- this.panelInteraction.emit({
688
+ this.PanelInteraction.emit({
485
689
  panelId: '',
486
690
  interactionType: 'custom',
487
- payload: { action: 'add-panel-requested', partTypes: this.partTypes }
691
+ payload: { action: 'add-panel-requested', partTypes: this.PartTypes }
488
692
  });
489
693
  }
694
+ /** @deprecated Use {@link OnAddPanelClick}. */
695
+ onAddPanelClick() {
696
+ return this.OnAddPanelClick();
697
+ }
490
698
  /**
491
699
  * Handle "Open in Tab" button click - emits event for parent to open dashboard in its own tab
492
700
  */
493
- onOpenInTabClick() {
701
+ OnOpenInTabClick() {
494
702
  if (this._dashboard) {
495
- this.openInTab.emit({
703
+ this.OpenInTab.emit({
496
704
  dashboardId: this._dashboard.ID,
497
705
  dashboardName: this._dashboard.Name
498
706
  });
499
707
  }
500
708
  }
709
+ /** @deprecated Use {@link OnOpenInTabClick}. */
710
+ onOpenInTabClick() {
711
+ return this.OnOpenInTabClick();
712
+ }
501
713
  /**
502
714
  * Handle breadcrumb navigation
503
715
  */
716
+ OnBreadcrumbNavigate(event) {
717
+ this.BreadcrumbNavigate.emit(event);
718
+ }
719
+ /** @deprecated Use {@link OnBreadcrumbNavigate}. */
504
720
  onBreadcrumbNavigate(event) {
505
- this.breadcrumbNavigate.emit(event);
721
+ return this.OnBreadcrumbNavigate(event);
506
722
  }
507
723
  // ========================================
508
724
  // Private Methods - Initialization
@@ -510,7 +726,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
510
726
  async loadPartTypes() {
511
727
  try {
512
728
  await DashboardEngine.Instance.Config(false);
513
- this.partTypes = DashboardEngine.Instance.DashboardPartTypes;
729
+ this.PartTypes = DashboardEngine.Instance.DashboardPartTypes;
514
730
  }
515
731
  catch (err) {
516
732
  console.error('Failed to load dashboard part types:', err);
@@ -568,7 +784,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
568
784
  }
569
785
  parseOrCreateConfig() {
570
786
  if (!this._dashboard?.UIConfigDetails) {
571
- return createDefaultDashboardConfig();
787
+ return CreateDefaultDashboardConfig();
572
788
  }
573
789
  try {
574
790
  const parsed = JSON.parse(this._dashboard.UIConfigDetails);
@@ -578,20 +794,20 @@ export class DashboardViewerComponent extends BaseAngularComponent {
578
794
  }
579
795
  // Invalid format, return default
580
796
  console.warn('[DashboardViewer] Invalid config format, using default');
581
- return createDefaultDashboardConfig();
797
+ return CreateDefaultDashboardConfig();
582
798
  }
583
799
  catch {
584
- return createDefaultDashboardConfig();
800
+ return CreateDefaultDashboardConfig();
585
801
  }
586
802
  }
587
803
  // ========================================
588
804
  // Private Methods - Layout
589
805
  // ========================================
590
806
  async initializeLayout(generation = this._layoutInitGeneration) {
591
- if (!this.config || !this.layoutContainer?.nativeElement) {
807
+ if (!this.config || !this.LayoutContainer?.nativeElement) {
592
808
  return;
593
809
  }
594
- const el = this.layoutContainer.nativeElement;
810
+ const el = this.LayoutContainer.nativeElement;
595
811
  const rect = el.getBoundingClientRect();
596
812
  if (rect.width === 0 || rect.height === 0) {
597
813
  // The container has no size yet — typically because Explorer is reattaching
@@ -602,7 +818,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
602
818
  // Defer init until the container actually has a size, then build the layout.
603
819
  const reason = 'layout container has zero size';
604
820
  this.emitLayoutLifecycle('waiting-for-size', reason);
605
- this.layoutDeferred.emit({ reason });
821
+ this.LayoutDeferred.emit({ reason });
606
822
  await this.waitForLayoutContainerSize(el, generation);
607
823
  if (generation !== this._layoutInitGeneration) {
608
824
  return;
@@ -629,7 +845,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
629
845
  // Initialize with saved layout (or null for empty dashboard)
630
846
  // Golden Layout's native ResolvedLayoutConfig is the source of truth
631
847
  // Panel data is embedded in each component's componentState
632
- this._glService.initialize(this.layoutContainer.nativeElement, this.config.layout, panelFactory, this.isEditing);
848
+ this._glService.initialize(this.LayoutContainer.nativeElement, this.config.layout, panelFactory, this.IsEditing);
633
849
  if (pendingPanelCreations.length > 0) {
634
850
  await Promise.all(pendingPanelCreations);
635
851
  }
@@ -651,7 +867,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
651
867
  this._glService?.updateSize();
652
868
  this.cdr.detectChanges();
653
869
  this.emitLayoutLifecycle('ready');
654
- this.layoutReady.emit();
870
+ this.LayoutReady.emit();
655
871
  this.resolveLayoutReady(generation);
656
872
  }
657
873
  /** ResizeObserver used to wait for a zero-size container to gain a size before init. */
@@ -758,7 +974,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
758
974
  }
759
975
  }
760
976
  emitLayoutLifecycle(state, reason, error) {
761
- this.layoutLifecycle.emit({
977
+ this.LayoutLifecycle.emit({
762
978
  state,
763
979
  dashboardId: this._dashboard?.ID,
764
980
  reason,
@@ -840,13 +1056,13 @@ export class DashboardViewerComponent extends BaseAngularComponent {
840
1056
  * Panel comes directly from GL's componentState - no lookup needed.
841
1057
  */
842
1058
  async createPanelComponent(panel, container) {
843
- const partType = this.partTypes.find(pt => UUIDsEqual(pt.ID, panel.partTypeId));
1059
+ const partType = this.PartTypes.find(pt => UUIDsEqual(pt.ID, panel.partTypeId));
844
1060
  // Create the panel wrapper with header and content
845
1061
  const wrapper = document.createElement('div');
846
1062
  wrapper.className = 'dashboard-part-wrapper';
847
1063
  wrapper.style.cssText = 'display: flex; flex-direction: column; height: 100%; background: var(--mj-bg-surface);';
848
1064
  // Only show header in edit mode - GL tabs already display the title in view mode
849
- if (this.isEditing) {
1065
+ if (this.IsEditing) {
850
1066
  const header = this.createPartHeader(panel, panel.id);
851
1067
  wrapper.appendChild(header);
852
1068
  }
@@ -890,7 +1106,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
890
1106
  const instance = componentRef.instance;
891
1107
  instance.Panel = panel;
892
1108
  instance.PartType = partType;
893
- instance.IsEditing = this.isEditing;
1109
+ instance.IsEditing = this.IsEditing;
894
1110
  // Subscribe to events
895
1111
  instance.ConfigureRequested.subscribe(() => {
896
1112
  this.onConfigurePart(panel.id);
@@ -899,7 +1115,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
899
1115
  this.onRemovePart(panel.id);
900
1116
  });
901
1117
  instance.NavigationRequested.subscribe((event) => {
902
- this.navigationRequested.emit(event);
1118
+ this.NavigationRequested.emit(event);
903
1119
  });
904
1120
  // Attach component to DOM
905
1121
  container.appendChild(componentRef.location.nativeElement);
@@ -933,7 +1149,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
933
1149
  `;
934
1150
  header.appendChild(titleSection);
935
1151
  // Action buttons (only in edit mode)
936
- if (this.isEditing) {
1152
+ if (this.IsEditing) {
937
1153
  const actions = document.createElement('div');
938
1154
  actions.style.cssText = 'display: flex; gap: 4px;';
939
1155
  // Configure button
@@ -1164,7 +1380,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
1164
1380
  }
1165
1381
  onConfigurePart(panelId) {
1166
1382
  // Emit event for parent to handle configuration
1167
- this.panelInteraction.emit({
1383
+ this.PanelInteraction.emit({
1168
1384
  panelId,
1169
1385
  interactionType: 'custom',
1170
1386
  payload: { action: 'configure-part-requested' }
@@ -1172,8 +1388,8 @@ export class DashboardViewerComponent extends BaseAngularComponent {
1172
1388
  }
1173
1389
  onRemovePart(panelId) {
1174
1390
  // Emit event for parent to show confirmation dialog
1175
- const panel = findPanelInLayout(this.config?.layout ?? null, panelId);
1176
- this.panelInteraction.emit({
1391
+ const panel = FindPanelInLayout(this.config?.layout ?? null, panelId);
1392
+ this.PanelInteraction.emit({
1177
1393
  panelId,
1178
1394
  interactionType: 'custom',
1179
1395
  payload: {
@@ -1185,8 +1401,12 @@ export class DashboardViewerComponent extends BaseAngularComponent {
1185
1401
  /**
1186
1402
  * Confirm removal of a panel (called by parent after confirmation dialog)
1187
1403
  */
1404
+ ConfirmRemovePanel(panelId) {
1405
+ this.RemovePanel(panelId);
1406
+ }
1407
+ /** @deprecated Use {@link ConfirmRemovePanel}. */
1188
1408
  confirmRemovePanel(panelId) {
1189
- this.removePanel(panelId);
1409
+ return this.ConfirmRemovePanel(panelId);
1190
1410
  }
1191
1411
  destroyPanelComponent(panelId) {
1192
1412
  const entry = this._panelComponents.get(panelId);
@@ -1203,7 +1423,7 @@ export class DashboardViewerComponent extends BaseAngularComponent {
1203
1423
  // Update IsEditing on all dynamic components
1204
1424
  this._panelComponents.forEach((entry) => {
1205
1425
  if (entry.componentRef) {
1206
- entry.componentRef.instance.IsEditing = this.isEditing;
1426
+ entry.componentRef.instance.IsEditing = this.IsEditing;
1207
1427
  }
1208
1428
  });
1209
1429
  // Save current layout before reinitializing (preserves user's arrangement)
@@ -1222,8 +1442,8 @@ export class DashboardViewerComponent extends BaseAngularComponent {
1222
1442
  // Private Methods - State
1223
1443
  // ========================================
1224
1444
  markDirty() {
1225
- this.hasUnsavedChanges = true;
1226
- if (this.autoSave && this.config) {
1445
+ this.HasUnsavedChanges = true;
1446
+ if (this.AutoSave && this.config) {
1227
1447
  this.save();
1228
1448
  }
1229
1449
  }
@@ -1232,8 +1452,8 @@ export class DashboardViewerComponent extends BaseAngularComponent {
1232
1452
  i0.ɵɵviewQuery(_c0, 7);
1233
1453
  } if (rf & 2) {
1234
1454
  let _t;
1235
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.layoutContainer = _t.first);
1236
- } }, inputs: { dashboard: "dashboard", dashboardId: "dashboardId", isEditing: "isEditing", showToolbar: "showToolbar", autoSave: "autoSave", showBreadcrumb: "showBreadcrumb", showOpenInTabButton: "showOpenInTabButton", showEditButton: "showEditButton", Categories: "Categories" }, outputs: { configChanged: "configChanged", navigationRequested: "navigationRequested", panelInteraction: "panelInteraction", dashboardSaved: "dashboardSaved", error: "error", editModeChanged: "editModeChanged", breadcrumbNavigate: "breadcrumbNavigate", openInTab: "openInTab", layoutLifecycle: "layoutLifecycle", layoutReady: "layoutReady", layoutDeferred: "layoutDeferred" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 7, vars: 8, consts: [["layoutContainer", ""], [1, "dashboard-viewer"], ["Size", "large", "RootIcon", "fa-solid fa-gauge-high", "RootLabel", "Dashboards", 3, "Categories", "CurrentCategoryId", "CurrentDashboard", "ShowDashboardName", "AllowDragDrop"], [1, "dashboard-toolbar"], [1, "loading-overlay"], [1, "layout-container"], ["Icon", "fa-solid fa-layer-group", "Title", "No parts configured", "Message", "This dashboard has no parts yet. Add your first part to start visualizing your data.", "ActionIcon", "fa-solid fa-plus", 1, "dashboard-empty", 3, "ActionText"], ["Size", "large", "RootIcon", "fa-solid fa-gauge-high", "RootLabel", "Dashboards", 3, "Navigate", "Categories", "CurrentCategoryId", "CurrentDashboard", "ShowDashboardName", "AllowDragDrop"], [1, "toolbar-left"], [1, "dashboard-title"], [1, "toolbar-center"], [1, "unsaved-indicator"], [1, "toolbar-right"], ["title", "Open in its own tab", 1, "toolbar-button"], [1, "toolbar-button"], [1, "toolbar-button", 3, "active"], [1, "toolbar-button", "primary"], [1, "fa-solid", "fa-chart-line"], [1, "fa-solid", "fa-circle"], ["title", "Open in its own tab", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-up-right-from-square"], [1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "fa-solid", "fa-edit"], [1, "toolbar-button", "primary", 3, "click"], [1, "fa-solid", "fa-save"], ["text", "Loading dashboard..."], ["Icon", "fa-solid fa-layer-group", "Title", "No parts configured", "Message", "This dashboard has no parts yet. Add your first part to start visualizing your data.", "ActionIcon", "fa-solid fa-plus", 1, "dashboard-empty", 3, "Action", "ActionText"]], template: function DashboardViewerComponent_Template(rf, ctx) { if (rf & 1) {
1455
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.LayoutContainer = _t.first);
1456
+ } }, inputs: { Dashboard: "Dashboard", dashboard: "dashboard", DashboardId: "DashboardId", dashboardId: "dashboardId", IsEditing: "IsEditing", isEditing: "isEditing", ShowToolbar: "ShowToolbar", showToolbar: "showToolbar", AutoSave: "AutoSave", autoSave: "autoSave", ShowBreadcrumb: "ShowBreadcrumb", showBreadcrumb: "showBreadcrumb", ShowOpenInTabButton: "ShowOpenInTabButton", showOpenInTabButton: "showOpenInTabButton", ShowEditButton: "ShowEditButton", showEditButton: "showEditButton", Categories: "Categories" }, outputs: { configChanged: "configChanged", NavigationRequested: "NavigationRequested", navigationRequested: "navigationRequested", PanelInteraction: "PanelInteraction", panelInteraction: "panelInteraction", DashboardSaved: "DashboardSaved", dashboardSaved: "dashboardSaved", error: "error", EditModeChanged: "EditModeChanged", editModeChanged: "editModeChanged", BreadcrumbNavigate: "BreadcrumbNavigate", breadcrumbNavigate: "breadcrumbNavigate", OpenInTab: "OpenInTab", openInTab: "openInTab", LayoutLifecycle: "LayoutLifecycle", layoutLifecycle: "layoutLifecycle", LayoutReady: "LayoutReady", layoutReady: "layoutReady", LayoutDeferred: "LayoutDeferred", layoutDeferred: "layoutDeferred" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 7, vars: 8, consts: [["layoutContainer", ""], [1, "dashboard-viewer"], ["Size", "large", "RootIcon", "fa-solid fa-gauge-high", "RootLabel", "Dashboards", 3, "Categories", "CurrentCategoryId", "CurrentDashboard", "ShowDashboardName", "AllowDragDrop"], [1, "dashboard-toolbar"], [1, "loading-overlay"], [1, "layout-container"], ["Icon", "fa-solid fa-layer-group", "Title", "No parts configured", "Message", "This dashboard has no parts yet. Add your first part to start visualizing your data.", "ActionIcon", "fa-solid fa-plus", 1, "dashboard-empty", 3, "ActionText"], ["Size", "large", "RootIcon", "fa-solid fa-gauge-high", "RootLabel", "Dashboards", 3, "Navigate", "Categories", "CurrentCategoryId", "CurrentDashboard", "ShowDashboardName", "AllowDragDrop"], [1, "toolbar-left"], [1, "dashboard-title"], [1, "toolbar-center"], [1, "unsaved-indicator"], [1, "toolbar-right"], ["title", "Open in its own tab", 1, "toolbar-button"], [1, "toolbar-button"], [1, "toolbar-button", 3, "active"], [1, "toolbar-button", "primary"], [1, "fa-solid", "fa-chart-line"], [1, "fa-solid", "fa-circle"], ["title", "Open in its own tab", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-up-right-from-square"], [1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "fa-solid", "fa-edit"], [1, "toolbar-button", "primary", 3, "click"], [1, "fa-solid", "fa-save"], ["text", "Loading dashboard..."], ["Icon", "fa-solid fa-layer-group", "Title", "No parts configured", "Message", "This dashboard has no parts yet. Add your first part to start visualizing your data.", "ActionIcon", "fa-solid fa-plus", 1, "dashboard-empty", 3, "Action", "ActionText"]], template: function DashboardViewerComponent_Template(rf, ctx) { if (rf & 1) {
1237
1457
  i0.ɵɵelementStart(0, "div", 1);
1238
1458
  i0.ɵɵconditionalCreate(1, DashboardViewerComponent_Conditional_1_Template, 1, 5, "mj-dashboard-breadcrumb", 2);
1239
1459
  i0.ɵɵconditionalCreate(2, DashboardViewerComponent_Conditional_2_Template, 10, 6, "div", 3);
@@ -1256,47 +1476,81 @@ export class DashboardViewerComponent extends BaseAngularComponent {
1256
1476
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DashboardViewerComponent, [{
1257
1477
  type: Component,
1258
1478
  args: [{ standalone: false, selector: 'mj-dashboard-viewer', encapsulation: ViewEncapsulation.None, template: "<!-- Dashboard Viewer Component -->\n<div class=\"dashboard-viewer\" [class.editing]=\"isEditing\" [class.has-toolbar]=\"shouldShowToolbar\">\n <!-- Breadcrumb Navigation (hidden in edit mode) -->\n @if (showBreadcrumb && !isEditing && dashboard) {\n <mj-dashboard-breadcrumb\n [Categories]=\"Categories\"\n [CurrentCategoryId]=\"dashboard.CategoryID\"\n [CurrentDashboard]=\"dashboard\"\n [ShowDashboardName]=\"true\"\n [AllowDragDrop]=\"false\"\n Size=\"large\"\n RootIcon=\"fa-solid fa-gauge-high\"\n RootLabel=\"Dashboards\"\n (Navigate)=\"onBreadcrumbNavigate($event)\">\n </mj-dashboard-breadcrumb>\n }\n\n <!-- Toolbar (auto-hides when all elements are disabled) -->\n @if (shouldShowToolbar) {\n <div class=\"dashboard-toolbar\">\n <div class=\"toolbar-left\">\n @if (dashboard && (isEditing || !showBreadcrumb)) {\n <span class=\"dashboard-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n {{ dashboard.Name }}\n </span>\n }\n </div>\n <div class=\"toolbar-center\">\n @if (hasUnsavedChanges && isEditing) {\n <span class=\"unsaved-indicator\">\n <i class=\"fa-solid fa-circle\"></i>\n Unsaved changes\n </span>\n }\n </div>\n <div class=\"toolbar-right\">\n <!-- Open in New Tab button (when embedded) -->\n @if (showOpenInTabButton && !isEditing) {\n <button\n class=\"toolbar-button\"\n (click)=\"onOpenInTabClick()\"\n title=\"Open in its own tab\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n Open in Tab\n </button>\n }\n @if (isEditing) {\n <button\n class=\"toolbar-button\"\n (click)=\"onAddPanelClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Part\n </button>\n }\n @if (showEditButton) {\n <button\n class=\"toolbar-button\"\n [class.active]=\"isEditing\"\n (click)=\"toggleEditMode()\">\n <i class=\"fa-solid fa-edit\"></i>\n {{ isEditing ? 'Editing' : 'Edit' }}\n </button>\n }\n @if (isEditing && hasUnsavedChanges) {\n <button\n class=\"toolbar-button primary\"\n (click)=\"save()\">\n <i class=\"fa-solid fa-save\"></i>\n Save\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Loading Overlay -->\n @if (isLoading) {\n <div class=\"loading-overlay\">\n <mj-loading text=\"Loading dashboard...\"></mj-loading>\n </div>\n }\n\n <!-- Layout Container -->\n <div class=\"layout-container\" #layoutContainer>\n <!-- Golden Layout will render panels here -->\n </div>\n\n <!-- Empty State -->\n @if (!hasPanels && !isLoading) {\n <mj-empty-state\n class=\"dashboard-empty\"\n Icon=\"fa-solid fa-layer-group\"\n Title=\"No parts configured\"\n Message=\"This dashboard has no parts yet. Add your first part to start visualizing your data.\"\n [ActionText]=\"isEditing ? 'Add Your First Part' : ''\"\n ActionIcon=\"fa-solid fa-plus\"\n (Action)=\"onAddPanelClick()\" />\n }\n</div>\n", styles: ["/**\n * Dashboard Viewer Component Styles\n *\n * IMPORTANT: For Golden Layout tabs to display correctly, you must import\n * Golden Layout's CSS in your application's global styles:\n *\n * @import 'golden-layout/dist/css/goldenlayout-base.css';\n *\n * Or add to your angular.json styles array:\n * \"node_modules/golden-layout/dist/css/goldenlayout-base.css\"\n */\n\n:host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.dashboard-viewer {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--dashboard-bg, var(--mj-bg-surface-card));\n}\n\n.dashboard-viewer.editing .layout-container {\n outline: 2px dashed var(--dashboard-edit-outline, var(--mj-brand-primary));\n outline-offset: -2px;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.dashboard-toolbar {\n flex: 0 0 48px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 16px;\n background: var(--dashboard-toolbar-bg, var(--mj-bg-surface));\n border-bottom: 1px solid var(--dashboard-border, var(--mj-border-default));\n box-sizing: border-box;\n z-index: 10;\n}\n\n.toolbar-left,\n.toolbar-center,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-left {\n flex: 1;\n}\n\n.toolbar-center {\n flex: 0 0 auto;\n}\n\n.toolbar-right {\n flex: 1;\n justify-content: flex-end;\n}\n\n.dashboard-title {\n font-size: 16px;\n font-weight: 500;\n color: var(--dashboard-title-color, var(--mj-text-primary));\n}\n\n.dashboard-title i {\n margin-right: 8px;\n color: var(--dashboard-title-icon, var(--mj-brand-primary));\n}\n\n.unsaved-indicator {\n font-size: 12px;\n color: var(--dashboard-unsaved-color, var(--mj-status-warning));\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.unsaved-indicator i {\n font-size: 8px;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: 1px solid var(--dashboard-button-border, var(--mj-border-strong));\n border-radius: 4px;\n background: var(--dashboard-button-bg, var(--mj-bg-surface));\n color: var(--dashboard-button-color, var(--mj-text-primary));\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.toolbar-button:hover {\n background: var(--dashboard-button-hover-bg, var(--mj-bg-surface-card));\n border-color: var(--dashboard-button-hover-border, var(--mj-border-strong));\n}\n\n.toolbar-button.active {\n background: var(--dashboard-button-active-bg, color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)));\n border-color: var(--dashboard-button-active-border, var(--mj-brand-primary));\n color: var(--dashboard-button-active-color, var(--mj-brand-primary));\n}\n\n.toolbar-button.primary {\n background: var(--dashboard-button-primary-bg, var(--mj-brand-primary));\n border-color: var(--dashboard-button-primary-border, var(--mj-brand-primary-hover));\n color: var(--dashboard-button-primary-color, var(--mj-text-inverse));\n}\n\n.toolbar-button.primary:hover {\n background: var(--dashboard-button-primary-hover-bg, var(--mj-brand-primary-hover));\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n/* ========================================\n Layout Container\n ======================================== */\n\n/* Layout container fills remaining space in the flex column */\n.layout-container {\n flex: 1;\n position: relative;\n overflow: hidden;\n min-height: 0;\n}\n\n/* ========================================\n Dashboard Panel Content (our wrapper)\n ======================================== */\n\n/* Dashboard panel wrapper (header + content) */\n:host ::ng-deep .dashboard-part-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n}\n\n/* Dashboard part header */\n:host ::ng-deep .dashboard-part-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n min-height: 40px;\n flex-shrink: 0;\n}\n\n/* Dashboard part content */\n:host ::ng-deep .dashboard-part-content {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-bg-surface) 90%, transparent);\n z-index: 100;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n/* Empty state centered in the dashboard pane (mj-empty-state centers its own\n content; absolute positioning keeps it overlaid on the layout container). */\n.dashboard-empty {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n max-width: 400px;\n}\n\n/* ========================================\n Panel Error State\n ======================================== */\n\n:host ::ng-deep .panel-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 24px;\n text-align: center;\n color: var(--dashboard-error-color, var(--mj-status-error));\n background: var(--dashboard-error-bg, color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface)));\n}\n\n:host ::ng-deep .panel-error i {\n font-size: 32px;\n margin-bottom: 12px;\n}\n\n:host ::ng-deep .panel-error span {\n font-size: 14px;\n}\n\n/* ========================================\n Golden Layout Overrides\n These require ViewEncapsulation.None to work on dynamic GL elements\n ======================================== */\n\n/* Override shell's hide-tab-bar rule that hides GL headers when dashboard is inside shell */\n/* The shell hides .lm_header when mj-tab-container has hide-tab-bar class */\n/* We need to ensure OUR Golden Layout headers are always visible */\nmj-dashboard-viewer .lm_header {\n display: block !important;\n}\n\n/* Ensure GL root container fills available space */\nmj-dashboard-viewer .lm_goldenlayout {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure the root layout item fills space */\nmj-dashboard-viewer .lm_root {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure proper box-sizing for all GL layout elements */\nmj-dashboard-viewer .lm_item,\nmj-dashboard-viewer .lm_content,\nmj-dashboard-viewer .lm_stack,\nmj-dashboard-viewer .lm_row,\nmj-dashboard-viewer .lm_column {\n box-sizing: border-box !important;\n}\n\n/* Ensure layout items don't overflow */\nmj-dashboard-viewer .lm_item {\n overflow: hidden !important;\n}\n\n/* Fix for .lm_items - the content container inside stacks */\nmj-dashboard-viewer .lm_items {\n width: 100% !important;\n height: calc(100% - 38px) !important; /* Account for header height (38px) */\n box-sizing: border-box !important;\n position: relative !important;\n}\n\n/* When tabs are maximized, no header visible */\nmj-dashboard-viewer .lm_stack.lm_maximised > .lm_items {\n height: 100% !important;\n}\n\n/* Target the ComponentItem div inside lm_items */\nmj-dashboard-viewer .lm_items > div {\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box !important;\n flex-direction: column !important;\n}\n\n/* Only apply flex display to the active/visible tab content div */\nmj-dashboard-viewer .lm_items > div:not([style*=\"display: none\"]) {\n display: flex !important;\n}\n\n/* Clearfix for float-based row layout */\nmj-dashboard-viewer .lm_row::after {\n content: \"\" !important;\n display: table !important;\n clear: both !important;\n}\n\n/* Force content children to respect parent bounds */\nmj-dashboard-viewer .lm_content > * {\n max-width: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_content {\n background: var(--mj-bg-surface) !important;\n display: flex !important;\n flex-direction: column !important;\n height: 100% !important;\n width: 100% !important;\n}\n\nmj-dashboard-viewer .lm_item_container {\n background: var(--mj-bg-surface) !important;\n}\n\n/* Tab header styling */\nmj-dashboard-viewer .lm_header {\n height: 38px !important;\n padding-top: 2px !important;\n padding-left: 4px !important;\n background: var(--mj-bg-surface-card) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n overflow: visible !important;\n box-sizing: border-box !important;\n}\n\nmj-dashboard-viewer .lm_tabs {\n height: 36px !important;\n}\n\n/* Hide Golden Layout window controls (popout, maximize) */\nmj-dashboard-viewer .lm_controls {\n display: none !important;\n}\n\n/* Tab styling */\nmj-dashboard-viewer .lm_header .lm_tab {\n padding: 0 16px 0 28px !important; /* Extra left padding for icon */\n font-size: 13px !important;\n height: 35px !important;\n line-height: 35px !important;\n box-sizing: border-box !important;\n cursor: pointer !important;\n user-select: none !important;\n background: transparent !important;\n border: none !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n transition: all 0.15s ease !important;\n position: relative !important;\n z-index: 1 !important;\n margin-right: 1px !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover {\n background: var(--mj-bg-surface-sunken) !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab.lm_active {\n background: var(--mj-bg-surface) !important;\n height: 36px !important;\n margin-bottom: -1px !important;\n margin-right: 0 !important;\n border: 1px solid var(--mj-border-default) !important;\n border-bottom-color: var(--mj-bg-surface) !important;\n border-radius: 4px 4px 0 0 !important;\n z-index: 2 !important;\n}\n\nmj-dashboard-viewer .lm_title {\n cursor: pointer !important;\n user-select: none !important;\n}\n\n/* Panel icon styling - icon is direct child of .lm_tab to preserve GL's drag/drop */\n/* Positioned absolutely in the left padding area so it doesn't affect GL's title structure */\nmj-dashboard-viewer .lm_header .lm_tab .panel-icon {\n position: absolute !important;\n left: 10px !important;\n top: 50% !important;\n transform: translateY(-30%) !important;\n font-family: \"Font Awesome 6 Free\", \"Font Awesome 6 Pro\", \"Font Awesome 5 Free\", \"Font Awesome 5 Pro\", FontAwesome !important;\n font-weight: 900 !important; /* Required for solid icons */\n font-size: 12px !important;\n color: var(--mj-brand-primary) !important;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nmj-dashboard-viewer .lm_close_tab {\n position: absolute !important;\n right: 4px !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n width: 16px !important;\n height: 16px !important;\n cursor: pointer !important;\n opacity: 0 !important;\n transition: all 0.15s ease !important;\n}\n\nmj-dashboard-viewer .lm_header .lm_tab:hover .lm_close_tab {\n opacity: 0.7 !important;\n}\n\nmj-dashboard-viewer .lm_close_tab:hover {\n opacity: 1 !important;\n color: var(--mj-status-error) !important;\n}\n\n/* Add padding for close button when editing */\nmj-dashboard-viewer .dashboard-viewer.editing .lm_header .lm_tab {\n padding-right: 24px !important;\n}\n\n/* ========================================\n View Mode (Not Editing) - Lock Layout\n ======================================== */\n\n/* Hide close buttons on tabs when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_close_tab {\n display: none !important;\n}\n\n/* Remove extra padding for close button when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n padding-right: 16px !important;\n}\n\n/* Disable splitter dragging when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter {\n pointer-events: none !important;\n cursor: default !important;\n}\n\n/* Hide splitter drag handle visual when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_splitter .lm_drag_handle {\n display: none !important;\n}\n\n/* Disable tab dragging cursor when not editing */\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_header .lm_tab {\n cursor: default !important;\n}\n\nmj-dashboard-viewer .dashboard-viewer:not(.editing) .lm_title {\n cursor: default !important;\n}\n"] }]
1259
- }], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ApplicationRef }, { type: i0.Injector }, { type: i0.EnvironmentInjector }], { dashboard: [{
1479
+ }], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ApplicationRef }, { type: i0.Injector }, { type: i0.EnvironmentInjector }], { Dashboard: [{
1480
+ type: Input
1481
+ }], dashboard: [{
1482
+ type: Input
1483
+ }], DashboardId: [{
1260
1484
  type: Input
1261
1485
  }], dashboardId: [{
1262
1486
  type: Input
1487
+ }], IsEditing: [{
1488
+ type: Input
1263
1489
  }], isEditing: [{
1264
1490
  type: Input
1491
+ }], ShowToolbar: [{
1492
+ type: Input
1265
1493
  }], showToolbar: [{
1266
1494
  type: Input
1495
+ }], AutoSave: [{
1496
+ type: Input
1267
1497
  }], autoSave: [{
1268
1498
  type: Input
1499
+ }], ShowBreadcrumb: [{
1500
+ type: Input
1269
1501
  }], showBreadcrumb: [{
1270
1502
  type: Input
1503
+ }], ShowOpenInTabButton: [{
1504
+ type: Input
1271
1505
  }], showOpenInTabButton: [{
1272
1506
  type: Input
1507
+ }], ShowEditButton: [{
1508
+ type: Input
1273
1509
  }], showEditButton: [{
1274
1510
  type: Input
1275
1511
  }], Categories: [{
1276
1512
  type: Input
1277
1513
  }], configChanged: [{
1278
1514
  type: Output
1515
+ }], NavigationRequested: [{
1516
+ type: Output
1279
1517
  }], navigationRequested: [{
1280
1518
  type: Output
1519
+ }], PanelInteraction: [{
1520
+ type: Output
1281
1521
  }], panelInteraction: [{
1282
1522
  type: Output
1523
+ }], DashboardSaved: [{
1524
+ type: Output
1283
1525
  }], dashboardSaved: [{
1284
1526
  type: Output
1285
1527
  }], error: [{
1286
1528
  type: Output
1529
+ }], EditModeChanged: [{
1530
+ type: Output
1287
1531
  }], editModeChanged: [{
1288
1532
  type: Output
1533
+ }], BreadcrumbNavigate: [{
1534
+ type: Output
1289
1535
  }], breadcrumbNavigate: [{
1290
1536
  type: Output
1537
+ }], OpenInTab: [{
1538
+ type: Output
1291
1539
  }], openInTab: [{
1292
1540
  type: Output
1541
+ }], LayoutLifecycle: [{
1542
+ type: Output
1293
1543
  }], layoutLifecycle: [{
1294
1544
  type: Output
1545
+ }], LayoutReady: [{
1546
+ type: Output
1295
1547
  }], layoutReady: [{
1296
1548
  type: Output
1549
+ }], LayoutDeferred: [{
1550
+ type: Output
1297
1551
  }], layoutDeferred: [{
1298
1552
  type: Output
1299
- }], layoutContainer: [{
1553
+ }], LayoutContainer: [{
1300
1554
  type: ViewChild,
1301
1555
  args: ['layoutContainer', { static: true }]
1302
1556
  }] }); })();