@object-ui/plugin-view 3.3.0 → 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.
- package/CHANGELOG.md +12 -0
- package/README.md +21 -1
- package/dist/index.js +2679 -2936
- package/dist/index.umd.cjs +1 -5
- package/dist/packages/plugin-view/src/config/view-config-schema.d.ts +20 -0
- package/dist/packages/plugin-view/src/config/view-config-utils.d.ts +58 -0
- package/dist/packages/plugin-view/src/index.d.ts +4 -0
- package/package.json +41 -9
- package/.turbo/turbo-build.log +0 -39
- package/src/FilterUI.tsx +0 -350
- package/src/ObjectView.tsx +0 -1133
- package/src/SharedViewLink.tsx +0 -199
- package/src/SortUI.tsx +0 -210
- package/src/ViewSwitcher.tsx +0 -379
- package/src/ViewTabBar.tsx +0 -656
- package/src/__tests__/FilterUI.test.tsx +0 -641
- package/src/__tests__/ObjectView.test.tsx +0 -705
- package/src/__tests__/SharedViewLinkPassword.test.tsx +0 -172
- package/src/__tests__/SortUI.test.tsx +0 -380
- package/src/__tests__/ViewTabBar.test.tsx +0 -710
- package/src/__tests__/config-sync-integration.test.tsx +0 -588
- package/src/__tests__/toolbar-consistency.test.tsx +0 -755
- package/src/index.tsx +0 -197
- package/tsconfig.json +0 -8
- package/vite.config.ts +0 -48
- package/vitest.config.ts +0 -12
- package/vitest.setup.ts +0 -1
|
@@ -1,588 +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
|
-
* Config Sync Integration Tests (Phase 7 — P1.8.1)
|
|
11
|
-
*
|
|
12
|
-
* Per-view-type tests verifying that ViewConfigPanel config properties
|
|
13
|
-
* propagate through PluginObjectView's renderListView to each view type.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
17
|
-
import { render, screen } from '@testing-library/react';
|
|
18
|
-
import { ObjectView } from '../ObjectView';
|
|
19
|
-
import type { ObjectViewSchema, DataSource } from '@object-ui/types';
|
|
20
|
-
|
|
21
|
-
// Mock @object-ui/react to avoid circular dependency issues
|
|
22
|
-
vi.mock('@object-ui/react', () => ({
|
|
23
|
-
SchemaRenderer: ({ schema }: any) => (
|
|
24
|
-
<div data-testid="schema-renderer" data-schema-type={schema?.type}>
|
|
25
|
-
{schema?.type}
|
|
26
|
-
</div>
|
|
27
|
-
),
|
|
28
|
-
SchemaRendererContext: null,
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
// Mock @object-ui/plugin-grid
|
|
32
|
-
vi.mock('@object-ui/plugin-grid', () => ({
|
|
33
|
-
ObjectGrid: ({ schema, onRowClick }: any) => (
|
|
34
|
-
<div data-testid="object-grid" data-object={schema?.objectName}>
|
|
35
|
-
<button data-testid="grid-row" onClick={() => onRowClick?.({ id: '1', name: 'Test' })}>
|
|
36
|
-
Row 1
|
|
37
|
-
</button>
|
|
38
|
-
</div>
|
|
39
|
-
),
|
|
40
|
-
}));
|
|
41
|
-
|
|
42
|
-
// Mock @object-ui/plugin-form
|
|
43
|
-
vi.mock('@object-ui/plugin-form', () => ({
|
|
44
|
-
ObjectForm: ({ schema }: any) => (
|
|
45
|
-
<div data-testid="object-form" data-mode={schema?.mode}>
|
|
46
|
-
Form ({schema?.mode})
|
|
47
|
-
</div>
|
|
48
|
-
),
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
const createMockDataSource = (): DataSource => ({
|
|
52
|
-
find: vi.fn().mockResolvedValue([]),
|
|
53
|
-
findOne: vi.fn().mockResolvedValue(null),
|
|
54
|
-
create: vi.fn().mockResolvedValue({}),
|
|
55
|
-
update: vi.fn().mockResolvedValue({}),
|
|
56
|
-
delete: vi.fn().mockResolvedValue({}),
|
|
57
|
-
getObjectSchema: vi.fn().mockResolvedValue({
|
|
58
|
-
label: 'Contacts',
|
|
59
|
-
fields: {
|
|
60
|
-
name: { label: 'Name', type: 'text' },
|
|
61
|
-
email: { label: 'Email', type: 'text' },
|
|
62
|
-
status: {
|
|
63
|
-
label: 'Status',
|
|
64
|
-
type: 'select',
|
|
65
|
-
options: [
|
|
66
|
-
{ label: 'Active', value: 'active' },
|
|
67
|
-
{ label: 'Inactive', value: 'inactive' },
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
created_at: { label: 'Created', type: 'date' },
|
|
71
|
-
},
|
|
72
|
-
}),
|
|
73
|
-
} as DataSource);
|
|
74
|
-
|
|
75
|
-
describe('Config Sync Integration — Per View Type', () => {
|
|
76
|
-
let mockDataSource: DataSource;
|
|
77
|
-
|
|
78
|
-
beforeEach(() => {
|
|
79
|
-
vi.clearAllMocks();
|
|
80
|
-
mockDataSource = createMockDataSource();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// ── Grid Config Sync ──
|
|
84
|
-
|
|
85
|
-
it('Grid: propagates showSort, showSearch, showFilters, striped, bordered via renderListView', () => {
|
|
86
|
-
const schema: ObjectViewSchema = {
|
|
87
|
-
type: 'object-view',
|
|
88
|
-
objectName: 'contacts',
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
92
|
-
<div data-testid="custom-list">Grid</div>
|
|
93
|
-
));
|
|
94
|
-
|
|
95
|
-
const views = [
|
|
96
|
-
{
|
|
97
|
-
id: 'v1',
|
|
98
|
-
label: 'Grid View',
|
|
99
|
-
type: 'grid' as const,
|
|
100
|
-
showSort: false,
|
|
101
|
-
showSearch: true,
|
|
102
|
-
showFilters: false,
|
|
103
|
-
striped: true,
|
|
104
|
-
bordered: true,
|
|
105
|
-
},
|
|
106
|
-
];
|
|
107
|
-
|
|
108
|
-
render(
|
|
109
|
-
<ObjectView
|
|
110
|
-
schema={schema}
|
|
111
|
-
dataSource={mockDataSource}
|
|
112
|
-
views={views}
|
|
113
|
-
activeViewId="v1"
|
|
114
|
-
renderListView={renderListViewSpy}
|
|
115
|
-
/>,
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
119
|
-
const callSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
120
|
-
expect(callSchema?.showSort).toBe(false);
|
|
121
|
-
expect(callSchema?.showSearch).toBe(true);
|
|
122
|
-
expect(callSchema?.showFilters).toBe(false);
|
|
123
|
-
expect(callSchema?.striped).toBe(true);
|
|
124
|
-
expect(callSchema?.bordered).toBe(true);
|
|
125
|
-
expect(callSchema?.viewType).toBe('grid');
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// ── Kanban Config Sync ──
|
|
129
|
-
|
|
130
|
-
it('Kanban: propagates groupBy, color, showSearch via renderListView', () => {
|
|
131
|
-
const schema: ObjectViewSchema = {
|
|
132
|
-
type: 'object-view',
|
|
133
|
-
objectName: 'contacts',
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
137
|
-
<div data-testid="custom-list">Kanban</div>
|
|
138
|
-
));
|
|
139
|
-
|
|
140
|
-
const views = [
|
|
141
|
-
{
|
|
142
|
-
id: 'v2',
|
|
143
|
-
label: 'Kanban View',
|
|
144
|
-
type: 'kanban' as const,
|
|
145
|
-
showSearch: false,
|
|
146
|
-
color: 'blue',
|
|
147
|
-
groupBy: 'status',
|
|
148
|
-
},
|
|
149
|
-
];
|
|
150
|
-
|
|
151
|
-
render(
|
|
152
|
-
<ObjectView
|
|
153
|
-
schema={schema}
|
|
154
|
-
dataSource={mockDataSource}
|
|
155
|
-
views={views}
|
|
156
|
-
activeViewId="v2"
|
|
157
|
-
renderListView={renderListViewSpy}
|
|
158
|
-
/>,
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
162
|
-
const callSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
163
|
-
expect(callSchema?.showSearch).toBe(false);
|
|
164
|
-
expect(callSchema?.color).toBe('blue');
|
|
165
|
-
expect(callSchema?.viewType).toBe('kanban');
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// ── Calendar Config Sync ──
|
|
169
|
-
|
|
170
|
-
it('Calendar: propagates startDateField, endDateField, showFilters via renderListView', () => {
|
|
171
|
-
const schema: ObjectViewSchema = {
|
|
172
|
-
type: 'object-view',
|
|
173
|
-
objectName: 'contacts',
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
177
|
-
<div data-testid="custom-list">Calendar</div>
|
|
178
|
-
));
|
|
179
|
-
|
|
180
|
-
const views = [
|
|
181
|
-
{
|
|
182
|
-
id: 'v3',
|
|
183
|
-
label: 'Calendar View',
|
|
184
|
-
type: 'calendar' as const,
|
|
185
|
-
showFilters: false,
|
|
186
|
-
showSearch: true,
|
|
187
|
-
},
|
|
188
|
-
];
|
|
189
|
-
|
|
190
|
-
render(
|
|
191
|
-
<ObjectView
|
|
192
|
-
schema={schema}
|
|
193
|
-
dataSource={mockDataSource}
|
|
194
|
-
views={views}
|
|
195
|
-
activeViewId="v3"
|
|
196
|
-
renderListView={renderListViewSpy}
|
|
197
|
-
/>,
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
201
|
-
const callSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
202
|
-
expect(callSchema?.showFilters).toBe(false);
|
|
203
|
-
expect(callSchema?.showSearch).toBe(true);
|
|
204
|
-
expect(callSchema?.viewType).toBe('calendar');
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// ── Timeline/Gantt Config Sync ──
|
|
208
|
-
|
|
209
|
-
it('Timeline: propagates dateField, appearance properties via renderListView', () => {
|
|
210
|
-
const schema: ObjectViewSchema = {
|
|
211
|
-
type: 'object-view',
|
|
212
|
-
objectName: 'contacts',
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
216
|
-
<div data-testid="custom-list">Timeline</div>
|
|
217
|
-
));
|
|
218
|
-
|
|
219
|
-
const views = [
|
|
220
|
-
{
|
|
221
|
-
id: 'v4',
|
|
222
|
-
label: 'Timeline View',
|
|
223
|
-
type: 'timeline' as const,
|
|
224
|
-
striped: true,
|
|
225
|
-
color: 'green',
|
|
226
|
-
},
|
|
227
|
-
];
|
|
228
|
-
|
|
229
|
-
render(
|
|
230
|
-
<ObjectView
|
|
231
|
-
schema={schema}
|
|
232
|
-
dataSource={mockDataSource}
|
|
233
|
-
views={views}
|
|
234
|
-
activeViewId="v4"
|
|
235
|
-
renderListView={renderListViewSpy}
|
|
236
|
-
/>,
|
|
237
|
-
);
|
|
238
|
-
|
|
239
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
240
|
-
const callSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
241
|
-
expect(callSchema?.striped).toBe(true);
|
|
242
|
-
expect(callSchema?.color).toBe('green');
|
|
243
|
-
expect(callSchema?.viewType).toBe('timeline');
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it('Gantt: propagates appearance properties via renderListView', () => {
|
|
247
|
-
const schema: ObjectViewSchema = {
|
|
248
|
-
type: 'object-view',
|
|
249
|
-
objectName: 'contacts',
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
253
|
-
<div data-testid="custom-list">Gantt</div>
|
|
254
|
-
));
|
|
255
|
-
|
|
256
|
-
const views = [
|
|
257
|
-
{
|
|
258
|
-
id: 'v5',
|
|
259
|
-
label: 'Gantt View',
|
|
260
|
-
type: 'gantt' as const,
|
|
261
|
-
bordered: true,
|
|
262
|
-
showSort: true,
|
|
263
|
-
},
|
|
264
|
-
];
|
|
265
|
-
|
|
266
|
-
render(
|
|
267
|
-
<ObjectView
|
|
268
|
-
schema={schema}
|
|
269
|
-
dataSource={mockDataSource}
|
|
270
|
-
views={views}
|
|
271
|
-
activeViewId="v5"
|
|
272
|
-
renderListView={renderListViewSpy}
|
|
273
|
-
/>,
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
277
|
-
const callSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
278
|
-
expect(callSchema?.bordered).toBe(true);
|
|
279
|
-
expect(callSchema?.showSort).toBe(true);
|
|
280
|
-
expect(callSchema?.viewType).toBe('gantt');
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
// ── Gallery Config Sync ──
|
|
284
|
-
|
|
285
|
-
it('Gallery: propagates imageField, titleField, appearance via renderListView', () => {
|
|
286
|
-
const schema: ObjectViewSchema = {
|
|
287
|
-
type: 'object-view',
|
|
288
|
-
objectName: 'contacts',
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
292
|
-
<div data-testid="custom-list">Gallery</div>
|
|
293
|
-
));
|
|
294
|
-
|
|
295
|
-
const views = [
|
|
296
|
-
{
|
|
297
|
-
id: 'v6',
|
|
298
|
-
label: 'Gallery View',
|
|
299
|
-
type: 'gallery' as const,
|
|
300
|
-
striped: false,
|
|
301
|
-
bordered: true,
|
|
302
|
-
showSearch: true,
|
|
303
|
-
},
|
|
304
|
-
];
|
|
305
|
-
|
|
306
|
-
render(
|
|
307
|
-
<ObjectView
|
|
308
|
-
schema={schema}
|
|
309
|
-
dataSource={mockDataSource}
|
|
310
|
-
views={views}
|
|
311
|
-
activeViewId="v6"
|
|
312
|
-
renderListView={renderListViewSpy}
|
|
313
|
-
/>,
|
|
314
|
-
);
|
|
315
|
-
|
|
316
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
317
|
-
const callSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
318
|
-
expect(callSchema?.striped).toBe(false);
|
|
319
|
-
expect(callSchema?.bordered).toBe(true);
|
|
320
|
-
expect(callSchema?.showSearch).toBe(true);
|
|
321
|
-
expect(callSchema?.viewType).toBe('gallery');
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
// ── Map Config Sync ──
|
|
325
|
-
|
|
326
|
-
it('Map: propagates locationField, appearance via renderListView', () => {
|
|
327
|
-
const schema: ObjectViewSchema = {
|
|
328
|
-
type: 'object-view',
|
|
329
|
-
objectName: 'contacts',
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
333
|
-
<div data-testid="custom-list">Map</div>
|
|
334
|
-
));
|
|
335
|
-
|
|
336
|
-
const views = [
|
|
337
|
-
{
|
|
338
|
-
id: 'v7',
|
|
339
|
-
label: 'Map View',
|
|
340
|
-
type: 'map' as const,
|
|
341
|
-
showFilters: true,
|
|
342
|
-
color: 'red',
|
|
343
|
-
},
|
|
344
|
-
];
|
|
345
|
-
|
|
346
|
-
render(
|
|
347
|
-
<ObjectView
|
|
348
|
-
schema={schema}
|
|
349
|
-
dataSource={mockDataSource}
|
|
350
|
-
views={views}
|
|
351
|
-
activeViewId="v7"
|
|
352
|
-
renderListView={renderListViewSpy}
|
|
353
|
-
/>,
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
357
|
-
const callSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
358
|
-
expect(callSchema?.showFilters).toBe(true);
|
|
359
|
-
expect(callSchema?.color).toBe('red');
|
|
360
|
-
expect(callSchema?.viewType).toBe('map');
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
// ── Cross-view-type config transfer ──
|
|
364
|
-
|
|
365
|
-
it('Cross-view: config properties transfer correctly when view type changes', () => {
|
|
366
|
-
const schema: ObjectViewSchema = {
|
|
367
|
-
type: 'object-view',
|
|
368
|
-
objectName: 'contacts',
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
372
|
-
<div data-testid="custom-list">{listSchema?.viewType}</div>
|
|
373
|
-
));
|
|
374
|
-
|
|
375
|
-
const gridViews = [
|
|
376
|
-
{
|
|
377
|
-
id: 'v1',
|
|
378
|
-
label: 'Grid View',
|
|
379
|
-
type: 'grid' as const,
|
|
380
|
-
showSearch: false,
|
|
381
|
-
showFilters: true,
|
|
382
|
-
striped: true,
|
|
383
|
-
},
|
|
384
|
-
];
|
|
385
|
-
|
|
386
|
-
const { rerender } = render(
|
|
387
|
-
<ObjectView
|
|
388
|
-
schema={schema}
|
|
389
|
-
dataSource={mockDataSource}
|
|
390
|
-
views={gridViews}
|
|
391
|
-
activeViewId="v1"
|
|
392
|
-
renderListView={renderListViewSpy}
|
|
393
|
-
/>,
|
|
394
|
-
);
|
|
395
|
-
|
|
396
|
-
// Verify grid config
|
|
397
|
-
const gridSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
398
|
-
expect(gridSchema?.viewType).toBe('grid');
|
|
399
|
-
expect(gridSchema?.showSearch).toBe(false);
|
|
400
|
-
expect(gridSchema?.striped).toBe(true);
|
|
401
|
-
|
|
402
|
-
// Switch to kanban with different config
|
|
403
|
-
const kanbanViews = [
|
|
404
|
-
{
|
|
405
|
-
id: 'v1',
|
|
406
|
-
label: 'Kanban View',
|
|
407
|
-
type: 'kanban' as const,
|
|
408
|
-
showSearch: true,
|
|
409
|
-
showFilters: false,
|
|
410
|
-
striped: false,
|
|
411
|
-
},
|
|
412
|
-
];
|
|
413
|
-
|
|
414
|
-
rerender(
|
|
415
|
-
<ObjectView
|
|
416
|
-
schema={schema}
|
|
417
|
-
dataSource={mockDataSource}
|
|
418
|
-
views={kanbanViews}
|
|
419
|
-
activeViewId="v1"
|
|
420
|
-
renderListView={renderListViewSpy}
|
|
421
|
-
/>,
|
|
422
|
-
);
|
|
423
|
-
|
|
424
|
-
const lastCallIndex = renderListViewSpy.mock.calls.length - 1;
|
|
425
|
-
const kanbanSchema = renderListViewSpy.mock.calls[lastCallIndex]?.[0]?.schema;
|
|
426
|
-
expect(kanbanSchema?.viewType).toBe('kanban');
|
|
427
|
-
expect(kanbanSchema?.showSearch).toBe(true);
|
|
428
|
-
expect(kanbanSchema?.showFilters).toBe(false);
|
|
429
|
-
expect(kanbanSchema?.striped).toBe(false);
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
// ── Extended property propagation ──
|
|
433
|
-
|
|
434
|
-
it('propagates all P0/P1/P2 spec properties via renderListView for grid view', () => {
|
|
435
|
-
const schema: ObjectViewSchema = {
|
|
436
|
-
type: 'object-view',
|
|
437
|
-
objectName: 'contacts',
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
441
|
-
<div data-testid="custom-list">Grid</div>
|
|
442
|
-
));
|
|
443
|
-
|
|
444
|
-
const views = [
|
|
445
|
-
{
|
|
446
|
-
id: 'v1',
|
|
447
|
-
label: 'Full Config View',
|
|
448
|
-
type: 'grid' as const,
|
|
449
|
-
// Toolbar toggles
|
|
450
|
-
showSearch: true,
|
|
451
|
-
showFilters: false,
|
|
452
|
-
showSort: true,
|
|
453
|
-
showHideFields: false,
|
|
454
|
-
showGroup: true,
|
|
455
|
-
showColor: false,
|
|
456
|
-
showDensity: true,
|
|
457
|
-
allowExport: true,
|
|
458
|
-
// Display properties
|
|
459
|
-
striped: true,
|
|
460
|
-
bordered: false,
|
|
461
|
-
color: 'blue',
|
|
462
|
-
// View config properties
|
|
463
|
-
inlineEdit: true,
|
|
464
|
-
wrapHeaders: true,
|
|
465
|
-
clickIntoRecordDetails: false,
|
|
466
|
-
addRecordViaForm: true,
|
|
467
|
-
addDeleteRecordsInline: false,
|
|
468
|
-
collapseAllByDefault: true,
|
|
469
|
-
fieldTextColor: 'red',
|
|
470
|
-
prefixField: 'name',
|
|
471
|
-
showDescription: true,
|
|
472
|
-
// P0/P1/P2 new spec properties
|
|
473
|
-
navigation: { mode: 'drawer' },
|
|
474
|
-
selection: { type: 'multi' },
|
|
475
|
-
pagination: { pageSize: 25 },
|
|
476
|
-
searchableFields: ['name', 'email'],
|
|
477
|
-
filterableFields: ['status'],
|
|
478
|
-
resizable: true,
|
|
479
|
-
hiddenFields: ['created_at'],
|
|
480
|
-
rowActions: ['edit', 'delete'],
|
|
481
|
-
bulkActions: ['export'],
|
|
482
|
-
sharing: { enabled: true, visibility: 'team' },
|
|
483
|
-
addRecord: { enabled: true },
|
|
484
|
-
conditionalFormatting: [{ field: 'status', operator: 'equals', value: 'active' }],
|
|
485
|
-
quickFilters: [{ label: 'Active', filters: [], defaultActive: true }],
|
|
486
|
-
showRecordCount: true,
|
|
487
|
-
allowPrinting: true,
|
|
488
|
-
virtualScroll: true,
|
|
489
|
-
emptyState: { title: 'No data', message: 'Add records', icon: 'inbox' },
|
|
490
|
-
aria: { label: 'Contacts', describedBy: 'desc', live: 'polite' },
|
|
491
|
-
},
|
|
492
|
-
];
|
|
493
|
-
|
|
494
|
-
render(
|
|
495
|
-
<ObjectView
|
|
496
|
-
schema={schema}
|
|
497
|
-
dataSource={mockDataSource}
|
|
498
|
-
views={views}
|
|
499
|
-
activeViewId="v1"
|
|
500
|
-
renderListView={renderListViewSpy}
|
|
501
|
-
/>,
|
|
502
|
-
);
|
|
503
|
-
|
|
504
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
505
|
-
const s = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
506
|
-
|
|
507
|
-
// Toolbar toggles
|
|
508
|
-
expect(s?.showSearch).toBe(true);
|
|
509
|
-
expect(s?.showFilters).toBe(false);
|
|
510
|
-
expect(s?.showSort).toBe(true);
|
|
511
|
-
expect(s?.showHideFields).toBe(false);
|
|
512
|
-
expect(s?.showGroup).toBe(true);
|
|
513
|
-
expect(s?.showColor).toBe(false);
|
|
514
|
-
expect(s?.showDensity).toBe(true);
|
|
515
|
-
expect(s?.allowExport).toBe(true);
|
|
516
|
-
|
|
517
|
-
// Display properties
|
|
518
|
-
expect(s?.striped).toBe(true);
|
|
519
|
-
expect(s?.bordered).toBe(false);
|
|
520
|
-
expect(s?.color).toBe('blue');
|
|
521
|
-
|
|
522
|
-
// View config properties
|
|
523
|
-
expect(s?.inlineEdit).toBe(true);
|
|
524
|
-
expect(s?.wrapHeaders).toBe(true);
|
|
525
|
-
expect(s?.clickIntoRecordDetails).toBe(false);
|
|
526
|
-
expect(s?.addRecordViaForm).toBe(true);
|
|
527
|
-
expect(s?.addDeleteRecordsInline).toBe(false);
|
|
528
|
-
expect(s?.collapseAllByDefault).toBe(true);
|
|
529
|
-
expect(s?.fieldTextColor).toBe('red');
|
|
530
|
-
expect(s?.prefixField).toBe('name');
|
|
531
|
-
expect(s?.showDescription).toBe(true);
|
|
532
|
-
|
|
533
|
-
// P0/P1/P2 new spec properties
|
|
534
|
-
expect(s?.navigation).toEqual({ mode: 'drawer' });
|
|
535
|
-
expect(s?.selection).toEqual({ type: 'multi' });
|
|
536
|
-
expect(s?.pagination).toEqual({ pageSize: 25 });
|
|
537
|
-
expect(s?.searchableFields).toEqual(['name', 'email']);
|
|
538
|
-
expect(s?.filterableFields).toEqual(['status']);
|
|
539
|
-
expect(s?.resizable).toBe(true);
|
|
540
|
-
expect(s?.hiddenFields).toEqual(['created_at']);
|
|
541
|
-
expect(s?.rowActions).toEqual(['edit', 'delete']);
|
|
542
|
-
expect(s?.bulkActions).toEqual(['export']);
|
|
543
|
-
expect(s?.sharing).toEqual({ enabled: true, visibility: 'team' });
|
|
544
|
-
expect(s?.addRecord).toEqual({ enabled: true });
|
|
545
|
-
expect(s?.conditionalFormatting).toEqual([{ field: 'status', operator: 'equals', value: 'active' }]);
|
|
546
|
-
expect(s?.quickFilters).toEqual([{ label: 'Active', filters: [], defaultActive: true }]);
|
|
547
|
-
expect(s?.showRecordCount).toBe(true);
|
|
548
|
-
expect(s?.allowPrinting).toBe(true);
|
|
549
|
-
expect(s?.virtualScroll).toBe(true);
|
|
550
|
-
expect(s?.emptyState).toEqual({ title: 'No data', message: 'Add records', icon: 'inbox' });
|
|
551
|
-
expect(s?.aria).toEqual({ label: 'Contacts', describedBy: 'desc', live: 'polite' });
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
it('propagates schema-level tabs through renderListView', () => {
|
|
555
|
-
const tabsConfig = [
|
|
556
|
-
{ name: 'all', label: 'All Records', isDefault: true },
|
|
557
|
-
{ name: 'active', label: 'Active', icon: 'circle-check', filter: { logic: 'and', conditions: [{ field: 'status', operator: 'eq', value: 'active' }] } },
|
|
558
|
-
{ name: 'vip', label: 'VIP', pinned: true },
|
|
559
|
-
];
|
|
560
|
-
|
|
561
|
-
const schema: ObjectViewSchema = {
|
|
562
|
-
type: 'object-view',
|
|
563
|
-
objectName: 'contacts',
|
|
564
|
-
tabs: tabsConfig,
|
|
565
|
-
} as any;
|
|
566
|
-
|
|
567
|
-
const renderListViewSpy = vi.fn(({ schema: listSchema }: any) => (
|
|
568
|
-
<div data-testid="custom-list">Grid</div>
|
|
569
|
-
));
|
|
570
|
-
|
|
571
|
-
render(
|
|
572
|
-
<ObjectView
|
|
573
|
-
schema={schema}
|
|
574
|
-
dataSource={mockDataSource}
|
|
575
|
-
views={[{ id: 'v1', label: 'Grid View', type: 'grid' as const }]}
|
|
576
|
-
activeViewId="v1"
|
|
577
|
-
renderListView={renderListViewSpy}
|
|
578
|
-
/>,
|
|
579
|
-
);
|
|
580
|
-
|
|
581
|
-
expect(renderListViewSpy).toHaveBeenCalled();
|
|
582
|
-
const callSchema = renderListViewSpy.mock.calls[0]?.[0]?.schema;
|
|
583
|
-
expect(callSchema?.tabs).toEqual(tabsConfig);
|
|
584
|
-
expect(callSchema?.tabs).toHaveLength(3);
|
|
585
|
-
expect(callSchema?.tabs[0]?.isDefault).toBe(true);
|
|
586
|
-
expect(callSchema?.tabs[2]?.pinned).toBe(true);
|
|
587
|
-
});
|
|
588
|
-
});
|