mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
ui: problemconfig: add subtask if and type
This commit is contained in:
5 files changed
+68
-15
No files matched your search
@@ -94,7 +94,7 @@ export function SubtaskNode(props: { subtaskId: number }) {
|
|||||||
<li className="bp4-tree-node">
|
<li className="bp4-tree-node">
|
||||||
<div className="bp4-tree-node-content">
|
<div className="bp4-tree-node-content">
|
||||||
<span className="bp4-tree-node-caret-none bp4-icon-standard"></span>
|
<span className="bp4-tree-node-caret-none bp4-icon-standard"></span>
|
||||||
<span className="bp4-tree-node-label">{subtaskId === -1
|
<span className="bp4-tree-node-label text-gray">{subtaskId === -1
|
||||||
? i18n('No testcase here')
|
? i18n('No testcase here')
|
||||||
: i18n('Drag and drop testcases here:')}</span>
|
: i18n('Drag and drop testcases here:')}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -131,9 +131,11 @@ export default function reducer(state = {
|
|||||||
const subtask = { ...state.subtasks.find((i) => i.id === action.id) };
|
const subtask = { ...state.subtasks.find((i) => i.id === action.id) };
|
||||||
const subtasks = [...state.subtasks];
|
const subtasks = [...state.subtasks];
|
||||||
subtasks.splice(state.subtasks.findIndex((i) => i.id === action.id), 1, subtask);
|
subtasks.splice(state.subtasks.findIndex((i) => i.id === action.id), 1, subtask);
|
||||||
subtask.time = action.time;
|
if (action.payload.time) subtask.time = action.payload.time;
|
||||||
subtask.memory = action.memory;
|
if (action.payload.memory) subtask.memory = action.payload.memory;
|
||||||
subtask.score = +action.score || 0;
|
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.time) delete subtask.time;
|
||||||
if (!subtask.memory) delete subtask.memory;
|
if (!subtask.memory) delete subtask.memory;
|
||||||
return { ...state, subtasks };
|
return { ...state, subtasks };
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import {
|
|||||||
Icon, InputGroup, Tag,
|
Icon, InputGroup, Tag,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { parseMemoryMB, parseTimeMS } from '@hydrooj/utils/lib/common';
|
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 { useDispatch, useSelector } from 'react-redux';
|
||||||
import { i18n } from 'vj/utils';
|
import { i18n } from 'vj/utils';
|
||||||
import { RootState } from '../reducer';
|
import { RootState } from '../reducer';
|
||||||
@@ -17,29 +18,43 @@ interface SubtaskSettingsProps {
|
|||||||
|
|
||||||
export function SubtaskSettings(props: SubtaskSettingsProps) {
|
export function SubtaskSettings(props: SubtaskSettingsProps) {
|
||||||
const [open, setOpen] = React.useState(false);
|
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 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 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 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 [ctime, setTime] = React.useState(time);
|
||||||
const [cmemory, setMemory] = React.useState(memory);
|
const [cmemory, setMemory] = React.useState(memory);
|
||||||
const [cscore, setScore] = React.useState(score);
|
const [cscore, setScore] = React.useState(score);
|
||||||
const dispatcher = (func, key) => (ev: React.ChangeEvent<HTMLInputElement | HTMLSelectElement> | number) => {
|
const [cdeps, setDeps] = React.useState(deps.join(', '));
|
||||||
let value = typeof ev !== 'object' ? ev : ev.currentTarget?.value;
|
const [ctype, setType] = React.useState(type);
|
||||||
if (key === 'score') value = +value;
|
|
||||||
func(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch({
|
||||||
|
type: 'problemconfig/updateSubtaskConfig',
|
||||||
|
id: props.subtaskId,
|
||||||
|
payload: {
|
||||||
|
type: ctype,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, [ctype]);
|
||||||
|
|
||||||
function onConfirm() {
|
function onConfirm() {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'problemconfig/updateSubtaskConfig',
|
type: 'problemconfig/updateSubtaskConfig',
|
||||||
id: props.subtaskId,
|
id: props.subtaskId,
|
||||||
time: ctime,
|
payload: {
|
||||||
memory: cmemory,
|
time: ctime,
|
||||||
score: cscore,
|
memory: cmemory,
|
||||||
|
score: cscore,
|
||||||
|
if: cdeps.split(',').map((i) => i.trim()).filter((i) => +i).map((i) => +i),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
setDepsOpen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
@@ -62,7 +77,7 @@ export function SubtaskSettings(props: SubtaskSettingsProps) {
|
|||||||
/>
|
/>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
leftElement={<Icon icon="star" />}
|
leftElement={<Icon icon="star" />}
|
||||||
onChange={dispatcher(setScore, 'score')}
|
onChange={(ev) => setScore(+ev.target.value || 0)}
|
||||||
placeholder="Score"
|
placeholder="Score"
|
||||||
type="number"
|
type="number"
|
||||||
value={cscore.toString()}
|
value={cscore.toString()}
|
||||||
@@ -71,6 +86,19 @@ export function SubtaskSettings(props: SubtaskSettingsProps) {
|
|||||||
</DialogBody>
|
</DialogBody>
|
||||||
<DialogFooter actions={<Button className="primary rounded button" onClick={onConfirm} intent="primary" text="Save" />} />
|
<DialogFooter actions={<Button className="primary rounded button" onClick={onConfirm} intent="primary" text="Save" />} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
<Dialog title={i18n('Set dependencies')} icon="cog" isOpen={depsOpen} onClose={() => setDepsOpen(false)}>
|
||||||
|
<DialogBody>
|
||||||
|
<ControlGroup fill={true} vertical={false}>
|
||||||
|
<InputGroup
|
||||||
|
leftElement={<Icon icon="diagram-tree" />}
|
||||||
|
onChange={(ev) => setDeps(ev.currentTarget.value)}
|
||||||
|
placeholder={'Dependencies'}
|
||||||
|
value={cdeps || ''}
|
||||||
|
/>
|
||||||
|
</ControlGroup>
|
||||||
|
</DialogBody>
|
||||||
|
<DialogFooter actions={<Button className="primary rounded button" onClick={onConfirm} intent="primary" text="Save" />} />
|
||||||
|
</Dialog>
|
||||||
<li className="bp4-tree-node" onClick={() => setOpen(true)}>
|
<li className="bp4-tree-node" onClick={() => setOpen(true)}>
|
||||||
<div className="bp4-tree-node-content">
|
<div className="bp4-tree-node-content">
|
||||||
<span className="bp4-tree-node-caret-none bp4-icon-standard"></span>
|
<span className="bp4-tree-node-caret-none bp4-icon-standard"></span>
|
||||||
@@ -85,6 +113,27 @@ export function SubtaskSettings(props: SubtaskSettingsProps) {
|
|||||||
<span className="bp4-tree-node-secondary-label">{score || 0}</span>
|
<span className="bp4-tree-node-secondary-label">{score || 0}</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li className="bp4-tree-node" onClick={() => setDepsOpen(true)}>
|
||||||
|
<div className="bp4-tree-node-content">
|
||||||
|
<span className="bp4-tree-node-caret-none bp4-icon-standard"></span>
|
||||||
|
<Icon icon="diagram-tree" />
|
||||||
|
|
||||||
|
<span className="bp4-tree-node-label">{i18n('Dependencies')}: {deps.length ? deps.join(', ') : i18n('(None)')}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li className="bp4-tree-node">
|
||||||
|
<div className="bp4-tree-node-content">
|
||||||
|
<span className="bp4-tree-node-caret-none bp4-icon-standard"></span>
|
||||||
|
<span className="bp4-tree-node-label">{i18n('Scoring method')}</span>
|
||||||
|
<span className="bp4-tree-node-secondary-label">
|
||||||
|
<select value={ctype} onChange={(e) => setType(e.target.value)}>
|
||||||
|
<option value="min">Min</option>
|
||||||
|
<option value="max">Max</option>
|
||||||
|
<option value="sum">Sum</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
</>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -258,6 +258,7 @@ Delete problem solutions: 删除题解
|
|||||||
Delete Selected Roles: 删除所选角色
|
Delete Selected Roles: 删除所选角色
|
||||||
delete: 删除
|
delete: 删除
|
||||||
Delete: 删除
|
Delete: 删除
|
||||||
|
Dependencies: 依赖
|
||||||
Description: 说明
|
Description: 说明
|
||||||
Destination Domain: 目标域
|
Destination Domain: 目标域
|
||||||
Development: 开发
|
Development: 开发
|
||||||
@@ -751,6 +752,7 @@ Score: 分数
|
|||||||
Scoreboard (Hidden): 成绩表 (隐藏)
|
Scoreboard (Hidden): 成绩表 (隐藏)
|
||||||
Scoreboard locked at {0}: 比赛已于 {0} 封榜。
|
Scoreboard locked at {0}: 比赛已于 {0} 封榜。
|
||||||
Scoreboard: 成绩表
|
Scoreboard: 成绩表
|
||||||
|
Scoring method: 评分方式
|
||||||
Scripts: 脚本
|
Scripts: 脚本
|
||||||
Search: 搜索
|
Search: 搜索
|
||||||
Secret (visible to admins): 保密(对管理员可见)
|
Secret (visible to admins): 保密(对管理员可见)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/ui-default",
|
"name": "@hydrooj/ui-default",
|
||||||
"version": "4.48.2",
|
"version": "4.48.3",
|
||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
|
|||||||
Reference in new issue
Block a user