@object-ui/plugin-dashboard 3.1.5 → 3.3.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 (84) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +21 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1162 -939
  5. package/dist/index.umd.cjs +4 -4
  6. package/dist/packages/plugin-dashboard/src/DashboardConfigPanel.d.ts.map +1 -0
  7. package/dist/packages/plugin-dashboard/src/DashboardConfigPanel.stories.d.ts.map +1 -0
  8. package/dist/packages/plugin-dashboard/src/DashboardGridLayout.d.ts.map +1 -0
  9. package/dist/{src → packages/plugin-dashboard/src}/DashboardRenderer.d.ts +5 -0
  10. package/dist/packages/plugin-dashboard/src/DashboardRenderer.d.ts.map +1 -0
  11. package/dist/packages/plugin-dashboard/src/DashboardRenderer.stories.d.ts.map +1 -0
  12. package/dist/packages/plugin-dashboard/src/DashboardWithConfig.d.ts.map +1 -0
  13. package/dist/{src → packages/plugin-dashboard/src}/MetricCard.d.ts +4 -0
  14. package/dist/packages/plugin-dashboard/src/MetricCard.d.ts.map +1 -0
  15. package/dist/packages/plugin-dashboard/src/MetricWidget.d.ts +31 -0
  16. package/dist/packages/plugin-dashboard/src/MetricWidget.d.ts.map +1 -0
  17. package/dist/packages/plugin-dashboard/src/ObjectDataTable.d.ts.map +1 -0
  18. package/dist/packages/plugin-dashboard/src/ObjectMetricWidget.d.ts +59 -0
  19. package/dist/packages/plugin-dashboard/src/ObjectMetricWidget.d.ts.map +1 -0
  20. package/dist/packages/plugin-dashboard/src/ObjectPivotTable.d.ts.map +1 -0
  21. package/dist/packages/plugin-dashboard/src/PivotTable.d.ts.map +1 -0
  22. package/dist/packages/plugin-dashboard/src/WidgetConfigPanel.d.ts.map +1 -0
  23. package/dist/{src → packages/plugin-dashboard/src}/index.d.ts +4 -2
  24. package/dist/packages/plugin-dashboard/src/index.d.ts.map +1 -0
  25. package/dist/packages/plugin-dashboard/src/utils.d.ts.map +1 -0
  26. package/package.json +44 -11
  27. package/.turbo/turbo-build.log +0 -34
  28. package/dist/src/DashboardConfigPanel.d.ts.map +0 -1
  29. package/dist/src/DashboardConfigPanel.stories.d.ts.map +0 -1
  30. package/dist/src/DashboardGridLayout.d.ts.map +0 -1
  31. package/dist/src/DashboardRenderer.d.ts.map +0 -1
  32. package/dist/src/DashboardRenderer.stories.d.ts.map +0 -1
  33. package/dist/src/DashboardWithConfig.d.ts.map +0 -1
  34. package/dist/src/MetricCard.d.ts.map +0 -1
  35. package/dist/src/MetricWidget.d.ts +0 -24
  36. package/dist/src/MetricWidget.d.ts.map +0 -1
  37. package/dist/src/ObjectDataTable.d.ts.map +0 -1
  38. package/dist/src/ObjectPivotTable.d.ts.map +0 -1
  39. package/dist/src/PivotTable.d.ts.map +0 -1
  40. package/dist/src/WidgetConfigPanel.d.ts.map +0 -1
  41. package/dist/src/index.d.ts.map +0 -1
  42. package/dist/src/utils.d.ts.map +0 -1
  43. package/src/DashboardConfigPanel.stories.tsx +0 -164
  44. package/src/DashboardConfigPanel.tsx +0 -158
  45. package/src/DashboardGridLayout.tsx +0 -367
  46. package/src/DashboardRenderer.stories.tsx +0 -173
  47. package/src/DashboardRenderer.tsx +0 -445
  48. package/src/DashboardWithConfig.tsx +0 -211
  49. package/src/MetricCard.tsx +0 -82
  50. package/src/MetricWidget.tsx +0 -76
  51. package/src/ObjectDataTable.tsx +0 -226
  52. package/src/ObjectPivotTable.tsx +0 -160
  53. package/src/PivotTable.tsx +0 -262
  54. package/src/WidgetConfigPanel.tsx +0 -540
  55. package/src/__tests__/DashboardConfigPanel.test.tsx +0 -206
  56. package/src/__tests__/DashboardGridLayout.test.tsx +0 -199
  57. package/src/__tests__/DashboardRenderer.autoRefresh.test.tsx +0 -124
  58. package/src/__tests__/DashboardRenderer.designMode.test.tsx +0 -386
  59. package/src/__tests__/DashboardRenderer.header.test.tsx +0 -114
  60. package/src/__tests__/DashboardRenderer.mobile.test.tsx +0 -214
  61. package/src/__tests__/DashboardRenderer.widgetData.test.tsx +0 -1283
  62. package/src/__tests__/DashboardWithConfig.test.tsx +0 -276
  63. package/src/__tests__/MetricCard.test.tsx +0 -82
  64. package/src/__tests__/ObjectDataTable.test.tsx +0 -211
  65. package/src/__tests__/ObjectPivotTable.test.tsx +0 -192
  66. package/src/__tests__/PivotTable.test.tsx +0 -162
  67. package/src/__tests__/WidgetConfigPanel.test.tsx +0 -492
  68. package/src/__tests__/ensureWidgetIds.test.tsx +0 -103
  69. package/src/index.tsx +0 -214
  70. package/src/utils.ts +0 -17
  71. package/tsconfig.json +0 -19
  72. package/vite.config.ts +0 -63
  73. package/vitest.config.ts +0 -9
  74. package/vitest.setup.tsx +0 -18
  75. /package/dist/{src → packages/plugin-dashboard/src}/DashboardConfigPanel.d.ts +0 -0
  76. /package/dist/{src → packages/plugin-dashboard/src}/DashboardConfigPanel.stories.d.ts +0 -0
  77. /package/dist/{src → packages/plugin-dashboard/src}/DashboardGridLayout.d.ts +0 -0
  78. /package/dist/{src → packages/plugin-dashboard/src}/DashboardRenderer.stories.d.ts +0 -0
  79. /package/dist/{src → packages/plugin-dashboard/src}/DashboardWithConfig.d.ts +0 -0
  80. /package/dist/{src → packages/plugin-dashboard/src}/ObjectDataTable.d.ts +0 -0
  81. /package/dist/{src → packages/plugin-dashboard/src}/ObjectPivotTable.d.ts +0 -0
  82. /package/dist/{src → packages/plugin-dashboard/src}/PivotTable.d.ts +0 -0
  83. /package/dist/{src → packages/plugin-dashboard/src}/WidgetConfigPanel.d.ts +0 -0
  84. /package/dist/{src → packages/plugin-dashboard/src}/utils.d.ts +0 -0
