Skip to content

various changes to add terms and security info #225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 4, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { CodeHostIconButton } from "../../components/codeHostIconButton";
import useCaptureEvent from "@/hooks/useCaptureEvent";
import { useSession } from "next-auth/react";
import posthog from "posthog-js";
import SecurityCard from "@/app/components/securityCard";

interface ConnectCodeHostProps {
nextStep: OnboardingSteps;
Expand Down Expand Up @@ -48,7 +49,10 @@ export const ConnectCodeHost = ({ nextStep }: ConnectCodeHostProps) => {

if (!selectedCodeHost) {
return (
<CodeHostSelection onSelect={setSelectedCodeHost} />
<>
<CodeHostSelection onSelect={setSelectedCodeHost} />
<SecurityCard />
</>
)
}

Expand Down
39 changes: 39 additions & 0 deletions packages/web/src/app/[domain]/onboard/components/demoCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use client"

import { ExternalLink } from "lucide-react"
import Link from "next/link"

import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import useCaptureEvent from "@/hooks/useCaptureEvent"

export default function DemoCard() {
const captureEvent = useCaptureEvent();

return (
<Card className="mb-6 w-full border bg-card text-card-foreground">
<CardContent className="p-4">
<div className="flex flex-col space-y-4">
<div className="flex items-center justify-between">
<div className="space-y-1">
<h3 className="text-sm font-medium">New to Sourcebot?</h3>
<p className="text-xs text-muted-foreground">Try our public demo before creating an account</p>
</div>

<Button asChild variant="outline" size="sm" className="h-8 text-xs">
<Link
href="https://sourcebot.dev/search"
target="_blank"
className="flex items-center gap-1.5"
onClick={() => captureEvent('wa_demo_card_click', {})}
>
Try demo
<ExternalLink className="h-3.5 w-3.5" />
</Link>
</Button>
</div>
</div>
</CardContent>
</Card>
)
}
2 changes: 2 additions & 0 deletions packages/web/src/app/[domain]/onboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { InviteTeam } from "./components/inviteTeam";
import { CompleteOnboarding } from "./components/completeOnboarding";
import { Checkout } from "./components/checkout";
import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch";
import SecurityCard from "@/app/components/securityCard";

interface OnboardProps {
params: {
domain: string
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/app/[domain]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { UpgradeToast } from "./components/upgradeToast";
import Link from "next/link";
import { getOrgFromDomain } from "@/data/org";
import { PageNotFound } from "./components/pageNotFound";
import { Footer } from "./components/footer";
import { Footer } from "@/app/components/footer";
import { SourcebotLogo } from "../components/sourcebotLogo";
import { RepositorySnapshot } from "./components/repositorySnapshot";
import { KeyboardShortcutHint } from "./components/keyboardShortcutHint";
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/app/[domain]/repos/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default async function ReposPage({ params: { domain } }: { params: { doma
<Header>
<h1 className="text-3xl">Repositories</h1>
</Header>
<div className="h-screen flex flex-col items-center">
<div className="flex flex-col items-center">
<div className="w-full">
<RepositoryTable />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export function Footer() {
<footer className="w-full mt-auto py-4 flex flex-row justify-center items-center gap-4">
<Link href="https://sourcebot.dev" className="text-gray-400 text-sm hover:underline">About</Link>
<Separator orientation="vertical" className="h-4" />
<Link href="https://github.com/sourcebot-dev/sourcebot/issues/new" className="text-gray-400 text-sm hover:underline">Support</Link>
<Link href="https://sourcebot.dev/terms" className="text-gray-400 text-sm hover:underline">Terms</Link>
<Separator orientation="vertical" className="h-4" />
<Link href="https://sourcebot.dev/security" className="text-gray-400 text-sm hover:underline">Security</Link>
<Separator orientation="vertical" className="h-4" />
<Link href="mailto:team@sourcebot.dev" className="text-gray-400 text-sm hover:underline">Contact Us</Link>
</footer>
Expand Down
86 changes: 86 additions & 0 deletions packages/web/src/app/components/securityCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"use client"

import Link from "next/link"
import { Shield, Lock, CheckCircle, ExternalLink, Mail } from "lucide-react"
import useCaptureEvent from "@/hooks/useCaptureEvent"

export default function SecurityCard() {
const captureEvent = useCaptureEvent();

return (
<div className="mt-12 max-w-md mx-auto text-center">
<div className="bg-backgroundSecondary border border-[#1E2A3A] rounded-lg p-6 shadow-lg">
<div className="flex justify-center mb-4">
<Shield className="h-10 w-10 text-[#9D5CFF]" />
</div>
<h3 className="text-xl font-semibold mb-3">Multi-Layered Security</h3>
<p className="text-[#A1A1AA] mb-6">
We take the security and privacy of your data seriously. All code and secret tokens you provide are protected
using multiple layers of security.
</p>

<div className="space-y-4 mb-5">
<div className="flex items-start">
<CheckCircle className="h-5 w-5 text-[#9D5CFF] mr-3 mt-0.5 flex-shrink-0" />
<span className="text-sm text-foregroundSecondary text-left">
All data is stored on Google Cloud Platform in the United States (us-west-1)
</span>
</div>

<div className="flex items-start">
<CheckCircle className="h-5 w-5 text-[#9D5CFF] mr-3 mt-0.5 flex-shrink-0" />
<span className="text-sm text-foregroundSecondary text-left">
All data is encrypted in transit using TLS 1.2+, and at rest using AES-256
</span>
</div>

<div className="flex items-start">
<CheckCircle className="h-5 w-5 text-[#9D5CFF] mr-3 mt-0.5 flex-shrink-0" />
<div className="text-sm text-foregroundSecondary text-left">
<div className="flex items-center">
<span>Sourcebot is open-source and trusted by thousands of developers</span>
<Link
href="https://github.com/sourcebot-dev/sourcebot"
target="_blank"
className="inline-flex items-center ml-2 text-[#9D5CFF] hover:text-[#B47EFF] transition-colors"
>
<svg
className="h-4 w-4 mr-0.5"
fill="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
<ExternalLink className="h-3 w-3" />
</Link>
</div>
</div>
</div>
</div>

<div className="text-sm text-[#A1A1AA] mb-5">
Have questions?
<Link
href="mailto:team@sourcebot.dev"
className="inline-flex items-center ml-2 text-[#9D5CFF] hover:text-[#B47EFF] transition-colors"
>
<Mail className="h-3.5 w-3.5 mr-1" />
<span>Get in touch</span>
</Link>
</div>

<Link
href="https://sourcebot.dev/security"
target="_blank"
className="inline-flex items-center justify-center px-5 py-2.5 rounded-md bg-backgroundSecondary border border-[#1E2A3A] text-foreground hover:bg-backgroundSecondary/80 transition-colors"
onClick={() => captureEvent('wa_security_page_click', {})}
>
<Lock className="h-4 w-4 mr-2" />
<span>Learn about our security measures</span>
</Link>
</div>
</div>
)
}

5 changes: 4 additions & 1 deletion packages/web/src/app/login/components/loginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { CredentialsForm } from "./credentialsForm";
import { SourcebotLogo } from "@/app/components/sourcebotLogo";
import { TextSeparator } from "@/app/components/textSeparator";
import useCaptureEvent from "@/hooks/useCaptureEvent";

import DemoCard from "@/app/[domain]/onboard/components/demoCard";
interface LoginFormProps {
callbackUrl?: string;
error?: string;
Expand Down Expand Up @@ -52,6 +52,9 @@ export const LoginForm = ({ callbackUrl, error, enabledMethods }: LoginFormProps
/>
<h2 className="text-lg font-bold text-center">Sign in to your account</h2>
</div>
<div className="w-full sm:w-[500px] max-w-[500px]">
<DemoCard />
</div>
<Card className="flex flex-col items-center border p-6 sm:p-12 rounded-lg gap-4 sm:gap-6 w-full sm:w-[500px] max-w-[500px] bg-background">
{error && (
<div className="text-sm text-destructive text-center text-wrap border p-2 rounded-md border-destructive">
Expand Down
41 changes: 23 additions & 18 deletions packages/web/src/app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { auth } from "@/auth";
import { LoginForm } from "./components/loginForm";
import { redirect } from "next/navigation";
import { getProviders } from "@/auth";
import { Footer } from "@/app/components/footer";

interface LoginProps {
searchParams: {
callbackUrl?: string;
Expand All @@ -18,26 +20,29 @@ export default async function Login({ searchParams }: LoginProps) {
const providers = getProviders();
const providerMap = providers
.map((provider) => {
if (typeof provider === "function") {
const providerData = provider()
return { id: providerData.id, name: providerData.name }
} else {
return { id: provider.id, name: provider.name }
}
});
if (typeof provider === "function") {
const providerData = provider()
return { id: providerData.id, name: providerData.name }
} else {
return { id: provider.id, name: provider.name }
}
});

return (
<div className="flex flex-col items-center p-4 sm:p-12 min-h-screen w-full bg-backgroundSecondary">
<LoginForm
callbackUrl={searchParams.callbackUrl}
error={searchParams.error}
enabledMethods={{
github: providerMap.some(provider => provider.id === "github"),
google: providerMap.some(provider => provider.id === "google"),
magicLink: providerMap.some(provider => provider.id === "nodemailer"),
credentials: providerMap.some(provider => provider.id === "credentials"),
}}
/>
<div className="flex flex-col min-h-screen">
<div className="flex-1 flex flex-col items-center p-4 sm:p-12 w-full bg-backgroundSecondary">
<LoginForm
callbackUrl={searchParams.callbackUrl}
error={searchParams.error}
enabledMethods={{
github: providerMap.some(provider => provider.id === "github"),
google: providerMap.some(provider => provider.id === "google"),
magicLink: providerMap.some(provider => provider.id === "nodemailer"),
credentials: providerMap.some(provider => provider.id === "credentials"),
}}
/>
</div>
<Footer />
</div>
)
}
100 changes: 52 additions & 48 deletions packages/web/src/app/login/verify/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useCallback, useState, Suspense } from "react"
import VerificationFailed from "./verificationFailed"
import { SourcebotLogo } from "@/app/components/sourcebotLogo"
import useCaptureEvent from "@/hooks/useCaptureEvent"
import { Footer } from "@/app/components/footer"

function VerifyPageContent() {
const [value, setValue] = useState("")
Expand Down Expand Up @@ -41,58 +42,61 @@ function VerifyPageContent() {
}

return (
<div className="flex flex-col items-center p-4 sm:p-12 min-h-screen w-full bg-backgroundSecondary">
<div className="w-full max-w-md">
<div className="flex justify-center mb-6">
<SourcebotLogo className="h-16" size="large" />
</div>
<Card className="w-full shadow-lg border-muted/40">
<CardHeader className="space-y-1">
<CardTitle className="text-2xl font-bold text-center">Verify your email</CardTitle>
<CardDescription className="text-center">
Enter the 6-digit code we sent to <span className="font-semibold text-primary">{email}</span>
</CardDescription>
</CardHeader>
<div className="flex flex-col min-h-screen">
<div className="flex-1 flex flex-col items-center p-4 sm:p-12 w-full bg-backgroundSecondary">
<div className="w-full max-w-md">
<div className="flex justify-center mb-6">
<SourcebotLogo className="h-16" size="large" />
</div>
<Card className="w-full shadow-lg border-muted/40">
<CardHeader className="space-y-1">
<CardTitle className="text-2xl font-bold text-center">Verify your email</CardTitle>
<CardDescription className="text-center">
Enter the 6-digit code we sent to <span className="font-semibold text-primary">{email}</span>
</CardDescription>
</CardHeader>

<CardContent>
<form onSubmit={(e) => {
e.preventDefault()
handleSubmit()
}} className="space-y-6">
<div className="flex justify-center py-4">
<InputOTP maxLength={6} value={value} onChange={setValue} onKeyDown={handleKeyDown} className="gap-2">
<InputOTPGroup>
<InputOTPSlot index={0} className="rounded-md border-input" />
<InputOTPSlot index={1} className="rounded-md border-input" />
<InputOTPSlot index={2} className="rounded-md border-input" />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} className="rounded-md border-input" />
<InputOTPSlot index={4} className="rounded-md border-input" />
<InputOTPSlot index={5} className="rounded-md border-input" />
</InputOTPGroup>
</InputOTP>
</div>
</form>
</CardContent>
<CardContent>
<form onSubmit={(e) => {
e.preventDefault()
handleSubmit()
}} className="space-y-6">
<div className="flex justify-center py-4">
<InputOTP maxLength={6} value={value} onChange={setValue} onKeyDown={handleKeyDown} className="gap-2">
<InputOTPGroup>
<InputOTPSlot index={0} className="rounded-md border-input" />
<InputOTPSlot index={1} className="rounded-md border-input" />
<InputOTPSlot index={2} className="rounded-md border-input" />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} className="rounded-md border-input" />
<InputOTPSlot index={4} className="rounded-md border-input" />
<InputOTPSlot index={5} className="rounded-md border-input" />
</InputOTPGroup>
</InputOTP>
</div>
</form>
</CardContent>

<CardFooter className="flex flex-col space-y-4 pt-0">
<Button variant="ghost" className="w-full text-sm" size="sm" onClick={() => window.history.back()}>
<ArrowLeft className="mr-2 h-4 w-4" />
Back to login
</Button>
</CardFooter>
</Card>
<div className="mt-8 text-center text-sm text-muted-foreground">
<p>
Having trouble?{" "}
<a href="mailto:team@sourcebot.dev" className="text-primary hover:underline">
Contact support
</a>
</p>
<CardFooter className="flex flex-col space-y-4 pt-0">
<Button variant="ghost" className="w-full text-sm" size="sm" onClick={() => window.history.back()}>
<ArrowLeft className="mr-2 h-4 w-4" />
Back to login
</Button>
</CardFooter>
</Card>
<div className="mt-8 text-center text-sm text-muted-foreground">
<p>
Having trouble?{" "}
<a href="mailto:team@sourcebot.dev" className="text-primary hover:underline">
Contact support
</a>
</p>
</div>
</div>
</div>
<Footer />
</div>
)
}
Expand Down
4 changes: 4 additions & 0 deletions packages/web/src/lib/posthogEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ export type PosthogEventMap = {
wa_onboard_gitlab_selected: {},
wa_onboard_gitea_selected: {},
wa_onboard_gerrit_selected: {},
//////////////////////////////////////////////////////////////////
wa_security_page_click: {},
//////////////////////////////////////////////////////////////////
wa_demo_card_click: {},
}

export type PosthogEvent = keyof PosthogEventMap;