import { useEffect, useState } from "react"; import { Copy, ExternalLink, Loader2, ShieldCheck, X } from "lucide-react"; import { authorize, cancelAuthorize, onCliAuth } from "../ipc"; import type { AuthFlowEvent, AuthModeInfo } from "../ipc/types"; import { Modal } from "./Modal"; /** 官方授权方式中文名 */ function authModeLabel(mode: string): string { switch (mode) { case "browser_oauth": return "账号授权(浏览器)"; case "device_code": return "设备码"; case "api_key": return "API Key"; case "local_tui": return "本机终端授权"; default: return mode; } } function modeButtonLabel(mode: string): string { switch (mode) { case "browser_oauth": return "开始授权"; case "device_code": return "开始授权"; case "local_tui": return "打开终端授权"; case "api_key": return "用已保存的 Key 授权"; default: return "去授权"; } } interface FlowState { mode: string; events: AuthFlowEvent[]; device: { code: string; url: string } | null; done: boolean | null; // null=进行中 } /** 软件内授权面板(Wave 2.2 Req 2):把「说明文字」升级为可操作授权流程。 * 覆盖 API Key / 浏览器 / 设备码 / 本机终端四类,事件流经 cli-auth-event 实时回传。 */ export function AuthPanel({ id, authModes, onAuthChanged, }: { id: string; authModes: AuthModeInfo[]; onAuthChanged: () => void; }) { const [flow, setFlow] = useState(null); useEffect(() => { let unlisten: (() => void) | undefined; onCliAuth((ev) => { if (ev.cli_id !== id) return; setFlow((f) => { if (!f) return f; const next: FlowState = { ...f, events: [...f.events, ev] }; if (ev.kind === "device_code" && ev.user_code && ev.verification_url) { next.device = { code: ev.user_code, url: ev.verification_url }; } if (ev.kind === "done") { next.done = ev.authorized ?? false; onAuthChanged(); } if (ev.kind === "error" || ev.kind === "cancelled") { next.done = false; } return next; }); }).then((fn) => { unlisten = fn; }); return () => unlisten?.(); }, [id, onAuthChanged]); function start(mode: string) { setFlow({ mode, events: [], device: null, done: null }); void authorize(id, mode); } function cancel() { if (flow) void cancelAuthorize(id, flow.mode); } function close() { setFlow(null); } if (authModes.length === 0) return null; return ( <> {flow && ( )} ); } function AuthFlowBody({ flow }: { flow: FlowState }) { const { device, events, done } = flow; return (
{/* 设备码:大号验证码 + 一键复制 + 打开授权网页 */} {device && (
在浏览器打开验证链接,输入以下设备码
{device.code}
请在弹出的浏览器里完成确认,本软件会轮询授权结果。
)} {/* 状态行 */}
{done == null ? ( ) : done ? ( ) : ( )}
{/* 实时输出(脱敏后) */} {events.length > 0 && (
{events .filter((e) => e.kind === "line" || e.kind === "waiting") .map((e, i) => (
{e.message}
))}
)}
); }