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 (
}
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}
{' '}
{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 (
);
}