@dragonworks/ngx-dashboard 20.0.6 → 20.1.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 (78) hide show
  1. package/fesm2022/dragonworks-ngx-dashboard.mjs +2250 -0
  2. package/fesm2022/dragonworks-ngx-dashboard.mjs.map +1 -0
  3. package/index.d.ts +727 -0
  4. package/package.json +45 -34
  5. package/ng-package.json +0 -7
  6. package/src/lib/__tests__/dashboard-component-widget-state-integration.spec.ts +0 -537
  7. package/src/lib/cell/__tests__/cell-resize.component.spec.ts +0 -442
  8. package/src/lib/cell/__tests__/cell.component.spec.ts +0 -541
  9. package/src/lib/cell/cell-context-menu.component.ts +0 -138
  10. package/src/lib/cell/cell-context-menu.service.ts +0 -36
  11. package/src/lib/cell/cell.component.html +0 -37
  12. package/src/lib/cell/cell.component.scss +0 -198
  13. package/src/lib/cell/cell.component.ts +0 -375
  14. package/src/lib/dashboard/dashboard.component.html +0 -18
  15. package/src/lib/dashboard/dashboard.component.scss +0 -17
  16. package/src/lib/dashboard/dashboard.component.ts +0 -187
  17. package/src/lib/dashboard-editor/dashboard-editor.component.html +0 -57
  18. package/src/lib/dashboard-editor/dashboard-editor.component.scss +0 -87
  19. package/src/lib/dashboard-editor/dashboard-editor.component.ts +0 -219
  20. package/src/lib/dashboard-viewer/__tests__/dashboard-viewer.component.spec.ts +0 -258
  21. package/src/lib/dashboard-viewer/dashboard-viewer.component.html +0 -20
  22. package/src/lib/dashboard-viewer/dashboard-viewer.component.scss +0 -50
  23. package/src/lib/dashboard-viewer/dashboard-viewer.component.ts +0 -70
  24. package/src/lib/drop-zone/__tests__/drop-zone.component.spec.ts +0 -465
  25. package/src/lib/drop-zone/drop-zone.component.html +0 -20
  26. package/src/lib/drop-zone/drop-zone.component.scss +0 -67
  27. package/src/lib/drop-zone/drop-zone.component.ts +0 -122
  28. package/src/lib/internal-widgets/unknown-widget/unknown-widget.component.ts +0 -72
  29. package/src/lib/models/cell-data.ts +0 -13
  30. package/src/lib/models/cell-dialog.ts +0 -7
  31. package/src/lib/models/cell-id.ts +0 -85
  32. package/src/lib/models/cell-position.ts +0 -15
  33. package/src/lib/models/dashboard-data.dto.ts +0 -44
  34. package/src/lib/models/dashboard-data.utils.ts +0 -49
  35. package/src/lib/models/drag-data.ts +0 -6
  36. package/src/lib/models/index.ts +0 -11
  37. package/src/lib/models/reserved-space.ts +0 -24
  38. package/src/lib/models/widget-factory.ts +0 -33
  39. package/src/lib/models/widget-id.ts +0 -70
  40. package/src/lib/models/widget.ts +0 -21
  41. package/src/lib/providers/cell-settings-dialog/cell-settings-dialog.component.ts +0 -127
  42. package/src/lib/providers/cell-settings-dialog/cell-settings-dialog.provider.ts +0 -15
  43. package/src/lib/providers/cell-settings-dialog/cell-settings-dialog.tokens.ts +0 -20
  44. package/src/lib/providers/cell-settings-dialog/default-cell-settings-dialog.provider.ts +0 -32
  45. package/src/lib/providers/cell-settings-dialog/index.ts +0 -3
  46. package/src/lib/providers/index.ts +0 -1
  47. package/src/lib/services/__tests__/dashboard-bridge.service.spec.ts +0 -220
  48. package/src/lib/services/__tests__/dashboard-viewport.service.spec.ts +0 -362
  49. package/src/lib/services/dashboard-bridge.service.ts +0 -155
  50. package/src/lib/services/dashboard-viewport.service.ts +0 -148
  51. package/src/lib/services/dashboard.service.ts +0 -62
  52. package/src/lib/store/__tests__/dashboard-store-collision-detection.spec.ts +0 -756
  53. package/src/lib/store/__tests__/dashboard-store-computed-properties.spec.ts +0 -974
  54. package/src/lib/store/__tests__/dashboard-store-drag-drop.spec.ts +0 -279
  55. package/src/lib/store/__tests__/dashboard-store-export-import.spec.ts +0 -780
  56. package/src/lib/store/__tests__/dashboard-store-grid-config.spec.ts +0 -128
  57. package/src/lib/store/__tests__/dashboard-store-query-methods.spec.ts +0 -229
  58. package/src/lib/store/__tests__/dashboard-store-resize-operations.spec.ts +0 -652
  59. package/src/lib/store/__tests__/dashboard-store-widget-management.spec.ts +0 -461
  60. package/src/lib/store/__tests__/dashboard-store-widget-state-preservation.spec.ts +0 -369
  61. package/src/lib/store/dashboard-store.ts +0 -239
  62. package/src/lib/store/features/drag-drop.feature.ts +0 -140
  63. package/src/lib/store/features/grid-config.feature.ts +0 -43
  64. package/src/lib/store/features/resize.feature.ts +0 -140
  65. package/src/lib/store/features/utils/collision.utils.ts +0 -89
  66. package/src/lib/store/features/utils/grid-query-internal.utils.ts +0 -37
  67. package/src/lib/store/features/utils/resize.utils.ts +0 -165
  68. package/src/lib/store/features/widget-management.feature.ts +0 -158
  69. package/src/lib/styles/_dashboard-grid-vars.scss +0 -11
  70. package/src/lib/widget-list/__tests__/widget-list-bridge-integration.spec.ts +0 -137
  71. package/src/lib/widget-list/widget-list.component.html +0 -22
  72. package/src/lib/widget-list/widget-list.component.scss +0 -154
  73. package/src/lib/widget-list/widget-list.component.ts +0 -106
  74. package/src/public-api.ts +0 -21
  75. package/src/test-setup.ts +0 -10
  76. package/tsconfig.lib.json +0 -15
  77. package/tsconfig.lib.prod.json +0 -11
  78. package/tsconfig.spec.json +0 -14
