diff --git a/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx b/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx index eac61ff56..5d39dc2a4 100644 --- a/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx +++ b/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx @@ -94,7 +94,7 @@ export function SubtaskNode(props: { subtaskId: number }) {
  • - {subtaskId === -1 + {subtaskId === -1 ? i18n('No testcase here') : i18n('Drag and drop testcases here:')}
    diff --git a/packages/ui-default/components/problemconfig/reducer/config.ts b/packages/ui-default/components/problemconfig/reducer/config.ts index ee7d31e2e..527e6f6bb 100644 --- a/packages/ui-default/components/problemconfig/reducer/config.ts +++ b/packages/ui-default/components/problemconfig/reducer/config.ts @@ -131,9 +131,11 @@ export default function reducer(state = { const subtask = { ...state.subtasks.find((i) => i.id === action.id) }; const subtasks = [...state.subtasks]; subtasks.splice(state.subtasks.findIndex((i) => i.id === action.id), 1, subtask); - subtask.time = action.time; - subtask.memory = action.memory; - subtask.score = +action.score || 0; + if (action.payload.time) subtask.time = action.payload.time; + if (action.payload.memory) subtask.memory = action.payload.memory; + if (action.payload.score) subtask.score = +action.payload.score || 0; + if (action.payload.if) subtask.if = action.payload.if; + if (action.payload.type) subtask.type = action.payload.type; if (!subtask.time) delete subtask.time; if (!subtask.memory) delete subtask.memory; return { ...state, subtasks }; diff --git a/packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx b/packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx index 7ab89ba12..9a58016f9 100644 --- a/packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx +++ b/packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx @@ -4,7 +4,8 @@ import { Icon, InputGroup, Tag, } from '@blueprintjs/core'; import { parseMemoryMB, parseTimeMS } from '@hydrooj/utils/lib/common'; -import React from 'react'; +import { isEqual } from 'lodash'; +import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { i18n } from 'vj/utils'; import { RootState } from '../reducer'; @@ -17,29 +18,43 @@ interface SubtaskSettingsProps { export function SubtaskSettings(props: SubtaskSettingsProps) { const [open, setOpen] = React.useState(false); + const [depsOpen, setDepsOpen] = React.useState(false); const score = useSelector((state: RootState) => state.config.subtasks.find((i) => i.id === props.subtaskId).score); const time = useSelector((state: RootState) => state.config.subtasks.find((i) => i.id === props.subtaskId).time); const memory = useSelector((state: RootState) => state.config.subtasks.find((i) => i.id === props.subtaskId).memory); + const deps = useSelector((state: RootState) => state.config.subtasks.find((i) => i.id === props.subtaskId).if || [], isEqual); + const type = useSelector((state: RootState) => state.config.subtasks.find((i) => i.id === props.subtaskId).type || 'min'); const [ctime, setTime] = React.useState(time); const [cmemory, setMemory] = React.useState(memory); const [cscore, setScore] = React.useState(score); - const dispatcher = (func, key) => (ev: React.ChangeEvent | number) => { - let value = typeof ev !== 'object' ? ev : ev.currentTarget?.value; - if (key === 'score') value = +value; - func(value); - }; + const [cdeps, setDeps] = React.useState(deps.join(', ')); + const [ctype, setType] = React.useState(type); const dispatch = useDispatch(); + useEffect(() => { + dispatch({ + type: 'problemconfig/updateSubtaskConfig', + id: props.subtaskId, + payload: { + type: ctype, + }, + }); + }, [ctype]); + function onConfirm() { dispatch({ type: 'problemconfig/updateSubtaskConfig', id: props.subtaskId, - time: ctime, - memory: cmemory, - score: cscore, + payload: { + time: ctime, + memory: cmemory, + score: cscore, + if: cdeps.split(',').map((i) => i.trim()).filter((i) => +i).map((i) => +i), + }, }); setOpen(false); + setDepsOpen(false); } return (<> @@ -62,7 +77,7 @@ export function SubtaskSettings(props: SubtaskSettingsProps) { /> } - onChange={dispatcher(setScore, 'score')} + onChange={(ev) => setScore(+ev.target.value || 0)} placeholder="Score" type="number" value={cscore.toString()} @@ -71,6 +86,19 @@ export function SubtaskSettings(props: SubtaskSettingsProps) { } /> + setDepsOpen(false)}> + + + } + onChange={(ev) => setDeps(ev.currentTarget.value)} + placeholder={'Dependencies'} + value={cdeps || ''} + /> + + + } /> +
  • setOpen(true)}>
    @@ -85,6 +113,27 @@ export function SubtaskSettings(props: SubtaskSettingsProps) { {score || 0}
  • +
  • setDepsOpen(true)}> +
    + + +    + {i18n('Dependencies')}: {deps.length ? deps.join(', ') : i18n('(None)')} +
    +
  • +
  • +
    + + {i18n('Scoring method')} + + + +
    +
  • ); } diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index 829b1ca22..555b1a633 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -258,6 +258,7 @@ Delete problem solutions: 删除题解 Delete Selected Roles: 删除所选角色 delete: 删除 Delete: 删除 +Dependencies: 依赖 Description: 说明 Destination Domain: 目标域 Development: 开发 @@ -751,6 +752,7 @@ Score: 分数 Scoreboard (Hidden): 成绩表 (隐藏) Scoreboard locked at {0}: 比赛已于 {0} 封榜。 Scoreboard: 成绩表 +Scoring method: 评分方式 Scripts: 脚本 Search: 搜索 Secret (visible to admins): 保密(对管理员可见) diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 0520d8375..c0a523c10 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.48.2", + "version": "4.48.3", "author": "undefined ", "license": "AGPL-3.0", "main": "index.ts",