Skip to content

Commit

Permalink
Merge branch 'main' into fix/useimodeldata-race-conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
simihartstein committed Jan 8, 2025
2 parents 8ee35c5 + ac051b8 commit b233dee
Show file tree
Hide file tree
Showing 16 changed files with 107 additions and 42 deletions.

This file was deleted.

2 changes: 1 addition & 1 deletion packages/apps/storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@itwin/create-imodel-react": "^2.0.0",
"@itwin/delete-imodel-react": "^2.0.0",
"@itwin/delete-itwin-react": "^2.0.0",
"@itwin/imodel-browser-react": "~2.1.2",
"@itwin/imodel-browser-react": "~2.2.0",
"@itwin/itwinui-react": "^2.12.18",
"@itwin/manage-versions-react": "~2.0.0",
"@itwin/storybook-auth-addon": "^0.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ const useIndividualState = (iModel: IModelFull, props: IModelTileProps) => {
}),
[fetchVersionsList, selection?.displayName, versions]
);
// Override the thumbnailClick so it recieves the selected version too.
// Override the thumbnailClick so it receives the selected version too.
// Not great typewise, but it is an example of what someone could do if it was really needed.
const onThumbnailClick = React.useCallback(
(iModel: IModelFull) => {
Expand All @@ -241,7 +241,7 @@ export const WithPostProcessCallback: Story<IModelGridProps> =
withAccessTokenOverride((args) => {
const [filter, setFilter] = React.useState("");
const filterOrAddStartTile = React.useCallback(
(iModels: IModelFull[], status: DataStatus) => {
(iModels: IModelFull[], status?: DataStatus) => {
if (status !== DataStatus.Complete) {
return iModels;
}
Expand Down
17 changes: 17 additions & 0 deletions packages/modules/imodel-browser/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
{
"name": "@itwin/imodel-browser-react",
"entries": [
{
"version": "2.2.0",
"tag": "@itwin/imodel-browser-react_v2.2.0",
"date": "Tue, 07 Jan 2025 19:47:55 GMT",
"comments": {
"none": [
{
"comment": "Update access token docs for iTwinGrid and iModelGrid"
}
],
"minor": [
{
"comment": "provide option to refresh the grid after an itwin/imodel action"
}
]
}
},
{
"version": "2.1.2",
"tag": "@itwin/imodel-browser-react_v2.1.2",
Expand Down
9 changes: 8 additions & 1 deletion packages/modules/imodel-browser/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Change Log - @itwin/imodel-browser-react

This log was last generated on Mon, 09 Dec 2024 19:40:38 GMT and should not be manually modified.
This log was last generated on Tue, 07 Jan 2025 19:47:55 GMT and should not be manually modified.

## 2.2.0
Tue, 07 Jan 2025 19:47:55 GMT

### Minor changes

- provide option to refresh the grid after an itwin/imodel action

## 2.1.2
Mon, 09 Dec 2024 19:40:38 GMT
Expand Down
2 changes: 1 addition & 1 deletion packages/modules/imodel-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@itwin/imodel-browser-react",
"description": "Components that let the user browse the iModels of a context and select one.",
"repository": "https://github.com/iTwin/admin-components-react/tree/main/packages/modules/imodel-browser",
"version": "2.1.2",
"version": "2.2.0",
"main": "cjs/index.js",
"module": "esm/index.js",
"types": "cjs/index.d.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe("ITwinGrid", () => {
],
status: DataStatus.Complete,
fetchMore: undefined,
refetchITwins: jest.fn(),
});
});

Expand All @@ -37,6 +38,7 @@ describe("ITwinGrid", () => {
iTwins: [],
status: DataStatus.Complete,
fetchMore: undefined,
refetchITwins: jest.fn(),
});

// Act
Expand All @@ -58,11 +60,11 @@ describe("ITwinGrid", () => {

it("should not refetch iTwins favorites when component rerenders", async () => {
// Arrange
const fetchMore = jest.fn();
jest.spyOn(useITwinData, "useITwinData").mockReturnValue({
iTwins: [],
status: DataStatus.Complete,
fetchMore,
fetchMore: jest.fn(),
refetchITwins: jest.fn(),
});
// Act
const signal = new AbortController().signal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export const ITwinGrid = ({
iTwins: fetchedItwins,
status: fetchStatus,
fetchMore,
refetchITwins,
} = useITwinData({
requestType,
iTwinSubClass,
Expand All @@ -168,6 +169,7 @@ export const ITwinGrid = ({
iTwinFavorites,
addITwinToFavorites,
removeITwinFromFavorites,
refetchITwins,
});

const noResultsText = {
Expand Down Expand Up @@ -211,6 +213,7 @@ export const ITwinGrid = ({
isFavorite={iTwinFavorites.has(iTwin.id)}
addToFavorites={addITwinToFavorites}
removeFromFavorites={removeITwinFromFavorites}
refetchITwins={refetchITwins}
{...tileOverrides}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export interface ITwinTileProps {
addToFavorites?(iTwinId: string): Promise<void>;
/** Function to remove the iTwin from favorites */
removeFromFavorites?(iTwinId: string): Promise<void>;
/** Function to refetch iTwins */
refetchITwins?: () => void;
}

/**
Expand All @@ -58,6 +60,7 @@ export const ITwinTile = ({
isFavorite,
addToFavorites,
removeFromFavorites,
refetchITwins,
}: ITwinTileProps) => {
const strings = _mergeStrings(
{
Expand All @@ -71,8 +74,14 @@ export const ITwinTile = ({
);

const moreOptions = React.useMemo(
() => _buildManagedContextMenuOptions(iTwinOptions, iTwin),
[iTwinOptions, iTwin]
() =>
_buildManagedContextMenuOptions(
iTwinOptions,
iTwin,
undefined,
refetchITwins
),
[iTwinOptions, iTwin, refetchITwins]
);
return (
<ThemeProvider theme="inherit">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ export const useITwinData = ({
const filteredProjects = useITwinFilter(projects, filterOptions);
const [page, setPage] = React.useState(0);
const [morePages, setMorePages] = React.useState(true);

const refetchData = React.useCallback(() => {
setStatus(DataStatus.Fetching);
setProjects([]);
setPage(0);
setMorePages(true);
}, []);

const fetchMore = React.useCallback(() => {
setPage((page) => page + 1);
}, []);
Expand All @@ -57,20 +65,21 @@ export const useITwinData = ({
morePagesRef.current ||
!["favorites", "recents"].includes(requestType)
) {
setStatus(DataStatus.Fetching);
setProjects([]);
setPage(0);
setMorePages(true);
refetchData();
}
}, [filterOptions, requestType]);
}, [filterOptions, requestType, refetchData]);

React.useEffect(() => {
// If any of the dependencies change, always restart the fetch from scratch.
setStatus(DataStatus.Fetching);
setProjects([]);
setPage(0);
setMorePages(true);
}, [accessToken, requestType, iTwinSubClass, data, serverEnvironmentPrefix]);
refetchData();
}, [
accessToken,
requestType,
iTwinSubClass,
data,
serverEnvironmentPrefix,
refetchData,
]);

React.useEffect(() => {
if (!morePages) {
Expand Down Expand Up @@ -165,5 +174,6 @@ export const useITwinData = ({
iTwins: filteredProjects,
status,
fetchMore: morePages ? fetchMore : undefined,
refetchITwins: refetchData,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface useITwinTableConfigProps {
iTwinFavorites: Set<string>;
addITwinToFavorites: (iTwinId: string) => Promise<void>;
removeITwinFromFavorites: (iTwinId: string) => Promise<void>;
refetchITwins: () => void;
}

export const useITwinTableConfig = ({
Expand All @@ -31,6 +32,7 @@ export const useITwinTableConfig = ({
iTwinFavorites,
addITwinToFavorites,
removeITwinFromFavorites,
refetchITwins,
}: useITwinTableConfigProps) => {
const onRowClick = (_: React.MouseEvent, row: any) => {
const iTwin = row.original as ITwinFull;
Expand Down Expand Up @@ -110,7 +112,8 @@ export const useITwinTableConfig = ({
const options = _buildManagedContextMenuOptions(
iTwinActions,
props.row.original,
close
close,
refetchITwins
);
return options !== undefined ? options : [];
};
Expand Down Expand Up @@ -145,6 +148,7 @@ export const useITwinTableConfig = ({
strings.tableColumnFavorites,
strings.tableColumnLastModified,
strings.tableColumnName,
refetchITwins,
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export const IModelGrid = ({
iModels: fetchediModels,
status: fetchStatus,
fetchMore,
refetchIModels,
} = useIModelData({
accessToken,
apiOverrides,
Expand All @@ -170,6 +171,7 @@ export const IModelGrid = ({
iModelActions,
onThumbnailClick,
strings,
refetchIModels,
});

const noResultsText = {
Expand Down Expand Up @@ -198,6 +200,7 @@ export const IModelGrid = ({
onThumbnailClick={onThumbnailClick}
apiOverrides={tileApiOverrides}
useTileState={useIndividualState}
refetchIModels={refetchIModels}
{...tileOverrides}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ export const useIModelData = ({
setPreviousSortOptions(sortOptions);
}

const reset = React.useCallback(() => {
setStatus(DataStatus.Fetching);
setIModels([]);
setPage(0);
setMorePagesAvailable(true);
setNeedsUpdate(true);
}, []);

const fetchMore = React.useCallback(() => {
if (status === DataStatus.Fetching || !morePagesAvailable) {
return;
Expand All @@ -77,11 +85,7 @@ export const useIModelData = ({

React.useEffect(() => {
// start from scratch when any external state changes
setStatus(DataStatus.Fetching);
setIModels([]);
setPage(0);
setMorePagesAvailable(true);
setNeedsUpdate(true);
reset();
}, [
iTwinId,
accessToken,
Expand All @@ -91,6 +95,7 @@ export const useIModelData = ({
apiOverrides?.serverEnvironmentPrefix,
searchText,
maxCount,
reset,
]);

// Main function
Expand Down Expand Up @@ -182,6 +187,7 @@ export const useIModelData = ({
iModels: sortedIModels,
status,
fetchMore: morePagesAvailable ? fetchMore : undefined,
refetchIModels: reset,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ export interface useIModelTableConfigProps {
noAuthentication: string;
error: string;
};
refetchIModels: () => void;
}

export const useIModelTableConfig = ({
iModelActions,
onThumbnailClick,
strings,
refetchIModels,
}: useIModelTableConfigProps) => {
const onRowClick = (_: React.MouseEvent, row: any) => {
const iModel = row.original as IModelFull;
Expand Down Expand Up @@ -86,7 +88,8 @@ export const useIModelTableConfig = ({
const options = _buildManagedContextMenuOptions(
iModelActions,
props.row.original,
close
close,
refetchIModels
);
return options !== undefined ? options : [];
};
Expand Down Expand Up @@ -115,6 +118,7 @@ export const useIModelTableConfig = ({
strings.tableColumnDescription,
strings.tableColumnLastModified,
strings.tableColumnName,
refetchIModels,
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export interface IModelTileProps {
tileProps?: Partial<TileProps>;
/** Object that configures different overrides for the API */
apiOverrides?: ApiOverrides;
/** Function to refetch iModels */
refetchIModels?: () => void;
}

/**
Expand All @@ -39,10 +41,17 @@ export const IModelTile = ({
onThumbnailClick,
apiOverrides,
tileProps,
refetchIModels,
}: IModelTileProps) => {
const moreOptions = React.useMemo(
() => _buildManagedContextMenuOptions(iModelOptions, iModel),
[iModelOptions, iModel]
() =>
_buildManagedContextMenuOptions(
iModelOptions,
iModel,
undefined,
refetchIModels
),
[iModelOptions, iModel, refetchIModels]
);
const thumbnailApiOverride =
apiOverrides || iModel?.thumbnail
Expand Down
Loading

0 comments on commit b233dee

Please sign in to comment.