Files
UHD_Media_Tool/apps/web/app/components/console/api-key-dialog.tsx
T
umtandClaude Fable 5.1 b22c440139 chore: scaffold monorepo and migrate uhd_web design system (W0-A)
- pnpm workspace: apps/{web,server}, packages/{contracts,db,domain,adapters,tasks,agent,testkit}
- server: Hono + zod-openapi, API Key auth with scopes, redacting pino logger, SSE event bus with replay, worker heartbeat
- db: Kysely + pg, file migrator, 0001_init (settings/api_key/audit_event/outbox_event)
- web: React Router 7 SPA console shell with 12 workspace placeholders, uhd_web tokens/ui/guard scripts
- docs: ADR-001 (Node over Deno), dev runbook, design system rules

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 17:36:26 +08:00

81 lines
2.2 KiB
TypeScript

import { KeyRound } from "lucide-react";
import { useState } from "react";
import { toast } from "sonner";
import { Button } from "~/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "~/components/ui/dialog";
import { Input } from "~/components/ui/input";
import { clearAuth, getToken, setToken } from "~/lib/api";
/** 设置本机使用的 API Key(存 localStorage,首版单管理员) */
export function ApiKeyDialog() {
const [open, setOpen] = useState(false);
const [value, setValue] = useState("");
const hasKey = typeof window !== "undefined" && !!getToken();
return (
<Dialog
open={open}
onOpenChange={(o) => {
setOpen(o);
if (o) setValue("");
}}
>
<DialogTrigger asChild>
<Button
variant="outline"
size="icon-sm"
aria-label="设置 API Key"
title={hasKey ? "已设置 API Key" : "设置 API Key"}
>
<KeyRound className="h-4 w-4" />
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>API Key</DialogTitle>
<DialogDescription>控制台用它访问服务端接口,只保存在本浏览器。</DialogDescription>
</DialogHeader>
<Input
type="password"
autoComplete="off"
placeholder={hasKey ? "已设置,输入新值以替换" : "粘贴 API Key"}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<DialogFooter>
{hasKey ? (
<Button
variant="ghost"
onClick={() => {
clearAuth();
setOpen(false);
toast.success("已清除 API Key");
}}
>
清除
</Button>
) : null}
<Button
disabled={!value.trim()}
onClick={() => {
setToken(value.trim());
setOpen(false);
toast.success("已保存 API Key");
}}
>
保存
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}