robobyte-front-builder 1.0.17 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,762 @@
1
+ import React, {useState, useRef} from 'react'
2
+ import {
3
+ Dialog,
4
+ DialogTitle,
5
+ DialogContent,
6
+ DialogActions,
7
+ Button,
8
+ Box,
9
+ Typography,
10
+ TextField,
11
+ IconButton,
12
+ List,
13
+ ListItem,
14
+ Paper,
15
+ Divider,
16
+ Accordion,
17
+ AccordionSummary,
18
+ AccordionDetails,
19
+ Alert,
20
+ Autocomplete,
21
+ Checkbox,
22
+ FormControlLabel
23
+ } from '@mui/material'
24
+ import {Add, Delete, ContentCopy, ExpandMore, Edit} from '@mui/icons-material'
25
+ import dynamic from 'next/dynamic'
26
+
27
+ const MonacoEditor = dynamic(() => import('@monaco-editor/react'), {ssr: false})
28
+
29
+ // Common AG Grid cell renderers
30
+ const CELL_RENDERERS = [
31
+ 'agCheckboxCellRenderer',
32
+ 'agGroupCellRenderer',
33
+ 'agAnimateShowChangeCellRenderer',
34
+ 'agAnimateSlideCellRenderer',
35
+ 'agLoadingCellRenderer',
36
+ 'agSkeletonCellRenderer',
37
+ 'agSparklineCellRenderer'
38
+ ]
39
+
40
+ // Common AG Grid cell editors
41
+ const CELL_EDITORS = [
42
+ 'agTextCellEditor',
43
+ 'agSelectCellEditor',
44
+ 'agRichSelectCellEditor',
45
+ 'agLargeTextCellEditor',
46
+ 'agNumberCellEditor',
47
+ 'agDateCellEditor',
48
+ 'agDateStringCellEditor',
49
+ 'agCheckboxCellEditor',
50
+ 'MultiSelectEditorWrapper'
51
+ ]
52
+
53
+ const ColumnConfiguratorDialog = ({open, onClose, onResult}) => {
54
+ const [extraCols, setExtraCols] = useState([])
55
+ const [columnsConfig, setColumnsConfig] = useState([])
56
+ const [editingExtraColIndex, setEditingExtraColIndex] = useState(null)
57
+ const [editingColumnConfigIndex, setEditingColumnConfigIndex] = useState(null)
58
+ const [newExtraCol, setNewExtraCol] = useState({
59
+ headerName: '',
60
+ field: '',
61
+ editable: true,
62
+ cellRenderer: '',
63
+ cellEditor: '',
64
+ cellEditorParams: '',
65
+ valueSetter: '',
66
+ valueGetter: '',
67
+ additionalParams: ''
68
+ })
69
+ const [newColumnConfig, setNewColumnConfig] = useState({
70
+ field: '',
71
+ editable: false,
72
+ cellRenderer: '',
73
+ cellEditor: '',
74
+ cellEditorParams: '',
75
+ valueSetter: '',
76
+ valueGetter: '',
77
+ additionalParams: ''
78
+ })
79
+
80
+ const handleAddExtraCol = () => {
81
+ if (!newExtraCol.headerName || !newExtraCol.field) {
82
+ return
83
+ }
84
+
85
+ if (editingExtraColIndex !== null) {
86
+ // Update existing
87
+ const updated = [...extraCols]
88
+ updated[editingExtraColIndex] = {...newExtraCol}
89
+ setExtraCols(updated)
90
+ setEditingExtraColIndex(null)
91
+ } else {
92
+ // Add new
93
+ setExtraCols([...extraCols, {...newExtraCol}])
94
+ }
95
+
96
+ setNewExtraCol({
97
+ headerName: '',
98
+ field: '',
99
+ editable: true,
100
+ cellRenderer: '',
101
+ cellEditor: '',
102
+ cellEditorParams: '',
103
+ valueSetter: '',
104
+ valueGetter: '',
105
+ additionalParams: ''
106
+ })
107
+ }
108
+
109
+ const handleEditExtraCol = (index) => {
110
+ setNewExtraCol({...extraCols[index]})
111
+ setEditingExtraColIndex(index)
112
+ }
113
+
114
+ const handleCancelEditExtraCol = () => {
115
+ setNewExtraCol({
116
+ headerName: '',
117
+ field: '',
118
+ editable: true,
119
+ cellRenderer: '',
120
+ cellEditor: '',
121
+ cellEditorParams: '',
122
+ valueSetter: '',
123
+ valueGetter: '',
124
+ additionalParams: ''
125
+ })
126
+ setEditingExtraColIndex(null)
127
+ }
128
+
129
+ const handleRemoveExtraCol = (index) => {
130
+ setExtraCols(extraCols.filter((_, i) => i !== index))
131
+ if (editingExtraColIndex === index) {
132
+ handleCancelEditExtraCol()
133
+ }
134
+ }
135
+
136
+ const handleAddColumnConfig = () => {
137
+ if (!newColumnConfig.field) {
138
+ return
139
+ }
140
+
141
+ if (editingColumnConfigIndex !== null) {
142
+ // Update existing
143
+ const updated = [...columnsConfig]
144
+ updated[editingColumnConfigIndex] = {...newColumnConfig}
145
+ setColumnsConfig(updated)
146
+ setEditingColumnConfigIndex(null)
147
+ } else {
148
+ // Add new
149
+ setColumnsConfig([...columnsConfig, {...newColumnConfig}])
150
+ }
151
+
152
+ setNewColumnConfig({
153
+ field: '',
154
+ editable: false,
155
+ cellRenderer: '',
156
+ cellEditor: '',
157
+ cellEditorParams: '',
158
+ valueSetter: '',
159
+ valueGetter: '',
160
+ additionalParams: ''
161
+ })
162
+ }
163
+
164
+ const handleEditColumnConfig = (index) => {
165
+ setNewColumnConfig({...columnsConfig[index]})
166
+ setEditingColumnConfigIndex(index)
167
+ }
168
+
169
+ const handleCancelEditColumnConfig = () => {
170
+ setNewColumnConfig({
171
+ field: '',
172
+ editable: false,
173
+ cellRenderer: '',
174
+ cellEditor: '',
175
+ cellEditorParams: '',
176
+ valueSetter: '',
177
+ valueGetter: '',
178
+ additionalParams: ''
179
+ })
180
+ setEditingColumnConfigIndex(null)
181
+ }
182
+
183
+ const handleRemoveColumnConfig = (index) => {
184
+ setColumnsConfig(columnsConfig.filter((_, i) => i !== index))
185
+ if (editingColumnConfigIndex === index) {
186
+ handleCancelEditColumnConfig()
187
+ }
188
+ }
189
+
190
+ const buildResult = () => {
191
+ const processedExtraCols = extraCols.map(col => {
192
+ console.log('Processing extraCol:', col.field, 'additionalParams:', col.additionalParams)
193
+
194
+ const colDef = {
195
+ headerName: col.headerName,
196
+ field: col.field,
197
+ editable: col.editable
198
+ }
199
+ if (col.cellRenderer) colDef.cellRenderer = col.cellRenderer
200
+ if (col.cellEditor) colDef.cellEditor = col.cellEditor
201
+ if (col.cellEditorParams) colDef.cellEditorParams = col.cellEditorParams
202
+ if (col.valueSetter) colDef.valueSetter = col.valueSetter
203
+ if (col.valueGetter) colDef.valueGetter = col.valueGetter
204
+
205
+ // Parse and merge additional params
206
+ if (col.additionalParams && col.additionalParams.trim()) {
207
+ console.log('Attempting to parse:', `{${col.additionalParams}}`)
208
+ try {
209
+ const additionalObj = JSON.parse(`{${col.additionalParams}}`)
210
+ console.log('Parsed successfully:', additionalObj)
211
+ Object.assign(colDef, additionalObj)
212
+ } catch (e) {
213
+ console.error('Failed to parse additionalParams for extraCol:', col.additionalParams, e)
214
+ }
215
+ } else {
216
+ console.log('additionalParams is empty or whitespace')
217
+ }
218
+
219
+ return colDef
220
+ })
221
+
222
+ const processedColumnsConfig = columnsConfig.map(config => {
223
+ const configObj = {
224
+ editable: config.editable,
225
+ ...(config.valueSetter && {valueSetter: config.valueSetter}),
226
+ ...(config.valueGetter && {valueGetter: config.valueGetter})
227
+ }
228
+
229
+ if (config.cellRenderer) configObj.cellRenderer = config.cellRenderer
230
+ if (config.cellEditor) configObj.cellEditor = config.cellEditor
231
+ if (config.cellEditorParams) configObj.cellEditorParams = config.cellEditorParams
232
+
233
+ // Parse and merge additional params
234
+ if (config.additionalParams && config.additionalParams.trim()) {
235
+ try {
236
+ const additionalObj = JSON.parse(`{${config.additionalParams}}`)
237
+ Object.assign(configObj, additionalObj)
238
+ } catch (e) {
239
+ console.warn('Failed to parse additionalParams for columnConfig:', config.additionalParams, e)
240
+ }
241
+ }
242
+
243
+ return {
244
+ field: config.field,
245
+ config: configObj
246
+ }
247
+ })
248
+
249
+ return {
250
+ extraCols: processedExtraCols,
251
+ columnsConfig: processedColumnsConfig
252
+ }
253
+ }
254
+
255
+ const handleGenerate = () => {
256
+ const result = buildResult()
257
+ onResult(result)
258
+ }
259
+
260
+ const handleCopyJSON = () => {
261
+ const result = buildResult()
262
+ navigator.clipboard.writeText(JSON.stringify(result, null, 2))
263
+ }
264
+
265
+ return (
266
+ <Dialog open={open} onClose={onClose} maxWidth="lg" fullWidth>
267
+ <DialogTitle>
268
+ <Box display="flex" justifyContent="space-between" alignItems="center">
269
+ <Typography variant="h6">Column Configurator</Typography>
270
+ <IconButton onClick={handleCopyJSON} size="small" title="Copy JSON to clipboard">
271
+ <ContentCopy/>
272
+ </IconButton>
273
+ </Box>
274
+ </DialogTitle>
275
+ <DialogContent>
276
+ <Box sx={{display: 'flex', flexDirection: 'column', gap: 3}}>
277
+ {/* Extra Columns Section */}
278
+ <Accordion defaultExpanded>
279
+ <AccordionSummary expandIcon={<ExpandMore/>}>
280
+ <Typography variant="h6">Extra Columns ({extraCols.length})</Typography>
281
+ </AccordionSummary>
282
+ <AccordionDetails>
283
+ <Box sx={{display: 'flex', flexDirection: 'column', gap: 2}}>
284
+ <Alert severity="info" sx={{mb: 2}}>
285
+ Extra columns are additional columns that don't exist in the report data. They can be used for
286
+ custom fields with editable values.
287
+ </Alert>
288
+
289
+ <Paper sx={{p: 2, bgcolor: 'background.default'}}>
290
+ <Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2}}>
291
+ <Typography variant="subtitle2">
292
+ {editingExtraColIndex !== null ? 'Edit Extra Column' : 'Add New Extra Column'}
293
+ </Typography>
294
+ {editingExtraColIndex !== null && (
295
+ <Button size="small" onClick={handleCancelEditExtraCol}>
296
+ Cancel Edit
297
+ </Button>
298
+ )}
299
+ </Box>
300
+ <Box sx={{display: 'flex', gap: 2, flexWrap: 'wrap', alignItems: 'flex-start'}}>
301
+ <TextField
302
+ size="small"
303
+ label="Header Name"
304
+ value={newExtraCol.headerName}
305
+ onChange={(e) => setNewExtraCol({...newExtraCol, headerName: e.target.value})}
306
+ sx={{flex: 1, minWidth: 150}}
307
+ />
308
+ <TextField
309
+ size="small"
310
+ label="Field"
311
+ value={newExtraCol.field}
312
+ onChange={(e) => setNewExtraCol({...newExtraCol, field: e.target.value})}
313
+ sx={{flex: 1, minWidth: 150}}
314
+ />
315
+ <FormControlLabel
316
+ control={
317
+ <Checkbox
318
+ checked={newExtraCol.editable}
319
+ onChange={(e) => setNewExtraCol({...newExtraCol, editable: e.target.checked})}
320
+ />
321
+ }
322
+ label="Editable"
323
+ sx={{minWidth: 100}}
324
+ />
325
+ <Autocomplete
326
+ size="small"
327
+ freeSolo
328
+ options={CELL_RENDERERS}
329
+ value={newExtraCol.cellRenderer}
330
+ onChange={(e, newValue) => setNewExtraCol({...newExtraCol, cellRenderer: newValue || ''})}
331
+ onInputChange={(e, newValue) => setNewExtraCol({...newExtraCol, cellRenderer: newValue || ''})}
332
+ renderInput={(params) => (
333
+ <TextField
334
+ {...params}
335
+ label="Cell Renderer"
336
+ placeholder="agCheckboxCellRenderer"
337
+ />
338
+ )}
339
+ sx={{flex: 1, minWidth: 200}}
340
+ />
341
+ <Autocomplete
342
+ size="small"
343
+ freeSolo
344
+ options={CELL_EDITORS}
345
+ value={newExtraCol.cellEditor}
346
+ onChange={(e, newValue) => setNewExtraCol({...newExtraCol, cellEditor: newValue || ''})}
347
+ onInputChange={(e, newValue) => setNewExtraCol({...newExtraCol, cellEditor: newValue || ''})}
348
+ renderInput={(params) => (
349
+ <TextField
350
+ {...params}
351
+ label="Cell Editor"
352
+ placeholder="agCheckboxCellEditor"
353
+ />
354
+ )}
355
+ sx={{flex: 1, minWidth: 200}}
356
+ />
357
+ </Box>
358
+ {newExtraCol.cellEditor === 'MultiSelectEditorWrapper' && (
359
+ <Box sx={{mt: 2}}>
360
+ <Alert severity="warning" sx={{mb: 2}}>
361
+ <Typography variant="caption">
362
+ MultiSelectEditorWrapper requires cellEditorParams with: fieldName, filterFields, uniqueId,
363
+ value, isSingle, asyncFetchOptions
364
+ </Typography>
365
+ </Alert>
366
+ <Typography variant="caption" sx={{mb: 1, display: 'block'}}>
367
+ Cell Editor Params (Function or Object)
368
+ </Typography>
369
+ <Box sx={{border: '1px solid #ddd', borderRadius: 1}}>
370
+ <MonacoEditor
371
+ height="200px"
372
+ language="javascript"
373
+ theme="vs-dark"
374
+ value={newExtraCol.cellEditorParams}
375
+ onChange={(value) => setNewExtraCol({...newExtraCol, cellEditorParams: value || ''})}
376
+ options={{
377
+ minimap: {enabled: false},
378
+ fontSize: 12,
379
+ lineNumbers: 'on',
380
+ scrollBeyondLastLine: false,
381
+ automaticLayout: true
382
+ }}
383
+ />
384
+ </Box>
385
+ </Box>
386
+ )}
387
+ <Box sx={{mt: 2}}>
388
+ <Typography variant="caption" sx={{mb: 1, display: 'block'}}>
389
+ Value Setter (optional)
390
+ </Typography>
391
+ <Box sx={{border: '1px solid #ddd', borderRadius: 1}}>
392
+ <MonacoEditor
393
+ height="120px"
394
+ language="javascript"
395
+ theme="vs-dark"
396
+ value={newExtraCol.valueSetter}
397
+ onChange={(value) => setNewExtraCol({...newExtraCol, valueSetter: value || ''})}
398
+ options={{
399
+ minimap: {enabled: false},
400
+ fontSize: 12,
401
+ lineNumbers: 'on',
402
+ scrollBeyondLastLine: false,
403
+ automaticLayout: true
404
+ }}
405
+ />
406
+ </Box>
407
+ </Box>
408
+ <Box sx={{mt: 2}}>
409
+ <Typography variant="caption" sx={{mb: 1, display: 'block'}}>
410
+ Value Getter (optional)
411
+ </Typography>
412
+ <Box sx={{border: '1px solid #ddd', borderRadius: 1}}>
413
+ <MonacoEditor
414
+ height="120px"
415
+ language="javascript"
416
+ theme="vs-dark"
417
+ value={newExtraCol.valueGetter}
418
+ onChange={(value) => setNewExtraCol({...newExtraCol, valueGetter: value || ''})}
419
+ options={{
420
+ minimap: {enabled: false},
421
+ fontSize: 12,
422
+ lineNumbers: 'on',
423
+ scrollBeyondLastLine: false,
424
+ automaticLayout: true
425
+ }}
426
+ />
427
+ </Box>
428
+ </Box>
429
+ <Box sx={{mt: 2}}>
430
+ <Typography variant="caption" sx={{mb: 1, display: 'block'}}>
431
+ Additional Column Parameters (valueFormatter, width, etc.)
432
+ </Typography>
433
+ <Alert severity="info" sx={{mb: 1, fontSize: '0.75rem'}}>
434
+ Add any AG Grid column properties as key-value pairs (without outer braces).
435
+ Example: valueFormatter: (p) =&gt; p.value?.name, width: 200
436
+ </Alert>
437
+ <Box sx={{border: '1px solid #ddd', borderRadius: 1}}>
438
+ <MonacoEditor
439
+ height="150px"
440
+ language="javascript"
441
+ theme="vs-dark"
442
+ value={newExtraCol.additionalParams}
443
+ onChange={(value) => setNewExtraCol({...newExtraCol, additionalParams: value || ''})}
444
+ options={{
445
+ minimap: {enabled: false},
446
+ fontSize: 12,
447
+ lineNumbers: 'on',
448
+ scrollBeyondLastLine: false,
449
+ automaticLayout: true
450
+ }}
451
+ />
452
+ </Box>
453
+ </Box>
454
+ <Box sx={{display: 'flex', justifyContent: 'flex-end', mt: 2}}>
455
+ <Button
456
+ variant="contained"
457
+ startIcon={editingExtraColIndex !== null ? <Edit/> : <Add/>}
458
+ onClick={handleAddExtraCol}
459
+ disabled={!newExtraCol.headerName || !newExtraCol.field}
460
+ >
461
+ {editingExtraColIndex !== null ? 'Update' : 'Add'}
462
+ </Button>
463
+ </Box>
464
+ </Paper>
465
+
466
+ <List sx={{bgcolor: 'background.paper', borderRadius: 1}}>
467
+ {extraCols.map((col, index) => (
468
+ <ListItem
469
+ key={index}
470
+ secondaryAction={
471
+ <Box>
472
+ <IconButton onClick={() => handleEditExtraCol(index)}>
473
+ <Edit/>
474
+ </IconButton>
475
+ <IconButton edge="end" onClick={() => handleRemoveExtraCol(index)}>
476
+ <Delete/>
477
+ </IconButton>
478
+ </Box>
479
+ }
480
+ >
481
+ <Box sx={{width: '100%'}}>
482
+ <Typography variant="body1" fontWeight="bold">
483
+ {col.headerName} ({col.field})
484
+ </Typography>
485
+ <Typography variant="caption" color="text.secondary" component="div">
486
+ Editable: {col.editable ? 'Yes' : 'No'} | Renderer: {col.cellRenderer || 'default'} | Editor: {col.cellEditor || 'default'}
487
+ {col.cellEditorParams && <> | Has cellEditorParams</>}
488
+ {col.valueSetter && <> | Has valueSetter</>}
489
+ {col.valueGetter && <> | Has valueGetter</>}
490
+ {col.additionalParams && <> | Has additionalParams</>}
491
+ </Typography>
492
+ </Box>
493
+ </ListItem>
494
+ ))}
495
+ {extraCols.length === 0 && (
496
+ <ListItem>
497
+ <Typography variant="body2" color="text.secondary">
498
+ No extra columns defined yet
499
+ </Typography>
500
+ </ListItem>
501
+ )}
502
+ </List>
503
+ </Box>
504
+ </AccordionDetails>
505
+ </Accordion>
506
+
507
+ {/* Column Config Section */}
508
+ <Accordion defaultExpanded>
509
+ <AccordionSummary expandIcon={<ExpandMore/>}>
510
+ <Typography variant="h6">Column Configurations ({columnsConfig.length})</Typography>
511
+ </AccordionSummary>
512
+ <AccordionDetails>
513
+ <Box sx={{display: 'flex', flexDirection: 'column', gap: 2}}>
514
+ <Alert severity="info" sx={{mb: 2}}>
515
+ Column configurations modify existing columns in the report. Use valueSetter and valueGetter to
516
+ manage custom values.
517
+ </Alert>
518
+
519
+ <Paper sx={{p: 2, bgcolor: 'background.default'}}>
520
+ <Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2}}>
521
+ <Typography variant="subtitle2">
522
+ {editingColumnConfigIndex !== null ? 'Edit Column Config' : 'Add New Column Config'}
523
+ </Typography>
524
+ {editingColumnConfigIndex !== null && (
525
+ <Button size="small" onClick={handleCancelEditColumnConfig}>
526
+ Cancel Edit
527
+ </Button>
528
+ )}
529
+ </Box>
530
+ <Box sx={{display: 'flex', flexDirection: 'column', gap: 2}}>
531
+ <TextField
532
+ size="small"
533
+ label="Field Name"
534
+ value={newColumnConfig.field}
535
+ onChange={(e) => setNewColumnConfig({...newColumnConfig, field: e.target.value})}
536
+ fullWidth
537
+ />
538
+ <FormControlLabel
539
+ control={
540
+ <Checkbox
541
+ checked={newColumnConfig.editable}
542
+ onChange={(e) => setNewColumnConfig({...newColumnConfig, editable: e.target.checked})}
543
+ />
544
+ }
545
+ label="Editable"
546
+ />
547
+ <Box sx={{display: 'flex', gap: 2}}>
548
+ <Autocomplete
549
+ size="small"
550
+ freeSolo
551
+ options={CELL_RENDERERS}
552
+ value={newColumnConfig.cellRenderer}
553
+ onChange={(e, newValue) => setNewColumnConfig({...newColumnConfig, cellRenderer: newValue || ''})}
554
+ onInputChange={(e, newValue) => setNewColumnConfig({...newColumnConfig, cellRenderer: newValue || ''})}
555
+ renderInput={(params) => (
556
+ <TextField
557
+ {...params}
558
+ label="Cell Renderer"
559
+ placeholder="agCheckboxCellRenderer"
560
+ />
561
+ )}
562
+ sx={{flex: 1}}
563
+ />
564
+ <Autocomplete
565
+ size="small"
566
+ freeSolo
567
+ options={CELL_EDITORS}
568
+ value={newColumnConfig.cellEditor}
569
+ onChange={(e, newValue) => setNewColumnConfig({...newColumnConfig, cellEditor: newValue || ''})}
570
+ onInputChange={(e, newValue) => setNewColumnConfig({...newColumnConfig, cellEditor: newValue || ''})}
571
+ renderInput={(params) => (
572
+ <TextField
573
+ {...params}
574
+ label="Cell Editor"
575
+ placeholder="agCheckboxCellEditor"
576
+ />
577
+ )}
578
+ sx={{flex: 1}}
579
+ />
580
+ </Box>
581
+ {newColumnConfig.cellEditor === 'MultiSelectEditorWrapper' && (
582
+ <Box>
583
+ <Alert severity="warning" sx={{mb: 1}}>
584
+ <Typography variant="caption">
585
+ MultiSelectEditorWrapper requires cellEditorParams with: fieldName, filterFields, uniqueId,
586
+ value, isSingle, asyncFetchOptions
587
+ </Typography>
588
+ </Alert>
589
+ <Typography variant="caption" sx={{mb: 1, display: 'block'}}>
590
+ Cell Editor Params (Function or Object)
591
+ </Typography>
592
+ <Box sx={{border: '1px solid #ddd', borderRadius: 1}}>
593
+ <MonacoEditor
594
+ height="150px"
595
+ language="javascript"
596
+ theme="vs-dark"
597
+ value={newColumnConfig.cellEditorParams}
598
+ onChange={(value) => setNewColumnConfig({...newColumnConfig, cellEditorParams: value || ''})}
599
+ options={{
600
+ minimap: {enabled: false},
601
+ fontSize: 12,
602
+ lineNumbers: 'on',
603
+ scrollBeyondLastLine: false,
604
+ automaticLayout: true
605
+ }}
606
+ />
607
+ </Box>
608
+ </Box>
609
+ )}
610
+ <Box>
611
+ <Typography variant="caption" sx={{mb: 1, display: 'block'}}>
612
+ Value Setter (optional)
613
+ </Typography>
614
+ <Box sx={{border: '1px solid #ddd', borderRadius: 1}}>
615
+ <MonacoEditor
616
+ height="120px"
617
+ language="javascript"
618
+ theme="vs-dark"
619
+ value={newColumnConfig.valueSetter}
620
+ onChange={(value) => setNewColumnConfig({...newColumnConfig, valueSetter: value || ''})}
621
+ options={{
622
+ minimap: {enabled: false},
623
+ fontSize: 12,
624
+ lineNumbers: 'on',
625
+ scrollBeyondLastLine: false,
626
+ automaticLayout: true
627
+ }}
628
+ />
629
+ </Box>
630
+ </Box>
631
+ <Box>
632
+ <Typography variant="caption" sx={{mb: 1, display: 'block'}}>
633
+ Value Getter (optional)
634
+ </Typography>
635
+ <Box sx={{border: '1px solid #ddd', borderRadius: 1}}>
636
+ <MonacoEditor
637
+ height="120px"
638
+ language="javascript"
639
+ theme="vs-dark"
640
+ value={newColumnConfig.valueGetter}
641
+ onChange={(value) => setNewColumnConfig({...newColumnConfig, valueGetter: value || ''})}
642
+ options={{
643
+ minimap: {enabled: false},
644
+ fontSize: 12,
645
+ lineNumbers: 'on',
646
+ scrollBeyondLastLine: false,
647
+ automaticLayout: true
648
+ }}
649
+ />
650
+ </Box>
651
+ </Box>
652
+ <Box>
653
+ <Typography variant="caption" sx={{mb: 1, display: 'block'}}>
654
+ Additional Column Parameters
655
+ </Typography>
656
+ <Alert severity="info" sx={{mb: 1, fontSize: '0.75rem'}}>
657
+ Add any AG Grid column config properties as key-value pairs (without outer braces).
658
+ Example: valueFormatter: (p) =&gt; p.value?.name, width: 200
659
+ </Alert>
660
+ <Box sx={{border: '1px solid #ddd', borderRadius: 1}}>
661
+ <MonacoEditor
662
+ height="120px"
663
+ language="javascript"
664
+ theme="vs-dark"
665
+ value={newColumnConfig.additionalParams}
666
+ onChange={(value) => setNewColumnConfig({...newColumnConfig, additionalParams: value || ''})}
667
+ options={{
668
+ minimap: {enabled: false},
669
+ fontSize: 12,
670
+ lineNumbers: 'on',
671
+ scrollBeyondLastLine: false,
672
+ automaticLayout: true
673
+ }}
674
+ />
675
+ </Box>
676
+ </Box>
677
+ <Button
678
+ variant="contained"
679
+ startIcon={editingColumnConfigIndex !== null ? <Edit/> : <Add/>}
680
+ onClick={handleAddColumnConfig}
681
+ disabled={!newColumnConfig.field}
682
+ sx={{alignSelf: 'flex-start'}}
683
+ >
684
+ {editingColumnConfigIndex !== null ? 'Update' : 'Add'}
685
+ </Button>
686
+ </Box>
687
+ </Paper>
688
+
689
+ <List sx={{bgcolor: 'background.paper', borderRadius: 1}}>
690
+ {columnsConfig.map((config, index) => (
691
+ <ListItem
692
+ key={index}
693
+ secondaryAction={
694
+ <Box>
695
+ <IconButton onClick={() => handleEditColumnConfig(index)}>
696
+ <Edit/>
697
+ </IconButton>
698
+ <IconButton edge="end" onClick={() => handleRemoveColumnConfig(index)}>
699
+ <Delete/>
700
+ </IconButton>
701
+ </Box>
702
+ }
703
+ >
704
+ <Box sx={{width: '100%'}}>
705
+ <Typography variant="body1" fontWeight="bold">
706
+ {config.field}
707
+ </Typography>
708
+ <Typography variant="caption" color="text.secondary" component="div">
709
+ Editable: {config.editable ? 'Yes' : 'No'}
710
+ {config.cellRenderer && <> | Renderer: {config.cellRenderer}</>}
711
+ {config.cellEditor && <> | Editor: {config.cellEditor}</>}
712
+ {config.cellEditorParams && <> | Has cellEditorParams</>}
713
+ {config.valueSetter && <> | Has valueSetter</>}
714
+ {config.valueGetter && <> | Has valueGetter</>}
715
+ {config.additionalParams && <> | Has additionalParams</>}
716
+ </Typography>
717
+ </Box>
718
+ </ListItem>
719
+ ))}
720
+ {columnsConfig.length === 0 && (
721
+ <ListItem>
722
+ <Typography variant="body2" color="text.secondary">
723
+ No column configurations defined yet
724
+ </Typography>
725
+ </ListItem>
726
+ )}
727
+ </List>
728
+ </Box>
729
+ </AccordionDetails>
730
+ </Accordion>
731
+
732
+ {/* JSON Preview */}
733
+ <Paper sx={{p: 2, bgcolor: 'background.default'}}>
734
+ <Typography variant="subtitle2" sx={{mb: 2}}>JSON Preview</Typography>
735
+ <Box
736
+ component="pre"
737
+ sx={{
738
+ p: 2,
739
+ bgcolor: 'grey.900',
740
+ color: 'grey.100',
741
+ borderRadius: 1,
742
+ overflow: 'auto',
743
+ maxHeight: 300,
744
+ fontSize: '0.875rem'
745
+ }}
746
+ >
747
+ {JSON.stringify(buildResult(), null, 2)}
748
+ </Box>
749
+ </Paper>
750
+ </Box>
751
+ </DialogContent>
752
+ <DialogActions>
753
+ <Button onClick={onClose}>Close</Button>
754
+ <Button variant="contained" onClick={handleGenerate}>
755
+ Generate Result
756
+ </Button>
757
+ </DialogActions>
758
+ </Dialog>
759
+ )
760
+ }
761
+
762
+ export default ColumnConfiguratorDialog