From 1ffcb5105269968a7987a7abdfdaae25a0315def Mon Sep 17 00:00:00 2001 From: Mingholy Date: Thu, 14 Aug 2025 21:17:56 +0800 Subject: [PATCH] fix: seperate static QR code and dynamic spin components (#327) * fix: seperate static QR code and dynamic spin components * fix: format issues --- .../src/ui/components/QwenOAuthProgress.tsx | 239 ++++++++++-------- 1 file changed, 127 insertions(+), 112 deletions(-) diff --git a/packages/cli/src/ui/components/QwenOAuthProgress.tsx b/packages/cli/src/ui/components/QwenOAuthProgress.tsx index 10977fe8..f1664215 100644 --- a/packages/cli/src/ui/components/QwenOAuthProgress.tsx +++ b/packages/cli/src/ui/components/QwenOAuthProgress.tsx @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState, useEffect } from 'react'; -import { Box, Text, useInput, Static } from 'ink'; +import React, { useState, useEffect, useMemo } from 'react'; +import { Box, Text, useInput } from 'ink'; import Spinner from 'ink-spinner'; import Link from 'ink-link'; import qrcode from 'qrcode-terminal'; @@ -26,17 +26,93 @@ interface QwenOAuthProgressProps { authMessage?: string | null; } -interface StaticItem { - key: string; - type: - | 'title' - | 'instructions' - | 'url' - | 'qr-instructions' - | 'qr-code' - | 'auth-content'; - url?: string; - qrCode?: string; +/** + * Static QR Code Display Component + * Renders the QR code and URL once and doesn't re-render unless the URL changes + */ +function QrCodeDisplay({ + verificationUrl, + qrCodeData, +}: { + verificationUrl: string; + qrCodeData: string | null; +}): React.JSX.Element | null { + if (!qrCodeData) { + return null; + } + + return ( + + + Qwen OAuth Authentication + + + + Please visit this URL to authorize: + + + + + {verificationUrl} + + + + + Or scan the QR code below: + + + + {qrCodeData} + + + ); +} + +/** + * Dynamic Status Display Component + * Shows the loading spinner, timer, and status messages + */ +function StatusDisplay({ + timeRemaining, + dots, +}: { + timeRemaining: number; + dots: string; +}): React.JSX.Element { + const formatTime = (seconds: number): string => { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds % 60; + return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; + }; + + return ( + + + + Waiting for authorization{dots} + + + + + + Time remaining: {formatTime(timeRemaining)} + + (Press ESC to cancel) + + + ); } export function QwenOAuthProgress({ @@ -60,33 +136,29 @@ export function QwenOAuthProgress({ } }); - // Generate QR code when device auth is available + // Generate QR code once when device auth is available useEffect(() => { - if (!deviceAuth) { - setQrCodeData(null); + if (!deviceAuth?.verification_uri_complete) { return; } - // Only generate QR code if we don't have one yet for this URL - if (qrCodeData === null) { - const generateQR = () => { - try { - qrcode.generate( - deviceAuth.verification_uri_complete, - { small: true }, - (qrcode: string) => { - setQrCodeData(qrcode); - }, - ); - } catch (error) { - console.error('Failed to generate QR code:', error); - setQrCodeData(null); - } - }; + const generateQR = () => { + try { + qrcode.generate( + deviceAuth.verification_uri_complete, + { small: true }, + (qrcode: string) => { + setQrCodeData(qrcode); + }, + ); + } catch (error) { + console.error('Failed to generate QR code:', error); + setQrCodeData(null); + } + }; - generateQR(); - } - }, [deviceAuth, qrCodeData]); + generateQR(); + }, [deviceAuth?.verification_uri_complete]); // Countdown timer useEffect(() => { @@ -115,11 +187,17 @@ export function QwenOAuthProgress({ return () => clearInterval(dotsTimer); }, []); - const formatTime = (seconds: number): string => { - const minutes = Math.floor(seconds / 60); - const remainingSeconds = seconds % 60; - return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; - }; + // Memoize the QR code display to prevent unnecessary re-renders + const qrCodeDisplay = useMemo(() => { + if (!deviceAuth?.verification_uri_complete) return null; + + return ( + + ); + }, [deviceAuth?.verification_uri_complete, qrCodeData]); // Handle timeout state if (authStatus === 'timeout') { @@ -151,6 +229,7 @@ export function QwenOAuthProgress({ ); } + // Show loading state when no device auth is available yet if (!deviceAuth) { return ( - Time remaining: {formatTime(timeRemaining)} + Time remaining: {Math.floor(timeRemaining / 60)}: + {(timeRemaining % 60).toString().padStart(2, '0')} (Press ESC to cancel) @@ -176,77 +256,12 @@ export function QwenOAuthProgress({ } return ( - <> - {qrCodeData && ( - - {(item: StaticItem) => ( - - - Qwen OAuth Authentication - + + {/* Static QR Code Display */} + {qrCodeDisplay} - - Please visit this URL to authorize: - - - - - {item.url || ''} - - - - - Or scan the QR code below: - - - - {item.qrCode || ''} - - - )} - - )} - - - - Waiting for authorization{dots} - - - - - - Time remaining: {formatTime(timeRemaining)} - - (Press ESC to cancel) - - - + {/* Dynamic Status Display */} + + ); }