From ab3cad57b89495af197495a3928b7547baf89b9a Mon Sep 17 00:00:00 2001 From: undefined Date: Tue, 15 Mar 2022 13:59:16 +0800 Subject: [PATCH] ui: pageLoader: support moduleName --- packages/hydrooj/src/model/opcount.ts | 6 ++-- .../components/scratchpad/reducers/ui.js | 7 ++-- packages/ui-default/hydro.ts | 17 +++++++--- packages/ui-default/misc/Page.ts | 33 +++++++++++++------ packages/ui-default/misc/PageLoader.js | 24 +++++++------- packages/ui-default/package.json | 2 +- 6 files changed, 56 insertions(+), 33 deletions(-) diff --git a/packages/hydrooj/src/model/opcount.ts b/packages/hydrooj/src/model/opcount.ts index e22b05775..bfbd8da4b 100644 --- a/packages/hydrooj/src/model/opcount.ts +++ b/packages/hydrooj/src/model/opcount.ts @@ -8,16 +8,18 @@ export async function inc(op: string, ident: string, periodSecs: number, maxOper const now = new Date().getTime(); const expireAt = new Date(now - (now % (periodSecs * 1000)) + periodSecs * 1000); try { - await coll.findOneAndUpdate({ + const res = await coll.findOneAndUpdate({ op, ident, expireAt, opcount: { $lt: maxOperations }, - }, { $inc: { opcount: 1 } }, { upsert: true }); + }, { $inc: { opcount: 1 } }, { upsert: true, returnDocument: 'after' }); + return res.value.opcount; } catch (e) { if (e.message.includes('duplicate')) throw new OpcountExceededError(op, periodSecs, maxOperations); throw e; } + return -1; } bus.once('app/started', () => db.ensureIndexes( diff --git a/packages/ui-default/components/scratchpad/reducers/ui.js b/packages/ui-default/components/scratchpad/reducers/ui.js index 6836fd07f..aa144e751 100644 --- a/packages/ui-default/components/scratchpad/reducers/ui.js +++ b/packages/ui-default/components/scratchpad/reducers/ui.js @@ -55,16 +55,15 @@ export default function reducer(state = { case 'SCRATCHPAD_POST_SUBMIT_PENDING': { return { ...state, - records: { - ...state.records, - visible: true, - }, isPosting: true, }; } case 'SCRATCHPAD_POST_PRETEST_FULFILLED': case 'SCRATCHPAD_POST_SUBMIT_FULFILLED': { Notification.success(i18n('Submitted.')); + if (action.type === 'SCRATCHPAD_POST_SUBMIT_FULFILLED') { + state.records.visible = true; + } return { ...state, isPosting: false, diff --git a/packages/ui-default/hydro.ts b/packages/ui-default/hydro.ts index bafb7ba89..eb711fa6b 100644 --- a/packages/ui-default/hydro.ts +++ b/packages/ui-default/hydro.ts @@ -50,10 +50,19 @@ async function load() { ...buildSequence(includedPages, 'after'), ...buildSequence(currentPage, 'after'), ]; + const loadPage = (depth: number, type: 'before' | 'after') => async (name: string) => { + if (depth > 32) { + console.error('loadPage depth', depth); + return; + } + for (const { func } of buildSequence(pageLoader.getPage(name), type)) { + await func(name, loadPage(depth + 1, type)); + } + }; for (const { page, func, type } of loadSequence) { - const ts = new Date().getTime(); + const ts = Date.now(); try { - await func(currentPageName); + await func(currentPageName, loadPage(1, type)); } catch (e) { Notification.warn(`Failed to call '${type}Loading' of ${page.name}`); console.error(`Failed to call '${type}Loading' of ${page.name}\n${e.stack}`); @@ -61,7 +70,7 @@ async function load() { if (process.env.NODE_ENV !== 'production') { console.time(`${page.name}: ${type}Loading`); } - const time = new Date().getTime() - ts; + const time = Date.now() - ts; if ((process.env.NODE_ENV !== 'production' && time > 16) || time > 256) { console.log(`${page.name}: ${type}Loading took ${time}ms`); } @@ -71,7 +80,7 @@ async function load() { $element: $(section), })); $('.page-loader').hide(); - console.log('done! %d ms', new Date().getTime() - start.getTime()); + console.log('done! %d ms', Date.now() - start.getTime()); for (const { $element, shouldDelay } of sections) { $element.addClass('visible'); if (shouldDelay) await delay(50); diff --git a/packages/ui-default/misc/Page.ts b/packages/ui-default/misc/Page.ts index d1854ae67..eba669153 100644 --- a/packages/ui-default/misc/Page.ts +++ b/packages/ui-default/misc/Page.ts @@ -1,15 +1,29 @@ +type callback = (pagename: string, loadPage: (name: string) => Promise) => any; + export class Page { - constructor(public name: string | string[], public autoload: boolean, public afterLoading, public beforeLoading) { + moduleName?: string; + autoload = false; + afterLoading?: callback; + beforeLoading?: callback; + constructor(pagename: string | string[], afterLoading: callback, beforeLoading: callback); + constructor(pagename: string | string[], moduleName: string, afterLoading: callback, beforeLoading: callback); + constructor(pagename: string | string[], ...args: any[]); + constructor(public name: string | string[], ...args: any[]) { + if (typeof args[0] === 'string') { + [this.moduleName, this.afterLoading, this.beforeLoading] = args; + } else { + [this.afterLoading, this.beforeLoading] = args; + } if (process.env.NODE_ENV !== 'production') { if (typeof name !== 'string' && !(name instanceof Array)) { // eslint-disable-next-line quotes throw new Error(`'name' should be a string or string[]`); } - if (typeof afterLoading !== 'function' && afterLoading != null) { + if (typeof this.afterLoading !== 'function' && this.afterLoading != null) { // eslint-disable-next-line quotes throw new Error(`'afterLoading' should be a function`); } - if (typeof beforeLoading !== 'function' && beforeLoading != null) { + if (typeof this.beforeLoading !== 'function' && this.beforeLoading != null) { // eslint-disable-next-line quotes throw new Error(`'beforeLoading' should be a function`); } @@ -23,15 +37,14 @@ export class Page { } } -export class NamedPage extends Page { - constructor(name: string | string[], afterLoading: (pagename: string) => any = null, beforeLoading = null) { - super(name, false, afterLoading, beforeLoading); - } -} +export class NamedPage extends Page { } export class AutoloadPage extends Page { - constructor(name: string | string[], afterLoading: (pagename: string) => any = null, beforeLoading = null) { - super(name, true, afterLoading, beforeLoading); + constructor(pagename: string | string[], afterLoading: callback, beforeLoading: callback); + constructor(pagename: string | string[], moduleName: string, afterLoading: callback, beforeLoading: callback); + constructor(pagename: string | string[], ...args: any[]) { + super(pagename, ...args); + this.autoload = true; } } diff --git a/packages/ui-default/misc/PageLoader.js b/packages/ui-default/misc/PageLoader.js index fd9ea07bf..cec650cc0 100644 --- a/packages/ui-default/misc/PageLoader.js +++ b/packages/ui-default/misc/PageLoader.js @@ -5,18 +5,14 @@ export default class PageLoader { const pages = require.context('../pages/', true, /\.page\.[jt]sx?$/i); const components = require.context('../components/', true, /\.page\.[jt]sx?$/i); this.pageInstances = [ - ...pages.keys().map((key) => { - const page = pages(key).default; - if (!page || !(page instanceof Page)) return null; - return page; - }), - ...components.keys().map((key) => { - const page = components(key).default; - if (!page || !(page instanceof Page)) return null; - return page; - }), - ]; - if (window.Hydro.extraPages) this.pageInstances.push(...window.Hydro.extraPages.filter((i) => i instanceof Page)); + ...pages.keys().map((key) => pages(key)), + ...components.keys().map((key) => components(key)), + ...window.Hydro.extraPages, + ].map((page) => { + page = page?.default || page; + if (!page || !(page instanceof Page)) return null; + return page; + }).filter((i) => i); window.Hydro.pageInstances = this.pageInstances; window.Hydro.extraPages.filter((i) => !(i instanceof Page)).forEach((i) => i()); } @@ -28,4 +24,8 @@ export default class PageLoader { getNamedPage(pageName) { return this.pageInstances.filter((page) => page && page.isNameMatch(pageName)); } + + getPage(moduleName) { + return this.pageInstances.filter((page) => page && page.moduleName === moduleName); + } } diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index b9307faa6..a0557a92c 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.34.5", + "version": "4.34.6", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js",