@@ -1,206 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import { describe, it, expect, vi } from 'vitest';
10
- import { render, screen, fireEvent } from '@testing-library/react';
11
- import { DashboardConfigPanel } from '../DashboardConfigPanel';
12
-
13
- const defaultConfig = {
14
- columns: 3,
15
- gap: 4,
16
- rowHeight: '120',
17
- refreshInterval: '0',
18
- title: 'My Dashboard',
19
- showDescription: true,
20
- theme: 'auto',
21
- };
22
-
23
- describe('DashboardConfigPanel', () => {
24
- it('should render nothing when closed', () => {
25
- const { container } = render(
26
- <DashboardConfigPanel
27
- open={false}
28
- onClose={vi.fn()}
29
- config={defaultConfig}
30
- onSave={vi.fn()}
31
- />,
32
- );
33
- expect(container.innerHTML).toBe('');
34
- });
35
-
36
- it('should render panel when open', () => {
37
- render(
38
- <DashboardConfigPanel
39
- open={true}
40
- onClose={vi.fn()}
41
- config={defaultConfig}
42
- onSave={vi.fn()}
43
- />,
44
- );
45
- expect(screen.getByTestId('config-panel')).toBeDefined();
46
- });
47
-
48
- it('should display dashboard breadcrumb', () => {
49
- render(
50
- <DashboardConfigPanel
51
- open={true}
52
- onClose={vi.fn()}
53
- config={defaultConfig}
54
- onSave={vi.fn()}
55
- />,
56
- );
57
- expect(screen.getByText('Dashboard')).toBeDefined();
58
- expect(screen.getByText('Configuration')).toBeDefined();
59
- });
60
-
61
- it('should display layout section fields', () => {
62
- render(
63
- <DashboardConfigPanel
64
- open={true}
65
- onClose={vi.fn()}
66
- config={defaultConfig}
67
- onSave={vi.fn()}
68
- />,
69
- );
70
- expect(screen.getByText('Layout')).toBeDefined();
71
- expect(screen.getByText('Columns')).toBeDefined();
72
- expect(screen.getByText('Gap')).toBeDefined();
73
- expect(screen.getByText('Row height')).toBeDefined();
74
- });
75
-
76
- it('should display data section', () => {
77
- render(
78
- <DashboardConfigPanel
79
- open={true}
80
- onClose={vi.fn()}
81
- config={defaultConfig}
82
- onSave={vi.fn()}
83
- />,
84
- );
85
- expect(screen.getByText('Data')).toBeDefined();
86
- expect(screen.getByText('Refresh interval')).toBeDefined();
87
- });
88
-
89
- it('should have appearance section collapsed by default', () => {
90
- render(
91
- <DashboardConfigPanel
92
- open={true}
93
- onClose={vi.fn()}
94
- config={defaultConfig}
95
- onSave={vi.fn()}
96
- />,
97
- );
98
- expect(screen.getByText('Appearance')).toBeDefined();
99
- // Title field should be hidden since appearance is collapsed by default
100
- // Note: 'My Dashboard' is the title field value from the config, not the section title.
101
- // The input label 'Title' should not be visible while collapsed
102
- expect(screen.queryByText('Show description')).toBeNull();
103
- });
104
-
105
- it('should expand appearance section on click', () => {
106
- render(
107
- <DashboardConfigPanel
108
- open={true}
109
- onClose={vi.fn()}
110
- config={defaultConfig}
111
- onSave={vi.fn()}
112
- />,
113
- );
114
- // Click to expand
115
- fireEvent.click(screen.getByTestId('section-header-appearance'));
116
- expect(screen.getByText('Show description')).toBeDefined();
117
- expect(screen.getByText('Theme')).toBeDefined();
118
- });
119
-
120
- it('should call onClose when close button clicked', () => {
121
- const onClose = vi.fn();
122
- render(
123
- <DashboardConfigPanel
124
- open={true}
125
- onClose={onClose}
126
- config={defaultConfig}
127
- onSave={vi.fn()}
128
- />,
129
- );
130
- fireEvent.click(screen.getByTestId('config-panel-close'));
131
- expect(onClose).toHaveBeenCalledTimes(1);
132
- });
133
-
134
- it('should show save/discard footer after editing a field', () => {
135
- render(
136
- <DashboardConfigPanel
137
- open={true}
138
- onClose={vi.fn()}
139
- config={defaultConfig}
140
- onSave={vi.fn()}
141
- />,
142
- );
143
- // Edit the row height input
144
- const rowHeightInput = screen.getByTestId('config-field-rowHeight');
145
- fireEvent.change(rowHeightInput, { target: { value: '200' } });
146
- expect(screen.getByTestId('config-panel-footer')).toBeDefined();
147
- });
148
-
149
- it('should call onSave with updated draft', () => {
150
- const onSave = vi.fn();
151
- render(
152
- <DashboardConfigPanel
153
- open={true}
154
- onClose={vi.fn()}
155
- config={defaultConfig}
156
- onSave={onSave}
157
- />,
158
- );
159
- // Modify a field
160
- fireEvent.change(screen.getByTestId('config-field-rowHeight'), {
161
- target: { value: '200' },
162
- });
163
- // Save
164
- fireEvent.click(screen.getByTestId('config-panel-save'));
165
- expect(onSave).toHaveBeenCalledTimes(1);
166
- const savedDraft = onSave.mock.calls[0][0];
167
- expect(savedDraft.rowHeight).toBe('200');
168
- });
169
-
170
- it('should revert changes on discard', () => {
171
- render(
172
- <DashboardConfigPanel
173
- open={true}
174
- onClose={vi.fn()}
175
- config={defaultConfig}
176
- onSave={vi.fn()}
177
- />,
178
- );
179
- const input = screen.getByTestId('config-field-rowHeight') as HTMLInputElement;
180
- fireEvent.change(input, { target: { value: '999' } });
181
- expect(input.value).toBe('999');
182
-
183
- // Discard
184
- fireEvent.click(screen.getByTestId('config-panel-discard'));
185
-
186
- // Footer should disappear (no longer dirty)
187
- expect(screen.queryByTestId('config-panel-footer')).toBeNull();
188
- });
189
-
190
- it('should call onFieldChange for live updates', () => {
191
- const onFieldChange = vi.fn();
192
- render(
193
- <DashboardConfigPanel
194
- open={true}
195
- onClose={vi.fn()}
196
- config={defaultConfig}
197
- onSave={vi.fn()}
198
- onFieldChange={onFieldChange}
199
- />,
200
- );
201
- fireEvent.change(screen.getByTestId('config-field-rowHeight'), {
202
- target: { value: '150' },
203
- });
204
- expect(onFieldChange).toHaveBeenCalledWith('rowHeight', '150');
205
- });
206
- });
@@ -1,199 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import { describe, it, expect, vi, beforeEach } from 'vitest';
10
- import { render, screen, fireEvent } from '@testing-library/react';
11
- import { DashboardGridLayout } from '../DashboardGridLayout';
12
- import type { DashboardSchema } from '@object-ui/types';
13
-
14
- // Mock localStorage
15
- const localStorageMock = (() => {
16
- let store: Record<string, string> = {};
17
- return {
18
- getItem: (key: string) => store[key] || null,
19
- setItem: (key: string, value: string) => { store[key] = value; },
20
- clear: () => { store = {}; },
21
- removeItem: (key: string) => { delete store[key]; },
22
- };
23
- })();
24
-
25
- Object.defineProperty(window, 'localStorage', { value: localStorageMock });
26
-
27
- // Mock react-grid-layout
28
- vi.mock('react-grid-layout', () => ({
29
- Responsive: ({ children }: any) => <div data-testid="grid-layout">{children}</div>,
30
- WidthProvider: (Component: any) => Component,
31
- }));
32
-
33
- describe('DashboardGridLayout', () => {
34
- beforeEach(() => {
35
- localStorageMock.clear();
36
- });
37
-
38
- const mockSchema: DashboardSchema = {
39
- type: 'dashboard',
40
- name: 'test_dashboard',
41
- title: 'Test Dashboard',
42
- widgets: [
43
- {
44
- id: 'widget-1',
45
- type: 'metric-card',
46
- title: 'Total Sales',
47
- layout: { x: 0, y: 0, w: 3, h: 2 },
48
- },
49
- {
50
- id: 'widget-2',
51
- type: 'bar',
52
- title: 'Revenue by Month',
53
- layout: { x: 3, y: 0, w: 6, h: 4 },
54
- },
55
- ],
56
- };
57
-
58
- it('should render without crashing', () => {
59
- const { container } = render(<DashboardGridLayout schema={mockSchema} />);
60
- expect(container).toBeTruthy();
61
- });
62
-
63
- it('should render dashboard title', () => {
64
- render(<DashboardGridLayout schema={mockSchema} />);
65
- expect(screen.getByText('Test Dashboard')).toBeInTheDocument();
66
- });
67
-
68
- it('should render all widgets', () => {
69
- render(<DashboardGridLayout schema={mockSchema} />);
70
-
71
- expect(screen.getAllByText('Total Sales').length).toBeGreaterThan(0);
72
- expect(screen.getByText('Revenue by Month')).toBeInTheDocument();
73
- });
74
-
75
- it('should render edit mode button', () => {
76
- render(<DashboardGridLayout schema={mockSchema} />);
77
-
78
- const editButton = screen.getByRole('button', { name: /edit/i });
79
- expect(editButton).toBeInTheDocument();
80
- });
81
-
82
- it('should toggle edit mode when edit button is clicked', () => {
83
- render(<DashboardGridLayout schema={mockSchema} />);
84
-
85
- const editButton = screen.getByRole('button', { name: /edit/i });
86
- fireEvent.click(editButton);
87
-
88
- // In edit mode, should show Save and Cancel buttons
89
- expect(screen.getByRole('button', { name: /save/i })).toBeInTheDocument();
90
- expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
91
- });
92
-
93
- it('should save layout to localStorage when save button is clicked', () => {
94
- render(<DashboardGridLayout schema={mockSchema} persistLayoutKey="test-layout" />);
95
-
96
- const editButton = screen.getByRole('button', { name: /edit/i });
97
- fireEvent.click(editButton);
98
-
99
- const saveButton = screen.getByRole('button', { name: /save/i });
100
- fireEvent.click(saveButton);
101
-
102
- // Check that layout was saved to localStorage
103
- const saved = localStorageMock.getItem('test-layout');
104
- expect(saved).toBeTruthy();
105
- });
106
-
107
- it('should restore layout from localStorage', () => {
108
- const savedLayout = {
109
- lg: [
110
- { i: 'widget-1', x: 0, y: 0, w: 3, h: 2 },
111
- { i: 'widget-2', x: 3, y: 0, w: 6, h: 4 },
112
- ],
113
- };
114
-
115
- localStorageMock.setItem('test-layout', JSON.stringify(savedLayout));
116
-
117
- render(<DashboardGridLayout schema={mockSchema} persistLayoutKey="test-layout" />);
118
-
119
- // Component should render with saved layout
120
- expect(screen.getByText('Test Dashboard')).toBeInTheDocument();
121
- });
122
-
123
- it('should call onLayoutChange when layout changes', () => {
124
- const onLayoutChange = vi.fn();
125
- render(<DashboardGridLayout schema={mockSchema} onLayoutChange={onLayoutChange} />);
126
-
127
- // Trigger layout change (this would normally happen through drag/drop)
128
- // In our mock, we can't easily trigger this, but we verify the callback exists
129
- expect(onLayoutChange).toBeDefined();
130
- });
131
-
132
- it('should cancel edit mode when cancel button is clicked', () => {
133
- render(<DashboardGridLayout schema={mockSchema} />);
134
-
135
- const editButton = screen.getByRole('button', { name: /edit/i });
136
- fireEvent.click(editButton);
137
-
138
- const cancelButton = screen.getByRole('button', { name: /cancel/i });
139
- fireEvent.click(cancelButton);
140
-
141
- // Should exit edit mode
142
- expect(screen.getByRole('button', { name: /edit/i })).toBeInTheDocument();
143
- expect(screen.queryByRole('button', { name: /save/i })).not.toBeInTheDocument();
144
- });
145
-
146
- it('should reset layout when reset button is clicked', () => {
147
- render(<DashboardGridLayout schema={mockSchema} />);
148
-
149
- const editButton = screen.getByRole('button', { name: /edit/i });
150
- fireEvent.click(editButton);
151
-
152
- // Look for reset button (might be in a dropdown or menu)
153
- const buttons = screen.getAllByRole('button');
154
- const resetButton = buttons.find(btn => btn.textContent?.includes('Reset'));
155
-
156
- if (resetButton) {
157
- fireEvent.click(resetButton);
158
- }
159
- });
160
-
161
- it('should render grid layout container', () => {
162
- render(<DashboardGridLayout schema={mockSchema} />);
163
-
164
- const gridLayout = screen.getByTestId('grid-layout');
165
- expect(gridLayout).toBeInTheDocument();
166
- });
167
-
168
- it('should handle empty widgets array', () => {
169
- const emptySchema: DashboardSchema = {
170
- type: 'dashboard',
171
- name: 'empty_dashboard',
172
- title: 'Empty Dashboard',
173
- widgets: [],
174
- };
175
-
176
- const { container } = render(<DashboardGridLayout schema={emptySchema} />);
177
- expect(container).toBeTruthy();
178
- });
179
-
180
- it('should apply custom className', () => {
181
- const { container } = render(
182
- <DashboardGridLayout schema={mockSchema} className="custom-class" />
183
- );
184
-
185
- const dashboardContainer = container.querySelector('.custom-class');
186
- expect(dashboardContainer).toBeTruthy();
187
- });
188
-
189
- it('should render drag handles in edit mode', () => {
190
- const { container } = render(<DashboardGridLayout schema={mockSchema} />);
191
-
192
- const editButton = screen.getByRole('button', { name: /edit/i });
193
- fireEvent.click(editButton);
194
-
195
- // In edit mode, widgets should have drag handles (GripVertical icons)
196
- const gripIcons = container.querySelectorAll('svg');
197
- expect(gripIcons.length).toBeGreaterThan(0);
198
- });
199
- });
@@ -1,124 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
10
- import { render, screen, fireEvent, act } from '@testing-library/react';
11
- import { DashboardRenderer } from '../DashboardRenderer';
12
- import type { DashboardSchema } from '@object-ui/types';
13
-
14
- describe('DashboardRenderer auto-refresh', () => {
15
- beforeEach(() => {
16
- vi.useFakeTimers();
17
- });
18
-
19
- afterEach(() => {
20
- vi.useRealTimers();
21
- });
22
-
23
- const mockSchema: DashboardSchema = {
24
- type: 'dashboard',
25
- name: 'test_dashboard',
26
- title: 'Test Dashboard',
27
- widgets: [],
28
- };
29
-
30
- it('should not render refresh button when onRefresh is not provided', () => {
31
- render(<DashboardRenderer schema={mockSchema} />);
32
- expect(screen.queryByLabelText('Refresh dashboard')).not.toBeInTheDocument();
33
- });
34
-
35
- it('should render refresh button when onRefresh is provided', () => {
36
- const onRefresh = vi.fn();
37
- render(<DashboardRenderer schema={mockSchema} onRefresh={onRefresh} />);
38
- expect(screen.getByLabelText('Refresh dashboard')).toBeInTheDocument();
39
- });
40
-
41
- it('should call onRefresh when refresh button is clicked', () => {
42
- const onRefresh = vi.fn();
43
- render(<DashboardRenderer schema={mockSchema} onRefresh={onRefresh} />);
44
-
45
- const button = screen.getByLabelText('Refresh dashboard');
46
- fireEvent.click(button);
47
-
48
- expect(onRefresh).toHaveBeenCalledTimes(1);
49
- });
50
-
51
- it('should auto-refresh at the configured interval', () => {
52
- const onRefresh = vi.fn();
53
- const schemaWithRefresh: DashboardSchema = {
54
- ...mockSchema,
55
- refreshInterval: 30, // 30 seconds
56
- };
57
-
58
- render(<DashboardRenderer schema={schemaWithRefresh} onRefresh={onRefresh} />);
59
-
60
- expect(onRefresh).not.toHaveBeenCalled();
61
-
62
- // Advance past one interval
63
- act(() => {
64
- vi.advanceTimersByTime(30_000);
65
- });
66
- expect(onRefresh).toHaveBeenCalledTimes(1);
67
-
68
- // Advance past another interval
69
- act(() => {
70
- vi.advanceTimersByTime(30_000);
71
- });
72
- expect(onRefresh).toHaveBeenCalledTimes(2);
73
- });
74
-
75
- it('should not auto-refresh when refreshInterval is 0', () => {
76
- const onRefresh = vi.fn();
77
- const schemaWithZeroInterval: DashboardSchema = {
78
- ...mockSchema,
79
- refreshInterval: 0,
80
- };
81
-
82
- render(<DashboardRenderer schema={schemaWithZeroInterval} onRefresh={onRefresh} />);
83
-
84
- act(() => {
85
- vi.advanceTimersByTime(60_000);
86
- });
87
-
88
- expect(onRefresh).not.toHaveBeenCalled();
89
- });
90
-
91
- it('should not auto-refresh when onRefresh is not provided', () => {
92
- const schemaWithRefresh: DashboardSchema = {
93
- ...mockSchema,
94
- refreshInterval: 10,
95
- };
96
-
97
- // Should not throw
98
- render(<DashboardRenderer schema={schemaWithRefresh} />);
99
-
100
- act(() => {
101
- vi.advanceTimersByTime(30_000);
102
- });
103
- });
104
-
105
- it('should clean up interval on unmount', () => {
106
- const onRefresh = vi.fn();
107
- const schemaWithRefresh: DashboardSchema = {
108
- ...mockSchema,
109
- refreshInterval: 5,
110
- };
111
-
112
- const { unmount } = render(
113
- <DashboardRenderer schema={schemaWithRefresh} onRefresh={onRefresh} />
114
- );
115
-
116
- unmount();
117
-
118
- act(() => {
119
- vi.advanceTimersByTime(30_000);
120
- });
121
-
122
- expect(onRefresh).not.toHaveBeenCalled();
123
- });
124
- });