1
- import { Fragment } from 'react' ;
2
- import { Switch , ActionIcon , Center } from '@mantine/core' ;
1
+ import { Fragment , useState , useEffect } from 'react' ;
2
+ import { Switch , ActionIcon , Center , Button , Modal } from '@mantine/core' ;
3
3
import { Draggable } from 'react-beautiful-dnd' ;
4
- import { GripVertical } from 'tabler-icons-react' ;
4
+ import { GripVertical , Plus } from 'tabler-icons-react' ;
5
5
import { TrashIcon as Trash } from '@heroicons/react/24/solid' ;
6
+ import { string } from 'joi' ;
6
7
7
- const Parameter = ( { form, type, index, ...rest } ) => {
8
+ const Parameter = ( { form, type, index, confirmedValues , setConfirmedValues , ...rest } ) => {
8
9
const remains = {
9
10
string : StringParam ,
10
11
integer : NumberParam ,
11
12
float : NumberParam ,
12
13
bool : BoolParam ,
14
+ stringlist : MultiStringParam ,
13
15
} ;
14
16
const Component = remains [ type ] ;
17
+
18
+ const updateConfirmedValues = ( index , newValues ) => {
19
+
20
+ const hasConfirmedValues = confirmedValues . some ( item => item . index === index ) ;
21
+ if ( hasConfirmedValues ) {
22
+ const newConfirmedValues = confirmedValues . map ( item => {
23
+ if ( item . index === index ) {
24
+ return {
25
+ index,
26
+ values : newValues ,
27
+ } ;
28
+ }
29
+ return item ;
30
+ } ) ;
31
+ setConfirmedValues ( newConfirmedValues ) ;
32
+ } else {
33
+ const newConfirmedValues = [ ...confirmedValues , { index, values : newValues } ] ;
34
+ setConfirmedValues ( newConfirmedValues ) ;
35
+ }
36
+
37
+ } ;
38
+
39
+ useEffect ( ( ) => {
40
+ if ( form . values . hyperparameters [ index ] . values && ( form . values . hyperparameters [ index ] . values . length != 1 && form . values . hyperparameters [ index ] . values [ 0 ] != '' ) ) {
41
+ updateConfirmedValues ( index , form . values . hyperparameters [ index ] . values ) ;
42
+ }
43
+ } , [ ] ) ;
44
+
45
+
46
+ const handleRemove = ( ) => {
47
+ form . removeListItem ( 'hyperparameters' , index ) ;
48
+ const newConfirmedValues = confirmedValues . filter ( item => item . index !== index ) ;
49
+ setConfirmedValues ( newConfirmedValues ) ;
50
+ } ;
51
+
15
52
return (
16
- < Draggable key = { index } index = { index } draggableId = { index . toString ( ) } >
17
- { ( provided ) => {
18
- return (
19
- < div
20
- ref = { provided . innerRef }
21
- { ...provided . draggableProps }
22
- // className={'mt-8 justify-start'}
23
- className = { 'flex items-center mb-2' }
24
- >
53
+ < Draggable key = { index } index = { index } draggableId = { index . toString ( ) } isDragDisabled = { true } >
54
+ { ( provided ) => (
55
+ < div
56
+ ref = { provided . innerRef }
57
+ { ...provided . draggableProps }
58
+ className = 'flex flex-col mb-2'
59
+ >
60
+ < div className = 'flex items-center' >
25
61
< Center { ...provided . dragHandleProps } >
26
62
< GripVertical className = 'mr-2' />
27
63
</ Center >
@@ -30,20 +66,33 @@ const Parameter = ({ form, type, index, ...rest }) => {
30
66
type = 'text'
31
67
placeholder = 'name'
32
68
className = 'block w-full rounded-l-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm'
33
- { ...form . getListInputProps ( ' hyperparameters' , index , ' name' ) }
69
+ { ...form . getInputProps ( ` hyperparameters. ${ index } . name` ) }
34
70
required
35
71
/>
36
- < Component form = { form } type = { type } index = { index } { ...rest } />
72
+ < Component form = { form } type = { type } index = { index } updateConfirmedValues = { updateConfirmedValues } { ...rest } />
73
+
37
74
< ActionIcon
38
75
color = 'red'
39
- onClick = { ( ) => form . removeListItem ( 'hyperparameters' , index ) }
76
+ onClick = { handleRemove }
40
77
className = 'ml-2'
41
78
>
42
- < Trash />
79
+ < Trash />
43
80
</ ActionIcon >
44
81
</ div >
45
- ) ;
46
- } }
82
+ { ( ( confirmedValues ?. find ( item => item . index === index ) ?. values ?. length ?? 0 ) > 0 && type === 'stringlist' ) && (
83
+ < div className = 'mt-4 p-4 bg-gray-100 rounded-md shadow-sm' >
84
+ < h3 className = 'text-lg font-medium text-gray-700 mb-2' > Values:</ h3 >
85
+ { confirmedValues . find ( item => item . index === index ) ?. values . map ( ( value , idx ) => (
86
+ < div key = { idx } className = 'flex items-center mb-2' >
87
+ < span className = 'block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm p-2 bg-white' >
88
+ { value }
89
+ </ span >
90
+ </ div >
91
+ ) ) }
92
+ </ div >
93
+ ) }
94
+ </ div >
95
+ ) }
47
96
</ Draggable >
48
97
) ;
49
98
} ;
@@ -52,14 +101,15 @@ const NumberParam = ({ form, type, index, ...rest }) => {
52
101
return (
53
102
< Fragment >
54
103
{ [ 'default' , 'min' , 'max' , 'step' ] . map ( ( label , i ) => {
104
+
55
105
return (
56
106
< input
57
107
key = { `number_${ type } _${ label } ` }
58
108
type = 'number'
59
109
placeholder = { `${ label } ` }
60
110
className = 'block w-full last-of-type:rounded-r-md border-gray-300 shadow-sm focus:border-blue-500 sm:text-sm'
61
111
required
62
- { ...form . getListInputProps ( ' hyperparameters' , index , label ) }
112
+ { ...form . getInputProps ( ` hyperparameters. ${ index } . ${ label } ` ) }
63
113
/>
64
114
) ;
65
115
} ) }
@@ -73,7 +123,7 @@ const BoolParam = ({ form, type, index, ...rest }) => {
73
123
label = { 'value' }
74
124
onLabel = { 'True' }
75
125
offLabel = { 'False' }
76
- { ...form . getListInputProps ( ' hyperparameters' , index , ' default' ) }
126
+ { ...form . getInputProps ( ` hyperparameters. ${ index } . default` ) }
77
127
/>
78
128
) ;
79
129
} ;
@@ -85,11 +135,106 @@ const StringParam = ({ form, type, index, ...rest }) => {
85
135
type = 'text'
86
136
placeholder = { `${ type } value` }
87
137
className = 'block w-full rounded-r-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm'
88
- { ...form . getListInputProps ( ' hyperparameters' , index , ' default' ) }
138
+ { ...form . getInputProps ( ` hyperparameters. ${ index } . default` ) }
89
139
required
90
140
/>
91
141
</ >
92
142
) ;
93
143
} ;
94
144
145
+ const MultiStringParam = ( { form, type, index, updateConfirmedValues, ...rest } ) => {
146
+ const [ opened , setOpened ] = useState ( false ) ;
147
+ const [ values , setValues ] = useState ( form . values . hyperparameters [ index ] . values || [ '' ] ) ;
148
+
149
+ useEffect ( ( ) => {
150
+ console . log ( 'Updated values:' , values ) ;
151
+ } , [ values ] ) ;
152
+
153
+ const handleAddValue = ( ) => {
154
+ setValues ( [ ...values , '' ] ) ;
155
+ form . insertListItem ( `hyperparameters[${ index } ].values` , '' ) ;
156
+ } ;
157
+
158
+ const handleChange = ( e , idx ) => {
159
+ console . log ( 'replacing list item:' , idx , e . target . value ) ;
160
+ form . replaceListItem ( `hyperparameters[${ index } ].values` , idx , e . target . value ) ;
161
+ console . log ( 'after replace:' , form . values . hyperparameters [ index ] . values ) ;
162
+ const newValues = [ ...values ] ;
163
+ newValues [ idx ] = e . target . value ;
164
+ setValues ( newValues ) ;
165
+ } ;
166
+
167
+ const handleDelete = ( idx ) => {
168
+ const newValues = values . filter ( ( _ , i ) => i !== idx ) ;
169
+ setValues ( newValues ) ;
170
+
171
+ const originalValues = form . values . hyperparameters [ index ] ?. values || [ ] ;
172
+ for ( let i = originalValues . length - 1 ; i >= 0 ; i -- ) {
173
+ if ( ! newValues . includes ( originalValues [ i ] ) ) {
174
+ console . log ( 'deleting:' , originalValues [ i ] ) ;
175
+ form . removeListItem ( `hyperparameters[${ index } ].values` , i ) ;
176
+ }
177
+ }
178
+
179
+ console . log ( 'after delete:' , form . values . hyperparameters [ index ] . values ) ;
180
+ } ;
181
+
182
+ const handleClose = ( ) => {
183
+ setOpened ( false ) ;
184
+ } ;
185
+
186
+ const handleConfirm = ( ) => {
187
+ form . values . hyperparameters [ index ] . values = values ;
188
+ updateConfirmedValues ( index , values ) ;
189
+ setOpened ( false ) ;
190
+ } ;
191
+
192
+ const handleOpen = ( ) => {
193
+ setOpened ( true ) ;
194
+ } ;
195
+
196
+ return (
197
+ < >
198
+ < Button onClick = { handleOpen } className = 'ml-2 rounded-md w-1/6 border border-transparent bg-blue-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2' >
199
+ Edit Strings
200
+ </ Button >
201
+ < Modal
202
+ opened = { opened }
203
+ onClose = { handleClose }
204
+ title = "Edit String Values"
205
+ >
206
+ { values . map ( ( value , idx ) => {
207
+ return (
208
+ < div key = { idx } className = 'flex items-center mb-2' >
209
+ < input
210
+ type = 'text'
211
+ placeholder = { `Value ${ idx + 1 } ` }
212
+ className = 'block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm'
213
+ value = { value }
214
+ onChange = { ( e ) => handleChange ( e , idx ) }
215
+ required
216
+ />
217
+ < ActionIcon onClick = { ( ) => handleDelete ( idx ) } color = 'red' className = 'ml-2' >
218
+ < Trash />
219
+ </ ActionIcon >
220
+ </ div >
221
+ ) ;
222
+ } ) }
223
+ < ActionIcon onClick = { handleAddValue } color = 'blue' >
224
+ < Plus />
225
+ </ ActionIcon >
226
+ < div className = "flex justify-end mt-4" >
227
+ < button
228
+ className = 'rounded-md border border-transparent bg-blue-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2'
229
+ onClick = { handleConfirm }
230
+ >
231
+ Confirm
232
+ </ button >
233
+ </ div >
234
+ </ Modal >
235
+ </ >
236
+ ) ;
237
+ } ;
238
+
95
239
export default Parameter ;
240
+
0 commit comments