@object-ui/plugin-charts 3.3.0 → 3.3.2
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.
- package/CHANGELOG.md +19 -0
- package/README.md +24 -0
- package/dist/{AdvancedChartImpl-JDjuxIZW.js → AdvancedChartImpl-DxaZtNlE.js} +17 -12
- package/dist/{BarChart-Bvt5Se8Q.js → BarChart-BQS4sYHd.js} +1 -1
- package/dist/{ChartImpl-CQj8Kris.js → ChartImpl-BaXisyXJ.js} +2 -2
- package/dist/index.js +2 -2
- package/dist/index.umd.cjs +2 -2
- package/dist/{jsx-runtime-C8d0IhUE.js → jsx-runtime-Caia9pQX.js} +1 -1
- package/package.json +32 -9
- package/.turbo/turbo-build.log +0 -26
- package/examples/chart-examples.ts +0 -54
- package/src/AdvancedChartImpl.tsx +0 -323
- package/src/ChartContainerImpl.tsx +0 -353
- package/src/ChartImpl.tsx +0 -91
- package/src/ChartRenderer.tsx +0 -112
- package/src/ObjectChart.stories.tsx +0 -104
- package/src/ObjectChart.tsx +0 -298
- package/src/__tests__/ObjectChart.aggregation.test.ts +0 -166
- package/src/__tests__/ObjectChart.dataFetch.test.tsx +0 -303
- package/src/__tests__/ObjectChart.labelResolution.test.ts +0 -329
- package/src/index.test.ts +0 -136
- package/src/index.tsx +0 -172
- package/src/types.ts +0 -68
- package/tsconfig.json +0 -17
- package/vite.config.ts +0 -62
- package/vitest.config.ts +0 -13
- package/vitest.setup.ts +0 -1
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for ObjectChart groupBy value→label resolution.
|
|
3
|
-
*
|
|
4
|
-
* Verifies that resolveGroupByLabels():
|
|
5
|
-
* - Maps select field values to their option labels
|
|
6
|
-
* - Handles string-only options (value === label)
|
|
7
|
-
* - Falls back to humanizeLabel() when no options match
|
|
8
|
-
* - Resolves lookup field IDs to referenced record names
|
|
9
|
-
* - Gracefully handles missing metadata or dataSource errors
|
|
10
|
-
* - Falls back to humanizeLabel() for unknown field types
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
14
|
-
import { resolveGroupByLabels, humanizeLabel } from '../ObjectChart';
|
|
15
|
-
|
|
16
|
-
describe('humanizeLabel', () => {
|
|
17
|
-
it('should convert snake_case to Title Case', () => {
|
|
18
|
-
expect(humanizeLabel('closed_won')).toBe('Closed Won');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should convert kebab-case to Title Case', () => {
|
|
22
|
-
expect(humanizeLabel('high-priority')).toBe('High Priority');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should handle single word', () => {
|
|
26
|
-
expect(humanizeLabel('active')).toBe('Active');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should handle empty string', () => {
|
|
30
|
-
expect(humanizeLabel('')).toBe('');
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('resolveGroupByLabels', () => {
|
|
35
|
-
// ---- select fields ----
|
|
36
|
-
|
|
37
|
-
it('should map select field values to option labels', async () => {
|
|
38
|
-
const data = [
|
|
39
|
-
{ stage: 'closed_won', amount: 500 },
|
|
40
|
-
{ stage: 'prospecting', amount: 200 },
|
|
41
|
-
{ stage: 'closed_lost', amount: 100 },
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
const objectSchema = {
|
|
45
|
-
fields: {
|
|
46
|
-
stage: {
|
|
47
|
-
type: 'select',
|
|
48
|
-
options: [
|
|
49
|
-
{ value: 'prospecting', label: 'Prospecting' },
|
|
50
|
-
{ value: 'closed_won', label: 'Closed Won' },
|
|
51
|
-
{ value: 'closed_lost', label: 'Closed Lost' },
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const result = await resolveGroupByLabels(data, 'stage', objectSchema);
|
|
58
|
-
|
|
59
|
-
expect(result).toEqual([
|
|
60
|
-
{ stage: 'Closed Won', amount: 500 },
|
|
61
|
-
{ stage: 'Prospecting', amount: 200 },
|
|
62
|
-
{ stage: 'Closed Lost', amount: 100 },
|
|
63
|
-
]);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should handle string-only options where value equals label', async () => {
|
|
67
|
-
const data = [
|
|
68
|
-
{ lead_source: 'Web', count: 10 },
|
|
69
|
-
{ lead_source: 'Phone', count: 5 },
|
|
70
|
-
];
|
|
71
|
-
|
|
72
|
-
const objectSchema = {
|
|
73
|
-
fields: {
|
|
74
|
-
lead_source: {
|
|
75
|
-
type: 'select',
|
|
76
|
-
options: ['Web', 'Phone', 'Partner'],
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const result = await resolveGroupByLabels(data, 'lead_source', objectSchema);
|
|
82
|
-
|
|
83
|
-
expect(result).toEqual([
|
|
84
|
-
{ lead_source: 'Web', count: 10 },
|
|
85
|
-
{ lead_source: 'Phone', count: 5 },
|
|
86
|
-
]);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should humanize unmatched select values', async () => {
|
|
90
|
-
const data = [
|
|
91
|
-
{ status: 'not_yet_started', count: 3 },
|
|
92
|
-
];
|
|
93
|
-
|
|
94
|
-
const objectSchema = {
|
|
95
|
-
fields: {
|
|
96
|
-
status: {
|
|
97
|
-
type: 'select',
|
|
98
|
-
options: [
|
|
99
|
-
{ value: 'active', label: 'Active' },
|
|
100
|
-
],
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const result = await resolveGroupByLabels(data, 'status', objectSchema);
|
|
106
|
-
|
|
107
|
-
expect(result[0].status).toBe('Not Yet Started');
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should humanize values when select field has empty options', async () => {
|
|
111
|
-
const data = [
|
|
112
|
-
{ status: 'in_progress', count: 1 },
|
|
113
|
-
];
|
|
114
|
-
|
|
115
|
-
const objectSchema = {
|
|
116
|
-
fields: {
|
|
117
|
-
status: {
|
|
118
|
-
type: 'select',
|
|
119
|
-
options: [],
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const result = await resolveGroupByLabels(data, 'status', objectSchema);
|
|
125
|
-
expect(result[0].status).toBe('In Progress');
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// ---- lookup fields ----
|
|
129
|
-
|
|
130
|
-
it('should resolve lookup field IDs to record names', async () => {
|
|
131
|
-
const data = [
|
|
132
|
-
{ account: '1', amount: 500 },
|
|
133
|
-
{ account: '2', amount: 300 },
|
|
134
|
-
];
|
|
135
|
-
|
|
136
|
-
const objectSchema = {
|
|
137
|
-
fields: {
|
|
138
|
-
account: {
|
|
139
|
-
type: 'lookup',
|
|
140
|
-
reference_to: 'accounts',
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
const mockFind = vi.fn().mockResolvedValue([
|
|
146
|
-
{ id: '1', name: 'Acme Corp' },
|
|
147
|
-
{ id: '2', name: 'Globex Inc' },
|
|
148
|
-
]);
|
|
149
|
-
|
|
150
|
-
const dataSource = { find: mockFind };
|
|
151
|
-
|
|
152
|
-
const result = await resolveGroupByLabels(data, 'account', objectSchema, dataSource);
|
|
153
|
-
|
|
154
|
-
expect(result).toEqual([
|
|
155
|
-
{ account: 'Acme Corp', amount: 500 },
|
|
156
|
-
{ account: 'Globex Inc', amount: 300 },
|
|
157
|
-
]);
|
|
158
|
-
|
|
159
|
-
expect(mockFind).toHaveBeenCalledWith('accounts', {
|
|
160
|
-
$filter: { id: { $in: ['1', '2'] } },
|
|
161
|
-
$top: 2,
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('should use display_field from metadata for lookup label', async () => {
|
|
166
|
-
const data = [
|
|
167
|
-
{ project: 'p1', hours: 40 },
|
|
168
|
-
];
|
|
169
|
-
|
|
170
|
-
const objectSchema = {
|
|
171
|
-
fields: {
|
|
172
|
-
project: {
|
|
173
|
-
type: 'lookup',
|
|
174
|
-
reference_to: 'projects',
|
|
175
|
-
display_field: 'title',
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const mockFind = vi.fn().mockResolvedValue([
|
|
181
|
-
{ id: 'p1', title: 'Website Redesign', name: 'PRJ-001' },
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
const result = await resolveGroupByLabels(data, 'project', objectSchema, { find: mockFind });
|
|
185
|
-
|
|
186
|
-
expect(result[0].project).toBe('Website Redesign');
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it('should use id_field from metadata for lookup query', async () => {
|
|
190
|
-
const data = [
|
|
191
|
-
{ owner: 'uid_42', count: 5 },
|
|
192
|
-
];
|
|
193
|
-
|
|
194
|
-
const objectSchema = {
|
|
195
|
-
fields: {
|
|
196
|
-
owner: {
|
|
197
|
-
type: 'lookup',
|
|
198
|
-
reference_to: 'users',
|
|
199
|
-
id_field: 'uid',
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const mockFind = vi.fn().mockResolvedValue([
|
|
205
|
-
{ uid: 'uid_42', name: 'Jane Doe' },
|
|
206
|
-
]);
|
|
207
|
-
|
|
208
|
-
const result = await resolveGroupByLabels(data, 'owner', objectSchema, { find: mockFind });
|
|
209
|
-
|
|
210
|
-
expect(result[0].owner).toBe('Jane Doe');
|
|
211
|
-
expect(mockFind).toHaveBeenCalledWith('users', {
|
|
212
|
-
$filter: { uid: { $in: ['uid_42'] } },
|
|
213
|
-
$top: 1,
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it('should handle lookup with reference property (ObjectStack convention)', async () => {
|
|
218
|
-
const data = [
|
|
219
|
-
{ customer: '10', total: 100 },
|
|
220
|
-
];
|
|
221
|
-
|
|
222
|
-
const objectSchema = {
|
|
223
|
-
fields: {
|
|
224
|
-
customer: {
|
|
225
|
-
type: 'master_detail',
|
|
226
|
-
reference: 'customers',
|
|
227
|
-
},
|
|
228
|
-
},
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
const mockFind = vi.fn().mockResolvedValue([
|
|
232
|
-
{ id: '10', name: 'Big Client' },
|
|
233
|
-
]);
|
|
234
|
-
|
|
235
|
-
const result = await resolveGroupByLabels(data, 'customer', objectSchema, { find: mockFind });
|
|
236
|
-
|
|
237
|
-
expect(result[0].customer).toBe('Big Client');
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('should keep raw values when lookup fetch fails', async () => {
|
|
241
|
-
const data = [
|
|
242
|
-
{ account: '1', amount: 500 },
|
|
243
|
-
];
|
|
244
|
-
|
|
245
|
-
const objectSchema = {
|
|
246
|
-
fields: {
|
|
247
|
-
account: {
|
|
248
|
-
type: 'lookup',
|
|
249
|
-
reference_to: 'accounts',
|
|
250
|
-
},
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
const dataSource = {
|
|
255
|
-
find: vi.fn().mockRejectedValue(new Error('Network error')),
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
const result = await resolveGroupByLabels(data, 'account', objectSchema, dataSource);
|
|
259
|
-
|
|
260
|
-
// Should gracefully return original data
|
|
261
|
-
expect(result[0].account).toBe('1');
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it('should keep raw values when no dataSource is available for lookup', async () => {
|
|
265
|
-
const data = [
|
|
266
|
-
{ account: '1', amount: 500 },
|
|
267
|
-
];
|
|
268
|
-
|
|
269
|
-
const objectSchema = {
|
|
270
|
-
fields: {
|
|
271
|
-
account: {
|
|
272
|
-
type: 'lookup',
|
|
273
|
-
reference_to: 'accounts',
|
|
274
|
-
},
|
|
275
|
-
},
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
const result = await resolveGroupByLabels(data, 'account', objectSchema);
|
|
279
|
-
|
|
280
|
-
expect(result[0].account).toBe('1');
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
// ---- fallback / edge cases ----
|
|
284
|
-
|
|
285
|
-
it('should humanize values when no field metadata exists', async () => {
|
|
286
|
-
const data = [
|
|
287
|
-
{ category: 'high_priority', count: 5 },
|
|
288
|
-
];
|
|
289
|
-
|
|
290
|
-
const objectSchema = { fields: {} };
|
|
291
|
-
|
|
292
|
-
const result = await resolveGroupByLabels(data, 'category', objectSchema);
|
|
293
|
-
|
|
294
|
-
expect(result[0].category).toBe('High Priority');
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
it('should humanize values for unknown field types', async () => {
|
|
298
|
-
const data = [
|
|
299
|
-
{ region: 'north_america', revenue: 1000 },
|
|
300
|
-
];
|
|
301
|
-
|
|
302
|
-
const objectSchema = {
|
|
303
|
-
fields: {
|
|
304
|
-
region: { type: 'text' },
|
|
305
|
-
},
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
const result = await resolveGroupByLabels(data, 'region', objectSchema);
|
|
309
|
-
|
|
310
|
-
expect(result[0].region).toBe('North America');
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
it('should return empty array for empty data', async () => {
|
|
314
|
-
const result = await resolveGroupByLabels([], 'stage', { fields: {} });
|
|
315
|
-
expect(result).toEqual([]);
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it('should return data as-is when groupByField is empty', async () => {
|
|
319
|
-
const data = [{ stage: 'a', count: 1 }];
|
|
320
|
-
const result = await resolveGroupByLabels(data, '', { fields: {} });
|
|
321
|
-
expect(result).toEqual(data);
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
it('should handle null objectSchema gracefully', async () => {
|
|
325
|
-
const data = [{ stage: 'closed_won', count: 1 }];
|
|
326
|
-
const result = await resolveGroupByLabels(data, 'stage', null);
|
|
327
|
-
expect(result[0].stage).toBe('Closed Won');
|
|
328
|
-
});
|
|
329
|
-
});
|
package/src/index.test.ts
DELETED
|
@@ -1,136 +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, beforeAll } from 'vitest';
|
|
10
|
-
import { ComponentRegistry } from '@object-ui/core';
|
|
11
|
-
|
|
12
|
-
describe('Plugin Charts', () => {
|
|
13
|
-
// Import all renderers to register them
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
await import('./index');
|
|
16
|
-
}, 60000);
|
|
17
|
-
|
|
18
|
-
describe('bar-chart component', () => {
|
|
19
|
-
it('should be registered in ComponentRegistry', () => {
|
|
20
|
-
const chartBarRenderer = ComponentRegistry.get('bar-chart');
|
|
21
|
-
expect(chartBarRenderer).toBeDefined();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should have proper metadata', () => {
|
|
25
|
-
const config = ComponentRegistry.getConfig('bar-chart');
|
|
26
|
-
expect(config).toBeDefined();
|
|
27
|
-
expect(config?.label).toBe('Bar Chart');
|
|
28
|
-
expect(config?.category).toBe('plugin');
|
|
29
|
-
expect(config?.inputs).toBeDefined();
|
|
30
|
-
expect(config?.defaultProps).toBeDefined();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should have expected inputs', () => {
|
|
34
|
-
const config = ComponentRegistry.getConfig('bar-chart');
|
|
35
|
-
const inputNames = config?.inputs?.map((input: any) => input.name) || [];
|
|
36
|
-
|
|
37
|
-
expect(inputNames).toContain('data');
|
|
38
|
-
expect(inputNames).toContain('dataKey');
|
|
39
|
-
expect(inputNames).toContain('xAxisKey');
|
|
40
|
-
expect(inputNames).toContain('height');
|
|
41
|
-
expect(inputNames).toContain('color');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should have data as required input', () => {
|
|
45
|
-
const config = ComponentRegistry.getConfig('bar-chart');
|
|
46
|
-
const dataInput = config?.inputs?.find((input: any) => input.name === 'data');
|
|
47
|
-
|
|
48
|
-
expect(dataInput).toBeDefined();
|
|
49
|
-
expect(dataInput?.required).toBe(true);
|
|
50
|
-
expect(dataInput?.type).toBe('array');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should have sensible default props', () => {
|
|
54
|
-
const config = ComponentRegistry.getConfig('bar-chart');
|
|
55
|
-
const defaults = config?.defaultProps;
|
|
56
|
-
|
|
57
|
-
expect(defaults).toBeDefined();
|
|
58
|
-
expect(defaults?.dataKey).toBe('value');
|
|
59
|
-
expect(defaults?.xAxisKey).toBe('name');
|
|
60
|
-
expect(defaults?.height).toBe(400);
|
|
61
|
-
expect(defaults?.color).toBe('#8884d8');
|
|
62
|
-
expect(defaults?.data).toBeDefined();
|
|
63
|
-
expect(Array.isArray(defaults?.data)).toBe(true);
|
|
64
|
-
expect(defaults?.data.length).toBeGreaterThan(0);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe('chart (advanced) component', () => {
|
|
69
|
-
it('should be registered in ComponentRegistry', () => {
|
|
70
|
-
const chartRenderer = ComponentRegistry.get('chart');
|
|
71
|
-
expect(chartRenderer).toBeDefined();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('should have proper metadata', () => {
|
|
75
|
-
const config = ComponentRegistry.getConfig('chart');
|
|
76
|
-
expect(config).toBeDefined();
|
|
77
|
-
expect(config?.label).toBe('Chart');
|
|
78
|
-
expect(config?.category).toBe('plugin');
|
|
79
|
-
expect(config?.inputs).toBeDefined();
|
|
80
|
-
expect(config?.defaultProps).toBeDefined();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should have expected inputs', () => {
|
|
84
|
-
const config = ComponentRegistry.getConfig('chart');
|
|
85
|
-
const inputNames = config?.inputs?.map((input: any) => input.name) || [];
|
|
86
|
-
|
|
87
|
-
expect(inputNames).toContain('chartType');
|
|
88
|
-
expect(inputNames).toContain('data');
|
|
89
|
-
expect(inputNames).toContain('config');
|
|
90
|
-
expect(inputNames).toContain('xAxisKey');
|
|
91
|
-
expect(inputNames).toContain('series');
|
|
92
|
-
expect(inputNames).toContain('className');
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should have chartType as enum input', () => {
|
|
96
|
-
const config = ComponentRegistry.getConfig('chart');
|
|
97
|
-
const chartTypeInput = config?.inputs?.find((input: any) => input.name === 'chartType');
|
|
98
|
-
|
|
99
|
-
expect(chartTypeInput).toBeDefined();
|
|
100
|
-
expect(chartTypeInput?.type).toBe('enum');
|
|
101
|
-
expect(chartTypeInput?.enum).toBeDefined();
|
|
102
|
-
expect(Array.isArray(chartTypeInput?.enum)).toBe(true);
|
|
103
|
-
|
|
104
|
-
const enumValues = chartTypeInput?.enum?.map((e: any) => e.value) || [];
|
|
105
|
-
expect(enumValues).toContain('bar');
|
|
106
|
-
expect(enumValues).toContain('line');
|
|
107
|
-
expect(enumValues).toContain('area');
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should have data and series as required inputs', () => {
|
|
111
|
-
const config = ComponentRegistry.getConfig('chart');
|
|
112
|
-
const dataInput = config?.inputs?.find((input: any) => input.name === 'data');
|
|
113
|
-
const seriesInput = config?.inputs?.find((input: any) => input.name === 'series');
|
|
114
|
-
|
|
115
|
-
expect(dataInput?.required).toBe(true);
|
|
116
|
-
expect(seriesInput?.required).toBe(true);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should have sensible default props', () => {
|
|
120
|
-
const config = ComponentRegistry.getConfig('chart');
|
|
121
|
-
const defaults = config?.defaultProps;
|
|
122
|
-
|
|
123
|
-
expect(defaults).toBeDefined();
|
|
124
|
-
expect(defaults?.chartType).toBe('bar');
|
|
125
|
-
expect(defaults?.xAxisKey).toBe('name');
|
|
126
|
-
expect(defaults?.data).toBeDefined();
|
|
127
|
-
expect(Array.isArray(defaults?.data)).toBe(true);
|
|
128
|
-
expect(defaults?.data.length).toBeGreaterThan(0);
|
|
129
|
-
expect(defaults?.config).toBeDefined();
|
|
130
|
-
expect(typeof defaults?.config).toBe('object');
|
|
131
|
-
expect(defaults?.series).toBeDefined();
|
|
132
|
-
expect(Array.isArray(defaults?.series)).toBe(true);
|
|
133
|
-
expect(defaults?.series.length).toBeGreaterThan(0);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
});
|
package/src/index.tsx
DELETED
|
@@ -1,172 +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 { ComponentRegistry } from '@object-ui/core';
|
|
10
|
-
import { ChartBarRenderer, ChartRenderer } from './ChartRenderer';
|
|
11
|
-
import { ObjectChart } from './ObjectChart';
|
|
12
|
-
|
|
13
|
-
// Export types for external use
|
|
14
|
-
export type { BarChartSchema } from './types';
|
|
15
|
-
export { ChartBarRenderer, ChartRenderer };
|
|
16
|
-
export { ObjectChart } from './ObjectChart';
|
|
17
|
-
|
|
18
|
-
// Standard Export Protocol - for manual integration
|
|
19
|
-
export const chartComponents = {
|
|
20
|
-
'bar-chart': ChartBarRenderer,
|
|
21
|
-
'chart': ChartRenderer,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// Register the component with the ComponentRegistry
|
|
25
|
-
ComponentRegistry.register(
|
|
26
|
-
'bar-chart',
|
|
27
|
-
ChartBarRenderer,
|
|
28
|
-
{
|
|
29
|
-
namespace: 'plugin-charts',
|
|
30
|
-
label: 'Bar Chart',
|
|
31
|
-
category: 'plugin',
|
|
32
|
-
inputs: [
|
|
33
|
-
{ name: 'data', type: 'array', label: 'Data', required: true },
|
|
34
|
-
{ name: 'dataKey', type: 'string', label: 'Data Key', defaultValue: 'value' },
|
|
35
|
-
{ name: 'xAxisKey', type: 'string', label: 'X-Axis Key', defaultValue: 'name' },
|
|
36
|
-
{ name: 'height', type: 'number', label: 'Height', defaultValue: 400 },
|
|
37
|
-
{ name: 'color', type: 'color', label: 'Color', defaultValue: '#8884d8' },
|
|
38
|
-
],
|
|
39
|
-
defaultProps: {
|
|
40
|
-
data: [
|
|
41
|
-
{ name: 'Jan', value: 400 },
|
|
42
|
-
{ name: 'Feb', value: 300 },
|
|
43
|
-
{ name: 'Mar', value: 600 },
|
|
44
|
-
{ name: 'Apr', value: 800 },
|
|
45
|
-
{ name: 'May', value: 500 },
|
|
46
|
-
],
|
|
47
|
-
dataKey: 'value',
|
|
48
|
-
xAxisKey: 'name',
|
|
49
|
-
height: 400,
|
|
50
|
-
color: '#8884d8',
|
|
51
|
-
},
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
// Alias for generic view
|
|
55
|
-
ComponentRegistry.register('chart', ObjectChart, {
|
|
56
|
-
namespace: 'view',
|
|
57
|
-
category: 'view',
|
|
58
|
-
label: 'Chart',
|
|
59
|
-
inputs: [
|
|
60
|
-
{ name: 'objectName', type: 'string', label: 'Object Name', required: true },
|
|
61
|
-
{ name: 'type', type: 'string', label: 'Chart Type' },
|
|
62
|
-
{ name: 'categoryField', type: 'string', label: 'Category Field' },
|
|
63
|
-
{ name: 'valueField', type: 'string', label: 'Value Field' },
|
|
64
|
-
]
|
|
65
|
-
});
|
|
66
|
-
// Register the advanced chart component
|
|
67
|
-
ComponentRegistry.register(
|
|
68
|
-
'chart',
|
|
69
|
-
ChartRenderer,
|
|
70
|
-
{
|
|
71
|
-
namespace: 'plugin-charts',
|
|
72
|
-
label: 'Chart',
|
|
73
|
-
category: 'plugin',
|
|
74
|
-
inputs: [
|
|
75
|
-
{
|
|
76
|
-
name: 'chartType',
|
|
77
|
-
type: 'enum',
|
|
78
|
-
label: 'Chart Type',
|
|
79
|
-
enum: [
|
|
80
|
-
{ label: 'Bar', value: 'bar' },
|
|
81
|
-
{ label: 'Line', value: 'line' },
|
|
82
|
-
{ label: 'Area', value: 'area' },
|
|
83
|
-
{ label: 'Pie', value: 'pie' },
|
|
84
|
-
{ label: 'Donut', value: 'donut' },
|
|
85
|
-
{ label: 'Radar', value: 'radar' },
|
|
86
|
-
{ label: 'Scatter', value: 'scatter' }
|
|
87
|
-
],
|
|
88
|
-
defaultValue: 'bar'
|
|
89
|
-
},
|
|
90
|
-
{ name: 'data', type: 'code', label: 'Data (JSON)', required: true },
|
|
91
|
-
{ name: 'config', type: 'code', label: 'Config (JSON)' },
|
|
92
|
-
{ name: 'xAxisKey', type: 'string', label: 'X Axis Key', defaultValue: 'name' },
|
|
93
|
-
{ name: 'series', type: 'code', label: 'Series (JSON Array)', required: true },
|
|
94
|
-
{ name: 'className', type: 'string', label: 'CSS Class' }
|
|
95
|
-
],
|
|
96
|
-
defaultProps: {
|
|
97
|
-
chartType: 'bar',
|
|
98
|
-
data: [
|
|
99
|
-
{ name: 'Jan', sales: 400, revenue: 240 },
|
|
100
|
-
{ name: 'Feb', sales: 300, revenue: 139 },
|
|
101
|
-
{ name: 'Mar', sales: 600, revenue: 380 },
|
|
102
|
-
{ name: 'Apr', sales: 800, revenue: 430 },
|
|
103
|
-
{ name: 'May', sales: 500, revenue: 220 },
|
|
104
|
-
],
|
|
105
|
-
config: {
|
|
106
|
-
sales: { label: 'Sales', color: '#8884d8' },
|
|
107
|
-
revenue: { label: 'Revenue', color: '#82ca9d' }
|
|
108
|
-
},
|
|
109
|
-
xAxisKey: 'name',
|
|
110
|
-
series: [
|
|
111
|
-
{ dataKey: 'sales' },
|
|
112
|
-
{ dataKey: 'revenue' }
|
|
113
|
-
]
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
// Alias for CRM App compatibility
|
|
119
|
-
ComponentRegistry.register(
|
|
120
|
-
'chart:bar',
|
|
121
|
-
ChartRenderer,
|
|
122
|
-
{
|
|
123
|
-
namespace: 'plugin-charts',
|
|
124
|
-
label: 'Bar Chart (Alias)',
|
|
125
|
-
category: 'plugin',
|
|
126
|
-
defaultProps: { chartType: 'bar' }
|
|
127
|
-
}
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
ComponentRegistry.register(
|
|
131
|
-
'pie-chart',
|
|
132
|
-
ChartRenderer,
|
|
133
|
-
{
|
|
134
|
-
namespace: 'plugin-charts',
|
|
135
|
-
label: 'Pie Chart',
|
|
136
|
-
category: 'plugin',
|
|
137
|
-
defaultProps: { chartType: 'pie' }
|
|
138
|
-
}
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
ComponentRegistry.register(
|
|
142
|
-
'donut-chart',
|
|
143
|
-
ChartRenderer,
|
|
144
|
-
{
|
|
145
|
-
namespace: 'plugin-charts',
|
|
146
|
-
label: 'Donut Chart',
|
|
147
|
-
category: 'plugin',
|
|
148
|
-
defaultProps: { chartType: 'donut' }
|
|
149
|
-
}
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
ComponentRegistry.register(
|
|
153
|
-
'radar-chart',
|
|
154
|
-
ChartRenderer,
|
|
155
|
-
{
|
|
156
|
-
namespace: 'plugin-charts',
|
|
157
|
-
label: 'Radar Chart',
|
|
158
|
-
category: 'plugin',
|
|
159
|
-
defaultProps: { chartType: 'radar' }
|
|
160
|
-
}
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
ComponentRegistry.register(
|
|
164
|
-
'scatter-chart',
|
|
165
|
-
ChartRenderer,
|
|
166
|
-
{
|
|
167
|
-
namespace: 'plugin-charts',
|
|
168
|
-
label: 'Scatter Chart',
|
|
169
|
-
category: 'plugin',
|
|
170
|
-
defaultProps: { chartType: 'scatter' }
|
|
171
|
-
}
|
|
172
|
-
);
|
package/src/types.ts
DELETED
|
@@ -1,68 +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
|
-
/**
|
|
10
|
-
* TypeScript type definitions for @object-ui/plugin-charts
|
|
11
|
-
*
|
|
12
|
-
* These types can be imported by applications using this plugin
|
|
13
|
-
* to get full TypeScript support for chart schemas.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { BaseSchema } from '@object-ui/types';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Bar Chart component schema.
|
|
20
|
-
* Renders a bar chart using Recharts library.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```typescript
|
|
24
|
-
* import type { BarChartSchema } from '@object-ui/plugin-charts';
|
|
25
|
-
*
|
|
26
|
-
* const chartSchema: BarChartSchema = {
|
|
27
|
-
* type: 'bar-chart',
|
|
28
|
-
* data: [
|
|
29
|
-
* { name: 'Jan', value: 400 },
|
|
30
|
-
* { name: 'Feb', value: 300 }
|
|
31
|
-
* ],
|
|
32
|
-
* dataKey: 'value',
|
|
33
|
-
* xAxisKey: 'name'
|
|
34
|
-
* }
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export interface BarChartSchema extends BaseSchema {
|
|
38
|
-
type: 'bar-chart';
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Array of data points to display in the chart.
|
|
42
|
-
*/
|
|
43
|
-
data?: Array<Record<string, any>>;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Key in the data object for the Y-axis values.
|
|
47
|
-
* @default 'value'
|
|
48
|
-
*/
|
|
49
|
-
dataKey?: string;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Key in the data object for the X-axis labels.
|
|
53
|
-
* @default 'name'
|
|
54
|
-
*/
|
|
55
|
-
xAxisKey?: string;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Height of the chart in pixels.
|
|
59
|
-
* @default 400
|
|
60
|
-
*/
|
|
61
|
-
height?: number;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Color of the bars.
|
|
65
|
-
* @default '#8884d8'
|
|
66
|
-
*/
|
|
67
|
-
color?: string;
|
|
68
|
-
}
|