Skip to content

Commit f81012a

Browse files
committed
fix(cloud): redirect to tasks when initial login (#3064)
### TL;DR Added custom error handling, 404 pages, and improved the onboarding flow with organization selection. ### What changed? - Added a custom 404 page with a "Go home" button - Created a centralized `RouteError` component for consistent error handling across routes - Added an onboarding flow with organization selection - Removed the standalone organizations index page in favor of the new onboarding flow - Enhanced the `FullscreenLoading` component to accept children - Fixed UI issues in the user dropdown by adding truncation to long usernames - Added fallback text for unknown projects and namespaces - Added Clerk task URLs for organization selection - Improved the project selection UI with better layout and styling ### How to test? 1. Test the 404 page by navigating to a non-existent route 2. Test error handling by triggering API errors 3. Test the onboarding flow by signing up as a new user 4. Verify that long usernames are properly truncated in the user dropdown 5. Check that the organization selection flow works correctly 6. Verify that the "Unknown Project" and "Unknown Namespace" fallbacks appear when appropriate ### Why make this change? These changes improve the user experience by providing better error handling and a more streamlined onboarding process. The custom 404 page and error components create a more consistent and user-friendly experience when errors occur. The new onboarding flow with organization selection makes it easier for new users to get started with the platform. UI improvements like text truncation and fallback text enhance usability and prevent layout issues.
1 parent 3072ed6 commit f81012a

File tree

16 files changed

+265
-299
lines changed

16 files changed

+265
-299
lines changed

frontend/src/app.tsx

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@ import type { Clerk } from "@clerk/clerk-js";
22
import * as Sentry from "@sentry/react";
33
import { QueryClientProvider } from "@tanstack/react-query";
44
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
5-
import { createRouter, RouterProvider } from "@tanstack/react-router";
5+
import { createRouter, Link, RouterProvider } from "@tanstack/react-router";
66
import { Suspense } from "react";
77
import {
8+
Button,
9+
Card,
10+
CardContent,
11+
CardDescription,
12+
CardHeader,
13+
CardTitle,
814
ConfigProvider,
915
FullscreenLoading,
1016
getConfig,
17+
H2,
1118
ThirdPartyProviders,
1219
Toaster,
1320
TooltipProvider,
1421
} from "@/components";
22+
import { RouteLayout } from "./app/route-layout";
23+
import { RootLayout } from "./components/layout";
1524
import { clerk } from "./lib/auth";
1625
import { queryClient } from "./queries/global";
1726
import { routeTree } from "./routeTree.gen";
@@ -49,6 +58,31 @@ export const router = createRouter({
4958
console.error("Router caught an error:", error);
5059
Sentry.captureException(error);
5160
},
61+
defaultNotFoundComponent: () => (
62+
<RouteLayout>
63+
<div className="bg-card h-full border my-2 mr-2 rounded-lg">
64+
<div className="mt-2 flex flex-col items-center justify-center h-full">
65+
<div className="w-full sm:w-96">
66+
<Card>
67+
<CardHeader>
68+
<CardTitle className="flex items-center">
69+
404
70+
</CardTitle>
71+
<CardDescription>
72+
The page was not found
73+
</CardDescription>
74+
</CardHeader>
75+
<CardContent>
76+
<Button asChild variant="secondary">
77+
<Link to="/">Go home</Link>
78+
</Button>
79+
</CardContent>
80+
</Card>
81+
</div>
82+
</div>
83+
</div>
84+
</RouteLayout>
85+
),
5286
});
5387

5488
function InnerApp() {

frontend/src/app/context-switcher.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,11 @@ function ProjectBreadcrumb({
132132
return <Skeleton className={cn("h-5 w-32", className)} />;
133133
}
134134

135-
return <span className={className}>{data?.displayName}</span>;
135+
return (
136+
<span className={className}>
137+
{data?.displayName || "Unknown Project"}
138+
</span>
139+
);
136140
}
137141

138142
function NamespaceBreadcrumb({
@@ -154,7 +158,11 @@ function NamespaceBreadcrumb({
154158
return <Skeleton className="h-5 w-32" />;
155159
}
156160

157-
return <span className={className}>{data?.displayName}</span>;
161+
return (
162+
<span className={className}>
163+
{data?.displayName || "Unknown Namespace"}
164+
</span>
165+
);
158166
}
159167

160168
function Content({ onClose }: { onClose?: () => void }) {

frontend/src/app/route-error.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { type ErrorComponentProps, Link } from "@tanstack/react-router";
2+
import {
3+
Button,
4+
Card,
5+
CardContent,
6+
CardDescription,
7+
CardHeader,
8+
CardTitle,
9+
} from "@/components";
10+
import { RouteLayout } from "./route-layout";
11+
12+
export const RouteError = ({ error }: ErrorComponentProps) => {
13+
return (
14+
<RouteLayout>
15+
<div className="bg-card h-full border my-2 mr-2 rounded-lg">
16+
<div className="mt-2 flex flex-col items-center justify-center h-full">
17+
<div className="w-full sm:w-96">
18+
<Card>
19+
<CardHeader>
20+
<CardTitle className="flex items-center">
21+
{"statusCode" in error &&
22+
error.statusCode === 404
23+
? "Resource not found"
24+
: "body" in error &&
25+
error.body &&
26+
typeof error.body ===
27+
"object" &&
28+
"message" in error.body
29+
? String(error.body.message)
30+
: error.message}
31+
</CardTitle>
32+
<CardDescription>
33+
{"statusCode" in error &&
34+
error.statusCode === 404
35+
? "The resource you are looking for does not exist or you do not have access to it."
36+
: "An unexpected error occurred. Please try again later."}
37+
</CardDescription>
38+
</CardHeader>
39+
<CardContent>
40+
<Button asChild variant="secondary">
41+
<Link to="." reloadDocument>
42+
Retry
43+
</Link>
44+
</Button>
45+
</CardContent>
46+
</Card>
47+
</div>
48+
</div>
49+
</div>
50+
</RouteLayout>
51+
);
52+
};

frontend/src/app/user-dropdown.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ function Preview({ org }: { org: string }) {
131131
className="text-muted-foreground justify-between py-1 min-h-8 gap-2 w-full"
132132
endIcon={<Icon icon={faChevronDown} />}
133133
>
134-
<div className="flex gap-2 items-center w-full">
134+
<div className="flex gap-2 items-center w-full min-w-0">
135135
<Avatar className="size-5">
136136
<AvatarImage src={data?.imageUrl} />
137137
<AvatarFallback>
@@ -142,11 +142,13 @@ function Preview({ org }: { org: string }) {
142142
)}
143143
</AvatarFallback>
144144
</Avatar>
145-
{isLoading ? (
146-
<Skeleton className="w-full h-4 flex-1" />
147-
) : (
148-
data?.name
149-
)}
145+
<span className="text-sm truncate">
146+
{isLoading ? (
147+
<Skeleton className="w-full h-4 flex-1" />
148+
) : (
149+
data?.name
150+
)}
151+
</span>
150152
</div>
151153
</Button>
152154
);
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import { AssetImage } from "./asset-image";
22

3-
export function FullscreenLoading() {
3+
export function FullscreenLoading({
4+
children,
5+
}: {
6+
children?: React.ReactNode;
7+
}) {
48
return (
5-
<div className="min-h-screen flex items-center justify-center">
9+
<div className="min-h-screen flex items-center justify-center flex-col">
610
<AssetImage
711
className="animate-pulse h-10"
812
src="/logo/icon-white.svg"
913
/>
14+
{children}
1015
</div>
1116
);
1217
}

0 commit comments

Comments
 (0)