mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-18 14:02:15 +00:00
Add training level list
Plus various other fettling
This commit is contained in:
23
training/migrations/0006_auto_20210903_2158.py
Normal file
23
training/migrations/0006_auto_20210903_2158.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 3.1.7 on 2021-09-03 20:58
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('training', '0005_auto_20210819_1833'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='traininglevel',
|
||||
name='icon',
|
||||
field=models.CharField(blank=True, max_length=20, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='traininglevelrequirement',
|
||||
name='depth',
|
||||
field=models.IntegerField(choices=[(0, 'Training Started'), (1, 'Training Complete'), (2, 'Passed Out')]),
|
||||
),
|
||||
]
|
||||
@@ -119,6 +119,19 @@ class TrainingLevel(models.Model, RevisionMixin):
|
||||
department = models.IntegerField(choices=DEPARTMENTS, null=True) # N.B. Technical Assistant does not have a department
|
||||
level = models.IntegerField(choices=CHOICES)
|
||||
prerequisite_levels = models.ManyToManyField('self', related_name='prerequisites', symmetrical=False, blank=True)
|
||||
icon = models.CharField(null=True, blank=True, max_length=20)
|
||||
|
||||
def get_department_colour(self):
|
||||
if self.department == 0:
|
||||
return "info"
|
||||
elif self.department == 1:
|
||||
return "dark"
|
||||
elif self.department == 2:
|
||||
return "danger"
|
||||
elif self.department == 3:
|
||||
return "light"
|
||||
else:
|
||||
return "primary"
|
||||
|
||||
def get_requirements_of_depth(self, depth):
|
||||
return self.requirements.filter(depth=depth)
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
Item Detail</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'level_list' %}"><span class="fas fa-layer-group"></span> All Levels</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'item_list' %}"><span class="fas fa-sitemap"></span> All Items</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'training_activity_table' %}"><span class="fas fa-random"></span> Recent Changes</a></li>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base_training.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<p>{{ object.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card mb-3 d-none d-md-block">
|
||||
<h4 class="card-header">Users with this level</h4>
|
||||
<div class="card-body">
|
||||
<div class="card-columns">
|
||||
<div class="card-columns" style="column-count: 5">
|
||||
{% for user in users_with %}
|
||||
{% user_level_if_present user object as level_qualification %}
|
||||
<div class="card w-50" {% if not level_qualification.confirmed_on %}style="border-style: dashed; opacity: 70%"{%endif%}>
|
||||
<div class="card" {% if not level_qualification.confirmed_on %}style="border-style: dashed; opacity: 70%"{%endif%}>
|
||||
<img src="{{user.profile_picture}}" class="card-img-top" />
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{user}}</h5>
|
||||
@@ -32,7 +32,7 @@
|
||||
<div class="card-footer text-right pr-1"><a href="{% url 'profile_detail' user.pk %}" class="btn btn-primary btn-sm"><span class="fas fa-user"></span> View Profile</a></div>
|
||||
</div>
|
||||
{% empty %}
|
||||
Nobody here but us chickens...
|
||||
Nobody here but us chickens... <span class="fas fa-egg text-warning"></span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,7 +62,7 @@
|
||||
{% user_level_if_present request.user level as level_qualification %}
|
||||
<li><a href="{{level.get_absolute_url}}">{{ level }}</a> <span class="fas {% if level_qualification %}text-success fa-check{% if level_qualification.confirmed_by is not None %}-double{% endif %}{% else %}fa-hourglass-start text-warning{%endif%}"></span></li>
|
||||
{% for nested_level in level.prerequisite_levels.all %}
|
||||
{% user_level_if_present request.user level as nested_level_qualification %}
|
||||
{% user_level_if_present request.user nested_level as nested_level_qualification %}
|
||||
<ul>
|
||||
<li><a href="{{nested_level.get_absolute_url}}">{{ nested_level }}</a> <span class="fas {% if nested_level_qualification %}text-success fa-check{% if nested_level_qualification.confirmed_by is not None %}-double{% endif %}{% else %}fa-hourglass-start text-warning{%endif%}"></span></li>
|
||||
</ul>
|
||||
@@ -73,5 +73,9 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'partials/last_edited.html' with target="traininglevel_history" %}
|
||||
<div class="row">
|
||||
<div class="col text-right">
|
||||
{% include 'partials/last_edited.html' with target="traininglevel_history" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
24
training/templates/level_list.html
Normal file
24
training/templates/level_list.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{% extends 'base_training.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="alert alert-info" role="alert">
|
||||
<p>Please Note:</p>
|
||||
<ul>
|
||||
<li>Technical Assistant status is automatically valid when the item requirements are met.</li>
|
||||
<li>Technician status is also automatic, but notification of status should be made at the next general meeting, at which point 'approval' should be granted on the system.</li>
|
||||
<li>Supervisor status is <em>not automatically valid</em> and until signed off at a general meeting, does not count.</li>
|
||||
</ul>
|
||||
<sup>Correct as of 3rd September 2021, check the Training Policy.</sup>
|
||||
</div>
|
||||
|
||||
<div class="card-columns">
|
||||
{% for level in levels %}
|
||||
<div class="card my-3">
|
||||
<h3 class="card-header"><a href="{% url 'level_detail' level.pk %}">{{ level }}</a></h3>
|
||||
<div class="card-body">
|
||||
<p>{{ level.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -6,19 +6,7 @@
|
||||
{% load user_level_if_present from tags %}
|
||||
{% load colour_from_depth from tags %}
|
||||
|
||||
{% block css %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/selects.css' %}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block preload_js %}
|
||||
{{ block.super }}
|
||||
<script src="{% static 'js/selects.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script src="{% static 'js/autocompleter.js' %}"></script>
|
||||
<script src="{% static 'js/tooltip.js' %}"></script>
|
||||
<script>
|
||||
$('document').ready(function(){
|
||||
$('#add_record').click(function (e) {
|
||||
@@ -54,22 +42,15 @@
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<h2 class="col-12">Training Levels</h2>
|
||||
<div class="alert alert-info" role="alert">
|
||||
<ul>
|
||||
<li>Technical Assistant is conferred automatically when the item requirements are met.</li>
|
||||
<li>Technician status is also automatic, but notification of status should be made at the next general meeting, at which point 'approval' should be granted on the system.</li>
|
||||
<li>Supervisor status is <em>not automatic</em> and until signed off at a general meeting, does not count.</li>
|
||||
</ul>
|
||||
<sup>Correct as of 7th July 2021, check the Training Policy.</sup>
|
||||
</div>
|
||||
<div class="card-columns">
|
||||
{% for level in levels %}
|
||||
{% percentage_complete level object as completion %}
|
||||
{% if completion > 0 %}
|
||||
<div class="card my-3">
|
||||
<h3 class="card-header"><a href="{% url 'level_detail' level.pk %}">{{ level }}</a></h3>
|
||||
<div class="card-body">
|
||||
<p>{{ level.description|truncatewords:30 }}</p>
|
||||
<div class="progress mb-2">
|
||||
{% percentage_complete level object as completion %}
|
||||
<div class="progress-bar progress-bar-striped" role="progressbar" style="width: {{completion}}%" aria-valuenow="{{completion}}" aria-valuemin="0" aria-valuemax="100">{{completion}}% complete</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -90,6 +71,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,6 @@ from training import views
|
||||
|
||||
urlpatterns = [
|
||||
path('items/', views.ItemList.as_view(), name='item_list'),
|
||||
|
||||
path('trainee/list/', views.TraineeList.as_view(), name='trainee_list'),
|
||||
path('trainee/', login_required(views.TraineeDetail.as_view()), name='trainee_detail'),
|
||||
path('trainee/<int:pk>/',
|
||||
@@ -16,6 +15,7 @@ urlpatterns = [
|
||||
path('trainee/<int:pk>/edit/', views.AddQualification.as_view(),
|
||||
name='edit_record'),
|
||||
path('session/', views.SessionLog.as_view(), name='session_log'),
|
||||
path('levels/', views.LevelList.as_view(), name='level_list'),
|
||||
path('level/<int:pk>/', views.LevelDetail.as_view(), name='level_detail'),
|
||||
path('level/<int:pk>/add_requirement/', views.AddLevelRequirement.as_view(), name='add_requirement'),
|
||||
path('level/remove_requirement/<int:pk>/', views.RemoveRequirement.as_view(), name='remove_requirement'),
|
||||
|
||||
@@ -28,6 +28,7 @@ class TraineeDetail(views.ProfileDetail, ModalURLMixin):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(TraineeDetail, self).get_context_data(**kwargs)
|
||||
context["page_title"] = "{}'s Training Record".format(self.object.first_name + " " + self.object.last_name)
|
||||
# TODO Filter this to levels the user has
|
||||
context["levels"] = models.TrainingLevel.objects.all()
|
||||
context["categories"] = models.TrainingCategory.objects.all().prefetch_related('items')
|
||||
choices = models.TrainingItemQualification.CHOICES
|
||||
@@ -53,6 +54,17 @@ class TraineeItemDetail(generic.ListView):
|
||||
return context
|
||||
|
||||
|
||||
class LevelList(generic.ListView):
|
||||
model = models.TrainingLevel
|
||||
template_name = "level_list.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_title"] = "All Training Levels"
|
||||
context["levels"] = models.TrainingLevel.objects.all()
|
||||
return context
|
||||
|
||||
|
||||
class TraineeList(generic.ListView):
|
||||
model = models.Trainee
|
||||
template_name = 'trainee_list.html'
|
||||
@@ -130,7 +142,7 @@ class LevelDetail(generic.DetailView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_title"] = "Training Level {}".format(self.object)
|
||||
context["page_title"] = "Training Level {} <span class='badge badge-{} badge-pill'><span class='fas fa-{}'></span></span>".format(self.object, self.object.get_department_colour(), self.object.icon)
|
||||
context["users_with"] = map(lambda qual: qual.trainee, models.TrainingLevelQualification.objects.filter(level=self.object))
|
||||
return context
|
||||
|
||||
|
||||
Reference in New Issue
Block a user