@@ -7,35 +7,151 @@ import {
77 Button ,
88 ToggleButton ,
99 ToggleButtonGroup ,
10+ TextField ,
11+ Box ,
12+ Typography ,
1013} from "@mui/material" ;
1114import Editor from "@monaco-editor/react" ;
1215import yaml from "js-yaml" ;
1316
17+ const RenderFields = ( { data, onChange, path = [ ] } ) => {
18+ return Object . entries ( data || { } ) . map ( ( [ key , value ] ) => {
19+ // Skip internal Kubernetes metadata
20+ if ( key === "managedFields" || key . startsWith ( "f:" ) ) {
21+ return null ;
22+ }
23+
24+ const currentPath = [ ...path , key ] ;
25+
26+ if ( Array . isArray ( value ) ) {
27+ return (
28+ < Box
29+ key = { currentPath . join ( "." ) }
30+ sx = { { mb : 2 , pl : 2 , borderLeft : "2px solid #ccc" } }
31+ >
32+ < Typography variant = "subtitle2" > { key } (Array)</ Typography >
33+ { value . map ( ( item , index ) => {
34+ const itemPath = [ ...currentPath , index ] ;
35+ if ( typeof item === "object" && item !== null ) {
36+ return (
37+ < Box
38+ key = { itemPath . join ( "." ) }
39+ sx = { {
40+ pl : 2 ,
41+ mb : 1 ,
42+ borderLeft : "1px dashed #999" ,
43+ } }
44+ >
45+ < Typography variant = "caption" >
46+ Item { index }
47+ </ Typography >
48+ < RenderFields
49+ data = { item }
50+ onChange = { onChange }
51+ path = { itemPath }
52+ />
53+ </ Box >
54+ ) ;
55+ } else {
56+ return (
57+ < TextField
58+ key = { itemPath . join ( "." ) }
59+ label = { `${ key } [${ index } ]` }
60+ value = { item }
61+ fullWidth
62+ margin = "dense"
63+ onChange = { ( e ) =>
64+ onChange ( itemPath , e . target . value )
65+ }
66+ />
67+ ) ;
68+ }
69+ } ) }
70+ </ Box >
71+ ) ;
72+ }
73+
74+ if ( typeof value === "object" && value !== null ) {
75+ return (
76+ < Box
77+ key = { currentPath . join ( "." ) }
78+ sx = { { mb : 2 , pl : 2 , borderLeft : "2px solid #ccc" } }
79+ >
80+ < Typography variant = "subtitle2" > { key } </ Typography >
81+ < RenderFields
82+ data = { value }
83+ onChange = { onChange }
84+ path = { currentPath }
85+ />
86+ </ Box >
87+ ) ;
88+ }
89+
90+ return (
91+ < TextField
92+ key = { currentPath . join ( "." ) }
93+ label = { currentPath . join ( "." ) }
94+ value = { value }
95+ fullWidth
96+ margin = "dense"
97+ onChange = { ( e ) => onChange ( currentPath , e . target . value ) }
98+ />
99+ ) ;
100+ } ) ;
101+ } ;
102+
103+ const updateNestedValue = ( obj , path , value ) => {
104+ const lastKey = path . pop ( ) ;
105+ const nested = path . reduce ( ( acc , key ) => ( acc [ key ] = acc [ key ] || { } ) , obj ) ;
106+ nested [ lastKey ] = value ;
107+ return { ...obj } ;
108+ } ;
109+
14110const EditQueueDialog = ( { open, queue, onClose, onSave } ) => {
15111 const [ editorValue , setEditorValue ] = useState ( "" ) ;
16112 const [ editMode , setEditMode ] = useState ( "yaml" ) ;
113+ const [ formState , setFormState ] = useState ( { } ) ;
17114
18115 useEffect ( ( ) => {
19116 if ( open && queue ) {
20- const content = yaml . dump ( queue ) ; // Always YAML
21- setEditorValue ( content ) ;
117+ const yamlContent = yaml . dump ( queue ) ;
118+ setEditorValue ( yamlContent ) ;
119+ setFormState ( queue ) ;
120+ setEditMode ( "yaml" ) ;
22121 }
23122 } , [ open , queue ] ) ;
24123
25124 const handleModeChange = ( event , newMode ) => {
26- if ( newMode !== null ) {
27- setEditMode ( newMode ) ; // Only for syntax highlighting
125+ if ( ! newMode ) return ;
126+ if ( newMode === "form" ) {
127+ try {
128+ const parsed = yaml . load ( editorValue ) ;
129+ setFormState ( parsed || { } ) ;
130+ setEditMode ( "form" ) ;
131+ } catch ( err ) {
132+ alert ( "Invalid YAML. Cannot switch to Form view." ) ;
133+ }
134+ } else if ( newMode === "yaml" ) {
135+ setEditorValue ( yaml . dump ( formState ) ) ;
136+ setEditMode ( "yaml" ) ;
28137 }
29138 } ;
30139
140+ const handleNestedChange = ( path , value ) => {
141+ setFormState ( ( prev ) =>
142+ updateNestedValue ( { ...prev } , [ ...path ] , value ) ,
143+ ) ;
144+ } ;
145+
31146 const handleSave = ( ) => {
32147 try {
33- const updatedQueue = yaml . load ( editorValue ) ; // Always parse as YAML
34- onSave ( updatedQueue ) ;
148+ const updated =
149+ editMode === "yaml" ? yaml . load ( editorValue ) : formState ;
150+ onSave ( updated ) ;
35151 onClose ( ) ;
36152 } catch ( error ) {
37- console . error ( "Error parsing edited content :" , error ) ;
38- alert ( "Invalid YAML format. Please check your input. " ) ;
153+ console . error ( "Invalid YAML :" , error ) ;
154+ alert ( "Invalid YAML format." ) ;
39155 }
40156 } ;
41157
@@ -53,23 +169,34 @@ const EditQueueDialog = ({ open, queue, onClose, onSave }) => {
53169 value = { editMode }
54170 exclusive
55171 onChange = { handleModeChange }
56- color = "primary"
57172 >
58173 < ToggleButton value = "yaml" > YAML</ ToggleButton >
174+ < ToggleButton value = "form" > Form</ ToggleButton >
59175 </ ToggleButtonGroup >
60176 </ DialogTitle >
61- < DialogContent sx = { { height : "500px" } } >
62- < Editor
63- height = "100%"
64- language = { editMode } // only affects syntax highlighting
65- value = { editorValue }
66- onChange = { ( value ) => setEditorValue ( value || "" ) }
67- options = { {
68- minimap : { enabled : false } ,
69- automaticLayout : true ,
70- } }
71- />
177+
178+ < DialogContent sx = { { height : 500 } } >
179+ { editMode === "yaml" ? (
180+ < Editor
181+ height = "100%"
182+ language = "yaml"
183+ value = { editorValue }
184+ onChange = { ( v ) => setEditorValue ( v || "" ) }
185+ options = { {
186+ minimap : { enabled : false } ,
187+ automaticLayout : true ,
188+ } }
189+ />
190+ ) : (
191+ < Box sx = { { mt : 2 } } >
192+ < RenderFields
193+ data = { formState }
194+ onChange = { handleNestedChange }
195+ />
196+ </ Box >
197+ ) }
72198 </ DialogContent >
199+
73200 < DialogActions >
74201 < Button onClick = { onClose } color = "primary" variant = "contained" >
75202 Cancel
0 commit comments