New UI for users and submissions

This commit is contained in:
cuom1999 2022-06-06 11:36:35 -05:00
parent d0ac92914d
commit 247e0e4740
12 changed files with 183 additions and 226 deletions

View file

@ -286,7 +286,7 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
show_problem = True
title = gettext_lazy("All submissions")
content_title = gettext_lazy("All submissions")
tab = "all_submissions_list"
page_type = "all_submissions_list"
template_name = "submission/list.html"
context_object_name = "submissions"
first_page_href = None
@ -429,7 +429,7 @@ class SubmissionsListBase(DiggPaginatorMixin, TitleMixin, ListView):
context["first_page_href"] = (self.first_page_href or ".") + suffix
context["my_submissions_link"] = self.get_my_submissions_page()
context["all_submissions_link"] = self.get_all_submissions_page()
context["tab"] = self.tab
context["page_type"] = self.page_type
return context
@ -460,9 +460,9 @@ class ConditionalUserTabMixin(object):
def get_context_data(self, **kwargs):
context = super(ConditionalUserTabMixin, self).get_context_data(**kwargs)
if self.request.user.is_authenticated and self.request.profile == self.profile:
context["tab"] = "my_submissions_tab"
context["page_type"] = "my_submissions_tab"
else:
context["tab"] = "user_submissions_tab"
context["page_type"] = "user_submissions_tab"
context["tab_username"] = self.profile.user.username
return context

View file

@ -461,6 +461,7 @@ class UserList(QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ListView):
all_sorts = frozenset(("points", "problem_count", "rating", "performance_points"))
default_desc = all_sorts
default_sort = "-performance_points"
filter_friend = False
def filter_friend_queryset(self, queryset):
friends = list(self.request.profile.get_friends())
@ -484,6 +485,7 @@ class UserList(QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ListView):
if (self.request.GET.get("friend") == "true") and self.request.profile:
ret = self.filter_friend_queryset(ret)
self.filter_friend = True
return ret
def get_context_data(self, **kwargs):
@ -492,6 +494,7 @@ class UserList(QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ListView):
context["users"], rank=self.paginate_by * (context["page_obj"].number - 1)
)
context["first_page_href"] = "."
context["page_type"] = "friends" if self.filter_friend else "list"
context.update(self.get_sort_context())
context.update(self.get_sort_paginate_context())
return context

View file

@ -3185,7 +3185,7 @@ msgstr "Chỉnh sửa thông tin"
#: judge/views/user.py:457 templates/user/user-list-tabs.html:4
msgid "Leaderboard"
msgstr "Bảng xếp hạng"
msgstr "Xếp hạng"
#: judge/views/user.py:553
msgid "Import Users"

View file

