Skip to content

Commit 7c21472

Browse files
Login page - Ona right panel for waitlist sign-up and information for gitpod.io users only
1 parent 1057aaf commit 7c21472

File tree

2 files changed

+252
-22
lines changed

2 files changed

+252
-22
lines changed

components/dashboard/src/Login.tsx

Lines changed: 134 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ import { cn } from "@podkit/lib/cn";
2323
import { userClient } from "./service/public-api";
2424
import { ProductLogo } from "./components/ProductLogo";
2525
import { useIsDataOps } from "./data/featureflag-query";
26-
import GitpodClassicCard from "./images/gitpod-classic-card.png";
2726
import { LoadingState } from "@podkit/loading/LoadingState";
2827
import { isGitpodIo } from "./utils";
28+
import { trackEvent } from "./Analytics";
29+
import { useCurrentUser } from "./user-context";
30+
import { getPrimaryEmail } from "@gitpod/public-api-common/lib/user-utils";
31+
import { useToast } from "./components/toasts/Toasts";
32+
import onaWordmark from "./images/ona-wordmark.svg";
33+
import onaApplication from "./images/ona-application.webp";
2934

3035
export function markLoggedIn() {
3136
document.cookie = GitpodCookie.generateCookie(window.location.hostname);
@@ -93,9 +98,15 @@ export const Login: FC<LoginProps> = ({ onLoggedIn }) => {
9398
return (
9499
<div
95100
id="login-container"
96-
className={cn("z-50 flex flex-col-reverse lg:flex-row w-full min-h-screen", {
97-
"bg-[#FDF1E7] dark:bg-[#23211e]": !enterprise,
98-
})}
101+
className={cn("z-50 flex flex-col-reverse lg:flex-row w-full min-h-screen")}
102+
style={
103+
!enterprise
104+
? {
105+
background:
106+
"linear-gradient(390deg, #1F1329 0%, #333A75 20%, #556CA8 50%, #90A898 60%, #90A898 70%, #E2B15C 90%, #BEA462 100%)",
107+
}
108+
: undefined
109+
}
99110
>
100111
{enterprise ? (
101112
<EnterpriseLoginWrapper
@@ -147,7 +158,7 @@ const PAYGLoginWrapper: FC<LoginWrapperProps> = ({ providerFromContext, repoPath
147158
<div
148159
id="login-section"
149160
// for some reason, min-h-dvh does not work, so we need tailwind's arbitrary values
150-
className="w-full min-h-[100dvh] lg:w-2/3 flex flex-col justify-center items-center bg-[#FDF1E7] dark:bg-[#23211e] p-2"
161+
className="w-full min-h-[100dvh] lg:w-2/3 flex flex-col justify-center items-center p-2"
151162
>
152163
<div
153164
id="login-section-column"
@@ -212,6 +223,8 @@ const LoginContent = ({
212223
const authProviders = useAuthProviderDescriptions();
213224
const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined);
214225

226+
const enterprise = !!authProviders.data && authProviders.data.length === 0;
227+
215228
const updateUser = useCallback(async () => {
216229
await getGitpodService().reconnect();
217230
const { user } = await userClient.getAuthenticatedUser({});
@@ -314,32 +327,131 @@ const LoginContent = ({
314327
<SSOLoginForm onSuccess={authorizeSuccessful} />
315328
</div>
316329
{errorMessage && <ErrorMessage imgSrc={exclamation} message={errorMessage} />}
330+
331+
{/* Gitpod Classic sunset notice - only show for non-enterprise */}
332+
{!enterprise && (
333+
<div className="mt-6 text-center text-sm bg-[#FDF1E7] dark:bg-[#23211e] p-2 rounded-lg">
334+
<p className="text-pk-content-primary">
335+
Gitpod classic is sunsetting fall 2025.{" "}
336+
<a
337+
href="https://app.gitpod.io"
338+
target="_blank"
339+
rel="noopener noreferrer"
340+
className="gp-link hover:text-gray-600"
341+
>
342+
Try the new Gitpod
343+
</a>{" "}
344+
now (hosted compute coming soon)
345+
</p>
346+
</div>
347+
)}
317348
</div>
318349
);
319350
};
320351

321352
const RightProductDescriptionPanel = () => {
322-
return (
323-
<div className="w-full lg:w-1/3 flex flex-col md:justify-center p-4 lg:p-10 lg:pb-2 md:min-h-screen">
353+
const [email, setEmail] = useState("");
354+
const [isSubmitted, setIsSubmitted] = useState(false);
355+
const user = useCurrentUser();
356+
const { toast } = useToast();
357+
358+
const handleEmailSubmit = (e: React.FormEvent) => {
359+
e.preventDefault();
360+
if (!email.trim()) return;
361+
362+
const userEmail = user ? getPrimaryEmail(user) || email : email;
363+
trackEvent("waitlist_joined", { email: userEmail, feature: "Ona" });
364+
365+
setIsSubmitted(true);
366+
367+
toast(
324368
<div>
325-
<div className="justify-center md:justify-start mb-6 md:mb-8">
326-
<h2 className="text-2xl font-medium mb-2 dark:text-white inline-flex items-center gap-x-2">
327-
Gitpod Classic
369+
<div className="font-medium">You're on the waitlist</div>
370+
<div className="text-sm opacity-80">We'll reach out to you soon.</div>
371+
</div>,
372+
);
373+
};
374+
375+
const handleLearnMore = () => {
376+
window.open("https://ona.com/", "_blank", "noopener,noreferrer");
377+
};
378+
379+
return (
380+
<div className="w-full lg:w-1/3 flex flex-col justify-center px-4 lg:px-4 md:min-h-screen">
381+
<div className="rounded-lg flex flex-col gap-6 text-white h-full py-4 lg:py-6 max-w-lg mx-auto w-full">
382+
<div className="relative bg-white/10 backdrop-blur-sm rounded-lg pt-4 px-4 -mt-2">
383+
<div className="flex justify-center pt-4 mb-4">
384+
<img src={onaWordmark} alt="ONA" className="w-36" draggable="false" />
385+
</div>
386+
<div className="relative overflow-hidden">
387+
<img
388+
src={onaApplication}
389+
alt="Ona application preview"
390+
className="w-full h-auto rounded-lg shadow-lg translate-y-8"
391+
draggable="false"
392+
/>
393+
</div>
394+
</div>
395+
396+
<div className="flex flex-col gap-4 flex-1">
397+
<h2 className="text-white text-2xl font-bold leading-tight text-center max-w-sm mx-auto">
398+
Meet Ona - the privacy-first software engineering agent.
328399
</h2>
329-
<p className="text-pk-content-secondary mb-2">
330-
Automated, standardized development environments hosted by us in Gitpod’s infrastructure. Users
331-
who joined before October 1, 2024 on non-Enterprise plans are considered Gitpod Classic users.
332-
</p>
333400

334-
<p className="text-pk-content-secondary mb-2">
335-
Gitpod Classic is sunsetting fall 2025.{" "}
336-
<a className="gp-link font-bold" href="https://app.gitpod.io" target="_blank" rel="noreferrer">
337-
Try the new Gitpod
338-
</a>{" "}
339-
now (hosted compute coming soon).
340-
</p>
401+
<div className="space-y-3 mt-4">
402+
<p className="text-white/70 text-xl">
403+
Delegate software tasks to Ona. It writes code, runs tests, and opens a pull request. Or
404+
jump in to inspect output or pair program in your IDE.
405+
</p>
406+
<p className="text-white/70 text-xl mt-2">
407+
Ona runs inside your infrastructure (VPC), with full audit trails, zero data exposure, and
408+
support for any LLM.
409+
</p>
410+
</div>
411+
412+
<div className="mt-auto pt-4">
413+
{!isSubmitted ? (
414+
<form onSubmit={handleEmailSubmit} className="space-y-3">
415+
<div className="flex gap-2">
416+
<input
417+
type="email"
418+
value={email}
419+
onChange={(e) => setEmail(e.target.value)}
420+
placeholder="Enter your work email"
421+
className="flex-1 px-4 py-2.5 rounded-lg bg-white/10 backdrop-blur-sm border border-white/20 text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-white/30 text-sm"
422+
required
423+
/>
424+
<button
425+
type="submit"
426+
className="bg-white text-gray-900 font-medium py-2.5 px-4 rounded-lg hover:bg-gray-100 transition-colors text-sm inline-flex items-center justify-center gap-2"
427+
>
428+
Request access
429+
<span className="font-bold"></span>
430+
</button>
431+
</div>
432+
<p className="text-xs text-white/70">
433+
By submitting this, you agree to our{" "}
434+
<a
435+
href="https://www.gitpod.io/privacy/"
436+
target="_blank"
437+
rel="noopener noreferrer"
438+
className="underline hover:text-white"
439+
>
440+
privacy policy
441+
</a>
442+
</p>
443+
</form>
444+
) : (
445+
<button
446+
onClick={handleLearnMore}
447+
className="w-full bg-white/20 backdrop-blur-sm text-white font-medium py-2.5 px-4 rounded-lg hover:bg-white/30 transition-colors border border-white/20 inline-flex items-center justify-center gap-2 text-sm"
448+
>
449+
Learn more
450+
<span className="font-bold"></span>
451+
</button>
452+
)}
453+
</div>
341454
</div>
342-
<img src={GitpodClassicCard} alt="Gitpod Classic" className="w-full" />
343455
</div>
344456
</div>
345457
);
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
* Copyright (c) 2025 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import React, { useState, useEffect } from "react";
8+
import { trackEvent } from "./Analytics";
9+
import { useCurrentUser } from "./user-context";
10+
import { getPrimaryEmail } from "@gitpod/public-api-common/lib/user-utils";
11+
import { useToast } from "./components/toasts/Toasts";
12+
import onaWordmark from "./images/ona-wordmark.svg";
13+
import onaApplication from "./images/ona-application.webp";
14+
15+
export const OnaRightPanel = () => {
16+
const [email, setEmail] = useState("");
17+
const [isSubmitted, setIsSubmitted] = useState(false);
18+
const user = useCurrentUser();
19+
const { toast } = useToast();
20+
21+
useEffect(() => {
22+
const storedOnaData = localStorage.getItem("ona-waitlist-data");
23+
if (storedOnaData) {
24+
const { submitted } = JSON.parse(storedOnaData);
25+
setIsSubmitted(submitted || false);
26+
}
27+
}, []);
28+
29+
const handleEmailSubmit = (e: React.FormEvent) => {
30+
e.preventDefault();
31+
if (!email.trim()) return;
32+
33+
const userEmail = user ? getPrimaryEmail(user) || email : email;
34+
trackEvent("waitlist_joined", { email: userEmail, feature: "Ona" });
35+
36+
setIsSubmitted(true);
37+
localStorage.setItem("ona-waitlist-data", JSON.stringify({ submitted: true }));
38+
39+
toast(
40+
<div>
41+
<div className="font-medium">You're on the waitlist</div>
42+
<div className="text-sm opacity-80">We'll reach out to you soon.</div>
43+
</div>,
44+
);
45+
};
46+
47+
return (
48+
<div className="w-full lg:w-1/3 flex flex-col justify-center p-4 lg:p-6 md:min-h-screen">
49+
<div
50+
className="rounded-lg flex flex-col gap-6 text-white p-6 h-full max-w-md mx-auto w-full"
51+
style={{
52+
background:
53+
"linear-gradient(340deg, #1F1329 0%, #333A75 20%, #556CA8 40%, #90A898 60%, #E2B15C 80%, #BEA462 100%)",
54+
}}
55+
>
56+
<div className="flex justify-center pt-4">
57+
<img src={onaWordmark} alt="ONA" className="w-32" draggable="false" />
58+
</div>
59+
60+
<div className="relative bg-white/10 backdrop-blur-sm rounded-lg p-4 -mt-2">
61+
<img
62+
src={onaApplication}
63+
alt="Ona application preview"
64+
className="w-full h-auto rounded-lg shadow-lg"
65+
draggable="false"
66+
/>
67+
</div>
68+
69+
<div className="flex flex-col gap-4 flex-1">
70+
<h2 className="text-white text-xl font-bold leading-tight text-center">
71+
Meet Ona - the privacy-first software engineering agent.
72+
</h2>
73+
74+
<div className="space-y-3 text-sm text-white/90 leading-relaxed">
75+
<p>
76+
Delegate software tasks to Ona. It writes code, runs tests, and opens a pull request. Or
77+
jump in to inspect output or pair program in your IDE.
78+
</p>
79+
<p>
80+
Ona runs inside your infrastructure (VPC), with full audit trails, zero data exposure, and
81+
support for any LLM.
82+
</p>
83+
</div>
84+
85+
<div className="mt-auto pt-4">
86+
{!isSubmitted ? (
87+
<form onSubmit={handleEmailSubmit} className="space-y-3">
88+
<input
89+
type="email"
90+
value={email}
91+
onChange={(e) => setEmail(e.target.value)}
92+
placeholder="Enter your work email"
93+
className="w-full px-4 py-2.5 rounded-lg bg-white/10 backdrop-blur-sm border border-white/20 text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-white/30 text-sm"
94+
required
95+
/>
96+
<button
97+
type="submit"
98+
className="w-full bg-white text-gray-900 font-medium py-2.5 px-4 rounded-lg hover:bg-gray-100 transition-colors text-sm inline-flex items-center justify-center gap-2"
99+
>
100+
Request access
101+
<span className="font-bold"></span>
102+
</button>
103+
</form>
104+
) : (
105+
<button
106+
onClick={() => window.open("https://ona.com/", "_blank", "noopener,noreferrer")}
107+
className="w-full bg-white/20 backdrop-blur-sm text-white font-medium py-2.5 px-4 rounded-lg hover:bg-white/30 transition-colors border border-white/20 inline-flex items-center justify-center gap-2 text-sm"
108+
>
109+
Learn more
110+
<span className="font-bold"></span>
111+
</button>
112+
)}
113+
</div>
114+
</div>
115+
</div>
116+
</div>
117+
);
118+
};

0 commit comments

Comments
 (0)