Skip to content

Commit f2d47bf

Browse files
Move access token to account settings (#33)
Before this pr the user access token was accessible under "Developer Settings". Since we have docs/error messages that refer to the access token by visiting `https://e2b.dev/dashboard?tab=personal`, this pr adds: 1. tab=personal redirect to account settings page 2. access token under account settings page 3. general ui improvements around the account settings page Before: <img width="2293" alt="Screenshot 2025-04-04 at 12 09 38 PM" src="https://github.com/user-attachments/assets/98e43cec-c889-4fd2-90ec-c556a7d99dde" /> After: <img width="2311" alt="Screenshot 2025-04-04 at 12 09 29 PM" src="https://github.com/user-attachments/assets/39ec3459-19c1-4312-82b4-8c57db2cb405" />
1 parent 79eb73a commit f2d47bf

File tree

10 files changed

+120
-46
lines changed

10 files changed

+120
-46
lines changed

src/app/dashboard/account/page.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,33 @@ import { EmailSettings } from '@/features/dashboard/account/email-settings'
44
import { PasswordSettings } from '@/features/dashboard/account/password-settings'
55
import { DangerZone } from '@/features/dashboard/account/danger-zone'
66
import { Suspense } from 'react'
7+
import { AccessTokenSettings } from '@/features/dashboard/account/access-token-settings'
78

89
export default async function AccountPage() {
910
return (
1011
<DashboardPageLayout
12+
hideFrame
1113
title="Account"
12-
className="grid grid-cols-12 pb-6 max-md:pt-6 md:gap-6"
14+
className="flex flex-col gap-6"
1315
>
1416
<Suspense fallback={null}>
15-
<NameSettings className="col-span-12 md:col-span-6" />
17+
<NameSettings />
1618
</Suspense>
1719

1820
<Suspense fallback={null}>
19-
<EmailSettings className="col-span-12 md:col-span-6" />
21+
<EmailSettings />
2022
</Suspense>
2123

2224
<Suspense fallback={null}>
23-
<PasswordSettings className="col-span-12 md:col-span-6" />
25+
<AccessTokenSettings />
2426
</Suspense>
2527

2628
<Suspense fallback={null}>
27-
<DangerZone className="col-span-12 h-min md:col-span-6" />
29+
<PasswordSettings />
30+
</Suspense>
31+
32+
<Suspense fallback={null}>
33+
<DangerZone />
2834
</Suspense>
2935
</DashboardPageLayout>
3036
)

src/app/dashboard/route.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const TAB_URL_MAP: Record<string, (teamId: string) => string> = {
1414
keys: (teamId) => PROTECTED_URLS.KEYS(teamId),
1515
team: (teamId) => PROTECTED_URLS.TEAM(teamId),
1616
account: (_) => PROTECTED_URLS.ACCOUNT_SETTINGS,
17+
personal: (_) => PROTECTED_URLS.ACCOUNT_SETTINGS,
1718
}
1819

1920
export async function GET(request: NextRequest) {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use client'
2+
3+
import {
4+
Card,
5+
CardContent,
6+
CardDescription,
7+
CardFooter,
8+
CardHeader,
9+
CardTitle,
10+
} from '@/ui/primitives/card'
11+
import { useUser } from '@/lib/hooks/use-user'
12+
import { cn } from '@/lib/utils'
13+
import UserAccessToken from './user-access-token'
14+
15+
interface AccessTokenSettingsProps {
16+
className?: string
17+
}
18+
19+
export function AccessTokenSettings({ className }: AccessTokenSettingsProps) {
20+
const { user } = useUser()
21+
22+
if (!user) return null
23+
24+
return (
25+
<Card className={cn('overflow-hidden rounded-xs border', className)}>
26+
<CardHeader>
27+
<CardTitle>Access Token</CardTitle>
28+
<CardDescription>Manage your personal access token.</CardDescription>
29+
</CardHeader>
30+
31+
<CardContent>
32+
<UserAccessToken className="max-w-lg" />
33+
</CardContent>
34+
35+
<CardFooter className="bg-bg-100 justify-between gap-6">
36+
<p className="text-fg-500 text-sm">
37+
Keep it safe, as it can be used to authenticate with E2B services.
38+
</p>
39+
</CardFooter>
40+
</Card>
41+
)
42+
}

src/features/dashboard/account/danger-zone.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Card,
88
CardContent,
99
CardDescription,
10+
CardFooter,
1011
CardHeader,
1112
CardTitle,
1213
} from '@/ui/primitives/card'
@@ -49,22 +50,29 @@ export function DangerZone({ className }: DangerZoneProps) {
4950
)
5051

5152
return (
52-
<Card variant="slate" className={cn(className)}>
53+
<Card
54+
className={cn(
55+
'border-error/50 overflow-hidden rounded-xs border',
56+
className
57+
)}
58+
>
5359
<CardHeader>
5460
<CardTitle>Danger Zone</CardTitle>
5561
<CardDescription>
56-
Delete your account and all associated data.
62+
This action is irreversible. It will delete your account and all
63+
associated data.
5764
</CardDescription>
5865
</CardHeader>
5966

60-
<CardContent>
67+
<CardFooter className="bg-error/5 border-error justify-between gap-6">
68+
<p className="text-error-fg text-sm">Continue with caution.</p>
6169
<AlertDialog
6270
trigger={<Button variant="error">Delete Account</Button>}
6371
title="Delete Account"
6472
description={
6573
<>
66-
This action cannot be undone. This will permanently delete your
67-
account and remove your data from our servers.
74+
This will permanently delete your account and remove your data
75+
from our servers.
6876
</>
6977
}
7078
confirm="Delete Account"
@@ -87,7 +95,7 @@ export function DangerZone({ className }: DangerZoneProps) {
8795
/>
8896
</>
8997
</AlertDialog>
90-
</CardContent>
98+
</CardFooter>
9199
</Card>
92100
)
93101
}

src/features/dashboard/account/email-settings.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Card,
66
CardContent,
77
CardDescription,
8+
CardFooter,
89
CardHeader,
910
CardTitle,
1011
} from '@/ui/primitives/card'
@@ -102,7 +103,7 @@ export function EmailSettings({ className }: EmailSettingsProps) {
102103
if (!user) return null
103104

104105
return (
105-
<Card variant="slate" className={cn(className)}>
106+
<Card className={cn('overflow-hidden rounded-xs border', className)}>
106107
<CardHeader>
107108
<CardTitle>E-Mail</CardTitle>
108109
<CardDescription>Update your e-mail address.</CardDescription>
@@ -131,17 +132,19 @@ export function EmailSettings({ className }: EmailSettingsProps) {
131132
</FormItem>
132133
)}
133134
/>
134-
<Button
135-
loading={isPending}
136-
disabled={form.watch('email') === user?.email}
137-
type="submit"
138-
variant="outline"
139-
>
140-
Save
141-
</Button>
142135
</form>
143136
</Form>
144137
</CardContent>
138+
<CardFooter className="bg-bg-100 justify-between">
139+
<p className="text-fg-500 text-sm">Has to be a valid e-mail address.</p>
140+
<Button
141+
loading={isPending}
142+
disabled={form.watch('email') === user?.email}
143+
type="submit"
144+
>
145+
Save
146+
</Button>
147+
</CardFooter>
145148
</Card>
146149
)
147150
}

