Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hydro v5 #951

Open
wants to merge 82 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
2c8c031
framework: use @cordisjs/core instead
undefined-moe Mar 3, 2025
bd63331
core&framework: pass type checks on cordis 4.0.0-alpha.1
undefined-moe Mar 4, 2025
aeb9d4c
bus: remove legacy `import *` usage support
undefined-moe Mar 4, 2025
dec3170
core: fix load
undefined-moe Mar 4, 2025
d72bb20
core: build with plugins
undefined-moe Mar 4, 2025
f7e635c
core: fix startup
undefined-moe Mar 4, 2025
688e0d2
migrate: fix checkLock
undefined-moe Mar 5, 2025
9c2b458
core: loader.reloadPlugin: remove first arg
undefined-moe Mar 5, 2025
9d64824
core: server: use handler mixin
undefined-moe Mar 5, 2025
f6bb3b6
bump deps
undefined-moe Mar 5, 2025
93f2402
migrate: handle bigint
undefined-moe Mar 5, 2025
f825fbe
import-qduoj: fix spj=null
undefined-moe Mar 5, 2025
31b4ed7
core: config: refactor (allow schemastery)
undefined-moe Mar 7, 2025
bb4c1ac
core: fix ci
undefined-moe Mar 7, 2025
37f5b98
core: add exports
undefined-moe Mar 7, 2025
a33826c
framework: ignore ECONNABORTED
undefined-moe Mar 7, 2025
209cee9
framework: disable prototype for kHandler
undefined-moe Mar 7, 2025
d009eb4
workspace: add ui-next
undefined-moe Mar 7, 2025
0aecafc
ui: new config page
undefined-moe Mar 8, 2025
4c086db
fix ci
undefined-moe Mar 8, 2025
a459b9a
core: loader: add missing inject
undefined-moe Mar 9, 2025
1a7b08e
core&ui: remove Hydro.service.bus, Hydro.ui.template
undefined-moe Mar 9, 2025
97ef575
core: fix builtin storage service
undefined-moe Mar 9, 2025
c4301a5
core: fix geoip inject
undefined-moe Mar 9, 2025
d0e8177
core: fix storage sign
undefined-moe Mar 9, 2025
1165bff
ui: use schemastery-react
undefined-moe Mar 9, 2025
6ff66f2
core: drop global.Hydro.lib
undefined-moe Mar 10, 2025
b48e700
judge: add user_code
undefined-moe Mar 10, 2025
cda3a8f
workspace: add oxlint
undefined-moe Mar 10, 2025
0414a13
workspace: fix eslint
undefined-moe Mar 10, 2025
51c3c4f
framework: show step error detail
undefined-moe Mar 11, 2025
af1b12d
framework: mixin: support callback style
undefined-moe Mar 12, 2025
af118e6
core: fix storage copy
undefined-moe Mar 12, 2025
caa4ddc
core: schema: hide secret value
undefined-moe Mar 12, 2025
8bc5fa1
bump prerelease
undefined-moe Mar 12, 2025
39dd47a
bump framework
undefined-moe Mar 12, 2025
af64125
workspace: fix publish script
undefined-moe Mar 12, 2025
f36c13d
fix publish script
undefined-moe Mar 12, 2025
985fd72
benchmark: fix write benchmark.json (#956)
criyle Mar 13, 2025
ebc2eae
core: i18n: better performance
undefined-moe Mar 13, 2025
875421d
judge: let sandbox client manages cache clean up & fix cache clean up…
criyle Mar 14, 2025
4b7de2f
judge: fix submission dispose too early & make submit_answer more eff…
criyle Mar 14, 2025
a01c83c
bug fixes
undefined-moe Mar 14, 2025
aa75195
core: command: respect HYDRO_PROFILE
undefined-moe Mar 14, 2025
e0628c6
core: bug fixes
undefined-moe Mar 15, 2025
f5eab3b
add support for config migration
undefined-moe Mar 15, 2025
0b03b17
bug fixes
undefined-moe Mar 16, 2025
09fe3a3
upgrade deps
undefined-moe Mar 16, 2025
415d1f4
framework: disable sse by default
undefined-moe Mar 16, 2025
0e7320f
core: store record rejudge history
undefined-moe Mar 14, 2025
cd92a41
ui: add record history panel
undefined-moe Mar 16, 2025
3c65c27
core&ui: show history judge time
undefined-moe Mar 16, 2025
80d2137
bug fixes
undefined-moe Mar 16, 2025
74a3ee9
ui-next: move to a seperate tsconfig
undefined-moe Mar 17, 2025
706a9a0
core&ui: UserSelectAutoComplete: support pasting username/email
undefined-moe Mar 19, 2025
7fd0171
core&ui: new domain_join logic
undefined-moe Mar 14, 2025
24f61b8
fix PRIV_VIEW_ALL_DOMAIN
undefined-moe Mar 14, 2025
2a04921
core: home_domain: only show joined
undefined-moe Mar 16, 2025
e15a310
core: upgrade: sync existing domain settings with legacy behavior
undefined-moe Mar 16, 2025
b9dbdc3
core: auto-join system domain
undefined-moe Mar 17, 2025
e9c5bf5
core: domain-join: bug fixes & add i18n
undefined-moe Mar 20, 2025
0bd15ca
bug fix
undefined-moe Mar 20, 2025
b6f1a9c
core: use mongodb@6
undefined-moe Mar 20, 2025
033e88f
core: cordis alpha.7
undefined-moe Mar 20, 2025
f0d49c2
core: domain_user: ignore role=default
undefined-moe Mar 20, 2025
040f7d8
workspace: use eslint@9
undefined-moe Mar 21, 2025
0e7f5fe
workspace: apply eslint edits
undefined-moe Mar 21, 2025
f8ed636
workspace: prepare: use single quote
undefined-moe Mar 21, 2025
a0f38d9
core&ui: implement domain leave and kick
undefined-moe Mar 21, 2025
3a776c3
bug fixes & improments
undefined-moe Mar 21, 2025
917ed3d
core: fix db pagination filter
undefined-moe Mar 22, 2025
ff16057
core: domain_join: allow auto group assignment
undefined-moe Mar 22, 2025
7ed859b
core: support ban user from domain
undefined-moe Mar 22, 2025
e1f4f69
bug fixes (fix #964 #957)
undefined-moe Mar 22, 2025
9bdf241
config: remove all setting.yaml
undefined-moe Mar 24, 2025
6009a3c
core: db.fixExpireAfter: ignore system collection
undefined-moe Mar 24, 2025
3d6b783
ui: fix domain_join link
undefined-moe Mar 24, 2025
68e641f
core: skip if no record selected to rejudge
undefined-moe Mar 24, 2025
62fb745
bug fixes
undefined-moe Mar 24, 2025
dc9cc9e
bug fixes
undefined-moe Mar 25, 2025
4421f98
judge: replace diff binary (fix #965)
undefined-moe Mar 25, 2025
f305110
ui: better config page layout
undefined-moe Mar 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .eslintignore

This file was deleted.

52 changes: 0 additions & 52 deletions .eslintrc.yaml

This file was deleted.

12 changes: 12 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
*.js text eol=lf
*.jsx text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.json text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
*.md text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.less text eol=lf
*.html text eol=lf
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
if [[ ${{ steps.ui-changed-files.outputs.any_changed }} == true ]] || [[ $(npm info @hydrooj/ui-default version) != $(node -e 'console.log(require("./packages/ui-default/package.json").version)') ]]
then
yarn build:ui:iconfont
parallel --tty -j+0 yarn ::: lint:ci lint:ui:ci build build:ui:production:webpack test
parallel --tty -j+0 yarn ::: lint:ci build build:ui:production:webpack test
else
parallel --tty -j+0 yarn ::: lint:ci build test
fi
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ yarn.lock
pnpm-lock.yaml
tsconfig.json
tsconfig.*.json
.oxlintrc.json

# Project Rules
## Core
Expand Down
893 changes: 0 additions & 893 deletions .yarn/releases/yarn-4.0.2.cjs

This file was deleted.

935 changes: 935 additions & 0 deletions .yarn/releases/yarn-4.7.0.cjs

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
enableTelemetry: false

nodeLinker: node-modules

npmPublishAccess: public

yarnPath: .yarn/releases/yarn-4.0.2.cjs

preferInteractive: true

preferReuse: true

tsEnableAutoTypes: true
enableTelemetry: false

yarnPath: .yarn/releases/yarn-4.7.0.cjs
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ Hydro 用户群:1085853538

## Unreleased

- judge: breaking: 不再支持在 checker 等的编译阶段读取选手代码
- judge: 添加 checker 编译缓存
- ui: 优化题目详情页面 OGP 信息
- core&ui: 升级 simplewebauthn
Expand All @@ -122,7 +121,32 @@ Hydro 用户群:1085853538
- core: 基于相对时间计算一血而非绝对时间
- ui&judge: 添加栈空间回显
- install: 在树莓派中自动启用 cgroup.memory
- install: 添加 shm 空间大小警告
- core: 升级到 cordis@4
- framework: 支持同时启用多个 renderer
- core: 分离 HMR 和 Watcher 组件
- core: i18n: 添加 interface 选项
- judge: 添加 kattis checker 支持
- migrate: 修复 hustoj 自动运行
- core: Settings: 支持使用 Schemastery
- ui: 更新系统设置页面样式
- import-qduoj: 修复 spj=null
- core: 修复文件复制
- core: 支持存储并显示提交记录重测历史
- core: 新的加域逻辑
- ui: UserSelect.Multi: 支持批量粘贴用户名

### Breaking API Changes

- vjudge: 使用 vjudge.mount 表替代 domain.mount
- judge: breaking: 不再支持在 checker 等的编译阶段读取选手代码
- core: 强制要求使用 inject 声明插件依赖
- core: 移除旧版本 bus 调用
- core: 移除 global.Hydro.service
- core: 移除 global.Hydro.ui.template
- core: 移除 global.Hydro.lib
- core: 移除 String.prototype.translate (使用 app.i18n.translate)
- core: 升级至 Mongo Driver 6

## Hydro 4.19.0 / UI 4.57.0

Expand Down
101 changes: 84 additions & 17 deletions build/prepare.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ const withoutTypes = (data) => ({

/** @type {import('typescript/lib/typescript').CompilerOptions} */
const compilerOptionsBase = {
target: 'es2020',
module: 'commonjs',
target: 'es2022',
lib: ['es2022'],
module: 'preserve',
esModuleInterop: true,
moduleResolution: 'node',
moduleResolution: 'bundler',
jsx: 'react',
sourceMap: false,
composite: true,
Expand All @@ -33,6 +34,7 @@ const config = {
compilerOptions: compilerOptionsBase,
references: [
{ path: 'tsconfig.ui.json' },
{ path: 'tsconfig.ui-next.json' },
{ path: 'plugins/tsconfig.json' },
],
files: [],
Expand Down Expand Up @@ -73,11 +75,16 @@ for (const name of ['plugins', 'modules']) {
const modules = [
'packages/hydrooj',
...['packages', 'framework'].flatMap((i) => fs.readdirSync(path.resolve(process.cwd(), i)).map((j) => `${i}/${j}`)),
].filter((i) => !i.includes('/.') && !i.includes('ui-default')).filter((i) => fs.statSync(path.resolve(process.cwd(), i)).isDirectory());
].filter((i) => !['/.', 'ui-default', 'ui-next'].some((t) => i.includes(t))).filter((i) => fs.statSync(path.resolve(process.cwd(), i)).isDirectory());

const UIConfig = {
exclude: [
'packages/ui-default/public',
'packages/ui-default/index.ts',
'packages/ui-default/backendlib/builder.ts',
'packages/ui-default/backendlib/misc.ts',
'packages/ui-default/backendlib/template.ts',
'packages/ui-default/backendlib/markdown.js',
'**/node_modules',
],
include: ['ts', 'tsx', 'vue', 'json']
Expand All @@ -90,15 +97,75 @@ const UIConfig = {
skipLibCheck: true,
allowSyntheticDefaultImports: true,
baseUrl: '.',
jsx: 'react-jsx',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

JSX transform update

Changed from 'react' to 'react-jsx', which uses React 17's new JSX transform. This is a breaking change that might require code updates if components rely on importing React in every file.


🏁 Script executed:

#!/bin/bash
# Check for React imports in JSX files that might be unnecessary with react-jsx
echo "Checking for potential unnecessary React imports with the new JSX transform..."
rg "import React from ['\"]react['\"]" --type tsx -g "!**/node_modules/**" --stats

Length of output: 283


Please run the above script to verify whether any TSX or JSX files still contain explicit React imports that can be removed with the new react-jsx JSX transform. Based on the output, further code updates might be necessary if such import statements are found.


🏁 Script executed:

#!/bin/bash
echo "Re-checking for potential unnecessary React imports with updated file filtering..."

echo "Checking .tsx files:"
rg "import React from ['\"]react['\"]" -g "*.tsx" --stats

echo "Checking .jsx files:"
rg "import React from ['\"]react['\"]" -g "*.jsx" --stats

Length of output: 4746


React JSX Transform Update – Address Unnecessary React Imports

The build configuration now uses the new react-jsx transform (React 17+), which means explicit import React from 'react' statements are generally no longer required for JSX to work. However, our verification shows that numerous files still include these imports (35 TSX files and 9 JSX files, for example, in packages/ui-default/components/languageselect.tsx, packages/ui-default/components/react/IconComponent.tsx, etc.).

Actionable next steps:

  • Review explicit React imports: Verify whether these imports are needed for side effects or legacy dependencies.
  • Cleanup consideration: If the explicit imports are redundant, remove them to align with the new JSX transform and avoid potential confusion.

outDir: path.join(baseOutDir, 'ui'),

useDefineForClassFields: true,
lib: ['es2022', 'DOM', 'DOM.Iterable'],

/* Bundler mode */
moduleResolution: 'bundler',
moduleDetection: 'force',
noEmit: true,

/* Linting */
noFallthroughCasesInSwitch: true,
noUncheckedSideEffectImports: true,

paths: {
'vj/*': [
'./packages/ui-default/*',
],
},
},
};

const UINextConfig = {
exclude: [
'**/node_modules',
],
include: ['ts', 'tsx', 'vue', 'json'].map((ext) => `packages/ui-next/src/**/*.${ext}`),
compilerOptions: {
...compilerOptionsBase,
module: 'ESNext',
skipLibCheck: true,
allowSyntheticDefaultImports: true,
baseUrl: '.',
jsx: 'react-jsx',
outDir: path.join(baseOutDir, 'ui-next'),

strict: true,
noImplicitAny: false,

useDefineForClassFields: true,
lib: ['es2022', 'DOM', 'DOM.Iterable'],

/* Bundler mode */
moduleResolution: 'bundler',
moduleDetection: 'force',
noEmit: true,

/* Linting */
noFallthroughCasesInSwitch: true,
noUncheckedSideEffectImports: true,

paths: {
'@/*': [
'./packages/ui-next/src/*',
],
'vj/*': [
'./packages/ui-default/*',
],
},
},
};

const tryUpdate = (location, content) => {
const current = fs.existsSync(location) ? fs.readFileSync(location, 'utf-8') : '';
const expected = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
if (expected !== current) fs.writeFileSync(location, expected);
};

const nm = path.resolve(__dirname, '../node_modules');
fs.ensureDirSync(path.join(nm, '@hydrooj'));
try {
Expand All @@ -119,40 +186,40 @@ const pluginsConfig = {
rootDir: '.',
baseUrl: '.',
outDir: path.join(baseOutDir, 'plugins'),
skipLibCheck: true,
paths: {
'vj/*': [
'../packages/ui-default/*',
],
},
},
};
fs.writeFileSync(path.resolve(process.cwd(), 'plugins', 'tsconfig.json'), JSON.stringify(pluginsConfig));
tryUpdate(path.resolve(process.cwd(), 'plugins', 'tsconfig.json'), pluginsConfig);

for (const package of modules) {
const basedir = path.resolve(process.cwd(), package);
for (const pkg of modules) {
const basedir = path.resolve(process.cwd(), pkg);
const files = fs.readdirSync(basedir);
try {
// eslint-disable-next-line import/no-dynamic-require
const name = require(path.join(basedir, 'package.json')).name;
fs.symlinkSync(basedir, path.join(nm, name), 'dir');
} catch (e) { }
if (!files.includes('src') && !files.filter((i) => i.endsWith('.ts')).length && package !== 'packages/utils') continue;
config.references.push({ path: package });
const origConfig = (files.includes('src') ? configSrc : configFlat)(package);
const expectedConfig = JSON.stringify(package.startsWith('modules/') ? withoutTypes(origConfig) : origConfig);
const configPath = path.resolve(basedir, 'tsconfig.json');
const currentConfig = fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf-8') : '';
if (expectedConfig !== currentConfig) fs.writeFileSync(configPath, expectedConfig);
if (!files.includes('src') && !files.filter((i) => i.endsWith('.ts')).length && pkg !== 'packages/utils') continue;
config.references.push({ path: pkg });
const origConfig = (files.includes('src') ? configSrc : configFlat)(pkg);
const expectedConfig = JSON.stringify(pkg.startsWith('modules/') ? withoutTypes(origConfig) : origConfig);
tryUpdate(path.resolve(basedir, 'tsconfig.json'), expectedConfig);
if (!files.includes('src')) continue;
// Create mapping entry
for (const file of fs.readdirSync(path.resolve(basedir, 'src'))) {
if (!fs.statSync(path.resolve(basedir, 'src', file)).isFile()) continue;
const name = file.split('.')[0];
const filePath = path.resolve(basedir, `${name}.js`);
if (name === 'index' && !fs.existsSync(filePath)) {
fs.writeFileSync(filePath, 'module.exports = require("./src/index");\n');
tryUpdate(filePath, "module.exports = require('./src/index');\n");
}
}
}
fs.writeFileSync(path.resolve(process.cwd(), 'tsconfig.ui.json'), JSON.stringify(UIConfig));
fs.writeFileSync(path.resolve(process.cwd(), 'tsconfig.json'), JSON.stringify(config));
tryUpdate(path.resolve(process.cwd(), 'tsconfig.ui.json'), UIConfig);
tryUpdate(path.resolve(process.cwd(), 'tsconfig.ui-next.json'), UINextConfig);
tryUpdate(path.resolve(process.cwd(), 'tsconfig.json'), config);
25 changes: 20 additions & 5 deletions build/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { writeFileSync } from 'fs';
import path from 'path';
import ora from 'ora';
import packageJson from 'package-json';
import { gt } from 'semver';
import { gt, prerelease } from 'semver';
import { getWorkspaces, spawnAsync } from './utils';

const {
CI, GITHUB_EVENT_NAME, GITHUB_REF,
} = process.env;

const tag = GITHUB_REF === 'refs/heads/master' ? 'latest' : GITHUB_REF === 'refs/heads/develop' ? 'dev' : undefined;
const tag = GITHUB_REF === 'refs/heads/master' ? 'latest' : GITHUB_REF === 'refs/heads/next' ? 'dev' : undefined;

if (CI && (!tag || GITHUB_EVENT_NAME !== 'push')) {
console.log('publish skipped.');
Expand All @@ -33,6 +33,14 @@ if (CI && (!tag || GITHUB_EVENT_NAME !== 'push')) {
let meta;
try {
meta = require(`../${name}/package.json`);
if (tag === 'dev') {
try {
const result = await packageJson(meta.name, { version: meta.version });
if (result?.version === meta.version) return progress++; // no change on dev version
} catch (e) {
// expected
}
} else if (prerelease(meta.version)) return progress++; // Refuse to publish prerelease as 'latest' tag
if (!meta.private && /^[0-9.]+$/.test(meta.version)) {
try {
const { version } = await packageJson(meta.name, { version: tag });
Expand All @@ -41,21 +49,28 @@ if (CI && (!tag || GITHUB_EVENT_NAME !== 'push')) {
if (e.name === 'VersionNotFoundError') bumpMap[name] = meta.version;
else throw e;
}
} else {
// x.x.x-alpha.x
bumpMap[name] = meta.version;
}
} catch (e) {
console.error(e);
}
spinner.text = `Loading workspaces (${++progress}/${folders.length})`;
return progress;
}));
spinner.succeed();

if (Object.keys(bumpMap).length) {
for (const name in bumpMap) {
console.log(`publishing ${name}@${bumpMap[name]} ...`);
if (tag === 'dev') {
const pkg = require(`${name}/package.json`);
pkg.version += '-dev';
writeFileSync(path.resolve(`${name}/package.json`), JSON.stringify(pkg));
const location = require.resolve(`../${name}/package.json`);
const pkg = require(location);
if (!prerelease(pkg.version)) {
pkg.version += '-dev';
writeFileSync(location, JSON.stringify(pkg));
}
}
await spawnAsync(
`yarn npm publish --access public --tag ${tag}`,
Expand Down
Loading
Loading