import { NumericInput, Tag } from '@blueprintjs/core'; import { parseMemoryMB, parseTimeMS } from '@hydrooj/utils/lib/common'; import type { SubtaskConfig } from 'hydrooj/src/interface'; import { isEqual } from 'lodash'; import React, { useEffect, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import i18n from 'vj/utils/i18n'; import FileSelectAutoComplete from '../autocomplete/components/FileSelectAutoComplete'; import type { RootState } from './reducer/index'; const eq = (a: SubtaskConfig, b: SubtaskConfig) => isEqual(a, b); const eqArr = (a: any[], b: any[]) => isEqual(a, b); export function TestCaseEntry({ index, subindex }) { const testcase = useSelector((state: RootState) => state.config.subtasks[index].cases[subindex], eq); const Files = useSelector((state: RootState) => state.testdata, eqArr); const defaultTime = useSelector((state: RootState) => state.config.subtasks[index].time || state.config.time); const defaultMemory = useSelector((state: RootState) => state.config.subtasks[index].memory || state.config.memory); const dispatch = useDispatch(); const dispatcher = (casesKey: string, valueSuffix = '') => (ev: React.ChangeEvent | number) => { let value = typeof ev !== 'object' ? ev : ev.currentTarget.value; if (value === 0) value = ''; if (valueSuffix && value) value += valueSuffix; dispatch({ type: 'CONFIG_SUBTASK_UPDATE', id: index, key: 'cases-edit', casesId: subindex, casesKey, value, }); if ((casesKey === 'input' && (value as string).endsWith('.in') && !testcase.output) || (casesKey === 'output' && (value as string).endsWith('.out') && !testcase.input)) { const filename = (value as string).substring(0, (value as string).lastIndexOf('.')); if (!testcase.output && (Files.map((f) => f.name).includes(`${filename}.out`) || Files.map((f) => f.name).includes(`${filename}.ans`))) { dispatch({ type: 'CONFIG_SUBTASK_UPDATE', id: index, key: 'cases-edit', casesId: subindex, casesKey: 'output', value: Files.map((f) => f.name).includes(`${filename}.out`) ? `${filename}.out` : `${filename}.ans`, }); } if (!testcase.input && Files.map((f) => f.name).includes(`${filename}.in`)) { dispatch({ type: 'CONFIG_SUBTASK_UPDATE', id: index, key: 'cases-edit', casesId: subindex, casesKey: 'input', value: `${filename}.in`, }); } } }; const refs = { input: useRef(), output: useRef(), }; for (const type of ['input', 'output']) { useEffect(() => { refs[type].current?.setSelectedItems(testcase[type] ? [testcase[type]] : []); }, [testcase[type]]); } if (!testcase || Object.keys(testcase).length === 0) { return ( {i18n('Failed to parse testcase.')} ); } return ( ms} value={testcase.time ? parseTimeMS(testcase.time, false).toString() : ''} placeholder={parseTimeMS(defaultTime || '1000ms', false).toString()} onValueChange={dispatcher('time', 'ms')} buttonPosition="none" fill /> MB} value={testcase.memory ? parseMemoryMB(testcase.memory, false).toString() : ''} placeholder={parseMemoryMB(defaultMemory || '256m', false).toString()} onValueChange={dispatcher('memory', 'MB')} buttonPosition="none" fill /> {['input', 'output'].map((t) => ( ))} dispatch({ type: 'CONFIG_SUBTASK_UPDATE', id: index, key: 'cases-delete', value: subindex, })} > ); } export function CasesTable({ index }) { const len = useSelector((state: RootState) => state.config.subtasks[index].cases?.length); const dispatch = useDispatch(); return ( {len > 0 && [...Array(len).keys()].map((i) => )}
{i18n('Time')} {i18n('Memory')} {i18n('Input')} {i18n('Output')} dispatch({ type: 'CONFIG_SUBTASK_UPDATE', id: index, key: 'cases-add', value: { input: '', output: '' }, })} >
{i18n('Time')} {i18n('Memory')} {i18n('Input')} {i18n('Output')} dispatch({ type: 'CONFIG_SUBTASK_UPDATE', id: index, key: 'cases-add', value: { input: '', output: '' }, })} >
); }