From befb42b6fd434ee7191139d703dadcc5cdf08032 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Fri, 17 Nov 2023 15:26:25 +0000 Subject: [PATCH] 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 --- site/src/api/api.ts | 5 +- site/src/api/queries/debug.ts | 17 +++++++ site/src/api/queries/deployment.ts | 7 --- .../DeploymentBanner/DeploymentBanner.tsx | 3 +- site/src/pages/HealthPage/HealthPage.tsx | 49 +++++++++++++++++-- 5 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 site/src/api/queries/debug.ts diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 6f0e4d3832..cb57a149f6 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1565,9 +1565,10 @@ export const getInsightsTemplate = async ( return response.data; }; -export const getHealth = async () => { +export const getHealth = async (force: boolean = false) => { + const params = new URLSearchParams({ force: force.toString() }); const response = await axios.get( - "/api/v2/debug/health", + `/api/v2/debug/health?${params}`, ); return response.data; }; diff --git a/site/src/api/queries/debug.ts b/site/src/api/queries/debug.ts new file mode 100644 index 0000000000..5381c6610f --- /dev/null +++ b/site/src/api/queries/debug.ts @@ -0,0 +1,17 @@ +import * as API from "api/api"; +import { QueryClient } from "react-query"; + +export const health = () => ({ + queryKey: ["health"], + queryFn: async () => API.getHealth(), +}); + +export const refreshHealth = (queryClient: QueryClient) => { + return { + mutationFn: async () => { + await queryClient.cancelQueries(["health"]); + const newHealthData = await API.getHealth(true); + queryClient.setQueryData(["health"], newHealthData); + }, + }; +}; diff --git a/site/src/api/queries/deployment.ts b/site/src/api/queries/deployment.ts index a8d066b41f..540c76ebd7 100644 --- a/site/src/api/queries/deployment.ts +++ b/site/src/api/queries/deployment.ts @@ -21,13 +21,6 @@ export const deploymentStats = () => { }; }; -export const health = () => { - return { - queryKey: ["deployment", "health"], - queryFn: API.getHealth, - }; -}; - export const deploymentSSHConfig = () => { return { queryKey: ["deployment", "sshConfig"], diff --git a/site/src/components/Dashboard/DeploymentBanner/DeploymentBanner.tsx b/site/src/components/Dashboard/DeploymentBanner/DeploymentBanner.tsx index 5ebeff79b4..a48de3251c 100644 --- a/site/src/components/Dashboard/DeploymentBanner/DeploymentBanner.tsx +++ b/site/src/components/Dashboard/DeploymentBanner/DeploymentBanner.tsx @@ -1,9 +1,10 @@ import { type FC } from "react"; import { useQuery } from "react-query"; -import { deploymentStats, health } from "api/queries/deployment"; +import { deploymentStats } from "api/queries/deployment"; import { usePermissions } from "hooks/usePermissions"; import { DeploymentBannerView } from "./DeploymentBannerView"; import { useDashboard } from "../DashboardProvider"; +import { health } from "api/queries/debug"; export const DeploymentBanner: FC = () => { const dashboard = useDashboard(); diff --git a/site/src/pages/HealthPage/HealthPage.tsx b/site/src/pages/HealthPage/HealthPage.tsx index c1692f7dd5..14018b3e8a 100644 --- a/site/src/pages/HealthPage/HealthPage.tsx +++ b/site/src/pages/HealthPage/HealthPage.tsx @@ -1,6 +1,6 @@ import { type Interpolation, type Theme } from "@emotion/react"; import Box from "@mui/material/Box"; -import { useQuery } from "react-query"; +import { useMutation, useQuery, useQueryClient } from "react-query"; import { getHealth } from "api/api"; import { Loader } from "components/Loader/Loader"; import { useTab } from "hooks"; @@ -19,6 +19,10 @@ import { import { Stats, StatsItem } from "components/Stats/Stats"; import { createDayString } from "utils/createDayString"; import { DashboardFullPage } from "components/Dashboard/DashboardLayout"; +import { LoadingButton } from "@mui/lab"; +import ReplayIcon from "@mui/icons-material/Replay"; +import { FC } from "react"; +import { health, refreshHealth } from "api/queries/debug"; const sections = { derp: "DERP", @@ -29,11 +33,14 @@ const sections = { export default function HealthPage() { const tab = useTab("tab", "derp"); + const queryClient = useQueryClient(); const { data: healthStatus } = useQuery({ - queryKey: ["health"], - queryFn: () => getHealth(), - refetchInterval: 120_000, + ...health(), + refetchInterval: 30_000, }); + const { mutate: forceRefresh, isLoading: isRefreshing } = useMutation( + refreshHealth(queryClient), + ); return ( <> @@ -42,7 +49,12 @@ export default function HealthPage() { {healthStatus ? ( - + ) : ( )} @@ -53,9 +65,13 @@ export default function HealthPage() { export function HealthPageView({ healthStatus, tab, + forceRefresh, + isRefreshing, }: { healthStatus: Awaited>; tab: ReturnType; + forceRefresh: () => void; + isRefreshing: boolean; }) { return ( @@ -109,6 +125,7 @@ export function HealthPageView({ value={healthStatus.coder_version} /> + >; + +interface HealthcheckAction { + handleAction: () => void; + loading: boolean; +} + +export const RefreshButton: FC = ({ + handleAction, + loading, +}) => { + return ( + } + onClick={handleAction} + > + Refresh + + ); +};