Skip to content

Commit befb42b

Browse files
feat(site): add refresh button on health page (#10719)
Adds a button on DeploymentHealth page to immediately re-run the healthcheck. Co-authored-by: BrunoQuaresma <bruno_nonato_quaresma@hotmail.com>
1 parent e6f11a3 commit befb42b

File tree

5 files changed

+66
-15
lines changed

5 files changed

+66
-15
lines changed

site/src/api/api.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,9 +1565,10 @@ export const getInsightsTemplate = async (
15651565
return response.data;
15661566
};
15671567

1568-
export const getHealth = async () => {
1568+
export const getHealth = async (force: boolean = false) => {
1569+
const params = new URLSearchParams({ force: force.toString() });
15691570
const response = await axios.get<TypesGen.HealthcheckReport>(
1570-
"/api/v2/debug/health",
1571+
`/api/v2/debug/health?${params}`,
15711572
);
15721573
return response.data;
15731574
};

site/src/api/queries/debug.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as API from "api/api";
2+
import { QueryClient } from "react-query";
3+
4+
export const health = () => ({
5+
queryKey: ["health"],
6+
queryFn: async () => API.getHealth(),
7+
});
8+
9+
export const refreshHealth = (queryClient: QueryClient) => {
10+
return {
11+
mutationFn: async () => {
12+
await queryClient.cancelQueries(["health"]);
13+
const newHealthData = await API.getHealth(true);
14+
queryClient.setQueryData(["health"], newHealthData);
15+
},
16+
};
17+
};

site/src/api/queries/deployment.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,6 @@ export const deploymentStats = () => {
2121
};
2222
};
2323

24-
export const health = () => {
25-
return {
26-
queryKey: ["deployment", "health"],
27-
queryFn: API.getHealth,
28-
};
29-
};
30-
3124
export const deploymentSSHConfig = () => {
3225
return {
3326
queryKey: ["deployment", "sshConfig"],

site/src/components/Dashboard/DeploymentBanner/DeploymentBanner.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { type FC } from "react";
22
import { useQuery } from "react-query";
3-
import { deploymentStats, health } from "api/queries/deployment";
3+
import { deploymentStats } from "api/queries/deployment";
44
import { usePermissions } from "hooks/usePermissions";
55
import { DeploymentBannerView } from "./DeploymentBannerView";
66
import { useDashboard } from "../DashboardProvider";
7+
import { health } from "api/queries/debug";
78

89
export const DeploymentBanner: FC = () => {
910
const dashboard = useDashboard();

site/src/pages/HealthPage/HealthPage.tsx

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type Interpolation, type Theme } from "@emotion/react";
22
import Box from "@mui/material/Box";
3-
import { useQuery } from "react-query";
3+
import { useMutation, useQuery, useQueryClient } from "react-query";
44
import { getHealth } from "api/api";
55
import { Loader } from "components/Loader/Loader";
66
import { useTab } from "hooks";
@@ -19,6 +19,10 @@ import {
1919
import { Stats, StatsItem } from "components/Stats/Stats";
2020
import { createDayString } from "utils/createDayString";
2121
import { DashboardFullPage } from "components/Dashboard/DashboardLayout";
22+
import { LoadingButton } from "@mui/lab";
23+
import ReplayIcon from "@mui/icons-material/Replay";
24+
import { FC } from "react";
25+
import { health, refreshHealth } from "api/queries/debug";
2226

2327
const sections = {
2428
derp: "DERP",
@@ -29,11 +33,14 @@ const sections = {
2933

3034
export default function HealthPage() {
3135
const tab = useTab("tab", "derp");
36+
const queryClient = useQueryClient();
3237
const { data: healthStatus } = useQuery({
33-
queryKey: ["health"],
34-
queryFn: () => getHealth(),
35-
refetchInterval: 120_000,
38+
...health(),
39+
refetchInterval: 30_000,
3640
});
41+
const { mutate: forceRefresh, isLoading: isRefreshing } = useMutation(
42+
refreshHealth(queryClient),
43+
);
3744

3845
return (
3946
<>
@@ -42,7 +49,12 @@ export default function HealthPage() {
4249
</Helmet>
4350

4451
{healthStatus ? (
45-
<HealthPageView healthStatus={healthStatus} tab={tab} />
52+
<HealthPageView
53+
tab={tab}
54+
healthStatus={healthStatus}
55+
forceRefresh={forceRefresh}
56+
isRefreshing={isRefreshing}
57+
/>
4658
) : (
4759
<Loader />
4860
)}
@@ -53,9 +65,13 @@ export default function HealthPage() {
5365
export function HealthPageView({
5466
healthStatus,
5567
tab,
68+
forceRefresh,
69+
isRefreshing,
5670
}: {
5771
healthStatus: Awaited<ReturnType<typeof getHealth>>;
5872
tab: ReturnType<typeof useTab>;
73+
forceRefresh: () => void;
74+
isRefreshing: boolean;
5975
}) {
6076
return (
6177
<DashboardFullPage>
@@ -109,6 +125,7 @@ export function HealthPageView({
109125
value={healthStatus.coder_version}
110126
/>
111127
</Stats>
128+
<RefreshButton loading={isRefreshing} handleAction={forceRefresh} />
112129
</FullWidthPageHeader>
113130
<Box
114131
sx={{
@@ -254,3 +271,25 @@ const styles = {
254271
},
255272
},
256273
} satisfies Record<string, Interpolation<Theme>>;
274+
275+
interface HealthcheckAction {
276+
handleAction: () => void;
277+
loading: boolean;
278+
}
279+
280+
export const RefreshButton: FC<HealthcheckAction> = ({
281+
handleAction,
282+
loading,
283+
}) => {
284+
return (
285+
<LoadingButton
286+
loading={loading}
287+
loadingPosition="start"
288+
data-testid="healthcheck-refresh-button"
289+
startIcon={<ReplayIcon />}
290+
onClick={handleAction}
291+
>
292+
Refresh
293+
</LoadingButton>
294+
);
295+
};

0 commit comments

Comments
 (0)