diff --git a/apps/web/package.json b/apps/web/package.json
index fdef9a867..7f9f96095 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -8,7 +8,7 @@
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 vite build -- --typecheck",
"build:staging": "cross-env NODE_OPTIONS=--max-old-space-size=8192 vite build --mode staging",
"build:production": "cross-env NODE_OPTIONS=--max-old-space-size=8192 vite build --mode production -- --typecheck",
- "build:local": "cross-env NODE_OPTIONS=--max-old-space-size=12288 vite build -- --typecheck --local",
+ "build:local": "pnpm prebuild && cross-env NODE_OPTIONS=--max-old-space-size=12288 vite build -- --typecheck --local",
"build-storybook": "storybook build",
"build:visualize": "npx vite-bundle-visualizer",
"deploy:dev": "pnpm run build && npx wrangler deploy .output/server/index.mjs --env dev --assets .output/public",
diff --git a/apps/web/src/api/createAxiosInstance.ts b/apps/web/src/api/createAxiosInstance.ts
index 68a78955b..f33cc22c8 100644
--- a/apps/web/src/api/createAxiosInstance.ts
+++ b/apps/web/src/api/createAxiosInstance.ts
@@ -69,7 +69,6 @@ export const defaultAxiosRequestHandler = async (config: InternalAxiosRequestCon
token = await getSupabaseSessionServerFn().then(
({ data: { session } }) => session.access_token
);
- console.log('token', token);
} else {
// Always check token validity before making requests
const tokenResult = await checkTokenValidity();
diff --git a/apps/web/src/api/server-functions/getSupabaseSession.ts b/apps/web/src/api/server-functions/getSupabaseSession.ts
index 5316b5816..082633324 100644
--- a/apps/web/src/api/server-functions/getSupabaseSession.ts
+++ b/apps/web/src/api/server-functions/getSupabaseSession.ts
@@ -11,7 +11,6 @@ export const getSupabaseSessionServerFn = createServerFn({ method: 'GET' }).hand
expires_at: session?.expires_at,
expires_in: session?.expires_in,
};
- console.log('pickedSession', JSON.stringify(pickedSession));
return {
data: {
diff --git a/apps/web/src/components/features/auth/SignOutHandler.tsx b/apps/web/src/components/features/auth/SignOutHandler.tsx
index 3ccd58d38..e76cfaeef 100644
--- a/apps/web/src/components/features/auth/SignOutHandler.tsx
+++ b/apps/web/src/components/features/auth/SignOutHandler.tsx
@@ -4,8 +4,6 @@ import { useBusterNotifications } from '@/context/BusterNotifications';
import { signOut } from '@/integrations/supabase/signOut';
import { clearAllBrowserStorage } from '@/lib/storage';
-const navigate = useNavigate();
-
export const useSignOut = () => {
const { openErrorMessage } = useBusterNotifications();
const navigate = useNavigate();
@@ -14,19 +12,17 @@ export const useSignOut = () => {
// Then perform server-side sign out
await signOut();
- // First clear all client-side storage
- clearAllBrowserStorage();
-
- navigate({ to: '/auth/login' });
-
- // Clear all cookies
- for (const cookie of document.cookie.split(';')) {
- const cookieName = cookie.replace(/^ +/, '').split('=')[0];
- // biome-ignore lint/suspicious/noDocumentCookie: clearing cookies
- document.cookie = `${cookieName}=;expires=${new Date().toUTCString()};path=/`;
+ try {
+ // First clear all client-side storage
+ clearAllBrowserStorage();
+ } catch (error) {
+ console.error('Error clearing browser storage', error);
}
} catch (error) {
+ console.error('Error signing out', error);
openErrorMessage('Error signing out');
+ } finally {
+ navigate({ to: '/auth/login' });
}
}, [navigate, openErrorMessage]);
diff --git a/apps/web/src/components/features/global/ComponentErrorCard.tsx b/apps/web/src/components/features/global/ComponentErrorCard.tsx
new file mode 100644
index 000000000..3a552be6f
--- /dev/null
+++ b/apps/web/src/components/features/global/ComponentErrorCard.tsx
@@ -0,0 +1,24 @@
+import { ErrorBoundary } from 'react-error-boundary';
+import { rustErrorHandler } from '@/api/errors';
+import { ErrorCard } from './GlobalErrorCard';
+
+export const ComponentErrorCard = ({
+ children,
+ header,
+ message,
+}: {
+ children: React.ReactNode;
+ header?: string;
+ message?: string;
+}) => {
+ return (
+ {
+ const errorMessage: string | undefined = rustErrorHandler(e).message || undefined;
+ return ;
+ }}
+ >
+ {children}
+
+ );
+};
diff --git a/apps/web/src/components/features/global/GlobalErrorCard.tsx b/apps/web/src/components/features/global/GlobalErrorCard.tsx
index cdae18618..a23007161 100644
--- a/apps/web/src/components/features/global/GlobalErrorCard.tsx
+++ b/apps/web/src/components/features/global/GlobalErrorCard.tsx
@@ -3,8 +3,19 @@ import { usePostHog } from 'posthog-js/react';
import { useEffect } from 'react';
import { Button } from '@/components/ui/buttons';
import { Card, CardContent, CardFooter } from '@/components/ui/card/CardBase';
+import { useMount } from '../../../hooks/useMount';
+
+export const ErrorCard = ({
+ header = 'Looks like we hit an unexpected error',
+ message = "Our team has been notified via Slack. We'll take a look at the issue ASAP and get back to you.",
+}: {
+ header?: string;
+ message?: string;
+}) => {
+ useMount(() => {
+ console.error('Error in card:', header, message);
+ });
-export const ErrorCard = () => {
return (
{
-
Looks like we hit an unexpected error
+ {header}
-
- {`Our team has been notified via Slack. We'll take a look at the issue ASAP and get back to you.`}
-
+ {message}
@@ -42,8 +51,6 @@ export const GlobalErrorCard: ErrorRouteComponent = ({ error }) => {
if (isPosthogLoaded) {
posthog.captureException(error);
}
-
- console.error('GlobalErrorCard error', error);
}, [error]);
return ;
diff --git a/apps/web/src/components/features/sidebars/SidebarSettings.tsx b/apps/web/src/components/features/sidebars/SidebarSettings.tsx
index c4ff9becb..6802f7f2c 100644
--- a/apps/web/src/components/features/sidebars/SidebarSettings.tsx
+++ b/apps/web/src/components/features/sidebars/SidebarSettings.tsx
@@ -6,6 +6,7 @@ import CircleUser from '@/components/ui/icons/NucleoIconOutlined/circle-user';
import { createSidebarGroup } from '@/components/ui/sidebar/create-sidebar-item';
import LockCircle from '../../ui/icons/NucleoIconOutlined/lock-circle';
import { type ISidebarGroup, Sidebar } from '../../ui/sidebar';
+import { ComponentErrorCard } from '../global/ComponentErrorCard';
import { SidebarUserFooter } from './SidebarUserFooter';
const accountItems: ISidebarGroup = createSidebarGroup({
@@ -107,12 +108,14 @@ export const SidebarSettings = () => {
}, [isAdmin]);
return (
- , [])}
- footer={useMemo(() => , [])}
- useCollapsible={isUserRegistered}
- />
+
+ , [])}
+ footer={useMemo(() => , [])}
+ useCollapsible={isUserRegistered}
+ />
+
);
};
diff --git a/apps/web/src/components/ui/report/elements/InlineCombobox.tsx b/apps/web/src/components/ui/report/elements/InlineCombobox.tsx
index 5370f62a1..504e87980 100644
--- a/apps/web/src/components/ui/report/elements/InlineCombobox.tsx
+++ b/apps/web/src/components/ui/report/elements/InlineCombobox.tsx
@@ -210,7 +210,6 @@ const InlineComboboxInput = React.forwardRef<
})?.width + 8
);
}, [placeholder]);
- console.log(placeHolderWidth);
/**
* To create an auto-resizing input, we render a visually hidden span
diff --git a/apps/web/src/context/Posthog/BusterPosthogProvider.tsx b/apps/web/src/context/Posthog/BusterPosthogProvider.tsx
index f399b1cb1..211459ce3 100644
--- a/apps/web/src/context/Posthog/BusterPosthogProvider.tsx
+++ b/apps/web/src/context/Posthog/BusterPosthogProvider.tsx
@@ -7,6 +7,7 @@ import {
useGetUserBasicInfo,
useGetUserOrganization,
} from '@/api/buster_rest/users/useGetUserInfo';
+import { ComponentErrorCard } from '@/components/features/global/ComponentErrorCard';
import { isDev } from '@/config/dev';
import { env } from '@/env';
import packageJson from '../../../package.json';
@@ -16,16 +17,18 @@ const POSTHOG_KEY = env.VITE_PUBLIC_POSTHOG_KEY;
const DEBUG_POSTHOG = false;
export const BusterPosthogProvider: React.FC = ({ children }) => {
- console.log('POSTHOG_KEY', POSTHOG_KEY);
- console.log('DEBUG_POSTHOG', DEBUG_POSTHOG);
if ((isDev && !DEBUG_POSTHOG) || !POSTHOG_KEY) {
return <>{children}>;
}
- console.log('POSTHOG_KEY22', POSTHOG_KEY);
- console.log('DEBUG_POSTHOG22', DEBUG_POSTHOG);
-
- return {children};
+ return (
+
+ {children}
+
+ );
};
BusterPosthogProvider.displayName = 'BusterPosthogProvider';
@@ -49,7 +52,6 @@ const options: Partial = {
};
const PosthogWrapper: React.FC = ({ children }) => {
- console.log('PosthogWrapper');
const user = useGetUserBasicInfo();
const { data: userTeams } = useGetUserTeams({ userId: user?.id ?? '' });
const userOrganizations = useGetUserOrganization();
@@ -113,8 +115,6 @@ const PosthogWrapper: React.FC = ({ children }) => {
return <>{children}>;
}
- console.log('PostHogProvider!!!!', PostHogProvider);
-
return (
{children}
diff --git a/apps/web/src/context/Providers.tsx b/apps/web/src/context/Providers.tsx
index 5f586fd02..f7889cbd4 100644
--- a/apps/web/src/context/Providers.tsx
+++ b/apps/web/src/context/Providers.tsx
@@ -17,8 +17,6 @@ export const AppProviders: React.FC> = ({
user,
accessToken,
}) => {
- console.log('user11', user);
- console.log('accessToken11', accessToken);
return (
{children}
diff --git a/apps/web/src/context/Supabase/SupabaseContextProvider.tsx b/apps/web/src/context/Supabase/SupabaseContextProvider.tsx
index 543957981..3535f35fb 100644
--- a/apps/web/src/context/Supabase/SupabaseContextProvider.tsx
+++ b/apps/web/src/context/Supabase/SupabaseContextProvider.tsx
@@ -66,10 +66,7 @@ export const SupabaseContext = createContext = React.memo(({ user, accessToken, children }) => {
- console.log('user22', user);
- console.log('accessToken22', accessToken);
const value = useSupabaseContextInternal({ user, accessToken });
- console.log('value22', value);
return {children};
});
diff --git a/apps/web/src/integrations/supabase/signIn.ts b/apps/web/src/integrations/supabase/signIn.ts
index c3b25903a..8d4bc3e69 100644
--- a/apps/web/src/integrations/supabase/signIn.ts
+++ b/apps/web/src/integrations/supabase/signIn.ts
@@ -13,8 +13,6 @@ const isValidRedirectUrl = (url: string): boolean => {
}
};
-const fallbackCallbackUrl = `${env.VITE_PUBLIC_URL}/auth/callback`;
-
// Common OAuth handler to reduce code duplication
const handleOAuthSignIn = async (
provider: 'google' | 'github' | 'azure',
@@ -55,6 +53,7 @@ export const signInWithEmailAndPassword = createServerFn({ method: 'POST' })
)
.handler(async ({ data }) => {
const supabase = getSupabaseServerClient();
+
const { error } = await supabase.auth.signInWithPassword({
email: data.email,
password: data.password,
diff --git a/apps/web/src/layouts/SettingsAppLayout.tsx b/apps/web/src/layouts/SettingsAppLayout.tsx
index 5ef4d40ec..51efe3a2c 100644
--- a/apps/web/src/layouts/SettingsAppLayout.tsx
+++ b/apps/web/src/layouts/SettingsAppLayout.tsx
@@ -1,4 +1,5 @@
import type React from 'react';
+import { ComponentErrorCard } from '@/components/features/global/ComponentErrorCard';
import { SidebarSettings } from '@/components/features/sidebars/SidebarSettings';
import { AppLayout, type LayoutSize } from '@/components/ui/layouts/AppLayout';
@@ -16,13 +17,15 @@ export const SettingsAppLayout: React.FC = ({
defaultLayout,
}) => {
return (
- }
- >
- {children}
-
+
+ }
+ >
+ {children}
+
+
);
};
diff --git a/apps/web/src/routeTree.gen.ts b/apps/web/src/routeTree.gen.ts
index a86acfffe..01d958b52 100644
--- a/apps/web/src/routeTree.gen.ts
+++ b/apps/web/src/routeTree.gen.ts
@@ -20,6 +20,7 @@ import { Route as AppIndexRouteImport } from './routes/app/index'
import { Route as AuthResetPasswordRouteImport } from './routes/auth.reset-password'
import { Route as AuthLogoutRouteImport } from './routes/auth.logout'
import { Route as AuthLoginRouteImport } from './routes/auth.login'
+import { Route as AppHealthcheckRouteImport } from './routes/app/healthcheck'
import { Route as AppSettingsRouteImport } from './routes/app/_settings'
import { Route as AppAppRouteImport } from './routes/app/_app'
import { Route as EmbedReportReportIdRouteImport } from './routes/embed.report.$reportId'
@@ -29,6 +30,7 @@ import { Route as AppSettingsRestricted_layoutRouteImport } from './routes/app/_
import { Route as AppSettingsPermissionsRouteImport } from './routes/app/_settings/_permissions'
import { Route as AppAppHomeRouteImport } from './routes/app/_app/home'
import { Route as AppAppAssetRouteImport } from './routes/app/_app/_asset'
+import { Route as AppSettingsSettingsIndexRouteImport } from './routes/app/_settings/settings.index'
import { Route as AppAppReportsIndexRouteImport } from './routes/app/_app/reports.index'
import { Route as AppAppMetricsIndexRouteImport } from './routes/app/_app/metrics.index'
import { Route as AppAppLogsIndexRouteImport } from './routes/app/_app/logs.index'
@@ -198,6 +200,11 @@ const AuthLoginRoute = AuthLoginRouteImport.update({
path: '/login',
getParentRoute: () => AuthRoute,
} as any)
+const AppHealthcheckRoute = AppHealthcheckRouteImport.update({
+ id: '/healthcheck',
+ path: '/healthcheck',
+ getParentRoute: () => AppRoute,
+} as any)
const AppSettingsRoute = AppSettingsRouteImport.update({
id: '/_settings',
getParentRoute: () => AppRoute,
@@ -240,6 +247,12 @@ const AppAppAssetRoute = AppAppAssetRouteImport.update({
id: '/_asset',
getParentRoute: () => AppAppRoute,
} as any)
+const AppSettingsSettingsIndexRoute =
+ AppSettingsSettingsIndexRouteImport.update({
+ id: '/settings/',
+ path: '/settings/',
+ getParentRoute: () => AppSettingsRoute,
+ } as any)
const AppAppReportsIndexRoute = AppAppReportsIndexRouteImport.update({
id: '/reports/',
path: '/reports/',
@@ -913,6 +926,7 @@ export interface FileRoutesByFullPath {
'/app': typeof AppSettingsRestricted_layoutAdmin_onlyRouteWithChildren
'/auth': typeof AuthRouteWithChildren
'/healthcheck': typeof HealthcheckRoute
+ '/app/healthcheck': typeof AppHealthcheckRoute
'/auth/login': typeof AuthLoginRoute
'/auth/logout': typeof AuthLogoutRoute
'/auth/reset-password': typeof AuthResetPasswordRoute
@@ -929,6 +943,7 @@ export interface FileRoutesByFullPath {
'/app/logs': typeof AppAppLogsIndexRoute
'/app/metrics': typeof AppAppMetricsIndexRoute
'/app/reports': typeof AppAppReportsIndexRoute
+ '/app/settings': typeof AppSettingsSettingsIndexRoute
'/app/chats/$chatId': typeof AppAppAssetChatsChatIdRouteWithChildren
'/app/datasets/$datasetId/editor': typeof AppAppDatasetsDatasetIdEditorRoute
'/app/datasets/$datasetId/overview': typeof AppAppDatasetsDatasetIdOverviewRoute
@@ -1018,6 +1033,7 @@ export interface FileRoutesByTo {
'/auth': typeof AuthRouteWithChildren
'/healthcheck': typeof HealthcheckRoute
'/app': typeof AppSettingsRestricted_layoutAdmin_onlyRouteWithChildren
+ '/app/healthcheck': typeof AppHealthcheckRoute
'/auth/login': typeof AuthLoginRoute
'/auth/logout': typeof AuthLogoutRoute
'/auth/reset-password': typeof AuthResetPasswordRoute
@@ -1033,6 +1049,7 @@ export interface FileRoutesByTo {
'/app/logs': typeof AppAppLogsIndexRoute
'/app/metrics': typeof AppAppMetricsIndexRoute
'/app/reports': typeof AppAppReportsIndexRoute
+ '/app/settings': typeof AppSettingsSettingsIndexRoute
'/app/datasets/$datasetId/editor': typeof AppAppDatasetsDatasetIdEditorRoute
'/app/datasets/$datasetId/overview': typeof AppAppDatasetsDatasetIdOverviewRoute
'/app/settings/profile': typeof AppSettingsRestricted_layoutSettingsProfileRoute
@@ -1108,6 +1125,7 @@ export interface FileRoutesById {
'/healthcheck': typeof HealthcheckRoute
'/app/_app': typeof AppAppRouteWithChildren
'/app/_settings': typeof AppSettingsRouteWithChildren
+ '/app/healthcheck': typeof AppHealthcheckRoute
'/auth/login': typeof AuthLoginRoute
'/auth/logout': typeof AuthLogoutRoute
'/auth/reset-password': typeof AuthResetPasswordRoute
@@ -1128,6 +1146,7 @@ export interface FileRoutesById {
'/app/_app/logs/': typeof AppAppLogsIndexRoute
'/app/_app/metrics/': typeof AppAppMetricsIndexRoute
'/app/_app/reports/': typeof AppAppReportsIndexRoute
+ '/app/_settings/settings/': typeof AppSettingsSettingsIndexRoute
'/app/_app/_asset/chats/$chatId': typeof AppAppAssetChatsChatIdRouteWithChildren
'/app/_app/datasets/$datasetId/editor': typeof AppAppDatasetsDatasetIdEditorRoute
'/app/_app/datasets/$datasetId/overview': typeof AppAppDatasetsDatasetIdOverviewRoute
@@ -1229,6 +1248,7 @@ export interface FileRouteTypes {
| '/app'
| '/auth'
| '/healthcheck'
+ | '/app/healthcheck'
| '/auth/login'
| '/auth/logout'
| '/auth/reset-password'
@@ -1245,6 +1265,7 @@ export interface FileRouteTypes {
| '/app/logs'
| '/app/metrics'
| '/app/reports'
+ | '/app/settings'
| '/app/chats/$chatId'
| '/app/datasets/$datasetId/editor'
| '/app/datasets/$datasetId/overview'
@@ -1334,6 +1355,7 @@ export interface FileRouteTypes {
| '/auth'
| '/healthcheck'
| '/app'
+ | '/app/healthcheck'
| '/auth/login'
| '/auth/logout'
| '/auth/reset-password'
@@ -1349,6 +1371,7 @@ export interface FileRouteTypes {
| '/app/logs'
| '/app/metrics'
| '/app/reports'
+ | '/app/settings'
| '/app/datasets/$datasetId/editor'
| '/app/datasets/$datasetId/overview'
| '/app/settings/profile'
@@ -1423,6 +1446,7 @@ export interface FileRouteTypes {
| '/healthcheck'
| '/app/_app'
| '/app/_settings'
+ | '/app/healthcheck'
| '/auth/login'
| '/auth/logout'
| '/auth/reset-password'
@@ -1443,6 +1467,7 @@ export interface FileRouteTypes {
| '/app/_app/logs/'
| '/app/_app/metrics/'
| '/app/_app/reports/'
+ | '/app/_settings/settings/'
| '/app/_app/_asset/chats/$chatId'
| '/app/_app/datasets/$datasetId/editor'
| '/app/_app/datasets/$datasetId/overview'
@@ -1627,6 +1652,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AuthLoginRouteImport
parentRoute: typeof AuthRoute
}
+ '/app/healthcheck': {
+ id: '/app/healthcheck'
+ path: '/healthcheck'
+ fullPath: '/app/healthcheck'
+ preLoaderRoute: typeof AppHealthcheckRouteImport
+ parentRoute: typeof AppRoute
+ }
'/app/_settings': {
id: '/app/_settings'
path: ''
@@ -1690,6 +1722,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AppAppAssetRouteImport
parentRoute: typeof AppAppRoute
}
+ '/app/_settings/settings/': {
+ id: '/app/_settings/settings/'
+ path: '/settings'
+ fullPath: '/app/settings'
+ preLoaderRoute: typeof AppSettingsSettingsIndexRouteImport
+ parentRoute: typeof AppSettingsRoute
+ }
'/app/_app/reports/': {
id: '/app/_app/reports/'
path: '/reports'
@@ -3120,12 +3159,14 @@ const AppSettingsRestricted_layoutRouteWithChildren =
interface AppSettingsRouteChildren {
AppSettingsPermissionsRoute: typeof AppSettingsPermissionsRouteWithChildren
AppSettingsRestricted_layoutRoute: typeof AppSettingsRestricted_layoutRouteWithChildren
+ AppSettingsSettingsIndexRoute: typeof AppSettingsSettingsIndexRoute
}
const AppSettingsRouteChildren: AppSettingsRouteChildren = {
AppSettingsPermissionsRoute: AppSettingsPermissionsRouteWithChildren,
AppSettingsRestricted_layoutRoute:
AppSettingsRestricted_layoutRouteWithChildren,
+ AppSettingsSettingsIndexRoute: AppSettingsSettingsIndexRoute,
}
const AppSettingsRouteWithChildren = AppSettingsRoute._addFileChildren(
@@ -3135,12 +3176,14 @@ const AppSettingsRouteWithChildren = AppSettingsRoute._addFileChildren(
interface AppRouteChildren {
AppAppRoute: typeof AppAppRouteWithChildren
AppSettingsRoute: typeof AppSettingsRouteWithChildren
+ AppHealthcheckRoute: typeof AppHealthcheckRoute
AppIndexRoute: typeof AppIndexRoute
}
const AppRouteChildren: AppRouteChildren = {
AppAppRoute: AppAppRouteWithChildren,
AppSettingsRoute: AppSettingsRouteWithChildren,
+ AppHealthcheckRoute: AppHealthcheckRoute,
AppIndexRoute: AppIndexRoute,
}
diff --git a/apps/web/src/routes/app.tsx b/apps/web/src/routes/app.tsx
index 6570e4859..754184f44 100644
--- a/apps/web/src/routes/app.tsx
+++ b/apps/web/src/routes/app.tsx
@@ -28,22 +28,14 @@ export const Route = createFileRoute('/app')({
loader: async ({ context }) => {
const { queryClient, accessToken } = context;
try {
- const [initialLayout, user, userInfo, userFavorites, listDatasources, datasets] =
- await Promise.all([
- getAppLayout({ id: PRIMARY_APP_LAYOUT_ID }),
- getSupabaseUser(),
- prefetchGetMyUserInfo(queryClient),
- prefetchGetUserFavorites(queryClient),
- prefetchListDatasources(queryClient),
- prefetchGetDatasets(queryClient),
- ]);
-
- console.log('initialLayout', initialLayout);
- console.log('user', user);
- console.log('userInfo', userInfo);
- console.log('userFavorites', userFavorites);
- console.log('listDatasources', listDatasources);
- console.log('datasets', datasets);
+ const [initialLayout, user] = await Promise.all([
+ getAppLayout({ id: PRIMARY_APP_LAYOUT_ID }),
+ getSupabaseUser(),
+ prefetchGetMyUserInfo(queryClient),
+ prefetchGetUserFavorites(queryClient),
+ prefetchListDatasources(queryClient),
+ prefetchGetDatasets(queryClient),
+ ]);
if (!user) {
throw redirect({ to: '/auth/login' });
@@ -63,8 +55,6 @@ export const Route = createFileRoute('/app')({
},
component: () => {
const { user, accessToken } = Route.useLoaderData();
- console.log('user', user);
- console.log('accessToken', accessToken);
return (
diff --git a/apps/web/src/routes/app/_settings.tsx b/apps/web/src/routes/app/_settings.tsx
index 27e4adce5..f33c6e916 100644
--- a/apps/web/src/routes/app/_settings.tsx
+++ b/apps/web/src/routes/app/_settings.tsx
@@ -6,6 +6,7 @@ const routeApi = getRouteApi('/app');
export const Route = createFileRoute('/app/_settings')({
component: () => {
const { initialLayout, layoutId, defaultLayout } = routeApi.useLoaderData();
+
return (
Hello "/app/_settings/"! ;
+}
diff --git a/apps/web/src/routes/app/healthcheck.tsx b/apps/web/src/routes/app/healthcheck.tsx
new file mode 100644
index 000000000..cd4b3da46
--- /dev/null
+++ b/apps/web/src/routes/app/healthcheck.tsx
@@ -0,0 +1,375 @@
+import type { HealthCheckResponse } from '@buster/server-shared/healthcheck';
+import { createFileRoute } from '@tanstack/react-router';
+import { useHealthcheck } from '@/api/buster_rest/healthcheck/queryRequests';
+import { useGetUserBasicInfo } from '@/api/buster_rest/users/useGetUserInfo';
+import type { RustApiError } from '@/api/errors';
+import { useGetSupabaseUser } from '@/context/Supabase';
+
+export const Route = createFileRoute('/app/healthcheck')({
+ component: RouteComponent,
+});
+
+function RouteComponent() {
+ const { data, isLoading, error } = useHealthcheck();
+ const supabaseUser = useGetSupabaseUser();
+ const user = useGetUserBasicInfo();
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (error) {
+ return ;
+ }
+
+ if (!data) {
+ return ;
+ }
+
+ return ;
+}
+
+function LoadingState() {
+ return (
+
+
+
+
Checking system health...
+
+
+ );
+}
+
+function ErrorState({ error }: { error: Error | RustApiError }) {
+ return (
+
+
+
+
+
+
Health Check Failed
+
Unable to retrieve system status
+
+
+
+
+
+ );
+}
+
+function HealthcheckDashboard({
+ data,
+ supabaseUser,
+ user,
+}: {
+ data: HealthCheckResponse;
+ supabaseUser: ReturnType;
+ user: ReturnType;
+}) {
+ const getStatusColor = (status: string) => {
+ switch (status) {
+ case 'healthy':
+ case 'pass':
+ return 'text-green-600 bg-green-100';
+ case 'degraded':
+ case 'warn':
+ return 'text-yellow-600 bg-yellow-100';
+ case 'unhealthy':
+ case 'fail':
+ return 'text-red-600 bg-red-100';
+ default:
+ return 'text-gray-600 bg-gray-100';
+ }
+ };
+
+ const getStatusIcon = (status: string) => {
+ switch (status) {
+ case 'healthy':
+ case 'pass':
+ return (
+
+ );
+ case 'degraded':
+ case 'warn':
+ return (
+
+ );
+ case 'unhealthy':
+ case 'fail':
+ return (
+
+ );
+ default:
+ return (
+
+ );
+ }
+ };
+
+ const formatUptime = (seconds: number) => {
+ const days = Math.floor(seconds / 86400);
+ const hours = Math.floor((seconds % 86400) / 3600);
+ const minutes = Math.floor((seconds % 3600) / 60);
+
+ if (days > 0) {
+ return `${days}d ${hours}h ${minutes}m`;
+ }
+ if (hours > 0) {
+ return `${hours}h ${minutes}m`;
+ }
+ return `${minutes}m`;
+ };
+
+ const formatTimestamp = (timestamp: string) => {
+ return new Date(timestamp).toLocaleString();
+ };
+
+ return (
+
+
+ {/* Header */}
+
+
System Health Dashboard
+
Real-time monitoring of system components
+
+
+ {/* User Data Section */}
+
+ {/* Supabase User Data */}
+
+
+
+ Supabase User
+
+
+
+ {JSON.stringify(supabaseUser, null, 2)}
+
+
+
+
+ {/* User Basic Info */}
+
+
+
+ User Basic Info
+
+
+
+ {JSON.stringify(user, null, 2)}
+
+
+
+
+
+ {/* Overall Status Card */}
+
+
+
+
+ {getStatusIcon(data.status)}
+
+
+
{data.status}
+
Overall System Status
+
+
+
+
Last checked
+
{formatTimestamp(data.timestamp)}
+
+
+
+
+ {/* Metrics Grid */}
+
+
+
+
+
+
Uptime
+
{formatUptime(data.uptime)}
+
+
+
+
+
+
+
+
+
Version
+
{data.version}
+
+
+
+
+
+
+
+
+
Environment
+
{data.environment}
+
+
+
+
+
+ {/* Component Checks */}
+
+
Component Health Checks
+
+ {Object.entries(data.checks).map(([componentName, check]) => (
+
+
+
+
+ {getStatusIcon(check.status)}
+
+
+
{componentName}
+ {check.message &&
{check.message}
}
+
+
+
+
+ {check.status}
+
+ {check.responseTime && (
+
{check.responseTime}ms
+ )}
+
+
+
+ ))}
+
+
+
+ {/* Footer */}
+
+
System health is monitored continuously. Data refreshes automatically.
+
+
+
+ );
+}
diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts
index 7e19ce88b..5bf7dd77b 100644
--- a/apps/web/vite.config.ts
+++ b/apps/web/vite.config.ts
@@ -10,7 +10,8 @@ const config = defineConfig(({ command, mode }) => {
const isProduction = mode === 'production' || mode === 'staging';
const isTypecheck = process.argv.includes('--typecheck') || process.env.TYPECHECK === 'true';
const useChecker = !process.env.VITEST && isBuild;
- const isLocalBuild = process.argv.includes('--local');
+ const isLocalBuild = process.argv.includes('--local') || mode === 'development';
+ const target = isLocalBuild ? ('bun' as const) : ('cloudflare-module' as const);
return {
server: { port: 3000 },
@@ -20,7 +21,7 @@ const config = defineConfig(({ command, mode }) => {
tailwindcss(),
tanstackStart({
customViteReactPlugin: true,
- target: isLocalBuild ? 'bun' : 'cloudflare-module',
+ target,
}),
viteReact(),
useChecker