isSelectable && isConfigured && onSelect?.()}
className={`relative bg-bgApp rounded-lg
diff --git a/ui/desktop/src/components/settings/providers/ConfigureProviders.tsx b/ui/desktop/src/components/settings/providers/ConfigureProviders.tsx
index bd472ba6f..68aa6ee0a 100644
--- a/ui/desktop/src/components/settings/providers/ConfigureProviders.tsx
+++ b/ui/desktop/src/components/settings/providers/ConfigureProviders.tsx
@@ -1,5 +1,4 @@
import React from 'react';
-import { Providers } from './Provider';
import { ScrollArea } from '../../ui/scroll-area';
import BackButton from '../../ui/BackButton';
import { ConfigureProvidersGrid } from './ConfigureProvidersGrid';
diff --git a/ui/desktop/src/components/settings/providers/ConfigureProvidersGrid.tsx b/ui/desktop/src/components/settings/providers/ConfigureProvidersGrid.tsx
index fa69cf84b..2e83621f8 100644
--- a/ui/desktop/src/components/settings/providers/ConfigureProvidersGrid.tsx
+++ b/ui/desktop/src/components/settings/providers/ConfigureProvidersGrid.tsx
@@ -1,8 +1,7 @@
import React, { useMemo, useState } from 'react';
import { useActiveKeys } from '../api_keys/ActiveKeysContext';
-import { BaseProviderGrid } from './BaseProviderGrid';
+import { BaseProviderGrid, getProviderDescription } from './BaseProviderGrid';
import { supported_providers, provider_aliases, required_keys } from '../models/hardcoded_stuff';
-import { getProviderDescription } from './Provider';
import { ProviderSetupModal } from '../ProviderSetupModal';
import { getApiUrl, getSecretKey } from '../../../config';
import { toast } from 'react-toastify';
diff --git a/ui/desktop/src/components/settings/providers/Header.tsx b/ui/desktop/src/components/settings/providers/Header.tsx
deleted file mode 100644
index ff67e98a0..000000000
--- a/ui/desktop/src/components/settings/providers/Header.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import { useNavigate } from 'react-router-dom';
-import { FaArrowLeft } from 'react-icons/fa';
-
-export default function Header() {
- const navigate = useNavigate();
-
- return (
-
- navigate(-1)}
- className="mr-4 p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full transition-colors"
- title="Go back"
- >
-
-
-
Providers
-
- );
-}
diff --git a/ui/desktop/src/components/settings/providers/Provider.tsx b/ui/desktop/src/components/settings/providers/Provider.tsx
deleted file mode 100644
index 82956604b..000000000
--- a/ui/desktop/src/components/settings/providers/Provider.tsx
+++ /dev/null
@@ -1,378 +0,0 @@
-import { supported_providers, required_keys, provider_aliases } from '../models/hardcoded_stuff';
-import { useActiveKeys } from '../api_keys/ActiveKeysContext';
-import { ProviderSetupModal } from '../ProviderSetupModal';
-import React from 'react';
-import {
- Accordion,
- AccordionContent,
- AccordionItem,
- AccordionTrigger,
-} from '@radix-ui/react-accordion';
-import { Check, ChevronDown, Edit2, Plus, X } from 'lucide-react';
-import { Button } from '../../ui/button';
-import { getApiUrl, getSecretKey } from '../../../config';
-import { getActiveProviders } from '../api_keys/utils';
-import { toast } from 'react-toastify';
-import { useModel } from '../models/ModelContext';
-
-function ConfirmationModal({ message, onConfirm, onCancel }) {
- return (
-
-
-
{message}
-
-
- Cancel
-
-
- Confirm
-
-
-
-
- );
-}
-
-// Utility Functions
-export function getProviderDescription(provider) {
- const descriptions = {
- OpenAI: 'Access GPT-4, GPT-3.5 Turbo, and other OpenAI models',
- Anthropic: 'Access Claude and other Anthropic models',
- Google: 'Access Gemini and other Google AI models',
- Groq: 'Access Mixtral and other Groq-hosted models',
- Databricks: 'Access models hosted on your Databricks instance',
- OpenRouter: 'Access a variety of AI models through OpenRouter',
- Ollama: 'Run and use open-source models locally',
- };
- return descriptions[provider] || `Access ${provider} models`;
-}
-
-function useProviders(activeKeys) {
- return React.useMemo(() => {
- return supported_providers.map((providerName) => {
- const alias =
- provider_aliases.find((p) => p.provider === providerName)?.alias ||
- providerName.toLowerCase();
- const requiredKeys = required_keys[providerName] || [];
- const isConfigured = activeKeys.includes(providerName);
-
- return {
- id: alias,
- name: providerName,
- keyName: requiredKeys,
- isConfigured,
- description: getProviderDescription(providerName),
- };
- });
- }, [activeKeys]);
-}
-
-// Reusable Components
-function ProviderStatus({ isConfigured }) {
- return isConfigured ? (
-
-
- Configured
-
- ) : (
-
-
- Not Configured
-
- );
-}
-
-function ProviderKeyList({ keyNames, activeKeys }) {
- return keyNames.length > 0 ? (
-
-
Required API Keys:
- {keyNames.map((key) => (
-
- {key}
- {activeKeys.includes(key) && }
-
- ))}
-
- ) : (
-
No API keys required
- );
-}
-
-function ProviderActions({ provider, onEdit, onDelete, onAdd }) {
- if (!provider.keyName || provider.keyName.length === 0) {
- return null;
- }
-
- return provider.isConfigured ? (
-
- onEdit(provider)}
- className="h-9 px-4 text-sm whitespace-nowrap shrink-0
- bg-gray-800 text-white dark:bg-gray-200 dark:text-gray-900
- rounded-full shadow-md border-none
- hover:bg-gray-700 hover:text-white
- focus:outline-none focus:ring-2 focus:ring-gray-500
- dark:hover:bg-gray-300 dark:hover:text-gray-900"
- >
-
- Edit Keys
-
- onDelete(provider)}
- className="h-9 px-4 text-sm whitespace-nowrap shrink-0
- rounded-full shadow-sm border-red-200 dark:border-red-800
- text-red-600 dark:text-red-500
- hover:bg-red-50 hover:text-red-700 hover:border-red-300
- dark:hover:bg-red-950/50 dark:hover:text-red-400
- focus:outline-none focus:ring-2 focus:ring-red-500"
- >
- Delete Keys
-
-
- ) : (
-
onAdd(provider)}
- className="h-9 px-4 text-sm whitespace-nowrap shrink-0
- bg-gray-800 text-white dark:bg-gray-200 dark:text-gray-900
- rounded-full shadow-md border-none
- hover:bg-gray-700 hover:text-white
- focus:outline-none focus:ring-2 focus:ring-gray-500
- dark:hover:bg-gray-300 dark:hover:text-gray-900"
- >
-
- Add Keys
-
- );
-}
-
-function ProviderItem({ provider, activeKeys, onEdit, onDelete, onAdd }) {
- return (
-
-
-
-
-
-
-
{provider.description}
-
-
-
-
- );
-}
-
-// Main Component
-export function Providers() {
- const { activeKeys, setActiveKeys } = useActiveKeys();
- const providers = useProviders(activeKeys);
- const [selectedProvider, setSelectedProvider] = React.useState(null);
- const [isModalOpen, setIsModalOpen] = React.useState(false);
- const [isConfirmationOpen, setIsConfirmationOpen] = React.useState(false);
- const { currentModel } = useModel();
-
- const handleEdit = (provider) => {
- setSelectedProvider(provider);
- setIsModalOpen(true);
- };
-
- const handleAdd = (provider) => {
- setSelectedProvider(provider);
- setIsModalOpen(true);
- };
-
- const handleModalSubmit = async (apiKey) => {
- if (!selectedProvider) return;
-
- const provider = selectedProvider.name;
- const keyName = required_keys[provider]?.[0]; // Get the first key, assuming one key per provider
-
- if (!keyName) {
- console.error(`No key found for provider ${provider}`);
- return;
- }
-
- try {
- if (selectedProvider.isConfigured) {
- // Delete existing key logic if configured
- const deleteResponse = await fetch(getApiUrl('/secrets/delete'), {
- method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json',
- 'X-Secret-Key': getSecretKey(),
- },
- body: JSON.stringify({ key: keyName }),
- });
-
- if (!deleteResponse.ok) {
- const errorText = await deleteResponse.text();
- console.error('Delete response error:', errorText);
- throw new Error('Failed to delete old key');
- }
-
- console.log('Old key deleted successfully.');
- }
-
- // Store new key logic
- const storeResponse = await fetch(getApiUrl('/secrets/store'), {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-Secret-Key': getSecretKey(),
- },
- body: JSON.stringify({
- key: keyName,
- value: apiKey.trim(),
- }),
- });
-
- if (!storeResponse.ok) {
- const errorText = await storeResponse.text();
- console.error('Store response error:', errorText);
- throw new Error('Failed to store new key');
- }
-
- console.log('Key stored successfully.');
-
- // Show success toast
- toast.success(
- selectedProvider.isConfigured
- ? `Successfully updated API key for ${provider}`
- : `Successfully added API key for ${provider}`
- );
-
- // Update active keys
- const updatedKeys = await getActiveProviders();
- setActiveKeys(updatedKeys);
-
- setIsModalOpen(false);
- } catch (error) {
- console.error('Error handling modal submit:', error);
- }
- };
-
- const handleDelete = (provider) => {
- setSelectedProvider(provider);
- setIsConfirmationOpen(true);
- };
-
- const confirmDelete = async () => {
- if (!selectedProvider) return;
-
- const provider = selectedProvider.name;
- const keyName = required_keys[provider]?.[0]; // Get the first key, assuming one key per provider
-
- if (!keyName) {
- console.error(`No key found for provider ${provider}`);
- return;
- }
-
- try {
- // Check if the selected provider is currently active
- if (currentModel?.provider === provider) {
- toast.error(
- `Cannot delete the API key for ${provider} because it's the provider of the current model (${currentModel.name}). Please switch to a different model first.`
- );
- setIsConfirmationOpen(false);
- return;
- }
-
- // Delete old key logic
- const deleteResponse = await fetch(getApiUrl('/secrets/delete'), {
- method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json',
- 'X-Secret-Key': getSecretKey(),
- },
- body: JSON.stringify({ key: keyName }),
- });
-
- if (!deleteResponse.ok) {
- const errorText = await deleteResponse.text();
- console.error('Delete response error:', errorText);
- throw new Error('Failed to delete key');
- }
-
- console.log('Key deleted successfully.');
- // Show success toast
- toast.success(`Successfully deleted API key for ${provider}`);
-
- // Update active keys
- const updatedKeys = await getActiveProviders();
- setActiveKeys(updatedKeys);
-
- setIsConfirmationOpen(false);
- } catch (error) {
- console.error('Error confirming delete:', error);
- // Show success toast
- toast.error(`Unable to delete API key for ${provider}`);
- }
- };
-
- return (
-
-
- Configure your AI model providers by adding their API keys. Your keys are stored securely
- and encrypted locally.
-
-
-
- {providers.map((provider) => (
-
- ))}
-
-
- {isModalOpen && selectedProvider && (
-
setIsModalOpen(false)}
- />
- )}
-
- {isConfirmationOpen && selectedProvider && (
- setIsConfirmationOpen(false)}
- />
- )}
-
- );
-}
diff --git a/ui/desktop/src/components/settings/providers/ProviderGrid.tsx b/ui/desktop/src/components/welcome_screen/ProviderGrid.tsx
similarity index 57%
rename from ui/desktop/src/components/settings/providers/ProviderGrid.tsx
rename to ui/desktop/src/components/welcome_screen/ProviderGrid.tsx
index c985af7b1..dde700cf8 100644
--- a/ui/desktop/src/components/settings/providers/ProviderGrid.tsx
+++ b/ui/desktop/src/components/welcome_screen/ProviderGrid.tsx
@@ -1,105 +1,22 @@
import React from 'react';
-import { Check, Plus } from 'lucide-react';
-import { Button } from '../../ui/button';
-import { supported_providers, required_keys, provider_aliases } from '../models/hardcoded_stuff';
-import { useActiveKeys } from '../api_keys/ActiveKeysContext';
-import { getProviderDescription } from './Provider';
-import { ProviderSetupModal } from '../ProviderSetupModal';
-import { useModel } from '../models/ModelContext';
-import { useRecentModels } from '../models/RecentModels';
-import { createSelectedModel } from '../models/utils';
-import { getDefaultModel } from '../models/hardcoded_stuff';
-import { initializeSystem } from '../../../utils/providerUtils';
-import { getApiUrl, getSecretKey } from '../../../config';
+import { Button } from '../ui/button';
+import {
+ supported_providers,
+ required_keys,
+ provider_aliases,
+} from '../settings/models/hardcoded_stuff';
+import { useActiveKeys } from '../settings/api_keys/ActiveKeysContext';
+import { ProviderSetupModal } from '../settings/ProviderSetupModal';
+import { useModel } from '../settings/models/ModelContext';
+import { useRecentModels } from '../settings/models/RecentModels';
+import { createSelectedModel } from '../settings/models/utils';
+import { getDefaultModel } from '../settings/models/hardcoded_stuff';
+import { initializeSystem } from '../../utils/providerUtils';
+import { getApiUrl, getSecretKey } from '../../config';
import { toast } from 'react-toastify';
-import { getActiveProviders } from '../api_keys/utils';
-import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/Tooltip';
+import { getActiveProviders } from '../settings/api_keys/utils';
import { useNavigate } from 'react-router-dom';
-import { BaseProviderGrid } from './BaseProviderGrid';
-
-interface ProviderCardProps {
- name: string;
- description: string;
- isConfigured: boolean;
- onConfigure: () => void;
- onAddKeys: () => void;
- isSelected: boolean;
- onSelect: () => void;
-}
-
-function getArticle(word: string): string {
- return 'aeiouAEIOU'.indexOf(word[0]) >= 0 ? 'an' : 'a';
-}
-
-function ProviderCard({
- name,
- description,
- isConfigured,
- onConfigure,
- onAddKeys,
- isSelected,
- onSelect,
-}: ProviderCardProps) {
- return (
-
isConfigured && onSelect()}
- className={`relative bg-white dark:bg-gray-800 rounded-lg border
- ${
- isSelected
- ? 'border-blue-500 dark:border-blue-400 shadow-[0_0_0_1px] shadow-blue-500/50'
- : 'border-gray-200 dark:border-gray-700'
- }
- p-3 transition-all duration-200 h-[140px] overflow-hidden
- ${isConfigured ? 'cursor-pointer hover:border-blue-400 dark:hover:border-blue-300' : ''}
- `}
- >
-
-
-
- {name}
-
- {isConfigured && (
-
-
-
-
-
-
-
-
-
- You have {getArticle(name)} {name} API Key set in your environment
-
-
-
-
- )}
-
-
-
-
- {description}
-
-
-
- {!isConfigured && (
-
{
- e.stopPropagation();
- onAddKeys();
- }}
- className="rounded-full h-7 px-3 min-w-[90px] bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-900 dark:text-gray-100 text-xs"
- >
-
- Add Key
-
- )}
-
-
- );
-}
+import { BaseProviderGrid, getProviderDescription } from '../settings/providers/BaseProviderGrid';
interface ProviderGridProps {
onSubmit?: () => void;
@@ -249,20 +166,16 @@ export function ProviderGrid({ onSubmit }: ProviderGridProps) {
const provider = providers.find((p) => p.id === selectedId);
if (provider) handleConfigure(provider);
}}
- className="rounded-full px-6 py-2 min-w-[160px] bg-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-700 text-white dark:text-white text-sm font-medium shadow-md hover:shadow-lg transition-all"
+ className={
+ 'bg-black dark:bg-white dark:hover:bg-gray-200 text-white dark:!text-black border-borderStandard hover:bg-slate text-sm whitespace-nowrap shrink-0 bg-bgSubtle text-textStandard rounded-full shadow-none border px-4 py-2'
+ }
>
- Select {providers.find((p) => p.id === selectedId)?.name}
+ Let's takeoff