@@ -6,13 +6,17 @@ import type { IProviderConfig } from '~/types/model';
66import { logStore } from '~/lib/stores/logs' ;
77
88// Import a default fallback icon
9- import DefaultIcon from '/icons/Default.svg' ; // Adjust the path as necessary
9+ import DefaultIcon from '/icons/Default.svg' ;
10+
11+ // List of advanced providers with correct casing
12+ const ADVANCED_PROVIDERS = [ 'Ollama' , 'OpenAILike' , 'LMStudio' ] ;
1013
1114export default function ProvidersTab ( ) {
1215 const { providers, updateProviderSettings, isLocalModel } = useSettings ( ) ;
1316 const [ filteredProviders , setFilteredProviders ] = useState < IProviderConfig [ ] > ( [ ] ) ;
17+ const [ advancedProviders , setAdvancedProviders ] = useState < IProviderConfig [ ] > ( [ ] ) ;
18+ const [ regularProviders , setRegularProviders ] = useState < IProviderConfig [ ] > ( [ ] ) ;
1419
15- // Load base URLs from cookies
1620 const [ searchTerm , setSearchTerm ] = useState ( '' ) ;
1721
1822 useEffect ( ( ) => {
@@ -31,11 +35,77 @@ export default function ProvidersTab() {
3135 newFilteredProviders = newFilteredProviders . filter ( ( provider ) => ! LOCAL_PROVIDERS . includes ( provider . name ) ) ;
3236 }
3337
34- newFilteredProviders . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
38+ // Split providers into regular and advanced
39+ const regular = newFilteredProviders . filter (
40+ ( provider ) => ! ADVANCED_PROVIDERS . includes ( provider . name )
41+ ) ;
42+ const advanced = newFilteredProviders . filter (
43+ ( provider ) => ADVANCED_PROVIDERS . includes ( provider . name )
44+ ) ;
45+
46+ // Sort advanced providers in specific order - OpenAILike at the end
47+ const advancedOrder = [ 'Ollama' , 'LMStudio' , 'OpenAILike' ] ;
48+ advanced . sort ( ( a , b ) => {
49+ return advancedOrder . indexOf ( a . name ) - advancedOrder . indexOf ( b . name ) ;
50+ } ) ;
51+
52+ // Sort regular providers alphabetically
53+ regular . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
3554
55+ setRegularProviders ( regular ) ;
56+ setAdvancedProviders ( advanced ) ;
3657 setFilteredProviders ( newFilteredProviders ) ;
3758 } , [ providers , searchTerm , isLocalModel ] ) ;
3859
60+ const ProviderCard = ( { provider } : { provider : IProviderConfig } ) => (
61+ < div className = "flex flex-col provider-item hover:bg-bolt-elements-bg-depth-3 p-4 rounded-lg border border-bolt-elements-borderColor" >
62+ < div className = "flex items-center justify-between mb-2" >
63+ < div className = "flex items-center gap-2" >
64+ < img
65+ src = { `/icons/${ provider . name } .svg` }
66+ onError = { ( e ) => {
67+ e . currentTarget . src = DefaultIcon ;
68+ } }
69+ alt = { `${ provider . name } icon` }
70+ className = "w-6 h-6 dark:invert"
71+ />
72+ < span className = "text-bolt-elements-textPrimary" > { provider . name } </ span >
73+ </ div >
74+ < Switch
75+ className = "ml-auto"
76+ checked = { provider . settings . enabled }
77+ onCheckedChange = { ( enabled ) => {
78+ updateProviderSettings ( provider . name , { ...provider . settings , enabled } ) ;
79+ if ( enabled ) {
80+ logStore . logProvider ( `Provider ${ provider . name } enabled` , { provider : provider . name } ) ;
81+ } else {
82+ logStore . logProvider ( `Provider ${ provider . name } disabled` , { provider : provider . name } ) ;
83+ }
84+ } }
85+ />
86+ </ div >
87+ { URL_CONFIGURABLE_PROVIDERS . includes ( provider . name ) && provider . settings . enabled && (
88+ < div className = "mt-2" >
89+ < label className = "block text-sm text-bolt-elements-textSecondary mb-1" > Base URL:</ label >
90+ < input
91+ type = "text"
92+ value = { provider . settings . baseUrl || '' }
93+ onChange = { ( e ) => {
94+ const newBaseUrl = e . target . value ;
95+ updateProviderSettings ( provider . name , { ...provider . settings , baseUrl : newBaseUrl } ) ;
96+ logStore . logProvider ( `Base URL updated for ${ provider . name } ` , {
97+ provider : provider . name ,
98+ baseUrl : newBaseUrl ,
99+ } ) ;
100+ } }
101+ placeholder = { `Enter ${ provider . name } base URL` }
102+ className = "w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
103+ />
104+ </ div >
105+ ) }
106+ </ div >
107+ ) ;
108+
39109 return (
40110 < div className = "p-4" >
41111 < div className = "flex mb-4" >
@@ -47,60 +117,29 @@ export default function ProvidersTab() {
47117 className = "w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
48118 />
49119 </ div >
50- { filteredProviders . map ( ( provider ) => (
51- < div
52- key = { provider . name }
53- className = "flex flex-col mb-2 provider-item hover:bg-bolt-elements-bg-depth-3 p-4 rounded-lg border border-bolt-elements-borderColor "
54- >
55- < div className = "flex items-center justify-between mb-2" >
56- < div className = "flex items-center gap-2" >
57- < img
58- src = { `/icons/${ provider . name } .svg` } // Attempt to load the specific icon
59- onError = { ( e ) => {
60- // Fallback to default icon on error
61- e . currentTarget . src = DefaultIcon ;
62- } }
63- alt = { `${ provider . name } icon` }
64- className = "w-6 h-6 dark:invert"
65- />
66- < span className = "text-bolt-elements-textPrimary" > { provider . name } </ span >
67- </ div >
68- < Switch
69- className = "ml-auto"
70- checked = { provider . settings . enabled }
71- onCheckedChange = { ( enabled ) => {
72- updateProviderSettings ( provider . name , { ...provider . settings , enabled } ) ;
73120
74- if ( enabled ) {
75- logStore . logProvider ( `Provider ${ provider . name } enabled` , { provider : provider . name } ) ;
76- } else {
77- logStore . logProvider ( `Provider ${ provider . name } disabled` , { provider : provider . name } ) ;
78- }
79- } }
80- />
121+ { /* Regular Providers Grid */ }
122+ < div className = "grid grid-cols-2 gap-4 mb-8" >
123+ { regularProviders . map ( ( provider ) => (
124+ < ProviderCard key = { provider . name } provider = { provider } />
125+ ) ) }
126+ </ div >
127+
128+ { /* Advanced Providers Section */ }
129+ { advancedProviders . length > 0 && (
130+ < div className = "mb-4 border-t border-bolt-elements-borderColor pt-4" >
131+ < h3 className = "text-bolt-elements-textSecondary text-lg font-medium mb-2" > Experimental Providers</ h3 >
132+ < p className = "text-bolt-elements-textSecondary mb-6" >
133+ These providers are experimental features that allow you to run AI models locally or connect to your own infrastructure.
134+ They require additional setup but offer more flexibility for advanced users.
135+ </ p >
136+ < div className = "grid grid-cols-2 gap-4" >
137+ { advancedProviders . map ( ( provider ) => (
138+ < ProviderCard key = { provider . name } provider = { provider } />
139+ ) ) }
81140 </ div >
82- { /* Base URL input for configurable providers */ }
83- { URL_CONFIGURABLE_PROVIDERS . includes ( provider . name ) && provider . settings . enabled && (
84- < div className = "mt-2" >
85- < label className = "block text-sm text-bolt-elements-textSecondary mb-1" > Base URL:</ label >
86- < input
87- type = "text"
88- value = { provider . settings . baseUrl || '' }
89- onChange = { ( e ) => {
90- const newBaseUrl = e . target . value ;
91- updateProviderSettings ( provider . name , { ...provider . settings , baseUrl : newBaseUrl } ) ;
92- logStore . logProvider ( `Base URL updated for ${ provider . name } ` , {
93- provider : provider . name ,
94- baseUrl : newBaseUrl ,
95- } ) ;
96- } }
97- placeholder = { `Enter ${ provider . name } base URL` }
98- className = "w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
99- />
100- </ div >
101- ) }
102141 </ div >
103- ) ) }
142+ ) }
104143 </ div >
105144 ) ;
106145}
0 commit comments