Skip to content

Commit

Permalink
added FTV brackets preview page
Browse files Browse the repository at this point in the history
  • Loading branch information
biuti committed Sep 15, 2024
1 parent c8dafe0 commit 3d2e88e
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 0 deletions.
46 changes: 46 additions & 0 deletions airscore/core/frontendUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2694,3 +2694,49 @@ def get_task_from_file(task_id: int, file) -> bool:
task = Task.update_from_dict(task_id, task_info)
return True


def create_ftv_bracket(comp_id: int) -> list:
from comp import Comp
from task import Task
from pilot.flightresult import FlightResult

comp = Comp.read(comp_id)
comp.populate_from_tasks_result_files()
bracket = {}

t = Task()
t.comp_id = comp_id
t.task_num = comp.tasks[-1].task_num + 1
t.formula = comp.tasks[-1].formula
t.day_quality = 1
t.status = 'dummy task for FTV brackets calculation'
t.get_pilots()

for p in t.pilots:
p.score = 1000
p.result_type = 'goal'
comp.tasks.append(t)

comp.create_results_score_details()

# create data
for p in comp.results:
bracket[p['ID']] = p['score']

# need to add a dummy pilot to calculate min score
dummy = FlightResult(name='dummy')
dummy.result_type = 'goal'
comp.tasks[-1].pilots.append(dummy)

for p in comp.tasks[-1].pilots:
p.score = 0 if p.ID is not None else 1000

comp.create_results_score_details()
data = comp.json_elements

# add min and max score to data
for p in data['results']:
p['min_score'] = p['score']
p['max_score'] = bracket[p['ID']]

return data
15 changes: 15 additions & 0 deletions airscore/public/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,21 @@ def comp_result(compid: int):
return render_template('public/comp_overall.html', compid=compid, results=result_file)


@blueprint.route('/ftv_bracket/<int:compid>')
def ftv_bracket(compid: int):

data = frontendUtils.create_ftv_bracket(compid)
result_file = frontendUtils.get_pretty_data(data, result_type='comp')
if result_file == 'error':
return render_template('404.html')

for t in result_file['tasks']:
link, code = f"/task_result/{t['id']}", t['task_code']
t['link'] = f"<a href='{link}' target='_blank'>{code}</a>"

return render_template('public/ftv_bracket.html', compid=compid, results=result_file)


@blueprint.route('/country_overall/<int:compid>')
def country_overall(compid: int):
return render_template('public/country_overall.html', compid=compid)
Expand Down
99 changes: 99 additions & 0 deletions airscore/static/js/pop_ftv_bracket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
function populate_ftv_brackets(json){
$('#comp_name').text('Loading Results ...');
var taskNum = json.stats.valid_tasks
console.log('taskNum='+taskNum);
var columns = [];
// rankings
json.rankings.forEach( function(item, index) {
columns.push({data: 'rankings.'+item.rank_id.toString(), title: '#', name: item.rank_id.toString(), className: "text-right", defaultContent: '', visible: (index === 0) ? true : false});
});
columns.push({data: 'ID', title:'ID', className: "text-right", defaultContent: ''});
columns.push({data: 'fai_id', title:'FAI', className: "text-right", defaultContent: '', visible: false});
columns.push({data: 'civl_id', title:'CIVL', className: "text-right", defaultContent: '', visible: false});
columns.push({data: 'name', title:'Name'});
columns.push({data: 'nat', title:'NAT', name:'NAT', defaultContent: ''});
columns.push({data: 'sex', title:'Sex', defaultContent: '', visible: false});
columns.push({data: 'glider', title:'Equip', defaultContent: '', visible: false});
columns.push({data: 'glider_cert', title:'Class', defaultContent: '', visible: false});
columns.push({data: 'sponsor', title:'Sponsor', defaultContent: '', visible: false});
columns.push({data: 'max_score', title:'Max Score', className: "text-right"});
columns.push({data: 'min_score', title:'Min Score', className: "text-right"});
$('#results_table').DataTable( {
data: json.results,
paging: false,
searching: true,
saveState: true,
info: false,
dom: 'lrtip',
columns: columns,
rowId: function(data) {
return 'id_' + data.par_id;
},
initComplete: function(settings) {
var table = $('#results_table');
var rows = $("tr", table).length-1;
// Get number of all columns
var numCols = table.DataTable().columns().nodes().length;
console.log('numCols='+numCols);

// comp info
$('#comp_name').text(json.info.comp_name);
$('#comp_date').text(json.info.date_from + ' - ' + json.info.date_to);
if (json.info.comp_class != "PG") {
update_classes(json.info.comp_class);
}
// description text
let text = document.createTextNode('Score bracket applying FTV parameters to the overall results after a new fully valid task');
$('#comp_header').append(text);

// some GAP parameters
$('#formula tbody').append(
"<tr><td>Director</td><td>" + json.info.MD_name + '</td></tr>' +
"<tr><td>Location</td><td>" + json.info.comp_site + '</td></tr>' +
"<tr><td>Formula</td><td>" + json.formula.formula_name + '</td></tr>' +
"<tr><td>Overall Scoring</td><td>" + json.formula.overall_validity + ' (' + json.formula.validity_param + ')</td></tr>');
if (json.formula.overall_validity.toLowerCase() == 'ftv') {
$('#formula tbody').append(
"<tr><td>Assumed Total Validity</td><td>" + json.stats.total_validity + ' (FTV validity ' + json.stats.avail_validity + ')</td></tr>');
}
// remove empty cols and NAT if all pilots are from a single country
var natId = table.DataTable().column('NAT:name').index();
var natRef = table.DataTable().column(natId).data()[0];
for ( var col=1; col<numCols; col++ ) {
var empty = true;
table.DataTable().column(col).data().each( val => {
if (col == natId) {
if (val != natRef) {
empty = false;
}
}
else {
if (val != "") {
empty = false;
}
}
if (!empty) {
return false;
}
} );

if (empty) {
table.DataTable().column( col ).visible( false );
}
}

// class picker
$("#dhv option").remove(); // Remove all <option> child tags.
// at the moment we provide the highest EN rating for a class and the overall_class_filter.js uses this.
// if we want to be more specific and pass a list of all EN ratings inside a class we can do something like this: https://stackoverflow.com/questions/15759863/get-array-values-from-an-option-select-with-javascript-to-populate-text-fields
console.log(json.rankings);
$.each(json.rankings, function(index, item) {
$("#dhv").append(
$("<option></option>")
.text(item.rank_name)
.val(item.rank_id)
);
});
}
});
}
61 changes: 61 additions & 0 deletions airscore/templates/public/ftv_bracket.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{% extends "base.html"%}

