fix: terminal flicker when waiting for login

This commit is contained in:
mingholy.lmh
2025-08-09 21:14:16 +08:00
committed by Mingholy
parent 96a9b683b2
commit a3ec2f52c9

View File

@@ -5,7 +5,7 @@
*/ */
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Box, Text, useInput } from 'ink'; import { Box, Text, useInput, Static } from 'ink';
import Spinner from 'ink-spinner'; import Spinner from 'ink-spinner';
import Link from 'ink-link'; import Link from 'ink-link';
import qrcode from 'qrcode-terminal'; import qrcode from 'qrcode-terminal';
@@ -17,15 +17,22 @@ interface QwenOAuthProgressProps {
onCancel: () => void; onCancel: () => void;
deviceAuth?: DeviceAuthorizationInfo; deviceAuth?: DeviceAuthorizationInfo;
authStatus?: authStatus?:
| 'idle' | 'idle'
| 'polling' | 'polling'
| 'success' | 'success'
| 'error' | 'error'
| 'timeout' | 'timeout'
| 'rate_limit'; | 'rate_limit';
authMessage?: string | null; authMessage?: string | null;
} }
interface StaticItem {
key: string;
type: 'title' | 'instructions' | 'url' | 'qr-instructions' | 'qr-code' | 'auth-content';
url?: string;
qrCode?: string;
}
export function QwenOAuthProgress({ export function QwenOAuthProgress({
onTimeout, onTimeout,
onCancel, onCancel,
@@ -54,24 +61,26 @@ export function QwenOAuthProgress({
return; return;
} }
// Generate QR code string // Only generate QR code if we don't have one yet for this URL
const generateQR = () => { if (qrCodeData === null) {
try { const generateQR = () => {
qrcode.generate( try {
deviceAuth.verification_uri_complete, qrcode.generate(
{ small: true }, deviceAuth.verification_uri_complete,
(qrcode: string) => { { small: true },
setQrCodeData(qrcode); (qrcode: string) => {
}, setQrCodeData(qrcode);
); },
} catch (error) { );
console.error('Failed to generate QR code:', error); } catch (error) {
setQrCodeData(null); console.error('Failed to generate QR code:', error);
} setQrCodeData(null);
}; }
};
generateQR(); generateQR();
}, [deviceAuth]); }
}, [deviceAuth, qrCodeData]);
// Countdown timer // Countdown timer
useEffect(() => { useEffect(() => {
@@ -161,48 +170,70 @@ export function QwenOAuthProgress({
} }
return ( return (
<Box <>
borderStyle="round"
borderColor={Colors.AccentBlue}
flexDirection="column"
padding={1}
width="100%"
>
<Text bold color={Colors.AccentBlue}>
Qwen OAuth Authentication
</Text>
<Box marginTop={1}>
<Text>Please visit this URL to authorize:</Text>
</Box>
<Link url={deviceAuth.verification_uri_complete} fallback={false}>
<Text color={Colors.AccentGreen} bold>
{deviceAuth.verification_uri_complete}
</Text>
</Link>
{qrCodeData && ( {qrCodeData && (
<> <Static items={[
<Box marginTop={1}> { key: 'auth-content', type: 'auth-content' as const, url: deviceAuth.verification_uri_complete, qrCode: qrCodeData }
<Text>Or scan the QR code below:</Text> ] as StaticItem[]}
</Box> style={{
<Box marginTop={1}> width: "100%"
<Text>{qrCodeData}</Text> }}
</Box> >
</> {(item: StaticItem) => (
<Box
borderStyle="round"
borderColor={Colors.AccentBlue}
flexDirection="column"
padding={1}
width="100%"
key={item.key}
>
<Text bold color={Colors.AccentBlue}>
Qwen OAuth Authentication
</Text>
<Box marginTop={1}>
<Text>Please visit this URL to authorize:</Text>
</Box>
<Link url={item.url || ''} fallback={false}>
<Text color={Colors.AccentGreen} bold>
{item.url || ''}
</Text>
</Link>
<Box marginTop={1}>
<Text>Or scan the QR code below:</Text>
</Box>
<Box marginTop={1}>
<Text>{item.qrCode || ''}</Text>
</Box>
</Box>
)}
</Static>
)} )}
<Box
borderStyle="round"
borderColor={Colors.AccentBlue}
flexDirection="column"
padding={1}
width="100%"
>
<Box marginTop={1}> <Box marginTop={1}>
<Text> <Text>
<Spinner type="dots" /> Waiting for authorization{dots} <Spinner type="dots" /> Waiting for authorization{dots}
</Text> </Text>
</Box> </Box>
<Box marginTop={1} justifyContent="space-between"> <Box marginTop={1} justifyContent="space-between">
<Text color={Colors.Gray}> <Text color={Colors.Gray}>
Time remaining: {formatTime(timeRemaining)} Time remaining: {formatTime(timeRemaining)}
</Text> </Text>
<Text color={Colors.AccentPurple}>(Press ESC to cancel)</Text> <Text color={Colors.AccentPurple}>(Press ESC to cancel)</Text>
</Box>
</Box> </Box>
</Box> </>
); );
} }