From 62cd01677dd9374c94e80316ca793131264f49a9 Mon Sep 17 00:00:00 2001 From: Katie Liu <98062538+kliu57@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:02:17 -0400 Subject: [PATCH] Fix for minor bugs in instructions page and prefs modal (#584) Fix for minor bugs in instructions page and prefs modal --- .../Message/AppMessage/Instructions.tsx | 110 ++++++++++-------- src/components/PasswordInput.tsx | 5 +- src/components/PreferencesModal.tsx | 3 +- src/lib/providers/index.ts | 16 +-- 4 files changed, 68 insertions(+), 66 deletions(-) diff --git a/src/components/Message/AppMessage/Instructions.tsx b/src/components/Message/AppMessage/Instructions.tsx index c1fd05f6..7aeb4416 100644 --- a/src/components/Message/AppMessage/Instructions.tsx +++ b/src/components/Message/AppMessage/Instructions.tsx @@ -1,4 +1,4 @@ -import { FormEvent, memo, useState, useCallback, ChangeEvent } from "react"; +import { FormEvent, memo, useState, useEffect } from "react"; import { Button, Box, @@ -13,11 +13,12 @@ import { import MessageBase, { type MessageBaseProps } from "../MessageBase"; import { ChatCraftAppMessage } from "../../../lib/ChatCraftMessage"; -import { nameToUrlMap, providerFromUrl, supportedProviders } from "../../../lib/providers"; +import { providerFromUrl, supportedProviders } from "../../../lib/providers"; import { OpenRouterProvider } from "../../../lib/providers/OpenRouterProvider"; import PasswordInput from "../../PasswordInput"; import { useSettings } from "../../../hooks/use-settings"; import { FreeModelProvider } from "../../../lib/providers/DefaultProvider/FreeModelProvider"; +import { ProviderData } from "../../../lib/ChatCraftProvider"; const ApiKeyInstructionsText = `## Getting Started with ChatCraft @@ -56,20 +57,50 @@ function Instructions(props: MessageBaseProps) { const { settings, setSettings } = useSettings(); const [isValidating, setIsValidating] = useState(false); const [isInvalid, setIsInvalid] = useState(false); + const [selectedProvider, setSelectedProvider] = useState(settings.currentProvider); + + useEffect(() => { + setSelectedProvider(settings.currentProvider); + }, [settings.currentProvider]); + + const providersList: ProviderData = { + ...supportedProviders, + ...settings.providers, + }; // Override the text of the message const message = new ChatCraftAppMessage({ ...props.message, text: ApiKeyInstructionsText }); + const handleApiKeyChange = (e: React.ChangeEvent) => { + const apiKey = e.target.value; + const newProvider = providerFromUrl( + selectedProvider.apiUrl, + apiKey, + selectedProvider.name, + selectedProvider.defaultModel + ); + + setSelectedProvider(newProvider); + providersList[newProvider.name] = newProvider; + + // Save key to settings.providers + setSettings({ + ...settings, + providers: { + ...settings.providers, + [newProvider.name]: newProvider, + }, + }); + }; + const handleApiKeySubmit = (e: FormEvent) => { e.preventDefault(); - const data = new FormData(e.target as HTMLFormElement); - const apiKey = data.get("openai-api-key"); - if (typeof apiKey !== "string") { + if (typeof selectedProvider.apiKey !== "string") { return; } - if (settings.currentProvider instanceof FreeModelProvider) { + if (selectedProvider instanceof FreeModelProvider) { // If user chooses the free provider, no need for validation setSettings({ ...settings, @@ -78,21 +109,15 @@ function Instructions(props: MessageBaseProps) { } else { // See if this API Key is valid setIsValidating(true); - settings.currentProvider - .validateApiKey(apiKey) + selectedProvider + .validateApiKey(selectedProvider.apiKey) .then((valid) => { if (valid) { setIsInvalid(false); - const newProvider = providerFromUrl(settings.currentProvider.apiUrl, apiKey.trim()); - setSettings({ ...settings, - currentProvider: newProvider, - providers: { - ...settings.providers, - [newProvider.name]: newProvider, - }, + currentProvider: selectedProvider, }); } else { setIsInvalid(true); @@ -106,35 +131,10 @@ function Instructions(props: MessageBaseProps) { } }; - const handleProviderChange = useCallback( - (e: ChangeEvent) => { - const apiUrl = nameToUrlMap[e.target.value]; - - // Get stored data from settings.providers array if exists - const newProvider = settings.providers[e.target.value] - ? settings.providers[e.target.value] - : providerFromUrl(apiUrl); - - if (newProvider instanceof FreeModelProvider) { - // If user chooses the free provider, set the key automatically - setSettings({ - ...settings, - currentProvider: new FreeModelProvider(), - }); - } else { - setSettings({ - ...settings, - currentProvider: newProvider, - }); - } - }, - [setSettings, settings] - ); - // Provide a form to enter and process the api key when entered const apiKeyForm = ( - {!supportedProviders ? ( + {!providersList ? ( Loading providers... ) : (
@@ -142,8 +142,14 @@ function Instructions(props: MessageBaseProps) { Provider API URL - { + setSelectedProvider(providersList[e.target.value]); + setIsInvalid(false); + }} + > + {Object.values(providersList).map((provider) => ( @@ -152,28 +158,32 @@ function Instructions(props: MessageBaseProps) { - {settings.currentProvider.name} API Key + {selectedProvider.name} API Key - {settings.currentProvider instanceof OpenRouterProvider && ( - )} - Unable to verify API Key with {settings.currentProvider.name}. + Unable to verify API Key with {selectedProvider.name}. diff --git a/src/components/PasswordInput.tsx b/src/components/PasswordInput.tsx index c2bf6358..f8f0b0f4 100644 --- a/src/components/PasswordInput.tsx +++ b/src/components/PasswordInput.tsx @@ -25,7 +25,10 @@ function PasswordInput({ paddingRight={paddingRight} isInvalid={isInvalid} {...props} - type={show ? "text" : "password"} + type="text" + sx={{ + WebkitTextSecurity: show ? "none" : "disc", + }} /> { if (!isOpen) { setNewCustomProvider(null); + setIsApiKeyInvalid(false); } }, [isOpen]); @@ -669,7 +670,6 @@ function PreferencesModal({ isOpen, onClose, finalFocusRef }: PreferencesModalPr paddingRight={"2.5rem"} paddingLeft={"0.5rem"} fontSize="xs" - type="password" placeholder="API Key" value={newCustomProvider.apiKey || ""} onChange={(e) => { @@ -746,7 +746,6 @@ function PreferencesModal({ isOpen, onClose, finalFocusRef }: PreferencesModalPr paddingRight={"2.5rem"} paddingLeft={"0.5rem"} fontSize="xs" - type="password" value={provider.apiKey || ""} onChange={(e) => handleApiKeyChange(provider, e.target.value)} onFocus={() => setFocusedProvider(provider)} diff --git a/src/lib/providers/index.ts b/src/lib/providers/index.ts index 0506ca11..f504c41e 100644 --- a/src/lib/providers/index.ts +++ b/src/lib/providers/index.ts @@ -1,12 +1,8 @@ import { ChatCraftProvider, ProviderData, SerializedChatCraftProvider } from "../ChatCraftProvider"; import { getSettings } from "../settings"; -import { OPENAI_API_URL, OPENAI_NAME, OpenAiProvider } from "./OpenAiProvider"; -import { OPENROUTER_API_URL, OPENROUTER_NAME, OpenRouterProvider } from "./OpenRouterProvider"; -import { - FREEMODELPROVIDER_API_URL, - FREEMODELPROVIDER_NAME, - FreeModelProvider, -} from "./DefaultProvider/FreeModelProvider"; +import { OPENAI_API_URL, OpenAiProvider } from "./OpenAiProvider"; +import { OPENROUTER_API_URL, OpenRouterProvider } from "./OpenRouterProvider"; +import { FREEMODELPROVIDER_API_URL, FreeModelProvider } from "./DefaultProvider/FreeModelProvider"; import { CustomProvider } from "./CustomProvider"; export const usingOfficialOpenAI = () => getSettings().currentProvider.apiUrl === OPENAI_API_URL; @@ -71,9 +67,3 @@ export const supportedProviders: ProviderData = (() => { [openAi.name]: openAi, }; })(); - -export const nameToUrlMap: { [key: string]: string } = { - [OPENAI_NAME]: OPENAI_API_URL, - [OPENROUTER_NAME]: OPENROUTER_API_URL, - [FREEMODELPROVIDER_NAME]: FREEMODELPROVIDER_API_URL, -};