User Interface improvement, adding routine management, ...

This commit is contained in:
Trullemans Gregory 2021-11-28 15:05:00 +01:00
parent 6765b54b2a
commit 362f8af3e3
29 changed files with 873 additions and 98 deletions

View File

@ -12,6 +12,7 @@ from django.contrib.auth import authenticate, login as auth_login, logout as aut
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods
from objective.models import Routine
from profiles.models import Profile
from followup.models import Accident, Skill, MindState, Point
@ -69,7 +70,7 @@ def home(request):
"""
Génère la page d'accueil du site basée sur la saison (si celle-ci est connue)
"""
event_list = Event.objects.all().order_by('datebegin')[:5]
event_list = Event.objects.filter(datebegin__gte=timezone.now()).order_by('datebegin')[:5]
last_updated_gymnast = Gymnast.objects.filter(
Q(mindstate__created_at__gt=request.user.last_login) |
@ -79,7 +80,21 @@ def home(request):
Q(can_do_skill__created_at__gt=request.user.last_login)
).distinct()
context = {'event_list': event_list, 'last_updated_gymnast': last_updated_gymnast}
nb_gymnast = Gymnast.objects.filter(is_active=True).count()
nb_event = Event.objects.all().count()
nb_skill = Skill.objects.all().count()
nb_routine = Routine.objects.all().count()
nb_score = Point.objects.all().count()
context = {
'event_list': event_list,
'last_updated_gymnast': last_updated_gymnast,
'nb_gymnast': nb_gymnast,
'nb_event': nb_event,
'nb_skill': nb_skill,
'nb_routine': nb_routine,
'nb_score': nb_score,
}
return render(request, "ultron/dashboard/dashboard.html", context)

View File

