Skip to content

Commit 13cc98b

Browse files
author
Nils Bars
committed
Auto-refresh exercise list when builds complete
Add a build-status API endpoint and poll it from the exercise list page. When a building exercise changes status, reload the page preserving scroll position.
1 parent 5b61fa8 commit 13cc98b

2 files changed

Lines changed: 48 additions & 2 deletions

File tree

webapp/ref/templates/exercise_view_all.html

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ <h4 class="card-header">
3939
<td>{{ e.short_name }}</td>
4040
<td>{{ e.version }}</td>
4141
<td>{{ e.max_grading_points }}</td>
42-
<td>{{ e.build_job_status.value }}</td>
42+
<td data-exercise-id="{{ e.id }}" data-build-status="{{ e.build_job_status.value }}">{{ e.build_job_status.value }}</td>
4343
<td>
4444
{{ e.active_instances|length }} <br> {{ e.submission_heads()|length }} ({{ e.submissions()|length }})
4545
</td>
@@ -83,6 +83,45 @@ <h4 class="card-header">
8383
</div>
8484
{% endfor %}
8585

86+
<script>
87+
(function() {
88+
var cells = document.querySelectorAll('td[data-build-status]');
89+
var initial = {};
90+
var hasBuilding = false;
91+
cells.forEach(function(td) {
92+
var id = td.getAttribute('data-exercise-id');
93+
var status = td.getAttribute('data-build-status');
94+
initial[id] = status;
95+
if (status === 'BUILDING') hasBuilding = true;
96+
});
97+
98+
// Restore scroll position after reload (defer until page is fully laid out)
99+
var savedScroll = sessionStorage.getItem('exerciseListScroll');
100+
if (savedScroll !== null) {
101+
sessionStorage.removeItem('exerciseListScroll');
102+
var scrollY = parseInt(savedScroll);
103+
window.addEventListener('load', function() {
104+
window.scrollTo(0, scrollY);
105+
});
106+
}
107+
108+
if (!hasBuilding) return;
109+
110+
setInterval(function() {
111+
axios.get('/api/build-status').then(function(response) {
112+
var statuses = response.data;
113+
for (var id in initial) {
114+
if (statuses[id] && statuses[id] !== initial[id]) {
115+
sessionStorage.setItem('exerciseListScroll', window.scrollY);
116+
location.reload();
117+
return;
118+
}
119+
}
120+
});
121+
}, 3000);
122+
})();
123+
</script>
124+
86125
{% if importable|length %}
87126
<div class="card mb-5">
88127
<h4 class="card-header">

webapp/ref/view/api.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,6 @@ def api_getkeys():
591591
keys.append(s.pub_key)
592592

593593
resp = {"keys": keys}
594-
log.info(f"Returning {len(keys)} public-keys in total.")
595594
return ok_response(resp)
596595

597596

@@ -905,6 +904,14 @@ def api_instance_info():
905904
return ok_response(ret)
906905

907906

907+
@refbp.route("/api/build-status")
908+
@admin_required
909+
def api_build_status():
910+
exercises = Exercise.query.all()
911+
statuses = {str(e.id): e.build_job_status.value for e in exercises}
912+
return jsonify(statuses)
913+
914+
908915
# @refbp.route('/api/instance/diff', methods=('GET', 'POST'))
909916
# @limiter.limit('6 per minute')
910917
# def api_instance_diff():

0 commit comments

Comments
 (0)