mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
core&ui: fix sidebar preview (#491)
Co-authored-by: panda <panda_dtdyy@outlook.com>
This commit is contained in:
1 parent
feb3b5cecb
commit
feb5180476
19 files changed
+152
-244
No files matched your search
@@ -671,19 +671,23 @@ export class ProblemFilesHandler extends ProblemDetailHandler {
|
||||
@param('testdata', Types.Boolean)
|
||||
@param('additional_file', Types.Boolean)
|
||||
@param('pjax', Types.Boolean)
|
||||
async get(domainId: string, getTestdata = true, getAdditionalFile = true, pjax = false) {
|
||||
@param('sidebar', Types.Boolean)
|
||||
async get(domainId: string, getTestdata = true, getAdditionalFile = true, pjax = false, sidebar = false) {
|
||||
this.response.body.testdata = getTestdata ? sortFiles(this.pdoc.data || []) : [];
|
||||
this.response.body.reference = getTestdata ? this.pdoc.reference : '';
|
||||
this.response.body.additional_file = getAdditionalFile ? sortFiles(this.pdoc.additional_file || []) : [];
|
||||
if (pjax) {
|
||||
const { testdata, additional_file } = this.response.body;
|
||||
const owner = await user.getById(domainId, this.pdoc.owner);
|
||||
const args = {
|
||||
testdata, additional_file, pdoc: this.pdoc, owner_udoc: owner, sidebar,
|
||||
};
|
||||
const tasks = [];
|
||||
if (getTestdata) tasks.push(this.renderHTML('partials/problem_files.html', { ...args, filetype: 'testdata' }));
|
||||
if (getAdditionalFile) tasks.push(this.renderHTML('partials/problem_files.html', { ...args, filetype: 'additional_file' }));
|
||||
if (!sidebar) tasks.push(this.renderHTML('partials/problem-sidebar-information.html', args));
|
||||
this.response.body = {
|
||||
fragments: (await Promise.all([
|
||||
this.renderHTML('partials/problem_files-testdata.html', { testdata, pdoc: this.pdoc }),
|
||||
this.renderHTML('partials/problem_files-additional_file.html', { additional_file, pdoc: this.pdoc }),
|
||||
this.renderHTML('partials/problem-sidebar-information.html', { pdoc: this.pdoc, owner_udoc: owner }),
|
||||
])).map((i) => ({ html: i })),
|
||||
fragments: (await Promise.all(tasks)).map((i) => ({ html: i })),
|
||||
};
|
||||
this.response.template = '';
|
||||
} else this.response.template = 'problem_files.html';
|
||||
|
||||
@@ -64,7 +64,7 @@ export const Types: Types = {
|
||||
Float: [(v) => +v, (v) => Number.isFinite(+v)],
|
||||
// eslint-disable-next-line no-shadow
|
||||
ObjectID: [(v) => new ObjectID(v), ObjectID.isValid],
|
||||
Boolean: [(v) => !!v, null, true],
|
||||
Boolean: [(v) => v && !['false', 'off'].includes(v), null, true],
|
||||
Date: [
|
||||
(v) => {
|
||||
const d = v.split('-');
|
||||
|
||||
@@ -4,9 +4,8 @@ import { nanoid } from 'nanoid';
|
||||
import { ActionDialog, InfoDialog } from 'vj/components/dialog/index';
|
||||
import Notification from 'vj/components/notification';
|
||||
import { AutoloadPage } from 'vj/misc/Page';
|
||||
import {
|
||||
i18n, pjax, request, tpl,
|
||||
} from 'vj/utils';
|
||||
import { i18n, request, tpl } from 'vj/utils';
|
||||
import uploadFiles from '../upload';
|
||||
|
||||
async function startEdit(filename, value, fileCategory = 'file') {
|
||||
const { default: Editor } = await import('vj/components/editor/index');
|
||||
@@ -144,17 +143,17 @@ export async function previewFile(ev, type = '') {
|
||||
} else Notification.info(i18n('Loading editor...'));
|
||||
const val = await startEdit(filename, content, type || 'file');
|
||||
if (typeof val !== 'string') return null;
|
||||
Notification.info(i18n('Saving file...'));
|
||||
const data = new FormData();
|
||||
data.append('filename', filename);
|
||||
data.append('file', new Blob([val], { type: 'text/plain' }));
|
||||
if (type) data.append('type', type);
|
||||
data.append('operation', 'upload_file');
|
||||
const postUrl = !window.location.href.endsWith('/files')
|
||||
? `${window.location.href.substring(0, window.location.href.lastIndexOf('/'))}/files` : '';
|
||||
await request.postFile(postUrl, data);
|
||||
Notification.success(i18n('File saved.'));
|
||||
return pjax.request({ push: false });
|
||||
const file = new File([val], filename, { type: 'text/plain' });
|
||||
const endpoint = new URL(!window.location.href.endsWith('/files')
|
||||
? `${window.location.href.substring(0, window.location.href.lastIndexOf('/'))}/files` : '', window.location.href);
|
||||
const sidebarType = $(ev.currentTarget).closest('[data-fragment-id]').data('type');
|
||||
const sidebar = $(ev.currentTarget).closest('[data-fragment-id]').data('sidebar') !== undefined;
|
||||
await uploadFiles(endpoint.toString(), [file], {
|
||||
type: sidebarType || type,
|
||||
sidebar,
|
||||
pjax: true,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
const dataPreviewPage = new AutoloadPage('dataPreview', () => {
|
||||
|
||||
@@ -11,6 +11,7 @@ function onBeforeUnload(e) {
|
||||
interface UploadOptions {
|
||||
type?: string;
|
||||
pjax?: boolean;
|
||||
sidebar?: boolean;
|
||||
singleFileUploadCallback?: (file: File) => any;
|
||||
}
|
||||
export default async function uploadFiles(endpoint = '', files: File[] | FileList = [], options: UploadOptions = {}) {
|
||||
@@ -65,7 +66,12 @@ export default async function uploadFiles(endpoint = '', files: File[] | FileLis
|
||||
}
|
||||
window.removeEventListener('beforeunload', onBeforeUnload);
|
||||
Notification.success(i18n('File uploaded successfully.'));
|
||||
if (options.pjax) await pjax.request({ push: false });
|
||||
if (options.pjax) {
|
||||
let params = '';
|
||||
if (options.type) params += `?testdata=${options.type === 'testdata'}&additional_file=${options.type === 'additional_file'}`;
|
||||
if (options.sidebar) params += `${params ? '&' : '?'}sidebar=true`;
|
||||
await pjax.request({ push: false, url: `${endpoint}${params || ''}` });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
Notification.error(i18n('File upload failed: {0}', e.toString()));
|
||||
|
||||
@@ -68,6 +68,7 @@ Add module: 添加模块
|
||||
Add new data: 添加新数据
|
||||
Add User: 添加用户
|
||||
Add: 添加
|
||||
additional_file: 附加文件
|
||||
All {0} Contests: 所有 {0} 比赛
|
||||
All Contests: 所有比赛
|
||||
All Homeworks: 所有作业
|
||||
@@ -529,8 +530,7 @@ New file: 新文件
|
||||
New Password: 新密码
|
||||
New Training Plan: 新训练计划
|
||||
New: 创建
|
||||
No additional file at current: 当前没有附加文件
|
||||
No additional file at current.: 暂无附加文件。
|
||||
No {0} at current.: 当前没有{0}。
|
||||
No comments so far...: 目前还没有评论...
|
||||
no discussion yet...: 目前没有讨论…
|
||||
No Permission to Attend Contest: 您没有权限参加比赛
|
||||
@@ -814,6 +814,7 @@ Temporary session: 临时会话
|
||||
Terms of Service: 服务条款
|
||||
Test data comes from: 测试数据来自
|
||||
Testdata Config: 测试数据配置
|
||||
testdata: 测试数据
|
||||
Testdata: 测试数据
|
||||
Text: 文本
|
||||
The 'default' role applies to ALL REGISTERED USER.: default 角色作用于<b>所有已注册用户</b>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
.page--problem_config
|
||||
.section--problem-sidebar-testdata
|
||||
.problem-sidebar-testdata__detail
|
||||
max-height: 270px
|
||||
overflow-y: auto
|
||||
.problem-sidebar-testdata
|
||||
max-height: 270px
|
||||
overflow-y: auto
|
||||
|
||||
.col--size
|
||||
width: 80px
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { normalizeSubtasks, readSubtasksFromFiles, size } from '@hydrooj/utils/lib/common';
|
||||
import { normalizeSubtasks, readSubtasksFromFiles } from '@hydrooj/utils/lib/common';
|
||||
import type { SubtaskType } from 'hydrooj/src/interface';
|
||||
import $ from 'jquery';
|
||||
import yaml from 'js-yaml';
|
||||
@@ -11,7 +11,7 @@ import uploadFiles from 'vj/components/upload';
|
||||
import download from 'vj/components/zipDownloader';
|
||||
import { NamedPage } from 'vj/misc/Page';
|
||||
import {
|
||||
i18n, loadReactRedux, request, tpl,
|
||||
i18n, loadReactRedux, pjax, request, tpl,
|
||||
} from 'vj/utils';
|
||||
|
||||
const page = new NamedPage('problem_config', () => {
|
||||
@@ -25,6 +25,8 @@ const page = new NamedPage('problem_config', () => {
|
||||
await new Promise((resolve) => { input.onchange = resolve; });
|
||||
await uploadFiles('./files', input.files, {
|
||||
type: 'testdata',
|
||||
sidebar: true,
|
||||
pjax: true,
|
||||
singleFileUploadCallback: (file) => {
|
||||
reduxStore.dispatch({
|
||||
type: 'CONFIG_ADD_TESTDATA',
|
||||
@@ -34,13 +36,6 @@ const page = new NamedPage('problem_config', () => {
|
||||
size: file.size,
|
||||
},
|
||||
});
|
||||
$('.testdata-table tbody').append(
|
||||
$(tpl`<tr data-filename="${file.name}" data-size="${file.size.toString()}">
|
||||
<td class="col--name" title="${file.name}"><a href="./file/${file.name}?type=testdata">${file.name}</a></td>
|
||||
<td class="col--size">${size(file.size)}</td>
|
||||
<td class="col--operation"><a href="javascript:;" name="testdata__delete"><span class="icon icon-delete"></span></a></td>
|
||||
</tr>`),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -62,7 +57,7 @@ const page = new NamedPage('problem_config', () => {
|
||||
type: 'CONFIG_DELETE_TESTDATA',
|
||||
value: file,
|
||||
});
|
||||
$(ev.currentTarget).parent().parent().remove();
|
||||
await pjax.request({ url: './files?testdata=false&sidebar=true', push: false });
|
||||
} catch (error) {
|
||||
Notification.error(error.message);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { size } from '@hydrooj/utils/lib/common';
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
import { ConfirmDialog } from 'vj/components/dialog';
|
||||
@@ -9,7 +8,7 @@ import uploadFiles from 'vj/components/upload';
|
||||
import download from 'vj/components/zipDownloader';
|
||||
import { NamedPage } from 'vj/misc/Page';
|
||||
import {
|
||||
i18n, request, slideDown, slideUp, tpl,
|
||||
i18n, pjax, request, slideDown, slideUp, tpl,
|
||||
} from 'vj/utils';
|
||||
|
||||
const categories = {};
|
||||
@@ -197,15 +196,8 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => {
|
||||
await new Promise((resolve) => { input.onchange = resolve; });
|
||||
await uploadFiles('./files', input.files, {
|
||||
type: 'additional_file',
|
||||
singleFileUploadCallback: (file) => {
|
||||
$('.additionalfile-table tbody').append(
|
||||
$(tpl`<tr data-filename="${file.name}" data-size="${file.size.toString()}">
|
||||
<td class="col--name" title="${file.name}"><a href="./file/${file.name}?type=testdata">${file.name}</a></td>
|
||||
<td class="col--size">${size(file.size)}</td>
|
||||
<td class="col--operation"><a href="javascript:;" name="testdata__delete"><span class="icon icon-delete"></span></a></td>
|
||||
</tr>`),
|
||||
);
|
||||
},
|
||||
sidebar: true,
|
||||
pjax: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -222,7 +214,7 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => {
|
||||
type: 'additional_file',
|
||||
});
|
||||
Notification.success(i18n('File have been deleted.'));
|
||||
$(ev.currentTarget).parent().parent().remove();
|
||||
await pjax.request({ url: './files?testdata=false&sidebar=true', push: false });
|
||||
} catch (error) {
|
||||
Notification.error(error.message);
|
||||
}
|
||||
|
||||
@@ -12,10 +12,9 @@
|
||||
&.tab--active
|
||||
border-color: #ed5f82;
|
||||
|
||||
.section--problem-sidebar-additional_file
|
||||
.problem-sidebar-additional_file__detail
|
||||
height: 270px
|
||||
overflow-y: auto
|
||||
.problem-sidebar-additional_file
|
||||
height: 270px
|
||||
overflow-y: auto
|
||||
|
||||
.col--size
|
||||
width: 80px
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% macro render(text, compact=false) %}
|
||||
{% macro render(text, compact=false, args=[]) %}
|
||||
<div class="nothing-placeholder{% if compact %} compact{% endif %}">
|
||||
<div class="nothing-icon"></div>
|
||||
{{ _(text) }}
|
||||
{{ _(text).format(args) }}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="section__body typo" data-fragment-id="problem-description">
|
||||
{% if not pdoc.data.length and not pdoc.reference %}
|
||||
<blockquote class="warn">
|
||||
<p>{{ _('No testdata at current.') }}</p>
|
||||
<p>{{ _('No {0} at current.').format(_("testdata")) }}</p>
|
||||
</blockquote>
|
||||
{% endif %}
|
||||
{% if typeof(pdoc.config) == 'string' %}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
{% import "components/nothing.html" as nothing with context %}
|
||||
<div class="section__body no-padding problem-files-additional_file" data-fragment-id="problem-files-additional_file">
|
||||
{% if additional_file.length %}
|
||||
<table class="data-table">
|
||||
<colgroup>
|
||||
<col class="col--checkbox">
|
||||
<col class="col--name">
|
||||
<col class="col--size">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col--checkbox">
|
||||
<label class="compact checkbox">
|
||||
<input type="checkbox" name="select_all" data-checkbox-toggle="additional_file">
|
||||
</label>
|
||||
</th>
|
||||
<th class="col--name">{{ _('Filename') }}</th>
|
||||
<th class="col--size">{{ _('Size') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%- for file in additional_file -%}
|
||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
||||
<td class="col--checkbox">
|
||||
<label class="compact checkbox">
|
||||
<input type="checkbox" data-checkbox-group="additional_file" data-checkbox-range>
|
||||
</label>
|
||||
</td>
|
||||
<td class="col--name" data-preview="additional_file">
|
||||
<a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name}) }}">{{ file.name }}</a>
|
||||
</td>
|
||||
<td class="col--size">{{ size(file.size) }}</td>
|
||||
</tr>
|
||||
{%- endfor -%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
{{ nothing.render('No additional file at current.') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -1,48 +0,0 @@
|
||||
{% import "components/nothing.html" as nothing with context %}
|
||||
<div class="section__body no-padding problem-files-testdata" data-fragment-id="problem-files-testdata">
|
||||
{% if reference %}
|
||||
<blockquote class="note">
|
||||
<p>{{ _('This is a copy of another problem.') }}</p>
|
||||
</blockquote>
|
||||
{% elif testdata.length %}
|
||||
<table class="data-table">
|
||||
<colgroup>
|
||||
<col class="col--checkbox">
|
||||
<col class="col--name">
|
||||
<col class="col--size">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col--checkbox">
|
||||
<label class="compact checkbox">
|
||||
<input type="checkbox" name="select_all" data-checkbox-toggle="testdata">
|
||||
</label>
|
||||
</th>
|
||||
<th class="col--name">{{ _('Filename') }}</th>
|
||||
<th class="col--size">{{ _('Size') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%- for file in testdata -%}
|
||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
||||
<td class="col--checkbox">
|
||||
<label class="compact checkbox">
|
||||
<input type="checkbox" data-checkbox-group="testdata" data-checkbox-range>
|
||||
</label>
|
||||
</td>
|
||||
<td class="col--name" data-preview="testdata">
|
||||
{% if handler.user.own(pdoc) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) %}
|
||||
<a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name, query:{type:'testdata'} }) }}">{{ file.name }}</a>
|
||||
{% else %}
|
||||
<p>{{ file.name }}</p>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="col--size">{{ size(file.size) }}</td>
|
||||
</tr>
|
||||
{%- endfor -%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
{{ nothing.render('No testdata at current.') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -0,0 +1,59 @@
|
||||
{% import "components/nothing.html" as nothing with context %}
|
||||
{% set _files = testdata if filetype == 'testdata' else additional_file %}
|
||||
<div class="section__body no-padding problem-{{ 'sidebar' if sidebar else 'files' }}-{{ filetype }}" data-fragment-id="problem-files-{{ filetype }}"
|
||||
{% if sidebar %}data-type="{{ filetype }}" data-sidebar{% endif %}>
|
||||
{% if reference %}
|
||||
<blockquote class="note">
|
||||
<p>{{ _('This is a copy of another problem.') }}</p>
|
||||
</blockquote>
|
||||
{% elif _files.length %}
|
||||
<table class="data-table {{ filetype }}-table">
|
||||
<colgroup>
|
||||
{% if not sidebar %}<col class="col--checkbox">{% endif %}
|
||||
<col class="col--name">
|
||||
<col class="col--size">
|
||||
{% if sidebar %}<col class="col--operation">{% endif %}
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
{% if not sidebar %}
|
||||
<th class="col--checkbox">
|
||||
<label class="compact checkbox">
|
||||
<input type="checkbox" name="select_all" data-checkbox-toggle="{{ filetype }}">
|
||||
</label>
|
||||
</th>
|
||||
{% endif %}
|
||||
<th class="col--name">{{ _('Filename') }}</th>
|
||||
<th class="col--size">{{ _('Size') }}</th>
|
||||
{% if sidebar %}<th class="col--operation"><span class="icon icon-wrench"></span></th>{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%- for file in _files -%}
|
||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
||||
{% if not sidebar %}
|
||||
<td class="col--checkbox">
|
||||
<label class="compact checkbox">
|
||||
<input type="checkbox" data-checkbox-group="{{ filetype }}" data-checkbox-range>
|
||||
</label>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="col--name" data-preview="{{ filetype }}">
|
||||
{% if filetype != 'testdata' or handler.user.own(pdoc) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) %}
|
||||
<a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name, query:{type:filetype} }) }}">{{ file.name }}</a>
|
||||
{% else %}
|
||||
<p>{{ file.name }}</p>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="col--size">{{ size(file.size) }}</td>
|
||||
{% if sidebar %}
|
||||
<td class="col--operation"><a href="javascript:;" name="{{ filetype }}__delete"><span class="icon icon-delete"></span></a></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{%- endfor -%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
{{ nothing.render('No {0} at current.', compact=sidebar, args=[_(filetype)]) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -1,48 +0,0 @@
|
||||
{% import "components/nothing.html" as nothing with context %}
|
||||
{% import "components/problem.html" as problem with context %}
|
||||
<div class="section side section--problem-sidebar-additional_file">
|
||||
<div class="section__header">
|
||||
<h1 class="section__title">{{ additional_file.length|default(0) }} {{_('Additional File')}}</h1>
|
||||
</div>
|
||||
<ol class="menu">
|
||||
<li class="menu__item flex-row">
|
||||
<a class="menu__link half" href="javascript:;" name="additional_file__upload">
|
||||
<span class="icon icon-upload"></span> {{ _('Upload') }}
|
||||
</a>
|
||||
<a class="menu__link half" href="javascript:;" name="additional_file__download">
|
||||
<span class="icon icon-download"></span> {{ _('Download All') }}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
<div class="section__body no-padding problem-sidebar-additional_file__detail" data-fragment-id="problem-sidebar-additional_file">
|
||||
{% if additional_file.length %}
|
||||
<table class="data-table additionalfile-table">
|
||||
<colgroup>
|
||||
<col class="col--name">
|
||||
<col class="col--size">
|
||||
<col class="col--operation">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col--name">{{ _('Filename') }}</th>
|
||||
<th class="col--size">{{ _('Size') }}</th>
|
||||
<th class="col--operation"><span class="icon icon-wrench"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%- for file in additional_file -%}
|
||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
||||
<td class="col--name" title="{{ file.name }}" data-preview="additional_file">
|
||||
<a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name}) }}">{{ file.name }}</a>
|
||||
</td>
|
||||
<td class="col--size">{{ size(file.size) }}</td>
|
||||
<td class="col--operation"><a href="javascript:;"name="additional_file__delete"><span class="icon icon-delete"></span></a></td>
|
||||
</tr>
|
||||
{%- endfor -%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
{{ nothing.render('No additional file at current.',compact = true) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,47 +0,0 @@
|
||||
{% import "components/nothing.html" as nothing with context %}
|
||||
{% import "components/problem.html" as problem with context %}
|
||||
<div class="section side section--problem-sidebar-testdata">
|
||||
<div class="section__header">
|
||||
<h1 class="section__title">{{ testdata.length if testdata.length else 0 }} {{_('Testdata')}}</h1>
|
||||
</div>
|
||||
<ol class="menu">
|
||||
<li class="menu__item flex-row">
|
||||
<a class="menu__link half" href="javascript:;" name="testdata__upload">
|
||||
<span class="icon icon-upload"></span> {{ _('Upload') }}
|
||||
</a>
|
||||
<a class="menu__link half" href="javascript:;" name="testdata__download__all">
|
||||
<span class="icon icon-download"></span> {{ _('Download All') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu__seperator"></li>
|
||||
</ol>
|
||||
<div class="section__body no-padding problem-sidebar-testdata__detail" data-fragment-id="problem-sidebar-testdata">
|
||||
{% if testdata.length %}
|
||||
<table class="data-table testdata-table">
|
||||
<colgroup>
|
||||
<col class="col--name">
|
||||
<col class="col--size">
|
||||
<col class="col--operation">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col--name">{{ _('Filename') }}</th>
|
||||
<th class="col--size">{{ _('Size') }}</th>
|
||||
<th class="col--operation"><span class="icon icon-wrench"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%- for file in testdata -%}
|
||||
<tr data-filename="{{ file.name }}" data-size="{{ file.size }}">
|
||||
<td class="col--name" title="{{ file.name }}" data-preview="testdata"><a href="{{ url('problem_file_download', {pid: pdoc.docId, filename: file.name, query:{type:'testdata'} }) }}">{{ file.name }}</a></td>
|
||||
<td class="col--size">{{ size(file.size) }}</td>
|
||||
<td class="col--operation"><a href="javascript:;" name="testdata__delete"><span class="icon icon-delete"></span></a></td>
|
||||
</tr>
|
||||
{%- endfor -%}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
{{ nothing.render('No testdata at current.', compact = true) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -13,7 +13,25 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="medium-3 columns">
|
||||
{% include "partials/problem_sidebar_testdata.html" %}
|
||||
<div class="section side">
|
||||
<div class="section__header">
|
||||
<h1 class="section__title">{{ testdata.length|default(0) }} {{_('Testdata')}}</h1>
|
||||
</div>
|
||||
<ol class="menu">
|
||||
<li class="menu__item flex-row">
|
||||
<a class="menu__link half" href="javascript:;" name="testdata__upload">
|
||||
<span class="icon icon-upload"></span> {{ _('Upload') }}
|
||||
</a>
|
||||
<a class="menu__link half" href="javascript:;" name="testdata__download__all">
|
||||
<span class="icon icon-download"></span> {{ _('Download All') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu__seperator"></li>
|
||||
</ol>
|
||||
{% set sidebar = true %}
|
||||
{% set filetype = "testdata" %}
|
||||
{% include "partials/problem_files.html" %}
|
||||
</div>
|
||||
{% set owner_udoc = udoc %}
|
||||
{% include "partials/problem_sidebar.html" %}
|
||||
</div>
|
||||
|
||||
@@ -92,7 +92,24 @@
|
||||
</div>
|
||||
</div>
|
||||
{% if page_name == 'problem_edit' %}
|
||||
{% include "partials/problem_sidebar_additional_file.html" %}
|
||||
<div class="section side">
|
||||
<div class="section__header">
|
||||
<h1 class="section__title">{{ additional_file.length|default(0) }} {{_('Additional File')}}</h1>
|
||||
</div>
|
||||
<ol class="menu">
|
||||
<li class="menu__item flex-row">
|
||||
<a class="menu__link half" href="javascript:;" name="additional_file__upload">
|
||||
<span class="icon icon-upload"></span> {{ _('Upload') }}
|
||||
</a>
|
||||
<a class="menu__link half" href="javascript:;" name="additional_file__download">
|
||||
<span class="icon icon-download"></span> {{ _('Download All') }}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
{% set sidebar = true %}
|
||||
{% set filetype = "additional_file" %}
|
||||
{% include "partials/problem_files.html" %}
|
||||
</div>
|
||||
{% set owner_udoc = udoc %}
|
||||
{% include "partials/problem_sidebar.html" %}
|
||||
{% else %}
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
</div>
|
||||
</div>
|
||||
{{ noscript_note.render() }}
|
||||
{% include "partials/problem_files-testdata.html" %}
|
||||
{% set filetype = "testdata" %}
|
||||
{% include "partials/problem_files.html" %}
|
||||
{% if not reference and (handler.user.own(pdoc) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) %}
|
||||
<div class="section__body">
|
||||
<button class="rounded button" name="download_selected_testdata">{{ _('Download Selected') }}</button>
|
||||
@@ -36,7 +37,8 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% include "partials/problem_files-additional_file.html" %}
|
||||
{% set filetype = "additional_file" %}
|
||||
{% include "partials/problem_files.html" %}
|
||||
<div class="section__body">
|
||||
<button class="rounded button" name="download_selected_file">{{ _('Download Selected') }}</button>
|
||||
{% if handler.user.own(pdoc, perm.PERM_EDIT_PROBLEM_SELF) or handler.user.hasPerm(perm.PERM_EDIT_PROBLEM) %}
|
||||
|
||||
Reference in new issue
Block a user