Skip to content

Commit a4bdf31

Browse files
committed
Update login modal to show the login link for ssh users (and key shortcut/button to copy instead of always copying)
1 parent 79f654b commit a4bdf31

File tree

1 file changed

+37
-42
lines changed

1 file changed

+37
-42
lines changed

cli/src/components/login-modal.tsx

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useRenderer } from '@opentui/react'
22
import open from 'open'
33
import React, { useCallback, useEffect, useRef, useState } from 'react'
44

5+
import { Button } from './button'
56
import { TerminalLink } from './terminal-link'
67
import { useLoginMutation } from '../hooks/use-auth-query'
78
import { useFetchLoginUrl } from '../hooks/use-fetch-login-url'
@@ -63,6 +64,9 @@ export const LoginModal = ({
6364
// Generate fingerprint ID (only once on mount)
6465
const [fingerprintId] = useState(() => generateFingerprintId())
6566

67+
// Track hover state for copy button
68+
const [isCopyButtonHovered, setIsCopyButtonHovered] = useState(false)
69+
6670
// Use TanStack Query for login mutation
6771
const loginMutation = useLoginMutation()
6872

@@ -95,11 +99,8 @@ export const LoginModal = ({
9599
setJustCopied(false)
96100
}, 3000)
97101
} catch (err) {
102+
// Silently fail - the URL is visible for manual copying
98103
logger.error(err, 'Failed to copy to clipboard')
99-
setCopyMessage('✗ Failed to copy to clipboard')
100-
setTimeout(() => {
101-
setCopyMessage(null)
102-
}, 3000)
103104
}
104105
},
105106
[setHasClickedLink, setJustCopied, setCopyMessage],
@@ -192,12 +193,6 @@ export const LoginModal = ({
192193
onCopyUrl: copyToClipboard,
193194
})
194195

195-
// Auto-copy URL when browser is opened
196-
useEffect(() => {
197-
if (hasOpenedBrowser && loginUrl) {
198-
copyToClipboard(loginUrl)
199-
}
200-
}, [hasOpenedBrowser, loginUrl, copyToClipboard])
201196

202197
// Calculate terminal width and height for responsive display
203198
const terminalWidth = renderer?.width || 80
@@ -363,15 +358,13 @@ export const LoginModal = ({
363358
>
364359
<text style={{ wrapMode: 'word' }}>
365360
<span fg={'#00cc00'}>
366-
{isNarrow
367-
? 'Press ENTER to login...'
368-
: 'Press ENTER to open your browser and login...'}
361+
Press ENTER to login...
369362
</span>
370363
</text>
371364
</box>
372365
)}
373366

374-
{/* After opening browser - show URL as fallback */}
367+
{/* After pressing enter - show URL prominently for all users */}
375368
{!loading && !error && loginUrl && hasOpenedBrowser && (
376369
<box
377370
style={{
@@ -384,15 +377,15 @@ export const LoginModal = ({
384377
}}
385378
>
386379
<text style={{ wrapMode: 'word' }}>
387-
<span fg={theme.secondary}>
380+
<span fg={theme.foreground}>
388381
{isNarrow
389-
? 'Opening browser...'
390-
: 'Opening browser to complete login...'}
382+
? 'Open this URL to login:'
383+
: 'Open this URL in your browser to login:'}
391384
</span>
392385
</text>
393386
<box
394387
style={{
395-
marginTop: 0,
388+
marginTop: isVerySmall ? 1 : 2,
396389
width: '100%',
397390
flexShrink: 0,
398391
}}
@@ -401,7 +394,7 @@ export const LoginModal = ({
401394
text={loginUrl}
402395
maxWidth={maxUrlWidth}
403396
formatLines={formatLoginUrlLines}
404-
color={hasClickedLink ? theme.success : theme.link}
397+
color={theme.primary}
405398
activeColor={theme.success}
406399
underlineOnHover={true}
407400
isActive={justCopied}
@@ -412,28 +405,35 @@ export const LoginModal = ({
412405
}}
413406
/>
414407
</box>
415-
{copyMessage && (
416-
<box
417-
style={{
418-
marginTop: isVerySmall ? 0 : 1,
419-
flexDirection: 'column',
420-
alignItems: 'center',
421-
width: '100%',
422-
flexShrink: 0,
423-
}}
408+
<box
409+
style={{
410+
marginTop: isVerySmall ? 1 : 2,
411+
flexDirection: 'column',
412+
alignItems: 'center',
413+
width: '100%',
414+
flexShrink: 0,
415+
}}
416+
>
417+
<Button
418+
onClick={() => copyToClipboard(loginUrl)}
419+
onMouseOver={() => setIsCopyButtonHovered(true)}
420+
onMouseOut={() => setIsCopyButtonHovered(false)}
424421
>
425-
<text style={{ wrapMode: 'none' }}>
422+
<text>
426423
<span
427424
fg={
428-
copyMessage.startsWith('✓') ? theme.success : theme.error
425+
justCopied
426+
? theme.foreground
427+
: isCopyButtonHovered
428+
? theme.foreground
429+
: theme.primary
429430
}
430431
>
431-
{copyMessage}
432+
{justCopied ? '[ ✓ Copied! ]' : '[ Copy link (c) ]'}
432433
</span>
433434
</text>
434-
</box>
435-
)}
436-
{/* Show raw URL as fallback for devices where open() doesn't work */}
435+
</Button>
436+
</box>
437437
<box
438438
style={{
439439
marginTop: isVerySmall ? 1 : 2,
@@ -443,14 +443,9 @@ export const LoginModal = ({
443443
flexShrink: 0,
444444
}}
445445
>
446-
<text style={{ wrapMode: 'word' }}>
447-
<span fg={theme.muted}>
448-
{isNarrow ? 'Or copy URL:' : "Or copy this URL if browser didn't open:"}
449-
</span>
450-
</text>
451-
<text style={{ wrapMode: 'word' }}>
452-
<span fg={theme.muted}>
453-
{loginUrl}
446+
<text style={{ wrapMode: 'none' }}>
447+
<span fg={theme.secondary}>
448+
Waiting for login...
454449
</span>
455450
</text>
456451
</box>

0 commit comments

Comments
 (0)