Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 58 additions & 18 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,24 +1,64 @@
# Uncomment according to src/lib/env.ts
# =================================
# REQUIRED SERVER ENVIRONMENT VARIABLES
# =================================
# Supabase service role key for admin operations
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key

# KV_URL=
# KV_REST_API_READ_ONLY_TOKEN=
# KV_REST_API_TOKEN=
# KV_REST_API_URL=
# SUPABASE_SERVICE_ROLE_KEY=
# COOKIE_ENCRYPTION_KEY=
# Key for encrypting cookies - must be at least 32 characters long
COOKIE_ENCRYPTION_KEY=your_secure_cookie_encryption_key_here

BILLING_API_URL=https://billing.e2b.dev
# KV database configuration
KV_URL=
KV_REST_API_READ_ONLY_TOKEN=
KV_REST_API_TOKEN=
KV_REST_API_URL=

# NEXT_PUBLIC_POSTHOG_KEY=
# NEXT_PUBLIC_SUPABASE_URL=
# NEXT_PUBLIC_SUPABASE_ANON_KEY=
# NEXT_PUBLIC_STRIPE_BILLING_URL=
# =================================
# REQUIRED CLIENT ENVIRONMENT VARIABLES
# =================================
# Supabase URL and anon key for client-side operations
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key

# API domain for your application
NEXT_PUBLIC_DEFAULT_API_DOMAIN=e2b.dev

# Set to 1 to expose
NEXT_PUBLIC_EXPOSE_STORYBOOK=0
NEXT_PUBLIC_SCAN=0
NEXT_PUBLIC_MOCK_DATA=0
# =================================
# OPTIONAL SERVER ENVIRONMENT VARIABLES
# =================================
# Billing API URL (Required if NEXT_PUBLIC_INCLUDE_BILLING=1)
# BILLING_API_URL=https://billing.e2b.dev

# Vercel URL (automatically set in Vercel deployments)
# VERCEL_URL=

# Development infrastructure API domain
# DEVELOPMENT_INFRA_API_DOMAIN=

# Sentry authentication token for error reporting
# SENTRY_AUTH_TOKEN=

# ZeroBounce API key for email validation
# ZEROBOUNCE_API_KEY=

# =================================
# OPTIONAL CLIENT ENVIRONMENT VARIABLES
# =================================
# PostHog analytics key
# NEXT_PUBLIC_POSTHOG_KEY=

# Enable billing features: set to 1 to enable
# When enabled, both BILLING_API_URL and NEXT_PUBLIC_STRIPE_BILLING_URL must be provided
# NEXT_PUBLIC_INCLUDE_BILLING=0

# Stripe billing URL (Required if NEXT_PUBLIC_INCLUDE_BILLING=1)
# NEXT_PUBLIC_STRIPE_BILLING_URL=https://billing.stripe.com/your-path

# Set to 1 to expose Storybook
# NEXT_PUBLIC_EXPOSE_STORYBOOK=0

# Set to 1 to enable scanning
# NEXT_PUBLIC_SCAN=0

# For applying migrations
# POSTGRES_CONNECTION_STRING=
# Set to 1 to use mock data
# NEXT_PUBLIC_MOCK_DATA=0
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"<<<<<< Development": "",
"storybook": "storybook dev -p 6006",
"shad": "bunx shadcn@canary",
"prebuild": "bun scripts:build-storybook",
"prebuild": "bun scripts:check-app-env && bun scripts:build-storybook",
"postinstall": "fumadocs-mdx",
"<<<<<< Testing": "",
"test:run": "bun scripts:check-all-env && vitest run",
Expand Down
17 changes: 16 additions & 1 deletion scripts/check-app-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,19 @@ import { loadEnvConfig } from '@next/env'
const projectDir = process.cwd()
loadEnvConfig(projectDir)

validateEnv(serverSchema.merge(clientSchema))
const schema = serverSchema.merge(clientSchema).refine(
(data) => {
if (data.NEXT_PUBLIC_INCLUDE_BILLING === '1') {
return !!data.BILLING_API_URL && !!data.NEXT_PUBLIC_STRIPE_BILLING_URL
}

return true
},
{
message:
'NEXT_PUBLIC_INCLUDE_BILLING is enabled, but either BILLING_API_URL or NEXT_PUBLIC_STRIPE_BILLING_URL is missing',
path: ['BILLING_API_URL', 'NEXT_PUBLIC_STRIPE_BILLING_URL'],
}
)

validateEnv(schema)
8 changes: 1 addition & 7 deletions src/app/dashboard/[teamIdOrSlug]/usage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,7 @@ async function UsagePageContent({ teamId }: { teamId: string }) {
const res = await getUsage({ teamId })

if (!res?.data || res.serverError || res.validationErrors) {
return (
<ErrorIndicator
description={'Could not load usage'}
message={res?.serverError || 'Unknown error'}
className="col-span-1 min-h-[360px] border-b lg:col-span-12"
/>
)
throw new Error(res?.serverError || 'Failed to load usage')
}

const data = res.data
Expand Down
9 changes: 6 additions & 3 deletions src/app/dashboard/error.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
'use client'

import { UnknownError } from '@/types/errors'
import ErrorBoundary from '@/ui/error'

export default function DashboardError() {
export default function DashboardError({
error,
}: {
error: Error & { digest?: string }
}) {
return (
<ErrorBoundary
error={UnknownError()}
error={error}
description={'An Unexpected Error Occurred'}
className="min-h-svh"
/>
Expand Down
18 changes: 13 additions & 5 deletions src/app/error.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
'use client'

import { createErrorBoundary } from '@/lib/create-error-boundary'
import ErrorBoundary from '@/ui/error'

export default createErrorBoundary({
title: 'Something went wrong',
description: 'An unexpected error occurred',
})
export default function Error({
error,
}: {
error: Error & { digest?: string }
}) {
return (
<ErrorBoundary
description="Sorry, something went wrong with the application."
error={error}
/>
)
}
8 changes: 3 additions & 5 deletions src/app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
'use client'

import { SentryErrorBoundary } from '@/ui/sentry-error-boundary'
import ErrorBoundary from '@/ui/error'

export default function GlobalError({
error,
}: {
error: Error & { digest?: string }
}) {
return (
<SentryErrorBoundary
error={error}
title="Application Error"
<ErrorBoundary
description="Sorry, something went wrong with the application."
preserveLayout={false}
error={error}
/>
)
}
47 changes: 30 additions & 17 deletions src/configs/dashboard-navs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Users,
} from 'lucide-react'
import { ForwardRefExoticComponent, RefAttributes } from 'react'
import { INCLUDE_BILLING } from './flags'

type DashboardNavLinkArgs = {
teamIdOrSlug?: string
Expand All @@ -35,11 +36,16 @@ export const MAIN_DASHBOARD_LINKS: DashboardNavLink[] = [
href: (args) => `/dashboard/${args.teamIdOrSlug}/templates`,
icon: Container,
},
{
label: 'Usage',
href: (args) => `/dashboard/${args.teamIdOrSlug}/usage`,
icon: Activity,
},
...(INCLUDE_BILLING
? [
{
label: 'Usage',
href: (args: DashboardNavLinkArgs) =>
`/dashboard/${args.teamIdOrSlug}/usage`,
icon: Activity,
},
]
: []),

{
label: 'Team',
Expand All @@ -53,16 +59,23 @@ export const MAIN_DASHBOARD_LINKS: DashboardNavLink[] = [
icon: Key,
group: 'manage',
},
{
label: 'Billing',
href: (args) => `/dashboard/${args.teamIdOrSlug}/billing`,
icon: CreditCard,
group: 'expenses',
},
{
label: 'Budget',
href: (args) => `/dashboard/${args.teamIdOrSlug}/budget`,
group: 'expenses',
icon: DollarSign,
},

...(INCLUDE_BILLING
? [
{
label: 'Billing',
href: (args: DashboardNavLinkArgs) =>
`/dashboard/${args.teamIdOrSlug}/billing`,
icon: CreditCard,
group: 'expenses',
},
{
label: 'Budget',
href: (args: DashboardNavLinkArgs) =>
`/dashboard/${args.teamIdOrSlug}/budget`,
group: 'expenses',
icon: DollarSign,
},
]
: []),
]
1 change: 1 addition & 0 deletions src/configs/flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const INCLUDE_BILLING = process.env.NEXT_PUBLIC_INCLUDE_BILLING === '1'
4 changes: 4 additions & 0 deletions src/features/client-providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export default function ClientProviders({ children }: ClientProvidersProps) {

export function PostHogProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
if (!process.env.NEXT_PUBLIC_POSTHOG_KEY) {
return
}

posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
// Note that PostHog will automatically capture page views and common events
//
Expand Down
11 changes: 1 addition & 10 deletions src/features/dashboard/billing/credits-content.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getUsage } from '@/server/usage/get-usage'
import { ErrorIndicator } from '@/ui/error-indicator'

export default async function BillingCreditsContent({
teamId,
Expand All @@ -9,15 +8,7 @@ export default async function BillingCreditsContent({
const res = await getUsage({ teamId })

if (!res?.data || res.serverError) {
return (
<div className="p-4 pb-0">
<ErrorIndicator
description={'Could not load credits'}
message={res?.serverError || 'Unknown error'}
className="bg-bg w-full max-w-full"
/>
</div>
)
throw new Error(res?.serverError || 'Failed to load credits')
}

const usage = res.data
Expand Down
12 changes: 1 addition & 11 deletions src/features/dashboard/budget/usage-limits.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { getBillingLimits } from '@/server/billing/get-billing-limits'
import LimitCard from './limit-card'
import AlertCard from './alert-card'
import { cn } from '@/lib/utils'
import Dotted from '@/ui/dotted'
import { ErrorIndicator } from '@/ui/error-indicator'

interface UsageLimitsProps {
className?: string
Expand All @@ -17,15 +15,7 @@ export default async function UsageLimits({
const res = await getBillingLimits({ teamId })

if (!res?.data || res.serverError || res.validationErrors) {
return (
<div className="p-4">
<ErrorIndicator
description={'Could not load usage limits'}
message={res?.serverError || 'Unknown error'}
className="w-full max-w-full"
/>
</div>
)
throw new Error(res?.serverError || 'Failed to load usage limits')
}

const limits = res.data
Expand Down
21 changes: 13 additions & 8 deletions src/features/dashboard/page-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Suspense } from 'react'
import SidebarMobile from './sidebar/sidebar-mobile'
import Frame from '@/ui/frame'
import { DashboardSurveyPopover } from './navbar/dashboard-survey-popover'
import { ErrorBoundary } from 'react-error-boundary'
import E2BErrorBoundary, { CatchErrorBoundary } from '@/ui/error'
import { UnknownError } from '@/types/errors'

interface DashboardPageLayoutProps {
children: React.ReactNode
Expand Down Expand Up @@ -43,14 +46,16 @@ export default async function DashboardPageLayout({
</div>
</div>

<DesktopContent
fullscreen={fullscreen}
classNames={classNames}
className={className}
>
{children}
</DesktopContent>
<MobileContent className={className}>{children}</MobileContent>
<CatchErrorBoundary>
<DesktopContent
fullscreen={fullscreen}
classNames={classNames}
className={className}
>
{children}
</DesktopContent>
<MobileContent className={className}>{children}</MobileContent>
</CatchErrorBoundary>
</div>
)
}
Expand Down
40 changes: 0 additions & 40 deletions src/lib/create-error-boundary.tsx

This file was deleted.

Loading