@ -151,7 +151,7 @@ class ScoreForm(forms.ModelForm):
class AccidentForm(forms.ModelForm):
class Meta:
model = Accident
fields = ("gymnast", "date", "informations") # , "educative"
fields = ('gymnast', 'date', 'skill', 'nb_week_off', 'informations')
widgets = {
'date': forms.DateInput(
attrs={
@ -160,9 +160,12 @@ class AccidentForm(forms.ModelForm):
"value": date.today().strftime("%Y-%m-%d"),
}
),
"gymnast": forms.HiddenInput(),
# "educative": forms.HiddenInput(),
"informations": forms.Textarea(
'gymnast': forms.HiddenInput(),
'skill': forms.HiddenInput(),
'nb_week_off': forms.NumberInput(
attrs={"class": "form-control", "placeholder": "xx"}
),
'informations': forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Informations about accident: context (why, where, …), consequencies, …",
@ -179,15 +182,15 @@ class AccidentForm(forms.ModelForm):
}
)
)
# educative_related = forms.CharField(
# widget=forms.TextInput(
# attrs={
# "class": "form-control",
# "placeholder": "Searching skill…",
# "data-ref": "#id_educative",
# }
# )
# )
skill_related = forms.CharField(
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Searching skill…",
"data-ref": "#id_skill",
}
)
)
class MindStateForm(forms.ModelForm):
class Meta:
@ -202,6 +205,7 @@ class MindStateForm(forms.ModelForm):
"value": date.today().strftime("%Y-%m-%d"),
}
),
'event': forms.HiddenInput(),
'score': forms.NumberInput(
attrs={"class": "form-control", "placeholder": "xx"}
),
@ -221,4 +225,15 @@ class MindStateForm(forms.ModelForm):
'data-ref': '#id_gymnast',
}
)
)
event_related = forms.CharField(
required=False,
widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'Searching event…',
'data-ref': '#id_event',
}
)
)

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.8 on 2021-11-28 06:18
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('planning', '0001_initial'),
('followup', '0002_alter_chrono_type'),
]
operations = [
migrations.AddField(
model_name='mindstate',
name='event',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mindstate', to='planning.event'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.8 on 2021-11-28 13:12
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('objective', '0004_alter_educative_difficulty'),
('followup', '0003_mindstate_event'),
]
operations = [
migrations.AlterField(
model_name='accident',
name='skill',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='accident', to='objective.skill', verbose_name='Skill'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.8 on 2021-11-28 13:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('followup', '0004_alter_accident_skill'),
]
operations = [
migrations.AddField(
model_name='accident',
name='nb_week_off',
field=models.SmallIntegerField(blank=True, null=True),
),
]

View File

@ -58,7 +58,8 @@ class Chrono(models.Model):
class Accident(Markdownizable):
"""
La classe `Accident` permet d'indiquer qu'un gymnaste a eu un accident.
La classe `Accident` permet d'indiquer qu'un gymnaste a eu un accident, en liaison avec un
skill ou non.
"""
class Meta:
@ -77,8 +78,11 @@ class Accident(Markdownizable):
verbose_name="Skill",
related_name="accident",
on_delete=models.CASCADE,
blank=True,
null=True,
)
date = models.DateField(verbose_name="Date")
nb_week_off = models.SmallIntegerField(blank=True, null=True, verbose_name="# week off")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@ -155,6 +159,7 @@ class MindState(Markdownizable):
gymnast = models.ForeignKey(Gymnast, on_delete=models.CASCADE, default=None, related_name="mindstate")
date = models.DateField(default=date.today, verbose_name="Date")
event = models.ForeignKey(Event, on_delete=models.CASCADE, default=None, blank=True, null=True, related_name="mindstate")
score = models.PositiveSmallIntegerField(verbose_name="Score")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

View File

@ -5,7 +5,9 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.db.models import Q
from people.models import Gymnast
from planning.models import Event
from .models import Chrono, MindState, Point, Accident
from .forms import ChronoForm, LearnedSkillForm, ScoreForm, AccidentForm, MindStateForm
import simplejson
@ -185,7 +187,7 @@ def accident_create_or_update(request, accidentid=None):
accident = get_object_or_404(Accident, pk=accidentid)
data = {
"gymnast_related": accident.gymnast,
# "educative_related": accident.educative,
"skill_related": accident.skill,
}
else:
accident = None
@ -237,7 +239,7 @@ def mindstate_listing(request, gymnastid=None):
@login_required
@require_http_methods(["GET", "POST"])
def mindstate_create_or_update(request, mindstateid=None, gymnastid=None):
def mindstate_create_or_update(request, mindstateid=None, gymnastid=None, eventid=None):
"""
Formulaire de création d'un nouvel accident.
"""
@ -246,14 +248,19 @@ def mindstate_create_or_update(request, mindstateid=None, gymnastid=None):
mindstate = get_object_or_404(MindState, pk=mindstateid)
data = {
"gymnast_related": mindstate.gymnast,
"event_related": mindstate.event
}
else:
mindstate = None
data = {}
if gymnastid is not None:
gymnast = get_object_or_404(Gymnast, pk=gymnastid)
data["gymnast"] = gymnastid
data["gymnast_related"] = str(gymnast)
data['gymnast'] = gymnastid
data['gymnast_related'] = str(gymnast)
if eventid is not None:
event = get_object_or_404(Event, pk=eventid)
data['event'] = eventid
data['event_related'] = str(event)
if request.method == "POST":
form = MindStateForm(request.POST, instance=mindstate)

27
objective/forms.py Normal file
View File

@ -0,0 +1,27 @@
from django import forms
from datetime import date
from .models import Routine, RoutineSkill
class RoutineForm(forms.ModelForm):
class Meta:
model = Routine
fields = ("long_label", "short_label", "difficulty", "level", "active", 'informations')
widgets = {
# Champs obligatoires de la classe mère.
'long_label': forms.TextInput(
attrs={"class": "form-control", "placeholder": "Routine's long name"}
),
'short_label': forms.TextInput(
attrs={"class": "form-control", "placeholder": "Routine's short name"}
),
'informations': forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Informations about the psychological state of mind : context (why, where, …), possible consequencies, …",
}
),
'difficulty': forms.HiddenInput(),
'level': forms.HiddenInput(),
'active': forms.HiddenInput(),
}

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.8 on 2021-11-28 11:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('objective', '0003_auto_20211127_1312'),
]
operations = [
migrations.AlterField(
model_name='educative',
name='difficulty',
field=models.DecimalField(decimal_places=1, default=0.0, max_digits=3, verbose_name='Difficulty'),
),
]

View File

@ -15,7 +15,7 @@ class Educative(Markdownizable):
long_label = models.CharField(max_length=255, verbose_name="Long Name")
short_label = models.CharField(max_length=255, verbose_name="Short Name")
difficulty = models.DecimalField(
max_digits=3, decimal_places=1, verbose_name="Difficulty"
max_digits=3, decimal_places=1, verbose_name="Difficulty", default=0.000
)
level = models.PositiveSmallIntegerField(verbose_name="Level", default=0)
rank = models.PositiveSmallIntegerField(verbose_name="Rank", default=0)
@ -57,7 +57,7 @@ class TouchPosition(models.Model):
is_default = models.BooleanField(verbose_name="Défault ?")
def __str__(self):
return "%s" % (self.label)
return "%s" % (self.long_label)
def get_default_position():

View File

