import type React from "react" import Link from "next/link" import { Card, CardContent } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { AuthMethodSelector } from "@/app/components/authMethodSelector" import { SourcebotLogo } from "@/app/components/sourcebotLogo" import { auth } from "@/auth"; import { getIdentityProviderMetadata } from "@/lib/identityProviders"; import { OrganizationAccessSettings } from "@/app/components/organizationAccessSettings"; import { CompleteOnboardingButton } from "./components/completeOnboardingButton"; import { getOrgFromDomain } from "@/data/org"; import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"; import { prisma } from "@/prisma"; import { OrgRole } from "@sourcebot/db"; import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch"; import { redirect } from "next/navigation"; import { BetweenHorizontalStart, Brain, GitBranchIcon, LockIcon } from "lucide-react"; import { hasEntitlement } from "@sourcebot/shared"; import { env } from "@/env.mjs"; import { GcpIapAuth } from "@/app/[domain]/components/gcpIapAuth"; interface OnboardingProps { searchParams?: Promise<{ step?: string }>; } interface OnboardingStep { id: string title: string subtitle: React.ReactNode component: React.ReactNode } interface ResourceCard { id: string title: string description: string href: string icon?: React.ReactNode } export default async function Onboarding(props: OnboardingProps) { const searchParams = await props.searchParams; const providers = getIdentityProviderMetadata(); const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN); const session = await auth(); if (!org) { return
Error loading organization
; } if (org && org.isOnboarded) { redirect('/'); } // Check if user is authenticated but not the owner if (session?.user) { if (org) { const membership = await prisma.userToOrg.findUnique({ where: { orgId_userId: { orgId: org.id, userId: session.user.id } } }); if (!membership || membership.role !== OrgRole.OWNER) { return ; } } } // If we're using an IAP bridge we need to sign them in now and then redirect them back to the onboarding page const ssoEntitlement = await hasEntitlement("sso"); if (ssoEntitlement && env.AUTH_EE_GCP_IAP_ENABLED && env.AUTH_EE_GCP_IAP_AUDIENCE) { return ; } // Determine current step based on URL parameter and authentication state const stepParam = searchParams?.step ? parseInt(searchParams.step) : 0; const currentStep = session?.user ? Math.max(2, stepParam) : Math.max(0, Math.min(stepParam, 1)); const resourceCards: ResourceCard[] = [ { id: "code-host-connections", title: "Code Host Connections", description: "Learn how to index repos across Sourcebot's supported platforms", href: "https://docs.sourcebot.dev/docs/connections/overview", icon: , }, { id: "language-models", title: "Language Models", description: "Learn how to configure your language model providers to start using Ask Sourcebot", href: "https://docs.sourcebot.dev/docs/configuration/language-model-providers", icon: , }, { id: "authentication-system", title: "Authentication System", description: "Learn how to setup additional auth providers, invite members, and more", href: "https://docs.sourcebot.dev/docs/configuration/auth", icon: , }, { id: "mcp-server", title: "MCP Server", description: "Learn how to setup Sourcebot's MCP server to provide code context to your AI agents", href: "https://docs.sourcebot.dev/docs/features/mcp-server", icon: , } ] const steps: OnboardingStep[] = [ { id: "welcome", title: "Welcome to Sourcebot", subtitle: "This onboarding flow will guide you through creating your owner account and configuring your organization.", component: (
), }, { id: "owner-signup", title: "Create Owner Account", subtitle: ( <> Use your preferred authentication method to create your owner account. To set up additional authentication providers, check out our{" "} documentation . ), component: (
), }, { id: "configure-org", title: "Configure Access Settings", subtitle: ( <> Set up your organization's access settings.{" "} Learn more ), component: (
), }, { id: "complete", title: "You're All Set!", subtitle: ( <> Your Sourcebot deployment is ready. Check out these resources to learn how to get the most out of Sourcebot.
), component: ( ), }, ] const currentStepData = steps[currentStep] return (
{/* Left Panel - Progress & Branding */}
{/* Step Progress Indicators */}
{steps.map((step, index) => (
{/* Connecting line */} {index < steps.length - 1 && (
)} {/* Circle - positioned above the line with z-index */}
{index < currentStep ? ( ) : ( {index + 1} )}
{step.title}
))}
{/* Footer */}

Need help? Check out our{" "} documentation {" "} or{" "} reach out .

{/* Right Panel - Content */}
{/* Step Header */}
Step {currentStep + 1} of {steps.length}

{currentStepData.title}

{currentStepData.subtitle}
{/* Step Content */}
{currentStepData.component}
) } function NonOwnerOnboardingMessage() { return (

Onboarding In Progress

Your Sourcebot deployment is being configured by the organization owner.

Owner Access Required

Only the organization owner can complete the initial setup and configuration. Once onboarding is complete, you'll be able to access Sourcebot.

Need help? Contact your organization owner or check out our{" "} documentation .
); }