Skip to content

Commit c84d96b

Browse files
fix(site): display not found page when pagination page is invalid (#12611)
1 parent b121f40 commit c84d96b

File tree

4 files changed

+66
-19
lines changed

4 files changed

+66
-19
lines changed

site/src/components/PaginationWidget/utils.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ describe(buildPagedList.name, () => {
5353
expect(uniqueCount).toEqual(result.length);
5454
}
5555
});
56+
57+
it("works for invalid active page number", () => {
58+
expect(buildPagedList(2, 4)).toEqual([1, 2]);
59+
});
5660
});
5761

5862
describe(getOffset.name, () => {

site/src/components/PaginationWidget/utils.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,14 @@ export const buildPagedList = (
3333
return range(1, numPages);
3434
}
3535

36+
const isInvalidActivePage = activePage > numPages || activePage < 1;
3637
const pageBeforeLast = numPages - 1;
37-
const startPage = Math.max(activePage - PAGE_NEIGHBORS, 2);
38-
const endPage = Math.min(activePage + PAGE_NEIGHBORS, pageBeforeLast);
38+
const startPage = isInvalidActivePage
39+
? 1 + PAGE_NEIGHBORS
40+
: Math.max(activePage - PAGE_NEIGHBORS, 2);
41+
const endPage = isInvalidActivePage
42+
? numPages - PAGE_NEIGHBORS
43+
: Math.min(activePage + PAGE_NEIGHBORS, pageBeforeLast);
3944

4045
let pages: ReturnType<typeof buildPagedList> = range(startPage, endPage);
4146

site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,12 @@ export const Error: Story = {
270270
error: mockApiError({ message: "Something went wrong" }),
271271
},
272272
};
273+
274+
export const InvalidPageNumber: Story = {
275+
args: {
276+
workspaces: [],
277+
count: 200,
278+
limit: 25,
279+
page: 1000,
280+
},
281+
};

site/src/pages/WorkspacesPage/WorkspacesPageView.tsx

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import KeyboardArrowDownOutlined from "@mui/icons-material/KeyboardArrowDownOutl
44
import PlayArrowOutlined from "@mui/icons-material/PlayArrowOutlined";
55
import StopOutlined from "@mui/icons-material/StopOutlined";
66
import LoadingButton from "@mui/lab/LoadingButton";
7+
import Button from "@mui/material/Button";
78
import Divider from "@mui/material/Divider";
89
import type { ComponentProps } from "react";
910
import type { UseQueryResult } from "react-query";
1011
import { hasError, isApiValidationError } from "api/errors";
1112
import type { Template, Workspace } from "api/typesGenerated";
1213
import { ErrorAlert } from "components/Alert/ErrorAlert";
14+
import { EmptyState } from "components/EmptyState/EmptyState";
1315
import { Margins } from "components/Margins/Margins";
1416
import {
1517
MoreMenu,
@@ -85,6 +87,11 @@ export const WorkspacesPageView = ({
8587
canCreateTemplate,
8688
canChangeVersions,
8789
}: WorkspacesPageViewProps) => {
90+
// Let's say the user has 5 workspaces, but tried to hit page 100, which does
91+
// not exist. In this case, the page is not valid and we want to show a better
92+
// error message.
93+
const invalidPageNumber = page !== 1 && workspaces?.length === 0;
94+
8895
return (
8996
<Margins>
9097
<PageHeader
@@ -168,26 +175,48 @@ export const WorkspacesPageView = ({
168175
</MoreMenu>
169176
</>
170177
) : (
171-
<PaginationHeader
172-
paginationUnitLabel="workspaces"
173-
limit={limit}
174-
totalRecords={count}
175-
currentOffsetStart={(page - 1) * limit + 1}
176-
css={{ paddingBottom: "0" }}
177-
/>
178+
!invalidPageNumber && (
179+
<PaginationHeader
180+
paginationUnitLabel="workspaces"
181+
limit={limit}
182+
totalRecords={count}
183+
currentOffsetStart={(page - 1) * limit + 1}
184+
css={{ paddingBottom: "0" }}
185+
/>
186+
)
178187
)}
179188
</TableToolbar>
180189

181-
<WorkspacesTable
182-
canCreateTemplate={canCreateTemplate}
183-
workspaces={workspaces}
184-
isUsingFilter={filterProps.filter.used}
185-
onUpdateWorkspace={onUpdateWorkspace}
186-
checkedWorkspaces={checkedWorkspaces}
187-
onCheckChange={onCheckChange}
188-
canCheckWorkspaces={canCheckWorkspaces}
189-
templates={templates}
190-
/>
190+
{invalidPageNumber ? (
191+
<EmptyState
192+
css={(theme) => ({
193+
border: `1px solid ${theme.palette.divider}`,
194+
borderRadius: theme.shape.borderRadius,
195+
})}
196+
message="Page not found"
197+
description="The page you are trying to access does not exist."
198+
cta={
199+
<Button
200+
onClick={() => {
201+
onPageChange(1);
202+
}}
203+
>
204+
Back to the first page
205+
</Button>
206+
}
207+
/>
208+
) : (
209+
<WorkspacesTable
210+
canCreateTemplate={canCreateTemplate}
211+
workspaces={workspaces}
212+
isUsingFilter={filterProps.filter.used}
213+
onUpdateWorkspace={onUpdateWorkspace}
214+
checkedWorkspaces={checkedWorkspaces}
215+
onCheckChange={onCheckChange}
216+
canCheckWorkspaces={canCheckWorkspaces}
217+
templates={templates}
218+
/>
219+
)}
191220

192221
{count !== undefined && (
193222
// Temporary styling stopgap before component is migrated to using

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy