mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 09:46:28 +08:00
update changelog
This commit is contained in:
8 files changed
+116
-29
No files matched your search
@@ -40,6 +40,23 @@ Telegram [@webpack_exports_undefined](https://t.me/webpack_exports_undefined)
|
|||||||
<details>
|
<details>
|
||||||
<summary><h2>更新日志(点击展开)</h2></summary>
|
<summary><h2>更新日志(点击展开)</h2></summary>
|
||||||
|
|
||||||
|
### Hydro 4.9.0 / UI 4.48.0
|
||||||
|
- core: 优化讨论鉴权
|
||||||
|
- judge: 优化统一回调评测状态回显
|
||||||
|
- judge: 移除 `processTestdata` 步骤
|
||||||
|
- judge: 客观题子任务分数回显
|
||||||
|
- core: 压平测试数据结构
|
||||||
|
- core: rp: 修复比赛分数
|
||||||
|
- core&ui: 首次使用 OAuth 时要求设置密码
|
||||||
|
- ui: 评测设置 UI 升级
|
||||||
|
- install: 根据系统内存调整 wtCacheSize
|
||||||
|
- ui: 加载速度优化
|
||||||
|
- core: 检测域 ID 大小写
|
||||||
|
- ui: 导航栏域索引
|
||||||
|
- ui: 支持按权限组过滤作业/比赛
|
||||||
|
- judge: 将 Javascript 默认解释器设置为 node
|
||||||
|
- judge: 修复删除未评测完成的题目导致评测队列卡死的问题
|
||||||
|
|
||||||
### Hydro 4.8.0 / UI 4.47.6
|
### Hydro 4.8.0 / UI 4.47.6
|
||||||
- core: 升级至 mongodb@5
|
- core: 升级至 mongodb@5
|
||||||
- ui: 评测详情中显示子任务得分
|
- ui: 评测详情中显示子任务得分
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "4.9.0",
|
"version": "4.9.1",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "src/plugin-api",
|
"main": "src/plugin-api",
|
||||||
"module": "src/plugin-api",
|
"module": "src/plugin-api",
|
||||||
|
|||||||
@@ -322,6 +322,11 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
|||||||
async exportScoreboard(domainId: string, tid: ObjectId, ext: string) {
|
async exportScoreboard(domainId: string, tid: ObjectId, ext: string) {
|
||||||
await this.limitRate('scoreboard_download', 60, 3);
|
await this.limitRate('scoreboard_download', 60, 3);
|
||||||
if (ext === 'ghost') {
|
if (ext === 'ghost') {
|
||||||
|
if ((contest.isDone(this.tdoc) || contest.isLocked(this.tdoc)) && !this.tdoc.unlocked) {
|
||||||
|
if (!this.user.own(this.tdoc)) {
|
||||||
|
this.checkPerm(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
|
||||||
|
}
|
||||||
|
}
|
||||||
await this.exportGhost(domainId, tid);
|
await this.exportGhost(domainId, tid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
Button, ControlGroup, Dialog, DialogBody, DialogFooter, Icon, InputGroup,
|
Button, Dialog, DialogBody, DialogFooter, Icon,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { readSubtasksFromFiles } from '@hydrooj/utils/lib/common';
|
import { readSubtasksFromFiles } from '@hydrooj/utils/lib/common';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { useSelector, useStore } from 'react-redux';
|
import { useSelector, useStore } from 'react-redux';
|
||||||
|
import FileSelectAutoComplete from '../../autocomplete/components/FileSelectAutoComplete';
|
||||||
import { RootState } from '../reducer';
|
import { RootState } from '../reducer';
|
||||||
|
|
||||||
export function AddTestcase() {
|
export function AddTestcase() {
|
||||||
@@ -13,9 +14,28 @@ export function AddTestcase() {
|
|||||||
const [valid, setValid] = React.useState(false);
|
const [valid, setValid] = React.useState(false);
|
||||||
const testdata = useSelector((state: RootState) => state.testdata);
|
const testdata = useSelector((state: RootState) => state.testdata);
|
||||||
const store = useStore<RootState>();
|
const store = useStore<RootState>();
|
||||||
|
const refInput = useRef();
|
||||||
|
const refOutput = useRef();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setValid(testdata.find((i) => i.name === input) && testdata.find((i) => i.name === output));
|
setValid(testdata.find((i) => i.name === input) && testdata.find((i) => i.name === output));
|
||||||
|
if (input && !output) {
|
||||||
|
const filename = input.substring(0, input.lastIndexOf('.'));
|
||||||
|
let outputFile = '';
|
||||||
|
if (testdata.find((i) => i.name === `${filename}.out`)) outputFile = `${filename}.out`;
|
||||||
|
else if (testdata.find((i) => i.name === `${filename}.ans`)) outputFile = `${filename}.ans`;
|
||||||
|
// @ts-ignore
|
||||||
|
refOutput.current!.setSelectedItems([outputFile]);
|
||||||
|
setOutput(outputFile);
|
||||||
|
}
|
||||||
|
if (output && !input) {
|
||||||
|
const filename = output.substring(0, output.lastIndexOf('.'));
|
||||||
|
if (testdata.find((i) => i.name === `${filename}.in`)) {
|
||||||
|
// @ts-ignore
|
||||||
|
refInput.current!.setSelectedItems([`${filename}.in`]);
|
||||||
|
setInput(`${filename}.in`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}, [input, output]);
|
}, [input, output]);
|
||||||
|
|
||||||
function onConfirm() {
|
function onConfirm() {
|
||||||
@@ -57,32 +77,52 @@ export function AddTestcase() {
|
|||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
className="bp4-tree-node"
|
className="bp4-tree-node"
|
||||||
onClick={() => setOpen(true)}
|
onClick={() => {
|
||||||
|
setInput('');
|
||||||
|
setOutput('');
|
||||||
|
setOpen(true);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="bp4-tree-node-content bp4-tree-node-content-0">
|
<div className="bp4-tree-node-content bp4-tree-node-content-0">
|
||||||
<Icon icon="clean" />
|
<Icon icon="clean" />
|
||||||
<span className="bp4-tree-node-label">Add testcase</span>
|
<span className="bp4-tree-node-label">Add testcase</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<Dialog title="Add testcasse" icon="cog" isOpen={open} onClose={() => setOpen(false)}>
|
<Dialog title="Add testcase" icon="cog" isOpen={open} onClose={() => setOpen(false)}>
|
||||||
<DialogBody>
|
<DialogBody>
|
||||||
<ControlGroup fill={true} vertical={false}>
|
<div className="row">
|
||||||
{/* TODO: autocomplete */}
|
<div className="columns medium-6">
|
||||||
<InputGroup
|
<FileSelectAutoComplete
|
||||||
leftElement={<Icon icon="import" />}
|
ref={refInput}
|
||||||
onChange={(e) => setInput(e.target.value)}
|
data={testdata}
|
||||||
|
label="Input"
|
||||||
|
width="100%"
|
||||||
|
onChange={(e) => setInput(e)}
|
||||||
placeholder="Input"
|
placeholder="Input"
|
||||||
value={input || ''}
|
value={input || ''}
|
||||||
/>
|
/>
|
||||||
<InputGroup
|
</div>
|
||||||
leftElement={<Icon icon="export" />}
|
<div className="columns medium-6">
|
||||||
onChange={(e) => setOutput(e.target.value)}
|
<FileSelectAutoComplete
|
||||||
|
ref={refOutput}
|
||||||
|
data={testdata}
|
||||||
|
label="Output"
|
||||||
|
width="100%"
|
||||||
|
onChange={(e) => setOutput(e)}
|
||||||
placeholder="Output"
|
placeholder="Output"
|
||||||
value={output || ''}
|
value={input || ''}
|
||||||
/>
|
/>
|
||||||
</ControlGroup>
|
</div>
|
||||||
|
</div>
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
<DialogFooter actions={<Button onClick={onConfirm} disabled={!valid} intent="primary" text="Save" />} />
|
<DialogFooter actions={
|
||||||
|
<Button
|
||||||
|
className={`primary rounded button${valid ? '' : ' disabled'}`}
|
||||||
|
onClick={onConfirm}
|
||||||
|
disabled={!valid}
|
||||||
|
intent="primary"
|
||||||
|
text="Save"
|
||||||
|
/>} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>);
|
</>);
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ export function SubtaskSettings(props: SubtaskSettingsProps) {
|
|||||||
/>
|
/>
|
||||||
</ControlGroup>
|
</ControlGroup>
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
<DialogFooter actions={<Button onClick={onConfirm} intent="primary" text="Save" />} />
|
<DialogFooter actions={<Button className="primary rounded button" onClick={onConfirm} intent="primary" text="Save" />} />
|
||||||
</Dialog>
|
</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">
|
||||||
@@ -123,7 +123,7 @@ export function GlobalSettings() {
|
|||||||
/>
|
/>
|
||||||
</ControlGroup>
|
</ControlGroup>
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
<DialogFooter actions={<Button onClick={onConfirm} intent="primary" text="Save" />} />
|
<DialogFooter actions={<Button className="primary rounded button" onClick={onConfirm} intent="primary" text="Save" />} />
|
||||||
</Dialog>
|
</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">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/ui-default",
|
"name": "@hydrooj/ui-default",
|
||||||
"version": "4.48.0",
|
"version": "4.48.1",
|
||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
|
|||||||
@@ -15,18 +15,20 @@
|
|||||||
.bp4-tab-panel
|
.bp4-tab-panel
|
||||||
margin-top: 5px
|
margin-top: 5px
|
||||||
|
|
||||||
.problem-config-form
|
.bp4-dialog
|
||||||
font-family: var(--code-font-family)
|
font-family: var(--code-font-family)
|
||||||
|
background: #fff
|
||||||
|
|
||||||
input::-webkit-outer-spin-button, input::-webkit-inner-spin-button
|
.autocomplete-container
|
||||||
-webkit-appearance: none !important
|
font-size: 0.875rem
|
||||||
input[type="number"]
|
color: #666
|
||||||
-moz-appearance: textfield
|
|
||||||
|
.bp4-dialog-footer-fixed
|
||||||
|
border-top: 0
|
||||||
|
|
||||||
|
.button
|
||||||
|
margin: 0
|
||||||
|
|
||||||
.bp4-tag.bp4-minimal
|
|
||||||
background: transparent
|
|
||||||
.bp4-input-action
|
|
||||||
pointer-events: none
|
|
||||||
.bp4-input-group
|
.bp4-input-group
|
||||||
input
|
input
|
||||||
appearance: none
|
appearance: none
|
||||||
@@ -39,12 +41,23 @@
|
|||||||
border: 1px solid #ddd
|
border: 1px solid #ddd
|
||||||
color: inherit
|
color: inherit
|
||||||
border-radius: 0
|
border-radius: 0
|
||||||
background-color: transparent
|
|
||||||
outline: 2px solid transparent
|
outline: 2px solid transparent
|
||||||
transition: outline-color 0.2s, border-color 0.2s
|
transition: outline-color 0.2s, border-color 0.2s
|
||||||
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1)
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1)
|
||||||
box-shadow: none
|
box-shadow: none
|
||||||
|
|
||||||
|
.problem-config-form
|
||||||
|
font-family: var(--code-font-family)
|
||||||
|
|
||||||
|
input::-webkit-outer-spin-button, input::-webkit-inner-spin-button
|
||||||
|
-webkit-appearance: none !important
|
||||||
|
input[type="number"]
|
||||||
|
-moz-appearance: textfield
|
||||||
|
|
||||||
|
.bp4-tag.bp4-minimal
|
||||||
|
background: transparent
|
||||||
|
.bp4-input-action
|
||||||
|
pointer-events: none
|
||||||
|
|
||||||
.data-table
|
.data-table
|
||||||
tr
|
tr
|
||||||
|
|||||||
@@ -390,3 +390,15 @@ $hover-background-color = #424242
|
|||||||
.omnibar-content-section
|
.omnibar-content-section
|
||||||
background-color: $main-background-color !important
|
background-color: $main-background-color !important
|
||||||
border-color: #3d3d3d !important
|
border-color: #3d3d3d !important
|
||||||
|
|
||||||
|
.bp4-tab
|
||||||
|
color: #aaa
|
||||||
|
|
||||||
|
&[aria-disabled=true]
|
||||||
|
color: #555
|
||||||
|
|
||||||
|
.bp4-card,.bp4-dialog,.bp4-dialog-header,.bp4-dialog-footer
|
||||||
|
background-color: #1f1f1f !important
|
||||||
|
|
||||||
|
.bp4-input-group input
|
||||||
|
border-color: #3d3d3d!important
|
||||||
Reference in new issue
Block a user