Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refresh grid on iTwin/iModel action #135

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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": "provide option to refresh the grid after an itwin/imodel action",
"type": "minor"
}
],
"packageName": "@itwin/imodel-browser-react"
}
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
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export const ITwinGrid = ({
shouldRefetchFavorites,
resetShouldRefetchFavorites,
} = useITwinFavorites(accessToken, apiOverrides?.serverEnvironmentPrefix);
const [isStale, setIsStale] = React.useState(false);

const strings = _mergeStrings(
{
Expand Down Expand Up @@ -153,6 +154,8 @@ export const ITwinGrid = ({
filterOptions,
shouldRefetchFavorites,
resetShouldRefetchFavorites,
isStaleData: isStale,
resetStaleData: React.useCallback(() => setIsStale(false), []),
});

const iTwins = React.useMemo(
Expand All @@ -161,13 +164,18 @@ export const ITwinGrid = ({
[postProcessCallback, fetchedItwins, fetchStatus]
);

const forceRefresh = React.useCallback(() => {
setIsStale(true);
}, []);

const { columns, onRowClick } = useITwinTableConfig({
iTwinActions,
onThumbnailClick,
strings,
iTwinFavorites,
addITwinToFavorites,
removeITwinFromFavorites,
forceRefresh,
});

const noResultsText = {
Expand Down Expand Up @@ -211,6 +219,7 @@ export const ITwinGrid = ({
isFavorite={iTwinFavorites.has(iTwin.id)}
addToFavorites={addITwinToFavorites}
removeFromFavorites={removeITwinFromFavorites}
forceRefresh={forceRefresh}
{...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 force a refetch of the iTwins */
forceRefresh: () => void;
}

/**
Expand All @@ -58,6 +60,7 @@ export const ITwinTile = ({
isFavorite,
addToFavorites,
removeFromFavorites,
forceRefresh,
}: ITwinTileProps) => {
const strings = _mergeStrings(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export interface ProjectDataHookOptions {
filterOptions?: ITwinFilterOptions;
shouldRefetchFavorites?: boolean;
resetShouldRefetchFavorites?: () => void;
isStaleData?: boolean;
resetStaleData?: () => void;
}

const PAGE_SIZE = 100;
Expand All @@ -34,6 +36,8 @@ export const useITwinData = ({
filterOptions,
shouldRefetchFavorites,
resetShouldRefetchFavorites,
isStaleData,
resetStaleData,
}: ProjectDataHookOptions) => {
const data = apiOverrides?.data;
const serverEnvironmentPrefix = apiOverrides?.serverEnvironmentPrefix;
Expand All @@ -42,6 +46,17 @@ export const useITwinData = ({
const filteredProjects = useITwinFilter(projects, filterOptions);
const [page, setPage] = React.useState(0);
const [morePages, setMorePages] = React.useState(true);

React.useEffect(() => {
if (isStaleData) {
setStatus(DataStatus.Fetching);
setProjects([]);
setPage(0);
setMorePages(true);
resetStaleData?.();
}
}, [isStaleData, resetStaleData]);

const fetchMore = React.useCallback(() => {
setPage((page) => page + 1);
}, []);
Expand Down
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>;
forceRefresh: () => void;
}

export const useITwinTableConfig = ({
Expand All @@ -31,6 +32,7 @@ export const useITwinTableConfig = ({
iTwinFavorites,
addITwinToFavorites,
removeITwinFromFavorites,
forceRefresh,
}: 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,
forceRefresh
);
return options !== undefined ? options : [];
};
Expand Down Expand Up @@ -145,6 +148,7 @@ export const useITwinTableConfig = ({
strings.tableColumnFavorites,
strings.tableColumnLastModified,
strings.tableColumnName,
forceRefresh,
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export const IModelGrid = ({
}: IModelGridProps) => {
const [sort, setSort] = React.useState<IModelSortOptions>(sortOptions);
const [isSortOnTable, setIsSortOnTable] = React.useState(false);
const [isStale, setIsStale] = React.useState(false);

React.useEffect(() => {
if (!isSortOnTable) {
Expand Down Expand Up @@ -157,6 +158,8 @@ export const IModelGrid = ({
searchText,
maxCount,
viewMode,
isStaleData: isStale,
resetStaleData: React.useCallback(() => setIsStale(false), []),
});

const iModels = React.useMemo(
Expand All @@ -165,11 +168,15 @@ export const IModelGrid = ({
fetchediModels,
[postProcessCallback, fetchediModels, fetchStatus, searchText]
);
const forceRefresh = React.useCallback(() => {
setIsStale(true);
}, []);

const { columns, onRowClick } = useIModelTableConfig({
iModelActions,
onThumbnailClick,
strings,
forceRefresh,
});

const noResultsText = {
Expand Down Expand Up @@ -206,6 +213,7 @@ export const IModelGrid = ({
onThumbnailClick={onThumbnailClick}
apiOverrides={tileApiOverrides}
useTileState={useIndividualState}
forceRefresh={forceRefresh}
{...tileOverrides}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export interface IModelDataHookOptions {
searchText?: string | undefined;
maxCount?: number;
viewMode?: ViewType;
isStaleData?: boolean;
resetStaleData?: () => void;
}
const PAGE_SIZE = 100;

Expand All @@ -33,6 +35,8 @@ export const useIModelData = ({
searchText,
maxCount,
viewMode,
isStaleData,
resetStaleData,
}: IModelDataHookOptions) => {
const sortType =
sortOptions && ["name", "createdDateTime"].includes(sortOptions.sortType)
Expand All @@ -44,11 +48,22 @@ export const useIModelData = ({
const [status, setStatus] = React.useState<DataStatus>();
const [page, setPage] = React.useState(0);
const [morePages, setMorePages] = React.useState(true);

const fetchMore = React.useCallback(() => {
viewMode === "cells" && setStatus(DataStatus.Fetching);
status !== DataStatus.Fetching && setPage((page) => page + 1);
}, [status, viewMode]);

React.useEffect(() => {
if (isStaleData) {
setStatus(DataStatus.Fetching);
setIModels([]);
setPage(0);
setMorePages(true);
resetStaleData?.();
}
}, [isStaleData, resetStaleData]);

React.useEffect(() => {
// If sort changes but we already have all the data,
// let client side sorting do its job, otherwise, refetch from scratch.
Expand All @@ -59,6 +74,7 @@ export const useIModelData = ({
setMorePages(true);
}
}, [sortType, sortDescending, morePages]);

React.useEffect(() => {
// If any of the dependencies change, always restart the fetch from scratch.
setStatus(DataStatus.Fetching);
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;
};
forceRefresh: () => void;
}

export const useIModelTableConfig = ({
iModelActions,
onThumbnailClick,
strings,
forceRefresh,
}: 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,
forceRefresh
);
return options !== undefined ? options : [];
};
Expand Down Expand Up @@ -115,6 +118,7 @@ export const useIModelTableConfig = ({
strings.tableColumnDescription,
strings.tableColumnLastModified,
strings.tableColumnName,
forceRefresh,
]
);

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 force a refetch of the iModels */
forceRefresh: () => void;
}

/**
Expand All @@ -39,10 +41,17 @@ export const IModelTile = ({
onThumbnailClick,
apiOverrides,
tileProps,
forceRefresh,
}: IModelTileProps) => {
const moreOptions = React.useMemo(
() => _buildManagedContextMenuOptions(iModelOptions, iModel),
[iModelOptions, iModel]
() =>
_buildManagedContextMenuOptions(
iModelOptions,
iModel,
undefined,
forceRefresh
),
[iModelOptions, iModel, forceRefresh]
);
const thumbnailApiOverride =
apiOverrides || iModel?.thumbnail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface ContextMenuBuilderItem<T = any>
extends Omit<MenuItemProps, "onClick" | "value"> {
key: string;
visible?: boolean | ((value: T) => boolean);
onClick?: ((value?: unknown) => void) | undefined;
onClick?: ((value?: T, forceRefresh?: () => void) => void) | undefined;
}

/** Build MenuItem array for the value for each provided options
Expand All @@ -20,8 +20,9 @@ export interface ContextMenuBuilderItem<T = any>
export const _buildManagedContextMenuOptions: <T>(
options: ContextMenuBuilderItem<T>[] | undefined,
value: T,
closeMenu?: () => void
) => JSX.Element[] | undefined = (options, value, closeMenu) => {
closeMenu?: () => void,
forceRefresh?: () => void
) => JSX.Element[] | undefined = (options, value, closeMenu, forceRefresh) => {
return options
?.filter?.(({ visible }) => {
return typeof visible === "function" ? visible(value) : visible ?? true;
Expand All @@ -32,7 +33,7 @@ export const _buildManagedContextMenuOptions: <T>(
{...contextMenuProps}
onClick={() => {
closeMenu?.();
onClick?.(value);
onClick?.(value, forceRefresh);
}}
key={key}
value={value}
Expand Down
Loading