diff --git a/packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx b/packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx index 934e7b074..da1bc8dea 100644 --- a/packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx +++ b/packages/ui-default/components/problemconfig/ProblemConfigEditor.tsx @@ -162,8 +162,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e width: '100%', }} className="ConfigMonacoEditor" - > - + /> ); } }); diff --git a/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx b/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx index f83547190..eac61ff56 100644 --- a/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx +++ b/packages/ui-default/components/problemconfig/ProblemConfigTree.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { DndProvider, useDrop } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import { useDispatch, useSelector, useStore } from 'react-redux'; +import { i18n } from 'vj/utils'; import { RootState } from './reducer'; import { AddTestcase } from './tree/AddTestcase'; import { SelectionManager } from './tree/SelectionManager'; @@ -63,13 +64,13 @@ export function SubtaskNode(props: { subtaskId: number }) {
  • {subtaskId !== -1 &&
    setExpand((e) => !e)}>   - Subtask {subtaskId} + {i18n('Subtask {0}', subtaskId)} ev.stopPropagation()}> - Are you sure you want to delete this subtask? + {i18n('Are you sure you want to delete this subtask?')}
    - +
    } > @@ -94,8 +95,8 @@ export function SubtaskNode(props: { subtaskId: number }) {
    {subtaskId === -1 - ? 'No testcase here' - : 'Drag and drop testcases here:'} + ? i18n('No testcase here') + : i18n('Drag and drop testcases here:')}
  • )} @@ -119,13 +120,10 @@ export function SubtaskConfigTree() { return (
    diff --git a/packages/ui-default/components/problemconfig/index.tsx b/packages/ui-default/components/problemconfig/index.tsx index 1bff20346..d3124f222 100644 --- a/packages/ui-default/components/problemconfig/index.tsx +++ b/packages/ui-default/components/problemconfig/index.tsx @@ -1,4 +1,6 @@ -import { Tab, Tabs } from '@blueprintjs/core'; +import { + Button, Dialog, DialogBody, DialogFooter, Tab, Tabs, +} from '@blueprintjs/core'; import React from 'react'; import { useSelector } from 'react-redux'; import { i18n } from 'vj/utils'; @@ -13,14 +15,12 @@ interface Props { export default function ProblemConfig(props: Props) { const [selected, setSelected] = React.useState('basic'); + const [open, setOpen] = React.useState(false); const valid = useSelector((state: RootState) => state.config.__valid); const errors = useSelector((state: RootState) => state.config.__errors, (a, b) => JSON.stringify(a) === JSON.stringify(b)); - - function save() { - // eslint-disable-next-line - if (!valid && !confirm('Errors detected in the config. Still save?')) return; - props.onSave(); - } + React.useEffect(() => { + if (valid) setOpen(false); + }, [valid]); return (<>
    @@ -29,13 +29,22 @@ export default function ProblemConfig(props: Props) {
    (t !== 'errors' && setSelected(t.toString()))} selectedTabId={valid ? selected : 'errors'}> - } /> - } /> + } /> + } /> {errors.map((i) => (
    {i}
    ))}
    } />
    - + setOpen(false)}> + +

    {i18n('Errors detected in the config. Confirm save?')}

    +
    + + + + } /> +
    + ); } diff --git a/packages/ui-default/components/problemconfig/reducer/config.ts b/packages/ui-default/components/problemconfig/reducer/config.ts index bff419ca7..65addaf51 100644 --- a/packages/ui-default/components/problemconfig/reducer/config.ts +++ b/packages/ui-default/components/problemconfig/reducer/config.ts @@ -72,8 +72,6 @@ export default function reducer(state = { } } else if (action.key === 'add') { subtasks.push({ - time: state.time || '1s', - memory: state.memory || '256m', cases: [], score: 0, id: Object.keys(subtasks).map((i) => subtasks[i].id).reduce((a, b) => Math.max(+a, +b), 0) + 1, diff --git a/packages/ui-default/components/problemconfig/tree/AddTestcase.tsx b/packages/ui-default/components/problemconfig/tree/AddTestcase.tsx index 6b9bb3dec..abfbea4b9 100644 --- a/packages/ui-default/components/problemconfig/tree/AddTestcase.tsx +++ b/packages/ui-default/components/problemconfig/tree/AddTestcase.tsx @@ -4,6 +4,7 @@ import { import { readSubtasksFromFiles } from '@hydrooj/utils/lib/common'; import React, { useEffect, useRef } from 'react'; import { useSelector, useStore } from 'react-redux'; +import { i18n } from 'vj/utils'; import FileSelectAutoComplete from '../../autocomplete/components/FileSelectAutoComplete'; import { RootState } from '../reducer'; @@ -72,7 +73,7 @@ export function AddTestcase() { >
      - Auto detect + {i18n('Auto detect')}
  •   - Add testcase + {i18n('Add testcase')}
  • setOpen(false)}> @@ -98,7 +99,7 @@ export function AddTestcase() { label="Input" width="100%" onChange={(e) => setInput(e)} - placeholder="Input" + placeholder={i18n('Input')} value={input || ''} /> @@ -109,20 +110,21 @@ export function AddTestcase() { label="Output" width="100%" onChange={(e) => setOutput(e)} - placeholder="Output" + placeholder={i18n('Output')} value={input || ''} /> - } /> + />} + /> ); } diff --git a/packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx b/packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx index c178ded2e..8177d2df8 100644 --- a/packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx +++ b/packages/ui-default/components/problemconfig/tree/SubtaskSettings.tsx @@ -5,6 +5,7 @@ import { } from '@blueprintjs/core'; import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; +import { i18n } from 'vj/utils'; import { RootState } from '../reducer'; interface SubtaskSettingsProps { @@ -41,7 +42,7 @@ export function SubtaskSettings(props: SubtaskSettingsProps) { } return (<> - setOpen(false)}> + setOpen(false)}>    - {time || props.time || '1s'} + {time || props.time || '1s'}    - {memory || props.memory || '256m'} + {memory || props.memory || '256m'} {' '} {score || 0} @@ -106,7 +107,7 @@ export function GlobalSettings() { setOpen(false); } return (<> - setOpen(false)}> + setOpen(false)}>    - {time || '1s'} + {time || '1s'} {' '} - {memory || '256m'} + {memory || '256m'} ); diff --git a/packages/ui-default/components/problemconfig/tree/Testcase.tsx b/packages/ui-default/components/problemconfig/tree/Testcase.tsx index f80c9eff3..26e193264 100644 --- a/packages/ui-default/components/problemconfig/tree/Testcase.tsx +++ b/packages/ui-default/components/problemconfig/tree/Testcase.tsx @@ -4,6 +4,7 @@ import { TestCaseConfig } from 'hydrooj'; import { omit } from 'lodash'; import React from 'react'; import { useDrag } from 'react-dnd'; +import { i18n } from 'vj/utils'; interface TestcaseNodeProps { c: TestCaseConfig; @@ -28,12 +29,12 @@ export function TestcaseNode(props: TestcaseNodeProps) { data-selected={selected} content={ - + {subtaskIds.filter((i) => i !== subtaskId).map((i) => ( - + ))} {subtaskIds.length <= 1 && ( - + )} diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index 081a67e72..829b1ca22 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -26,6 +26,7 @@ __langname: 简体中文 'Copy failed :(': '复制失败 :(' 'Current dataset: {0}': '当前测试数据: {0}' 'Discussion: Terms Of Service': 讨论区服务条款 +'Drag and drop testcases here:': '拖拽测试点到此处:' 'Failed to get credential: {0}': '获取认证数据失败: {0}' 'File upload failed: {0}': 文件上传失败:{0} 'Format: category 1, category 2, ..., category n': 格式:分类1, 分类2, ..., 分类n @@ -69,6 +70,8 @@ Add Authenticator: 添加认证器 Add File: 添加文件 Add module: 添加模块 Add new data: 添加新数据 +Add new subtask: 添加新子任务 +Add testcase: 添加测试点 Add User: 添加用户 Add: 添加 additional_file: 附加文件 @@ -88,6 +91,7 @@ An example of dataset: 测试数据集的一个例子 Any user is allowed to join this domain with an invitation code: 任意用户都可以通过邀请码加入此域 Any user is allowed to join this domain: 任意用户都可以加入此域 API: API +Are you sure you want to delete this subtask?: 确认删除此子任务? Argument {0} is invalid.: 非法的参数 {0} 。 Arguments: 参数 Assign User or Group: 分配给用户或小组 @@ -101,9 +105,12 @@ Attendee Manage: 参赛者管理 Authenticator: 认证器 Authenticators: 认证器 author: 作者 +Auto configure: 自动配置 +Auto detect: 自动检测 Auto hide problems during the contest: 在比赛过程中自动隐藏题目 Auto Read Tasks: 自动识别任务 Basic Info: 基础信息 +Basic: 基础 Be Copied: 被复制 Begin at: 开始于 Begin Date: 开始日期 @@ -340,6 +347,7 @@ Enroll Training: 参加训练 Enrolled: 已参加 Enrollees: 参加人数 error: 错误 +Errors detected in the config. Confirm save?: 配置中存在错误。确认保存? Evaluated difficulty: 估计的难度 Exit: 退出 expand: 展开 @@ -519,6 +527,7 @@ Month: 月 Monthly Popular: 月度最受欢迎 More: 更多 Most Upvoted Solutions: 最被赞同的题解 +Move to subtask: 移动到子任务 Multi Platform Authenticator: 跨平台认证器 My Domains: 我的域 My Files: 我的文件 @@ -549,6 +558,8 @@ No Permission to Submit: 您没有权限递交 No problem.: 没有题目。 No solutions so far...: 目前还没有题解... No Submissions: 没有递交 +No target available: 无可用目标 +No testcase here: 此处没有测试点 No user is allowed to join this domain: 没有用户可以自助加入此域 no_translation_warn: '' None: 无 @@ -764,6 +775,7 @@ Set Privilege: 设置权限 Set Role: 设置角色 Set Roles for Selected User: 设置所选用户的角色 Set Roles for selected users: 为所选用户设置角色 +Set time and memory limits: 设置时空限制 setting_customize: 个性化 setting_display: 显示偏好 setting_domain: 域设置 @@ -813,6 +825,8 @@ Submit to Judge: 递交以评测 Submit Your Code: 递交代码进行正式评测 Submit: 递交 Submitted: 已递交 +Subtask {0}: 子任务 {0} +Subtasks: 子任务 SuperUser: 超级管理员 Support: 支持 Switch account: 切换账户