+ {providerModels.db_models.length > 0 && (
+
+ Custom models override or extend the
+ provider's catalog.
+
+ )}
+
+
+ handleBatchOverride(provider.id)
+ }
>
-
- {providerModels.db_models.length > 0 && (
-
- Custom models override or extend the
- provider's catalog.
+
+ Batch Override
+
+
handleAddModel(provider.id)}
+ >
+
+ Add Custom Model
+
+
+
+ {providerModels.db_models.length === 0 ? (
+
+ No custom models configured
+
+ ) : (
+
+ {providerModels.db_models.map((model) => (
+
+
+
+
+ {model.id}
+
+
+ {model.enabled
+ ? 'Enabled'
+ : 'Disabled'}
+
+
+
+ {model.description || model.name}
+
+
+
+
+ {model.context_length?.toLocaleString()}{' '}
+ tokens
- )}
-
- handleBatchOverride(provider.id)
+ handleEditModel(provider.id, model)
}
>
-
- Batch Override
+
- handleAddModel(provider.id)
+ handleDeleteModel(
+ provider.id,
+ model.id
+ )
}
+ disabled={deleteModelMutation.isPending}
>
-
- Add Custom Model
+
- {providerModels.db_models.length === 0 ? (
-
- No custom models configured
-
- ) : (
-
- {providerModels.db_models.map((model) => (
-
-
-
-
- {model.id}
-
-
- {model.enabled
- ? 'Enabled'
- : 'Disabled'}
-
-
-
- {model.description || model.name}
-
-
-
-
- {model.context_length?.toLocaleString()}{' '}
- tokens
-
-
- handleEditModel(
- provider.id,
- model
- )
- }
- >
-
-
-
- handleDeleteModel(
- provider.id,
- model.id
- )
- }
- disabled={
- deleteModelMutation.isPending
- }
- >
-
-
-
-
- ))}
-
- )}
-
-
+ )}
+
+
+
+ These models are provided directly by the upstream
+ service.
+
+
+ {providerModels.remote_models.map((model) => (
+
- {providerModels.remote_models.length > 0 ? (
- <>
-
- Models automatically discovered from the
- provider's catalog.
-
-
- {providerModels.remote_models.map(
- (model) => (
-
-
-
- {model.id}
-
-
- {model.description ||
- model.name}
-
-
-
-
- {model.context_length?.toLocaleString()}{' '}
- tokens
-
-
- handleOverrideModel(
- provider.id,
- model
- )
- }
- >
-
- Override
-
-
-
- )
- )}
-
- >
- ) : (
-
- No provided models available
+
+
+
+ {model.id}
+
- )}
-
-
- ) : null}
+
+ {model.name}
+
+
+
+
+ {model.context_length?.toLocaleString()}{' '}
+ tokens
+
+
+ handleOverrideModel(provider.id, model)
+ }
+ >
+
+ Override
+
+
+
+ ))}
+
+
+
+ ) : null}
+
+ );
+
+ if (provider.provider_type === 'routstr') {
+ return (
+
+ toggleProviderExpansion(provider.id)
+ }
+ onEdit={() => handleEdit(provider)}
+ onDelete={() => handleDelete(provider.id)}
+ balanceComponent={
+
+ }
+ >
+
+
+
+ {provider.api_version && (
+
+
+ API Version:
+
+
+ {provider.api_version}
+
+
+ )}
+
+ {modelsContent}
- )}
-
-
-
- ))}
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ {provider.provider_type}
+
+
+ {provider.enabled ? 'Enabled' : 'Disabled'}
+
+
+
+ {provider.base_url}
+
+
+
+ {canShowBalance(provider.provider_type) &&
+ provider.api_key && (
+
+ )}
+
+ toggleProviderExpansion(provider.id)
+ }
+ className='w-full sm:w-auto'
+ >
+
+ Models
+ {expandedProviders.has(provider.id) ? (
+
+ ) : (
+
+ )}
+
+
handleEdit(provider)}
+ className='w-full sm:w-auto'
+ >
+
+
+
handleDelete(provider.id)}
+ className='w-full sm:w-auto'
+ >
+
+
+
+
+
+
+
+
+ {provider.api_version && (
+
+
+ API Version:
+
+
+ {provider.api_version}
+
+
+ )}
+
+ {modelsContent}
+
+
+
+ );
+ })}
)}
@@ -1418,7 +1440,6 @@ export default function ProvidersPage() {
void;
+ onEdit: () => void;
+ onDelete: () => void;
+ balanceComponent: React.ReactNode;
+ children?: React.ReactNode;
+}
+
+export function RoutstrProviderCard({
+ provider,
+ expanded,
+ onToggleExpand,
+ onEdit,
+ onDelete,
+ balanceComponent,
+ children,
+}: RoutstrProviderCardProps) {
+ const queryClient = useQueryClient();
+
+ const refundMutation = useMutation({
+ mutationFn: () => RoutstrProviderService.refundBalance(provider.id),
+ onSuccess: (data) => {
+ if (data.ok) {
+ toast.success('Refund successful', {
+ description: data.message,
+ });
+ queryClient.invalidateQueries({
+ queryKey: ['provider-balance', provider.id],
+ });
+ queryClient.invalidateQueries({ queryKey: ['balances'] }); // Global wallet balance
+ } else {
+ toast.error('Refund failed', {
+ description: data.message,
+ });
+ }
+ },
+ onError: (error: Error) => {
+ toast.error(`Refund error: ${error.message}`);
+ },
+ });
+
+ return (
+
+
+
+
+
+ Routstr Node
+
+ {provider.enabled ? 'Enabled' : 'Disabled'}
+
+
+ NIP-91
+
+
+
+ {provider.base_url}
+
+
+
+
{balanceComponent}
+
+
refundMutation.mutate()}
+ disabled={refundMutation.isPending}
+ className='text-orange-600 hover:text-orange-700 dark:text-orange-400'
+ title='Refund balance to local wallet'
+ >
+
+ Refund
+
+
+
+
+ Models
+ {expanded ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+ {children}
+
+ );
+}