From 84d69bc348982886b186774cd25441e7c0b22778 Mon Sep 17 00:00:00 2001 From: panda Date: Mon, 25 Apr 2022 22:26:08 +0800 Subject: [PATCH] core&ui: add language filter (#346) --- packages/hydrooj/src/handler/record.ts | 6 +++- .../scratchpad/ScratchpadToolbarContainer.jsx | 22 +++++-------- packages/ui-default/locales/zh.yaml | 2 ++ .../ui-default/pages/problem_submit.page.js | 11 +++---- packages/ui-default/pages/record_main.page.ts | 7 +++++ .../ui-default/templates/record_main.html | 31 +++++++++++-------- packages/ui-default/utils/avaliableLangs.ts | 12 +++++++ 7 files changed, 57 insertions(+), 34 deletions(-) create mode 100644 packages/ui-default/utils/avaliableLangs.ts diff --git a/packages/hydrooj/src/handler/record.ts b/packages/hydrooj/src/handler/record.ts index fee58172c..f766aa428 100644 --- a/packages/hydrooj/src/handler/record.ts +++ b/packages/hydrooj/src/handler/record.ts @@ -25,12 +25,14 @@ class RecordListHandler extends Handler { @param('pid', Types.Name, true) @param('tid', Types.ObjectID, true) @param('uidOrName', Types.Name, true) + @param('lang', Types.String, true) @param('status', Types.Int, true) @param('fullStatus', Types.Boolean) @param('allDomain', Types.Boolean, true) async get( domainId: string, page = 1, pid?: string, tid?: ObjectID, - uidOrName?: string, status?: number, full = false, all = false, + uidOrName?: string, lang?: string, status?: number, full = false, + all = false, ) { let tdoc = null; let invalid = false; @@ -60,6 +62,7 @@ class RecordListHandler extends Handler { if (pdoc) q.pid = pdoc.docId; else invalid = true; } + if (lang) q.lang = lang; if (status) q.status = status; if (all) { this.checkPriv(PRIV.PRIV_MANAGE_ALL_DOMAIN); @@ -90,6 +93,7 @@ class RecordListHandler extends Handler { filterPid: pid, filterTid: tid, filterUidOrName: uidOrName, + filterLang: lang, filterStatus: status, }; if (this.user.hasPriv(PRIV.PRIV_VIEW_JUDGE_STATISTICS) && !full) { diff --git a/packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx b/packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx index 536054e20..d9035b83d 100644 --- a/packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx +++ b/packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx @@ -7,6 +7,7 @@ import { connect } from 'react-redux'; import i18n from 'vj/utils/i18n'; import request from 'vj/utils/request'; import Icon from 'vj/components/react/IconComponent'; +import getAvaliableLangs from 'vj/utils/avaliableLangs'; import Toolbar, { ToolbarItemComponent as ToolbarItem, ToolbarButtonComponent as ToolbarButton, @@ -66,15 +67,8 @@ const mapDispatchToProps = (dispatch) => ({ }, }); -const LANGS = {}; -const prefix = new Set(Object.keys(window.LANGS).filter((i) => i.includes('.')).map((i) => i.split('.')[0])); -for (const key in window.LANGS) { - if (prefix.has(key)) continue; - if (UiContext.pdoc.config.langs && !UiContext.pdoc.config.langs.includes(key)) continue; - if (window.LANGS[key].hidden && !UiContext.pdoc.config.langs?.includes(key)) continue; - LANGS[key] = window.LANGS[key]; -} -const keys = Object.keys(LANGS); +const avaliableLangs = getAvaliableLangs(UiContext.pdoc.config.langs); +const keys = Object.keys(avaliableLangs); export default connect(mapStateToProps, mapDispatchToProps)(class ScratchpadToolbarContainer extends React.PureComponent { static contextTypes = { @@ -83,10 +77,10 @@ export default connect(mapStateToProps, mapDispatchToProps)(class ScratchpadTool constructor(props) { super(props); - if (!LANGS[this.props.editorLang]) { + if (!avaliableLangs[this.props.editorLang]) { // preference not allowed - const key = keys.find((i) => LANGS[i].pretest === this.props.editorLang); - this.props.setEditorLanguage(key || Object.keys(LANGS)[0]); + const key = keys.find((i) => avaliableLangs[i].pretest === this.props.editorLang); + this.props.setEditorLanguage(key || keys[0]); } } @@ -97,9 +91,9 @@ export default connect(mapStateToProps, mapDispatchToProps)(class ScratchpadTool render() { let canUsePretest = ['default', 'fileio'].includes(UiContext.pdoc.config?.type); if (UiContext.pdoc.config?.type === 'remote_judge') { - if (window.LANGS[this.props.editorLang].pretest) canUsePretest = true; + if (avaliableLangs[this.props.editorLang].pretest) canUsePretest = true; } - if (window.LANGS[this.props.editorLang].pretest === false) canUsePretest = false; + if (avaliableLangs[this.props.editorLang].pretest === false) canUsePretest = false; return ( {canUsePretest && ( diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index 93066ae16..429064326 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -68,6 +68,7 @@ Add: 添加 All {0} Contests: 所有 {0} 比赛 All Contests: 所有比赛 All Homeworks: 所有作业 +All Languages: 所有语言 All Submissions: 所有递交 All Training Plans: 所有训练计划 All: 全部 @@ -100,6 +101,7 @@ Built-in: 内置 Bulletin: 公告 By clicking the button, you will become a member of the domain {0}.: 点击按钮,您将成为域 {0} 的成员。 By Contest: 由比赛 +By Language: 由语言 By Problem: 由题目 By signing up a {0} universal account, you can submit code and join discussions in all online judging services provided by us.: 注册一个 {0} 通用账户,您就可以在我们提供的所有在线评测服务上提交代码、参与讨论。 By Status: 由状态 diff --git a/packages/ui-default/pages/problem_submit.page.js b/packages/ui-default/pages/problem_submit.page.js index 019e0115d..ee170c422 100644 --- a/packages/ui-default/pages/problem_submit.page.js +++ b/packages/ui-default/pages/problem_submit.page.js @@ -1,4 +1,5 @@ import { NamedPage } from 'vj/misc/Page'; +import getAvaliableLangs from 'vj/utils/avaliableLangs'; function setOptions($el, options) { $el.empty(); @@ -9,13 +10,12 @@ function setOptions($el, options) { const page = new NamedPage(['problem_submit', 'contest_detail_problem_submit', 'homework_detail_problem_submit'], async () => { const { config } = UiContext.pdoc; + const avaliableLangs = getAvaliableLangs(config.langs); function onChangeMain(update = true) { const options = {}; - for (const key in window.LANGS) { - if (config.langs && !config.langs.includes(key)) continue; - if (window.LANGS[key].hidden && !config.langs?.includes(key)) continue; - if (key.startsWith(`${this.value}.`) && key !== this.value) options[key] = window.LANGS[key].display; + for (const key in avaliableLangs) { + if (key.startsWith(`${this.value}.`) && key !== this.value) options[key] = avaliableLangs[key].display; } setOptions($('#codelang-sub-select'), options); if (Object.keys(options).length) { @@ -28,9 +28,8 @@ const page = new NamedPage(['problem_submit', 'contest_detail_problem_submit', ' return Object.keys(options)[0]; } const main = {}; - for (const key in window.LANGS) { + for (const key in avaliableLangs) { if (config.langs && !config.langs.filter((i) => i === key || i.startsWith(`${key}.`)).length) continue; - if (window.LANGS[key].hidden && !config.langs?.includes(key)) continue; if (!key.includes('.')) main[key] = window.LANGS[key].display; else { const a = key.split('.')[0]; diff --git a/packages/ui-default/pages/record_main.page.ts b/packages/ui-default/pages/record_main.page.ts index 023ddc6c0..f7a61f709 100644 --- a/packages/ui-default/pages/record_main.page.ts +++ b/packages/ui-default/pages/record_main.page.ts @@ -1,6 +1,8 @@ import { NamedPage } from 'vj/misc/Page'; import UserSelectAutoComplete from 'vj/components/autocomplete/UserSelectAutoComplete'; import ProblemSelectAutoComplete from 'vj/components/autocomplete/ProblemSelectAutoComplete'; +import tpl from 'vj/utils/tpl'; +import getAvaliableLangs from 'vj/utils/avaliableLangs'; const page = new NamedPage('record_main', async () => { const [{ default: SockJs }, { DiffDOM }] = await Promise.all([ @@ -36,6 +38,11 @@ const page = new NamedPage('record_main', async () => { ProblemSelectAutoComplete.getOrConstruct($('[name="pid"]'), { clearDefaultValue: false, }); + const avaliableLangs = getAvaliableLangs(UiContext.domain.langs?.split(',')); + Object.keys(avaliableLangs).map( + (i) => ($('select[name="lang"]').append(tpl``))); + const lang = new URL(window.location.href).searchParams.get('lang'); + if (lang) $('select[name="lang"]').val(lang); }); export default page; diff --git a/packages/ui-default/templates/record_main.html b/packages/ui-default/templates/record_main.html index 6209b0474..09f96ee03 100644 --- a/packages/ui-default/templates/record_main.html +++ b/packages/ui-default/templates/record_main.html @@ -22,37 +22,41 @@
-
+
-
+
-
+
+
+ + +
@@ -61,12 +65,12 @@
- {% if not rdocs %} + {% if not rdocs.length %} {% if not filterUidOrName and not filterPid and not filterTid %} {{ nothing.render('Oh, there is no task in the queue!') }} {% else %} {{ nothing.render('Oh, there is no task that matches the filter!') }} - {% endif%} + {% endif %} {% else %} @@ -103,6 +107,7 @@ diff --git a/packages/ui-default/utils/avaliableLangs.ts b/packages/ui-default/utils/avaliableLangs.ts new file mode 100644 index 000000000..ca916897b --- /dev/null +++ b/packages/ui-default/utils/avaliableLangs.ts @@ -0,0 +1,12 @@ +const prefixes = new Set(Object.keys(LANGS).filter((i) => i.includes('.')).map((i) => i.split('.')[0])); + +export default function getAvaliableLangs(langsList?: string[]) { + const Langs = {}; + for (const key in LANGS) { + if (prefixes.has(key)) continue; + if (langsList && !langsList.includes(key)) continue; + if (LANGS[key].hidden && !langsList?.includes(key)) continue; + Langs[key] = LANGS[key]; + } + return Langs; +}