Compare commits

...
Author SHA1 Message Date
Manuel 475d27baa0 feat: add websocket banner 2025-03-28 22:19:32 +01:00
3 changed files with 48 additions and 7 deletions

No files matched your search

@@ -21,6 +21,13 @@ import type { AppRouter } from "@homarr/api";
import { clientApi } from "@homarr/api/client";
import { createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/shared";
import { env } from "@homarr/common/env";
import { atom, useSetAtom } from "jotai";
interface WebSocketConnection {
state: 'connecting' | 'connected' | 'error' | 'closed'
}
export const webSocketConnectionAtom = atom<WebSocketConnection>({ state: 'connecting' });
const getWebSocketProtocol = () => {
// window is not defined on server side
@@ -44,9 +51,27 @@ const constructWebsocketUrl = () => {
return `${getWebSocketProtocol()}://${window.location.hostname}:${window.location.port}/websockets`;
};
const wsClient = createWSClient({
url: constructWebsocketUrl(),
});
let wsClient: WsClient | null;
const createWsClientOrDefault = (setState: (connection: WebSocketConnection) => void) => {
if (wsClient) {
return wsClient;
}
wsClient = createWSClient({
url: constructWebsocketUrl(),
onOpen() {
setState({ state: "connected" });
},
onClose() {
setState({ state: "closed" });
},
onError() {
setState({ state: "error" });
}
});
return wsClient;
}
export function TRPCReactProvider(props: PropsWithChildren) {
const [queryClient] = useState(
@@ -60,6 +85,8 @@ export function TRPCReactProvider(props: PropsWithChildren) {
}),
);
const setWebSocketConnection = useSetAtom(webSocketConnectionAtom);
const [trpcClient] = useState(() => {
return clientApi.createClient({
links: [
@@ -70,7 +97,7 @@ export function TRPCReactProvider(props: PropsWithChildren) {
splitLink({
condition: ({ type }) => type === "subscription",
true: wsLink<AppRouter>({
client: wsClient,
client: createWsClientOrDefault((state) => setWebSocketConnection(state)),
transformer: superjson,
}),
false: splitLink({
@@ -106,7 +133,7 @@ export function TRPCReactProvider(props: PropsWithChildren) {
<clientApi.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
<ReactQueryStreamedHydration transformer={superjson}>{props.children}</ReactQueryStreamedHydration>
<ReactQueryDevtools initialIsOpen={false} />
<ReactQueryDevtools initialIsOpen={false}/>
</QueryClientProvider>
</clientApi.Provider>
);
@@ -0,0 +1,11 @@
"use client";
import { useAtomValue } from "jotai";
import { webSocketConnectionAtom } from "~/app/[locale]/_client-providers/trpc";
export const WebSocketConnectionBanner = () => {
const value = useAtomValue(webSocketConnectionAtom);
console.log('socket connection', value)
return <div>dfheuihjfieufheuhfuefhuehfu</div>
};
+5 -2
View File
@@ -6,6 +6,7 @@ import { useAtomValue } from "jotai";
import { useOptionalBackgroundProps } from "./background";
import { navigationCollapsedAtom } from "./header/burger";
import { webSocketConnectionAtom } from "~/app/[locale]/_client-providers/trpc";
interface ClientShellProps {
hasHeader?: boolean;
@@ -18,12 +19,14 @@ export const ClientShell = ({
children,
}: PropsWithChildren<ClientShellProps>) => {
const collapsed = useAtomValue(navigationCollapsedAtom);
const backgroundProps = useOptionalBackgroundProps();
const backgroundProps = useOptionalBackgroundProps()
const value = useAtomValue(webSocketConnectionAtom);
return (
<AppShell
{...backgroundProps}
header={hasHeader ? { height: 60 } : undefined}
header={hasHeader ? { height: 60 + (value === 'closed' ? 20 : 0) } : undefined}
navbar={
hasNavigation
? {