Spaces:
Running
Running
File size: 4,389 Bytes
fcc02a2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
'use client';
import { useEffect, useState, useRef } from 'react';
import { JobConfig } from '@/types';
import YAML from 'yaml';
import Editor, { OnMount } from '@monaco-editor/react';
import type { editor } from 'monaco-editor';
import { Settings } from '@/hooks/useSettings';
type Props = {
jobConfig: JobConfig;
setJobConfig: (value: any, key?: string) => void;
status: 'idle' | 'saving' | 'success' | 'error';
handleSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
runId: string | null;
gpuIDs: string | null;
setGpuIDs: (value: string | null) => void;
gpuList: any;
datasetOptions: any;
settings: Settings;
};
const isDev = process.env.NODE_ENV === 'development';
const yamlConfig: YAML.DocumentOptions &
YAML.SchemaOptions &
YAML.ParseOptions &
YAML.CreateNodeOptions &
YAML.ToStringOptions = {
indent: 2,
lineWidth: 999999999999,
defaultStringType: 'QUOTE_DOUBLE',
defaultKeyType: 'PLAIN',
directives: true,
};
export default function AdvancedJob({ jobConfig, setJobConfig, settings }: Props) {
const [editorValue, setEditorValue] = useState<string>('');
const lastJobConfigUpdateStringRef = useRef('');
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
// Track if the editor has been mounted
const isEditorMounted = useRef(false);
// Handler for editor mounting
const handleEditorDidMount: OnMount = editor => {
editorRef.current = editor;
isEditorMounted.current = true;
// Initial content setup
try {
const yamlContent = YAML.stringify(jobConfig, yamlConfig);
setEditorValue(yamlContent);
lastJobConfigUpdateStringRef.current = JSON.stringify(jobConfig);
} catch (e) {
console.warn(e);
}
};
useEffect(() => {
const lastUpdate = lastJobConfigUpdateStringRef.current;
const currentUpdate = JSON.stringify(jobConfig);
// Skip if no changes or editor not yet mounted
if (lastUpdate === currentUpdate || !isEditorMounted.current) {
return;
}
try {
// Preserve cursor position and selection
const editor = editorRef.current;
if (editor) {
// Save current editor state
const position = editor.getPosition();
const selection = editor.getSelection();
const scrollTop = editor.getScrollTop();
// Update content
const yamlContent = YAML.stringify(jobConfig, yamlConfig);
// Only update if the content is actually different
if (yamlContent !== editor.getValue()) {
// Set value directly on the editor model instead of using React state
editor.getModel()?.setValue(yamlContent);
// Restore cursor position and selection
if (position) editor.setPosition(position);
if (selection) editor.setSelection(selection);
editor.setScrollTop(scrollTop);
}
lastJobConfigUpdateStringRef.current = currentUpdate;
}
} catch (e) {
console.warn(e);
}
}, [jobConfig]);
const handleChange = (value: string | undefined) => {
if (value === undefined) return;
try {
const parsed = YAML.parse(value);
// Don't update jobConfig if the change came from the editor itself
// to avoid a circular update loop
if (JSON.stringify(parsed) !== lastJobConfigUpdateStringRef.current) {
lastJobConfigUpdateStringRef.current = JSON.stringify(parsed);
// We have to ensure certain things are always set
try {
parsed.config.process[0].type = 'ui_trainer';
parsed.config.process[0].sqlite_db_path = './aitk_db.db';
parsed.config.process[0].training_folder = settings.TRAINING_FOLDER;
parsed.config.process[0].device = 'cuda';
parsed.config.process[0].performance_log_every = 10;
} catch (e) {
console.warn(e);
}
setJobConfig(parsed);
}
} catch (e) {
// Don't update on parsing errors
console.warn(e);
}
};
return (
<>
<Editor
height="100%"
width="100%"
defaultLanguage="yaml"
value={editorValue}
theme="vs-dark"
onChange={handleChange}
onMount={handleEditorDidMount}
options={{
minimap: { enabled: true },
scrollBeyondLastLine: false,
automaticLayout: true,
}}
/>
</>
);
}
|