Files
bifrost/ui/app/clientLayout.tsx
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

84 lines
3.0 KiB
TypeScript

import FullPageLoader from "@/components/fullPageLoader";
import NotAvailableBanner from "@/components/notAvailableBanner";
import ProgressProvider from "@/components/progressBar";
import Sidebar from "@/components/sidebar";
import { ThemeProvider } from "@/components/themeProvider";
import { SidebarProvider } from "@/components/ui/sidebar";
import { useStoreSync } from "@/hooks/useStoreSync";
import { WebSocketProvider } from "@/hooks/useWebSocket";
import { getErrorMessage, ReduxProvider, useGetCoreConfigQuery } from "@/lib/store";
import { BifrostConfig } from "@/lib/types/config";
import { RbacProvider } from "@enterprise/lib/contexts/rbacContext";
import { useLocation } from "@tanstack/react-router";
import { NuqsAdapter } from "nuqs/adapters/tanstack-router";
import { Suspense, lazy, useEffect } from "react";
import { CookiesProvider } from "react-cookie";
import { toast, Toaster } from "sonner";
// Lazy import — only loaded in development, completely excluded from prod bundle
const DevProfilerLazy = lazy(() => import("@/components/devProfiler").then((mod) => ({ default: mod.DevProfiler })));
const DevProfiler = () => (
<Suspense fallback={null}>
<DevProfilerLazy />
</Suspense>
);
function StoreSyncInitializer() {
useStoreSync();
return null;
}
function AppContent({ children }: { children: React.ReactNode }) {
const { data: bifrostConfig, error, isLoading } = useGetCoreConfigQuery({});
useEffect(() => {
if (error) {
toast.error(getErrorMessage(error));
}
}, [error]);
return (
<WebSocketProvider>
<CookiesProvider>
<StoreSyncInitializer />
<SidebarProvider>
<Sidebar />
<div className="dark:bg-card custom-scrollbar content-container my-[0.5rem] mr-[0.5rem] h-[calc(100dvh-1rem)] w-full min-w-xl overflow-auto rounded-md border border-gray-200 bg-white px-10 dark:border-zinc-800">
<main className="custom-scrollbar content-container-inner relative mx-auto flex flex-col overflow-y-hidden p-4">
{isLoading ? <FullPageLoader /> : <FullPage config={bifrostConfig}>{children}</FullPage>}
</main>
</div>
</SidebarProvider>
</CookiesProvider>
</WebSocketProvider>
);
}
function FullPage({ config, children }: { config: BifrostConfig | undefined; children: React.ReactNode }) {
const pathname = useLocation({ select: (l) => l.pathname });
if (config && config.is_db_connected) {
return children;
}
if (config && config.is_logs_connected && pathname.startsWith("/workspace/logs")) {
return children;
}
return <NotAvailableBanner />;
}
export function ClientLayout({ children }: { children: React.ReactNode }) {
return (
<ProgressProvider>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<Toaster />
<ReduxProvider>
<NuqsAdapter>
<RbacProvider>
<AppContent>{children}</AppContent>
{process.env.NODE_ENV === "development" && !process.env.BIFROST_DISABLE_PROFILER && <DevProfiler />}
</RbacProvider>
</NuqsAdapter>
</ReduxProvider>
</ThemeProvider>
</ProgressProvider>
);
}