@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,192 +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, waitFor } from '@testing-library/react';
11
- import React from 'react';
12
- import { ObjectPivotTable } from '../ObjectPivotTable';
13
- import { SchemaRendererProvider } from '@object-ui/react';
14
-
15
- describe('ObjectPivotTable', () => {
16
- const baseSchema = {
17
- type: 'pivot' as const,
18
- rowField: 'region',
19
- columnField: 'quarter',
20
- valueField: 'revenue',
21
- aggregation: 'sum' as const,
22
- };
23
-
24
- it('should render PivotTable with static data', () => {
25
- const schema = {
26
- ...baseSchema,
27
- data: [
28
- { region: 'North', quarter: 'Q1', revenue: 100 },
29
- { region: 'South', quarter: 'Q1', revenue: 200 },
30
- ],
31
- };
32
-
33
- render(<ObjectPivotTable schema={schema} />);
34
- expect(screen.getByText('North')).toBeDefined();
35
- expect(screen.getByText('South')).toBeDefined();
36
- });
37
-
38
- it('should show loading skeleton when fetching data', async () => {
39
- // A dataSource that resolves slowly
40
- const dataSource = {
41
- find: vi.fn(() => new Promise(() => {})), // Never resolves
42
- };
43
-
44
- const schema = {
45
- ...baseSchema,
46
- objectName: 'sales',
47
- };
48
-
49
- const { container } = render(
50
- <SchemaRendererProvider dataSource={dataSource}>
51
- <ObjectPivotTable schema={schema} />
52
- </SchemaRendererProvider>,
53
- );
54
-
55
- // Should show loading skeleton
56
- await waitFor(() => {
57
- const loadingEl = container.querySelector('[data-testid="pivot-loading"]');
58
- expect(loadingEl).toBeDefined();
59
- });
60
- });
61
-
62
- it('should show error state on fetch failure', async () => {
63
- const dataSource = {
64
- find: vi.fn().mockRejectedValue(new Error('Network error')),
65
- };
66
-
67
- const schema = {
68
- ...baseSchema,
69
- objectName: 'sales',
70
- };
71
-
72
- const { container } = render(
73
- <SchemaRendererProvider dataSource={dataSource}>
74
- <ObjectPivotTable schema={schema} />
75
- </SchemaRendererProvider>,
76
- );
77
-
78
- await waitFor(() => {
79
- const errorEl = container.querySelector('[data-testid="pivot-error"]');
80
- expect(errorEl).not.toBeNull();
81
- });
82
-
83
- expect(screen.getByText('Network error')).toBeDefined();
84
- });
85
-
86
- it('should render fetched data in PivotTable', async () => {
87
- const dataSource = {
88
- find: vi.fn().mockResolvedValue({
89
- records: [
90
- { region: 'East', quarter: 'Q1', revenue: 500 },
91
- { region: 'West', quarter: 'Q2', revenue: 300 },
92
- ],
93
- }),
94
- };
95
-
96
- const schema = {
97
- ...baseSchema,
98
- objectName: 'sales',
99
- };
100
-
101
- render(
102
- <SchemaRendererProvider dataSource={dataSource}>
103
- <ObjectPivotTable schema={schema} />
104
- </SchemaRendererProvider>,
105
- );
106
-
107
- await waitFor(() => {
108
- expect(screen.getByText('East')).toBeDefined();
109
- expect(screen.getByText('West')).toBeDefined();
110
- });
111
-
112
- expect(dataSource.find).toHaveBeenCalledWith('sales', { $filter: undefined });
113
- });
114
-
115
- it('should show empty state when no data returned', async () => {
116
- const dataSource = {
117
- find: vi.fn().mockResolvedValue({ records: [] }),
118
- };
119
-
120
- const schema = {
121
- ...baseSchema,
122
- objectName: 'sales',
123
- };
124
-
125
- const { container } = render(
126
- <SchemaRendererProvider dataSource={dataSource}>
127
- <ObjectPivotTable schema={schema} />
128
- </SchemaRendererProvider>,
129
- );
130
-
131
- await waitFor(() => {
132
- const emptyState = container.querySelector('[data-testid="pivot-empty-state"]');
133
- expect(emptyState).toBeDefined();
134
- });
135
- });
136
-
137
- it('should prefer static data over fetched data', () => {
138
- const dataSource = {
139
- find: vi.fn(),
140
- };
141
-
142
- const schema = {
143
- ...baseSchema,
144
- objectName: 'sales',
145
- data: [
146
- { region: 'Static', quarter: 'Q1', revenue: 999 },
147
- ],
148
- };
149
-
150
- render(
151
- <SchemaRendererProvider dataSource={dataSource}>
152
- <ObjectPivotTable schema={schema} />
153
- </SchemaRendererProvider>,
154
- );
155
-
156
- expect(screen.getByText('Static')).toBeDefined();
157
- expect(dataSource.find).not.toHaveBeenCalled();
158
- });
159
-
160
- it('should show no-data-source message when objectName is set but no dataSource available', () => {
161
- const schema = {
162
- ...baseSchema,
163
- objectName: 'sales',
164
- };
165
-
166
- render(<ObjectPivotTable schema={schema} />);
167
- expect(screen.getByText(/No data source available/)).toBeDefined();
168
- });
169
-
170
- it('should render title in all states', async () => {
171
- const dataSource = {
172
- find: vi.fn().mockRejectedValue(new Error('fail')),
173
- };
174
-
175
- const schema = {
176
- ...baseSchema,
177
- objectName: 'sales',
178
- title: 'Revenue Pivot',
179
- };
180
-
181
- render(
182
- <SchemaRendererProvider dataSource={dataSource}>
183
- <ObjectPivotTable schema={schema} />
184
- </SchemaRendererProvider>,
185
- );
186
-
187
- // Title shows even in error state
188
- await waitFor(() => {
189
- expect(screen.getByText('Revenue Pivot')).toBeDefined();
190
- });
191
- });
192
- });
@@ -1,162 +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 } from 'vitest';
10
- import { render, screen } from '@testing-library/react';
11
- import '@testing-library/jest-dom';
12
- import { PivotTable } from '../PivotTable';
13
- import type { PivotTableSchema } from '@object-ui/types';
14
-
15
- const SAMPLE_DATA = [
16
- { owner: 'Alice', stage: 'Discovery', amount: 1000 },
17
- { owner: 'Alice', stage: 'Proposal', amount: 2000 },
18
- { owner: 'Alice', stage: 'Discovery', amount: 500 },
19
- { owner: 'Bob', stage: 'Discovery', amount: 3000 },
20
- { owner: 'Bob', stage: 'Closed', amount: 5000 },
21
- { owner: 'Carol', stage: 'Proposal', amount: 4000 },
22
- ];
23
-
24
- function makeSchema(overrides?: Partial<PivotTableSchema>): PivotTableSchema {
25
- return {
26
- type: 'pivot',
27
- rowField: 'owner',
28
- columnField: 'stage',
29
- valueField: 'amount',
30
- data: SAMPLE_DATA,
31
- ...overrides,
32
- };
33
- }
34
-
35
- describe('PivotTable', () => {
36
- it('should render row and column headers', () => {
37
- render(<PivotTable schema={makeSchema()} />);
38
-
39
- // Row headers
40
- expect(screen.getByText('Alice')).toBeInTheDocument();
41
- expect(screen.getByText('Bob')).toBeInTheDocument();
42
- expect(screen.getByText('Carol')).toBeInTheDocument();
43
-
44
- // Column headers
45
- expect(screen.getByText('Discovery')).toBeInTheDocument();
46
- expect(screen.getByText('Proposal')).toBeInTheDocument();
47
- expect(screen.getByText('Closed')).toBeInTheDocument();
48
- });
49
-
50
- it('should aggregate values with sum by default', () => {
51
- render(<PivotTable schema={makeSchema()} />);
52
-
53
- // Alice + Discovery = 1000 + 500 = 1500
54
- expect(screen.getByText('1500')).toBeInTheDocument();
55
- // Alice + Proposal = 2000
56
- expect(screen.getByText('2000')).toBeInTheDocument();
57
- // Bob + Discovery = 3000
58
- expect(screen.getByText('3000')).toBeInTheDocument();
59
- // Bob + Closed = 5000
60
- expect(screen.getByText('5000')).toBeInTheDocument();
61
- // Carol + Proposal = 4000
62
- expect(screen.getByText('4000')).toBeInTheDocument();
63
- });
64
-
65
- it('should support count aggregation', () => {
66
- render(<PivotTable schema={makeSchema({ aggregation: 'count' })} />);
67
-
68
- // Alice + Discovery = 2 items
69
- expect(screen.getByText('2')).toBeInTheDocument();
70
- });
71
-
72
- it('should support avg aggregation', () => {
73
- render(<PivotTable schema={makeSchema({ aggregation: 'avg' })} />);
74
-
75
- // Alice + Discovery = avg(1000, 500) = 750
76
- expect(screen.getByText('750')).toBeInTheDocument();
77
- });
78
-
79
- it('should render title when provided', () => {
80
- render(<PivotTable schema={makeSchema({ title: 'Revenue Pivot' })} />);
81
-
82
- expect(screen.getByText('Revenue Pivot')).toBeInTheDocument();
83
- });
84
-
85
- it('should show row totals when showRowTotals is true', () => {
86
- render(<PivotTable schema={makeSchema({ showRowTotals: true })} />);
87
-
88
- // Header "Total" column
89
- const totalHeaders = screen.getAllByText('Total');
90
- expect(totalHeaders.length).toBeGreaterThanOrEqual(1);
91
-
92
- // Alice total = 1000 + 2000 + 500 = 3500
93
- expect(screen.getByText('3500')).toBeInTheDocument();
94
- // Bob total = 3000 + 5000 = 8000
95
- expect(screen.getByText('8000')).toBeInTheDocument();
96
- });
97
-
98
- it('should show column totals when showColumnTotals is true', () => {
99
- render(<PivotTable schema={makeSchema({ showColumnTotals: true })} />);
100
-
101
- // Footer row with "Total" label
102
- const totalCells = screen.getAllByText('Total');
103
- expect(totalCells.length).toBeGreaterThanOrEqual(1);
104
-
105
- // Discovery total = 1000 + 500 + 3000 = 4500
106
- expect(screen.getByText('4500')).toBeInTheDocument();
107
- // Proposal total = 2000 + 4000 = 6000
108
- expect(screen.getByText('6000')).toBeInTheDocument();
109
- });
110
-
111
- it('should show grand total when both row and column totals are enabled', () => {
112
- render(<PivotTable schema={makeSchema({ showRowTotals: true, showColumnTotals: true })} />);
113
-
114
- // Grand total = 1000 + 2000 + 500 + 3000 + 5000 + 4000 = 15500
115
- expect(screen.getByText('15500')).toBeInTheDocument();
116
- });
117
-
118
- it('should apply format string', () => {
119
- render(<PivotTable schema={makeSchema({ format: '$,.0f' })} />);
120
-
121
- // Alice + Discovery = $1,500
122
- expect(screen.getByText('$1,500')).toBeInTheDocument();
123
- // Bob + Closed = $5,000
124
- expect(screen.getByText('$5,000')).toBeInTheDocument();
125
- });
126
-
127
- it('should handle empty data gracefully', () => {
128
- const { container } = render(<PivotTable schema={makeSchema({ data: [] })} />);
129
-
130
- // Should render a friendly empty state instead of an empty table
131
- const emptyState = container.querySelector('[data-testid="pivot-empty-state"]');
132
- expect(emptyState).toBeInTheDocument();
133
- expect(screen.getByText('No data available')).toBeInTheDocument();
134
- });
135
-
136
- it('should handle missing values in data as 0', () => {
137
- const data = [
138
- { owner: 'Alice', stage: 'A', amount: 10 },
139
- { owner: 'Bob', stage: 'B', amount: 20 },
140
- ];
141
- render(<PivotTable schema={makeSchema({ data })} />);
142
-
143
- // Alice × B = 0, Bob × A = 0 should appear
144
- const zeroCells = screen.getAllByText('0');
145
- expect(zeroCells.length).toBe(2);
146
- });
147
-
148
- it('should show title in empty state', () => {
149
- render(<PivotTable schema={makeSchema({ data: [], title: 'Empty Pivot' })} />);
150
-
151
- expect(screen.getByText('Empty Pivot')).toBeInTheDocument();
152
- expect(screen.getByText('No data available')).toBeInTheDocument();
153
- });
154
-
155
- it('should treat non-array data (e.g. provider config) as empty', () => {
156
- const schema = makeSchema({ data: { provider: 'object', object: 'sales' } as any });
157
- const { container } = render(<PivotTable schema={schema} />);
158
-
159
- const emptyState = container.querySelector('[data-testid="pivot-empty-state"]');
160
- expect(emptyState).toBeInTheDocument();
161
- });
162
- });