1
1
import * as Eff from 'effect'
2
2
import * as React from 'react'
3
3
import * as M from '@material-ui/core'
4
+ import {
5
+ Clear as ClearIcon ,
6
+ Delete as DeleteIcon ,
7
+ GetApp as GetAppIcon ,
8
+ } from '@material-ui/icons'
4
9
5
10
import JsonDisplay from 'components/JsonDisplay'
6
11
7
12
import * as Model from '../../Model'
8
13
14
+ const useModelIdOverrideStyles = M . makeStyles ( ( t ) => ( {
15
+ root : {
16
+ margin : t . spacing ( 2 , 0 ) ,
17
+ padding : t . spacing ( 0 , 2 ) ,
18
+ } ,
19
+ } ) )
20
+
21
+ type ModelIdOverrideProps = Model . Assistant . API [ 'devTools' ] [ 'modelIdOverride' ]
22
+
23
+ function ModelIdOverride ( { value, setValue } : ModelIdOverrideProps ) {
24
+ const classes = useModelIdOverrideStyles ( )
25
+
26
+ const handleModelIdChange = React . useCallback (
27
+ ( event : React . ChangeEvent < HTMLInputElement > ) => {
28
+ setValue ( event . target . value )
29
+ } ,
30
+ [ setValue ] ,
31
+ )
32
+
33
+ const handleClear = React . useCallback ( ( ) => setValue ( '' ) , [ setValue ] )
34
+
35
+ return (
36
+ < div className = { classes . root } >
37
+ < M . TextField
38
+ label = "Bedrock Model ID"
39
+ placeholder = { Model . Assistant . DEFAULT_MODEL_ID }
40
+ value = { value }
41
+ onChange = { handleModelIdChange }
42
+ fullWidth
43
+ helperText = "Leave empty to use default"
44
+ InputLabelProps = { { shrink : true } }
45
+ InputProps = { {
46
+ endAdornment : value ? (
47
+ < M . InputAdornment position = "end" >
48
+ < M . IconButton
49
+ aria-label = "Clear model ID override"
50
+ onClick = { handleClear }
51
+ edge = "end"
52
+ size = "small"
53
+ >
54
+ < M . Tooltip arrow title = "Clear model ID override" >
55
+ < ClearIcon />
56
+ </ M . Tooltip >
57
+ </ M . IconButton >
58
+ </ M . InputAdornment >
59
+ ) : null ,
60
+ } }
61
+ />
62
+ </ div >
63
+ )
64
+ }
65
+
66
+ const useRecordingControlsStyles = M . makeStyles ( ( t ) => ( {
67
+ root : {
68
+ alignItems : 'center' ,
69
+ display : 'flex' ,
70
+ gap : t . spacing ( 1 ) ,
71
+ margin : t . spacing ( 2 , 0 ) ,
72
+ padding : t . spacing ( 0 , 2 ) ,
73
+ } ,
74
+ label : {
75
+ ...t . typography . body2 ,
76
+ flexGrow : 1 ,
77
+ padding : t . spacing ( 0 , 2 ) ,
78
+ } ,
79
+ } ) )
80
+
81
+ type RecordingControlsProps = Model . Assistant . API [ 'devTools' ] [ 'recording' ]
82
+
83
+ function RecordingControls ( { enabled, log, enable, clear } : RecordingControlsProps ) {
84
+ const classes = useRecordingControlsStyles ( )
85
+
86
+ const handleToggleRecording = React . useCallback ( ( ) => {
87
+ enable ( ! enabled )
88
+ } , [ enabled , enable ] )
89
+
90
+ const handleDownload = React . useCallback ( ( ) => {
91
+ const data = `[\n${ log . join ( ',\n' ) } \n]`
92
+ const blob = new Blob ( [ data ] , { type : 'application/json' } )
93
+ const url = URL . createObjectURL ( blob )
94
+ const a = document . createElement ( 'a' )
95
+ a . href = url
96
+ a . download = `qurator-session-${ new Date ( ) . toISOString ( ) } .json`
97
+ document . body . appendChild ( a )
98
+ a . click ( )
99
+ document . body . removeChild ( a )
100
+ URL . revokeObjectURL ( url )
101
+ } , [ log ] )
102
+
103
+ return (
104
+ < div className = { classes . root } >
105
+ < M . Button
106
+ onClick = { handleToggleRecording }
107
+ variant = "contained"
108
+ color = "primary"
109
+ size = "small"
110
+ >
111
+ { enabled ? 'Stop' : 'Start' } Recording
112
+ </ M . Button >
113
+
114
+ { ( enabled || log . length > 0 ) && (
115
+ < div className = { classes . label } >
116
+ { log . length > 0 ? `${ log . length } item(s) recorded` : 'Recording...' }
117
+ </ div >
118
+ ) }
119
+
120
+ { log . length > 0 && (
121
+ < >
122
+ < M . Button
123
+ onClick = { handleDownload }
124
+ size = "small"
125
+ variant = "outlined"
126
+ startIcon = { < GetAppIcon /> }
127
+ >
128
+ Download Log
129
+ </ M . Button >
130
+ < M . Button
131
+ onClick = { clear }
132
+ size = "small"
133
+ variant = "outlined"
134
+ startIcon = { < DeleteIcon /> }
135
+ >
136
+ Clear Log
137
+ </ M . Button >
138
+ </ >
139
+ ) }
140
+ </ div >
141
+ )
142
+ }
143
+
9
144
const useStyles = M . makeStyles ( ( t ) => ( {
10
145
root : {
11
146
display : 'flex' ,
@@ -30,9 +165,11 @@ const useStyles = M.makeStyles((t) => ({
30
165
31
166
interface DevToolsProps {
32
167
state : Model . Assistant . API [ 'state' ]
168
+ modelIdOverride : Model . Assistant . API [ 'devTools' ] [ 'modelIdOverride' ]
169
+ recording : Model . Assistant . API [ 'devTools' ] [ 'recording' ]
33
170
}
34
171
35
- export default function DevTools ( { state } : DevToolsProps ) {
172
+ export default function DevTools ( { state, modelIdOverride , recording } : DevToolsProps ) {
36
173
const classes = useStyles ( )
37
174
38
175
const context = Model . Context . useAggregatedContext ( )
@@ -52,6 +189,10 @@ export default function DevTools({ state }: DevToolsProps) {
52
189
< section className = { classes . root } >
53
190
< h1 className = { classes . heading } > Qurator Developer Tools</ h1 >
54
191
< div className = { classes . contents } >
192
+ < ModelIdOverride { ...modelIdOverride } />
193
+ < M . Divider />
194
+ < RecordingControls { ...recording } />
195
+ < M . Divider />
55
196
< JsonDisplay className = { classes . json } name = "Context" value = { context } />
56
197
< JsonDisplay className = { classes . json } name = "State" value = { state } />
57
198
< JsonDisplay className = { classes . json } name = "Prompt" value = { prompt } />
0 commit comments