@ -307,6 +307,7 @@ ul.problem-list {
padding-bottom: 1em;
border-radius: 5px;
margin-bottom: 1em;
display: flex;
}
.problem-feed-option-item {

View file

@ -121,7 +121,7 @@ label[for="language"], label[for="status"] {
padding-top: 0;
}
@media(max-width: 700px) {
@media(max-width: 799px) {
.sub-prop {
.label {
display: none;
@ -136,10 +136,6 @@ label[for="language"], label[for="status"] {
display: none;
}
#statistics-table {
display: none;
}
#content-left.submission {
flex: 100%;
}

View file

@ -4,23 +4,23 @@
{% block middle_title %}
<div class="page-title">
<div class="tabs">
<h2>{{title}}</h2>
<span class="spacer"></span>
{% if request.user.is_authenticated %}
{% if is_member or can_edit %}
{% elif organization.is_open or can_edit %}
<form method="post" action="{{ url('join_organization', organization.id, organization.slug) }}">
{% csrf_token %}
<input type="submit" class="unselectable button" value="{{ _('Join') }}">
</form>
{% else %}
<a href="{{ url('request_organization', organization.id, organization.slug) }}"
class="unselectable button">{{ _('Request membership') }}</a>
<div class="tabs" style="border: none;">
<h2><img src="{{logo_override_image}}" style="height: 3rem; vertical-align: middle"> <span>{{title}}</span></h2>
<span class="spacer"></span>
{% if request.user.is_authenticated %}
{% if is_member %}
{% elif organization.is_open or can_edit %}
<form method="post" action="{{ url('join_organization', organization.id, organization.slug) }}">
{% csrf_token %}
<input type="submit" class="unselectable button" value="{{ _('Join') }}">
</form>
{% else %}
<a href="{{ url('request_organization', organization.id, organization.slug) }}"
class="unselectable button">{{ _('Request membership') }}</a>
{% endif %}
{% endif %}
{% endif %}
</div>
</div>
</div>
{% endblock %}

View file

@ -1,5 +1,5 @@
{% extends "common-content.html" %}
{% block js_media %}
{% extends "three-column-content.html" %}
{% block three_col_js %}
<script type="text/javascript">
{% if dynamic_update and last_msg %}
{% if request.in_contest_mode %}
@ -256,11 +256,9 @@
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% include "submission/submission-list-tabs.html" %}
{% endblock %}
{% block title_row %}{% endblock %}
{% block media %}
{% block three_col_media %}
{% if perms.judge.change_submission and perms.judge.rejudge_submission %}
<style>
td.sub-prop, col.sub-prop {
@ -294,83 +292,96 @@
</style>
{% endblock %}
{% block body %}
{% block middle_content %}
{% if page_obj.num_pages > 1 %}
<div style="margin-bottom: 6px; margin-top: 11px">
{% include "list-pages.html" %}
</div>
{% endif %}
<div id="common-content">
<div id="content-right" class="submission">
<div class="info-float">
<div class="sidebox">
<h3>{{ _('Filter submissions') }} <i class="fa fa-search"></i></h3>
<div class="sidebox-content">
<form id="filter-form" name="form" action="" method="get">
<div class="filter-form-group">
<label for="status"><i>{{ _('Status') }}</i></label>
<select id="status" name="status" multiple>
{% for id, name in all_statuses %}
<option {% if id in selected_statuses %}selected{% endif %}
value="{{ id }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="filter-form-group">
<label for="language"><i>{{ _('Language') }}</i></label>
<select id="language" name="language" multiple>
{% for code, name in all_languages %}
<option {% if code in selected_languages %}selected{% endif %}
value="{{ code }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="form-submit-group">
<a id="go" onclick="form.submit()" class="button">{{ _('Go') }}</a>
</div>
</form>
</div>
</div>
<div class="submission">
<div class="ws-closed">
<a href="javascript:void(0)">{{ _('You were disconnected. Refresh to show latest updates.') }}</a>
</div>
<div class="sidebox">
<div id="statistics-table">
<h3>{{ _('Statistics') }} <i class="fa fa-pie-chart"></i></h3>
<div class="sidebox-content">
<div id="status-graph">
<canvas width="230" height="170"></canvas>
</div>
<div class="total">
{{ _('Total:') }} <span id="total-submission-count"></span>
</div>
<div id="submissions-table">
{% set profile_id = request.profile.id if request.user.is_authenticated else 0 %}
{% for submission in submissions %}
<div class="submission-row" id="{{ submission.id }}">
{% with problem_name=show_problem and submission.problem.i18n_name %}
{% include "submission/row.html" %}
{% endwith %}
</div>
{% endfor %}
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block right_sidebar %}
<div class="right-sidebar">
<div class="submission">
<div class="sidebox">
<h3>{{ _('Filter submissions') }} <i class="fa fa-search"></i></h3>
<div class="sidebox-content">
<form id="filter-form" name="form" action="" method="get">
<div class="filter-form-group">
<label for="status"><i>{{ _('Status') }}</i></label>
<select id="status" name="status" multiple>
{% for id, name in all_statuses %}
<option {% if id in selected_statuses %}selected{% endif %}
value="{{ id }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="filter-form-group">
<label for="language"><i>{{ _('Language') }}</i></label>
<select id="language" name="language" multiple>
{% for code, name in all_languages %}
<option {% if code in selected_languages %}selected{% endif %}
value="{{ code }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="form-submit-group">
<a id="go" onclick="form.submit()" class="button">{{ _('Go') }}</a>
</div>
</form>
</div>
</div>
<div class="sidebox">
<div id="statistics-table">
<h3>{{ _('Statistics') }} <i class="fa fa-pie-chart"></i></h3>
<div class="sidebox-content">
<div id="status-graph">
<canvas width="230" height="170"></canvas>
</div>
<div class="total">
{{ _('Total:') }} <span id="total-submission-count"></span>
</div>
</div>
</div>
</div>
</div>
<div id="content-left" class="submission">
<div class="ws-closed">
<a href="javascript:void(0)">{{ _('You were disconnected. Refresh to show latest updates.') }}</a>
</div>
<div id="submissions-table">
{% set profile_id = request.profile.id if request.user.is_authenticated else 0 %}
{% for submission in submissions %}
<div class="submission-row" id="{{ submission.id }}">
{% with problem_name=show_problem and submission.problem.i18n_name %}
{% include "submission/row.html" %}
{% endwith %}
</div>
{% endfor %}
</div>
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block bodyend %}
{# Don't load MathJax from common-content! #}
{% endblock %}
{% block left_sidebar %}
<div class="left-sidebar">
{{ make_tab_item('all_submissions_list', 'fa fa-list', all_submissions_link, _('All')) }}
{% if my_submissions_link or tab == 'my_submissions_tab' %}
{{ make_tab_item('my_submissions_tab', 'fa fa-user', my_submissions_link, _('Mine')) }}
{% endif %}
{% if best_submissions_link %}
{{ make_tab_item('best_submissions_list', 'fa fa-bar-chart', best_submissions_link, _('Best')) }}
{% endif %}
{% if page_type == 'user_submissions_tab' %}
{{ make_tab_item('user_submissions_tab', 'fa fa-user', None, _("%(user)s", user=tab_username)) }}
{% endif %}
{% if perms.judge.change_submission %}
{{ make_tab_item('admin', 'fa fa-edit', url('admin:judge_submission_changelist'), _('Admin')) }}
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1,60 @@
<script>
$(function () {
$('#search-handle').replaceWith($('<select>').attr({
id: 'search-handle',
name: 'handle',
onchange: 'form.submit()'
}));
var in_user_redirect = false;
$('#search-handle').select2({
placeholder: '{{ _('Search by handle...') }}',
ajax: {
url: '{{ url('user_search_select2_ajax') }}'
},
minimumInputLength: 1,
escapeMarkup: function (markup) {
return markup;
},
templateResult: function (data, container) {
return $('<span>')
.append($('<img>', {
'class': 'user-search-image', src: data.gravatar_url,
width: 24, height: 24
}))
.append($('<span>', {'class': data.display_rank + ' user-search-name'}).text(data.text))
.append($('<a>', {href: '/user/' + data.text, 'class': 'user-redirect'})
.append($('<i>', {'class': 'fa fa-mail-forward'}))
.mouseover(function () {
in_user_redirect = true;
}).mouseout(function () {
in_user_redirect = false;
}));
}
}).on('select2:selecting', function () {
return !in_user_redirect;
});
var $last = null;
$(window).on('hashchange', function () {
var hash = window.location.hash;
if (hash.startsWith('#!')) {
var $user = $('#user-' + hash.substring(2)).addClass('highlight');
if ($user) {
$(document).scrollTop($user.position().top - 50);
if ($last !== null) $last.removeClass('highlight');
$last = $user;
}
}
}).trigger('hashchange');
$('.about-td').on('click', function() {
var max_height = $(this).css('max-height');
if (max_height !== 'fit-content') {
$(this).css('max-height', 'fit-content');
}
else {
$(this).css('max-height', '45px');
}
})
});
</script>

View file

@ -2,66 +2,7 @@
{% block three_col_js %}
{% block users_js_media %}{% endblock %}
<script>
$(function () {
$('#search-handle').replaceWith($('<select>').attr({
id: 'search-handle',
name: 'handle',
onchange: 'form.submit()'
}));
var in_user_redirect = false;
$('#search-handle').select2({
placeholder: '{{ _('Search by handle...') }}',
ajax: {
url: '{{ url('user_search_select2_ajax') }}'
},
minimumInputLength: 1,
escapeMarkup: function (markup) {
return markup;
},
templateResult: function (data, container) {
return $('<span>')
.append($('<img>', {
'class': 'user-search-image', src: data.gravatar_url,
width: 24, height: 24
}))
.append($('<span>', {'class': data.display_rank + ' user-search-name'}).text(data.text))
.append($('<a>', {href: '/user/' + data.text, 'class': 'user-redirect'})
.append($('<i>', {'class': 'fa fa-mail-forward'}))
.mouseover(function () {
in_user_redirect = true;
}).mouseout(function () {
in_user_redirect = false;
}));
}
}).on('select2:selecting', function () {
return !in_user_redirect;
});
var $last = null;
$(window).on('hashchange', function () {
var hash = window.location.hash;
if (hash.startsWith('#!')) {
var $user = $('#user-' + hash.substring(2)).addClass('highlight');
if ($user) {
$(document).scrollTop($user.position().top - 50);
if ($last !== null) $last.removeClass('highlight');
$last = $user;
}
}
}).trigger('hashchange');
$('.about-td').on('click', function() {
var max_height = $(this).css('max-height');
if (max_height !== 'fit-content') {
$(this).css('max-height', 'fit-content');
}
else {
$(this).css('max-height', '45px');
}
})
});
</script>
{% include "user/base-users-js.html" %}
{% endblock %}
{% block three_col_media %}

View file

@ -2,66 +2,7 @@
{% block js_media %}
{% block users_js_media %}{% endblock %}
<script>
$(function () {
$('#search-handle').replaceWith($('<select>').attr({
id: 'search-handle',
name: 'handle',
onchange: 'form.submit()'
}));
var in_user_redirect = false;
$('#search-handle').select2({
placeholder: '{{ _('Search by handle...') }}',
ajax: {
url: '{{ url('user_search_select2_ajax') }}'
},
minimumInputLength: 1,
escapeMarkup: function (markup) {
return markup;
},
templateResult: function (data, container) {
return $('<span>')
.append($('<img>', {
'class': 'user-search-image', src: data.gravatar_url,
width: 24, height: 24
}))
.append($('<span>', {'class': data.display_rank + ' user-search-name'}).text(data.text))
.append($('<a>', {href: '/user/' + data.text, 'class': 'user-redirect'})
.append($('<i>', {'class': 'fa fa-mail-forward'}))
.mouseover(function () {
in_user_redirect = true;
}).mouseout(function () {
in_user_redirect = false;
}));
}
}).on('select2:selecting', function () {
return !in_user_redirect;
});
var $last = null;
$(window).on('hashchange', function () {
var hash = window.location.hash;
if (hash.startsWith('#!')) {
var $user = $('#user-' + hash.substring(2)).addClass('highlight');
if ($user) {
$(document).scrollTop($user.position().top - 50);
if ($last !== null) $last.removeClass('highlight');
$last = $user;
}
}
}).trigger('hashchange');
$('.about-td').on('click', function() {
var max_height = $(this).css('max-height');
if (max_height !== 'fit-content') {
$(this).css('max-height', 'fit-content');
}
else {
$(this).css('max-height', '45px');
}
})
});
</script>
{% include "user/base-users-js.html" %}
{% endblock %}
{% block media %}

View file

@ -1,4 +1,4 @@
{% extends "user/base-users.html" %}
{% extends "user/base-users-three-col.html" %}
{% block users_media %}
<style>
@ -18,14 +18,10 @@
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% if request.GET.get('friend') == 'true'%}
{% set tab = 'friends' %}
{% else %}
{% set tab = 'list' %}
{% endif %}
{% set title = 'Leaderboard' %}
{% include "user/user-list-tabs.html" %}
{% block title_row %}{% endblock %}
{% block left_sidebar %}
{% include "user/user-left-sidebar.html" %}
{% endblock %}
{% block users_table %}

View file

@ -0,0 +1,8 @@
<div class="left-sidebar">
{{ make_tab_item('list', 'fa fa-trophy', url('user_list'), _('Leaderboard')) }}
{{ make_tab_item('friends', 'fa fa-users', url('user_list') + '?friend=true', _('Friends')) }}
{{ make_tab_item('organizations', 'fa fa-university', url('organization_list'), _('Groups')) }}
{% if request.user.is_superuser %}
{{ make_tab_item('import', 'fa fa-table', url('import_users'), _('Import')) }}
{% endif %}
</div>