src/features/dashboard/account/name-settings.tsx

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Card,
77
CardContent,
88
CardDescription,
9+
CardFooter,
910
CardHeader,
1011
CardTitle,
1112
} from '@/ui/primitives/card'
@@ -27,7 +28,7 @@ import { useToast } from '@/lib/hooks/use-toast'
2728
import { defaultSuccessToast, defaultErrorToast } from '@/lib/hooks/use-toast'
2829

2930
const formSchema = z.object({
30-
name: z.string().min(1, 'Name cannot be empty'),
31+
name: z.string().min(1, 'Name cannot be empty').max(32, 'Max 32 characters'),
3132
})
3233

3334
type FormValues = z.infer<typeof formSchema>
@@ -66,10 +67,15 @@ export function NameSettings({ className }: NameSettingsProps) {
6667
if (!user) return null
6768

6869
return (
69-
<Card variant="slate" className={cn(className)} hideUnderline>
70+
<Card
71+
className={cn('overflow-hidden rounded-xs border', className)}
72+
hideUnderline
73+
>
7074
<CardHeader>
71-
<CardTitle>Your Name</CardTitle>
72-
<CardDescription>Will be visible to your team members.</CardDescription>
75+
<CardTitle>Name</CardTitle>
76+
<CardDescription>
77+
Update your account name, which will be visible to your team members.
78+
</CardDescription>
7379
</CardHeader>
7480
<CardContent className="flex flex-col gap-3">
7581
<Form {...form}>
@@ -91,17 +97,19 @@ export function NameSettings({ className }: NameSettingsProps) {
9197
</FormItem>
9298
)}
9399
/>
94-
<Button
95-
variant="outline"
96-
loading={isPending}
97-
disabled={form.watch('name') === user?.user_metadata?.name}
98-
type="submit"
99-
>
100-
Save
101-
</Button>
102100
</form>
103101
</Form>
104102
</CardContent>
103+
<CardFooter className="bg-bg-100 justify-between">
104+
<p className="text-fg-500 text-sm">Max 32 characters.</p>
105+
<Button
106+
loading={isPending}
107+
disabled={form.watch('name') === user?.user_metadata?.name}
108+
type="submit"
109+
>
110+
Save
111+
</Button>
112+
</CardFooter>
105113
</Card>
106114
)
107115
}

