@@ -35,6 +35,7 @@ import {
3535 ToggleButton ,
3636 Menu ,
3737 MenuItem ,
38+ TextField ,
3839} from '@mui/material' ;
3940
4041
@@ -46,7 +47,7 @@ import { DataFormulatorFC } from '../views/DataFormulator';
4647
4748import GridViewIcon from '@mui/icons-material/GridView' ;
4849import ViewSidebarIcon from '@mui/icons-material/ViewSidebar' ;
49-
50+ import SettingsIcon from '@mui/icons-material/Settings' ;
5051import {
5152 createBrowserRouter ,
5253 RouterProvider ,
@@ -295,10 +296,122 @@ const ResetDialog: React.FC = () => {
295296 ) ;
296297} ;
297298
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+
298411export const AppFC : FC < AppFCProps > = function AppFC ( appProps ) {
299412
300413 const visViewMode = useSelector ( ( state : DataFormulatorState ) => state . visViewMode ) ;
301- const betaMode = useSelector ( ( state : DataFormulatorState ) => state . betaMode ) ;
414+ const config = useSelector ( ( state : DataFormulatorState ) => state . config ) ;
302415 const tables = useSelector ( ( state : DataFormulatorState ) => state . tables ) ;
303416
304417 // if the user has logged in
@@ -410,7 +523,7 @@ export const AppFC: FC<AppFCProps> = function AppFC(appProps) {
410523
411524 let appBar = [
412525 < AppBar className = "app-bar" position = "static" key = "app-bar-main" >
413- < Toolbar variant = "dense" sx = { { backgroundColor : betaMode ? 'lavender' : '' } } >
526+ < Toolbar variant = "dense" >
414527 < Button href = { "/" } sx = { {
415528 display : "flex" , flexDirection : "row" , textTransform : "none" ,
416529 backgroundColor : 'transparent' ,
@@ -420,7 +533,7 @@ export const AppFC: FC<AppFCProps> = function AppFC(appProps) {
420533 } } color = "inherit" >
421534 < Box component = "img" sx = { { height : 32 , marginRight : "12px" } } alt = "" src = { dfLogo } />
422535 < 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" ? "" : "" }
424537 </ Typography >
425538 </ Button >
426539 < Box sx = { { flexGrow : 1 , textAlign : 'center' , display : 'flex' , justifyContent : 'center' } } >
@@ -432,6 +545,8 @@ export const AppFC: FC<AppFCProps> = function AppFC(appProps) {
432545 about
433546 </Button>
434547 <Divider orientation="vertical" variant="middle" flexItem /> */ }
548+ < ConfigDialog />
549+ < Divider orientation = "vertical" variant = "middle" flexItem />
435550 < ModelSelectionButton />
436551 < Divider orientation = "vertical" variant = "middle" flexItem />
437552 < Typography sx = { { display : 'flex' , fontSize : 14 , alignItems : 'center' , gap : 1 } } >
0 commit comments