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) {
} />
+
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",