Skip to content

Commit

Permalink
track_admin page updated to the new Livetracking format
Browse files Browse the repository at this point in the history
  • Loading branch information
biuti committed Apr 30, 2021
1 parent 12bb5e6 commit 7da4d41
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 66 deletions.
6 changes: 4 additions & 2 deletions airscore/core/frontendUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -865,8 +865,10 @@ def track_result_output(pilot, task_id) -> dict:
data['Result'] = f'<a href="/map/{pilot.par_id}-{task_id}?back_link=0" target="_blank">{result}</a>'
if pilot.notifications:
data['notifications'] = f"{'<br />'.join(n.comment for n in pilot.notifications)}"
data['Result'] += f'<a class="text-warning p-1 ml-4" data-toggle="tooltip" ' \
f'title="{data["notifications"]}">[Notes]</a>'
data['Result'] += f'<a tabindex="0" class="p-1 ml-2" role="button" data-toggle="popover" ' \
f'data-container="body" data-trigger="focus" data-html="true" data-placement="top" ' \
f'title="Warning" data-content="{data["notifications"]}">' \
f'<span class="fas fa-exclamation-circle text-warning"></span></a>'

return data

Expand Down
70 changes: 44 additions & 26 deletions airscore/static/js/pop_track_admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ function populate_track_admin(task_id) {
return '<span class="btn btn-info">locked<span>';
}
else if(data['Result']=='Not Yet Processed' | data['Result'].indexOf("G record") >= 0){
var buttons;
let buttons;
buttons =
'<button id="ABS' + data.par_id +'" class="btn btn-primary mt-3" type="button" onclick="set_result(' + data.par_id +',\'abs\')">Set ABS</button> '
+'<button id="MD' + data.par_id +'" class="btn btn-primary mt-3" type="button" onclick="set_result(' + data.par_id +',\'mindist\')">Set Min Dist</button> '
+'<button id="DNF' + data.par_id +'" class="btn btn-primary mt-3" type="button" onclick="set_result(' + data.par_id +',\'dnf\')">Set DNF</button> '
+'<button id="TrackUp' + data.par_id +'" class="btnupload btn btn-primary mt-3" onclick="choose_file(' + data.par_id +');">Upload Track</button>'
'<button id="ABS' + data.par_id +'" class="btn btn-primary mt-1 mb-1" type="button" onclick="set_result(' + data.par_id +',\'abs\')">Set ABS</button> '
+'<button id="MD' + data.par_id +'" class="btn btn-primary mt-1 mb-1" type="button" onclick="set_result(' + data.par_id +',\'mindist\')">Set Min Dist</button> '
+'<button id="DNF' + data.par_id +'" class="btn btn-primary mt-1 mb-1" type="button" onclick="set_result(' + data.par_id +',\'dnf\')">Set DNF</button> '
+'<button id="TrackUp' + data.par_id +'" class="btnupload btn btn-primary mt-1 mb-1" onclick="choose_file(' + data.par_id +');">Upload Track</button>'
+'<div id="filediv' + data.par_id +'" class = "hideatstart" > '
+'<input id="fileupload' + data.par_id +'" type="file" size="chars" class="custom-file-input" oninput="filesize(this);" data-url="/users/_upload_track/'+ task_id + '/' + data.par_id + '" name="tracklog" >'
+'<input id="fileupload_NO_G' + data.par_id +'" type="file" size="chars" class="custom-file-input" oninput="filesize(this);" data-url="/users/_upload_track/'+ task_id + '/' + data.par_id + '" name="tracklog_NO_G" >'
Expand All @@ -42,15 +42,20 @@ function populate_track_admin(task_id) {
else if (data['Result']=='Processing..') {
return data['file']
}
else if ( ['ABS', 'DNF', 'Min Dist'].includes(data.Result) ){
return '<button class="btn btn-warning mt-1 mb-1" type="button" onclick="delete_track('+ data.track_id +','+ data.par_id +')">Set NYP</button> ';
}
else {
let column = '<button class="btn btn-danger mt-3" type="button" onclick="delete_track('+ data.track_id +','+ data.par_id +')">Delete Track</button> ';
if ( !['ABS', 'DNF', 'Min Dist'].includes(data.Result) ) {
if (data.outdated) column += '<button class="btn btn-warning mt-3" id="button_check_'+data.par_id+'" type="button" onclick="recheck_track('+ data.track_id +','+ data.par_id +')">Recheck Track</button> ';
}
return column;
let column = '<button class="btn btn-danger mt-1 mb-1" type="button" onclick="delete_track('+ data.track_id +','+ data.par_id +')">Delete Track</button> ';
if (data.outdated) column += '<button class="btn btn-warning mt-3" id="button_check_'+data.par_id+'" type="button" onclick="recheck_track('+ data.track_id +','+ data.par_id +')">Recheck Track</button> ';
return column
}
}
}
}],
],
drawCallback: function() {
refresh_popover()
},
initComplete: function(response) {
let rows = response.json.data;
$(".hideatstart").hide();
Expand All @@ -77,6 +82,7 @@ function update_row(new_data){
new_data.name = $('#tracks').DataTable().row( $('tr#id_'+ new_data.par_id)).data()['name'];
table.fnUpdate(new_data, $('tr#id_'+ new_data.par_id), undefined, false);
$(".hideatstart").hide();
refresh_popover();
console.log(new_data.ID+' '+new_data.name);
}

Expand Down Expand Up @@ -290,34 +296,39 @@ function get_lt_status() {
$('#lt_modal_button').hide();
console.log(response);
if ( response.success ) {
$('#lt_details_main').html('STATUS: ' + response.status);
if (response.meta) {
let data = '';
$.each(response.meta, key => {
let title = key.replace(/_/g,' ');
let value = response.meta[key];
if (key == 'last_update') {
let time = parseInt(new Date().getTime() / 1000);
value = time - parseInt(response.meta[key]);
}
data += title + ': <span class="font-weight-bold">' + value + '</span><br />';
});
$('#lt_details_secondary').html(data);
// Livetrack service is currently running for the task
let status = 'STATUS: ';
let details = 'Updated: ';
let info = '';
if ( response.status ) {
details += (response.status.updated ? response.status.updated + ' (UTC)' : 'Unknown') + '<br />';
if ( response.status.finished ) status += 'Terminated <br />'
else if ( response.status.scheduled ) {
status += 'Running <br />';
info = 'Next update schedule: ' + (response.registry.scheduled.length ? response.registry.scheduled[0] : 'Unknown');
}
else status += 'Unknown';
}
else status += 'Unknown';
$('#lt_details_main').html(status + details);
$('#lt_details_secondary').html(info);

$('#lt_modal_button').attr("onclick","window.open('/live/"+taskid+"', '_blank')").text('LIVE Rankings').show();
$('#livetracking_button').removeClass( "btn-primary btn-warning" ).addClass( "btn-success" ).text('Live Tracking Info');
update_track_pilot_stats();
}
else if ( response.error) {
else if ( response.error ) {
// Livetrack service started but stopped with errors
$('#lt_details_main').text('ERROR');
$('#lt_details_secondary').text(response.error);
$('#lt_modal_button').attr("onclick","start_livetracking()").text('TRY AGAIN').show();
$('#livetracking_button').removeClass( "btn-primary btn-success" ).addClass( "btn-warning" ).text('Live Tracking');
update_track_pilot_stats();
}
else {
// Livetrack has not run yet on this task
$('#lt_details_main').text('Start Live Tracking');
$('#lt_details_secondary').text('');
$('#lt_details_secondary').html('To start livetrack service, retrieving tracks in real time from ' + task_info.track_source + ', click START');
$('#lt_modal_button').attr("onclick","start_livetracking()").text('START').show();
$('#livetracking_button').text('Live Tracking');
$('#livetracking_button').removeClass( "btn-warning btn-success" ).addClass( "btn-primary" ).text('Live Tracking');
Expand All @@ -334,6 +345,7 @@ function start_livetracking() {
dataType: "json",
success: function ( response ) {
$('#lt_modal_button').hide();
console.log(response);
if ( response.success ) {
$('#livetracking_button').text('Live Tracking Info');
}
Expand Down Expand Up @@ -551,6 +563,12 @@ $(document).ready(function(){
update_row(data.message);
toastr.warning(data.message.text, 'G Record Fail', {timeOut: 5000});
}, false);
es.addEventListener('livetracking', function(event) {
let data = JSON.parse(event.data);
toastr.success(data.id + ': ' + data.message, 'Live Tracking', {timeOut: 5000});
console.log(data.id + ': ' + data.message, 'Live Tracking')
get_lt_status();
}, false);
es.addEventListener('reload', function(event) {
clear_flashed_messages();
populate_track_admin(taskid);
Expand Down
4 changes: 4 additions & 0 deletions airscore/static/js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,7 @@ function getCookie(cname) {
}
return "";
}

function refresh_popover() {
$('[data-toggle="popover"]').popover();
}
21 changes: 8 additions & 13 deletions airscore/templates/users/track_admin.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
{% extends "base_admin.html"%}

{% block page_title %}
Track Management
Track Management
{% endblock %}

{% block css %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet"/>
<link href="{{ static_url_for('static', filename='css/task.css') }}" rel="stylesheet">
{% endblock %}

{% block back %}
Expand All @@ -33,7 +32,6 @@
{% endblock %}

{% block content %}

{% if not session.is_editor %}
<h2>You are not authorised to access this page as you are not a scorekeeper of this competition</h2>

Expand All @@ -48,10 +46,12 @@ <h2>You are not authorised to access this page as you are not a scorekeeper of t
<button id='{{ task_info.track_source }}_button' class='btn btn-primary ml-2' onclick='get_{{ task_info.track_source }}_tracks()'>
{{ task_info.track_source|title }}
</button>
{% if task_info.lt_active is defined %}
<button id='livetracking_button' class='btn btn-primary ml-2'>
Live Tracking
</button>
{% endif %}
{% endif %}
{% if telegram %}
<button id='telegram_button' class='btn btn-primary ml-2' onclick='send_telegram({{ taskid }});'>
Send Telegram Update
Expand All @@ -74,13 +74,12 @@ <h3 id='TracksProcessed'></h3>
</div>

<div class='container' id='main'>
<br>
<br />
<table id='tracks' class='row-border stripe compact mb-1' cellspacing='0' width='100%'>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<!-- <th>Status</th>-->
<th>Result</th>
<th></th>
</tr>
Expand Down Expand Up @@ -120,7 +119,7 @@ <h4 class='modal-title'>Bulk IGC Zip File Upload</h4>
</div>
</div>
</div>
<!-bulk-Modal ends here--->
<!-- bulk-Modal ends here--->

<!-- process log Modal starts here -->
<div class='modal fade' id='ProcessModal' tabindex='-1' role='dialog' aria-labelledby='ProcessModalTitle'
Expand Down Expand Up @@ -171,21 +170,18 @@ <h4 class='modal-title'>Live Tracking Details</h4>
</div>
</div>
<!--- livetracking details Modal ends here--->

{% endif %}
{% endblock %}

{% if session.is_editor %}
{% block js %}
<!--<script src="{{ static_url_for('static', filename='js/jquery.initialize.js') }}"></script>-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<script src="{{ static_url_for('static', filename='js/utils.js') }}"></script>
<script src="{{ static_url_for('static', filename='js/pop_track_admin.js') }}"></script>
<script src="{{ static_url_for('static', filename='js/jquery-file-upload/jquery.ui.widget.js') }}"></script>
<script src="{{ static_url_for('static', filename='js/jquery-file-upload/jquery.iframe-transport.js') }}"></script>
<script src="{{ static_url_for('static', filename='js/jquery-file-upload/jquery.fileupload.js') }}"></script>
<!--<script src="{{ static_url_for('static', filename='js/jquery-alert.js') }}"></script>-->
<script>
<script src="{{ static_url_for('static', filename='js/pop_track_admin.js') }}"></script>
<script type=text/javascript>
var production = {{ production|tojson }};
var taskid = {{ taskid|tojson }};
var task_info = {{ task_info|tojson }};
Expand All @@ -195,5 +191,4 @@ <h4 class='modal-title'>Live Tracking Details</h4>
var url_sse_stream = "{{ url_for('sse.stream', channel=current_user.username)}}";
</script>
{% endblock %}
{% endif%}

{% endif %}
70 changes: 45 additions & 25 deletions airscore/user/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1098,14 +1098,19 @@ def _get_tracks_processed(taskid: int):
@session_task
@state_messages
def track_admin(taskid: int):
from Defines import TELEGRAM
task = next((t for t in session['tasks'] if t['task_id'] == taskid), None)
from Defines import TELEGRAM, LIVETRACKDIR
compid = int(session['compid'])

'''check livetracking availability'''
if session['task'].get('track_source') == 'flymaster':
session['task']['lt_active'] = False
if Path(LIVETRACKDIR, str(taskid)).is_file():
session['task']['lt_active'] = True

formats = frontendUtils.get_igc_filename_formats_list()

return render_template('users/track_admin.html', taskid=taskid, compid=compid, filename_formats=formats,
production=frontendUtils.production(), task_info=task, telegram=TELEGRAM)
production=frontendUtils.production(), task_info=session['task'], telegram=TELEGRAM)


@blueprint.route('/_set_result/<int:taskid>', methods=['POST'])
Expand Down Expand Up @@ -2187,29 +2192,44 @@ def _get_lt_info(taskid: int):
from Defines import LIVETRACKDIR
from result import open_json_file
from calcUtils import epoch_to_string
job_id = f'job_livetracking_task_{taskid}'
job = current_app.task_queue.fetch_job(job_id)
if job is None:
'''check if we have a lt file'''
if Path(LIVETRACKDIR, str(taskid)).is_file():
data = open_json_file(Path(LIVETRACKDIR, str(taskid)))
timestamp = epoch_to_string(data['file_stats']['timestamp'], data['info']['time_offset'])
resp = {
'success': True,
'status': 'ended',
'meta': {'timestamp': timestamp }
}
else:
resp = {'success': False, 'status': 'unknown'}
elif job.is_failed:
resp = {'success': False, 'error': job.exc_info.strip().split('\n')[-1]}
else:
resp = {
'success': True,
'status': job.get_status(),
'meta': job.meta,
'result': job.result,

started = False
timestamp = None
scheduled = False
finished = False
error = False
q = current_app.task_queue
sched = q.scheduled_job_registry
ended = q.finished_job_registry
failed = q.failed_job_registry
job_id = f'livetracking_task_{taskid}'

'''check if LT started'''
if Path(LIVETRACKDIR, f'{taskid}').is_file():
started = True
data = open_json_file(Path(LIVETRACKDIR, f'{taskid}'))
timestamp = epoch_to_string(data['file_stats']['timestamp'])
finished = 'terminated' in data['file_stats']['status']

'''check if LT is scheduled'''
if any(el.endswith(job_id) for el in sched.get_job_ids()):
# sjob = q.fetch(next(el.endswith(job_id) for el in sched.get_job_ids()))
sjob_id = next(el for el in sched.get_job_ids() if el.endswith(job_id))
scheduled = sched.get_scheduled_time(sjob_id)
elif any(el.endswith(job_id) for el in failed.get_job_ids()):
sjob = q.fetch(next(el for el in failed.get_job_ids() if el.endswith(job_id)))
error = sjob.exc_info.strip().split('\n')[-1]

resp = {
'success': started and (scheduled or finished),
'status': dict(updated=timestamp, scheduled=scheduled, finished=finished),
'error': error,
'registry': {
'finished': [el for el in ended.get_job_ids() if el.endswith(job_id)],
'failed': [el for el in failed.get_job_ids() if el.endswith(job_id)],
'scheduled': [f"{el}: {sched.get_scheduled_time(el)}" for el in sched.get_job_ids() if el.endswith(job_id)]
}
}

return jsonify(resp)

Expand Down

0 comments on commit 7da4d41

Please sign in to comment.