src/features/dashboard/account/password-settings.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Card,
66
CardContent,
77
CardDescription,
8+
CardFooter,
89
CardHeader,
910
CardTitle,
1011
} from '@/ui/primitives/card'
@@ -41,15 +42,14 @@ export function PasswordSettings({ className }: PasswordSettingsProps) {
4142
if (!user) return null
4243

4344
return (
44-
<Card variant="slate" className={cn(className)}>
45+
<Card className={cn('overflow-hidden rounded-xs border', className)}>
4546
<CardHeader>
4647
<CardTitle>Password</CardTitle>
47-
<CardDescription>
48-
Change your account password used to sign in.
49-
</CardDescription>
48+
<CardDescription>Change your account password.</CardDescription>
5049
</CardHeader>
5150

52-
<CardContent>
51+
<CardFooter className="bg-bg-100 justify-between gap-6">
52+
<p className="text-fg-500 text-sm">Sends a reset link.</p>
5353
<Button
5454
variant="outline"
5555
onClick={() => {
@@ -65,7 +65,7 @@ export function PasswordSettings({ className }: PasswordSettingsProps) {
6565
>
6666
Change Password
6767
</Button>
68-
</CardContent>
68+
</CardFooter>
6969
</Card>
7070
)
7171
}

src/features/dashboard/developer-settings/user-access-token.tsx renamed to src/features/dashboard/account/user-access-token.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ export default function UserAccessToken({ className }: UserAccessTokenProps) {
3939

4040
return (
4141
<div className={className}>
42-
<div className="flex h-5 items-center gap-2">
43-
<Label>Access Token</Label>
44-
<HelpTooltip>
45-
Your personal access token for authenticating with E2B services.
46-
</HelpTooltip>
47-
</div>
4842
<div className="mt-2 flex items-center">
4943
<Input
5044
type={isVisible ? 'text' : 'password'}

src/features/dashboard/developer-settings/settings-dialog.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
DialogTrigger,
1111
} from '@/ui/primitives/dialog'
1212
import InfraDomainForm from './infra-domain-form'
13-
import UserAccessToken from './user-access-token'
1413

1514
interface DeveloperSettingsDialogProps extends DialogProps {
1615
apiDomain?: string
@@ -33,7 +32,6 @@ export default function DeveloperSettingsDialog({
3332
</DialogDescription>
3433
</DialogHeader>
3534
<InfraDomainForm apiDomain={apiDomain} className="py-6" />
36-
<UserAccessToken className="py-6" />
3735
</DialogContent>
3836
</Dialog>
3937
)

src/features/dashboard/page-layout.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ interface DashboardPageLayoutProps {
1111
title: string
1212
className?: string
1313
fullscreen?: boolean
14+
hideFrame?: boolean
1415
classNames?: {
1516
frameWrapper?: string
1617
}
@@ -22,6 +23,7 @@ export default async function DashboardPageLayout({
2223
className,
2324
classNames,
2425
fullscreen = false,
26+
hideFrame = false,
2527
}: DashboardPageLayoutProps) {
2628
return (
2729
<div
@@ -49,6 +51,7 @@ export default async function DashboardPageLayout({
4951
fullscreen={fullscreen}
5052
classNames={classNames}
5153
className={className}
54+
hideFrame={hideFrame}
5255
>
5356
{children}
5457
</DesktopContent>
@@ -65,13 +68,15 @@ interface ContentProps {
6568
}
6669
className?: string
6770
fullscreen?: boolean
71+
hideFrame?: boolean
6872
}
6973

7074
function DesktopContent({
7175
children,
7276
classNames,
7377
className,
7478
fullscreen,
79+
hideFrame,
7580
}: ContentProps) {
7681
return (
7782
<div
@@ -84,6 +89,15 @@ function DesktopContent({
8489
>
8590
{fullscreen ? (
8691
<div className={cn('h-full', className)}>{children}</div>
92+
) : hideFrame ? (
93+
<div
94+
className={cn(
95+
'relative flex h-fit w-full max-w-[1200px] pb-2',
96+
className
97+
)}
98+
>
99+
{children}
100+
</div>
87101
) : (
88102
<Frame
89103
classNames={{

0 commit comments

Comments
 (0)