@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-list",
3
- "version": "3.1.2",
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.576.0",
28
- "@object-ui/components": "3.1.2",
29
- "@object-ui/core": "3.1.2",
30
- "@object-ui/i18n": "3.1.2",
31
- "@object-ui/mobile": "3.1.2",
32
- "@object-ui/react": "3.1.2",
33
- "@object-ui/types": "3.1.2"
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": "^5.1.4",
42
+ "@vitejs/plugin-react": "^6.0.1",
43
43
  "typescript": "^5.9.3",
44
- "vite": "^7.3.1",
44
+ "vite": "^8.0.1",
45
45
  "vite-plugin-dts": "^4.5.4",
46
- "vitest": "^4.0.18"
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
 
@@ -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._id ?? item.id ?? i) as string | number;
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
- _id: String(i),
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
- { _id: '1', name: 'Alice' },
66
- { _id: '2', name: 'Bob' },
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
- _id: String(i),
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
- { _id: '1', name: 'Order 1', customer: { name: 'Alice' }, account: { name: 'Acme' } },
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([{ _id: '1', name: 'Item 1' }]);
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!([{ _id: '2', name: 'Second' }]);
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!([{ _id: '1', name: 'First (stale)' }]);
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
- { _id: '1', name: 'Alice', tags: ['admin', 'user'], metadata: { role: 'lead' } },
80
- { _id: '2', name: 'Bob', tags: ['user'], metadata: null },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
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
- { _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' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
934
- { _id: '2', name: 'Bob', email: 'bob@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
1543
- { _id: '2', name: 'Bob', email: 'bob@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
1566
- { _id: '2', name: 'Bob', email: 'bob@test.com' },
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
- { _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' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
1620
- { _id: '2', name: 'Bob', email: 'bob@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
1951
- { _id: '2', name: 'Bob', email: 'bob@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
1976
- { _id: '2', name: 'Bob', email: 'bob@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
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
- { _id: '1', name: 'Alice', email: 'alice@test.com' },
2039
+ { id: '1', name: 'Alice', email: 'alice@test.com' },
2040
2040
  ];
2041
2041
  mockDataSource.find.mockResolvedValue(mockItems);
2042
2042