@object-ui/plugin-dashboard 3.1.3 → 3.1.4

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.
@@ -19,6 +19,20 @@ export interface ObjectDataTableProps {
19
19
  dataSource?: any;
20
20
  className?: string;
21
21
  }
22
+ /** A column definition after normalization, with header and accessor key. */
23
+ interface NormalizedColumn {
24
+ header: string;
25
+ accessorKey: string;
26
+ [key: string]: any;
27
+ }
28
+ /**
29
+ * Normalize columns to support both string[] shorthand and object[] formats.
30
+ *
31
+ * - `string[]` entries are converted to `{ header, accessorKey }` objects,
32
+ * handling both snake_case and camelCase for header generation.
33
+ * - Object entries are returned as-is.
34
+ */
35
+ export declare function normalizeColumns(columns: (string | Record<string, any>)[]): NormalizedColumn[];
22
36
  /**
23
37
  * ObjectDataTable — Async-aware wrapper for data-table.
24
38
  *
@@ -36,4 +50,5 @@ export interface ObjectDataTableProps {
36
50
  * - **Data** → data-table with fetched rows
37
51
  */
38
52
  export declare const ObjectDataTable: React.FC<ObjectDataTableProps>;
53
+ export {};
39
54
  //# sourceMappingURL=ObjectDataTable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectDataTable.d.ts","sourceRoot":"","sources":["../../src/ObjectDataTable.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAKxE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACrD,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,GAAG,CAAC;QACb,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;QAChB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;IACF,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA+I1D,CAAC"}
