@@ -116,12 +116,17 @@ const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModel
116116 const [ inputPrice , setInputPrice ] = useState < number > ( customModel ?. inputPrice || 0 ) ;
117117 const [ outputPrice , setOutputPrice ] = useState < number > ( customModel ?. outputPrice || 0 ) ;
118118 const [ modelName , setModelName ] = useState ( customModel ?. name || "" ) ;
119+ const [ isModelNameValid , setIsModelNameValid ] = useState ( true ) ;
120+ const [ isSlugValid , setIsSlugValid ] = useState ( true ) ;
121+ const [ isBaseUrlValid , setIsBaseUrlValid ] = useState ( true ) ;
122+ const [ isApiKeyValid , setIsApiKeyValid ] = useState ( true ) ;
119123
120124 const borderedInputClassName = "rnd-cancel px-2 py-1 border !border-gray-200 dark:!border-default-200 rounded-md" ;
121125 const baseClassName = "bg-transparent p-1 focus:outline-none disabled:opacity-70 disabled:cursor-not-allowed" ;
122126 const modelNameInputClassName = `${ baseClassName } ${ isEditing || isNew ? borderedInputClassName : "" } text-sm text-default-900 font-medium flex-1 truncate mr-1` ;
123127 const labelClassName = `${ baseClassName } text-xs text-default-900 w-auto` ;
124128 const detailInputClassName = `${ baseClassName } ${ isEditing || isNew ? borderedInputClassName : "" } flex-1 noselect focus:outline-none text-xs text-default-700 placeholder:text-default-400` ;
129+ const errorInputClassName = "!border-red-500 focus:!border-red-500" ;
125130
126131 const handleOnChange = ( isDelete : boolean ) => {
127132 if (
@@ -130,6 +135,10 @@ const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModel
130135 baseUrl . trim ( ) . length < 1 ||
131136 apiKey . trim ( ) . length < 1
132137 ) {
138+ setIsModelNameValid ( modelName . trim ( ) . length > 0 ) ;
139+ setIsSlugValid ( slug . trim ( ) . length > 0 ) ;
140+ setIsBaseUrlValid ( baseUrl . trim ( ) . length > 0 ) ;
141+ setIsApiKeyValid ( apiKey . trim ( ) . length > 0 ) ;
133142 return ;
134143 }
135144
@@ -157,19 +166,24 @@ const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModel
157166 setMaxOutput ( 0 ) ;
158167 setInputPrice ( 0 ) ;
159168 setOutputPrice ( 0 ) ;
169+ } else {
170+ setIsEditing ( false ) ;
160171 }
161172 } ;
162173
163174 return (
164175 < div className = "flex flex-col w-full pl-1" >
165176 < div className = "flex flex-row justify-between" >
166177 < input
167- className = { modelNameInputClassName }
178+ className = { ` ${ modelNameInputClassName } ${ ! isModelNameValid && errorInputClassName } ` }
168179 value = { modelName }
169180 placeholder = "My Model"
170181 type = "text"
171182 disabled = { ! isEditing }
172- onChange = { ( e ) => setModelName ( e . target . value ) }
183+ onChange = { ( e ) => {
184+ setIsModelNameValid ( true ) ;
185+ setModelName ( e . target . value ) ;
186+ } }
173187 > </ input >
174188
175189 { isNew ? (
@@ -185,8 +199,9 @@ const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModel
185199 onClick = { ( ) => {
186200 if ( isEditing ) {
187201 handleOnChange ( false ) ;
202+ } else {
203+ setIsEditing ( true ) ;
188204 }
189- setIsEditing ( ( i ) => ! i ) ;
190205 } }
191206 className = "p-1 hover:bg-default-100 rounded"
192207 >
@@ -205,36 +220,45 @@ const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModel
205220 < div className = "flex flex-row mt-[4px]" >
206221 < label className = { labelClassName } > Slug</ label >
207222 < input
208- className = { detailInputClassName }
223+ className = { ` ${ detailInputClassName } ${ ! isSlugValid && errorInputClassName } ` }
209224 value = { slug }
210225 placeholder = "e.g., gemini-2.5-flash"
211226 type = "text"
212227 disabled = { ! isEditing }
213- onChange = { ( e ) => setSlug ( e . target . value ) }
228+ onChange = { ( e ) => {
229+ setIsSlugValid ( true ) ;
230+ setSlug ( e . target . value ) ;
231+ } }
214232 />
215233 </ div >
216234
217235 < div className = "flex flex-row mt-[4px]" >
218236 < label className = { labelClassName } > Base URL</ label >
219237 < input
220- className = { detailInputClassName }
238+ className = { ` ${ detailInputClassName } ${ ! isBaseUrlValid && errorInputClassName } ` }
221239 value = { baseUrl }
222240 placeholder = "An OpenAI-compatible endpoint"
223241 type = "text"
224242 disabled = { ! isEditing }
225- onChange = { ( e ) => setBaseUrl ( e . target . value ) }
243+ onChange = { ( e ) => {
244+ setIsBaseUrlValid ( true ) ;
245+ setBaseUrl ( e . target . value ) ;
246+ } }
226247 />
227248 </ div >
228249
229250 < div className = "flex flex-row mt-[4px]" >
230251 < label className = { labelClassName } > API Key</ label >
231252 < input
232- className = { detailInputClassName }
253+ className = { ` ${ detailInputClassName } ${ ! isApiKeyValid && errorInputClassName } ` }
233254 value = { apiKey }
234255 placeholder = "Your API Key"
235256 type = { ! isEditing && ! isNew ? "password" : "text" }
236257 disabled = { ! isEditing }
237- onChange = { ( e ) => setApiKey ( e . target . value ) }
258+ onChange = { ( e ) => {
259+ setIsApiKeyValid ( true ) ;
260+ setApiKey ( e . target . value ) ;
261+ } }
238262 />
239263 </ div >
240264
0 commit comments