From 3c7bf8c259d262126a7c736ed2b14425b35f4dcc Mon Sep 17 00:00:00 2001 From: ali00209 Date: Sun, 27 Oct 2024 23:58:04 +0500 Subject: [PATCH 1/3] feat: add ability to enter API keys in the UI --- app/components/chat/APIKeyManager.tsx | 49 ++++++++++++++++++++++ app/components/chat/BaseChat.tsx | 58 +++++++++++++++++++-------- 2 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 app/components/chat/APIKeyManager.tsx diff --git a/app/components/chat/APIKeyManager.tsx b/app/components/chat/APIKeyManager.tsx new file mode 100644 index 000000000..aab70107c --- /dev/null +++ b/app/components/chat/APIKeyManager.tsx @@ -0,0 +1,49 @@ +import React, { useState } from 'react'; +import { IconButton } from '~/components/ui/IconButton'; + +interface APIKeyManagerProps { + provider: string; + apiKey: string; + setApiKey: (key: string) => void; +} + +export const APIKeyManager: React.FC = ({ provider, apiKey, setApiKey }) => { + const [isEditing, setIsEditing] = useState(false); + const [tempKey, setTempKey] = useState(apiKey); + + const handleSave = () => { + setApiKey(tempKey); + setIsEditing(false); + }; + + return ( +
+ {provider} API Key: + {isEditing ? ( + <> + setTempKey(e.target.value)} + className="flex-1 p-1 text-sm rounded border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus" + /> + +
+ + setIsEditing(false)} title="Cancel"> +
+ + + ) : ( + <> + + {apiKey ? '••••••••' : 'Not set'} + + setIsEditing(true)} title="Edit API Key"> +
+ + + )} +
+ ); +}; diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index c1175f700..e3be27bb3 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -1,7 +1,7 @@ // @ts-nocheck // Preventing TS checks with files presented in the video for a better presentation. import type { Message } from 'ai'; -import React, { type RefCallback } from 'react'; +import React, { type RefCallback, useEffect } from 'react'; import { ClientOnly } from 'remix-utils/client-only'; import { Menu } from '~/components/sidebar/Menu.client'; import { IconButton } from '~/components/ui/IconButton'; @@ -11,6 +11,7 @@ import { MODEL_LIST, DEFAULT_PROVIDER } from '~/utils/constants'; import { Messages } from './Messages.client'; import { SendButton } from './SendButton.client'; import { useState } from 'react'; +import { APIKeyManager } from './APIKeyManager'; import styles from './BaseChat.module.scss'; @@ -24,18 +25,17 @@ const EXAMPLE_PROMPTS = [ const providerList = [...new Set(MODEL_LIST.map((model) => model.provider))] -const ModelSelector = ({ model, setModel, modelList, providerList }) => { - const [provider, setProvider] = useState(DEFAULT_PROVIDER); +const ModelSelector = ({ model, setModel, modelList, providerList, provider, setProvider }) => { return ( -
- { setProvider(e.target.value); const firstModel = [...modelList].find(m => m.provider == e.target.value); setModel(firstModel ? firstModel.name : ''); }} - className="w-full p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none" + className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all" > {providerList.map((provider) => (