Skip to content

Commit a2da3ae

Browse files
fix: don't call window reload every time we receive an alert (#251)
* fix: don't call window reload every time we receive an alert * feat: add ReactQueryDevtools * chore: remove notification code * feat: more granular invalidation of data when alerts SSE is received
1 parent 47349da commit a2da3ae

8 files changed

+77
-120
lines changed

package-lock.json

+28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@radix-ui/react-slot": "^1.1.0",
2828
"@stacklok/ui-kit": "^1.0.1-1",
2929
"@tanstack/react-query": "^5.64.1",
30+
"@tanstack/react-query-devtools": "^5.66.0",
3031
"@types/prismjs": "^1.26.5",
3132
"@types/react-syntax-highlighter": "^15.5.13",
3233
"@untitled-ui/icons-react": "^0.1.4",

src/hooks/__tests__/useBrowserNotification.test.ts

-57
This file was deleted.

src/hooks/__tests__/useSee.test.ts

+15-31
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,19 @@ vi.mock("react-router-dom", () => ({
77
useLocation: vi.fn(() => ({ pathname: "/" })),
88
}));
99

10-
const mockSendNotification = vi.fn();
11-
vi.mock("../useBrowserNotification", () => ({
12-
useBrowserNotification: vi.fn(() => {
13-
return { sendNotification: mockSendNotification };
14-
}),
15-
}));
10+
const mockInvalidate = vi.fn();
11+
12+
vi.mock("@tanstack/react-query", async () => {
13+
const original = await vi.importActual<
14+
typeof import("@tanstack/react-query")
15+
>("@tanstack/react-query");
16+
return {
17+
...original,
18+
useQueryClient: () => ({
19+
invalidateQueries: mockInvalidate,
20+
}),
21+
};
22+
});
1623

1724
class MockEventSource {
1825
static instances: MockEventSource[] = [];
@@ -63,7 +70,7 @@ describe("useSse", () => {
6370
global.EventSource = originalEventSource;
6471
});
6572

66-
it("should send notification if new alert is detected", () => {
73+
it("should invalidate queries if new alert is detected", () => {
6774
renderHook(() => useSse(), { wrapper: TestQueryClientProvider });
6875

6976
expect(MockEventSource.instances.length).toBe(1);
@@ -76,29 +83,6 @@ describe("useSse", () => {
7683
MockEventSource.triggerMessage("new alert detected");
7784
});
7885

79-
expect(mockSendNotification).toHaveBeenCalledWith("CodeGate Dashboard", {
80-
body: "New Alert detected!",
81-
});
82-
83-
act(() => {
84-
vi.advanceTimersByTime(2000);
85-
});
86-
87-
expect(global.location.reload).toHaveBeenCalled();
88-
});
89-
90-
it("should send notification if new alert is detected", () => {
91-
renderHook(() => useSse(), { wrapper: TestQueryClientProvider });
92-
93-
act(() => {
94-
MockEventSource.triggerMessage("other message");
95-
});
96-
97-
expect(mockSendNotification).not.toHaveBeenCalledWith(
98-
"CodeGate Dashboard",
99-
{
100-
body: "New Alert detected!",
101-
},
102-
);
86+
expect(mockInvalidate).toHaveBeenCalled();
10387
});
10488
});

src/hooks/useBrowserNotification.ts

-21
This file was deleted.

src/hooks/useSse.ts

+20-11
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { useEffect } from "react";
2-
import { useBrowserNotification } from "./useBrowserNotification";
32
import { useLocation } from "react-router-dom";
4-
import { useQueryClient } from "@tanstack/react-query";
3+
import { Query, useQueryClient } from "@tanstack/react-query";
4+
import { OpenApiTsReactQueryKey } from "@/types/openapi-ts";
5+
import {
6+
v1GetWorkspaceAlertsQueryKey,
7+
v1GetWorkspaceMessagesQueryKey,
8+
} from "@/api/generated/@tanstack/react-query.gen";
59

610
const BASE_URL = import.meta.env.VITE_BASE_API_URL;
711

812
export function useSse() {
913
const location = useLocation();
10-
const { sendNotification } = useBrowserNotification();
1114
const queryClient = useQueryClient();
1215

1316
useEffect(() => {
@@ -17,19 +20,25 @@ export function useSse() {
1720

1821
eventSource.onmessage = function (event) {
1922
if (event.data.toLowerCase().includes("new alert detected")) {
20-
queryClient.invalidateQueries({ refetchType: "all" });
21-
sendNotification("CodeGate Dashboard", {
22-
body: "New Alert detected!",
23+
queryClient.invalidateQueries({
24+
refetchType: "all",
25+
predicate: (
26+
query: Query<unknown, Error, unknown, OpenApiTsReactQueryKey>,
27+
) =>
28+
query.queryKey[0]._id ===
29+
v1GetWorkspaceAlertsQueryKey({
30+
path: { workspace_name: "default" }, // NOTE: Just supplying "default" to satisfy the type-checker, because we are just using the `_id`, this invalidates for any workspace
31+
})[0]?._id ||
32+
query.queryKey[0]._id ===
33+
v1GetWorkspaceMessagesQueryKey({
34+
path: { workspace_name: "default" }, // NOTE: Just supplying "default" to satisfy the type-checker, because we are just using the `_id`, this invalidates for any workspace
35+
})[0]?._id,
2336
});
24-
25-
setTimeout(() => {
26-
window.location.reload();
27-
}, 2000);
2837
}
2938
};
3039

3140
return () => {
3241
eventSource.close();
3342
};
34-
}, [location.pathname, queryClient, sendNotification]);
43+
}, [location.pathname, queryClient]);
3544
}

src/main.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { QueryClientProvider } from "./components/react-query-provider.tsx";
1212
import { BrowserRouter } from "react-router-dom";
1313
import { UiKitClientSideRoutingProvider } from "./lib/ui-kit-client-side-routing.tsx";
1414
import { ConfirmProvider } from "./context/confirm-context.tsx";
15+
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
1516

1617
// Initialize the API client
1718
client.setConfig({
@@ -31,6 +32,7 @@ createRoot(document.getElementById("root")!).render(
3132
<App />
3233
</ConfirmProvider>
3334
</ErrorBoundary>
35+
<ReactQueryDevtools initialIsOpen={false} />
3436
</QueryClientProvider>
3537
</SidebarProvider>
3638
</DarkModeProvider>

src/types/openapi-ts.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { OptionsLegacyParser } from "@hey-api/client-fetch";
2+
3+
export type OpenApiTsReactQueryKey = [
4+
Pick<
5+
OptionsLegacyParser,
6+
"baseUrl" | "body" | "headers" | "path" | "query"
7+
> & {
8+
_id: string;
9+
_infinite?: boolean;
10+
},
11+
];

0 commit comments

Comments
 (0)