@@ -17,15 +17,19 @@ import { SSOLoginForm } from "./login/SSOLoginForm";
17
17
import { useAuthProviderDescriptions } from "./data/auth-providers/auth-provider-descriptions-query" ;
18
18
import { SetupPending } from "./login/SetupPending" ;
19
19
import { useNeedsSetup } from "./dedicated-setup/use-needs-setup" ;
20
+ import { useInstallationConfiguration } from "./data/installation/installation-config-query" ;
20
21
import { AuthProviderDescription } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb" ;
21
22
import { Button , ButtonProps } from "@podkit/buttons/Button" ;
22
23
import { cn } from "@podkit/lib/cn" ;
23
24
import { userClient } from "./service/public-api" ;
24
25
import { ProductLogo } from "./components/ProductLogo" ;
25
26
import { useIsDataOps } from "./data/featureflag-query" ;
26
- import GitpodClassicCard from "./images/gitpod-classic-card.png" ;
27
27
import { LoadingState } from "@podkit/loading/LoadingState" ;
28
28
import { isGitpodIo } from "./utils" ;
29
+ import { trackEvent } from "./Analytics" ;
30
+ import { useToast } from "./components/toasts/Toasts" ;
31
+ import onaWordmark from "./images/ona-wordmark.svg" ;
32
+ import onaApplication from "./images/ona-application.webp" ;
29
33
30
34
export function markLoggedIn ( ) {
31
35
document . cookie = GitpodCookie . generateCookie ( window . location . hostname ) ;
@@ -64,7 +68,8 @@ export const Login: FC<LoginProps> = ({ onLoggedIn }) => {
64
68
const [ hostFromContext , setHostFromContext ] = useState < string | undefined > ( ) ;
65
69
const [ repoPathname , setRepoPathname ] = useState < string | undefined > ( ) ;
66
70
67
- const enterprise = ! ! authProviders . data && authProviders . data . length === 0 ;
71
+ const { data : installationConfig } = useInstallationConfiguration ( ) ;
72
+ const enterprise = ! ! installationConfig ?. isDedicatedInstallation ;
68
73
69
74
useEffect ( ( ) => {
70
75
try {
@@ -93,9 +98,15 @@ export const Login: FC<LoginProps> = ({ onLoggedIn }) => {
93
98
return (
94
99
< div
95
100
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 = "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
+ }
99
110
>
100
111
{ enterprise ? (
101
112
< EnterpriseLoginWrapper
@@ -147,7 +158,7 @@ const PAYGLoginWrapper: FC<LoginWrapperProps> = ({ providerFromContext, repoPath
147
158
< div
148
159
id = "login-section"
149
160
// 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-full flex flex-col justify-center items-center p-2"
151
162
>
152
163
< div
153
164
id = "login-section-column"
@@ -212,6 +223,9 @@ const LoginContent = ({
212
223
const authProviders = useAuthProviderDescriptions ( ) ;
213
224
const [ errorMessage , setErrorMessage ] = useState < string | undefined > ( undefined ) ;
214
225
226
+ const { data : installationConfig } = useInstallationConfiguration ( ) ;
227
+ const enterprise = ! ! installationConfig ?. isDedicatedInstallation ;
228
+
215
229
const updateUser = useCallback ( async ( ) => {
216
230
await getGitpodService ( ) . reconnect ( ) ;
217
231
const { user } = await userClient . getAuthenticatedUser ( { } ) ;
@@ -314,32 +328,127 @@ const LoginContent = ({
314
328
< SSOLoginForm onSuccess = { authorizeSuccessful } />
315
329
</ div >
316
330
{ errorMessage && < ErrorMessage imgSrc = { exclamation } message = { errorMessage } /> }
331
+
332
+ { /* Gitpod Classic sunset notice - only show for non-enterprise */ }
333
+ { ! enterprise && (
334
+ < div className = "mt-6 text-center text-sm" >
335
+ < p className = "text-pk-content-primary" >
336
+ Gitpod classic is sunsetting fall 2025.{ " " }
337
+ < a
338
+ href = "https://app.gitpod.io"
339
+ target = "_blank"
340
+ rel = "noopener noreferrer"
341
+ className = "gp-link hover:text-gray-600"
342
+ >
343
+ Try the new Gitpod
344
+ </ a > { " " }
345
+ now (hosted compute & SWE agents coming soon )
346
+ </ p >
347
+ </ div >
348
+ ) }
317
349
</ div >
318
350
) ;
319
351
} ;
320
352
321
353
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" >
354
+ const [ email , setEmail ] = useState ( "" ) ;
355
+ const [ isSubmitted , setIsSubmitted ] = useState ( false ) ;
356
+ const { toast } = useToast ( ) ;
357
+
358
+ const handleEmailSubmit = ( e : React . FormEvent ) => {
359
+ e . preventDefault ( ) ;
360
+ if ( ! email . trim ( ) ) return ;
361
+
362
+ trackEvent ( "waitlist_joined" , { email : email , feature : "Ona" } ) ;
363
+
364
+ setIsSubmitted ( true ) ;
365
+
366
+ toast (
324
367
< 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
368
+ < div className = "font-medium" > You're on the waitlist</ div >
369
+ < div className = "text-sm opacity-80" > We'll reach out to you soon.</ div >
370
+ </ div > ,
371
+ ) ;
372
+ } ;
373
+
374
+ return (
375
+ < div className = "w-full lg:max-w-lg 2xl:max-w-[600px] flex flex-col justify-center px-4 lg:px-4 md:min-h-screen my-auto" >
376
+ < 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" >
377
+ < div className = "relative bg-white/10 backdrop-blur-sm rounded-lg pt-4 px-4 -mt-2" >
378
+ < div className = "flex justify-center pt-4 mb-4" >
379
+ < img src = { onaWordmark } alt = "ONA" className = "w-36" draggable = "false" />
380
+ </ div >
381
+ < div className = "relative overflow-hidden" >
382
+ < img
383
+ src = { onaApplication }
384
+ alt = "Ona application preview"
385
+ className = "w-full h-auto rounded-lg shadow-lg translate-y-8"
386
+ draggable = "false"
387
+ />
388
+ </ div >
389
+ </ div >
390
+
391
+ < div className = "flex flex-col gap-4 flex-1" >
392
+ < h2 className = "text-white text-xl font-bold leading-tight text-center max-w-sm mx-auto" >
393
+ Meet Ona - the privacy-first software engineering agent.
328
394
</ 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 >
333
395
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 >
396
+ < div className = "space-y-3 mt-4" >
397
+ < p className = "text-white/70 text-base" >
398
+ Delegate software tasks to Ona. It writes code, runs tests, and opens a pull request. Or
399
+ jump in to inspect output or pair program in your IDE.
400
+ </ p >
401
+ < p className = "text-white/70 text-base mt-2" >
402
+ Ona runs inside your infrastructure (VPC), with full audit trails, zero data exposure, and
403
+ support for any LLM.
404
+ </ p >
405
+ </ div >
406
+
407
+ < div className = "mt-4" >
408
+ { ! isSubmitted ? (
409
+ < form onSubmit = { handleEmailSubmit } className = "space-y-3" >
410
+ < div className = "flex gap-2" >
411
+ < input
412
+ type = "email"
413
+ value = { email }
414
+ onChange = { ( e ) => setEmail ( e . target . value ) }
415
+ placeholder = "Enter your work email"
416
+ 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"
417
+ required
418
+ />
419
+ < button
420
+ type = "submit"
421
+ 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"
422
+ >
423
+ Request access
424
+ < span className = "font-bold" > →</ span >
425
+ </ button >
426
+ </ div >
427
+ < p className = "text-xs text-white/70" >
428
+ By submitting this, you agree to our{ " " }
429
+ < a
430
+ href = "https://www.gitpod.io/privacy/"
431
+ target = "_blank"
432
+ rel = "noopener noreferrer"
433
+ className = "underline hover:text-white"
434
+ >
435
+ privacy policy
436
+ </ a >
437
+ </ p >
438
+ </ form >
439
+ ) : (
440
+ < a
441
+ href = "https://www.gitpod.io/solutions/ai"
442
+ target = "_blank"
443
+ rel = "noopener noreferrer"
444
+ 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"
445
+ >
446
+ Learn more
447
+ < span className = "font-bold" > →</ span >
448
+ </ a >
449
+ ) }
450
+ </ div >
341
451
</ div >
342
- < img src = { GitpodClassicCard } alt = "Gitpod Classic" className = "w-full" />
343
452
</ div >
344
453
</ div >
345
454
) ;
0 commit comments