mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
bug fixes
This commit is contained in:
10 files changed
+56
-65
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hydrooj/register",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
|
||||
@@ -69,21 +69,19 @@ export async function apply(ctx: HydroContext) {
|
||||
const parallelism = getConfig('parallelism');
|
||||
async function collectInfo() {
|
||||
const coll = db.collection('status');
|
||||
const compilers = await compilerVersions(langs);
|
||||
const [compilers, size] = await Promise.all([
|
||||
compilerVersions(langs),
|
||||
stackSize(),
|
||||
]);
|
||||
await coll.updateOne(
|
||||
{ mid: info.mid, type: 'server' },
|
||||
{ $set: { compilers } },
|
||||
{ upsert: true },
|
||||
);
|
||||
const size = await stackSize();
|
||||
await coll.updateOne(
|
||||
{ mid: info.mid, type: 'server' },
|
||||
{ $set: { stackSize: size } },
|
||||
{ $set: { compilers, stackSize: size } },
|
||||
{ upsert: true },
|
||||
);
|
||||
}
|
||||
ctx.effect(() => {
|
||||
const taskConsumer = TaskModel.consume({ type: 'judge' }, handle, true, parallelism);
|
||||
collectInfo();
|
||||
const dispose = ctx.on('system/setting', () => {
|
||||
taskConsumer.setConcurrency(getConfig('parallelism'));
|
||||
collectInfo();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from 'path';
|
||||
import {
|
||||
ContestModel, Context, fs, getAlphabeticId, ObjectId, PERM, Schema, STATUS, Types, UserModel,
|
||||
avatar, ContestModel, Context, fs, getAlphabeticId, ObjectId, PERM, Schema, STATUS, Types, UserModel,
|
||||
} from 'hydrooj';
|
||||
|
||||
const file = fs.readFileSync(path.join(__dirname, 'public/assets/board.html'), 'utf8');
|
||||
@@ -47,8 +47,9 @@ export async function apply(ctx: Context) {
|
||||
team_id: `${udoc._id}`,
|
||||
name: udoc.uname,
|
||||
organization: udoc.school,
|
||||
members: [],
|
||||
coach: '',
|
||||
members: udoc.members?.split(',').filter((t) => t) || [],
|
||||
coach: udoc.coach,
|
||||
badge: { url: avatar(udoc.avatar) },
|
||||
group: [
|
||||
...(udoc.group || []),
|
||||
i.unrank ? 'unofficial' : 'official',
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
"postinstall": "node -r @hydrooj/register install.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@xcpcio/board-app": "^0.64.5"
|
||||
"@xcpcio/board-app": "^0.67.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@xcpcio/types": "^0.67.0"
|
||||
}
|
||||
}
|
||||
@@ -102,10 +102,13 @@ export function Media(md: MarkdownIt) {
|
||||
}
|
||||
if (service === 'pdf') {
|
||||
if (src.startsWith('file://') || src.startsWith('./')) src += src.includes('?') ? '&noDisposition=1' : '?noDisposition=1';
|
||||
// A response with has content-disposition header causes the browser to download the file automatically.
|
||||
// As we cannot control response header from external sites, we block embedding external PDFs.
|
||||
else return '<p>Embedding an external PDF is no longer supported.</p>';
|
||||
return `\
|
||||
<object classid="clsid:${uuid().toUpperCase()}">
|
||||
<param name="SRC" value="${src}" >
|
||||
<embed width="100%" style="min-height: 100vh;border: none;" fullscreen="yes" src="${src}">
|
||||
<param name="SRC" value="${src}">
|
||||
<embed type="application/pdf" width="100%" style="min-height:100vh;border:none;" fullscreen="yes" src="${src}#toolbar=0&navpanes=0">
|
||||
<noembed></noembed>
|
||||
</embed>
|
||||
</object>`;
|
||||
|
||||
@@ -125,14 +125,19 @@ export interface Field {
|
||||
}
|
||||
|
||||
type Result<T extends string, R extends Record<T, Field>> = {
|
||||
[K in keyof R]: ('text' | 'password' | 'username' | 'domain') extends R[K]['type'] ? string
|
||||
[K in keyof R]: R[K]['type'] extends ('text' | 'password' | 'username' | 'domain') ? string
|
||||
: R[K]['type'] extends 'checkbox' ? boolean
|
||||
: R[K]['type'] extends 'userId' ? number
|
||||
: R[K]['type'] extends 'user' ? any
|
||||
: never;
|
||||
};
|
||||
|
||||
export async function prompt<T extends string, R extends Record<T, Field>>(title: string, fields: R): Promise<Result<T, R>> {
|
||||
interface PromptOptions {
|
||||
cancelByClickingBack: boolean;
|
||||
cancelByEsc: boolean;
|
||||
}
|
||||
|
||||
export async function prompt<T extends string, R extends Record<T, Field>>(title: string, fields: R, options?: PromptOptions): Promise<Result<T, R>> {
|
||||
let valueCache: Result<T, R> = {} as any;
|
||||
const defaultValues = Object.fromEntries(Object.entries(fields)
|
||||
.map(([name, field]: [T, Field]) => {
|
||||
@@ -225,6 +230,8 @@ export async function prompt<T extends string, R extends Record<T, Field>>(title
|
||||
const res = await new Dialog({
|
||||
$body: $(div),
|
||||
$action: [buttonCancel, buttonOk].join('\n'),
|
||||
cancelByClickingBack: options?.cancelByClickingBack ?? false,
|
||||
cancelByEsc: options?.cancelByEsc ?? false,
|
||||
onDispatch(action) {
|
||||
if (action === 'ok') {
|
||||
for (const [name, field] of Object.entries(fields) as [string, Field][]) {
|
||||
|
||||
@@ -2,12 +2,10 @@ import { browserSupportsWebAuthnAutofill, startAuthentication } from '@simpleweb
|
||||
import $ from 'jquery';
|
||||
import responsiveCutoff from 'vj/breakpoints.json';
|
||||
import DomDialog from 'vj/components/dialog/DomDialog';
|
||||
import { InfoDialog } from 'vj/components/dialog/index';
|
||||
import { alert } from 'vj/components/dialog/index';
|
||||
import Notification from 'vj/components/notification';
|
||||
import { AutoloadPage } from 'vj/misc/Page';
|
||||
import {
|
||||
i18n, mediaQuery, request, tpl,
|
||||
} from 'vj/utils';
|
||||
import { i18n, mediaQuery, request } from 'vj/utils';
|
||||
|
||||
const signinDialogPage = new AutoloadPage('signinDialogPage', null, () => {
|
||||
const signInDialog = DomDialog.getOrConstruct($('.dialog--signin'), {
|
||||
@@ -18,7 +16,7 @@ const signinDialogPage = new AutoloadPage('signinDialogPage', null, () => {
|
||||
let authnInitialized = false;
|
||||
|
||||
async function initPasskey() {
|
||||
if (authnInitialized) return;
|
||||
if (authnInitialized || !window.isSecureContext) return;
|
||||
authnInitialized = true;
|
||||
const support = await browserSupportsWebAuthnAutofill();
|
||||
if (!support) return;
|
||||
@@ -79,9 +77,7 @@ const signinDialogPage = new AutoloadPage('signinDialogPage', null, () => {
|
||||
|
||||
$('[data-lostpass]').on('click', (e) => {
|
||||
e.preventDefault();
|
||||
new InfoDialog({
|
||||
$body: tpl.typoMsg(i18n('Relax and try to remember your password.')),
|
||||
}).open();
|
||||
alert(i18n('Relax and try to remember your password.'));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -164,6 +164,9 @@ $highlight-button-color = #F6DF45
|
||||
.row
|
||||
max-width: 100vw !important;
|
||||
|
||||
.data-table td
|
||||
line-height: 1.5
|
||||
|
||||
.col--rank
|
||||
width: rem(60px)
|
||||
text-align: center
|
||||
|
||||
@@ -1,42 +1,22 @@
|
||||
import $ from 'jquery';
|
||||
import React from 'react';
|
||||
import DomainSelectAutoComplete from 'vj/components/autocomplete/DomainSelectAutoComplete';
|
||||
import { ActionDialog } from 'vj/components/dialog';
|
||||
import { prompt } from 'vj/components/dialog';
|
||||
import { NamedPage } from 'vj/misc/Page';
|
||||
import { i18n, tpl } from 'vj/utils';
|
||||
import { i18n } from 'vj/utils';
|
||||
|
||||
export default new NamedPage('home_domain', () => {
|
||||
$(tpl(
|
||||
<div style={{ display: 'none' }} className="dialog__body--join-domain" id="join-domain-dialog">
|
||||
<div className="row"><div className="columns">
|
||||
<h1>{i18n('Join Domain')}</h1>
|
||||
</div></div>
|
||||
<div className="row">
|
||||
<div className="columns">
|
||||
<label>
|
||||
{i18n('Domain ID')}
|
||||
<div className="textbox-container">
|
||||
<input name="domainId" type="text" className="textbox" data-autofocus />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
)).appendTo(document.body);
|
||||
const selector: any = DomainSelectAutoComplete.getOrConstruct($('#join-domain-dialog [name="domainId"]'));
|
||||
|
||||
$(document).on('click', '[id="join-domain-button"]', async () => {
|
||||
const action = await new ActionDialog({
|
||||
$body: $('.dialog__body--join-domain > div'),
|
||||
onDispatch(a) {
|
||||
if (a === 'ok' && selector.value() === null) {
|
||||
selector.focus();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
const res = await prompt(i18n('Join Domain'), {
|
||||
domain: {
|
||||
type: 'domain',
|
||||
label: i18n('Domain ID'),
|
||||
required: true,
|
||||
autofocus: true,
|
||||
},
|
||||
}).open();
|
||||
if (action !== 'ok') return;
|
||||
window.location.href = `/domain/join?target=${encodeURIComponent(selector.value()._id.toString())}`;
|
||||
}, {
|
||||
cancelByClickingBack: true,
|
||||
cancelByEsc: true,
|
||||
});
|
||||
if (!res?.domain) return;
|
||||
window.location.href = `/domain/join?target=${encodeURIComponent(res.domain.toString())}`;
|
||||
});
|
||||
});
|
||||
@@ -15,11 +15,12 @@ import {
|
||||
addSpeculationRules, delay, i18n, pjax, request,
|
||||
} from 'vj/utils';
|
||||
|
||||
const keywords = ['category', 'difficulty', 'namespace'];
|
||||
const list = [];
|
||||
const filterTags = {};
|
||||
const pinned: Record<string, string[]> = { category: [], difficulty: [], namespace: [] };
|
||||
const selections = { category: {}, difficulty: {}, namespace: {} };
|
||||
const selectedTags: Record<string, string[]> = { category: [], difficulty: [], namespace: [] };
|
||||
const pinned: Record<string, string[]> = Object.fromEntries(keywords.map((keyword) => [keyword, []]));
|
||||
const selections = Object.fromEntries(keywords.map((keyword) => [keyword, {}]));
|
||||
const selectedTags: Record<string, string[]> = Object.fromEntries(keywords.map((keyword) => [keyword, []]));
|
||||
|
||||
let selectedPids: string[] = [];
|
||||
let clearSelectionHandler: (() => void) | null = null;
|
||||
@@ -35,7 +36,7 @@ function setDomSelected($dom, selected, icon?) {
|
||||
}
|
||||
|
||||
const parserOptions = {
|
||||
keywords: ['category', 'difficulty', 'namespace'],
|
||||
keywords,
|
||||
offsets: true,
|
||||
alwaysArray: true,
|
||||
tokenize: true,
|
||||
@@ -46,8 +47,7 @@ function writeSelectionToInput() {
|
||||
const parsedCurrentValue = parser.parse(currentValue, parserOptions) as SearchParserResult;
|
||||
const q = parser.stringify({
|
||||
...parsedCurrentValue,
|
||||
category: selectedTags.category,
|
||||
difficulty: selectedTags.difficulty,
|
||||
...keywords.reduce((acc, keyword) => ({ ...acc, [keyword]: selectedTags[keyword] }), {}),
|
||||
text: parsedCurrentValue.text,
|
||||
}, parserOptions);
|
||||
$('[name="q"]').val(q);
|
||||
|
||||
Reference in new issue
Block a user