1
+ {"version":3,"file":"ObjectDataTable.d.ts","sourceRoot":"","sources":["../../src/ObjectDataTable.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAKxE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACrD,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,GAAG,CAAC;QACb,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;QAChB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;IACF,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,6EAA6E;AAC7E,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,gBAAgB,EAAE,CAiB9F;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAiJ1D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-dashboard",
3
- "version": "3.1.3",
3
+ "version": "3.1.4",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Dashboard plugin for Object UI",
@@ -21,10 +21,10 @@
21
21
  "react-dom": "19.2.4",
22
22
  "react-grid-layout": "^2.2.2",
23
23
  "tailwind-merge": "^3.5.0",
24
- "@object-ui/components": "3.1.3",
25
- "@object-ui/core": "3.1.3",
26
- "@object-ui/react": "3.1.3",
27
- "@object-ui/types": "3.1.3"
24
+ "@object-ui/components": "3.1.4",
25
+ "@object-ui/core": "3.1.4",
26
+ "@object-ui/react": "3.1.4",
27
+ "@object-ui/types": "3.1.4"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "react": "^18.0.0",
@@ -32,9 +32,9 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/react-grid-layout": "^2.1.0",
35
- "@vitejs/plugin-react": "^5.1.4",
35
+ "@vitejs/plugin-react": "^6.0.1",
36
36
  "typescript": "^5.9.3",
37
- "vite": "^7.3.1",
37
+ "vite": "^8.0.1",
38
38
  "vite-plugin-dts": "^4.5.4"
39
39
  },
40
40
  "scripts": {
@@ -29,6 +29,39 @@ export interface ObjectDataTableProps {
29
29
  className?: string;
30
30
  }
31
31
 
32
+ /** A column definition after normalization, with header and accessor key. */
33
+ interface NormalizedColumn {
34
+ header: string;
35
+ accessorKey: string;
36
+ [key: string]: any;
37
+ }
38
+
39
+ /**
40
+ * Normalize columns to support both string[] shorthand and object[] formats.
41
+ *
42
+ * - `string[]` entries are converted to `{ header, accessorKey }` objects,
43
+ * handling both snake_case and camelCase for header generation.
44
+ * - Object entries are returned as-is.
45
+ */
46
+ export function normalizeColumns(columns: (string | Record<string, any>)[]): NormalizedColumn[] {
47
+ return columns.map((col) => {
48
+ if (typeof col === 'string') {
49
+ return {
50
+ header: col
51
+ // snake_case → spaces
52
+ .replace(/_/g, ' ')
53
+ // camelCase → spaces before uppercase letters
54
+ .replace(/([A-Z])/g, ' $1')
55
+ .trim()
56
+ // Title Case each word
57
+ .replace(/\b\w/g, (c: string) => c.toUpperCase()),
58
+ accessorKey: col,
59
+ };
60
+ }
61
+ return col;
62
+ });
63
+ }
64
+
32
65
  /**
33
66
  * ObjectDataTable — Async-aware wrapper for data-table.
34
67
  *
@@ -101,7 +134,9 @@ export const ObjectDataTable: React.FC<ObjectDataTableProps> = ({ schema, dataSo
101
134
 
102
135
  // Auto-derive columns from data keys when none are provided
103
136
  const derivedColumns = useMemo(() => {
104
- if (schema.columns && schema.columns.length > 0) return schema.columns;
137
+ if (schema.columns && schema.columns.length > 0) {
138
+ return normalizeColumns(schema.columns);
139
+ }
105
140
  if (finalData.length === 0) return [];
106
141
  // Exclude internal/private fields (prefixed with '_') from auto-derived columns
107
142
  const keys = Object.keys(finalData[0]).filter(k => !k.startsWith('_'));
@@ -9,7 +9,7 @@
9
9
  import { describe, it, expect, vi } from 'vitest';
10
10
  import { render, screen, waitFor } from '@testing-library/react';
11
11
  import React from 'react';
12
- import { ObjectDataTable } from '../ObjectDataTable';
12
+ import { ObjectDataTable, normalizeColumns } from '../ObjectDataTable';
13
13
  import { SchemaRendererProvider } from '@object-ui/react';
14
14
 
15
15
  describe('ObjectDataTable', () => {
@@ -119,4 +119,93 @@ describe('ObjectDataTable', () => {
119
119
 
120
120
  expect(dataSource.find).not.toHaveBeenCalled();
121
121
  });
122
+
123
+ it('should normalize string[] columns without crashing', () => {
124
+ const schema = {
125
+ ...baseSchema,
126
+ columns: ['name', 'amount', 'close_date'],
127
+ data: [
128
+ { name: 'Deal A', amount: 1000, close_date: '2025-01-01' },
129
+ { name: 'Deal B', amount: 2000, close_date: '2025-06-01' },
130
+ ],
131
+ };
132
+
133
+ // Should not crash when columns are strings
134
+ const { container } = render(
135
+ <SchemaRendererProvider>
136
+ <ObjectDataTable schema={schema} />
137
+ </SchemaRendererProvider>,
138
+ );
139
+
140
+ expect(container).toBeDefined();
141
+ });
142
+
143
+ it('should pass through object[] columns unchanged', () => {
144
+ const schema = {
145
+ ...baseSchema,
146
+ columns: [
147
+ { header: 'Name', accessorKey: 'name' },
148
+ { header: 'Amount', accessorKey: 'amount' },
149
+ ],
150
+ data: [
151
+ { name: 'Deal A', amount: 1000 },
152
+ ],
153
+ };
154
+
155
+ const { container } = render(
156
+ <SchemaRendererProvider>
157
+ <ObjectDataTable schema={schema} />
158
+ </SchemaRendererProvider>,
159
+ );
160
+
161
+ expect(container).toBeDefined();
162
+ });
163
+ });
164
+
165
+ describe('normalizeColumns', () => {
166
+ it('should convert snake_case string to title-cased header', () => {
167
+ const result = normalizeColumns(['close_date']);
168
+ expect(result).toEqual([{ header: 'Close Date', accessorKey: 'close_date' }]);
169
+ });
170
+
171
+ it('should convert camelCase string to title-cased header', () => {
172
+ const result = normalizeColumns(['firstName']);
173
+ expect(result).toEqual([{ header: 'First Name', accessorKey: 'firstName' }]);
174
+ });
175
+
176
+ it('should convert simple string to capitalized header', () => {
177
+ const result = normalizeColumns(['name']);
178
+ expect(result).toEqual([{ header: 'Name', accessorKey: 'name' }]);
179
+ });
180
+
181
+ it('should handle multiple string columns', () => {
182
+ const result = normalizeColumns(['name', 'total_amount', 'createdAt']);
183
+ expect(result).toEqual([
184
+ { header: 'Name', accessorKey: 'name' },
185
+ { header: 'Total Amount', accessorKey: 'total_amount' },
186
+ { header: 'Created At', accessorKey: 'createdAt' },
187
+ ]);
188
+ });
189
+
190
+ it('should pass through object columns unchanged', () => {
191
+ const cols = [
192
+ { header: 'Custom Name', accessorKey: 'name' },
193
+ { header: 'Amount ($)', accessorKey: 'amount' },
194
+ ];
195
+ const result = normalizeColumns(cols);
196
+ expect(result).toEqual(cols);
197
+ });
198
+
199
+ it('should handle mixed string and object columns', () => {
200
+ const result = normalizeColumns([
201
+ 'name',
202
+ { header: 'Custom Amount', accessorKey: 'amount' },
203
+ 'close_date',
204
+ ]);
205
+ expect(result).toEqual([
206
+ { header: 'Name', accessorKey: 'name' },
207
+ { header: 'Custom Amount', accessorKey: 'amount' },
208
+ { header: 'Close Date', accessorKey: 'close_date' },
209
+ ]);
210
+ });
122
211
  });