@object-ui/plugin-list 3.1.2 → 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.
- package/.turbo/turbo-build.log +16 -10
- package/CHANGELOG.md +22 -0
- package/dist/index.js +79620 -98273
- package/dist/index.umd.cjs +55 -128
- package/dist/plugin-list.css +3 -1
- package/dist/src/ListView.d.ts.map +1 -1
- package/package.json +11 -11
- package/src/ListView.tsx +2 -0
- package/src/ObjectGallery.tsx +1 -1
- package/src/__tests__/DataFetch.test.tsx +37 -8
- package/src/__tests__/Export.test.tsx +3 -3
- package/src/__tests__/ListView.test.tsx +24 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/plugin-list",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "ListView plugin for Object UI - unified view component with view type switching",
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"lucide-react": "^0.
|
|
28
|
-
"@object-ui/components": "3.1.
|
|
29
|
-
"@object-ui/core": "3.1.
|
|
30
|
-
"@object-ui/i18n": "3.1.
|
|
31
|
-
"@object-ui/mobile": "3.1.
|
|
32
|
-
"@object-ui/react": "3.1.
|
|
33
|
-
"@object-ui/types": "3.1.
|
|
27
|
+
"lucide-react": "^0.577.0",
|
|
28
|
+
"@object-ui/components": "3.1.4",
|
|
29
|
+
"@object-ui/core": "3.1.4",
|
|
30
|
+
"@object-ui/i18n": "3.1.4",
|
|
31
|
+
"@object-ui/mobile": "3.1.4",
|
|
32
|
+
"@object-ui/react": "3.1.4",
|
|
33
|
+
"@object-ui/types": "3.1.4"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/react": "19.2.14",
|
|
41
41
|
"@types/react-dom": "19.2.3",
|
|
42
|
-
"@vitejs/plugin-react": "^
|
|
42
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
43
43
|
"typescript": "^5.9.3",
|
|
44
|
-
"vite": "^
|
|
44
|
+
"vite": "^8.0.1",
|
|
45
45
|
"vite-plugin-dts": "^4.5.4",
|
|
46
|
-
"vitest": "^4.0
|
|
46
|
+
"vitest": "^4.1.0"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "vite build",
|
package/src/ListView.tsx
CHANGED
|
@@ -661,6 +661,8 @@ export const ListView: React.FC<ListViewProps> = ({
|
|
|
661
661
|
items = (results as any).data;
|
|
662
662
|
} else if (Array.isArray((results as any).records)) {
|
|
663
663
|
items = (results as any).records;
|
|
664
|
+
} else if (Array.isArray((results as any).value)) {
|
|
665
|
+
items = (results as any).value;
|
|
664
666
|
}
|
|
665
667
|
}
|
|
666
668
|
|
package/src/ObjectGallery.tsx
CHANGED
|
@@ -193,7 +193,7 @@ export const ObjectGallery: React.FC<ObjectGalleryProps> = (props) => {
|
|
|
193
193
|
if (!items.length) return <div className="p-4 text-sm text-muted-foreground">No items to display</div>;
|
|
194
194
|
|
|
195
195
|
const renderCard = (item: Record<string, unknown>, i: number) => {
|
|
196
|
-
const id = (item.
|
|
196
|
+
const id = (item.id ?? item._id ?? i) as string | number;
|
|
197
197
|
const title = String(item[titleField] ?? 'Untitled');
|
|
198
198
|
const imageUrl = item[coverField] as string | undefined;
|
|
199
199
|
|
|
@@ -40,7 +40,7 @@ describe('ListView Data Fetch', () => {
|
|
|
40
40
|
it('shows data limit warning when items reach the page size', async () => {
|
|
41
41
|
// Generate exactly 100 items (default page size)
|
|
42
42
|
const items = Array.from({ length: 100 }, (_, i) => ({
|
|
43
|
-
|
|
43
|
+
id: String(i),
|
|
44
44
|
name: `Item ${i}`,
|
|
45
45
|
}));
|
|
46
46
|
mockDataSource.find.mockResolvedValue(items);
|
|
@@ -62,8 +62,8 @@ describe('ListView Data Fetch', () => {
|
|
|
62
62
|
|
|
63
63
|
it('does not show data limit warning when items are below page size', async () => {
|
|
64
64
|
const items = [
|
|
65
|
-
{
|
|
66
|
-
{
|
|
65
|
+
{ id: '1', name: 'Alice' },
|
|
66
|
+
{ id: '2', name: 'Bob' },
|
|
67
67
|
];
|
|
68
68
|
mockDataSource.find.mockResolvedValue(items);
|
|
69
69
|
|
|
@@ -84,7 +84,7 @@ describe('ListView Data Fetch', () => {
|
|
|
84
84
|
|
|
85
85
|
it('uses custom page size from schema.pagination', async () => {
|
|
86
86
|
const items = Array.from({ length: 50 }, (_, i) => ({
|
|
87
|
-
|
|
87
|
+
id: String(i),
|
|
88
88
|
name: `Item ${i}`,
|
|
89
89
|
}));
|
|
90
90
|
mockDataSource.find.mockResolvedValue(items);
|
|
@@ -113,6 +113,35 @@ describe('ListView Data Fetch', () => {
|
|
|
113
113
|
});
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
+
// =========================================================================
|
|
117
|
+
// OData { value: [] } response format handling
|
|
118
|
+
// =========================================================================
|
|
119
|
+
describe('OData value response format', () => {
|
|
120
|
+
it('should extract records from { value: [] } OData response', async () => {
|
|
121
|
+
const items = [
|
|
122
|
+
{ id: '1', name: 'Alice' },
|
|
123
|
+
{ id: '2', name: 'Bob' },
|
|
124
|
+
];
|
|
125
|
+
mockDataSource.find.mockResolvedValue({ value: items, '@odata.count': 2 });
|
|
126
|
+
|
|
127
|
+
const schema: ListViewSchema = {
|
|
128
|
+
type: 'list-view',
|
|
129
|
+
objectName: 'contacts',
|
|
130
|
+
viewType: 'grid',
|
|
131
|
+
fields: ['name'],
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
renderWithProvider(<ListView schema={schema} dataSource={mockDataSource} />);
|
|
135
|
+
|
|
136
|
+
await vi.waitFor(() => {
|
|
137
|
+
expect(screen.getByTestId('record-count-bar')).toBeInTheDocument();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Records should be extracted and rendered (not empty)
|
|
141
|
+
expect(screen.queryByTestId('empty-state')).not.toBeInTheDocument();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
116
145
|
// =========================================================================
|
|
117
146
|
// $expand race condition fix (Issue #939 Bug 1)
|
|
118
147
|
// =========================================================================
|
|
@@ -126,7 +155,7 @@ describe('ListView Data Fetch', () => {
|
|
|
126
155
|
},
|
|
127
156
|
});
|
|
128
157
|
mockDataSource.find.mockResolvedValue([
|
|
129
|
-
{
|
|
158
|
+
{ id: '1', name: 'Order 1', customer: { name: 'Alice' }, account: { name: 'Acme' } },
|
|
130
159
|
]);
|
|
131
160
|
|
|
132
161
|
const schema: ListViewSchema = {
|
|
@@ -152,7 +181,7 @@ describe('ListView Data Fetch', () => {
|
|
|
152
181
|
let resolveSchema: (value: any) => void;
|
|
153
182
|
const schemaPromise = new Promise(resolve => { resolveSchema = resolve; });
|
|
154
183
|
mockDataSource.getObjectSchema = vi.fn().mockReturnValue(schemaPromise);
|
|
155
|
-
mockDataSource.find.mockResolvedValue([{
|
|
184
|
+
mockDataSource.find.mockResolvedValue([{ id: '1', name: 'Item 1' }]);
|
|
156
185
|
|
|
157
186
|
const schema: ListViewSchema = {
|
|
158
187
|
type: 'list-view',
|
|
@@ -203,14 +232,14 @@ describe('ListView Data Fetch', () => {
|
|
|
203
232
|
);
|
|
204
233
|
|
|
205
234
|
// Resolve second (newer) request first
|
|
206
|
-
resolveSecond!([{
|
|
235
|
+
resolveSecond!([{ id: '2', name: 'Second' }]);
|
|
207
236
|
|
|
208
237
|
await vi.waitFor(() => {
|
|
209
238
|
expect(mockDataSource.find).toHaveBeenCalled();
|
|
210
239
|
});
|
|
211
240
|
|
|
212
241
|
// Resolve first (stale) request later
|
|
213
|
-
resolveFirst!([{
|
|
242
|
+
resolveFirst!([{ id: '1', name: 'First (stale)' }]);
|
|
214
243
|
|
|
215
244
|
// Wait for state to settle — second request data should win
|
|
216
245
|
await vi.waitFor(() => {
|
|
@@ -76,8 +76,8 @@ describe('ListView Export', () => {
|
|
|
76
76
|
|
|
77
77
|
it('should handle export with complex object fields in CSV safely', async () => {
|
|
78
78
|
const mockItems = [
|
|
79
|
-
{
|
|
80
|
-
{
|
|
79
|
+
{ id: '1', name: 'Alice', tags: ['admin', 'user'], metadata: { role: 'lead' } },
|
|
80
|
+
{ id: '2', name: 'Bob', tags: ['user'], metadata: null },
|
|
81
81
|
];
|
|
82
82
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
83
83
|
|
|
@@ -134,7 +134,7 @@ describe('ListView Export', () => {
|
|
|
134
134
|
|
|
135
135
|
it('should handle export with JSON format', async () => {
|
|
136
136
|
const mockItems = [
|
|
137
|
-
{
|
|
137
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
138
138
|
];
|
|
139
139
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
140
140
|
|
|
@@ -430,9 +430,9 @@ describe('ListView', () => {
|
|
|
430
430
|
|
|
431
431
|
it('should show record count bar when data is loaded', async () => {
|
|
432
432
|
const mockItems = [
|
|
433
|
-
{
|
|
434
|
-
{
|
|
435
|
-
{
|
|
433
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
434
|
+
{ id: '2', name: 'Bob', email: 'bob@test.com' },
|
|
435
|
+
{ id: '3', name: 'Charlie', email: 'charlie@test.com' },
|
|
436
436
|
];
|
|
437
437
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
438
438
|
|
|
@@ -930,8 +930,8 @@ describe('ListView', () => {
|
|
|
930
930
|
describe('showRecordCount flag', () => {
|
|
931
931
|
it('should hide record count bar when showRecordCount is false', async () => {
|
|
932
932
|
const mockItems = [
|
|
933
|
-
{
|
|
934
|
-
{
|
|
933
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
934
|
+
{ id: '2', name: 'Bob', email: 'bob@test.com' },
|
|
935
935
|
];
|
|
936
936
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
937
937
|
|
|
@@ -957,7 +957,7 @@ describe('ListView', () => {
|
|
|
957
957
|
|
|
958
958
|
it('should show record count bar by default (showRecordCount undefined)', async () => {
|
|
959
959
|
const mockItems = [
|
|
960
|
-
{
|
|
960
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
961
961
|
];
|
|
962
962
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
963
963
|
|
|
@@ -1453,7 +1453,7 @@ describe('ListView', () => {
|
|
|
1453
1453
|
describe('pageSizeOptions', () => {
|
|
1454
1454
|
it('should render page size selector when pageSizeOptions is provided', async () => {
|
|
1455
1455
|
const mockItems = [
|
|
1456
|
-
{
|
|
1456
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1457
1457
|
];
|
|
1458
1458
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
1459
1459
|
|
|
@@ -1474,7 +1474,7 @@ describe('ListView', () => {
|
|
|
1474
1474
|
|
|
1475
1475
|
it('should not render page size selector when pageSizeOptions is not provided', async () => {
|
|
1476
1476
|
const mockItems = [
|
|
1477
|
-
{
|
|
1477
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1478
1478
|
];
|
|
1479
1479
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
1480
1480
|
|
|
@@ -1539,8 +1539,8 @@ describe('ListView', () => {
|
|
|
1539
1539
|
data: {
|
|
1540
1540
|
provider: 'value',
|
|
1541
1541
|
items: [
|
|
1542
|
-
{
|
|
1543
|
-
{
|
|
1542
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1543
|
+
{ id: '2', name: 'Bob', email: 'bob@test.com' },
|
|
1544
1544
|
],
|
|
1545
1545
|
} as any,
|
|
1546
1546
|
};
|
|
@@ -1562,8 +1562,8 @@ describe('ListView', () => {
|
|
|
1562
1562
|
viewType: 'grid',
|
|
1563
1563
|
fields: ['name', 'email'],
|
|
1564
1564
|
data: [
|
|
1565
|
-
{
|
|
1566
|
-
{
|
|
1565
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1566
|
+
{ id: '2', name: 'Bob', email: 'bob@test.com' },
|
|
1567
1567
|
] as any,
|
|
1568
1568
|
};
|
|
1569
1569
|
|
|
@@ -1584,9 +1584,9 @@ describe('ListView', () => {
|
|
|
1584
1584
|
viewType: 'grid',
|
|
1585
1585
|
fields: ['name', 'email'],
|
|
1586
1586
|
data: [
|
|
1587
|
-
{
|
|
1588
|
-
{
|
|
1589
|
-
{
|
|
1587
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1588
|
+
{ id: '2', name: 'Bob', email: 'bob@test.com' },
|
|
1589
|
+
{ id: '3', name: 'Charlie', email: 'charlie@test.com' },
|
|
1590
1590
|
] as any,
|
|
1591
1591
|
};
|
|
1592
1592
|
|
|
@@ -1616,8 +1616,8 @@ describe('ListView', () => {
|
|
|
1616
1616
|
data: {
|
|
1617
1617
|
provider: 'value',
|
|
1618
1618
|
items: [
|
|
1619
|
-
{
|
|
1620
|
-
{
|
|
1619
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1620
|
+
{ id: '2', name: 'Bob', email: 'bob@test.com' },
|
|
1621
1621
|
],
|
|
1622
1622
|
} as any,
|
|
1623
1623
|
};
|
|
@@ -1641,7 +1641,7 @@ describe('ListView', () => {
|
|
|
1641
1641
|
|
|
1642
1642
|
it('should fall back to dataSource.find when schema.data is not set', async () => {
|
|
1643
1643
|
const mockItems = [
|
|
1644
|
-
{
|
|
1644
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1645
1645
|
];
|
|
1646
1646
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
1647
1647
|
|
|
@@ -1947,8 +1947,8 @@ describe('ListView', () => {
|
|
|
1947
1947
|
describe('pageSizeOptions dynamic integration', () => {
|
|
1948
1948
|
it('should render page size selector as controlled component', async () => {
|
|
1949
1949
|
const mockItems = [
|
|
1950
|
-
{
|
|
1951
|
-
{
|
|
1950
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1951
|
+
{ id: '2', name: 'Bob', email: 'bob@test.com' },
|
|
1952
1952
|
];
|
|
1953
1953
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
1954
1954
|
|
|
@@ -1972,8 +1972,8 @@ describe('ListView', () => {
|
|
|
1972
1972
|
|
|
1973
1973
|
it('should re-fetch data when page size changes', async () => {
|
|
1974
1974
|
const mockItems = [
|
|
1975
|
-
{
|
|
1976
|
-
{
|
|
1975
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
1976
|
+
{ id: '2', name: 'Bob', email: 'bob@test.com' },
|
|
1977
1977
|
];
|
|
1978
1978
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
1979
1979
|
|
|
@@ -2008,7 +2008,7 @@ describe('ListView', () => {
|
|
|
2008
2008
|
|
|
2009
2009
|
it('should render all page size options in the selector', async () => {
|
|
2010
2010
|
const mockItems = [
|
|
2011
|
-
{
|
|
2011
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
2012
2012
|
];
|
|
2013
2013
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
2014
2014
|
|
|
@@ -2036,7 +2036,7 @@ describe('ListView', () => {
|
|
|
2036
2036
|
|
|
2037
2037
|
it('should not render page size selector when pageSizeOptions is not configured', async () => {
|
|
2038
2038
|
const mockItems = [
|
|
2039
|
-
{
|
|
2039
|
+
{ id: '1', name: 'Alice', email: 'alice@test.com' },
|
|
2040
2040
|
];
|
|
2041
2041
|
mockDataSource.find.mockResolvedValue(mockItems);
|
|
2042
2042
|
|