Skip to content

Commit

Permalink
Merge pull request #101 from tobiichi3227/impr/board-ui
Browse files Browse the repository at this point in the history
impr(board): enhance UI usability
  • Loading branch information
LifeAdventurer authored Dec 18, 2024
2 parents ad2f985 + 982e4bf commit 94f52a2
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 43 deletions.
27 changes: 22 additions & 5 deletions src/handlers/pro.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,17 @@ async def get(self):
except tornado.web.HTTPError:
order_reverse = False

try:
search_name = self.get_argument('name')
except tornado.web.HTTPError:
search_name = None

flt = {
'order': order,
'problem_show': problem_show,
'online': show_only_online_pro,
'reverse': order_reverse,
'name': search_name,
}

try:
Expand All @@ -76,7 +82,7 @@ async def get(self):
err, prolist = await ProService.inst.list_pro(self.acct)

proclass = None
if proclass_id is not None:
if proclass_id:
err, proclass = await ProClassService.inst.get_proclass(proclass_id)
if err:
self.error(err)
Expand All @@ -96,8 +102,18 @@ async def get(self):
_, creator = await UserService.inst.info_acct(proclass['acct_id'])
proclass['creator_name'] = creator.name

if search_name:
search_name = set(search_name.lower())
def _find(name: str):
for ch in name.lower():
if ch in search_name:
return True

return False
prolist = filter(lambda pro: _find(pro['name']), prolist)

if show_only_online_pro:
prolist = list(filter(lambda pro: pro['status'] == ProConst.STATUS_ONLINE, prolist))
prolist = filter(lambda pro: pro['status'] == ProConst.STATUS_ONLINE, prolist)

_, acct_states = await RateService.inst.map_rate_acct(self.acct)
ac_pro_cnt = 0
Expand All @@ -111,14 +127,15 @@ def _set_pro_state_and_tags(pro):

return pro

prolist = list(map(lambda pro: _set_pro_state_and_tags(pro), prolist))
prolist = map(lambda pro: _set_pro_state_and_tags(pro), prolist)

if problem_show == "onlyac":
prolist = list(filter(lambda pro: pro['state'] == ChalConst.STATE_AC, prolist))
prolist = filter(lambda pro: pro['state'] == ChalConst.STATE_AC, prolist)

elif problem_show == "notac":
prolist = list(filter(lambda pro: pro['state'] != ChalConst.STATE_AC, prolist))
prolist = filter(lambda pro: pro['state'] != ChalConst.STATE_AC, prolist)