{% block page_title %}
Competition Results - Overall
{% endblock %}

{% block head %}
<!-- CSS -->
<link href='/static/css/task.css' rel='stylesheet'>

<!-- JS -->
<script type='text/javascript' src='/static/js/utils.js'></script>
<script type='text/javascript' src='/static/js/microajax.minified.js'></script>
{% endblock %}

{% block back %}
<a href='/competition/{{ compid }}'>Back to Competition</a>
{% endblock %}

{% block content %}
<div class='container-fluid'>
<div class='row'>
<div class='col col-md-7 comp_header mt-1' id='comp_header'>
<h2 id='comp_name'></h2>
<h4 id='comp_date'></h4>
<h4 id='comp_director'></h4>
<select name='dhv' id='dhv' class='form-control col-md-4' placeholder='Class'>
<option value='' selected>Open</option>
<option value='A'>Novice</option>
<option value='B'>Fun</option>
<option value='C'>Sports</option>
<option value='D'>Serial</option>
<option value='CCC'>Competition</option>
</select>
</div>
<div class='col col-md-5 parameters'>
<table class='table table-sm' id='formula'>
<thead class='thead-light' id='formula_hd'>
<tr>
<th>Information</th>
<th></th>
</tr>
</thead>
<tbody class='small' id='formula_bd'></tbody>
</table>
</div>
</div>
{% from "macros.html" import datatable with context %}
{{ datatable('results_table') }}
<p>
<span id='created' class=''></span>
</p>
</div>
{% endblock %}

{% block js %}
<script src="{{ static_url_for('static', filename='js/enums.js') }}"></script>
<script src="{{ static_url_for('static', filename='js/pop_ftv_bracket.js') }}"></script>
<script src="{{ static_url_for('static', filename='js/class_filter.js') }}"></script>
<script type='text/javascript'>populate_ftv_brackets({{results|tojson}})</script>
{% endblock %}
2 changes: 2 additions & 0 deletions airscore/templates/users/comp_score_admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ <h4 class='tab-title font-weight-bold'>Comp Result Info:</h4>
<td colspan="2"><table id="tasks_table"></table></td>
</tr>
</table>
<h4 class='font-weight-bold'>FTV Brackets Info:</h4>
<p>If FTV is in use, at the url <i><a href="{{ url_for('public.ftv_bracket', compid=session.compid) }}" target="_blank">"/ftv_bracket/{{session.compid}}"</a></i> is available the FTV bracket for each pilot after a new fully valid task.</p>
</div>
</div>
</div>
Expand Down

0 comments on commit 3d2e88e

Please sign in to comment.