mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-12 20:43:02 +00:00
avoid offset race cycle in groups as well
This commit is contained in:
@@ -14,8 +14,7 @@ const Groups = (props) => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { setOffset, offset, handleLimit, limit, setPagination } =
|
const { offset, handleLimit, limit, setPagination } = usePaginationParams();
|
||||||
usePaginationParams();
|
|
||||||
|
|
||||||
const total = groups_page ? groups_page.total : undefined;
|
const total = groups_page ? groups_page.total : undefined;
|
||||||
|
|
||||||
@@ -32,11 +31,22 @@ const Groups = (props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// single callback to reload the page
|
||||||
|
// uses current state, or params can be specified if state
|
||||||
|
// should be updated _after_ load, e.g. offset
|
||||||
|
const loadPageData = (params) => {
|
||||||
|
params = params || {};
|
||||||
|
return updateGroups(
|
||||||
|
params.offset === undefined ? offset : params.offset,
|
||||||
|
params.limit === undefined ? limit : params.limit,
|
||||||
|
)
|
||||||
|
.then((data) => dispatchPageUpdate(data.items, data._pagination))
|
||||||
|
.catch((err) => setErrorAlert("Failed to update group list."));
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateGroups(offset, limit).then((data) =>
|
loadPageData();
|
||||||
dispatchPageUpdate(data.items, data._pagination),
|
}, [limit]);
|
||||||
);
|
|
||||||
}, [offset, limit]);
|
|
||||||
|
|
||||||
if (!groups_data || !groups_page) {
|
if (!groups_data || !groups_page) {
|
||||||
return <div data-testid="no-show"></div>;
|
return <div data-testid="no-show"></div>;
|
||||||
@@ -72,8 +82,10 @@ const Groups = (props) => {
|
|||||||
limit={limit}
|
limit={limit}
|
||||||
visible={groups_data.length}
|
visible={groups_data.length}
|
||||||
total={total}
|
total={total}
|
||||||
next={() => setOffset(offset + limit)}
|
next={() => loadPageData({ offset: offset + limit })}
|
||||||
prev={() => setOffset(offset - limit)}
|
prev={() =>
|
||||||
|
loadPageData({ offset: limit > offset ? 0 : offset - limit })
|
||||||
|
}
|
||||||
handleLimit={handleLimit}
|
handleLimit={handleLimit}
|
||||||
/>
|
/>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
|
@@ -112,8 +112,8 @@ test("Renders nothing if required data is not available", async () => {
|
|||||||
expect(noShow).toBeVisible();
|
expect(noShow).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Interacting with PaginationFooter causes state update and refresh via useEffect call", async () => {
|
test("Interacting with PaginationFooter causes page refresh", async () => {
|
||||||
let upgradeGroupsSpy = mockAsync();
|
let updateGroupsSpy = mockAsync();
|
||||||
let setSearchParamsSpy = mockAsync();
|
let setSearchParamsSpy = mockAsync();
|
||||||
let searchParams = new URLSearchParams({ limit: "2" });
|
let searchParams = new URLSearchParams({ limit: "2" });
|
||||||
useSearchParams.mockImplementation(() => [
|
useSearchParams.mockImplementation(() => [
|
||||||
@@ -125,11 +125,11 @@ test("Interacting with PaginationFooter causes state update and refresh via useE
|
|||||||
]);
|
]);
|
||||||
let _, setSearchParams;
|
let _, setSearchParams;
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(groupsJsx(upgradeGroupsSpy));
|
render(groupsJsx(updateGroupsSpy));
|
||||||
[_, setSearchParams] = useSearchParams();
|
[_, setSearchParams] = useSearchParams();
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(upgradeGroupsSpy).toBeCalledWith(0, 2);
|
expect(updateGroupsSpy).toBeCalledWith(0, 2);
|
||||||
|
|
||||||
var lastState =
|
var lastState =
|
||||||
mockReducers.mock.results[mockReducers.mock.results.length - 1].value;
|
mockReducers.mock.results[mockReducers.mock.results.length - 1].value;
|
||||||
@@ -140,9 +140,7 @@ test("Interacting with PaginationFooter causes state update and refresh via useE
|
|||||||
await act(async () => {
|
await act(async () => {
|
||||||
fireEvent.click(next);
|
fireEvent.click(next);
|
||||||
});
|
});
|
||||||
expect(setSearchParamsSpy).toBeCalledWith("limit=2&offset=2");
|
expect(updateGroupsSpy).toBeCalledWith(2, 2);
|
||||||
|
// mocked updateGroups means callback after load doesn't fire
|
||||||
// FIXME: mocked useSelector, state seem to prevent updateGroups from being called
|
// expect(setSearchParamsSpy).toBeCalledWith("limit=2&offset=2");
|
||||||
// making the test environment not representative
|
|
||||||
// expect(callbackSpy).toHaveBeenCalledWith(2, 2);
|
|
||||||
});
|
});
|
||||||
|
@@ -155,7 +155,7 @@ const ServerDashboard = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadPageData();
|
loadPageData();
|
||||||
}, [offset, limit, name_filter, sort, state_filter]);
|
}, [limit, name_filter, sort, state_filter]);
|
||||||
|
|
||||||
if (!user_data || !user_page) {
|
if (!user_data || !user_page) {
|
||||||
return <div data-testid="no-show"></div>;
|
return <div data-testid="no-show"></div>;
|
||||||
|
Reference in New Issue
Block a user