Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/imodel-browser-react",
"comment": "Prevent concurrent iTwin API fetches",
"type": "patch"
}
],
"packageName": "@itwin/imodel-browser-react"
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,29 @@ export const IModelGrid = (props: IModelGridProps) => (
export default {
title: "imodel-browser/IModelGrid",
component: IModelGrid,
argTypes: accessTokenArgTypes,
argTypes: {
...accessTokenArgTypes,
requestType: {
options: ["all", "recents", "favorites"],
mapping: {
all: "",
recents: "recents",
favorites: "favorites",
},
control: {
type: "radio",
},
},
viewMode: {
options: ["tile", "cells"],
control: {
type: "radio",
},
},
},
args: {
requestType: "all",
},
excludeStories: ["IModelGrid"],
} as Meta;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ export default {
component: ITwinGrid,
argTypes: {
accessToken,
requestType: {
options: ["all", "recents", "favorites"],
mapping: {
all: "",
recents: "recents",
favorites: "favorites",
},
control: {
type: "radio",
},
},
viewMode: {
options: ["tile", "cells"],
control: {
type: "radio",
},
},
},
args: {
requestType: "all",
},
excludeStories: ["ITwinGrid"],
} as Meta;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,29 @@ export const IModelGridMUI = (props: IModelGridMUIProps) => (
export default {
title: "imodel-browser/IModelGridMUI",
component: IModelGridMUI,
argTypes: accessTokenArgTypes,
argTypes: {
...accessTokenArgTypes,
requestType: {
options: ["all", "recents", "favorites"],
mapping: {
all: "",
recents: "recents",
favorites: "favorites",
},
control: {
type: "radio",
},
},
viewMode: {
options: ["tile", "cells"],
control: {
type: "radio",
},
},
},
args: {
requestType: "all",
},
excludeStories: ["IModelGridMUI"],
} as Meta;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,26 @@ export default {
component: ITwinGrid,
argTypes: {
accessToken,
viewMode: {
options: ["tile", "cells"],
control: {
type: "radio",
},
},
requestType: {
options: ["all", "recents", "favorites"],
mapping: {
all: "",
recents: "recents",
favorites: "favorites",
},
control: {
type: "radio",
},
},
},
args: {
requestType: "all",
},
excludeStories: ["ITwinGrid"],
} as Meta;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { renderHook } from "@testing-library/react-hooks";
import { act, renderHook } from "@testing-library/react-hooks";
import {
type ResponseComposition,
type RestContext,
Expand Down Expand Up @@ -280,4 +280,78 @@ describe("useITwinData hook", () => {
expect(urlWatcher).toHaveBeenCalledTimes(2);
});
});

describe("fetchMore", () => {
it("ignores fetchMore until the initial request settles", async () => {
const requestedPages: (string | null)[] = [];
server.use(
rest.get("https://api.bentley.com/itwins/", (req, res, ctx) => {
const skip = req.url.searchParams.get("$skip");
requestedPages.push(skip);
return res(
ctx.status(200),
ctx.json({
iTwins: [{ id: `id-${skip}`, displayName: `name-${skip}` }],
})
);
})
);

const { result, waitForNextUpdate } = renderHook(() =>
useITwinData({ accessToken })
);

// fetchMore is available immediately but must be ignored until the first request completes.
act(() => {
result.current.fetchMore?.();
result.current.fetchMore?.();
});

await waitForNextUpdate();

expect(result.current.status).toEqual(DataStatus.Complete);
// Only the first page should have been requested
expect(requestedPages).toEqual(["0"]);
expect(result.current.iTwins).toEqual([
{ id: "id-0", displayName: "name-0" },
]);
});

it("fetches the next page once the previous request has settled", async () => {
const firstPage = Array.from({ length: 100 }, (_, i) => ({
id: `first-${i}`,
displayName: `first-${i}`,
}));
const secondPage = [{ id: "second-0", displayName: "second-0" }];
server.use(
rest.get("https://api.bentley.com/itwins/", (req, res, ctx) => {
const skip = req.url.searchParams.get("$skip");
return res(
ctx.status(200),
ctx.json({ iTwins: skip === "0" ? firstPage : secondPage })
);
})
);

const { result, waitForNextUpdate } = renderHook(() =>
useITwinData({ accessToken })
);

await waitForNextUpdate();
expect(result.current.status).toEqual(DataStatus.Complete);
expect(result.current.iTwins).toHaveLength(100);
expect(result.current.fetchMore).toBeDefined();

act(() => {
result.current.fetchMore?.();
});
await waitForNextUpdate();

expect(result.current.iTwins).toHaveLength(101);
expect(result.current.iTwins).toContainEqual({
id: "second-0",
displayName: "second-0",
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ export const useITwinData = ({
setProjects([]);
setPage(0);
setMorePages(true);
fetchingMoreRef.current = false;
fetchingMoreRef.current = true;
}, []);

const fetchingMoreRef = React.useRef(false);
// We start in a fetching state
const fetchingMoreRef = React.useRef(true);
const fetchMore = React.useCallback(() => {
if (fetchingMoreRef.current) {
return;
Expand Down
Loading