ui: problemconfig: add i18n

This commit is contained in:
undefined committed 2023-03-16 08:48:27 +08:00
1 parent b6abb11e72
commit d4047c6b78
8 files changed
+63 -41

No files matched your search

@@ -162,8 +162,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e
width: '100%',
}}
className="ConfigMonacoEditor"
>
</div>
/>
);
}
});
@@ -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 }) {
<li className="bp4-tree-node bp4-tree-node-expanded">
{subtaskId !== -1 && <div className="bp4-tree-node-content" onClick={() => setExpand((e) => !e)}>
<Icon icon={expand ? 'folder-open' : 'folder-close'} />&nbsp;
<span className="bp4-tree-node-label">Subtask {subtaskId}</span>
<span className="bp4-tree-node-label">{i18n('Subtask {0}', subtaskId)}</span>
<span className="bp4-tree-node-secondary-label" onClick={(ev) => ev.stopPropagation()}>
<Popover2
content={<div style={{ padding: 20 }}>
<b>Are you sure you want to delete this subtask?</b>
<b>{i18n('Are you sure you want to delete this subtask?')}</b>
<div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 15 }}>
<Button intent="danger" onClick={deleteSubtask}>Delete</Button>
<Button intent="danger" onClick={deleteSubtask}>{i18n('Delete')}</Button>
</div>
</div>}
>
@@ -94,8 +95,8 @@ export function SubtaskNode(props: { subtaskId: number }) {
<div className="bp4-tree-node-content">
<span className="bp4-tree-node-caret-none bp4-icon-standard"></span>
<span className="bp4-tree-node-label">{subtaskId === -1
? 'No testcase here'
: 'Drag and drop testcases here:'}</span>
? i18n('No testcase here')
: i18n('Drag and drop testcases here:')}</span>
</div>
</li>
)}
@@ -119,13 +120,10 @@ export function SubtaskConfigTree() {
return (
<div className="bp4-tree">
<ul className="bp4-tree-node-list bp4-tree-root">
<li
className="bp4-tree-node"
onClick={autoConfigure}
>
<li className="bp4-tree-node" onClick={autoConfigure}>
<div className="bp4-tree-node-content bp4-tree-node-content-0">
<Icon icon="clean" />&nbsp;
<span className="bp4-tree-node-label">Auto Configure</span>
<span className="bp4-tree-node-label">{i18n('Auto configure')}</span>
</div>
</li>
<GlobalSettings />
@@ -136,7 +134,7 @@ export function SubtaskConfigTree() {
>
<div className="bp4-tree-node-content bp4-tree-node-content-0">
<Icon icon="folder-new" />&nbsp;
<span className="bp4-tree-node-label">Add New Subtask</span>
<span className="bp4-tree-node-label">{i18n('Add new subtask')}</span>
</div>
</li>
</ul>
@@ -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 (<>
<div className="row">
@@ -29,13 +29,22 @@ export default function ProblemConfig(props: Props) {
</div>
<div className="medium-8 columns">
<Tabs onChange={(t) => (t !== 'errors' && setSelected(t.toString()))} selectedTabId={valid ? selected : 'errors'}>
<Tab id="basic" disabled={!valid} title="Basic" panel={<ProblemConfigForm />} />
<Tab id="subtasks" disabled={!valid} title="Subtasks" panel={<ProblemConfigTree />} />
<Tab id="basic" disabled={!valid} title={i18n('Basic')} panel={<ProblemConfigForm />} />
<Tab id="subtasks" disabled={!valid} title={i18n('Subtasks')} panel={<ProblemConfigTree />} />
<Tab id="errors" disabled={valid} title={errors.length ? `Errors(${errors.length})` : 'No Errors'} panel={
<div>{errors.map((i) => (<pre key={i}>{i}</pre>))}</div>} />
</Tabs>
</div>
</div>
<button className="rounded primary button" onClick={save}>{i18n('Submit')}</button>
<Dialog isOpen={open && !valid} onClose={() => setOpen(false)}>
<DialogBody>
<p>{i18n('Errors detected in the config. Confirm save?')}</p>
</DialogBody>
<DialogFooter actions={<>
<Button onClick={() => setOpen(false)}>{i18n('Cancel')}</Button>
<Button intent="warning" onClick={props.onSave}>{i18n('Save')}</Button>
</>} />
</Dialog>
<button className="rounded primary button" onClick={valid ? props.onSave : () => setOpen(true)}>{i18n('Save')}</button>
</>);
}
@@ -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,
@@ -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() {
>
<div className="bp4-tree-node-content bp4-tree-node-content-0">
<Icon icon="clean" />&nbsp;
<span className="bp4-tree-node-label">Auto detect</span>
<span className="bp4-tree-node-label">{i18n('Auto detect')}</span>
</div>
</li>
<li
@@ -85,7 +86,7 @@ export function AddTestcase() {
>
<div className="bp4-tree-node-content bp4-tree-node-content-0">
<Icon icon="clean" />&nbsp;
<span className="bp4-tree-node-label">Add testcase</span>
<span className="bp4-tree-node-label">{i18n('Add testcase')}</span>
</div>
</li>
<Dialog title="Add testcase" icon="cog" isOpen={open} onClose={() => setOpen(false)}>
@@ -98,7 +99,7 @@ export function AddTestcase() {
label="Input"
width="100%"
onChange={(e) => setInput(e)}
placeholder="Input"
placeholder={i18n('Input')}
value={input || ''}
/>
</div>
@@ -109,20 +110,21 @@ export function AddTestcase() {
label="Output"
width="100%"
onChange={(e) => setOutput(e)}
placeholder="Output"
placeholder={i18n('Output')}
value={input || ''}
/>
</div>
</div>
</DialogBody>
<DialogFooter actions={
<Button
<DialogFooter
actions={<Button
className={`primary rounded button${valid ? '' : ' disabled'}`}
onClick={onConfirm}
disabled={!valid}
intent="primary"
text="Save"
/>} />
/>}
/>
</Dialog>
</>);
}
@@ -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 (<>
<Dialog title="Set limits" icon="cog" isOpen={open} onClose={() => setOpen(false)}>
<Dialog title={i18n('Set time and memory limits')} icon="cog" isOpen={open} onClose={() => setOpen(false)}>
<DialogBody>
<ControlGroup fill={true} vertical={false}>
<InputGroup
@@ -72,10 +73,10 @@ export function SubtaskSettings(props: SubtaskSettingsProps) {
<span className="bp4-tree-node-caret-none bp4-icon-standard"></span>
<Icon icon="time" />
&nbsp;&nbsp;
<span className={`bp4-tree-node-label${!(time || props.time) ? ' text-gray' : ''}`}>{time || props.time || '1s'}</span>
<span className={`bp4-tree-node-label${time ? '' : ' text-gray'}`}>{time || props.time || '1s'}</span>
<Icon icon="comparison" />
&nbsp;&nbsp;
<span className={`bp4-tree-node-label${!(memory || props.memory) ? ' text-gray' : ''}`}>{memory || props.memory || '256m'}</span>
<span className={`bp4-tree-node-label${memory ? '' : ' text-gray'}`}>{memory || props.memory || '256m'}</span>
<Icon icon="star" />
{' '}
<span className="bp4-tree-node-secondary-label">{score || 0}</span>
@@ -106,7 +107,7 @@ export function GlobalSettings() {
setOpen(false);
}
return (<>
<Dialog title="Set limits" icon="cog" isOpen={open} onClose={() => setOpen(false)}>
<Dialog title={i18n('Set time and memory limits')} icon="cog" isOpen={open} onClose={() => setOpen(false)}>
<DialogBody>
<ControlGroup fill={true} vertical={false}>
<InputGroup
@@ -129,10 +130,10 @@ export function GlobalSettings() {
<div className="bp4-tree-node-content">
<Icon icon="time" />
&nbsp;&nbsp;
<span className={`bp4-tree-node-label${!time ? ' text-gray' : ''}`}>{time || '1s'}</span>
<span className={`bp4-tree-node-label${time ? '' : ' text-gray'}`}>{time || '1s'}</span>
<Icon icon="comparison" />
{' '}
<span className={`bp4-tree-node-secondary-label${!memory ? ' text-gray' : ''}`}>{memory || '256m'}</span>
<span className={`bp4-tree-node-secondary-label${memory ? '' : ' text-gray'}`}>{memory || '256m'}</span>
</div>
</li>
</>);
@@ -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={
<Menu>
<MenuItem icon="drawer-left" text="Move to subtask" >
<MenuItem icon="drawer-left" text={i18n('Move to subtask')} >
{subtaskIds.filter((i) => i !== subtaskId).map((i) => (
<MenuItem key={i} text={`Subtask ${i}`} />
<MenuItem key={i} text={i18n('Subtask {0}', i)} />
))}
{subtaskIds.length <= 1 && (
<MenuItem icon="disable" disabled text="No target available" />
<MenuItem icon="disable" disabled text={i18n('No target available')} />
)}
</MenuItem>
</Menu>