@ -19,18 +19,18 @@ skill_urlpatterns = [
routine_urlpatterns = [
path(r"search/", views.routine_listing),
path(r"lookup/", views.routine_lookup),
# path(r"add/", views.routine_create_or_update, name="routine_create"),
# path(
# r"edit/<int:routineid>/", views.routine_create_or_update, name="routine_update"
# ),
path(r"add/", views.routine_create_or_update, name="routine_create"),
path(
r"edit/<int:routineid>/", views.routine_create_or_update, name="routine_update"
),
path(r"<int:routineid>", views.routine_details, name="routine_details"),
# path(r"compose/<int:routineid>/", views.compose_routine, name="compose_routine"),
# path(
# r"<int:routineid>/add_skill/<int:skillid>/order/<int:order>/",
# views.link_skill_to_routine,
# name="link_skill_to_routine",
# ),
path(r"compose/<int:routineid>/", views.compose_routine, name="compose_routine"),
path(
r"<int:routineid>/add_skill/<int:skillid>/order/<int:order>/",
views.link_skill_to_routine,
name="link_skill_to_routine",
),
# # path(r'<int:routineid>/del_skill/<int:skillid>/order/<int:order>/', views.delete_skill_from_routine, name="delete_skill_from_routine"),
# path(
# r"<int:routineid>/order/<int:order>/",

View File

@ -3,9 +3,11 @@ from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods
from django.http import HttpResponse, HttpResponseRedirect
from django.db.models import Q
from django.urls import reverse
from people.models import Gymnast
from .models import Skill, Routine
from .models import Skill, Routine, RoutineSkill
from .forms import RoutineForm
import simplejson
@ -19,14 +21,14 @@ def skill_lookup(request):
"""
results = []
pattern = request.GET.get("pattern", None)
pattern = request.GET.get('pattern', None)
# Ignore queries shorter than length 3
if pattern is not None and len(pattern) > 3:
model_results = Skill.objects.filter(
Q(short_label__icontains=pattern) | Q(long_label__icontains=pattern)
)
results = [{"ID": x.id, "Name": str(x)} for x in model_results]
results = [{'ID': x.id, 'Name': str(x), 'Notation': x.notation} for x in model_results]
json = simplejson.dumps(results)
return HttpResponse(json, content_type="application/json")
@ -91,7 +93,7 @@ def routine_listing(request):
routine_list = Routine.objects.all()
context = {"routine_list": routine_list}
return render(request, "routine_list.html", context)
return render(request, "objectives/routines/list.html", context)
@login_required
@ -172,4 +174,72 @@ def routine_details(request, routineid):
routine.save()
context = {"routine": routine, "skill_link_list": routine.skill_links.all()}
return render(request, "objectives/routines/details.html", context)
return render(request, "objectives/routines/details.html", context)
@login_required
@require_http_methods(["GET", "POST"])
def routine_create_or_update(request, routineid=None):
""" Création d'une série.
Args:
routine_id (int): identifiant d'un object de classe <routine>.
"""
if routineid:
routine = get_object_or_404(Routine, pk=routineid)
else:
routine = None
if request.method == "POST":
form = RoutineForm(request.POST, instance=routine)
if form.is_valid():
routine = form.save()
# ici faire un FOR skill in form_skills_list:
# record.save() # ca sauve le record dans la table RoutineSkill
# something like this : http://stackoverflow.com/questions/3074938/django-m2m-form-save-through-table
# TO_FRED : can you help me ?
return HttpResponseRedirect(reverse("routine_details", args=(routine.pk,)))
else:
print(form.errors)
else:
form = RoutineForm(instance=routine)
context = {"form": form, "routineid": routineid}
return render(request, "objectives/routines/create.html", context)
@login_required
@require_http_methods(["GET"])
def compose_routine(request, routineid):
"""
Récupère une routine et les sauts associés.
"""
routine = get_object_or_404(Routine, pk=routineid)
number_of_skill = routine.skill_links.all().count()
context = {
"routine": routine,
"skill_link_list": routine.skill_links.all(),
"number_of_skill": number_of_skill,
}
return render(request, "objectives/routines/compose.html", context)
@require_http_methods(["GET"])
def link_skill_to_routine(request, routineid, skillid, order):
"""
Recoit trois informations permettant de lier complètement un saut à une routine
"""
routine = get_object_or_404(Routine, pk=routineid)
skill = get_object_or_404(Skill, pk=skillid)
link, created = RoutineSkill.objects.get_or_create(
routine=routine, skill=skill, rank=order
)
# context = {'link':link, 'created':created}
# return render(request, 'compose_routine.html', context)
return HttpResponse(200, (link, created))
# except:
# return False

View File

@ -69,7 +69,7 @@ def event_create_or_update(request, eventid=None):
form = EventForm(instance=event, initial=data)
context = {"form": form, "eventid": eventid}
return render(request, "events/create.html", context)
return render(request, "planning/events/create.html", context)
@require_http_methods(["GET"])
@ -158,7 +158,7 @@ def event_listing(request):
"""
event_list = __get_event_list(request)
context = {"event_list": event_list}
return render(request, "events/list.html", context)
return render(request, "planning/events/list.html", context)
@login_required
@ -186,4 +186,4 @@ def event_detail(request, eventid=None):
context = {"event": event, "gymnast_list": gymnasts}
return render(request, "events/details.html", context)
return render(request, "planning/events/details.html", context)

View File

@ -60,6 +60,7 @@
{% menuitem 'home' 'fal fa-chart-pie' 'Dashboard' %}
{% menuitem 'gymnast_list' 'tim-icons icon-badge' 'Gymnasts' %}
{% menuitem 'skill_list' 'tim-icons icon-molecule-40' 'Skills' %}
{% menuitem 'routine_list' 'tim-icons icon-components' 'Routine' %}
<!-- {% menuitem 'event_list' 'tim-icons icon-calendar-60' 'Events' %} -->
{% menuitem 'event_list' 'fal fa-calendar-alt' 'Events' %}
{% menuitem 'accident_list' 'tim-icons icon-notes' 'Accidents' %}

View File

@ -25,9 +25,24 @@
{% if form.gymnast.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.gymnast.errors %}{{error}}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_skill" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Skill</label>
<div class="col-8 col-sm-8 col-md-6 col-lg-6 col-xl-6 {% if form.skill.errors %}has-danger{% endif %}">
{{ form.skill }}
{{ form.skill_related }}
{% if form.skill.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.skill.errors %}{{error}}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_nb_week_off" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-2 col-form-label"># Week off</label>
<div class="col-sm-5 col-md-4 col-lg-2 {% if form.nb_week_off.errors %}has-danger{% endif %}">
{{ form.nb_week_off }}
{% if form.nb_week_off.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.nb_week_off.errors %}{{error}}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_information" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Informations</label>
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-9 {% if form.id_information.errors %}has-danger{% endif %}">
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-9 {% if form.id_informations.errors %}has-danger{% endif %}">
{{ form.informations }}
</div>
</div>
@ -39,7 +54,9 @@
</div>
</div>
</div>
{% endblock %}
{% block footerscript %}
<script type="text/javascript" >
$(function(){
blackDashboard.initDateTimePicker();
@ -74,18 +91,18 @@
}
});
$('#id_educative_related').autocomplete({
$('#id_skill_related').autocomplete({
source: function(request, response) {
$.ajax({
url: '/skill/lookup/?pattern=' + $('#id_educative_related').val(),
url: '/skill/lookup/?pattern=' + $('#id_skill_related').val(),
dataType: "json",
success: function(data) {
if(data.length != 0) {
response($.map(data, function(item) {
return {
label: item.label,
value: item.label,
skillid: item.id
label: item.Name,
value: item.Name,
skillid: item.ID
}
}))
} else {
@ -105,5 +122,4 @@
});
});
</script>
{% endblock %}

View File

@ -9,8 +9,10 @@
<h4 class="card-title mb-0">Accident : {{ accident.date | date:"d-m-Y" }}</h4>
</div>
<div class="card-body">
<a href="{% url 'gymnast_details' accident.gymnast.id %}">{{ accident.gymnast }}</a>
<br />
<a href="{% url 'gymnast_details' accident.gymnast.id %}">{{ accident.gymnast }}</a><br />
{% if accident.nb_week_off %}
{{ accident.nb_week_off }} week(s) off.<br />
{% endif %}
<br />
{{ accident.to_markdown | safe }}

View File

@ -13,8 +13,9 @@
<tr>
<th style="width: 3%"></th>
<th class="header text-left" style="width: 10%">Date</th>
<th class="header text-left" style="width: 45%">Gymnast</th>
<th style="width: 42%">Skill</th>
<th class="header text-left" style="width: 30%">Gymnast</th>
<th style="width: 30%">Skill</th>
<th style="width: 25%"># Week off</th>
</tr>
</thead>
<tbody>
@ -29,7 +30,20 @@
</td>
<td class="text-left"><a href="{% url 'accident_details' accident.id %}">{{ accident.date | date:"d-m-Y" }}</a></td>
<td class="text-left"><a href="{% url 'gymnast_details' accident.gymnast.id %}">{{ accident.gymnast }}</a></td>
<td class="text-left"><a href="{% url 'skill_details' accident.skill.id %}">{{ accident.skill }}</a></td>
<td class="text-left">
{% if accident.skill %}
<a href="{% url 'skill_details' accident.skill.id %}">{{ accident.skill }}</a>
{% else %}
-
{% endif %}
</td>
<td class="text-right">
{% if accident.nb_week_off %}
{{ accident.nb_week_off }}
{% else %}
-
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>

View File

@ -30,6 +30,18 @@
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{error}}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_event" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-2 col-form-label">event</label>
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-10 {% if form.date.errors %}has-danger{% endif %}">
{{ form.event }}
{{ form.event_related }}
{% if form.eventt.errors %}
<label class="text-danger" for="id_eventt" id="event-error">
{% for error in form.event.errors %}{{ error }}{% endfor %}
</label>
{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_score" class="col-4 col-sm-3 col-md-3 col-lg-3 col-xl-2 col-form-label">Score</label>
<div class="col-sm-5 col-md-4 col-lg-2 {% if form.score.errors %}has-danger{% endif %}">
@ -88,6 +100,35 @@
}
});
$('#id_event_related').autocomplete({
source: function(request, response) {
$.ajax({
url: '/event/lookup/?pattern=' + $('#id_event_related').val(),
dataType: "json",
success: function(data) {
if(data.length != 0) {
response($.map(data, function(item) {
return {
label: item.Name,
value: item.Name,
gymnastid: item.ID
}
}))
} else {
response([{ label: 'No result found.', value: '' }]);
};
},
error: function (exception) {
console.log(exception);
}
});
},
minLength: 3,
select: function (event, ui) {
$($(this).data('ref')).val(ui.item.gymnastid);
}
});
});
</script>
{% endblock %}

View File

@ -0,0 +1,106 @@
{% extends "base.html" %}
<!-- {% block page_title %}.: New Routine :.{% endblock %} -->
<!-- {% block title %}Routine{% endblock %} -->
{% block content %}
<div class="row justify-content-center">
<div class="col-12 col-sm-12 col-md-8 col-lg-8 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">Compose Routine : {{ routine.long_label }}</h4>
</div>
<div class="card-body">
<ol>
{% for link in skill_link_list %}
<li>
<div class="form-group row pb-0 mb-0">
<label class="col-1 col-sm-1 col-md-1 col-lg-1 col-xl-1 col-form-label text-right">&nbsp;</label>
<div class="col-11 col-sm-11 col-md-11 col-lg-11 col-xl-11 pt-2 text-danger">
{{ link.skill.notation }}
</div>
</div>
</li>
{% endfor %}
<li>
<div class="form-group row">
<label class="col-1 col-sm-1 col-md-1 col-lg-1 col-xl-1 col-form-label text-right">&nbsp;</label>
<div class="col-11 col-sm-11 col-md-11 col-lg-11 col-xl-11">
<input type="text" name="skill" placeholder="Skill" class="form-control" id="skill">
</div>
</div>
</li>
</ol>
</div>
<div class="card-footer pt-0">
<a href="{% url 'routine_details' routine.id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="tim-icons icon-double-left"></i>
</button>
</a>
</div>
</div>
</div>
</div>
{% endblock %}
{% block footerscript %}
<script type="text/javascript" >
$(document).ready(function() {
var number_of_skill = {{ number_of_skill }};
function insert_selected_skill(skill_label)
{
$('#minusButton').remove();
$('ol li:last-child').before('<li><div class="form-group row"><label class="col-1 col-sm-1 col-md-1 col-lg-1 col-xl-1 col-form-label text-right">&nbsp;</label><div class="col-3 col-sm-3 col-md-3 col-lg-3 col-xl-3 pt-2">' + skill_label + '</div><div class="col-1 col-sm-1 col-md-1 col-lg-1 col-xl-1"><button type="button" class="btn btn-warning btn-sm" id="minusButton">-</button></div></div></li>');
$('#skill').val('');
}
$('body').on('click', '#minusButton', function(event){
// alert('Suppression du skill !');
$.ajax({
url: '/routine/' + {{ routine.id }} + '/order/' + number_of_skill + '/'
}).done(function() {
// alert('suppression du li');
$('ol li:last-child').prev().remove();
});
});
$('#skill').autocomplete({
source: function(request, response) {
$.ajax({
url: '/skill/lookup/?pattern=' + request.term,
dataType: "json",
success: function(data) {
if(data.length != 0) {
response($.map(data, function(item) {
return {
label: item.Name,
value: item.Name,
skillid: item.ID,
notation: item.Notation,
}
}))
} else {
response([{ label: 'No result found.', value: '' }]);
};
},
error: function (exception) {
console.log(exception);
}
});
},
minLength: 3,
select: function (event, ui) {
number_of_skill += 1;
$.ajax({
url: '/routine/' + {{ routine.id }} + '/add_skill/' + ui.item.skillid + '/order/' + number_of_skill + '/'
}).done(function() {
insert_selected_skill(ui.item.notation);
});
}
});
});
</script>
{% endblock %}

View File

@ -0,0 +1,61 @@
{% extends "base.html" %}
<!-- {% block page_title %}.: New Routine :.{% endblock %} -->
<!-- {% block title %}Routine{% endblock %} -->
{% block content %}
<div class="row justify-content-center">
<div class="col-12 col-sm-12 col-md-8 col-lg-7 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">{% if routineid %}Edit{% else %}Add{% endif %} Routine</h4>
</div>
<div class="card-body">
<form action="{% if routineid %}{% url 'routine_update' routineid %}{% else %}{% url 'routine_create' %}{% endif %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="form-group row {% if form.long_label.errors %}has-error has-feedback{% endif %}">
<label for="id_date" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Long label</label>
<div class="col-8 col-sm-10 col-md-10 col-lg-10 col-xl-10">
{{ form.long_label }}&nbsp;{% if form.long_label.errors %}
{% for error in form.long_label.errors %}{{error}}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row {% if form.short_label.errors %}has-error has-feedback{% endif %}">
<label for="id_date" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Short label</label>
<div class="col-8 col-sm-10 col-md-10 col-lg-10 col-xl-10">
{{ form.short_label }}&nbsp;{% if form.short_label.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.short_label.errors %}{{error}}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_information" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Informations</label>
<div class="col-8 col-sm-9 col-md-9 col-lg-9 col-xl-9 {% if form.id_information.errors %}has-danger{% endif %}">
{{ form.informations }}
</div>
</div>
<div class="form-group text-center">
<input type="submit" value="Save" class="btn btn-warning" />
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript" >
$(function(){
$('#id_long_label').keyup(function(){
$('#id_short_label').val($('#id_long_label').val());
});
$('#id_difficulty').val(0);
$('#id_level').val(0);
$('#id_active').val(1);
});
</script>
{% endblock %}

View File

@ -1,14 +1,14 @@
{% extends "base.html" %}
{% block page_title %}{{ routine.shortLabel }}{% endblock %}
{% block page_title %}{{ routine.short_label }}{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-12 col-sm-12 col-md-8 col-lg-8 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class="card-title mb-0">{{ routine.shortLabel }}</h3>
<h5 class="card-category mb-0">{{ routine.longLabel }}</h4>
<h4 class="card-title mb-0">{{ routine.short_label }}</h3>
<h5 class="card-category mb-0">{{ routine.long_label }}</h4>
</div>
<div class="card-body">
<!-- <p>Description : </p> -->
@ -32,22 +32,22 @@
<td class="text-center"><b>{{ routine.difficulty }}</b></td>
</tr>
</table>
{% else %}
<p>No description available for this routine.</p>
{% endif %}
<div class="row">
<div class="col-3 text-center">Niveau : {{ routine.level }}</div>
<div class="col-3 text-center">Rank : {{ routine.rank }}</div>
<div class="col-3 text-center">Age Boy : {{ routine.age_boy }}</div>
<div class="col-3 text-center">Age Girl : {{ routine.age_girl }}</div>
</div>
<br>
{% else %}
<p>No skill defined for this routine.</p>
{% endif %}
</div>
{% if routine.content %}
{% if routine.informations %}
<div class="col-md-12">
<hr class="m-t">
<h4>Commentaires</h4>
<h4>Informations</h4>
<!-- <p>{{ skill.educative }}</p> -->
<span id="comment">

View File

@ -0,0 +1,88 @@
{% extends "listing.html" %}
<!-- {% block page_title %}.: Routine's list :.{% endblock %}
{% block title %}Routines{% endblock %}
{% block searchurl %}routine{% endblock %}
{% block addurl %}routine{% endblock %}
{% block search %}routine{% endblock %} -->
{% block datacontent %}
<div class="card mb-0">
<div class="card-header">
<h4 class="card-title"> Routines' Listing</h4>
<div class="text-right">
<a href="{% url 'routine_create' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="tim-icons icon-simple-add"></i>
</button>
</a>
</div>
</div>
<div class="card-body pb-0">
<div class="table-responsive pb-0">
<table class="table tablesorter table-striped table-condensed" data-sort="table" id="maintable">
{% if routine_list %}
<thead>
<tr>
<th style="width: 3%"></th>
<th class="header text-left" style="width: 62%">Label</th>
<th class="header text-center" style="width: 10%">Compétitive ?</th>
<th class="header ext-center" style="width: 5%">Diff.</th>
<th class="header text-center" style="width: 5%">Level</th>
<th class="header text-center" style="width: 5%">Rank</th>
<th class="header text-center" style="width: 5%">Girl</th>
<th class="header text-center" style="width: 5%">Boy</th>
</tr>
</thead>
<tbody>
{% for routine in routine_list %}
<tr>
<td>
<a href="{% url 'routine_update' routine.id %}">
<button type="button" rel="tooltip" class="btn btn-link btn-sm btn-icon">
<span class="tim-icons icon-pencil text-warning"></span>
</button>
</a>
</td>
<td class="text-left"><a href="{% url 'routine_details' routine.id %}">{{ routine.long_label }}</a></td>
<td class="text-center">{% if routine.is_competitive %}<i class="fa fa-check text-success" aria-hidden="true"></i>{% else %}<i class="fa fa-times text-danger" aria-hidden="true"></i>{% endif %}</td>
<td class="text-center">{{ routine.difficulty }}</td>
<td class="text-center">{{ routine.level }}</td>
<td class="text-center">{{ routine.rank }}</td>
<td class="text-center">{{ routine.age_girl }}</td>
<td class="text-center">{{ routine.age_boy }}</td>
</tr>
{% endfor %}
</tbody>
{% else %}
<tr>
<td>There are no routine corresponding to your criterias</td>
</tr>
{% endif %}
</table>
</div>
</div>
<div class="card-footer text-right text-muted pt-0">
<a href="{% url 'routine_create' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="tim-icons icon-simple-add"></i>
</button>
</a>
</div>
</div>
{% endblock %}
{% block footerscript %}
<script type="text/javascript">
$(document).ready(function() {
$('[data-sort="table"]').tablesorter({
headers: {
0: { sorter: false }, // disable first column
},
sortList: [[1,0]]
})
});
</script>
{% endblock %}

View File

@ -129,6 +129,12 @@
-->
<ul class="nav nav-pills nav-pills-primary nav-pills-icons flex-column">
<li class="nav-item">
<a class="nav-link get-info {% if tab is None or tab == 'level' %}active{% endif %}" data-toggle="tab" href="#statistics" data-ref="#statistics" data-url="statistics/" id="display_statistics">
<i class="tim-icons icon-sound-wave"></i> Level
</a>
</li>
<li class="nav-item">
<a class="nav-link get-info {% if tab == 'scores' %}active{% endif %}" data-toggle="tab" href="#scores" data-ref="#scores" data-url="scores_chrono/" id="display_scores_chrono">
<i class="fal fa-crosshairs"></i> Scores
@ -149,11 +155,6 @@
<i class="tim-icons icon-calendar-60"></i> Program
</a>
</li> -->
<li class="nav-item">
<a class="nav-link get-info {% if tab is None or tab == 'level' %}active{% endif %}" data-toggle="tab" href="#statistics" data-ref="#statistics" data-url="statistics/" id="display_statistics">
<i class="tim-icons icon-sound-wave"></i> Level
</a>
</li>
<!-- <li class="nav-item">
<a class="nav-link get-info {% if tab == 'routine' %}active{% endif %}" data-toggle="tab" href="#routine" data-ref="#routine" data-url="routine/" id="display_routines">
<i class="tim-icons icon-components"></i> Routines
@ -168,11 +169,11 @@
</div>
<div class="col-12 col-sm-10 col-md-10 col-lg-11">
<div class="tab-content">
<div class="tab-pane {% if tab == 'program' %}active{% endif %}" id="program"></div>
<div class="tab-pane {% if tab is None or tab == 'level' %}active{% endif %}" id="statistics"></div>
<!-- <div class="tab-pane {% if tab == 'program' %}active{% endif %}" id="program"></div> -->
<div class="tab-pane {% if tab == 'routine' %}active{% endif %}" id="routine"></div>
<!-- <div class="tab-pane {% if tab == 'routine' %}active{% endif %}" id="routine"></div> -->
<div class="tab-pane {% if tab == 'scores' %}active{% endif %}" id="scores"></div>

View File

@ -3,7 +3,7 @@
<div class="col-md-12 pr-0">
<div class="card">
<div class="card-header">
<h4>Scores</h4>
<h4>Mindstates</h4>
</div>
<div class="card-body pt-0 pb-0">
{% if mindstate_list %}
@ -11,30 +11,34 @@
<canvas id="chartjs_mindstate" class="chartjs" width="400" height="200"></canvas>
</div>
<table class="table tablesorter table-striped table-condensed" id="mindstate_table">
<thead>
<tr>
<th style="width: 3%"></th>
<th style="width: 45%" class="header text-center">Date</th>
<th style="width: 45%" class="header text-center">Score</th>
</tr>
</thead>
<tbody>
{% for state in mindstate_list %}
<tr class="routine_{{ score.routine_type }}">
<td>
<a href="{% url 'score_update' state.id %}">
<button type="button" rel="tooltip" class="btn btn-link btn-sm btn-icon">
<span class="tim-icons icon-pencil text-warning"></span>
</button>
</a>
</td>
<td class="text-right">{{ state.date | date:"d-m-Y" }}</td>
<td class="text-right">{{ state.score }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-md-8 col-l-6 col-xl-4 offset-xl-4">
<table class="table tablesorter table-striped table-condensed" id="mindstate_table">
<thead>
<tr>
<th style="width: 4%"></th>
<th style="width: 48%" class="header text-center">Date</th>
<th style="width: 48%" class="header text-center">Score</th>
</tr>
</thead>
<tbody>
{% for state in mindstate_list %}
<tr class="routine_{{ score.routine_type }}">
<td>
<a href="{% url 'score_update' state.id %}">
<button type="button" rel="tooltip" class="btn btn-link btn-sm btn-icon">
<span class="tim-icons icon-pencil text-warning"></span>
</button>
</a>
</td>
<td class="text-right">{{ state.date | date:"d-m-Y" }}</td>
<td class="text-right">{{ state.score }}&nbsp;</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$('#mindstate_table').tablesorter({
@ -48,9 +52,16 @@
});
</script>
{% else %}
<p>No scores to display.</p>
<p>No mindstate to display.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
<a href="{% url 'mindstate_create' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="tim-icons icon-simple-add"></i>
</button>
</a>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,210 @@
<div class="row justify-content-center ml-3 pr-0">
<div class="col-md-12 pr-0">
<div class="card">
<div class="card-body">
<ul class="nav nav-pills nav-pills-warning nav-pills-icons justify-content-center">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#skillbyrank">
By rank ({{ skillByRank|length }})
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#skillbylevel">
By level ({{ skillByLevel|length }})
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#skillbyage">
By Age ({{ skillByAge|length }})
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#newunknownskill">
All skill
</a>
</li>
</ul>
<div class="tab-content tab-space tab-subcategories pt-0 pb-0">
<div class="tab-pane active" id="skillbyrank">
{% if skillByRank %}
<table class="table table-striped table-condensed tablesorter" id="table-by-rank">
<thead>
<tr>
<th style="width: 4%"></th>
<th class="header text-left" style="width: 55%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th style="width: 10%">Notation</th>
</tr>
</thead>
<tbody>
{% for skill in skillByRank %}
<tr>
<td>
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill" data-gymnastid="{{ gymnast.id }}" data-skillid="{{ skill.id }}">
<i class="fa fa-check" aria-hidden="true"></i>
</button>
</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.longLabel }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td>{{ skill.notation }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
No skill to propose.
{% endif %}
</div>
<div class="tab-pane" id="skillbylevel">
{% if skillByLevel %}
<table class="table table-striped table-condensed tablesorter" id="table-by-level">
<thead>
<tr>
<th style="width: 4%"></th>
<th class="header text-left" style="width: 55%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th style="width: 10%">Notation</th>
</tr>
</thead>
<tbody>
{% for skill in skillByLevel %}
<tr>
<td>
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill" data-gymnastid="{{ gymnast.id }}" data-skillid="{{ skill.id }}">
<i class="fa fa-check" aria-hidden="true"></i>
</button>
</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.longLabel }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td>{{ skill.notation }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
No skill to propose.
{% endif %}
</div>
<div class="tab-pane" id="skillbyage">
{% if skillByAge %}
<table class="table table-striped table-condensed tablesorter" id="table-by-age">
<thead>
<tr>
<th style="width: 4%"></th>
<th class="header text-left" style="width: 55%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th style="width: 10%">Notation</th>
</tr>
</thead>
<tbody>
{% for skill in skillByAge %}
<tr>
<td>
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill" data-gymnastid="{{ gymnast.id }}" data-skillid="{{ skill.id }}">
<i class="fa fa-check" aria-hidden="true"></i>
</button>
</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.longLabel }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td>{{ skill.notation }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
It doesn't work (age) ! There is a bug !
{% endif %}
</div>
<div class="tab-pane" id="newunknownskill">
{% if newUnknownSkill %}
<table class="table table-striped table-condensed tablesorter" id="table-other">
<thead>
<tr>
<th style="width: 4%"></th>
<th class="header text-left" style="width: 64%">Label</th>
<th class="header" style="width: 7%">Diff.</th>
<th class="header" style="width: 7%">Level</th>
<th class="header" style="width: 7%">Rank</th>
<th style="width: 10%">Notation</th>
</tr>
</thead>
<tbody>
{% for skill in newUnknownSkill %}
<tr>
<td>
<button type="button" rel="tooltip" class="btn btn-success btn-link btn-sm btn-icon checkUnknownSkill" data-gymnastid="{{ gymnast.id }}" data-skillid="{{ skill.id }}">
<i class="fa fa-check" aria-hidden="true"></i>
</button>
</td>
<td class="text-left"><a href="{% url 'skill_details' skill.id %}">{{ skill.longLabel }}</a></td>
<td>{{ skill.difficulty }}</td>
<td>{{ skill.level }}</td>
<td>{{ skill.rank }}</td>
<td>{{ skill.notation }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
It doesn't work (new skill) ! There is a bug !
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(function(){
$('.checkUnknownSkill').click(function(){
$.ajax({
url: '/skill/insert/',
data: {
gymnastid: $(this).data('gymnastid'),
skillid: $(this).data('skillid'),
},
type: 'POST',
context: $(this),
success: function (response) {
// avec reload (data à jour)
// location.reload();
// sans relaod des datas (data pas totalement à jour)
$(this).closest('tr').fadeTo("slow", 0.0, function(){
$(this).remove();
});
// $(this).closest('tr').slideUp("slow");
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
},
failure: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
}
});
});
$('#table-by-rank, #table-by-level, #table-by-age, #table-other').tablesorter({
headers: {
0: { sorter: false }, // disable first column
5: { sorter: false },
},
// dateFormat: "uk",
sortList: [[4,0], [1,0]]
});
});
</script>

View File

@ -1,6 +1,6 @@
{% extends "base.html" %}
<!-- {% block page_title %}.: Overview :.{% endblock %} -->
{% block page_title %}Dashboard{% endblock %}
<!-- {% block title %}Overview{% endblock %} -->
@ -13,16 +13,25 @@
<h4 class="fal fa-laugh-wink"> Hi {{ user.username }} !</h4>
</div>
<div class="card-body">
Welcome to Ultron v0.24<br />
Welcome to Ultron v0.25<br />
This application is there to help us manage the gymnasts (evolution, evaluation, ...). It is not perfect so feel free to make improvement proposals, bug reports, … by sending me an <a href="mailto:gregory@flyingacrobaticstrampoline.be">email</a>.
</div>
</div>
</div>
<div class="col-md-3">
<div class="card mb-2">
<div class="card-header">
<h4 class="fal fa-chart-area"> Some statistics</h4>
</div>
<div class="card-body">
<div class="w-lg m-x-auto">
(line 1 cadre 2)
<ul class="list-unstyled">
<li>{{ nb_gymnast }} active gymnasts</li>
<li>{{ nb_event }} events</li>
<li>{{ nb_skill }} skills</li>
<li>{{ nb_routine }} routines</li>
<li>{{ nb_score }} scores</li>
</ul>
</div>
</div>
</div>