diff --git a/src/renderer/components/Experiment/Tasks/QueueTaskModal.tsx b/src/renderer/components/Experiment/Tasks/QueueTaskModal.tsx index 96537be88..1c150f7d2 100644 --- a/src/renderer/components/Experiment/Tasks/QueueTaskModal.tsx +++ b/src/renderer/components/Experiment/Tasks/QueueTaskModal.tsx @@ -25,7 +25,12 @@ import { Chip, } from '@mui/joy'; import { Editor } from '@monaco-editor/react'; -import { PlayIcon, AlertTriangleIcon, CheckCircleIcon } from 'lucide-react'; +import { + PlayIcon, + AlertTriangleIcon, + CheckCircleIcon, + ChevronDownIcon, +} from 'lucide-react'; import { setTheme } from 'renderer/lib/monacoConfig'; import { useSWRWithAuth as useSWR, useAPI } from 'renderer/lib/authContext'; import * as chatAPI from 'renderer/lib/transformerlab-api-sdk'; @@ -115,6 +120,11 @@ export default function QueueTaskModal({ const [acceleratorsInput, setAcceleratorsInput] = React.useState(''); const [numNodesInput, setNumNodesInput] = React.useState(''); const [minutesRequestedInput, setMinutesRequestedInput] = React.useState(''); + const [showResourceOverrides, setShowResourceOverrides] = + React.useState(false); + const [showParameterOverrides, setShowParameterOverrides] = + React.useState(true); + const resourceOverridesRef = React.useRef(null); const loadingMessages = React.useMemo( () => [ 'Contacting compute provider…', @@ -152,6 +162,18 @@ export default function QueueTaskModal({ }; }, [open, isSubmitting, loadingMessages]); + React.useEffect(() => { + if (!showResourceOverrides) { + return; + } + window.requestAnimationFrame(() => { + resourceOverridesRef.current?.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + }); + }); + }, [showResourceOverrides]); + // Fetch available models and datasets from the API const { data: modelsData } = useSWR( open ? chatAPI.Endpoints.Models.LocalList() : null, @@ -1275,213 +1297,75 @@ export default function QueueTaskModal({ )} - - {/* Resource Requirements Section */} - - - Resource Requirements - - - CPUs - setCpusInput(e.target.value)} - disabled={isSubmitting} - /> - - - Memory - setMemoryInput(e.target.value)} - disabled={isSubmitting} - /> - - - - - Disk space - setDiskSpaceInput(e.target.value)} - disabled={isSubmitting} - /> - - - Accelerators - setAcceleratorsInput(e.target.value)} - disabled={isSubmitting} - /> - - - - - Num nodes - setNumNodesInput(e.target.value)} - disabled={isSubmitting} - /> - - - Minutes requested - setMinutesRequestedInput(e.target.value)} - disabled={isSubmitting} - /> - - - - These values override the template's resource - requirements for this run only. Leave a field empty to use the - template default. - - - - {/* Incompatibility Warning */} - {selectedProvider && - effectiveResources?.accelerators && - !isProviderCompatible(selectedProvider) && ( - } - sx={{ mt: 1 }} - > - - This provider may not support the requested accelerators ( - {effectiveResources.accelerators}). - - - )} - - {/* Local Provider Resource Validation */} - {isLocalProvider && - resourceValidation && - !resourceValidation.isCompatible && ( - } - sx={{ mt: 1 }} - > - - - {resourceValidation.hasErrors - ? 'Local provider cannot meet task requirements' - : 'Local provider may not meet task requirements'} - - - {resourceValidation.issues.map((issue, idx) => ( - - - {issue.label} - - - Required: {issue.required} — - Available: {issue.available} - - - ))} - - {resourceValidation.hasErrors && ( - - Consider selecting a different provider with the - required resources. - - )} - - - )} - - {isLocalProvider && - resourceValidation?.isCompatible && - effectiveResources && ( - } - sx={{ mt: 1 }} - > - - Local provider meets the task resource requirements. - - - )} {/* Task Parameters Section */} - Task Parameters - {parameters.length === 0 || - (parameters.length === 1 && - !parameters[0].key && - !parameters[0].value) ? ( - - This task has no parameters defined. Click Submit to queue - with default configuration. - - ) : ( + setShowParameterOverrides((prev) => !prev)} + > + Parameter overrides + + + {showParameterOverrides && ( - {parameters.map((param, index) => { - const schema = param.schema; - const label = schema?.title || param.key; - - return ( - - - + This task has no parameters defined. Click Submit to queue + with default configuration. + + ) : ( + + {parameters.map((param, index) => { + const schema = param.schema; + const label = schema?.title || param.key; + + return ( + - {label}: - - {renderParameterInput(param, index)} - - - ); - })} + + + {label}: + + {renderParameterInput(param, index)} + + + ); + })} + + )} + + Parameters can be accessed in your task script using{' '} + lab.get_config() + )} - - Parameters can be accessed in your task script using{' '} - lab.get_config() - @@ -1547,6 +1431,197 @@ export default function QueueTaskModal({ onLowerIsBetterChange={setLowerIsBetter} parameters={parameters} /> + + {/* Optional Resource Overrides Section */} + + + setShowResourceOverrides((prev) => !prev)} + > + + Optional resource overrides + + + + {showResourceOverrides && ( + + + + CPUs + setCpusInput(e.target.value)} + disabled={isSubmitting} + /> + + + Memory + setMemoryInput(e.target.value)} + disabled={isSubmitting} + /> + + + + + Disk space + setDiskSpaceInput(e.target.value)} + disabled={isSubmitting} + /> + + + Accelerators + setAcceleratorsInput(e.target.value)} + disabled={isSubmitting} + /> + + + + + Num nodes + setNumNodesInput(e.target.value)} + disabled={isSubmitting} + /> + + + Minutes requested + + setMinutesRequestedInput(e.target.value) + } + disabled={isSubmitting} + /> + + + + These values override the template's resource + requirements for this run only. Leave a field empty to use + the template default. + + + {/* Incompatibility Warning */} + {selectedProvider && + effectiveResources?.accelerators && + !isProviderCompatible(selectedProvider) && ( + } + sx={{ mt: 1 }} + > + + This provider may not support the requested + accelerators ( + {effectiveResources.accelerators}). + + + )} + + {/* Local Provider Resource Validation */} + {isLocalProvider && + resourceValidation && + !resourceValidation.isCompatible && ( + } + sx={{ mt: 1 }} + > + + + {resourceValidation.hasErrors + ? 'Local provider cannot meet task requirements' + : 'Local provider may not meet task requirements'} + + + {resourceValidation.issues.map((issue, idx) => ( + + + {issue.label} + + + Required: {issue.required} — + Available: {issue.available} + + + ))} + + {resourceValidation.hasErrors && ( + + Consider selecting a different provider with the + required resources. + + )} + + + )} + + {isLocalProvider && + resourceValidation?.isCompatible && + effectiveResources && ( + } + sx={{ mt: 1 }} + > + + Local provider meets the task resource requirements. + + + )} + + )} +