key-button.tsx
1,376 bytes
| 1 | 'use client'; |
|---|---|
| 2 | |
| 3 | import { KeyRound } from 'lucide-react'; |
| 4 | import { useEffect, useState } from 'react'; |
| 5 | import { ApiKeyDialog } from '@/components/api-key-dialog'; |
| 6 | import { Button } from '@/components/ui/button'; |
| 7 | import { cn } from '@/lib/utils'; |
| 8 | |
| 9 | export function KeyButton() { |
| 10 | const [open, setOpen] = useState(false); |
| 11 | const [state, setState] = useState<{ hasKey: boolean; mock: boolean }>({ |
| 12 | hasKey: false, |
| 13 | mock: false, |
| 14 | }); |
| 15 | |
| 16 | const load = () => |
| 17 | fetch('/api/keys') |
| 18 | .then((r) => r.json()) |
| 19 | .then((s: { hasKey: boolean; mockMode: boolean }) => |
| 20 | setState({ hasKey: s.hasKey, mock: s.mockMode }), |
| 21 | ) |
| 22 | .catch(() => {}); |
| 23 | |
| 24 | useEffect(() => { |
| 25 | void load(); |
| 26 | }, []); |
| 27 | |
| 28 | return ( |
| 29 | <> |
| 30 | <Button variant="ghost" size="sm" className="gap-2" onClick={() => setOpen(true)}> |
| 31 | <span |
| 32 | className={cn( |
| 33 | 'h-2 w-2 rounded-full', |
| 34 | state.mock |
| 35 | ? 'bg-amber-500' |
| 36 | : state.hasKey |
| 37 | ? 'bg-emerald-500' |
| 38 | : 'bg-muted-foreground/40', |
| 39 | )} |
| 40 | /> |
| 41 | <KeyRound className="h-4 w-4" /> |
| 42 | <span className="hidden sm:inline"> |
| 43 | {state.mock ? 'Demo models' : state.hasKey ? 'Models connected' : 'Connect models'} |
| 44 | </span> |
| 45 | </Button> |
| 46 | <ApiKeyDialog open={open} onOpenChange={setOpen} onChanged={load} /> |
| 47 | </> |
| 48 | ); |
| 49 | } |
| 50 | |