Skip to content

Commit 3d9bfdd

Browse files
chore(site): remove update check service (#10355)
1 parent 1ba5169 commit 3d9bfdd

File tree

7 files changed

+194
-282
lines changed

7 files changed

+194
-282
lines changed

site/src/api/queries/updateCheck.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as API from "api/api";
2+
3+
export const updateCheck = () => {
4+
return {
5+
queryKey: ["updateCheck"],
6+
queryFn: () => API.getUpdateCheck(),
7+
};
8+
};

site/src/components/Dashboard/DashboardLayout.test.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
import { renderWithAuth } from "testHelpers/renderHelpers";
22
import { DashboardLayout } from "./DashboardLayout";
3-
import * as API from "api/api";
43
import { screen } from "@testing-library/react";
4+
import { rest } from "msw";
5+
import { server } from "testHelpers/server";
56

67
test("Show the new Coder version notification", async () => {
7-
jest.spyOn(API, "getUpdateCheck").mockResolvedValue({
8-
current: false,
9-
version: "v0.12.9",
10-
url: "https://github.com/coder/coder/releases/tag/v0.12.9",
11-
});
8+
server.use(
9+
rest.get("/api/v2/updatecheck", (req, res, ctx) => {
10+
return res(
11+
ctx.status(200),
12+
ctx.json({
13+
current: false,
14+
version: "v0.12.9",
15+
url: "https://github.com/coder/coder/releases/tag/v0.12.9",
16+
}),
17+
);
18+
}),
19+
);
1220
renderWithAuth(<DashboardLayout />, {
1321
children: [{ element: <h1>Test page</h1> }],
1422
});

site/src/components/Dashboard/DashboardLayout.tsx

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { useMachine } from "@xstate/react";
21
import { DeploymentBanner } from "./DeploymentBanner/DeploymentBanner";
32
import { LicenseBanner } from "components/Dashboard/LicenseBanner/LicenseBanner";
43
import { Loader } from "components/Loader/Loader";
@@ -7,23 +6,18 @@ import { usePermissions } from "hooks/usePermissions";
76
import { FC, Suspense } from "react";
87
import { Outlet } from "react-router-dom";
98
import { dashboardContentBottomPadding } from "theme/constants";
10-
import { updateCheckMachine } from "xServices/updateCheck/updateCheckXService";
119
import { Navbar } from "./Navbar/Navbar";
1210
import Snackbar from "@mui/material/Snackbar";
1311
import Link from "@mui/material/Link";
1412
import Box, { BoxProps } from "@mui/material/Box";
1513
import InfoOutlined from "@mui/icons-material/InfoOutlined";
1614
import Button from "@mui/material/Button";
1715
import { docs } from "utils/docs";
16+
import { useUpdateCheck } from "./useUpdateCheck";
1817

1918
export const DashboardLayout: FC = () => {
2019
const permissions = usePermissions();
21-
const [updateCheckState, updateCheckSend] = useMachine(updateCheckMachine, {
22-
context: {
23-
permissions,
24-
},
25-
});
26-
const { updateCheck } = updateCheckState.context;
20+
const updateCheck = useUpdateCheck(permissions.viewUpdateCheck);
2721
const canViewDeployment = Boolean(permissions.viewDeploymentValues);
2822

2923
return (
@@ -57,7 +51,7 @@ export const DashboardLayout: FC = () => {
5751

5852
<Snackbar
5953
data-testid="update-check-snackbar"
60-
open={updateCheckState.matches("show")}
54+
open={updateCheck.isVisible}
6155
anchorOrigin={{
6256
vertical: "bottom",
6357
horizontal: "right",
@@ -89,19 +83,15 @@ export const DashboardLayout: FC = () => {
8983
})}
9084
/>
9185
<Box>
92-
Coder {updateCheck?.version} is now available. View the{" "}
93-
<Link href={updateCheck?.url}>release notes</Link> and{" "}
86+
Coder {updateCheck.data?.version} is now available. View the{" "}
87+
<Link href={updateCheck.data?.url}>release notes</Link> and{" "}
9488
<Link href={docs("/admin/upgrade")}>upgrade instructions</Link>{" "}
9589
for more information.
9690
</Box>
9791
</Box>
9892
}
9993
action={
100-
<Button
101-
variant="text"
102-
size="small"
103-
onClick={() => updateCheckSend("DISMISS")}
104-
>
94+
<Button variant="text" size="small" onClick={updateCheck.dismiss}>
10595
Dismiss
10696
</Button>
10797
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { act, renderHook, waitFor } from "@testing-library/react";
2+
import { useUpdateCheck } from "./useUpdateCheck";
3+
import { QueryClient, QueryClientProvider } from "react-query";
4+
import { ReactNode } from "react";
5+
import { rest } from "msw";
6+
import { MockUpdateCheck } from "testHelpers/entities";
7+
import { server } from "testHelpers/server";
8+
9+
const createWrapper = () => {
10+
const queryClient = new QueryClient();
11+
return ({ children }: { children: ReactNode }) => (
12+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
13+
);
14+
};
15+
16+
beforeEach(() => {
17+
window.localStorage.clear();
18+
});
19+
20+
it("is dismissed when does not have permission to see it", () => {
21+
const { result } = renderHook(() => useUpdateCheck(false), {
22+
wrapper: createWrapper(),
23+
});
24+
expect(result.current.isVisible).toBeFalsy();
25+
});
26+
27+
it("is dismissed when it is already using current version", async () => {
28+
server.use(
29+
rest.get("/api/v2/updatecheck", (req, res, ctx) => {
30+
return res(
31+
ctx.status(200),
32+
ctx.json({
33+
...MockUpdateCheck,
34+
current: true,
35+
}),
36+
);
37+
}),
38+
);
39+
const { result } = renderHook(() => useUpdateCheck(true), {
40+
wrapper: createWrapper(),
41+
});
42+
43+
await waitFor(() => {
44+
expect(result.current.isVisible).toBeFalsy();
45+
});
46+
});
47+
48+
it("is dismissed when it was dismissed previously", async () => {
49+
server.use(
50+
rest.get("/api/v2/updatecheck", (req, res, ctx) => {
51+
return res(
52+
ctx.status(200),
53+
ctx.json({
54+
...MockUpdateCheck,
55+
current: false,
56+
}),
57+
);
58+
}),
59+
);
60+
window.localStorage.setItem("dismissedVersion", MockUpdateCheck.version);
61+
const { result } = renderHook(() => useUpdateCheck(true), {
62+
wrapper: createWrapper(),
63+
});
64+
65+
await waitFor(() => {
66+
expect(result.current.isVisible).toBeFalsy();
67+
});
68+
});
69+
70+
it("shows when has permission and is outdated", async () => {
71+
server.use(
72+
rest.get("/api/v2/updatecheck", (req, res, ctx) => {
73+
return res(
74+
ctx.status(200),
75+
ctx.json({
76+
...MockUpdateCheck,
77+
current: false,
78+
}),
79+
);
80+
}),
81+
);
82+
const { result } = renderHook(() => useUpdateCheck(true), {
83+
wrapper: createWrapper(),
84+
});
85+
86+
await waitFor(() => {
87+
expect(result.current.isVisible).toBeTruthy();
88+
});
89+
});
90+
91+
it("shows when has permission and is outdated", async () => {
92+
server.use(
93+
rest.get("/api/v2/updatecheck", (req, res, ctx) => {
94+
return res(
95+
ctx.status(200),
96+
ctx.json({
97+
...MockUpdateCheck,
98+
current: false,
99+
}),
100+
);
101+
}),
102+
);
103+
const { result } = renderHook(() => useUpdateCheck(true), {
104+
wrapper: createWrapper(),
105+
});
106+
107+
await waitFor(() => {
108+
expect(result.current.isVisible).toBeTruthy();
109+
});
110+
111+
act(() => {
112+
result.current.dismiss();
113+
});
114+
115+
await waitFor(() => {
116+
expect(result.current.isVisible).toBeFalsy();
117+
});
118+
expect(localStorage.getItem("dismissedVersion")).toEqual(
119+
MockUpdateCheck.version,
120+
);
121+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { updateCheck } from "api/queries/updateCheck";
2+
import { useMemo, useState } from "react";
3+
import { useQuery } from "react-query";
4+
5+
export const useUpdateCheck = (enabled: boolean) => {
6+
const [dismissedVersion, setDismissedVersion] = useState(() =>
7+
getDismissedVersionOnLocal(),
8+
);
9+
const updateCheckQuery = useQuery({
10+
...updateCheck(),
11+
enabled,
12+
});
13+
14+
const isVisible: boolean = useMemo(() => {
15+
if (!updateCheckQuery.data) {
16+
return false;
17+
}
18+
19+
const isNotDismissed = dismissedVersion !== updateCheckQuery.data.version;
20+
const isOutdated = !updateCheckQuery.data.current;
21+
return isNotDismissed && isOutdated ? true : false;
22+
}, [dismissedVersion, updateCheckQuery.data]);
23+
24+
const dismiss = () => {
25+
if (!updateCheckQuery.data) {
26+
return;
27+
}
28+
setDismissedVersion(updateCheckQuery.data.version);
29+
saveDismissedVersionOnLocal(updateCheckQuery.data.version);
30+
};
31+
32+
return {
33+
isVisible,
34+
dismiss,
35+
data: updateCheckQuery.data,
36+
};
37+
};
38+
39+
const saveDismissedVersionOnLocal = (version: string): void => {
40+
window.localStorage.setItem("dismissedVersion", version);
41+
};
42+
43+
const getDismissedVersionOnLocal = (): string | undefined => {
44+
return localStorage.getItem("dismissedVersion") ?? undefined;
45+
};

0 commit comments

Comments
 (0)