@@ -29,10 +29,20 @@ export default function ChatInterface() {
29
29
const searchParams = useSearchParams ( ) ;
30
30
// null port gets converted to NaN
31
31
const parsedPort = parseInt ( searchParams . get ( "port" ) as string ) ;
32
- const port = isNaN ( parsedPort ) ? 3284 : parsedPort ;
32
+ // We're setting port via URL query param, not directly with setPort
33
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
34
+ const [ port , setPort ] = useState < number > (
35
+ isNaN ( parsedPort ) ? 3284 : parsedPort
36
+ ) ;
37
+ const [ portInput , setPortInput ] = useState < string > ( port . toString ( ) ) ;
33
38
const AgentAPIUrl = `http://localhost:${ port } ` ;
34
39
const eventSourceRef = useRef < EventSource | null > ( null ) ;
35
40
41
+ // Update portInput when port changes
42
+ useEffect ( ( ) => {
43
+ setPortInput ( port . toString ( ) ) ;
44
+ } , [ port ] ) ;
45
+
36
46
// Set up SSE connection to the events endpoint
37
47
useEffect ( ( ) => {
38
48
// Function to create and set up EventSource
@@ -179,23 +189,82 @@ export default function ChatInterface() {
179
189
}
180
190
} ;
181
191
192
+ const updatePort = ( ) => {
193
+ const newPort = parseInt ( portInput ) ;
194
+ if ( ! isNaN ( newPort ) && newPort > 0 && newPort < 65536 ) {
195
+ window . location . href = `?port=${ newPort } ` ;
196
+ } else {
197
+ setError ( "Invalid port number. Please enter a number between 1-65535." ) ;
198
+ setTimeout ( ( ) => setError ( null ) , 5000 ) ;
199
+ }
200
+ } ;
201
+
182
202
return (
183
203
< div className = "flex flex-col h-[80vh] bg-gray-100 rounded-lg overflow-hidden border border-gray-300 shadow-lg w-full max-w-[95vw]" >
184
- < div className = "p-3 bg-gray-800 text-white text-sm flex justify-between items-center" >
204
+ < div className = "p-3 bg-gray-800 text-white text-sm flex items-center justify-between " >
185
205
< span > AgentAPI Chat</ span >
186
- < span className = "flex items-center" >
187
- < span
188
- className = { `w-2 h-2 rounded-full mr-2 ${
189
- [ "offline" , "unknown" ] . includes ( serverStatus )
190
- ? "bg-red-500"
191
- : "bg-green-500"
192
- } `}
193
- > </ span >
194
- < span > Status: { serverStatus } </ span >
195
- < span className = "ml-2" > Port: { port } </ span >
196
- </ span >
206
+ < div className = "flex items-center space-x-3" >
207
+ < div className = "flex items-center" >
208
+ < label htmlFor = "port-input" className = "text-white mr-1" >
209
+ Port:
210
+ </ label >
211
+ < input
212
+ id = "port-input"
213
+ type = "text"
214
+ value = { portInput }
215
+ onChange = { ( e ) => setPortInput ( e . target . value ) }
216
+ className = "w-16 px-1 py-0.5 text-xs rounded border border-gray-400 bg-gray-700 text-white"
217
+ onKeyDown = { ( e ) => e . key === "Enter" && updatePort ( ) }
218
+ />
219
+ < button
220
+ onClick = { updatePort }
221
+ className = "ml-1 px-2 py-0.5 text-xs bg-gray-600 hover:bg-gray-500 rounded"
222
+ >
223
+ Apply
224
+ </ button >
225
+ </ div >
226
+ < div className = "flex items-center" >
227
+ < span
228
+ className = { `w-2 h-2 rounded-full mr-2 ${
229
+ [ "offline" , "unknown" ] . includes ( serverStatus )
230
+ ? "bg-red-500"
231
+ : "bg-green-500"
232
+ } `}
233
+ > </ span >
234
+ < span > Status: { serverStatus } </ span >
235
+ </ div >
236
+ </ div >
197
237
</ div >
198
238
239
+ { ( serverStatus === "offline" || serverStatus === "unknown" ) && (
240
+ < div className = "bg-yellow-100 border-y border-yellow-400 text-yellow-800 px-4 py-3 flex items-center justify-between font-medium" >
241
+ < div className = "flex items-center" >
242
+ < svg
243
+ className = "w-5 h-5 mr-2"
244
+ fill = "currentColor"
245
+ viewBox = "0 0 20 20"
246
+ xmlns = "http://www.w3.org/2000/svg"
247
+ >
248
+ < path
249
+ fillRule = "evenodd"
250
+ d = "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
251
+ clipRule = "evenodd"
252
+ />
253
+ </ svg >
254
+ < span >
255
+ API server is offline. Please start the API server on localhost:
256
+ { port } .
257
+ </ span >
258
+ </ div >
259
+ < button
260
+ onClick = { ( ) => window . location . reload ( ) }
261
+ className = "bg-yellow-200 px-3 py-1 rounded text-xs hover:bg-yellow-300"
262
+ >
263
+ Retry Connection
264
+ </ button >
265
+ </ div >
266
+ ) }
267
+
199
268
{ error && (
200
269
< div className = "bg-red-100 border border-red-400 text-red-700 px-4 py-2 text-sm relative" >
201
270
< span className = "block sm:inline" > { error } </ span >
0 commit comments