From dd56a51b4c5de7a266d0233623c412c116b16817 Mon Sep 17 00:00:00 2001 From: Vivek Patil Date: Wed, 17 Sep 2025 14:41:31 +0530 Subject: [PATCH 1/6] Fixed the filtering issue --- .../src/containers/iModelGrid/IModelGrid.tsx | 12 +++++++++++- .../src/containers/iModelGrid/useIModelData.ts | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.tsx b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.tsx index 657c6951..b7832ad4 100644 --- a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.tsx +++ b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.tsx @@ -20,7 +20,7 @@ import { _mergeStrings } from "../../utils/_apiOverrides"; import { ContextMenuBuilderItem } from "../../utils/_buildMenuOptions"; import { IModelGhostTile } from "../iModelTiles/IModelGhostTile"; import { IModelTile, IModelTileProps } from "../iModelTiles/IModelTile"; -import { useIModelData } from "./useIModelData"; +import { DEFAULT_PAGE_SIZE, useIModelData } from "./useIModelData"; import { useIModelTableConfig } from "./useIModelTableConfig"; export interface IModelGridProps { /** @@ -173,6 +173,16 @@ export const IModelGrid = ({ [postProcessCallback, fetchediModels, fetchStatus, searchText] ); + React.useEffect(() => { + if ( + iModels.length < (pageSize ?? DEFAULT_PAGE_SIZE) && + fetchMore && + fetchStatus !== DataStatus.Fetching + ) { + fetchMore(); + } + }, [iModels.length, pageSize, fetchMore, fetchStatus]); + const { columns, onRowClick } = useIModelTableConfig({ iModelActions, onThumbnailClick, diff --git a/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.ts b/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.ts index d2610255..82cbc23d 100644 --- a/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.ts +++ b/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.ts @@ -25,7 +25,7 @@ export interface IModelDataHookOptions { /** @deprecated in 2.1 It is no longer used as it has no effect on the data fetching. */ viewMode?: ViewType; } -const DEFAULT_PAGE_SIZE = 100; +export const DEFAULT_PAGE_SIZE = 100; export const useIModelData = ({ iTwinId, From 97d90b1c9a8886961b8d105a0a3c9d3717637c67 Mon Sep 17 00:00:00 2001 From: Vivek Patil Date: Wed, 17 Sep 2025 14:47:17 +0530 Subject: [PATCH 2/6] added changelog --- .../vp-fix-filtering-issue_2025-09-17-09-16.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@itwin/imodel-browser-react/vp-fix-filtering-issue_2025-09-17-09-16.json diff --git a/common/changes/@itwin/imodel-browser-react/vp-fix-filtering-issue_2025-09-17-09-16.json b/common/changes/@itwin/imodel-browser-react/vp-fix-filtering-issue_2025-09-17-09-16.json new file mode 100644 index 00000000..c5be9596 --- /dev/null +++ b/common/changes/@itwin/imodel-browser-react/vp-fix-filtering-issue_2025-09-17-09-16.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/imodel-browser-react", + "comment": "Fix iModelGrid Filtering via postProcessCallback to Show Complete Results Across All Data", + "type": "patch" + } + ], + "packageName": "@itwin/imodel-browser-react" +} \ No newline at end of file From c5e67195f98e81c68391f2185fb1e78c0927be09 Mon Sep 17 00:00:00 2001 From: Vivek Patil Date: Thu, 18 Sep 2025 12:45:50 +0530 Subject: [PATCH 3/6] Added test --- .../containers/iModelGrid/IModelGrid.test.tsx | 123 +++++++++++++++++- 1 file changed, 121 insertions(+), 2 deletions(-) diff --git a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx index fb205f61..d9dd161d 100644 --- a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx +++ b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import "@testing-library/jest-dom"; -import { render } from "@testing-library/react"; +import { render, waitFor } from "@testing-library/react"; import React from "react"; -import { DataStatus, IModelCellOverrides, IModelGrid } from "../.."; +import { DataStatus, IModelCellOverrides, IModelFull, IModelGrid } from "../.."; import * as useIModelData from "./useIModelData"; describe("IModelGrid", () => { @@ -185,4 +185,123 @@ describe("IModelGrid", () => { menuItems = queryAllByRole("menuitem"); expect(menuItems.length).toBe(2); // Action 1 and Action 2 }); + + const generateMockIModels = (count: number, prefix = ""): IModelFull[] => { + return Array.from({ length: count }).map((_, index) => ({ + id: `${prefix}${index}`, + displayName: `${prefix}${index}`, + name: `${prefix}${index}`, + description: `${prefix}-description`, + })); + }; + + it("handles pagination correctly with postProcessCallback filtering", async () => { + const pageSize = 3; + const firstPageIModels = generateMockIModels(3, "iModel"); + firstPageIModels[1].description = "unmatched"; + firstPageIModels[2].description = "unmatched"; + + const secondPageIModels = generateMockIModels(3, "iModel"); + secondPageIModels[1].description = "unmatched"; + secondPageIModels[2].description = "unmatched"; + + const thirdPageIModels = generateMockIModels(3, "iModel"); + + const mockFetchMore = jest.fn(); + + const useIModelDataMock = jest.spyOn(useIModelData, "useIModelData"); + + useIModelDataMock.mockReturnValue({ + iModels: firstPageIModels, + status: DataStatus.Complete, + fetchMore: mockFetchMore, + refetchIModels: jest.fn(), + }); + + const postProcessCallback = jest + .fn() + .mockImplementation((iModels: IModelFull[]) => { + return iModels.filter( + (iModel) => iModel.description === "iModel-description" + ); + }); + + const { rerender } = render( + + ); + + await waitFor(() => { + expect(mockFetchMore).toHaveBeenCalled(); + }); + + useIModelDataMock.mockReturnValue({ + iModels: [...firstPageIModels, ...secondPageIModels], + status: DataStatus.Complete, + fetchMore: mockFetchMore, + refetchIModels: jest.fn(), + }); + + mockFetchMore.mockClear(); + + postProcessCallback.mockImplementation((iModels: IModelFull[]) => { + return iModels.filter((iModel) => { + if (iModel.description === "iModel-description") { + return true; + } + }); + }); + + rerender( + + ); + + expect(postProcessCallback).toHaveBeenCalledWith( + [...firstPageIModels, ...secondPageIModels], + DataStatus.Complete, + undefined + ); + + await waitFor(() => { + expect(mockFetchMore).toHaveBeenCalled(); + }); + + useIModelDataMock.mockReturnValue({ + iModels: [...firstPageIModels, ...secondPageIModels, ...thirdPageIModels], + status: DataStatus.Complete, + fetchMore: mockFetchMore, + refetchIModels: jest.fn(), + }); + + mockFetchMore.mockClear(); + + postProcessCallback.mockImplementation((iModels: IModelFull[]) => { + return iModels.filter( + (iModel) => iModel.description === "iModel-description" + ); + }); + + rerender( + + ); + + expect(postProcessCallback).toHaveBeenCalledWith( + [...firstPageIModels, ...secondPageIModels, ...thirdPageIModels], + DataStatus.Complete, + undefined + ); + + expect(mockFetchMore).not.toHaveBeenCalled(); + }); }); From 8077135d82705315ee59e88960ae06e5e498b92b Mon Sep 17 00:00:00 2001 From: Vivek Patil Date: Thu, 18 Sep 2025 13:42:32 +0530 Subject: [PATCH 4/6] Improved test name --- .../src/containers/iModelGrid/IModelGrid.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx index d9dd161d..2a545694 100644 --- a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx +++ b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx @@ -195,7 +195,7 @@ describe("IModelGrid", () => { })); }; - it("handles pagination correctly with postProcessCallback filtering", async () => { + it("should show all data with postProcessCallback filtering", async () => { const pageSize = 3; const firstPageIModels = generateMockIModels(3, "iModel"); firstPageIModels[1].description = "unmatched"; From 738a267b4a972ce94be82fa62b1d8d5bc1ee555b Mon Sep 17 00:00:00 2001 From: Arun George <11051042+aruniverse@users.noreply.github.com> Date: Fri, 19 Sep 2025 07:01:49 -0400 Subject: [PATCH 5/6] Update IModelGrid.test.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../src/containers/iModelGrid/IModelGrid.test.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx index 2a545694..01dbce4a 100644 --- a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx +++ b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx @@ -248,11 +248,9 @@ describe("IModelGrid", () => { mockFetchMore.mockClear(); postProcessCallback.mockImplementation((iModels: IModelFull[]) => { - return iModels.filter((iModel) => { - if (iModel.description === "iModel-description") { - return true; - } - }); + return iModels.filter( + (iModel) => iModel.description === "iModel-description" + ); }); rerender( From adddeea5cef255b5346745c75a1de99d09cd08f4 Mon Sep 17 00:00:00 2001 From: Vivek Patil Date: Fri, 19 Sep 2025 17:20:32 +0530 Subject: [PATCH 6/6] Rerun the build --- .../imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx index 01dbce4a..0576b836 100644 --- a/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx +++ b/packages/modules/imodel-browser/src/containers/iModelGrid/IModelGrid.test.tsx @@ -246,7 +246,6 @@ describe("IModelGrid", () => { }); mockFetchMore.mockClear(); - postProcessCallback.mockImplementation((iModels: IModelFull[]) => { return iModels.filter( (iModel) => iModel.description === "iModel-description"