Skip to content

Commit 1351ffa

Browse files
authored
Merge pull request #983 from objectstack-ai/copilot/fix-search-box-popover-layout
2 parents c0976a4 + bb8a035 commit 1351ffa

2 files changed

Lines changed: 83 additions & 3 deletions

File tree

packages/plugin-list/src/ListView.tsx

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -557,15 +557,33 @@ export const ListView: React.FC<ListViewProps> = ({
557557
if (schema.data && typeof schema.data === 'object' && !Array.isArray(schema.data)) {
558558
const dataConfig = schema.data as any;
559559
if (dataConfig.provider === 'value' && Array.isArray(dataConfig.items)) {
560-
setData(dataConfig.items);
560+
let items = dataConfig.items;
561+
if (searchTerm) {
562+
const q = searchTerm.toLowerCase();
563+
items = items.filter((row: any) =>
564+
Object.values(row).some(
565+
(v) => v != null && String(v).toLowerCase().includes(q),
566+
),
567+
);
568+
}
569+
setData(items);
561570
setLoading(false);
562571
setDataLimitReached(false);
563572
return;
564573
}
565574
}
566575
// Also support schema.data as a plain array (shorthand for value provider)
567576
if (Array.isArray(schema.data)) {
568-
setData(schema.data as any[]);
577+
let items = schema.data as any[];
578+
if (searchTerm) {
579+
const q = searchTerm.toLowerCase();
580+
items = items.filter((row: any) =>
581+
Object.values(row).some(
582+
(v) => v != null && String(v).toLowerCase().includes(q),
583+
),
584+
);
585+
}
586+
setData(items);
569587
setLoading(false);
570588
setDataLimitReached(false);
571589
return;
@@ -1455,7 +1473,7 @@ export const ListView: React.FC<ListViewProps> = ({
14551473
<Search className="h-3.5 w-3.5" />
14561474
</Button>
14571475
</PopoverTrigger>
1458-
<PopoverContent align="end" className="w-64 p-2" data-testid="search-popover">
1476+
<PopoverContent align="end" className="w-[calc(100vw-2rem)] sm:w-64 p-2" data-testid="search-popover">
14591477
<div className="relative">
14601478
<Search className="absolute left-2 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground" />
14611479
<Input

packages/plugin-list/src/__tests__/ListView.test.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,68 @@ describe('ListView', () => {
15771577
expect(mockDataSource.find).not.toHaveBeenCalled();
15781578
});
15791579

1580+
it('should filter inline array data by searchTerm', async () => {
1581+
const schema: ListViewSchema = {
1582+
type: 'list-view',
1583+
objectName: 'contacts',
1584+
viewType: 'grid',
1585+
fields: ['name', 'email'],
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' },
1590+
] as any,
1591+
};
1592+
1593+
mockDataSource.find.mockClear();
1594+
renderWithProvider(<ListView schema={schema} dataSource={mockDataSource} />);
1595+
1596+
await vi.waitFor(() => {
1597+
expect(screen.getByText('3 records')).toBeInTheDocument();
1598+
});
1599+
1600+
// Open search popover and type search query
1601+
fireEvent.click(screen.getByTestId('search-icon-button'));
1602+
fireEvent.change(screen.getByPlaceholderText(/search/i), { target: { value: 'alice' } });
1603+
1604+
await vi.waitFor(() => {
1605+
expect(screen.getByText('1 record')).toBeInTheDocument();
1606+
});
1607+
expect(mockDataSource.find).not.toHaveBeenCalled();
1608+
});
1609+
1610+
it('should filter value provider data by searchTerm', async () => {
1611+
const schema: ListViewSchema = {
1612+
type: 'list-view',
1613+
objectName: 'contacts',
1614+
viewType: 'grid',
1615+
fields: ['name', 'email'],
1616+
data: {
1617+
provider: 'value',
1618+
items: [
1619+
{ _id: '1', name: 'Alice', email: 'alice@test.com' },
1620+
{ _id: '2', name: 'Bob', email: 'bob@test.com' },
1621+
],
1622+
} as any,
1623+
};
1624+
1625+
mockDataSource.find.mockClear();
1626+
renderWithProvider(<ListView schema={schema} dataSource={mockDataSource} />);
1627+
1628+
await vi.waitFor(() => {
1629+
expect(screen.getByText('2 records')).toBeInTheDocument();
1630+
});
1631+
1632+
// Open search popover and type search query
1633+
fireEvent.click(screen.getByTestId('search-icon-button'));
1634+
fireEvent.change(screen.getByPlaceholderText(/search/i), { target: { value: 'bob' } });
1635+
1636+
await vi.waitFor(() => {
1637+
expect(screen.getByText('1 record')).toBeInTheDocument();
1638+
});
1639+
expect(mockDataSource.find).not.toHaveBeenCalled();
1640+
});
1641+
15801642
it('should fall back to dataSource.find when schema.data is not set', async () => {
15811643
const mockItems = [
15821644
{ _id: '1', name: 'Alice', email: 'alice@test.com' },

0 commit comments

Comments
 (0)