Download packages/cli/src/ui/auth/ApiAuthDialog.tsx from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 3.84 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/auth/ApiAuthDialog.tsx
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/cli/src/ui/auth/ApiAuthDialog.tsx
-
curl -L -o ApiAuthDialog.tsx https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/cli/src/ui/auth/ApiAuthDialog.tsx
3.84 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import type React from 'react'; | |
| import { useRef, useEffect } from 'react'; | |
| import { Box, Text } from 'ink'; | |
| import { theme } from '../semantic-colors.js'; | |
| import { TextInput } from '../components/shared/TextInput.js'; | |
| import { useTextBuffer } from '../components/shared/text-buffer.js'; | |
| import { useUIState } from '../contexts/UIStateContext.js'; | |
| import { clearApiKey, debugLogger } from '@google/gemini-cli-core'; | |
| import { useKeypress } from '../hooks/useKeypress.js'; | |
| import { Command } from '../key/keyMatchers.js'; | |
| import { useKeyMatchers } from '../hooks/useKeyMatchers.js'; | |
| interface ApiAuthDialogProps { | |
| onSubmit: (apiKey: string) => void; | |
| onCancel: () => void; | |
| error?: string | null; | |
| defaultValue?: string; | |
| } | |
| export function ApiAuthDialog({ | |
| onSubmit, | |
| onCancel, | |
| error, | |
| defaultValue = '', | |
| }: ApiAuthDialogProps): React.JSX.Element { | |
| const keyMatchers = useKeyMatchers(); | |
| const { terminalWidth } = useUIState(); | |
| const viewportWidth = terminalWidth - 8; | |
| const pendingPromise = useRef<{ cancel: () => void } | null>(null); | |
| useEffect( | |
| () => () => { | |
| pendingPromise.current?.cancel(); | |
| }, | |
| [], | |
| ); | |
| const initialApiKey = defaultValue; | |
| const buffer = useTextBuffer({ | |
| initialText: initialApiKey || '', | |
| initialCursorOffset: initialApiKey?.length || 0, | |
| viewport: { | |
| width: viewportWidth, | |
| height: 4, | |
| }, | |
| inputFilter: (text) => | |
| text.replace(/[^a-zA-Z0-9_.-]/g, '').replace(/[\r\n]/g, ''), | |
| singleLine: true, | |
| }); | |
| const handleSubmit = (value: string) => { | |
| onSubmit(value); | |
| }; | |
| const handleClear = () => { | |
| pendingPromise.current?.cancel(); | |
| let isCancelled = false; | |
| const wrappedPromise = new Promise<void>((resolve, reject) => { | |
| clearApiKey().then( | |
| () => !isCancelled && resolve(), | |
| (error) => !isCancelled && reject(error), | |
| ); | |
| }); | |
| pendingPromise.current = { | |
| cancel: () => { | |
| isCancelled = true; | |
| }, | |
| }; | |
| return wrappedPromise | |
| .then(() => { | |
| buffer.setText(''); | |
| }) | |
| .catch((err) => { | |
| debugLogger.debug('Failed to clear API key:', err); | |
| }); | |
| }; | |
| useKeypress( | |
| (key) => { | |
| if (keyMatchers[Command.CLEAR_INPUT](key)) { | |
| void handleClear(); | |
| return true; | |
| } | |
| return false; | |
| }, | |
| { isActive: true }, | |
| ); | |
| return ( | |
| <Box | |
| borderStyle="round" | |
| borderColor={theme.ui.focus} | |
| flexDirection="column" | |
| padding={1} | |
| width="100%" | |
| > | |
| <Text bold color={theme.text.primary}> | |
| Enter Gemini API Key | |
| </Text> | |
| <Box marginTop={1} flexDirection="column"> | |
| <Text color={theme.text.primary}> | |
| Please enter your Gemini API key. It will be securely stored in your | |
| system keychain. | |
| </Text> | |
| <Text color={theme.text.secondary}> | |
| You can get an API key from{' '} | |
| <Text color={theme.text.link}> | |
| https://aistudio.google.com/app/apikey | |
| </Text> | |
| </Text> | |
| </Box> | |
| <Box marginTop={1} flexDirection="row"> | |
| <Box | |
| borderStyle="round" | |
| borderColor={theme.border.default} | |
| paddingX={1} | |
| flexGrow={1} | |
| > | |
| <TextInput | |
| buffer={buffer} | |
| onSubmit={handleSubmit} | |
| onCancel={onCancel} | |
| placeholder="Paste your API key here" | |
| /> | |
| </Box> | |
| </Box> | |
| {error && ( | |
| <Box marginTop={1}> | |
| <Text color={theme.status.error}>{error}</Text> | |
| </Box> | |
| )} | |
| <Box marginTop={1}> | |
| <Text color={theme.text.secondary}> | |
| (Press Enter to submit, Esc to cancel, Ctrl+C to clear stored key) | |
| </Text> | |
| </Box> | |
| </Box> | |
| ); | |
| } | |