@@ -8,12 +8,31 @@ import FormControl from '@mui/joy/FormControl';
88import FormLabel from '@mui/joy/FormLabel' ;
99import Input from '@mui/joy/Input' ;
1010import Textarea from '@mui/joy/Textarea' ;
11- import { ModalClose , ModalDialog , Sheet , Stack , Typography } from '@mui/joy' ;
11+ import {
12+ FormHelperText ,
13+ ModalClose ,
14+ ModalDialog ,
15+ Sheet ,
16+ Stack ,
17+ Typography ,
18+ } from '@mui/joy' ;
1219import { FolderIcon } from 'lucide-react' ;
20+ import { Editor } from '@monaco-editor/react' ;
21+ import fairyflossTheme from '../../Shared/fairyfloss.tmTheme.js' ;
1322
1423import * as chatAPI from 'renderer/lib/transformerlab-api-sdk' ;
1524import { useNotification } from 'renderer/components/Shared/NotificationSystem' ;
1625import { SafeJSONParse } from 'renderer/components/Shared/SafeJSONParse' ;
26+ import { useRef } from 'react' ;
27+
28+ const { parseTmTheme } = require ( 'monaco-themes' ) ;
29+
30+ function setTheme ( editor : any , monaco : any ) {
31+ const themeData = parseTmTheme ( fairyflossTheme ) ;
32+
33+ monaco . editor . defineTheme ( 'my-theme' , themeData ) ;
34+ monaco . editor . setTheme ( 'my-theme' ) ;
35+ }
1736
1837type EditTaskModalProps = {
1938 open : boolean ;
@@ -40,6 +59,9 @@ export default function EditTaskModal({
4059 const [ setup , setSetup ] = React . useState ( '' ) ;
4160 const [ saving , setSaving ] = React . useState ( false ) ;
4261
62+ const setupEditorRef = useRef < any > ( null ) ;
63+ const commandEditorRef = useRef < any > ( null ) ;
64+
4365 React . useEffect ( ( ) => {
4466 if ( ! task ) return ;
4567 setTitle ( task . name || '' ) ;
@@ -54,23 +76,48 @@ export default function EditTaskModal({
5476 setSetup ( cfg . setup != null ? String ( cfg . setup ) : '' ) ;
5577 } , [ task ] ) ;
5678
79+ // Keep Monaco editors in sync if the state changes after mount
80+ React . useEffect ( ( ) => {
81+ if (
82+ setupEditorRef . current &&
83+ typeof setupEditorRef . current . setValue === 'function'
84+ ) {
85+ setupEditorRef . current . setValue ( setup ?? '' ) ;
86+ }
87+ } , [ setup ] ) ;
88+
89+ React . useEffect ( ( ) => {
90+ if (
91+ commandEditorRef . current &&
92+ typeof commandEditorRef . current . setValue === 'function'
93+ ) {
94+ commandEditorRef . current . setValue ( command ?? '' ) ;
95+ }
96+ } , [ command ] ) ;
97+
5798 const handleSubmit = async ( e : React . FormEvent ) => {
5899 e . preventDefault ( ) ;
100+
101+ const setupValue =
102+ setupEditorRef ?. current ?. getValue ?.( ) ?? ( setup || undefined ) ;
103+ const commandValue =
104+ commandEditorRef ?. current ?. getValue ?.( ) ?? ( command || undefined ) ;
105+
59106 if ( ! task ) return ;
60- if ( ! command ) {
107+ if ( ! commandValue ) {
61108 addNotification ( { type : 'warning' , message : 'Command is required' } ) ;
62109 return ;
63110 }
64111 setSaving ( true ) ;
65112 const config = {
66113 cluster_name : clusterName ,
67- command,
114+ command : commandValue ,
68115 cpus : cpus || undefined ,
69116 memory : memory || undefined ,
70117 disk_space : diskSpace || undefined ,
71118 accelerators : accelerators || undefined ,
72119 num_nodes : numNodes ? parseInt ( numNodes , 10 ) : undefined ,
73- setup : setup || undefined ,
120+ setup : setupValue || undefined ,
74121 } as any ;
75122
76123 const body = {
@@ -115,6 +162,28 @@ export default function EditTaskModal({
115162 }
116163 } ;
117164
165+ function handleSetupEditorDidMount ( editor : any , monaco : any ) {
166+ setupEditorRef . current = editor ;
167+ setTheme ( editor , monaco ) ;
168+ // initialize editor with current setup state
169+ try {
170+ editor . setValue ( setup ?? '' ) ;
171+ } catch ( e ) {
172+ // ignore if setValue not available
173+ }
174+ }
175+
176+ function handleCommandEditorDidMount ( editor : any , monaco : any ) {
177+ commandEditorRef . current = editor ;
178+ setTheme ( editor , monaco ) ;
179+ // initialize editor with current command state
180+ try {
181+ editor . setValue ( command ?? '' ) ;
182+ } catch ( e ) {
183+ // ignore if setValue not available
184+ }
185+ }
186+
118187 return (
119188 < Modal open = { open } onClose = { onClose } >
120189 < ModalDialog
@@ -201,22 +270,59 @@ export default function EditTaskModal({
201270
202271 < FormControl sx = { { mt : 2 } } >
203272 < FormLabel > Setup Command</ FormLabel >
204- < Textarea
273+ { /* <Textarea
205274 minRows={2}
206275 value={setup}
207276 onChange={(e) => setSetup(e.target.value)}
208277 placeholder="Setup commands (optional) that runs before task is run. e.g. pip install -r requirements.txt"
278+ /> */ }
279+ < Editor
280+ defaultLanguage = "shell"
281+ theme = "my-theme"
282+ defaultValue = { setup }
283+ height = "6rem"
284+ options = { {
285+ minimap : {
286+ enabled : false ,
287+ } ,
288+ fontSize : 18 ,
289+ cursorStyle : 'block' ,
290+ wordWrap : 'on' ,
291+ } }
292+ onMount = { handleSetupEditorDidMount }
209293 />
294+ < FormHelperText >
295+ e.g. < code > pip install -r requirements.txt</ code >
296+ </ FormHelperText >
210297 </ FormControl >
211298
212299 < FormControl required sx = { { mt : 2 } } >
213300 < FormLabel > Command</ FormLabel >
214- < Textarea
301+ { /* <Textarea
215302 minRows={4}
216303 value={command}
217304 onChange={(e) => setCommand(e.target.value)}
218305 placeholder="e.g. python train.py --epochs 10"
306+ /> */ }
307+
308+ < Editor
309+ defaultLanguage = "shell"
310+ theme = "my-theme"
311+ defaultValue = { command }
312+ height = "8rem"
313+ options = { {
314+ minimap : {
315+ enabled : false ,
316+ } ,
317+ fontSize : 18 ,
318+ cursorStyle : 'block' ,
319+ wordWrap : 'on' ,
320+ } }
321+ onMount = { handleCommandEditorDidMount }
219322 />
323+ < FormHelperText >
324+ e.g. < code > python train.py --epochs 10</ code >
325+ </ FormHelperText >
220326 </ FormControl >
221327
222328 { /* Show uploaded directory indicator if present */ }
0 commit comments