@@ -35,6 +35,7 @@ import {
35
35
ToggleButton ,
36
36
Menu ,
37
37
MenuItem ,
38
+ TextField ,
38
39
} from '@mui/material' ;
39
40
40
41
@@ -46,7 +47,7 @@ import { DataFormulatorFC } from '../views/DataFormulator';
46
47
47
48
import GridViewIcon from '@mui/icons-material/GridView' ;
48
49
import ViewSidebarIcon from '@mui/icons-material/ViewSidebar' ;
49
-
50
+ import SettingsIcon from '@mui/icons-material/Settings' ;
50
51
import {
51
52
createBrowserRouter ,
52
53
RouterProvider ,
@@ -295,10 +296,122 @@ const ResetDialog: React.FC = () => {
295
296
) ;
296
297
} ;
297
298
299
+ const ConfigDialog : React . FC = ( ) => {
300
+ const [ open , setOpen ] = useState ( false ) ;
301
+ const dispatch = useDispatch ( ) ;
302
+ const config = useSelector ( ( state : DataFormulatorState ) => state . config ) ;
303
+
304
+ const [ formulateTimeoutSeconds , setFormulateTimeoutSeconds ] = useState ( config . formulateTimeoutSeconds ) ;
305
+ const [ maxRepairAttempts , setMaxRepairAttempts ] = useState ( config . maxRepairAttempts ) ;
306
+
307
+ // Add check for changes
308
+ const hasChanges = formulateTimeoutSeconds !== config . formulateTimeoutSeconds ||
309
+ maxRepairAttempts !== config . maxRepairAttempts ;
310
+
311
+ return (
312
+ < >
313
+ < Button variant = "text" sx = { { textTransform : 'none' } } onClick = { ( ) => setOpen ( true ) } startIcon = { < SettingsIcon /> } >
314
+ < Box component = "span" sx = { { lineHeight : 1.2 , display : 'flex' , flexDirection : 'column' , alignItems : 'left' } } >
315
+ < Box component = "span" sx = { { py : 0 , my : 0 , fontSize : '10px' , mr : 'auto' } } > timeout={ config . formulateTimeoutSeconds } s</ Box >
316
+ < Box component = "span" sx = { { py : 0 , my : 0 , fontSize : '10px' , mr : 'auto' } } > max_repair={ config . maxRepairAttempts } </ Box >
317
+ </ Box >
318
+ </ Button >
319
+ < Dialog onClose = { ( ) => setOpen ( false ) } open = { open } >
320
+ < DialogTitle > Data Formulator Configuration</ DialogTitle >
321
+ < DialogContent >
322
+ < DialogContentText >
323
+ < Box sx = { {
324
+ display : 'flex' ,
325
+ flexDirection : 'column' ,
326
+ gap : 3 ,
327
+ my : 2 ,
328
+ maxWidth : 400
329
+ } } >
330
+ < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 2 } } >
331
+ < Box sx = { { flex : 1 } } >
332
+ < TextField
333
+ label = "formulate timeout (seconds)"
334
+ type = "number"
335
+ variant = "outlined"
336
+ value = { formulateTimeoutSeconds }
337
+ onChange = { ( e ) => {
338
+ const value = parseInt ( e . target . value ) ;
339
+ setFormulateTimeoutSeconds ( value ) ;
340
+ } }
341
+ inputProps = { {
342
+ min : 0 ,
343
+ max : 3600 ,
344
+ } }
345
+ error = { formulateTimeoutSeconds <= 0 || formulateTimeoutSeconds > 3600 }
346
+ helperText = { formulateTimeoutSeconds <= 0 || formulateTimeoutSeconds > 3600 ?
347
+ "Value must be between 1 and 3600 seconds" : "" }
348
+ fullWidth
349
+ />
350
+ < Typography variant = "caption" color = "text.secondary" sx = { { mt : 1 , display : 'block' } } >
351
+ Maximum time allowed for the formulation process before timing out.
352
+ </ Typography >
353
+ < Typography variant = "caption" color = "text.secondary" sx = { { mt : 1 , display : 'block' } } >
354
+ Smaller values (<30s) make the model fails fast thus providing a smoother UI experience. Increase this value for slow models.
355
+ </ Typography >
356
+ </ Box >
357
+ </ Box >
358
+ < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 2 } } >
359
+ < Box sx = { { flex : 1 } } >
360
+ < TextField
361
+ label = "max repair attempts"
362
+ type = "number"
363
+ variant = "outlined"
364
+ value = { maxRepairAttempts }
365
+ onChange = { ( e ) => {
366
+ const value = parseInt ( e . target . value ) ;
367
+ setMaxRepairAttempts ( value ) ;
368
+ } }
369
+ fullWidth
370
+ inputProps = { {
371
+ min : 1 ,
372
+ max : 5 ,
373
+ } }
374
+ error = { maxRepairAttempts <= 0 || maxRepairAttempts > 5 }
375
+ helperText = { maxRepairAttempts <= 0 || maxRepairAttempts > 5 ?
376
+ "Value must be between 1 and 5" : "" }
377
+ />
378
+ < Typography variant = "caption" color = "text.secondary" sx = { { mt : 1 , display : 'block' } } >
379
+ Maximum number of times the LLM will attempt to repair code if generated code fails to execute (recommended = 1).
380
+ </ Typography >
381
+ < Typography variant = "caption" color = "text.secondary" sx = { { mt : 1 , display : 'block' } } >
382
+ Higher values might slightly increase the chance of success but can crash the backend. Repair time is as part of the formulate timeout.
383
+ </ Typography >
384
+ </ Box >
385
+ </ Box >
386
+ </ Box >
387
+ </ DialogContentText >
388
+ </ DialogContent >
389
+ < DialogActions sx = { { '.MuiButton-root' : { textTransform : 'none' } } } >
390
+ < Button sx = { { marginRight : 'auto' } } onClick = { ( ) => {
391
+ setFormulateTimeoutSeconds ( 30 ) ;
392
+ setMaxRepairAttempts ( 1 ) ;
393
+ } } > Reset to default</ Button >
394
+ < Button onClick = { ( ) => setOpen ( false ) } > Cancel</ Button >
395
+ < Button
396
+ variant = { hasChanges ? "contained" : "text" }
397
+ disabled = { ! hasChanges || isNaN ( maxRepairAttempts ) || maxRepairAttempts <= 0 || maxRepairAttempts > 5 || isNaN ( formulateTimeoutSeconds ) || formulateTimeoutSeconds <= 0 || formulateTimeoutSeconds > 3600 }
398
+ onClick = { ( ) => {
399
+ dispatch ( dfActions . setConfig ( { formulateTimeoutSeconds, maxRepairAttempts} ) ) ;
400
+ setOpen ( false ) ;
401
+ } }
402
+ >
403
+ Apply
404
+ </ Button >
405
+ </ DialogActions >
406
+ </ Dialog >
407
+ </ >
408
+ ) ;
409
+ }
410
+
298
411
export const AppFC : FC < AppFCProps > = function AppFC ( appProps ) {
299
412
300
413
const visViewMode = useSelector ( ( state : DataFormulatorState ) => state . visViewMode ) ;
301
- const betaMode = useSelector ( ( state : DataFormulatorState ) => state . betaMode ) ;
414
+ const config = useSelector ( ( state : DataFormulatorState ) => state . config ) ;
302
415
const tables = useSelector ( ( state : DataFormulatorState ) => state . tables ) ;
303
416
304
417
// if the user has logged in
@@ -410,7 +523,7 @@ export const AppFC: FC<AppFCProps> = function AppFC(appProps) {
410
523
411
524
let appBar = [
412
525
< AppBar className = "app-bar" position = "static" key = "app-bar-main" >
413
- < Toolbar variant = "dense" sx = { { backgroundColor : betaMode ? 'lavender' : '' } } >
526
+ < Toolbar variant = "dense" >
414
527
< Button href = { "/" } sx = { {
415
528
display : "flex" , flexDirection : "row" , textTransform : "none" ,
416
529
backgroundColor : 'transparent' ,
@@ -420,7 +533,7 @@ export const AppFC: FC<AppFCProps> = function AppFC(appProps) {
420
533
} } color = "inherit" >
421
534
< Box component = "img" sx = { { height : 32 , marginRight : "12px" } } alt = "" src = { dfLogo } />
422
535
< Typography variant = "h6" noWrap component = "h1" sx = { { fontWeight : 300 , display : { xs : 'none' , sm : 'block' } } } >
423
- { toolName } { betaMode ? "β" : "" } { process . env . NODE_ENV == "development" ? "" : "" }
536
+ { toolName } { process . env . NODE_ENV == "development" ? "" : "" }
424
537
</ Typography >
425
538
</ Button >
426
539
< Box sx = { { flexGrow : 1 , textAlign : 'center' , display : 'flex' , justifyContent : 'center' } } >
@@ -432,6 +545,8 @@ export const AppFC: FC<AppFCProps> = function AppFC(appProps) {
432
545
about
433
546
</Button>
434
547
<Divider orientation="vertical" variant="middle" flexItem /> */ }
548
+ < ConfigDialog />
549
+ < Divider orientation = "vertical" variant = "middle" flexItem />
435
550
< ModelSelectionButton />
436
551
< Divider orientation = "vertical" variant = "middle" flexItem />
437
552
< Typography sx = { { display : 'flex' , fontSize : 14 , alignItems : 'center' , gap : 1 } } >
0 commit comments