prolist = list(prolist)
for pro in prolist:
_, rate = await RateService.inst.get_pro_ac_rate(pro['pro_id'])
pro['rate_data'] = rate
Expand Down
7 changes: 4 additions & 3 deletions src/services/rate.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ async def map_rate(self, starttime='1970-01-01 00:00:00.000', endtime='2100-01-0
'''
SELECT "challenge"."acct_id", "challenge"."pro_id",
ROUND(MAX("challenge_state"."rate"), (SELECT rate_precision FROM problem WHERE pro_id = challenge.pro_id)) AS "rate",
COUNT("challenge_state") AS "count"
COUNT("challenge_state") AS "count",
MIN("challenge_state"."state") AS "state"
FROM "challenge"
INNER JOIN "challenge_state"
ON "challenge"."chal_id" = "challenge_state"."chal_id"
Expand All @@ -208,7 +209,7 @@ async def map_rate(self, starttime='1970-01-01 00:00:00.000', endtime='2100-01-0
)

statemap = defaultdict(dict)
for acct_id, pro_id, rate, count in result:
statemap[acct_id][pro_id] = {'rate': rate, 'count': count}
for acct_id, pro_id, rate, count, state in result:
statemap[acct_id][pro_id] = {'rate': rate, 'count': count, 'state': state}

return None, statemap
24 changes: 20 additions & 4 deletions src/static/templ/board-list.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{% from services.board import BoardConst %}
<script type="text/javascript" id="contjs">
function init() {
}
Expand All @@ -8,25 +9,40 @@
<tr>
<th scope="col">#</th>
<th scope="col">Board Name</th>
<th scope="col">Status</th>
<th scope="col">Expire Status</th>
{% if user.is_kernel() %}
<th scope="col">Public Status</th>
{% end %}
</tr>
</thead>
<tbody>
{% for board in boardlist %}
{% if not user.is_kernel() and board['status'] != BoardConst.STATUS_ONLINE %}
{% continue %}
{% end %}
<tr>
<th scope="row">{{ board['board_id'] }}</th>
<td><a href="/oj/board/{{ board['board_id'] }}/">{{ board['name'] }}</a></td>
<td>
{% set delta = board['end'] - datetime.datetime.now().replace(tzinfo=datetime.timezone(datetime.timedelta(hours=8))) %}
{% set deltasecond = delta.days * 24 * 60 * 60 + delta.seconds %}
{% if deltasecond <= 0 %}
Over
Over
{% else %}
Online
Online
{% end %}
</td>
{% if user.is_kernel() %}
{% if board['status'] == BoardConst.STATUS_ONLINE %}
<td>Public</td>
{% elif board['status'] == BoardConst.STATUS_HIDDEN %}
<td>Hidden</td>
{% elif board['status'] == BoardConst.STATUS_OFFLINE %}
<td>Offline</td>
{% end %}
{% end %}
</tr>
{% end %}
</tbody>
</table>
</div>
</div>
120 changes: 104 additions & 16 deletions src/static/templ/board.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
{% import math %}
{% from services.chal import ChalConst %}
<style>
/* from https://www.astralweb.com.tw/pure-css-implementation-table-headers-columns-fixed/ */
/* freeze table head like excel */
table {
table-layout: fixed;
}
td._rank, th._rank {
position: sticky;
left: 0;
z-index: 1;
}
table thead tr th {
position: sticky;
top: 0;
z-index: 1;
}
th._rank {
z-index: 4;
}
@media only screen and (min-width: 992px) {
td._acct {
position: sticky;
left: 64px;
z-index: 1;
}
tr th._acct {
position: sticky;
left: 64px;
z-index: 2;
}

td._score {
position: sticky;
left: 214px;
z-index: 1;
}
tr th._score {
position: sticky;
left: 214px;
z-index: 2;
}

td._submit {
position: sticky;
left: 0;
z-index: 2;
}
}
/* end */

table th._rank {
text-align: center;
width: 64px;
Expand Down Expand Up @@ -84,6 +134,24 @@
window.localStorage.setItem('board_scoll_left', board.scrollLeft)
}, false)

$("#topScrollBar").scroll(function() {
$("#board1").scrollLeft($(this).scrollLeft());
});
$("#board1").scroll(function() {
$("#topScrollBar").scrollLeft($(this).scrollLeft());
});

$("#showSelf").on('change', function (e) {
let clicked = $(this).is(":checked");
$("tbody > tr").each((idx, el) => {
el = $(el);
if (!el.hasClass("_self")) {
if (clicked) el.hide();
else el.show();
}
});
});

setTimeout(() => {
var board = document.getElementById('board1');
if (window.localStorage.getItem('board_scoll_left')) {
Expand All @@ -96,22 +164,28 @@

function GetCount() {
var j_count = $('#count');
var now = new Date().getTime();
var delta = Math.floor((end - now) / 1000);
if (delta <= 0) {
j_count.text('Over');

let now = new Date().getTime();
let secs = Math.floor((end - now) / 1000);
let ss = 0, mm = 0, hh = 0, dd = 0;
ss = Math.floor(secs % 60);
if (secs > 0) {
dd = Math.floor(secs / 86400);
secs %= 86400;
hh = Math.floor(secs / 3600);
secs %= 3600;
mm = Math.floor(secs / 60) % 60;

const getS = (number) => {
return number > 1 ? 's': '';
};
j_count.text(`${dd} Day${getS(dd)} ${hh} Hour${getS(hh)} ${mm} Minute${getS(mm)} ${ss} Second${getS(ss)} Left`);
setTimeout(() => GetCount(), 1000);
} else {
var hour = Math.floor(delta / 3600);
delta = (delta % 3600);
var minute = Math.floor(delta / 60);
delta = (delta % 60);
var second = Math.floor(delta);
j_count.text(hour + ' ' + 'hour' + (hour > 1 ? 's' : '') + ' ' + minute + ' ' + 'minute' + (minute > 1 ? 's' : '') + ' ' + second + ' ' + 'second' + (second >1 ? 's' : '') + ' ' + 'Left');
setTimeout(function(){
GetCount()
},1000);
j_count.text('Over');
}
}

function init() {
GetCount();
}
Expand All @@ -127,15 +201,25 @@
<strong>Standings&nbsp;&nbsp;</strong>
<select class="form-select" id="cont">
{% for board in board_list %}
<option value="{{ board['board_id'] }}" {% if board['name'] == name %}selected{% end %}>{{ board['name'] }}</option>
{% if not user.is_kernel() and board['status'] != BoardConst.STATUS_ONLINE %}
{% continue %}
{% end %}
<option value="{{ board['board_id'] }}" {% if board['name'] == name %}selected{% end %}>{{ board['name'] }}</option>
{% end %}
</select>
</div>
<h3>
<div id="count"></div>
</h3>
<div class="form-check form-check-inline">
<label class="form-check-label" for="showSelf">Only Show Myself</label>
<input type="checkbox" id="showSelf" class="form-check-input">
</div>
</div>
<div class="col-lg-12" style="overflow-x: scroll;" id="board1">
<div style="overflow-x: scroll; overflow-y: hidden;" id="topScrollBar">
<div style="height: 8px; width:{{9+64+150+112+len(prolist)*99}}px;"></div>
</div>
<div class="col-lg-12" id="board1" style="overflow-x: scroll; max-height: 100vh;">
<table class="table table-hover table-sm table-bordered table-responsive-sm col mx-lg-3" style="width:{{9+64+150+112+len(prolist)*99}}px;">
<thead>
<tr>
Expand All @@ -150,7 +234,7 @@ <h3>
<tbody>
{% for acct in acctlist %}
{% set acct_id = acct.acct_id %}
<tr>
<tr {% if acct_id == user.acct_id %} style="--bs-table-bg: #123456;" class="_self" {% end %}>
<td class="_rank">{{ acct.rank }}</td>
<td class="_acct">&nbsp<a href="/oj/acct/{{ acct_id }}/">{{ acct.name }}</a></td>
<td class="_score"><a href="/oj/chal/?acctid={{ acct_id }}">{{ acct.rate }} / {{ acct_submit[acct_id] }}</a></td>
Expand All @@ -159,6 +243,10 @@ <h3>
{% if acct_id in ratemap and pro_id in ratemap[acct_id] %}
{% set rate = ratemap[acct_id][pro_id] %}
{% set sc = math.floor(rate['rate'] / 10) %}
{% if rate['state'] == ChalConst.STATE_AC %}
{% set sc = 10 %}
{% end %}

<td class="_pro _state-{{ sc }} _state"><a href="/oj/chal/?acctid={{ acct_id }}&proid={{ pro_id }}&state=0">{{ rate['rate'] }} / {{ rate['count'] }}</a></td>
{% else %}
<td class="_pro _state">&nbsp</td>
Expand Down
7 changes: 4 additions & 3 deletions src/static/templ/manage/board/add.html
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
</script>
{% end %}
{% block content %}
{% from services.board import BoardConst %}
<div class="col-lg-10 ms-lg-2 mt-lg-2">
<form id="form">
<div class="mb-1">
Expand All @@ -103,9 +104,9 @@
<div class="mb-1">
<label for="#status" class="form-label">Status</label>
<select class="form-select" id="status">
<option value=0>Online</option>
<option value=1>Hidden</option>
<option value=2>Offline</option>
<option value="{{ BoardConst.STATUS_ONLINE }}">Online</option>
<option value="{{ BoardConst.STATUS_HIDDEN }}">Hidden</option>
<option value="{{ BoardConst.STATUS_OFFLINE }}">Offline</option>
</select>
</div>

Expand Down
7 changes: 4 additions & 3 deletions src/static/templ/manage/board/board-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

{% end %}
{% block content %}
{% from services.board import BoardConst %}
<div class="col-lg-10 ms-lg-2 mt-lg-2">

<table class="table table-hover table-sm table-responsive-sm col mx-lg-3">
Expand All @@ -28,11 +29,11 @@
<th scope="row">{{ board['board_id'] }}</th>
<td><a href="/oj/board/{{ board['board_id'] }}/">{{ board['name'] }}</a></td>

{% if board['status'] == 0 %}
{% if board['status'] == BoardConst.STATUS_ONLINE %}
<td class="status-online">Online</td>
{% elif board['status'] == 1 %}
{% elif board['status'] == BoardConst.STATUS_HIDDEN %}
<td class="status-hidden">Hidden</td>
{% elif board['status'] == 2 %}
{% elif board['status'] == BoardConst.STATUS_OFFLINE %}
<td class="status-offline">Offline</td>
{% end %}

Expand Down
9 changes: 5 additions & 4 deletions src/static/templ/manage/board/update.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
let pro_list = j_form.find("#pro_list").val();
let acct_list = j_form.find("#acct_list").val();

start_time = start_date_picker.viewDate;
start_time = start_date_picker.viewDate;
if (start_time == '') {
index.show_notify_dialog("開始時間不可為空", index.DIALOG_TYPE.warning);
return;
Expand Down Expand Up @@ -109,6 +109,7 @@
</script>
{% end %}
{% block content %}
{% from services.board import BoardConst %}
<div class="col-lg-10 ms-lg-2 mt-lg-2">
<form id="form">
<div class="mb-1">
Expand All @@ -118,9 +119,9 @@
<div class="mb-1">
<label for="#status" class="form-label">Status</label>
<select class="form-select" id="status">
<option value="0" {% if board['status'] == 0 %} selected {% end %} >Online</option>
<option value="1" {% if board['status'] == 1 %} selected {% end %} >Hidden</option>
<option value="2" {% if board['status'] == 2 %} selected {% end %} >Offline</option>
<option value="{{ BoardConst.STATUS_ONLINE }}" {% if board['status'] == BoardConst.STATUS_ONLINE %} selected {% end %} >Online</option>
<option value="{{ BoardConst.STATUS_HIDDEN }}" {% if board['status'] == BoardConst.STATUS_HIDDEN %} selected {% end %} >Hidden</option>
<option value="{{ BoardConst.STATUS_OFFLINE }}" {% if board['status'] == BoardConst.STATUS_OFFLINE %} selected {% end %} >Offline</option>
</select>
</div>

Expand Down
Loading

0 comments on commit 94f52a2

Please sign in to comment.