import React, { memo, useMemo, useCallback, useState } from 'react'; import { ProviderCard } from './subcomponents/ProviderCard'; import CardContainer from './subcomponents/CardContainer'; import ProviderConfigurationModal from './modal/ProviderConfiguationModal'; import { DeclarativeProviderConfig, ProviderDetails, UpdateCustomProviderRequest, } from '../../../api'; import { Plus } from 'lucide-react'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../../ui/dialog'; import CustomProviderForm from './modal/subcomponents/forms/CustomProviderForm'; import { SwitchModelModal } from '../models/subcomponents/SwitchModelModal'; import type { View } from '../../../utils/navigationUtils'; const GridLayout = memo(function GridLayout({ children }: { children: React.ReactNode }) { return (
{children}
); }); const CustomProviderCard = memo(function CustomProviderCard({ onClick }: { onClick: () => void }) { return (
Add
Custom Provider
} grayedOut={false} borderStyle="dashed" /> ); }); function ProviderCards({ providers, isOnboarding, refreshProviders, setView, onModelSelected, }: { providers: ProviderDetails[]; isOnboarding: boolean; refreshProviders?: () => void; setView?: (view: View) => void; onModelSelected?: (model?: string) => void; }) { const [configuringProvider, setConfiguringProvider] = useState(null); const [showCustomProviderModal, setShowCustomProviderModal] = useState(false); const [showSwitchModelModal, setShowSwitchModelModal] = useState(false); const [switchModelProvider, setSwitchModelProvider] = useState(null); const [editingProvider, setEditingProvider] = useState<{ id: string; config: DeclarativeProviderConfig; isEditable: boolean; } | null>(null); const handleProviderLaunchWithModelSelection = useCallback((provider: ProviderDetails) => { setSwitchModelProvider(provider.name); setShowSwitchModelModal(true); }, []); const openModal = useCallback( (provider: ProviderDetails) => setConfiguringProvider(provider), [] ); const configureProviderViaModal = useCallback( async (provider: ProviderDetails) => { if (provider.provider_type === 'Custom' || provider.provider_type === 'Declarative') { const { getCustomProvider } = await import('../../../api'); const result = await getCustomProvider({ path: { id: provider.name }, throwOnError: true }); if (result.data) { setEditingProvider({ id: provider.name, config: result.data.config, isEditable: result.data.is_editable, }); setShowCustomProviderModal(true); } } else { openModal(provider); } }, [openModal] ); const handleUpdateCustomProvider = useCallback( async (data: UpdateCustomProviderRequest) => { if (!editingProvider) return; const { updateCustomProvider } = await import('../../../api'); await updateCustomProvider({ path: { id: editingProvider.id }, body: data, throwOnError: true, }); const providerId = editingProvider.id; setShowCustomProviderModal(false); setEditingProvider(null); if (refreshProviders) { refreshProviders(); } setSwitchModelProvider(providerId); setShowSwitchModelModal(true); }, [editingProvider, refreshProviders] ); const handleCloseModal = useCallback(() => { setShowCustomProviderModal(false); setEditingProvider(null); }, []); const onCloseProviderConfig = useCallback(() => { setConfiguringProvider(null); if (refreshProviders) { refreshProviders(); } }, [refreshProviders]); const onProviderConfigured = useCallback( (provider: ProviderDetails) => { setConfiguringProvider(null); if (refreshProviders) { refreshProviders(); } setSwitchModelProvider(provider.name); setShowSwitchModelModal(true); }, [refreshProviders] ); const onCloseSwitchModelModal = useCallback(() => { setShowSwitchModelModal(false); }, []); const handleSetView = useCallback( (view: View) => { setShowSwitchModelModal(false); if (setView) { setView(view); } }, [setView] ); const handleCreateCustomProvider = useCallback( async (data: UpdateCustomProviderRequest) => { const { createCustomProvider } = await import('../../../api'); await createCustomProvider({ body: data, throwOnError: true }); setShowCustomProviderModal(false); if (refreshProviders) { refreshProviders(); } setShowSwitchModelModal(true); }, [refreshProviders] ); const providerCards = useMemo(() => { // providers needs to be an array const providersArray = Array.isArray(providers) ? providers : []; // Sort providers alphabetically by name const sortedProviders = [...providersArray].sort((a, b) => a.name.localeCompare(b.name)); const cards = sortedProviders.map((provider) => ( configureProviderViaModal(provider)} onLaunch={() => handleProviderLaunchWithModelSelection(provider)} isOnboarding={isOnboarding} /> )); cards.push( setShowCustomProviderModal(true)} /> ); return cards; }, [providers, isOnboarding, configureProviderViaModal, handleProviderLaunchWithModelSelection]); const initialData = editingProvider && { engine: editingProvider.config.engine, display_name: editingProvider.config.display_name, api_url: editingProvider.config.base_url, api_key: '', models: editingProvider.config.models.map((m) => m.name), supports_streaming: editingProvider.config.supports_streaming ?? true, requires_auth: editingProvider.config.requires_auth ?? true, }; const editable = editingProvider ? editingProvider.isEditable : true; const title = (editingProvider ? (editable ? 'Edit' : 'Configure') : 'Add') + ' Provider'; return ( <> {providerCards} {title} {' '} {configuringProvider && ( )} {showSwitchModelModal && ( )} ); } export default function ProviderGrid({ providers, isOnboarding, refreshProviders, setView, onModelSelected, }: { providers: ProviderDetails[]; isOnboarding: boolean; refreshProviders?: () => void; setView?: (view: View) => void; onModelSelected?: (model?: string) => void; }) { return ( ); }