@@ -6,17 +6,14 @@ 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' ;
10- const ADVANCED_PROVIDERS = [ 'Ollama' , 'OpenAILike' , 'LMStudio' ] ;
9+ import DefaultIcon from '/icons/Default.svg' ; // Adjust the path as necessary
1110import { providerBaseUrlEnvKeys } from '~/utils/constants' ;
1211
13-
1412export default function ProvidersTab ( ) {
1513 const { providers, updateProviderSettings, isLocalModel } = useSettings ( ) ;
1614 const [ filteredProviders , setFilteredProviders ] = useState < IProviderConfig [ ] > ( [ ] ) ;
17- const [ advancedProviders , setAdvancedProviders ] = useState < IProviderConfig [ ] > ( [ ] ) ;
18- const [ regularProviders , setRegularProviders ] = useState < IProviderConfig [ ] > ( [ ] ) ;
1915
16+ // Load base URLs from cookies
2017 const [ searchTerm , setSearchTerm ] = useState ( '' ) ;
2118
2219 useEffect ( ( ) => {
@@ -35,76 +32,88 @@ export default function ProvidersTab() {
3532 newFilteredProviders = newFilteredProviders . filter ( ( provider ) => ! LOCAL_PROVIDERS . includes ( provider . name ) ) ;
3633 }
3734
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- } ) ;
35+ newFilteredProviders . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
5136
52- // Sort regular providers alphabetically
53- regular . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
37+ // Split providers into regular and URL-configurable
38+ const regular = newFilteredProviders . filter ( p => ! URL_CONFIGURABLE_PROVIDERS . includes ( p . name ) ) ;
39+ const urlConfigurable = newFilteredProviders . filter ( p => URL_CONFIGURABLE_PROVIDERS . includes ( p . name ) ) ;
5440
55- setRegularProviders ( regular ) ;
56- setAdvancedProviders ( advanced ) ;
57- setFilteredProviders ( newFilteredProviders ) ;
41+ setFilteredProviders ( [ ...regular , ...urlConfigurable ] ) ;
5842 } , [ providers , searchTerm , isLocalModel ] ) ;
5943
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 ;
44+ const renderProviderCard = ( provider : IProviderConfig ) => {
45+ const envBaseUrlKey = providerBaseUrlEnvKeys [ provider . name ] . baseUrlKey ;
46+ const envBaseUrl = envBaseUrlKey ? import . meta. env [ envBaseUrlKey ] : undefined ;
47+ const isUrlConfigurable = URL_CONFIGURABLE_PROVIDERS . includes ( provider . name ) ;
48+
49+ return (
50+ < div
51+ key = { provider . name }
52+ className = "flex flex-col provider-item hover:bg-bolt-elements-bg-depth-3 p-4 rounded-lg border border-bolt-elements-borderColor"
53+ >
54+ < div className = "flex items-center justify-between mb-2" >
55+ < div className = "flex items-center gap-2" >
56+ < img
57+ src = { `/icons/${ provider . name } .svg` }
58+ onError = { ( e ) => {
59+ e . currentTarget . src = DefaultIcon ;
60+ } }
61+ alt = { `${ provider . name } icon` }
62+ className = "w-6 h-6 dark:invert"
63+ />
64+ < span className = "text-bolt-elements-textPrimary" > { provider . name } </ span >
65+ </ div >
66+ < Switch
67+ className = "ml-auto"
68+ checked = { provider . settings . enabled }
69+ onCheckedChange = { ( enabled ) => {
70+ updateProviderSettings ( provider . name , { ...provider . settings , enabled } ) ;
71+
72+ if ( enabled ) {
73+ logStore . logProvider ( `Provider ${ provider . name } enabled` , { provider : provider . name } ) ;
74+ } else {
75+ logStore . logProvider ( `Provider ${ provider . name } disabled` , { provider : provider . name } ) ;
76+ }
6877 } }
69- alt = { `${ provider . name } icon` }
70- className = "w-6 h-6 dark:invert"
7178 />
72- < span className = "text-bolt-elements-textPrimary" > { provider . name } </ span >
7379 </ 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- />
80+ { isUrlConfigurable && provider . settings . enabled && (
81+ < div className = "mt-2" >
82+ { envBaseUrl && (
83+ < label className = "block text-xs text-bolt-elements-textSecondary text-green-300 mb-2" >
84+ Set On (.env) : { envBaseUrl }
85+ </ label >
86+ ) }
87+ < label className = "block text-sm text-bolt-elements-textSecondary mb-2" >
88+ { envBaseUrl ? 'Override Base Url' : 'Base URL ' } :{ ' ' }
89+ </ label >
90+ < input
91+ type = "text"
92+ value = { provider . settings . baseUrl || '' }
93+ onChange = { ( e ) => {
94+ let newBaseUrl : string | undefined = e . target . value ;
95+
96+ if ( newBaseUrl && newBaseUrl . trim ( ) . length === 0 ) {
97+ newBaseUrl = undefined ;
98+ }
99+
100+ updateProviderSettings ( provider . name , { ...provider . settings , baseUrl : newBaseUrl } ) ;
101+ logStore . logProvider ( `Base URL updated for ${ provider . name } ` , {
102+ provider : provider . name ,
103+ baseUrl : newBaseUrl ,
104+ } ) ;
105+ } }
106+ placeholder = { `Enter ${ provider . name } base URL` }
107+ 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"
108+ />
109+ </ div >
110+ ) }
86111 </ 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- ) ;
112+ ) ;
113+ } ;
114+
115+ const regularProviders = filteredProviders . filter ( p => ! URL_CONFIGURABLE_PROVIDERS . includes ( p . name ) ) ;
116+ const urlConfigurableProviders = filteredProviders . filter ( p => URL_CONFIGURABLE_PROVIDERS . includes ( p . name ) ) ;
108117
109118 return (
110119 < div className = "p-4" >
@@ -118,77 +127,20 @@ export default function ProvidersTab() {
118127 />
119128 </ div >
120129
121- { filteredProviders . map ( ( provider ) => {
122- const envBaseUrlKey = providerBaseUrlEnvKeys [ provider . name ] . baseUrlKey ;
123- const envBaseUrl = envBaseUrlKey ? import . meta. env [ envBaseUrlKey ] : undefined ;
124-
125- return (
126- < div
127- key = { provider . name }
128- className = "flex flex-col mb-2 provider-item hover:bg-bolt-elements-bg-depth-3 p-4 rounded-lg border border-bolt-elements-borderColor "
129- >
130- < div className = "flex items-center justify-between mb-2" >
131- < div className = "flex items-center gap-2" >
132- < img
133- src = { `/icons/${ provider . name } .svg` } // Attempt to load the specific icon
134- onError = { ( e ) => {
135- // Fallback to default icon on error
136- e . currentTarget . src = DefaultIcon ;
137- } }
138- alt = { `${ provider . name } icon` }
139- className = "w-6 h-6 dark:invert"
140- />
141- < span className = "text-bolt-elements-textPrimary" > { provider . name } </ span >
142- </ div >
143- < Switch
144- className = "ml-auto"
145- checked = { provider . settings . enabled }
146- onCheckedChange = { ( enabled ) => {
147- updateProviderSettings ( provider . name , { ...provider . settings , enabled } ) ;
148-
149- if ( enabled ) {
150- logStore . logProvider ( `Provider ${ provider . name } enabled` , { provider : provider . name } ) ;
151- } else {
152- logStore . logProvider ( `Provider ${ provider . name } disabled` , { provider : provider . name } ) ;
153- }
154- } }
155- />
156- </ div >
157- { /* Base URL input for configurable providers */ }
158- { URL_CONFIGURABLE_PROVIDERS . includes ( provider . name ) && provider . settings . enabled && (
159- < div className = "mt-2" >
160- { envBaseUrl && (
161- < label className = "block text-xs text-bolt-elements-textSecondary text-green-300 mb-2" >
162- Set On (.env) : { envBaseUrl }
163- </ label >
164- ) }
165- < label className = "block text-sm text-bolt-elements-textSecondary mb-2" >
166- { envBaseUrl ? 'Override Base Url' : 'Base URL ' } :{ ' ' }
167- </ label >
168- < input
169- type = "text"
170- value = { provider . settings . baseUrl || '' }
171- onChange = { ( e ) => {
172- let newBaseUrl : string | undefined = e . target . value ;
173-
174- if ( newBaseUrl && newBaseUrl . trim ( ) . length === 0 ) {
175- newBaseUrl = undefined ;
176- }
177-
178- updateProviderSettings ( provider . name , { ...provider . settings , baseUrl : newBaseUrl } ) ;
179- logStore . logProvider ( `Base URL updated for ${ provider . name } ` , {
180- provider : provider . name ,
181- baseUrl : newBaseUrl ,
182- } ) ;
183- } }
184- placeholder = { `Enter ${ provider . name } base URL` }
185- 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"
186- />
187- </ div >
188- ) }
130+ { /* Regular Providers Grid */ }
131+ < div className = "grid grid-cols-2 gap-4 mb-8" >
132+ { regularProviders . map ( renderProviderCard ) }
133+ </ div >
134+
135+ { /* URL Configurable Providers Section */ }
136+ { urlConfigurableProviders . length > 0 && (
137+ < div className = "mt-8" >
138+ < h3 className = "text-lg font-semibold mb-4 text-bolt-elements-textPrimary" > Providers with Custom Base URL</ h3 >
139+ < div className = "space-y-4" >
140+ { urlConfigurableProviders . map ( renderProviderCard ) }
189141 </ div >
190- ) ;
191- } ) }
142+ </ div >
143+ ) }
192144 </ div >
193145 ) ;
194- }
146+ }
0 commit comments