diff --git a/src/ThreeEditor/components/Dialog/SaveFileDialog.tsx b/src/ThreeEditor/components/Dialog/SaveFileDialog.tsx index e1ed63d08..c0bca7271 100644 --- a/src/ThreeEditor/components/Dialog/SaveFileDialog.tsx +++ b/src/ThreeEditor/components/Dialog/SaveFileDialog.tsx @@ -1,8 +1,9 @@ import { Button, Checkbox, FormControlLabel, TextField } from '@mui/material'; import { ChangeEvent, useCallback, useEffect, useState } from 'react'; -import { FullSimulationData } from '../../../services/ShSimulatorService'; +import { FullSimulationData, JobResults } from '../../../services/ShSimulatorService'; import { StoreContext } from '../../../services/StoreService'; +import { RequestGetJobResults } from '../../../types/RequestTypes'; import { saveString } from '../../../util/File'; import { ConcreteDialogProps, CustomDialog } from './CustomDialog'; @@ -26,21 +27,33 @@ export function SaveFileDialog({ name: defaultName = 'editor', results: providedResults, disableCheckbox = false, - yaptideEditor + yaptideEditor, + getJobResults, + expectedEstimatorsSize }: ConcreteDialogProps< { name?: string; results?: FullSimulationData; disableCheckbox?: boolean; + getJobResults: (...args: RequestGetJobResults) => Promise; + expectedEstimatorsSize?: number; } & Required> >) { const results: FullSimulationData | undefined = providedResults ?? yaptideEditor?.getResults(); + const [controller] = useState(new AbortController()); const [keepResults, setKeepResults] = useState(false); + const [fetchedResults, setFetchedResults] = useState(results); + const jobId = fetchedResults?.jobId; + const shouldFetchEstimators = + jobId && fetchedResults?.estimators.length !== expectedEstimatorsSize; const canKeepResults = useCallback(() => { - return disableCheckbox && results?.input.inputJson?.hash === yaptideEditor?.toJSON().hash; - }, [disableCheckbox, results?.input.inputJson?.hash, yaptideEditor]); + return ( + disableCheckbox && + fetchedResults?.input.inputJson?.hash === yaptideEditor?.toJSON().hash + ); + }, [disableCheckbox, fetchedResults?.input.inputJson?.hash, yaptideEditor]); useEffect(() => { setKeepResults(canKeepResults() || !!providedResults); @@ -58,6 +71,27 @@ export function SaveFileDialog({ setKeepResults(event.target.checked); }; + // Get results from the server if they are not provided + useEffect(() => { + if (shouldFetchEstimators) { + getJobResults({ jobId }, controller.signal, false) + .then(requestResults => { + if (requestResults) { + setFetchedResults( + prevResults => + ({ + ...prevResults, + estimators: requestResults.estimators + }) as FullSimulationData + ); + } + }) + .catch(error => { + console.error('Failed to fetch job results:', error); + }); + } + }, [jobId, controller.signal, getJobResults, shouldFetchEstimators]); + return ( Save diff --git a/src/ThreeEditor/components/Editor/EditorAppBar/EditorAppBar.tsx b/src/ThreeEditor/components/Editor/EditorAppBar/EditorAppBar.tsx index e26eaad46..ac61c76e8 100644 --- a/src/ThreeEditor/components/Editor/EditorAppBar/EditorAppBar.tsx +++ b/src/ThreeEditor/components/Editor/EditorAppBar/EditorAppBar.tsx @@ -12,6 +12,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useDialog } from '../../../../services/DialogService'; import { useLoader } from '../../../../services/LoaderService'; +import { useShSimulation } from '../../../../services/ShSimulatorService'; import { useStore } from '../../../../services/StoreService'; import { YaptideEditor } from '../../../js/YaptideEditor'; import { EditorTitleBar } from './components/EditorTitlebar'; @@ -31,6 +32,7 @@ type AppBarOptions = { function EditorAppBar({ editor }: AppBarProps) { const { loadFromJson, loadFromFiles, loadFromUrl, loadFromJsonString } = useLoader(); + const { getJobResults } = useShSimulation(); const { open: openTheOpenFileDialog } = useDialog('openFile'); const { open: openTheSaveFileDialog } = useDialog('saveFile'); const { open: openTheNewProjectDialog } = useDialog('newProject'); @@ -98,7 +100,8 @@ function EditorAppBar({ editor }: AppBarProps) { label: 'Save as', icon: , disabled: false, - onClick: () => yaptideEditor && openTheSaveFileDialog({ yaptideEditor }) + onClick: () => + yaptideEditor && openTheSaveFileDialog({ yaptideEditor, getJobResults }) }, { label: 'Redo (ctrl+y)', diff --git a/src/WrapperApp/components/InputEditor/InputFilesEditor.tsx b/src/WrapperApp/components/InputEditor/InputFilesEditor.tsx index e9797ff58..ec2666f10 100644 --- a/src/WrapperApp/components/InputEditor/InputFilesEditor.tsx +++ b/src/WrapperApp/components/InputEditor/InputFilesEditor.tsx @@ -41,9 +41,7 @@ export function InputFilesEditor(props: InputFilesEditorProps) { switch (props.simulator) { case SimulatorType.SHIELDHIT: return !(name in _defaultShInputFiles); - // Topas is not supported in current version of yaptide - // case SimulatorType.TOPAS: - // return !(name in _defaultTopasInputFiles); + case SimulatorType.FLUKA: return !(name in _defaultFlukaInputFiles); default: diff --git a/src/WrapperApp/components/Results/EstimatorTab/EstimatorTab.tsx b/src/WrapperApp/components/Results/EstimatorTab/EstimatorTab.tsx new file mode 100644 index 000000000..3643dfa9d --- /dev/null +++ b/src/WrapperApp/components/Results/EstimatorTab/EstimatorTab.tsx @@ -0,0 +1,77 @@ +import { Box, Card, CardContent, CircularProgress } from '@mui/material'; + +import { generateGraphs } from '../../../../JsRoot/GraphData'; +import { FullSimulationData } from '../../../../services/ShSimulatorService'; +import { TabPanel } from '../../Panels/TabPanel'; +import { EstimatorResults } from '../ResultsPanel'; +import TablePage0D from '../ResultsTable'; + +interface EstimatorTabProps { + estimator: EstimatorResults; + tabsValue: number; + resultsGeneratedFromProjectFile: boolean; + groupQuantities: boolean; + simulation: FullSimulationData; +} + +const EstimatorTab = ({ + estimator, + tabsValue, + resultsGeneratedFromProjectFile, + groupQuantities, + simulation +}: EstimatorTabProps) => { + return ( + + theme.palette.mode === 'dark' ? 'text.disabled' : 'background.paper', + '& .MuiCardContent-root div': { + bgcolor: 'transparent', + backgroundImage: 'none', + color: 'black' + } + }}> + {!estimator ? ( + + + + ) : ( + + + + {estimator.tablePages.length > 0 && ( + + )} + {generateGraphs( + estimator, + resultsGeneratedFromProjectFile && groupQuantities, + simulation?.jobId + )} + + + + )} + + ); +}; + +export default EstimatorTab; diff --git a/src/WrapperApp/components/Results/EstimatorsSelect/EstimatorsSelect.tsx b/src/WrapperApp/components/Results/EstimatorsSelect/EstimatorsSelect.tsx new file mode 100644 index 000000000..fcb5b8593 --- /dev/null +++ b/src/WrapperApp/components/Results/EstimatorsSelect/EstimatorsSelect.tsx @@ -0,0 +1,125 @@ +import { Card, CardContent, Tab, Tabs } from '@mui/material'; +import { SyntheticEvent, useCallback, useEffect, useState } from 'react'; + +import { FullSimulationData, useShSimulation } from '../../../../services/ShSimulatorService'; + +interface EstimatorsTabProps { + tabsValue: number; + setTabsValue: (value: number) => void; + simulation: FullSimulationData; + setResultsSimulationData: React.Dispatch>; + estimatorsTabData: string[]; +} + +const EstimatorsSelect = ({ + tabsValue, + setTabsValue, + simulation, + setResultsSimulationData, + estimatorsTabData +}: EstimatorsTabProps) => { + const [controller] = useState(new AbortController()); + + const { getJobResult } = useShSimulation(); + + const handleEstimatorTabChange = useCallback( + async (id: number) => { + const currentEstimatorData = simulation.estimators; + const estimatorExists = + currentEstimatorData[id] && currentEstimatorData[id].name !== ''; + + if (!estimatorExists) { + const simulationJobId = simulation.jobId; + + const estimatorData = await getJobResult( + { + jobId: simulationJobId, + estimatorName: estimatorsTabData[id] + '_' + }, + controller.signal, + true + ); + + const newEstimatorData = estimatorData?.estimators; + + if (newEstimatorData) { + const newEstimators = [...currentEstimatorData]; + + while (newEstimators.length <= id) { + newEstimators.push({ + name: '', + pages: [] + }); + } + + newEstimators[id] = newEstimatorData[0]; + + const newSimulation = { + ...simulation, + estimators: newEstimators + }; + setResultsSimulationData(newSimulation); + } + } + }, + [controller.signal, estimatorsTabData, getJobResult, setResultsSimulationData, simulation] + ); + + useEffect(() => { + handleEstimatorTabChange(0); + }, [handleEstimatorTabChange]); + + const handleChange = (_event: SyntheticEvent, newValue: number) => { + setTabsValue(newValue); + }; + + return ( + + + theme.palette.mode === 'dark' ? 'secondary.contrastText' : 'secondary.dark' + }}> + + theme.palette.mode === 'dark' + ? 'secondary.contrastText' + : 'secondary.dark' + }, + '& .MuiButtonBase-root': { + fontWeight: 'bold' + } + }} + orientation='vertical' + variant='scrollable' + value={tabsValue} + onChange={handleChange}> + {estimatorsTabData.map((estimatorName, id) => { + return ( + handleEstimatorTabChange(id)} + /> + ); + })} + + + + ); +}; + +export default EstimatorsSelect; diff --git a/src/WrapperApp/components/Results/ResultsPanel.tsx b/src/WrapperApp/components/Results/ResultsPanel.tsx index d4a6aaacd..3561d1213 100644 --- a/src/WrapperApp/components/Results/ResultsPanel.tsx +++ b/src/WrapperApp/components/Results/ResultsPanel.tsx @@ -1,23 +1,14 @@ -import { - Box, - Button, - Card, - CardContent, - FormControlLabel, - Switch, - Tab, - Tabs, - Typography -} from '@mui/material'; -import { ChangeEvent, SyntheticEvent, useEffect, useState } from 'react'; - -import { Estimator, generateGraphs, isPage0d, Page, Page0D } from '../../../JsRoot/GraphData'; +import { Box, Button, Card, FormControlLabel, Switch, Typography } from '@mui/material'; +import { ChangeEvent, useEffect, useState } from 'react'; + +import { Estimator, isPage0d, Page, Page0D } from '../../../JsRoot/GraphData'; import { useDialog } from '../../../services/DialogService'; +import { useShSimulation } from '../../../services/ShSimulatorService'; import { useStore } from '../../../services/StoreService'; import { InfoTooltip } from '../../../shared/components/tooltip/InfoTooltip'; import { titleToKebabCase } from '../../../ThreeEditor/components/Dialog/CustomDialog'; -import { TabPanel } from '../Panels/TabPanel'; -import TablePage0D from './ResultsTable'; +import EstimatorsSelect from './EstimatorsSelect/EstimatorsSelect'; +import EstimatorTab from './EstimatorTab/EstimatorTab'; export interface EstimatorResults extends Estimator { tablePages: Page0D[]; @@ -25,29 +16,52 @@ export interface EstimatorResults extends Estimator { } function ResultsPanel() { + const { getJobResults } = useShSimulation(); const { open: openSaveFileDialog } = useDialog('saveFile'); - const { yaptideEditor, resultsSimulationData: simulation } = useStore(); + const { + yaptideEditor, + resultsSimulationData: simulation, + setResultsSimulationData + } = useStore(); const [tabsValue, setTabsValue] = useState(0); const [estimatorsResults, setEstimatorsResults] = useState([]); const [groupQuantities, setGroupQuantities] = useState(false); + const userTabInputFilesEstimatorNames = simulation?.input.userInputFilesEstimatorNames?.map( + output => output.slice(0, -1) + ); + const uploadedInputFilesEstimatorNames = estimatorsResults?.map(estimator => estimator.name); + + const editorEstimatorNames = simulation?.input.inputJson?.scoringManager.outputs + .filter(output => output.name) + .map(output => output.name); + + const estimatorsTabData: string[] | undefined = simulation?.input.userInputFilesEstimatorNames + ? userTabInputFilesEstimatorNames + : editorEstimatorNames; + useEffect(() => { - setTabsValue(0); setEstimatorsResults(parseEstimators(simulation?.estimators ?? [])); - }, [simulation]); - const handleChange = (_event: SyntheticEvent, newValue: number) => { - setTabsValue(newValue); - }; + if (simulation?.estimators.length === 1) { + setTabsValue(0); + } + }, [simulation]); const onClickSaveToFile = () => { + const expectedEstimators = estimatorsTabData + ? estimatorsTabData + : uploadedInputFilesEstimatorNames; + if (yaptideEditor) openSaveFileDialog({ name: `${titleToKebabCase(simulation?.title ?? 'simulation')}-result.json`, results: simulation, disableCheckbox: true, - yaptideEditor + yaptideEditor, + getJobResults, + expectedEstimatorsSize: expectedEstimators.length }); }; @@ -64,6 +78,7 @@ function ResultsPanel() { }; const resultsGeneratedFromProjectFile = !!simulation?.input.inputJson; + const chosenEstimator = estimatorsResults[tabsValue]; return ( - {estimatorsResults.length > 0 && ( + {estimatorsResults.length > 0 && simulation && ( <> - - - theme.palette.mode === 'dark' - ? 'secondary.contrastText' - : 'secondary.dark' - }}> - - theme.palette.mode === 'dark' - ? 'secondary.contrastText' - : 'secondary.dark' - }, - '& .MuiButtonBase-root': { - fontWeight: 'bold' - } - }} - orientation='vertical' - variant='scrollable' - value={tabsValue} - onChange={handleChange}> - {estimatorsResults.map((estimator, idx) => { - return ( - - ); - })} - - - - - theme.palette.mode === 'dark' - ? 'text.disabled' - : 'background.paper', - '& .MuiCardContent-root div': { - bgcolor: 'transparent', - backgroundImage: 'none', - color: 'black' - } - }}> - - {estimatorsResults.map((estimator, idx) => { - return ( - - - {estimator.tablePages.length > 0 && ( - - )} - {generateGraphs( - estimator, - resultsGeneratedFromProjectFile && - groupQuantities, - simulation?.jobId - )} - - - ); - })} - - + + )} diff --git a/src/WrapperApp/components/Simulation/SimulationCard/SimulationCardHelpers.ts b/src/WrapperApp/components/Simulation/SimulationCard/SimulationCardHelpers.ts index ab5d7faed..0208063d0 100644 --- a/src/WrapperApp/components/Simulation/SimulationCard/SimulationCardHelpers.ts +++ b/src/WrapperApp/components/Simulation/SimulationCard/SimulationCardHelpers.ts @@ -23,7 +23,7 @@ const SimulationCardHelpers = ({ yaptideEditor }: SimulationCardHelpersProps) => { const { loadFromJson } = useLoader(); - const { getJobLogs, getJobInputs, getFullSimulationData } = useShSimulation(); + const { getJobLogs, getJobInputs, getFullSimulationData, getJobResults } = useShSimulation(); const { enqueueSnackbar } = useSnackbar(); const { open: openSaveFileDialog } = useDialog('saveFile'); @@ -90,7 +90,8 @@ const SimulationCardHelpers = ({ name: `${titleToKebabCase(simulation?.title ?? 'simulation')}-result.json`, results: simulation, disableCheckbox: true, - yaptideEditor + yaptideEditor, + getJobResults }); }) .catch(() => { diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index 868d3fb65..6377ce409 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -10,6 +10,7 @@ import { RequestCancelJob, RequestGetJobInputs, RequestGetJobLogs, + RequestGetJobResult, RequestGetJobResults, RequestGetJobStatus, RequestGetPageContents, @@ -21,12 +22,14 @@ import { import { currentJobStatusData, currentTaskStatusData, + EstimatorNamesResponse, JobStatusCompleted, JobStatusData, JobStatusFailed, PlatformType, ResponseGetJobInputs, ResponseGetJobLogs, + ResponseGetJobResult, ResponseGetJobResults, ResponseGetJobStatus, ResponseGetPageContents, @@ -56,6 +59,12 @@ export type JobResults = { jobId: string; } & ResponseGetJobResults; +export type SpecificEstimator = { + jobId: string; + estimators: Estimator[]; + message: string; +}; + export type FullSimulationData = Omit; export const fetchItSymbol = Symbol('fetchItSymbol'); @@ -69,13 +78,15 @@ export interface RestSimulationContext { getJobStatus: (...args: RequestGetJobStatus) => Promise; getJobInputs: (...args: RequestGetJobInputs) => Promise; getJobResults: (...args: RequestGetJobResults) => Promise; + getJobResult: (...args: RequestGetJobResult) => Promise; getJobLogs: (...args: RequestGetJobLogs) => Promise; getPageContents: (...args: RequestGetPageContents) => Promise; getPageStatus: (...args: RequestGetPageStatus) => Promise; getFullSimulationData: ( jobStatus: JobStatusData, signal?: AbortSignal, - cache?: boolean + cache?: boolean, + givenEstimatorName?: string ) => Promise; } @@ -330,6 +341,94 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { [authKy, getJobInputs, resultsCache] ); + const getJobResult = useCallback( + async (...[info, signal, cache = true, beforeCacheWrite]: RequestGetJobResult) => { + const { jobId, estimatorName } = info; + + if (cache && resultsCache.has(jobId)) { + const data: Promise | JobResults | undefined = resultsCache.get(jobId); + + if (data instanceof Promise) { + return data.then(resolvedData => { + const estimators = resolvedData.estimators; + const estimatorExists = estimators.some( + estimator => estimator.name === estimatorName + ); + + if (estimatorExists) return Promise.resolve(resolvedData); + }); + } else if (data) { + const estimators = data.estimators; + const estimatorExists = estimators.some( + estimator => estimator.name === estimatorName + ); + + if (estimatorExists) return Promise.resolve(data); + } + } + + const cachePromise = resultsCache.createPromise( + async resolve => { + const response = await authKy + .get('results', { + signal, + searchParams: camelToSnakeCase({ + job_id: jobId, + estimator_name: estimatorName + }) + }) + .json(); + + const estimator: Estimator[] = [ + { + name: response.name, + metadata: response.metadata, + pages: response.pages + } + ]; + + updateEstimators(estimator); + + const jobInputs = await getJobInputs(info, signal, cache); + + const refsInResults = + jobInputs?.input.inputJson && + recreateRefsInResults(jobInputs.input.inputJson, estimator); + + const data: SpecificEstimator = { + jobId, + estimators: refsInResults ?? estimator, + message: response.message + }; + + resolve(data); + }, + jobId, + beforeCacheWrite + ); + + return await cachePromise; + }, + [authKy, getJobInputs, resultsCache] + ); + + const getCurrentEstimators = useCallback( + async (job_id: string) => { + try { + return await authKy + .get('estimators', { + searchParams: { job_id } + }) + .json(); + } catch (error) { + console.error('Failed to fetch estimators:', error); + + return undefined; + } + }, + [authKy] + ); + //TODO: fix backend responses and remove this function const validStatusToCache = (data: JobStatusCompleted | JobStatusFailed) => { if (data.jobState === StatusState.FAILED) return true; @@ -447,12 +546,77 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { [getJobStatus] ); + // This function is used to find the first estimator name in the simulation data to fetch the results for estimators. + // If name isn't passed, it will try to find the first estimator name in the simulation data. + // If the name isn't found, it will try to get name from the backend. + // It wouldn't be handled if we load the example. + const findFirstEstimatorNameForInputFiles = useCallback( + async ( + jobStatus: JobStatusData, + inputs: JobInputs | undefined, + givenEstimatorName?: string + ) => { + if (!givenEstimatorName && jobStatus.jobState === StatusState.COMPLETED) { + if (inputs && !inputs.input.userInputFilesEstimatorNames) { + const estimators = await getCurrentEstimators(jobStatus.jobId); + + inputs.input.userInputFilesEstimatorNames = estimators?.estimatorNames; + } + } + + const firstEstimatorInputFileName = inputs?.input.userInputFilesEstimatorNames?.[0]; + + if (givenEstimatorName) { + return givenEstimatorName; + } + + if (firstEstimatorInputFileName) { + return firstEstimatorInputFileName; + } + }, + [getCurrentEstimators] + ); + + const findFirstEstimatorNameForEditor = useCallback( + (inputs: JobInputs | undefined, givenEstimatorName?: string) => { + const firstEstimatorName = inputs?.input.inputJson?.scoringManager.outputs[0].name; + + if (givenEstimatorName) { + return givenEstimatorName; + } + + if (firstEstimatorName) { + return firstEstimatorName + '_'; + } + }, + [] + ); + const getFullSimulationData = useCallback( - async (jobStatus: JobStatusData, signal?: AbortSignal, cache = true) => { + async ( + jobStatus: JobStatusData, + signal?: AbortSignal, + cache = true, + givenEstimatorName?: string + ) => { const inputs: JobInputs | undefined = await getJobInputs(jobStatus, signal, cache); + + const isSimulationFromEditor = inputs?.input.inputType.toLowerCase() === 'editor'; + + const firstEstimator = isSimulationFromEditor + ? findFirstEstimatorNameForEditor(inputs, givenEstimatorName) + : await findFirstEstimatorNameForInputFiles(jobStatus, inputs, givenEstimatorName); + const results: JobResults | undefined = - jobStatus.jobState === StatusState.COMPLETED - ? await getJobResults(jobStatus, signal, cache) + jobStatus.jobState === StatusState.COMPLETED && firstEstimator + ? await getJobResult( + { + jobId: jobStatus.jobId, + estimatorName: firstEstimator + }, + signal, + cache + ) : undefined; if (!inputs || !results) return undefined; @@ -469,7 +633,12 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { return simData; }, - [getJobInputs, getJobResults] + [ + findFirstEstimatorNameForEditor, + findFirstEstimatorNameForInputFiles, + getJobInputs, + getJobResult + ] ); return ( @@ -487,6 +656,7 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { getPageStatus, getJobInputs, getJobResults, + getJobResult, getJobLogs, getFullSimulationData }}> diff --git a/src/types/RequestTypes.ts b/src/types/RequestTypes.ts index 05b985d15..a1273555b 100644 --- a/src/types/RequestTypes.ts +++ b/src/types/RequestTypes.ts @@ -100,4 +100,8 @@ export type RequestGetJobResults = Flatten< [[{ jobId: string }], RequestParam, CachedDataParams] >; +export type RequestGetJobResult = Flatten< + [[{ jobId: string; estimatorName: string }], RequestParam, CachedDataParams] +>; + /* ------------------------------------ */ diff --git a/src/types/ResponseTypes.ts b/src/types/ResponseTypes.ts index bcca956d1..614239d49 100644 --- a/src/types/ResponseTypes.ts +++ b/src/types/ResponseTypes.ts @@ -1,5 +1,6 @@ -import { Estimator } from '../JsRoot/GraphData'; +import { Estimator, Page } from '../JsRoot/GraphData'; import { EditorJson } from '../ThreeEditor/js/EditorJson'; +import { ScoringOutputJSON } from '../ThreeEditor/Simulation/Scoring/ScoringOutput'; import { SimulationSourceType } from '../WrapperApp/components/Simulation/RunSimulationForm'; import { DataWithStatus, LookUp, TypeIdentifiedByKey } from './TypeTransformUtil'; @@ -60,7 +61,10 @@ export type InputFilesRecord; -type ShInputFilesRecord = InputFilesRecord; +export type ShInputFilesRecord = InputFilesRecord< + ShInputFilesNames, + 'info.json' | 'sobp.dat' | 'detect.dat' +>; type TopasInputFilesRecord = InputFilesRecord; type FlukaInputFilesRecord = InputFilesRecord; export type SimulationInputFiles = @@ -74,7 +78,7 @@ export type TaskTime = { seconds: string; }; -export type MetaKey = 'server' | 'platform' | 'input' | 'simType'; +export type MetaKey = 'server' | 'platform' | 'inputType' | 'simType'; export type PlatformType = 'DIRECT' | 'BATCH'; @@ -330,9 +334,15 @@ export type ResponseGetJobInputs = { inputFiles: SimulationInputFiles; inputJson?: EditorJson; inputType: SimulationSourceType; + userInputFilesEstimatorNames?: string[]; }; } & YaptideResponse; +export type EstimatorNamesResponse = { + estimatorNames: string[]; + message: string; +}; + export type ResponseGetJobLogs = { logfiles: Record; } & YaptideResponse; @@ -341,6 +351,8 @@ export type ResponseGetJobResults = { estimators: Estimator[]; } & YaptideResponse; +export type ResponseGetJobResult = Estimator & YaptideResponse; + export type ResponseAuthStatus = AuthStatus; export type ResponseAuthRefresh = AuthData; diff --git a/src/util/Sort.ts b/src/util/Sort.ts index 98f96c375..fcf283afd 100644 --- a/src/util/Sort.ts +++ b/src/util/Sort.ts @@ -14,8 +14,6 @@ export const orderAccordingToList =