mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
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>
This commit is contained in:
co-authored by
BrunoQuaresma
parent
e6f11a383a
commit
befb42b6fd
+3
-2
@@ -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<TypesGen.HealthcheckReport>(
|
||||
"/api/v2/debug/health",
|
||||
`/api/v2/debug/health?${params}`,
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -21,13 +21,6 @@ export const deploymentStats = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const health = () => {
|
||||
return {
|
||||
queryKey: ["deployment", "health"],
|
||||
queryFn: API.getHealth,
|
||||
};
|
||||
};
|
||||
|
||||
export const deploymentSSHConfig = () => {
|
||||
return {
|
||||
queryKey: ["deployment", "sshConfig"],
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {
|
||||
</Helmet>
|
||||
|
||||
{healthStatus ? (
|
||||
<HealthPageView healthStatus={healthStatus} tab={tab} />
|
||||
<HealthPageView
|
||||
tab={tab}
|
||||
healthStatus={healthStatus}
|
||||
forceRefresh={forceRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
/>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
@@ -53,9 +65,13 @@ export default function HealthPage() {
|
||||
export function HealthPageView({
|
||||
healthStatus,
|
||||
tab,
|
||||
forceRefresh,
|
||||
isRefreshing,
|
||||
}: {
|
||||
healthStatus: Awaited<ReturnType<typeof getHealth>>;
|
||||
tab: ReturnType<typeof useTab>;
|
||||
forceRefresh: () => void;
|
||||
isRefreshing: boolean;
|
||||
}) {
|
||||
return (
|
||||
<DashboardFullPage>
|
||||
@@ -109,6 +125,7 @@ export function HealthPageView({
|
||||
value={healthStatus.coder_version}
|
||||
/>
|
||||
</Stats>
|
||||
<RefreshButton loading={isRefreshing} handleAction={forceRefresh} />
|
||||
</FullWidthPageHeader>
|
||||
<Box
|
||||
sx={{
|
||||
@@ -254,3 +271,25 @@ const styles = {
|
||||
},
|
||||
},
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
interface HealthcheckAction {
|
||||
handleAction: () => void;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export const RefreshButton: FC<HealthcheckAction> = ({
|
||||
handleAction,
|
||||
loading,
|
||||
}) => {
|
||||
return (
|
||||
<LoadingButton
|
||||
loading={loading}
|
||||
loadingPosition="start"
|
||||
data-testid="healthcheck-refresh-button"
|
||||
startIcon={<ReplayIcon />}
|
||||
onClick={handleAction}
|
||||
>
|
||||
Refresh
|
||||
</LoadingButton>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user