@@ -1,258 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
- import { Component, signal } from '@angular/core';
3
- import { DashboardViewerComponent } from '../dashboard-viewer.component';
4
- import { DashboardStore } from '../../store/dashboard-store';
5
- import { CellIdUtils, WidgetIdUtils, CellData, WidgetFactory, Widget } from '../../models';
6
-
7
- // Mock test widget component
8
- @Component({
9
- selector: 'lib-test-widget',
10
- template: '<div class="test-widget">Test Widget: {{state().value}}</div>',
11
- standalone: true,
12
- })
13
- class TestWidgetComponent implements Widget {
14
- private state = signal<any>({ value: 'initial' });
15
-
16
- dashboardGetState(): any {
17
- return this.state();
18
- }
19
-
20
- dashboardSetState(state: any): void {
21
- this.state.set(state);
22
- }
23
-
24
- dashboardEditState(): void {
25
- // Mock edit state method
26
- }
27
- }
28
-
29
- describe('DashboardViewerComponent - Integration Tests', () => {
30
- let component: DashboardViewerComponent;
31
- let fixture: ComponentFixture<DashboardViewerComponent>;
32
- let store: InstanceType<typeof DashboardStore>;
33
-
34
- const mockWidgetFactory: WidgetFactory = {
35
- widgetTypeid: 'test-widget',
36
- name: 'Test Widget',
37
- description: 'A test widget for testing',
38
- svgIcon: '<svg></svg>',
39
- createInstance: (container) => {
40
- const componentRef = container.createComponent(TestWidgetComponent);
41
- return componentRef;
42
- }
43
- };
44
-
45
- beforeEach(async () => {
46
- await TestBed.configureTestingModule({
47
- imports: [DashboardViewerComponent],
48
- providers: [DashboardStore]
49
- }).compileComponents();
50
-
51
- fixture = TestBed.createComponent(DashboardViewerComponent);
52
- component = fixture.componentInstance;
53
- store = TestBed.inject(DashboardStore);
54
-
55
- // Set required inputs
56
- fixture.componentRef.setInput('rows', 8);
57
- fixture.componentRef.setInput('columns', 12);
58
- fixture.componentRef.setInput('gutterSize', '1em');
59
- });
60
-
61
- describe('Complete Widget Rendering Workflow', () => {
62
- it('should render widgets from store and export dashboard with current states', () => {
63
- // SCENARIO: User loads dashboard with widgets, sees them rendered, exports dashboard
64
-
65
- // Setup: Add widgets to store
66
- const widget1: CellData = {
67
- widgetId: WidgetIdUtils.generate(),
68
- cellId: CellIdUtils.create(1, 1),
69
- row: 1,
70
- col: 1,
71
- rowSpan: 1,
72
- colSpan: 2,
73
- flat: false,
74
- widgetFactory: mockWidgetFactory,
75
- widgetState: { value: 'Widget 1' }
76
- };
77
-
78
- const widget2: CellData = {
79
- widgetId: WidgetIdUtils.generate(),
80
- cellId: CellIdUtils.create(2, 3),
81
- row: 2,
82
- col: 3,
83
- rowSpan: 2,
84
- colSpan: 1,
85
- flat: true,
86
- widgetFactory: mockWidgetFactory,
87
- widgetState: { value: 'Widget 2' }
88
- };
89
-
90
- // Action: Add widgets to store
91
- store.addWidget(widget1);
92
- store.addWidget(widget2);
93
- fixture.detectChanges();
94
-
95
- // Verify: Widgets are rendered
96
- const cellElements = fixture.nativeElement.querySelectorAll('lib-cell');
97
- expect(cellElements.length).toBe(2);
98
- expect(cellElements[0]).toBeTruthy();
99
- expect(cellElements[1]).toBeTruthy();
100
-
101
- // Verify: Store integration works
102
- expect(component.cells().length).toBe(2);
103
- expect(component.cells()[0]).toEqual(widget1);
104
- expect(component.cells()[1]).toEqual(widget2);
105
-
106
- // Action: Export dashboard
107
- const exported = component.exportDashboard();
108
-
109
- // Verify: Export contains dashboard structure
110
- expect(exported.version).toBe('1.0.0');
111
- expect(exported.rows).toBe(8);
112
- expect(exported.columns).toBe(12);
113
- expect(exported.gutterSize).toBe('1em');
114
- expect(exported.cells.length).toBe(2);
115
- });
116
- });
117
-
118
- describe('Grid Configuration and Layout', () => {
119
- it('should apply grid configuration and update CSS variables when inputs change', () => {
120
- // SCENARIO: User changes grid configuration and sees layout update
121
-
122
- // Initial setup
123
- fixture.detectChanges();
124
-
125
- // Verify: Initial CSS variables are set
126
- const hostElement = fixture.nativeElement;
127
- let computedStyle = getComputedStyle(hostElement);
128
- expect(computedStyle.getPropertyValue('--rows')).toBe('8');
129
- expect(computedStyle.getPropertyValue('--columns')).toBe('12');
130
- expect(computedStyle.getPropertyValue('--gutter-size')).toBe('1em');
131
- expect(computedStyle.getPropertyValue('--gutters')).toBe('13'); // columns + 1
132
-
133
- // Action: Change grid configuration
134
- fixture.componentRef.setInput('rows', 6);
135
- fixture.componentRef.setInput('columns', 10);
136
- fixture.componentRef.setInput('gutterSize', '2em');
137
- fixture.detectChanges();
138
-
139
- // Verify: CSS variables updated
140
- computedStyle = getComputedStyle(hostElement);
141
- expect(computedStyle.getPropertyValue('--rows')).toBe('6');
142
- expect(computedStyle.getPropertyValue('--columns')).toBe('10');
143
- expect(computedStyle.getPropertyValue('--gutter-size')).toBe('2em');
144
- expect(computedStyle.getPropertyValue('--gutters')).toBe('11'); // columns + 1
145
-
146
- // Verify: Store is updated
147
- expect(store.rows()).toBe(6);
148
- expect(store.columns()).toBe(10);
149
- expect(store.gutterSize()).toBe('2em');
150
- });
151
- });
152
-
153
- describe('Reactive Store Updates', () => {
154
- it('should reactively update when store changes', () => {
155
- // SCENARIO: User performs actions that modify store, sees immediate UI updates
156
-
157
- // Initial state: No widgets
158
- fixture.detectChanges();
159
- expect(fixture.nativeElement.querySelectorAll('lib-cell').length).toBe(0);
160
-
161
- // Action: Add widget to store
162
- const widget: CellData = {
163
- widgetId: WidgetIdUtils.generate(),
164
- cellId: CellIdUtils.create(1, 1),
165
- row: 1,
166
- col: 1,
167
- rowSpan: 1,
168
- colSpan: 1,
169
- flat: false,
170
- widgetFactory: mockWidgetFactory,
171
- widgetState: { value: 'Dynamic Widget' }
172
- };
173
-
174
- store.addWidget(widget);
175
- fixture.detectChanges();
176
-
177
- // Verify: Widget appears in UI
178
- expect(fixture.nativeElement.querySelectorAll('lib-cell').length).toBe(1);
179
-
180
- // Action: Remove widget from store
181
- store.removeWidget(widget.widgetId);
182
- fixture.detectChanges();
183
-
184
- // Verify: Widget disappears from UI
185
- expect(fixture.nativeElement.querySelectorAll('lib-cell').length).toBe(0);
186
- });
187
- });
188
-
189
- describe('Empty State Handling', () => {
190
- it('should handle empty dashboard gracefully', () => {
191
- // SCENARIO: User loads empty dashboard or clears all widgets
192
-
193
- // Action: Initialize with empty dashboard
194
- fixture.detectChanges();
195
-
196
- // Verify: No widgets rendered
197
- expect(fixture.nativeElement.querySelectorAll('lib-cell').length).toBe(0);
198
- expect(component.cells().length).toBe(0);
199
-
200
- // Verify: Export works with empty state
201
- const exported = component.exportDashboard();
202
- expect(exported.cells.length).toBe(0);
203
- expect(exported.version).toBe('1.0.0');
204
- expect(exported.rows).toBe(8);
205
- expect(exported.columns).toBe(12);
206
-
207
- // Verify: Widget state collection works with no widgets
208
- const widgetStates = component.getCurrentWidgetStates();
209
- expect(widgetStates.size).toBe(0);
210
- expect(widgetStates instanceof Map).toBe(true);
211
- });
212
- });
213
-
214
- describe('Export Functionality with Live Widget States', () => {
215
- it('should export dashboard with live widget states from component instances', () => {
216
- // SCENARIO: User modifies widget states and exports - should get current states, not store states
217
-
218
- // Setup: Add widget with initial state
219
- const widget: CellData = {
220
- widgetId: WidgetIdUtils.generate(),
221
- cellId: CellIdUtils.create(1, 1),
222
- row: 1,
223
- col: 1,
224
- rowSpan: 1,
225
- colSpan: 1,
226
- flat: false,
227
- widgetFactory: mockWidgetFactory,
228
- widgetState: { value: 'Initial State' }
229
- };
230
-
231
- store.addWidget(widget);
232
- fixture.detectChanges();
233
-
234
- // Verify: Widget is rendered
235
- const cellElements = fixture.nativeElement.querySelectorAll('lib-cell');
236
- expect(cellElements.length).toBe(1);
237
-
238
- // Action: Export dashboard (should include live states)
239
- const exported = component.exportDashboard();
240
-
241
- // Verify: Export structure is correct
242
- expect(exported.version).toBe('1.0.0');
243
- expect(exported.cells.length).toBe(1);
244
- expect(exported.cells[0].widgetTypeid).toBe('test-widget');
245
- expect(exported.cells[0].row).toBe(1);
246
- expect(exported.cells[0].col).toBe(1);
247
-
248
- // Verify: getCurrentWidgetStates returns proper map structure
249
- const widgetStates = component.getCurrentWidgetStates();
250
- expect(widgetStates instanceof Map).toBe(true);
251
-
252
- // The actual state collection depends on cell components being properly rendered
253
- // This tests that the method exists and returns the right type with WidgetId keys
254
- const widgetIdKey = WidgetIdUtils.toString(widget.widgetId);
255
- expect(typeof widgetIdKey).toBe('string');
256
- });
257
- });
258
- });
@@ -1,20 +0,0 @@
1
- <!-- Dashboard viewer - read-only grid -->
2
- <div class="grid top-grid">
3
- @for (cell of cells(); track cell.widgetId) {
4
- <lib-cell
5
- class="grid-cell"
6
- [widgetId]="cell.widgetId"
7
- [cellId]="cell.cellId"
8
- [isEditMode]="false"
9
- [draggable]="false"
10
- [row]="cell.row"
11
- [column]="cell.col"
12
- [rowSpan]="cell.rowSpan"
13
- [colSpan]="cell.colSpan"
14
- [flat]="cell.flat"
15
- [widgetFactory]="cell.widgetFactory"
16
- [widgetState]="cell.widgetState"
17
- >
18
- </lib-cell>
19
- }
20
- </div>
@@ -1,50 +0,0 @@
1
- /* dashboard-viewer.component.scss */
2
- @use "../styles/dashboard-grid-vars" as *;
3
-
4
- :host {
5
- @include dashboard-grid-vars;
6
-
7
- display: block;
8
- container-type: inline-size;
9
- box-sizing: border-box;
10
- aspect-ratio: var(--columns) / var(--rows);
11
- width: 100%;
12
- height: auto;
13
-
14
- background-color: var(--mat-sys-surface-container);
15
- }
16
-
17
- .grid {
18
- display: grid;
19
- gap: var(--gutter-size);
20
- padding: var(--gutter-size);
21
-
22
- width: 100%;
23
- height: 100%;
24
- box-sizing: border-box;
25
-
26
- /* ←―― single-source-of-truth for the cell geometry */
27
- grid-template-columns: repeat(var(--columns), var(--cell-size));
28
- grid-template-rows: repeat(var(--rows), var(--cell-size));
29
-
30
- // background-color: var(--mat-sys-surface);
31
- }
32
-
33
- /* Interaction rules */
34
- .grid-cell {
35
- pointer-events: none;
36
- }
37
-
38
- .grid-cell:not(.flat) {
39
- pointer-events: auto;
40
- cursor: default;
41
-
42
- .content-area {
43
- pointer-events: none;
44
- }
45
- }
46
-
47
- .top-grid {
48
- z-index: 2;
49
- pointer-events: none;
50
- }
@@ -1,70 +0,0 @@
1
- import { Component, computed, effect, inject, input, viewChildren, ChangeDetectionStrategy } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { CellComponent } from '../cell/cell.component';
4
- import { DashboardStore } from '../store/dashboard-store';
5
- import { CellIdUtils, WidgetIdUtils } from '../models';
6
-
7
- @Component({
8
- selector: 'ngx-dashboard-viewer',
9
- standalone: true,
10
- imports: [CellComponent, CommonModule],
11
- changeDetection: ChangeDetectionStrategy.OnPush,
12
- templateUrl: './dashboard-viewer.component.html',
13
- styleUrl: './dashboard-viewer.component.scss',
14
- host: {
15
- '[style.--rows]': 'rows()',
16
- '[style.--columns]': 'columns()',
17
- '[style.--gutter-size]': 'gutterSize()',
18
- '[style.--gutters]': 'gutters()',
19
- },
20
- })
21
- export class DashboardViewerComponent {
22
- #store = inject(DashboardStore);
23
- cellComponents = viewChildren(CellComponent);
24
-
25
- rows = input.required<number>();
26
- columns = input.required<number>();
27
- gutterSize = input<string>('1em');
28
- gutters = computed(() => this.columns() + 1);
29
-
30
- // store signals - read-only
31
- cells = this.#store.cells;
32
-
33
- constructor() {
34
- // Sync grid configuration with store when inputs change
35
- effect(() => {
36
- this.#store.setGridConfig({
37
- rows: this.rows(),
38
- columns: this.columns(),
39
- gutterSize: this.gutterSize(),
40
- });
41
- });
42
- }
43
-
44
- /**
45
- * Get current widget states from all cell components.
46
- * Used during dashboard export to get live widget states.
47
- */
48
- getCurrentWidgetStates(): Map<string, unknown> {
49
- const stateMap = new Map<string, unknown>();
50
-
51
- const cells = this.cellComponents();
52
- for (const cell of cells) {
53
- const cellId = cell.cellId();
54
- const currentState = cell.getCurrentWidgetState();
55
- if (currentState !== undefined) {
56
- stateMap.set(CellIdUtils.toString(cellId), currentState);
57
- }
58
- }
59
-
60
- return stateMap;
61
- }
62
-
63
- /**
64
- * Export dashboard with live widget states from current component instances.
65
- * This ensures the most up-to-date widget states are captured.
66
- */
67
- exportDashboard() {
68
- return this.#store.exportDashboard(() => this.getCurrentWidgetStates());
69
- }
70
- }