mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
patches from chongqing site
This commit is contained in:
16 files changed
+146
-85
No files matched your search
@@ -6,9 +6,9 @@
|
||||
"repository": "https://github.com/hydro-dev/Hydro",
|
||||
"dependencies": {
|
||||
"@antfu/eslint-config": "^6.2.0",
|
||||
"@eslint-react/eslint-plugin": "^2.3.7",
|
||||
"@typescript-eslint/eslint-plugin": "^8.47.0",
|
||||
"@typescript-eslint/parser": "^8.47.0",
|
||||
"@eslint-react/eslint-plugin": "^2.3.9",
|
||||
"@typescript-eslint/eslint-plugin": "^8.48.0",
|
||||
"@typescript-eslint/parser": "^8.48.0",
|
||||
"eslint-plugin-de-morgan": "^2.0.0",
|
||||
"eslint-plugin-github": "^6.0.0",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@
|
||||
"mongodb-memory-server": "10.3.0",
|
||||
"nyc": "^17.1.0",
|
||||
"ora": "^9.0.0",
|
||||
"oxlint": "^1.29.0",
|
||||
"oxlint": "^1.30.0",
|
||||
"package-json": "^10.0.1",
|
||||
"semver": "^7.7.3",
|
||||
"simple-git": "^3.30.0",
|
||||
|
||||
@@ -36,13 +36,13 @@
|
||||
"koa-proxies": "^0.12.4",
|
||||
"koa-static-cache": "^5.1.4",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^11.2.2",
|
||||
"lru-cache": "^11.2.4",
|
||||
"mime-types": "^3.0.2",
|
||||
"moment-timezone": "^0.6.0",
|
||||
"mongodb": "^7.0.0",
|
||||
"mongodb-uri": "^0.9.7",
|
||||
"nanoid": "^5.1.6",
|
||||
"nodemailer": "^7.0.10",
|
||||
"nodemailer": "^7.0.11",
|
||||
"notp": "^2.0.3",
|
||||
"p-queue": "^9.0.1",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
|
||||
@@ -485,8 +485,11 @@ export class ContestCodeHandler extends Handler {
|
||||
async get(domainId: string, tid: ObjectId, all: boolean) {
|
||||
await this.limitRate('contest_code', 60, 10);
|
||||
const [tdoc, tsdocs] = await contest.getAndListStatus(domainId, tid);
|
||||
if (!this.user.own(tdoc) && !this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) {
|
||||
this.checkPerm(PERM.PERM_READ_RECORD_CODE);
|
||||
if (!this.user.own(tdoc)) {
|
||||
if (!this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) {
|
||||
this.checkPerm(PERM.PERM_READ_RECORD_CODE);
|
||||
}
|
||||
if (!contest.isDone(tdoc)) throw new ContestNotEndedError(domainId, tid);
|
||||
}
|
||||
if (!contest.canShowRecord.call(this, tdoc as any, true)) {
|
||||
throw new PermissionError(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
|
||||
@@ -754,7 +757,7 @@ export class ContestBalloonHandler extends ContestManagementBaseHandler {
|
||||
async postDone(domainId: string, tid: ObjectId, bid: ObjectId) {
|
||||
const balloon = await contest.getBalloon(domainId, tid, bid);
|
||||
if (!balloon) throw new ValidationError('balloon');
|
||||
if (balloon.sent) throw new ValidationError('balloon', null, 'Balloon already sent');
|
||||
if (balloon.sent) throw new ValidationError('Balloon already sent');
|
||||
await contest.updateBalloon(domainId, tid, bid, { sent: this.user._id, sentAt: new Date() });
|
||||
this.back();
|
||||
}
|
||||
|
||||
@@ -124,15 +124,13 @@ class HomeworkDetailHandler extends Handler {
|
||||
await contest.setStatus(domainId, tid, this.user._id, { startAt: new Date() });
|
||||
tsdoc.startAt = new Date();
|
||||
}
|
||||
for (const pdetail of tsdoc.journal || []) {
|
||||
const valid = (tsdoc.journal || []).filter((p) => this.tdoc.pids.includes(p.pid));
|
||||
for (const pdetail of valid) {
|
||||
psdict[pdetail.pid] = pdetail;
|
||||
rdict[pdetail.rid] = { _id: pdetail.rid };
|
||||
}
|
||||
if (contest.canShowSelfRecord.call(this, this.tdoc) && tsdoc.journal) {
|
||||
rdict = await record.getList(
|
||||
domainId,
|
||||
tsdoc.journal.map((pdetail) => pdetail.rid),
|
||||
);
|
||||
if (contest.canShowSelfRecord.call(this, this.tdoc) && valid.length) {
|
||||
rdict = await record.getList(domainId, valid.map((pdetail) => pdetail.rid));
|
||||
}
|
||||
}
|
||||
Object.assign(this.response.body, { pdict, psdict, rdict });
|
||||
|
||||
@@ -331,6 +331,7 @@ class RecordMainConnectionHandler extends ConnectionHandler {
|
||||
if (rdoc.domainId !== this.args.domainId) return;
|
||||
if (!this.pretest && typeof rdoc.input === 'string') return;
|
||||
if (!this.all) {
|
||||
if (!rdoc.contest && this.tid) return;
|
||||
if (rdoc.contest && ![this.tid, '000000000000000000000000'].includes(rdoc.contest.toString())) return;
|
||||
if (this.tid && rdoc.contest?.toString() !== '0'.repeat(24)) {
|
||||
if (rdoc.uid !== this.user._id && !contest.canShowRecord.call(this, this.tdoc, true)) return;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import { LRUCache } from 'lru-cache';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
_, avatar, ContestModel, ContestNotEndedError, Context, db, findFileSync,
|
||||
_, avatar, BadRequestError, ContestModel, ContestNotEndedError, Context, db, findFileSync,
|
||||
ForbiddenError, fs, ObjectId, parseTimeMS, PERM, PRIV, ProblemConfig, ProblemModel,
|
||||
randomstring, Schema, SettingModel, STATUS, STATUS_SHORT_TEXTS, STATUS_TEXTS,
|
||||
Time, Types, UserModel, Zip,
|
||||
SystemModel, Time, Types, UserModel, Zip,
|
||||
} from 'hydrooj';
|
||||
import { ResolverInput } from './interface';
|
||||
|
||||
@@ -118,7 +118,7 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
exclude: t.unrank,
|
||||
})),
|
||||
submissions: submissions.map((i) => ({
|
||||
team: i.uid.toString(),
|
||||
team: udict[i.uid]?.seat || i.uid.toString(),
|
||||
problem: i.pid.toString(),
|
||||
verdict: STATUS_SHORT_TEXTS[i.status],
|
||||
time: time(i.rid),
|
||||
@@ -134,6 +134,11 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
async display({ tdoc }) {
|
||||
if (!this.user.own(tdoc)) this.checkPerm(PERM.PERM_EDIT_CONTEST);
|
||||
if (!ContestModel.isDone(tdoc)) throw new ContestNotEndedError();
|
||||
try {
|
||||
new URL(SystemModel.get('server.url')); // eslint-disable-line no-new
|
||||
} catch (e) {
|
||||
throw new BadRequestError('Server URL not set');
|
||||
}
|
||||
let token = 0;
|
||||
const getFeed = (type: string, data: any) => ({
|
||||
type, id: data.id, data, token: `t${token++}`,
|
||||
@@ -146,7 +151,7 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
const teams = tsdocs.map((i) => {
|
||||
const udoc = udict[i.uid];
|
||||
return {
|
||||
team_id: `team-${udoc._id}`,
|
||||
team_id: udoc.seat || `team-${udoc._id}`,
|
||||
name: udoc.uname,
|
||||
displayName: (i.unrank ? '⭐' : '') + (udoc.displayName || udoc.uname),
|
||||
organization: udoc.school || udoc.uname,
|
||||
@@ -239,6 +244,13 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
}],
|
||||
logo: [{
|
||||
href: new URL(i.avatar, SystemModel.get('server.url')).toString(),
|
||||
filename: 'logo.webp',
|
||||
mime: 'image/webp',
|
||||
width: 128,
|
||||
height: 128,
|
||||
}],
|
||||
})),
|
||||
...tdoc.pids.map((i, idx) => getFeed('problems', {
|
||||
id: `${i}`,
|
||||
@@ -265,7 +277,7 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
const judgeAt = moment().startOf('day').seconds(judgeDelta).format('HH:mm:ss.SSS');
|
||||
result.push(getFeed('submissions', {
|
||||
id: s.rid,
|
||||
team_id: `team-${i.uid}`,
|
||||
team_id: udict[i.uid]?.seat || `team-${i.uid}`,
|
||||
problem_id: `${s.pid}`,
|
||||
language_id: s.lang?.split('.')[0] || 'cpp',
|
||||
files: [],
|
||||
@@ -305,13 +317,13 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
]);
|
||||
await Promise.all(teams.map(async (i) => {
|
||||
await zip.add(`teams/${i.team_id}/`, null, { directory: true });
|
||||
await zip.add(`teams/${i.team_id}/photo.download.txt`, new Zip.TextReader(i.avatar));
|
||||
await zip.add(`teams/${i.team_id}/photo.url`, new Zip.TextReader(`URL=${i.avatar}`));
|
||||
}));
|
||||
await Promise.all(organizations.map(async (i) => {
|
||||
const avatarSrc = teams.find((j) => j.organization === i)?.avatar;
|
||||
if (!avatarSrc) return;
|
||||
await zip.add(`organizations/${orgId[i]}/`, null, { directory: true });
|
||||
await zip.add(`organizations/${orgId[i]}/photo.download.txt`, new Zip.TextReader(avatar(avatarSrc)));
|
||||
await zip.add(`organizations/${orgId[i]}/photo.url`, new Zip.TextReader(`URL=${avatar(avatarSrc)}`));
|
||||
}));
|
||||
this.binary(await zip.close(), `contest-${tdoc._id}-cdp.zip`);
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"repository": "https://github.com/hydro-dev/Hydro",
|
||||
"dependencies": {
|
||||
"@react-spring/web": "^10.0.3",
|
||||
"lru-cache": "^11.2.2",
|
||||
"lru-cache": "^11.2.4",
|
||||
"react-use": "^17.6.0"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import path from 'path';
|
||||
import { LRUCache } from 'lru-cache';
|
||||
import {
|
||||
avatar, ContestModel, Context, fs, getAlphabeticId, ObjectId, PERM,
|
||||
RecordDoc, Schema, STATUS, Tdoc, Types, UserModel,
|
||||
avatar, ContestModel, Context, fs, getAlphabeticId, Logger, ObjectId,
|
||||
PERM, RecordDoc, Schema, STATUS, superagent, Tdoc, Types, UserModel,
|
||||
} from 'hydrooj';
|
||||
|
||||
const logger = new Logger('scoreboard-xcpcio');
|
||||
|
||||
const file = fs.readFileSync(path.join(__dirname, 'public/assets/board.html'), 'utf8');
|
||||
const indexJs = file.match(/index-([\w-]+)\.js"/)?.[1];
|
||||
const indexCss = file.match(/index-([\w-]+)\.css"/)?.[1];
|
||||
@@ -88,11 +90,28 @@ async function loadContestState(tdoc: Tdoc, realtime: boolean) {
|
||||
}
|
||||
|
||||
export const name = 'scoreboard-xcpcio';
|
||||
|
||||
const PublishConfig = Schema.object({
|
||||
domainId: Schema.string().required(),
|
||||
contestId: Schema.string().required(),
|
||||
publishToken: Schema.string().required(),
|
||||
publishPath: Schema.string().required(),
|
||||
publishEndpoint: Schema.string().default('https://scoreboard.hydrooj.com/_publish'),
|
||||
medals: Schema.object({
|
||||
gold: Schema.number().required(),
|
||||
silver: Schema.number().required(),
|
||||
bronze: Schema.number().required(),
|
||||
}),
|
||||
banner: Schema.string().default(''),
|
||||
badge: Schema.boolean().default(false),
|
||||
override: Schema.any().default({}).description('Scoreboard contest override'),
|
||||
});
|
||||
export const Config = Schema.object({
|
||||
cacheTTL: Schema.number().default(0).description('Cache TTL in milliseconds'),
|
||||
cacheSize: Schema.number().default(100).description('Cache size'),
|
||||
asDefault: Schema.boolean().default(false).description('As default scoreboard'),
|
||||
override: Schema.any().default({}).description('Scoreboard contest override'),
|
||||
publish: Schema.array(PublishConfig).description('Scoreboard publish config'),
|
||||
});
|
||||
|
||||
export async function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
@@ -138,6 +157,80 @@ export async function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
});
|
||||
}
|
||||
|
||||
const getJson = async (tdoc, realtime: boolean, cfg: Partial<ReturnType<typeof PublishConfig>>) => {
|
||||
const isLocked = ContestModel.isLocked(tdoc);
|
||||
const cacheKey = `${tdoc.docId.toHexString()}/${(isLocked && realtime) ? 'realtime' : 'public'}`;
|
||||
const state = lru.get(cacheKey) || await loadContestState(tdoc, realtime);
|
||||
if (cfg.cacheTTL) lru.set(cacheKey, state);
|
||||
const relatedGroups = state.teams.flatMap((i) => i.group);
|
||||
return {
|
||||
contest: {
|
||||
contest_name: tdoc.title,
|
||||
start_time: Math.floor(tdoc.beginAt.getTime() / 1000),
|
||||
end_time: Math.floor(tdoc.endAt.getTime() / 1000),
|
||||
frozen_time: tdoc.lockAt ? Math.floor((tdoc.endAt.getTime() - tdoc.lockAt.getTime()) / 1000) : 0,
|
||||
penalty: 1200,
|
||||
problem_quantity: tdoc.pids.length,
|
||||
problem_id: tdoc.pids.map((i, idx) => getAlphabeticId(idx)),
|
||||
group: {
|
||||
official: '正式队伍',
|
||||
unofficial: '打星队伍',
|
||||
...Object.fromEntries(cfg.groups?.filter((i) => relatedGroups.includes(i.name)).map((i) => [i.name, i.name]) || []),
|
||||
},
|
||||
...(cfg.badge ? { badge: 'Badge' } : {}),
|
||||
organization: 'School',
|
||||
status_time_display: {
|
||||
correct: true,
|
||||
incorrect: true,
|
||||
pending: true,
|
||||
},
|
||||
medal: {
|
||||
official: cfg.medals,
|
||||
},
|
||||
balloon_color: tdoc.balloon
|
||||
? tdoc.pids.filter((i) => tdoc.balloon[i]).map((i) => ({
|
||||
color: '#000',
|
||||
background_color: typeof tdoc.balloon[i] === 'string' ? tdoc.balloon[i] : tdoc.balloon[i].color,
|
||||
}))
|
||||
: [],
|
||||
logo: {
|
||||
preset: 'ICPC',
|
||||
},
|
||||
...(cfg.banner ? { banner: { url: 'banner.jpg' } } : {}),
|
||||
options: {
|
||||
submission_timestamp_unit: 'millisecond',
|
||||
},
|
||||
...(typeof cfg.override === 'object' ? cfg.override || {} : {}),
|
||||
},
|
||||
...state,
|
||||
};
|
||||
};
|
||||
|
||||
if (config.publish?.length && process.env.NODE_APP_INSTANCE === '0') {
|
||||
const done = [];
|
||||
const unlocked = [];
|
||||
logger.debug('Will publish scoreboards', config.publish);
|
||||
ctx.effect(() => ctx.setInterval(() => {
|
||||
Promise.allSettled(config.publish.map(async (i) => {
|
||||
const key = `${i.domainId}/${i.contestId}`;
|
||||
if (unlocked.includes(key)) return;
|
||||
const tdoc = await ContestModel.get(i.domainId, new ObjectId(i.contestId));
|
||||
if (ContestModel.isDone(tdoc) && ContestModel.isLocked(tdoc) && done.includes(key)) return;
|
||||
if (ContestModel.isDone(tdoc) && !ContestModel.isLocked(tdoc)) unlocked.push(key);
|
||||
if (ContestModel.isDone(tdoc)) done.push(key);
|
||||
const groups = await UserModel.listGroup(i.domainId);
|
||||
const json = await getJson(tdoc, false, { ...i, groups });
|
||||
logger.info(`Publishing scoreboard ${i.domainId}/${i.contestId} to ${i.publishEndpoint}`);
|
||||
const res = await superagent.post(i.publishEndpoint).send({
|
||||
path: i.publishPath,
|
||||
token: i.publishToken,
|
||||
json,
|
||||
});
|
||||
logger.info(`Published scoreboard ${i.domainId}/${i.contestId} to ${i.publishEndpoint}`, res.body);
|
||||
})).catch(console.error);
|
||||
}, 30000));
|
||||
}
|
||||
|
||||
ctx.inject(['scoreboard'], ({ scoreboard }) => {
|
||||
scoreboard.addView('xcpcio', 'XCPCIO', {
|
||||
tdoc: 'tdoc',
|
||||
@@ -155,56 +248,7 @@ export async function apply(ctx: Context, config: ReturnType<typeof Config>) {
|
||||
}) {
|
||||
if (realtime && !this.user.own(tdoc)) this.checkPerm(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
|
||||
if (json || this.request.json) {
|
||||
const isLocked = ContestModel.isLocked(tdoc);
|
||||
const cacheKey = `${tdoc.docId.toHexString()}/${(isLocked && realtime) ? 'realtime' : 'public'}`;
|
||||
const state = lru.get(cacheKey) || await loadContestState(tdoc, realtime);
|
||||
if (config.cacheTTL) lru.set(cacheKey, state);
|
||||
const relatedGroups = state.teams.flatMap((i) => i.group);
|
||||
this.response.body = {
|
||||
contest: {
|
||||
contest_name: tdoc.title,
|
||||
start_time: Math.floor(tdoc.beginAt.getTime() / 1000),
|
||||
end_time: Math.floor(tdoc.endAt.getTime() / 1000),
|
||||
frozen_time: tdoc.lockAt ? Math.floor((tdoc.endAt.getTime() - tdoc.lockAt.getTime()) / 1000) : 0,
|
||||
penalty: 1200,
|
||||
problem_quantity: tdoc.pids.length,
|
||||
problem_id: tdoc.pids.map((i, idx) => getAlphabeticId(idx)),
|
||||
group: {
|
||||
official: '正式队伍',
|
||||
unofficial: '打星队伍',
|
||||
...Object.fromEntries(groups.filter((i) => relatedGroups.includes(i.name)).map((i) => [i.name, i.name])),
|
||||
},
|
||||
...(badge ? { badge: 'Badge' } : {}),
|
||||
organization: 'School',
|
||||
status_time_display: {
|
||||
correct: true,
|
||||
incorrect: true,
|
||||
pending: true,
|
||||
},
|
||||
medal: {
|
||||
official: {
|
||||
gold,
|
||||
silver,
|
||||
bronze,
|
||||
},
|
||||
},
|
||||
balloon_color: tdoc.balloon
|
||||
? tdoc.pids.filter((i) => tdoc.balloon[i]).map((i) => ({
|
||||
color: '#000',
|
||||
background_color: typeof tdoc.balloon[i] === 'string' ? tdoc.balloon[i] : tdoc.balloon[i].color,
|
||||
}))
|
||||
: [],
|
||||
logo: {
|
||||
preset: 'ICPC',
|
||||
},
|
||||
...(banner ? { banner: { url: 'banner.jpg' } } : {}),
|
||||
options: {
|
||||
submission_timestamp_unit: 'millisecond',
|
||||
},
|
||||
...(typeof config.override === 'object' ? config.override || {} : {}),
|
||||
},
|
||||
...state,
|
||||
};
|
||||
this.response.body = await getJson(tdoc, realtime, { badge, banner, groups, medals: { gold, silver, bronze } });
|
||||
} else {
|
||||
this.response.template = 'xcpcio_board.html';
|
||||
let query = '';
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@hydrooj/scoreboard-xcpcio",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"version": "0.0.5-beta.7",
|
||||
"version": "0.0.5-beta.8",
|
||||
"main": "index.ts",
|
||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||
"scripts": {
|
||||
"postinstall": "node -r @hydrooj/register install.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@xcpcio/board-app": "^0.75.1"
|
||||
"@xcpcio/board-app": "^0.76.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@xcpcio/types": "^0.75.1"
|
||||
"@xcpcio/types": "^0.76.0"
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
window.DATA_REGION = "Hydro";
|
||||
window.DEFAULT_LANG = "{{ 'zh-CN' if _('__id').startsWith('zh') else 'en' }}";
|
||||
window.DATA_SOURCE = "{{ dataSource|safe }}";
|
||||
{% if refreshInterval %}window.REFRESH_INTERVAL = {{ refreshInterval }};{% endif %}
|
||||
if (document.documentElement.classList.contains("theme--dark")) document.documentElement.classList.toggle("dark", !0);
|
||||
setInterval(() => {
|
||||
const location = window.location.href;
|
||||
@@ -30,7 +31,7 @@
|
||||
</style>
|
||||
<script type="module" crossorigin src="{{ '/' if process.env.DEV else UiContext.cdn_prefix }}assets/index-{{ js }}.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="{{ '/' if process.env.DEV else UiContext.cdn_prefix }}assets/index-{{ css }}.css">
|
||||
{% if realtime and model.contest.isLocked(tdoc) and model.contest.isDone(tdoc) and handler.user.own(tdoc) %}
|
||||
{% if tdoc and realtime and model.contest.isLocked(tdoc) and model.contest.isDone(tdoc) and handler.user.own(tdoc) %}
|
||||
<div class="main">
|
||||
<div class="row typo">
|
||||
<blockquote class="note">
|
||||
|
||||
@@ -587,6 +587,7 @@ My Files: 我的文件
|
||||
My Profile: 我的资料
|
||||
My Recent Submissions: 我的最近递交记录
|
||||
My Role: 我的角色
|
||||
My Submissions: 我的递交
|
||||
name: 名称
|
||||
Name: 名称
|
||||
Nav Logo Dark: 左上角小图标(暗)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"@mantine/core": "^8.3.9",
|
||||
"@mantine/hooks": "^8.3.9",
|
||||
"@mantine/notifications": "^8.3.9",
|
||||
"@sentry/browser": "^10.26.0",
|
||||
"@sentry/browser": "^10.27.0",
|
||||
"@sentry/webpack-plugin": "^4.6.1",
|
||||
"@simplewebauthn/browser": "13.2.2",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
@@ -36,7 +36,7 @@
|
||||
"@types/nunjucks": "^3.2.6",
|
||||
"@types/pickadate": "^3.5.35",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"@types/react": "^19.2.6",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@types/redux-logger": "^3.0.13",
|
||||
"@types/uuid": "^11.0.0",
|
||||
@@ -75,7 +75,7 @@
|
||||
"monaco-editor": "0.52.2",
|
||||
"monaco-editor-nls": "^3.1.0",
|
||||
"monaco-editor-webpack-plugin": "^7.1.1",
|
||||
"monaco-themes": "^0.4.7",
|
||||
"monaco-themes": "0.4.7",
|
||||
"monaco-yaml": "5.1.1",
|
||||
"nanoid": "^5.1.6",
|
||||
"normalize.css": "^8.0.1",
|
||||
|
||||
@@ -38,7 +38,7 @@ const page = new NamedPage('domain_user', () => {
|
||||
options: UiContext.roles.filter((i) => !['default', 'guest'].includes(i)),
|
||||
columns: -6,
|
||||
},
|
||||
...(UiContext.canForceJoin ? {
|
||||
...((UiContext.canForceJoin && UiContext.domain._id !== 'system') ? {
|
||||
join: {
|
||||
type: 'checkbox',
|
||||
label: i18n('Mark user as joined using admin privilege'),
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<span style="color: #66d9ef">return</span> <span style="color: #ae81ff">0</span><span style="color: #f8f8f2">;</span>
|
||||
<span style="color: #f8f8f2">}</span>
|
||||
<span style="color: #75715e">/*</span>
|
||||
<span style="color: #75715e">{{ handler.request.hostname }}{{ handler.request.originalPath|default(handler.request.path) }}</span>
|
||||
<span style="color: #75715e">{{ error.message }}</span>
|
||||
<span style="color: #75715e">{{ error.stack }}</span>
|
||||
<span style="color: #75715e">*/</span>
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
"react-dom": "^19.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.6",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react-swc": "^4.2.2",
|
||||
"vite": "^7.2.4"
|
||||
"vite": "^7.2.6"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user