mirror of
				https://github.com/ItzCrazyKns/Perplexica.git
				synced 2025-10-31 11:28:15 +00:00 
			
		
		
		
	feat(app): rename providers to connection, enhance UX
This commit is contained in:
		| @@ -82,10 +82,10 @@ const AddProvider = ({ | ||||
|  | ||||
|       setProviders((prev) => [...prev, data]); | ||||
|  | ||||
|       toast.success('Provider added successfully.'); | ||||
|       toast.success('Connection added successfully.'); | ||||
|     } catch (error) { | ||||
|       console.error('Error adding provider:', error); | ||||
|       toast.error('Failed to add provider.'); | ||||
|       toast.error('Failed to add connection.'); | ||||
|     } finally { | ||||
|       setLoading(false); | ||||
|       setOpen(false); | ||||
| @@ -99,7 +99,7 @@ const AddProvider = ({ | ||||
|         className="px-3 md:px-4 py-1.5 md:py-2 rounded-lg text-xs sm:text-sm border border-light-200 dark:border-dark-200 text-black dark:text-white bg-light-secondary/50 dark:bg-dark-secondary/50 hover:bg-light-secondary hover:dark:bg-dark-secondary hover:border-light-300 hover:dark:border-dark-300 flex flex-row items-center space-x-1 active:scale-95 transition duration-200" | ||||
|       > | ||||
|         <Plus className="w-3.5 h-3.5 md:w-4 md:h-4" /> | ||||
|         <span>Add Provider</span> | ||||
|         <span>Add Connection</span> | ||||
|       </button> | ||||
|       <AnimatePresence> | ||||
|         {open && ( | ||||
| @@ -120,7 +120,7 @@ const AddProvider = ({ | ||||
|                 <form onSubmit={handleSubmit} className="flex flex-col flex-1"> | ||||
|                   <div className="px-6 pt-6 pb-4"> | ||||
|                     <h3 className="text-black/90 dark:text-white/90 font-medium"> | ||||
|                       Add new provider | ||||
|                       Add new connection | ||||
|                     </h3> | ||||
|                   </div> | ||||
|                   <div className="border-t border-light-200 dark:border-dark-200" /> | ||||
| @@ -128,7 +128,7 @@ const AddProvider = ({ | ||||
|                     <div className="flex flex-col space-y-4"> | ||||
|                       <div className="flex flex-col items-start space-y-2"> | ||||
|                         <label className="text-xs text-black/70 dark:text-white/70"> | ||||
|                           Select provider type | ||||
|                           Select connection type | ||||
|                         </label> | ||||
|                         <Select | ||||
|                           value={selectedProvider ?? ''} | ||||
| @@ -149,13 +149,13 @@ const AddProvider = ({ | ||||
|                         className="flex flex-col items-start space-y-2" | ||||
|                       > | ||||
|                         <label className="text-xs text-black/70 dark:text-white/70"> | ||||
|                           Name* | ||||
|                           Connection Name* | ||||
|                         </label> | ||||
|                         <input | ||||
|                           value={name} | ||||
|                           onChange={(e) => setName(e.target.value)} | ||||
|                           className="w-full rounded-lg border border-light-200 dark:border-dark-200 bg-light-primary dark:bg-dark-primary px-4 py-3 pr-10 text-sm text-black/80 dark:text-white/80 placeholder:text-black/40 dark:placeholder:text-white/40 focus-visible:outline-none focus-visible:border-light-300 dark:focus-visible:border-dark-300 transition-colors disabled:cursor-not-allowed disabled:opacity-60" | ||||
|                           placeholder={'Provider Name'} | ||||
|                           placeholder={'e.g., My OpenAI Connection'} | ||||
|                           type="text" | ||||
|                           required={true} | ||||
|                         /> | ||||
| @@ -199,7 +199,7 @@ const AddProvider = ({ | ||||
|                       {loading ? ( | ||||
|                         <Loader2 className="animate-spin" size={16} /> | ||||
|                       ) : ( | ||||
|                         'Add Provider' | ||||
|                         'Add Connection' | ||||
|                       )} | ||||
|                     </button> | ||||
|                   </div> | ||||
|   | ||||
| @@ -34,10 +34,10 @@ const DeleteProvider = ({ | ||||
|         return prev.filter((p) => p.id !== modelProvider.id); | ||||
|       }); | ||||
|  | ||||
|       toast.success('Provider deleted successfully.'); | ||||
|       toast.success('Connection deleted successfully.'); | ||||
|     } catch (error) { | ||||
|       console.error('Error deleting provider:', error); | ||||
|       toast.error('Failed to delete provider.'); | ||||
|       toast.error('Failed to delete connection.'); | ||||
|     } finally { | ||||
|       setLoading(false); | ||||
|     } | ||||
| @@ -51,7 +51,7 @@ const DeleteProvider = ({ | ||||
|           setOpen(true); | ||||
|         }} | ||||
|         className="group p-1.5 rounded-md hover:bg-light-200 hover:dark:bg-dark-200 transition-colors group" | ||||
|         title="Delete provider" | ||||
|         title="Delete connection" | ||||
|       > | ||||
|         <Trash2 | ||||
|           size={14} | ||||
| @@ -76,14 +76,15 @@ const DeleteProvider = ({ | ||||
|               <DialogPanel className="w-full mx-4 lg:w-[600px] max-h-[85vh] flex flex-col border bg-light-primary dark:bg-dark-primary border-light-secondary dark:border-dark-secondary rounded-lg"> | ||||
|                 <div className="px-6 pt-6 pb-4"> | ||||
|                   <h3 className="text-black/90 dark:text-white/90 font-medium"> | ||||
|                     Delete provider | ||||
|                     Delete connection | ||||
|                   </h3> | ||||
|                 </div> | ||||
|                 <div className="border-t border-light-200 dark:border-dark-200" /> | ||||
|                 <div className="flex-1 overflow-y-auto px-6 py-4"> | ||||
|                   <p className="text-SM text-black/60 dark:text-white/60"> | ||||
|                     Are you sure you want to delete the provider " | ||||
|                   <p className="text-sm text-black/60 dark:text-white/60"> | ||||
|                     Are you sure you want to delete the connection " | ||||
|                     {modelProvider.name}"? This action cannot be undone. | ||||
|                     All associated models will also be removed. | ||||
|                   </p> | ||||
|                 </div> | ||||
|                 <div className="px-6 py-6 flex justify-end space-x-2"> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { UIConfigField, ConfigModelProvider } from '@/lib/config/types'; | ||||
| import { cn } from '@/lib/utils'; | ||||
| import { AnimatePresence, motion } from 'framer-motion'; | ||||
| import { AlertCircle, ChevronDown, Pencil, Trash2, X } from 'lucide-react'; | ||||
| import { AlertCircle, Plug2, Plus, Pencil, Trash2, X } from 'lucide-react'; | ||||
| import { useState } from 'react'; | ||||
| import { toast } from 'sonner'; | ||||
| import AddModel from './AddModelDialog'; | ||||
| @@ -17,7 +17,7 @@ const ModelProvider = ({ | ||||
|   fields: UIConfigField[]; | ||||
|   setProviders: React.Dispatch<React.SetStateAction<ConfigModelProvider[]>>; | ||||
| }) => { | ||||
|   const [open, setOpen] = useState(false); | ||||
|   const [open, setOpen] = useState(true); | ||||
|  | ||||
|   const handleModelDelete = async ( | ||||
|     type: 'chat' | 'embedding', | ||||
| @@ -66,146 +66,157 @@ const ModelProvider = ({ | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   const modelCount = | ||||
|     modelProvider.chatModels.filter((m) => m.key !== 'error').length + | ||||
|     modelProvider.embeddingModels.filter((m) => m.key !== 'error').length; | ||||
|   const hasError = | ||||
|     modelProvider.chatModels.some((m) => m.key === 'error') || | ||||
|     modelProvider.embeddingModels.some((m) => m.key === 'error'); | ||||
|  | ||||
|   return ( | ||||
|     <div | ||||
|       key={modelProvider.id} | ||||
|       className="border border-light-200 dark:border-dark-200 rounded-lg overflow-hidden" | ||||
|       className="border border-light-200 dark:border-dark-200 rounded-lg overflow-hidden bg-light-primary dark:bg-dark-primary" | ||||
|     > | ||||
|       <div | ||||
|         className={cn( | ||||
|           'group px-5 py-4 flex flex-row justify-between w-full cursor-pointer hover:bg-light-secondary hover:dark:bg-dark-secondary transition duration-200 items-center', | ||||
|           !open && 'rounded-lg', | ||||
|         )} | ||||
|         onClick={() => setOpen(!open)} | ||||
|       > | ||||
|         <p className="text-sm lg:text-base text-black dark:text-white font-medium"> | ||||
|           {modelProvider.name} | ||||
|         </p> | ||||
|         <div className="flex items-center gap-4"> | ||||
|           <div className="flex flex-row items-center"> | ||||
|             <UpdateProvider | ||||
|               fields={fields} | ||||
|               modelProvider={modelProvider} | ||||
|               setProviders={setProviders} | ||||
|             /> | ||||
|             <DeleteProvider | ||||
|               modelProvider={modelProvider} | ||||
|               setProviders={setProviders} | ||||
|             /> | ||||
|       <div className="px-5 py-3.5 flex flex-row justify-between w-full items-center border-b border-light-200 dark:border-dark-200 bg-light-secondary/30 dark:bg-dark-secondary/30"> | ||||
|         <div className="flex items-center gap-2.5"> | ||||
|           <div className="p-1.5 rounded-md bg-sky-500/10 dark:bg-sky-500/10"> | ||||
|             <Plug2 size={14} className="text-sky-500" /> | ||||
|           </div> | ||||
|           <ChevronDown | ||||
|             size={16} | ||||
|             className={cn( | ||||
|               open ? 'rotate-180' : '', | ||||
|               'transition duration-200 text-black/70 dark:text-white/70 group-hover:text-sky-500', | ||||
|           <div className="flex flex-col"> | ||||
|             <p className="text-sm lg:text-base text-black dark:text-white font-medium"> | ||||
|               {modelProvider.name} | ||||
|             </p> | ||||
|             {modelCount > 0 && ( | ||||
|               <p className="text-[10px] lg:text-xs text-black/50 dark:text-white/50"> | ||||
|                 {modelCount} model{modelCount !== 1 ? 's' : ''} configured | ||||
|               </p> | ||||
|             )} | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className="flex flex-row items-center gap-1"> | ||||
|           <UpdateProvider | ||||
|             fields={fields} | ||||
|             modelProvider={modelProvider} | ||||
|             setProviders={setProviders} | ||||
|           /> | ||||
|           <DeleteProvider | ||||
|             modelProvider={modelProvider} | ||||
|             setProviders={setProviders} | ||||
|           /> | ||||
|         </div> | ||||
|       </div> | ||||
|       <AnimatePresence> | ||||
|         {open && ( | ||||
|           <motion.div | ||||
|             initial={{ height: 0, opacity: 0 }} | ||||
|             animate={{ height: 'auto', opacity: 1 }} | ||||
|             exit={{ height: 0, opacity: 0 }} | ||||
|             transition={{ duration: 0.1 }} | ||||
|           > | ||||
|             <div className="border-t border-light-200 dark:border-dark-200" /> | ||||
|             <div className="flex flex-col gap-y-4 px-5 py-4"> | ||||
|               <div className="flex flex-col gap-y-2"> | ||||
|                 <div className="flex flex-row w-full justify-between items-center"> | ||||
|                   <p className="text-[11px] lg:text-xs text-black/70 dark:text-white/70"> | ||||
|                     Chat models | ||||
|                   </p> | ||||
|                   <AddModel | ||||
|                     providerId={modelProvider.id} | ||||
|                     setProviders={setProviders} | ||||
|                     type="chat" | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div className="flex flex-col gap-2"> | ||||
|                   {modelProvider.chatModels.some((m) => m.key === 'error') ? ( | ||||
|                     <div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30"> | ||||
|                       <AlertCircle size={16} className="shrink-0" /> | ||||
|                       <span className="break-words"> | ||||
|                         { | ||||
|                           modelProvider.chatModels.find( | ||||
|                             (m) => m.key === 'error', | ||||
|                           )?.name | ||||
|                         } | ||||
|                       </span> | ||||
|                     </div> | ||||
|                   ) : ( | ||||
|                     <div className="flex flex-row flex-wrap gap-2"> | ||||
|                       {modelProvider.chatModels.map((model, index) => ( | ||||
|                         <div | ||||
|                           key={`${modelProvider.id}-chat-${model.key}-${index}`} | ||||
|                           className="flex flex-row items-center space-x-1 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5" | ||||
|                         > | ||||
|                           <span>{model.name}</span> | ||||
|                           <button | ||||
|                             onClick={() => { | ||||
|                               handleModelDelete('chat', model.key); | ||||
|                             }} | ||||
|                           > | ||||
|                             <X size={12} /> | ||||
|                           </button> | ||||
|                         </div> | ||||
|                       ))} | ||||
|                     </div> | ||||
|                   )} | ||||
|                 </div> | ||||
|       <div className="flex flex-col gap-y-4 px-5 py-4"> | ||||
|         <div className="flex flex-col gap-y-2"> | ||||
|           <div className="flex flex-row w-full justify-between items-center"> | ||||
|             <p className="text-[11px] lg:text-xs font-medium text-black/70 dark:text-white/70 uppercase tracking-wide"> | ||||
|               Chat Models | ||||
|             </p> | ||||
|             {!modelProvider.chatModels.some((m) => m.key === 'error') && ( | ||||
|               <AddModel | ||||
|                 providerId={modelProvider.id} | ||||
|                 setProviders={setProviders} | ||||
|                 type="chat" | ||||
|               /> | ||||
|             )} | ||||
|           </div> | ||||
|           <div className="flex flex-col gap-2"> | ||||
|             {modelProvider.chatModels.some((m) => m.key === 'error') ? ( | ||||
|               <div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30"> | ||||
|                 <AlertCircle size={16} className="shrink-0" /> | ||||
|                 <span className="break-words"> | ||||
|                   { | ||||
|                     modelProvider.chatModels.find((m) => m.key === 'error') | ||||
|                       ?.name | ||||
|                   } | ||||
|                 </span> | ||||
|               </div> | ||||
|               <div className="flex flex-col gap-y-2"> | ||||
|                 <div className="flex flex-row w-full justify-between items-center"> | ||||
|                   <p className="text-[11px] lg:text-xs text-black/70 dark:text-white/70"> | ||||
|                     Embedding models | ||||
|                   </p> | ||||
|                   <AddModel | ||||
|                     providerId={modelProvider.id} | ||||
|                     setProviders={setProviders} | ||||
|                     type="embedding" | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div className="flex flex-col gap-2"> | ||||
|                   {modelProvider.embeddingModels.some( | ||||
|                     (m) => m.key === 'error', | ||||
|                   ) ? ( | ||||
|                     <div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30"> | ||||
|                       <AlertCircle size={16} className="shrink-0" /> | ||||
|                       <span className="break-words"> | ||||
|                         { | ||||
|                           modelProvider.embeddingModels.find( | ||||
|                             (m) => m.key === 'error', | ||||
|                           )?.name | ||||
|                         } | ||||
|                       </span> | ||||
|                     </div> | ||||
|                   ) : ( | ||||
|                     <div className="flex flex-row flex-wrap gap-2"> | ||||
|                       {modelProvider.embeddingModels.map((model, index) => ( | ||||
|                         <div | ||||
|                           key={`${modelProvider.id}-embedding-${model.key}-${index}`} | ||||
|                           className="flex flex-row items-center space-x-1 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5" | ||||
|                         > | ||||
|                           <span>{model.name}</span> | ||||
|                           <button | ||||
|                             onClick={() => { | ||||
|                               handleModelDelete('embedding', model.key); | ||||
|                             }} | ||||
|                           > | ||||
|                             <X size={12} /> | ||||
|                           </button> | ||||
|                         </div> | ||||
|                       ))} | ||||
|                     </div> | ||||
|                   )} | ||||
|                 </div> | ||||
|             ) : modelProvider.chatModels.filter((m) => m.key !== 'error') | ||||
|                 .length === 0 && !hasError ? ( | ||||
|               <div className="flex flex-col items-center justify-center py-4 px-4 rounded-lg border-2 border-dashed border-light-200 dark:border-dark-200 bg-light-secondary/20 dark:bg-dark-secondary/20"> | ||||
|                 <p className="text-xs text-black/50 dark:text-white/50 text-center"> | ||||
|                   No chat models configured | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|           </motion.div> | ||||
|         )} | ||||
|       </AnimatePresence> | ||||
|             ) : modelProvider.chatModels.filter((m) => m.key !== 'error') | ||||
|                 .length > 0 ? ( | ||||
|               <div className="flex flex-row flex-wrap gap-2"> | ||||
|                 {modelProvider.chatModels.map((model, index) => ( | ||||
|                   <div | ||||
|                     key={`${modelProvider.id}-chat-${model.key}-${index}`} | ||||
|                     className="flex flex-row items-center space-x-1.5 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5 border border-light-200 dark:border-dark-200" | ||||
|                   > | ||||
|                     <span>{model.name}</span> | ||||
|                     <button | ||||
|                       onClick={() => { | ||||
|                         handleModelDelete('chat', model.key); | ||||
|                       }} | ||||
|                       className="hover:text-red-500 dark:hover:text-red-400 transition-colors" | ||||
|                     > | ||||
|                       <X size={12} /> | ||||
|                     </button> | ||||
|                   </div> | ||||
|                 ))} | ||||
|               </div> | ||||
|             ) : null} | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <div className="flex flex-col gap-y-2"> | ||||
|           <div className="flex flex-row w-full justify-between items-center"> | ||||
|             <p className="text-[11px] lg:text-xs font-medium text-black/70 dark:text-white/70 uppercase tracking-wide"> | ||||
|               Embedding Models | ||||
|             </p> | ||||
|             {!modelProvider.embeddingModels.some((m) => m.key === 'error') && ( | ||||
|               <AddModel | ||||
|                 providerId={modelProvider.id} | ||||
|                 setProviders={setProviders} | ||||
|                 type="embedding" | ||||
|               /> | ||||
|             )} | ||||
|           </div> | ||||
|           <div className="flex flex-col gap-2"> | ||||
|             {modelProvider.embeddingModels.some((m) => m.key === 'error') ? ( | ||||
|               <div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30"> | ||||
|                 <AlertCircle size={16} className="shrink-0" /> | ||||
|                 <span className="break-words"> | ||||
|                   { | ||||
|                     modelProvider.embeddingModels.find((m) => m.key === 'error') | ||||
|                       ?.name | ||||
|                   } | ||||
|                 </span> | ||||
|               </div> | ||||
|             ) : modelProvider.embeddingModels.filter((m) => m.key !== 'error') | ||||
|                 .length === 0 && !hasError ? ( | ||||
|               <div className="flex flex-col items-center justify-center py-4 px-4 rounded-lg border-2 border-dashed border-light-200 dark:border-dark-200 bg-light-secondary/20 dark:bg-dark-secondary/20"> | ||||
|                 <p className="text-xs text-black/50 dark:text-white/50 text-center"> | ||||
|                   No embedding models configured | ||||
|                 </p> | ||||
|               </div> | ||||
|             ) : modelProvider.embeddingModels.filter((m) => m.key !== 'error') | ||||
|                 .length > 0 ? ( | ||||
|               <div className="flex flex-row flex-wrap gap-2"> | ||||
|                 {modelProvider.embeddingModels.map((model, index) => ( | ||||
|                   <div | ||||
|                     key={`${modelProvider.id}-embedding-${model.key}-${index}`} | ||||
|                     className="flex flex-row items-center space-x-1.5 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5 border border-light-200 dark:border-dark-200" | ||||
|                   > | ||||
|                     <span>{model.name}</span> | ||||
|                     <button | ||||
|                       onClick={() => { | ||||
|                         handleModelDelete('embedding', model.key); | ||||
|                       }} | ||||
|                       className="hover:text-red-500 dark:hover:text-red-400 transition-colors" | ||||
|                     > | ||||
|                       <X size={12} /> | ||||
|                     </button> | ||||
|                   </div> | ||||
|                 ))} | ||||
|               </div> | ||||
|             ) : null} | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|   | ||||
| @@ -64,8 +64,8 @@ const ModelSelect = ({ | ||||
|           </h4> | ||||
|           <p className="text-[11px] lg:text-xs text-black/50 dark:text-white/50"> | ||||
|             {type === 'chat' | ||||
|               ? 'Select the model to use for chat responses' | ||||
|               : 'Select the model to use for embeddings'} | ||||
|               ? 'Choose which model to use for generating responses' | ||||
|               : 'Choose which model to use for generating embeddings'} | ||||
|           </p> | ||||
|         </div> | ||||
|         <Select | ||||
|   | ||||
| @@ -39,22 +39,50 @@ const Models = ({ | ||||
|       <div className="border-t border-light-200 dark:border-dark-200" /> | ||||
|       <div className="flex flex-row justify-between items-center px-6 "> | ||||
|         <p className="text-xs lg:text-sm text-black/70 dark:text-white/70"> | ||||
|           Manage model provider | ||||
|           Manage connections | ||||
|         </p> | ||||
|         <AddProvider modelProviders={fields} setProviders={setProviders} /> | ||||
|       </div> | ||||
|       <div className="flex flex-col px-6 gap-y-4"> | ||||
|         {providers.map((provider) => ( | ||||
|           <ModelProvider | ||||
|             key={`provider-${provider.id}`} | ||||
|             fields={ | ||||
|               (fields.find((f) => f.key === provider.type)?.fields ?? | ||||
|                 []) as UIConfigField[] | ||||
|             } | ||||
|             modelProvider={provider} | ||||
|             setProviders={setProviders} | ||||
|           /> | ||||
|         ))} | ||||
|         {providers.length === 0 ? ( | ||||
|           <div className="flex flex-col items-center justify-center py-12 px-4 rounded-lg border-2 border-dashed border-light-200 dark:border-dark-200 bg-light-secondary/10 dark:bg-dark-secondary/10"> | ||||
|             <div className="p-3 rounded-full bg-sky-500/10 dark:bg-sky-500/10 mb-3"> | ||||
|               <svg | ||||
|                 xmlns="http://www.w3.org/2000/svg" | ||||
|                 className="w-8 h-8 text-sky-500" | ||||
|                 fill="none" | ||||
|                 viewBox="0 0 24 24" | ||||
|                 stroke="currentColor" | ||||
|               > | ||||
|                 <path | ||||
|                   strokeLinecap="round" | ||||
|                   strokeLinejoin="round" | ||||
|                   strokeWidth={2} | ||||
|                   d="M13 10V3L4 14h7v7l9-11h-7z" | ||||
|                 /> | ||||
|               </svg> | ||||
|             </div> | ||||
|             <p className="text-sm font-medium text-black/70 dark:text-white/70 mb-1"> | ||||
|               No connections yet | ||||
|             </p> | ||||
|             <p className="text-xs text-black/50 dark:text-white/50 text-center max-w-sm mb-4"> | ||||
|               Add your first connection to start using AI models. Connect to | ||||
|               OpenAI, Anthropic, Ollama, and more. | ||||
|             </p> | ||||
|           </div> | ||||
|         ) : ( | ||||
|           providers.map((provider) => ( | ||||
|             <ModelProvider | ||||
|               key={`provider-${provider.id}`} | ||||
|               fields={ | ||||
|                 (fields.find((f) => f.key === provider.type)?.fields ?? | ||||
|                   []) as UIConfigField[] | ||||
|               } | ||||
|               modelProvider={provider} | ||||
|               setProviders={setProviders} | ||||
|             /> | ||||
|           )) | ||||
|         )} | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
|   | ||||
| @@ -67,10 +67,10 @@ const UpdateProvider = ({ | ||||
|         }); | ||||
|       }); | ||||
|  | ||||
|       toast.success('Provider updated successfully.'); | ||||
|       toast.success('Connection updated successfully.'); | ||||
|     } catch (error) { | ||||
|       console.error('Error updating provider:', error); | ||||
|       toast.error('Failed to update provider.'); | ||||
|       toast.error('Failed to update connection.'); | ||||
|     } finally { | ||||
|       setLoading(false); | ||||
|       setOpen(false); | ||||
| @@ -110,7 +110,7 @@ const UpdateProvider = ({ | ||||
|                 <form onSubmit={handleSubmit} className="flex flex-col flex-1"> | ||||
|                   <div className="px-6 pt-6 pb-4"> | ||||
|                     <h3 className="text-black/90 dark:text-white/90 font-medium"> | ||||
|                       Update provider | ||||
|                       Update connection | ||||
|                     </h3> | ||||
|                   </div> | ||||
|                   <div className="border-t border-light-200 dark:border-dark-200" /> | ||||
| @@ -121,13 +121,13 @@ const UpdateProvider = ({ | ||||
|                         className="flex flex-col items-start space-y-2" | ||||
|                       > | ||||
|                         <label className="text-xs text-black/70 dark:text-white/70"> | ||||
|                           Name* | ||||
|                           Connection Name* | ||||
|                         </label> | ||||
|                         <input | ||||
|                           value={name} | ||||
|                           onChange={(event) => setName(event.target.value)} | ||||
|                           className="w-full rounded-lg border border-light-200 dark:border-dark-200 bg-light-primary dark:bg-dark-primary px-4 py-3 pr-10 text-sm text-black/80 dark:text-white/80 placeholder:text-black/40 dark:placeholder:text-white/40 focus-visible:outline-none focus-visible:border-light-300 dark:focus-visible:border-dark-300 transition-colors disabled:cursor-not-allowed disabled:opacity-60" | ||||
|                           placeholder={'Provider Name'} | ||||
|                           placeholder={'Connection Name'} | ||||
|                           type="text" | ||||
|                           required={true} | ||||
|                         /> | ||||
| @@ -171,7 +171,7 @@ const UpdateProvider = ({ | ||||
|                       {loading ? ( | ||||
|                         <Loader2 className="animate-spin" size={16} /> | ||||
|                       ) : ( | ||||
|                         'Update Provider' | ||||
|                         'Update Connection' | ||||
|                       )} | ||||
|                     </button> | ||||
|                   </div> | ||||
|   | ||||
| @@ -28,7 +28,7 @@ const sections = [ | ||||
|   { | ||||
|     key: 'models', | ||||
|     name: 'Models', | ||||
|     description: 'Configure model settings.', | ||||
|     description: 'Connect to AI services and manage connections.', | ||||
|     icon: BrainCog, | ||||
|     component: Models, | ||||
|     dataAdd: 'modelProviders', | ||||
|   | ||||
| @@ -63,7 +63,11 @@ const SetupConfig = ({ | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   const hasProviders = providers.length > 0; | ||||
|   const visibleProviders = providers.filter( | ||||
|     (p) => p.name.toLowerCase() !== 'transformers', | ||||
|   ); | ||||
|   const hasProviders = | ||||
|     visibleProviders.filter((p) => p.chatModels.length > 0).length > 0; | ||||
|  | ||||
|   return ( | ||||
|     <div className="w-[95vw] md:w-[80vw] lg:w-[65vw] mx-auto px-2 sm:px-4 md:px-6 flex flex-col space-y-6"> | ||||
| @@ -81,10 +85,10 @@ const SetupConfig = ({ | ||||
|             <div className="flex flex-row justify-between items-center mb-4 md:mb-6 pb-3 md:pb-4 border-b border-light-200 dark:border-dark-200"> | ||||
|               <div> | ||||
|                 <p className="text-xs sm:text-sm font-medium text-black dark:text-white"> | ||||
|                   Manage Providers | ||||
|                   Manage Connections | ||||
|                 </p> | ||||
|                 <p className="text-[10px] sm:text-xs text-black/50 dark:text-white/50 mt-0.5"> | ||||
|                   Add and configure your model providers | ||||
|                   Add connections to access AI models | ||||
|                 </p> | ||||
|               </div> | ||||
|               <AddProvider | ||||
| @@ -100,14 +104,17 @@ const SetupConfig = ({ | ||||
|                     Loading providers... | ||||
|                   </p> | ||||
|                 </div> | ||||
|               ) : providers.length === 0 ? ( | ||||
|               ) : visibleProviders.length === 0 ? ( | ||||
|                 <div className="flex flex-col items-center justify-center py-8 md:py-12 text-center"> | ||||
|                   <p className="text-xs sm:text-sm font-medium text-black/70 dark:text-white/70"> | ||||
|                     No providers configured | ||||
|                     No connections configured | ||||
|                   </p> | ||||
|                   <p className="text-[10px] sm:text-xs text-black/50 dark:text-white/50 mt-1"> | ||||
|                     Click "Add Connection" above to get started | ||||
|                   </p> | ||||
|                 </div> | ||||
|               ) : ( | ||||
|                 providers.map((provider) => ( | ||||
|                 visibleProviders.map((provider) => ( | ||||
|                   <ModelProvider | ||||
|                     key={`provider-${provider.id}`} | ||||
|                     fields={ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user