Compare commits

...

8 Commits

Author SHA1 Message Date
df5e4c8e0a Level detail tweaking 2021-08-21 01:44:26 +01:00
3601c14ab7 Oops 2021-08-21 01:36:35 +01:00
adde6496f5 Add loads more sample training items
Hopefully the generator won't make levels with no requirements anymore now
2021-08-21 00:45:35 +01:00
ad734d94b2 Display pre pre requisite levels on level detail 2021-08-21 00:32:04 +01:00
7d3ada822d Common competencies sample data 2021-08-21 00:28:24 +01:00
732af53fda Groundwork stuff for common competencies + other fixes 2021-08-21 00:09:00 +01:00
4fb0529cc0 Modalify the training record addition form 2021-08-20 21:52:33 +01:00
aa23b1cd09 Add sharepoint link to new homepage
Good at scope, me
2021-08-20 21:52:17 +01:00
9 changed files with 128 additions and 59 deletions

View File

@@ -64,16 +64,16 @@
<div class="form-group form-row">
{% include 'partials/form_field.html' with field=form.length append=form.length.help_text col="col-6" %}
<div class="col-4">
<button class="btn btn-danger" onclick="setFieldValue('{{ form.length.id_for_label }}','5');" tabindex="-1">5{{ form.length.help_text }}</button>
<button class="btn btn-success" onclick="setFieldValue('{{ form.length.id_for_label }}','10');" tabindex="-1">10{{ form.length.help_text }}</button>
<button class="btn btn-info" onclick="setFieldValue('{{ form.length.id_for_label }}','20');" tabindex="-1">20{{ form.length.help_text }}</button>
<button class="btn btn-danger" onclick="setFieldValue('{{ form.length.id_for_label }}','5');" tabindex="-1" type="button">5{{ form.length.help_text }}</button>
<button class="btn btn-success" onclick="setFieldValue('{{ form.length.id_for_label }}','10');" tabindex="-1" type="button">10{{ form.length.help_text }}</button>
<button class="btn btn-info" onclick="setFieldValue('{{ form.length.id_for_label }}','20');" tabindex="-1" type="button">20{{ form.length.help_text }}</button>
</div>
</div>
<div class="form-group form-row">
{% include 'partials/form_field.html' with field=form.csa append=form.csa.help_text title='CSA' col="col-6" %}
<div class="col-4">
<button class="btn btn-secondary" onclick="setFieldValue('{{ form.csa.id_for_label }}', '1.5');" tabindex="-1">1.5{{ form.csa.help_text }}</button>
<button class="btn btn-secondary" onclick="setFieldValue('{{ form.csa.id_for_label }}', '2.5');" tabindex="-1">2.5{{ form.csa.help_text }}</button>
<button class="btn btn-secondary" onclick="setFieldValue('{{ form.csa.id_for_label }}', '1.5');" tabindex="-1" type="button">1.5{{ form.csa.help_text }}</button>
<button class="btn btn-secondary" onclick="setFieldValue('{{ form.csa.id_for_label }}', '2.5');" tabindex="-1" type="button">2.5{{ form.csa.help_text }}</button>
</div>
</div>
</div>

View File

@@ -12,9 +12,7 @@
});
$('#searchButton').click(function (e) {
e.preventDefault();
var url = "{% url 'asset_audit' None %}";
var id = $("#{{form.q.id_for_label}}").val();
url = url.replace('None', id);
var url = "{% url 'asset_audit' None %}".replace('None', $("#{{form.q.id_for_label}}").val();
$.ajax({
url: url,
success: function(){

View File

@@ -49,14 +49,15 @@
<a class="list-group-item list-group-item-action" href="{% url 'session_log' %}"><span class="fas fa-plus align-middle"></span><span class="align-middle"> Log Training Session</span></a>
</div>
</div>
</div>
</div>
<div class="col-sm mb-3">
<div class="card">
<div class="card">
<h4 class="card-header">Quick Links</h4>
<div class="list-group list-group-flush">
<a class="list-group-item list-group-item-action" href="https://forum.nottinghamtec.co.uk" target="_blank" rel="noopener noreferrer"><span class="fas fa-comment-alt text-info align-middle"></span><span class="align-middle"> TEC Forum</span></a>
<a class="list-group-item list-group-item-action" href="https://forum.nottinghamtec.co.uk" target="_blank" rel="noopener noreferrer"><span class="fas fa-comment-alt text-primary align-middle"></span><span class="align-middle"> TEC Forum</span></a>
<a class="list-group-item list-group-item-action" href="//nottinghamtec.sharepoint.com" target="_blank" rel="noopener noreferrer"><span class="fas fa-folder text-info align-middle"></span><span class="align-middle"> TEC Sharepoint</span></a>
<a class="list-group-item list-group-item-action" href="//wiki.nottinghamtec.co.uk" target="_blank" rel="noopener noreferrer"><span class="fas fa-pen-square align-middle"></span><span class="align-middle"> TEC Wiki</span></a>
{% if perms.RIGS.view_event %}
{% if perms.RIGS.change_event %}
<a class="list-group-item list-group-item-action" href="//members.nottinghamtec.co.uk/price" target="_blank" rel="noopener noreferrer"><span class="fas fa-pound-sign text-warning align-middle"></span><span class="align-middle"> Price List</span></a>
{% endif %}
</div>

View File

@@ -43,19 +43,34 @@ class Command(BaseCommand):
self.categories.append(category)
def setup_items(self):
names = ["Motorised Power Towers", "Catering", "Forgetting Cables", "Gazebo Construction", "Balanced Audio", "Unbalanced Audio", "BBQ/Bin Interactions", "Pushing Boxes", "How Not To Die", "Setting up projectors", "Basketing truss", "First Aid", "Digging Trenches", "Avoiding Bin Lorries", "Getting cherry pickers stuck in mud", "Crashing the Van", "Getting pigs to fly", "Basketing picnics", "Python programming", "Building Cables", "Unbuilding Cables", "Cat Herding", "Pancake making", "Tidying up", "Reading Manuals", "Bikeshedding"]
names = ["Motorised Power Towers", "Catering", "Forgetting Cables", "Gazebo Construction", "Balanced Audio", "Unbalanced Audio", "BBQ/Bin Interactions", "Pushing Boxes", "How Not To Die", "Setting up projectors", "Basketing truss", "First Aid", "Digging Trenches", "Avoiding Bin Lorries", "Getting cherry pickers stuck in mud", "Crashing the Van", "Getting pigs to fly", "Basketing picnics", "Python programming", "Building Cables", "Unbuilding Cables", "Cat Herding", "Pancake making", "Tidying up", "Reading Manuals", "Bikeshedding", "DJing", "Partying", "Teccie Gym", "Putting dust covers on", "Cleaning Lights", "Water Skiing", "Drinking", "Fundamentals of Audio", "Fundamentals of Photons", "Social Interaction", "Discourse Searching", "Discord Searching", "Coiling Cables", "Kit Amnesties", "Van Insurance", "Subhire Insurance", "Paperwork", "More Paperwork", "Second Aid", "Being Old", "Maxihoists", "Sleazyhoists", "Telehoists", "Prolyte", "Prolights", "Making Phonecalls", "Quoting For A Rig", "Basic MIC", "Advanced MIC", "Avoiding MIC", "Washing Cables", "Cable Ramp", "Van Loading", "Trailer Loading", "Storeroom Loading", "Welding", "Fire Extinguishers", "Boring Conference AV", "Flyaway", "Short Leads", "RF Systems", "QLab", "Use of Ladders", "Working at Height", "Organising Training", "Organising Organising Training Training", "Mental Health First Aid", "Writing RAMS", "Makros Runs", "PAT", "Kit Fixing", "Kit Breaking", "Replacing Lamps", "Flying Pig Systems", "Procrastination", "Drinking Beer", "Sending Emails", "Email Signatures", "Digital Sound Desks", "Digital Lighting Desks", "Painting PS10s", "Chain Lubrication", "Big Power", "BIGGER POWER", "Pixel Mapping", "RDM", "Ladder Inspections", "Losing Crimpaz", "Scrapping Trilite", "Bin Diving", "Wiki Editing"]
for i,name in enumerate(names):
item = models.TrainingItem.objects.create(category=random.choice(self.categories), reference_number=random.randint(0, 100), name=name)
self.items.append(item)
def setup_levels(self):
self.levels.append(models.TrainingLevel.objects.create(level=models.TrainingLevel.TA, description="Passion will hatred faithful evil suicide noble battle. Truth aversion gains grandeur noble. Dead play gains prejudice god ascetic grandeur zarathustra dead good. Faithful ultimate justice overcome love will mountains inexpedient."))
items = self.items.copy()
ta = models.TrainingLevel.objects.create(level=models.TrainingLevel.TA, description="Passion will hatred faithful evil suicide noble battle. Truth aversion gains grandeur noble. Dead play gains prejudice god ascetic grandeur zarathustra dead good. Faithful ultimate justice overcome love will mountains inexpedient.")
self.levels.append(ta)
tech_ccs = models.TrainingLevel.objects.create(level=models.TrainingLevel.TECHNICIAN, description="Technician Common Competencies. Spirit abstract endless insofar horror sexuality depths war decrepit against strong aversion revaluation free. Christianity reason joy sea law mountains transvaluation. Sea battle aversion dead ultimate morality self. Faithful morality.")
tech_ccs.prerequisite_levels.add(ta)
super_ccs = models.TrainingLevel.objects.create(level=models.TrainingLevel.SUPERVISOR, description="Depths disgust hope faith of against hatred will victorious. Law...")
for i in range(0, 5):
if len(items) == 0:
break
item = random.choice(items)
items.remove(item)
if i % 3 == 0:
models.TrainingLevelRequirement.objects.create(level=tech_ccs, item=item, depth=random.choice(models.TrainingItemQualification.CHOICES)[0])
else:
models.TrainingLevelRequirement.objects.create(level=super_ccs, item=item, depth=random.choice(models.TrainingItemQualification.CHOICES)[0])
for i,name in models.TrainingLevel.DEPARTMENTS:
technician = models.TrainingLevel.objects.create(level=models.TrainingLevel.TECHNICIAN, department=i, description="Moral pinnacle derive ultimate war dead. Strong fearful joy contradict battle christian faithful enlightenment prejudice zarathustra moral.")
technician.prerequisite_levels.add(tech_ccs)
supervisor = models.TrainingLevel.objects.create(level=models.TrainingLevel.SUPERVISOR, department=i, description="Spirit holiest merciful mountains inexpedient reason value. Suicide ultimate hope.")
supervisor.prerequisite_levels.add(technician)
items = self.items.copy()
supervisor.prerequisite_levels.add(super_ccs, technician)
for i in range(0, 30):
if len(items) == 0:
break

View File

@@ -143,8 +143,11 @@ class TrainingLevel(models.Model, RevisionMixin):
return all(TrainingItem.user_has_qualification(req.item, user, req.depth) for req in self.requirements.select_related().all())
def __str__(self):
if self.department is None: # 2TA
return self.get_level_display()
if self.department is None:
if self.level == self.TA:
return self.get_level_display()
else:
return "{} Common Competencies".format(self.get_level_display())
else:
return "{} {}".format(self.get_department_display(), self.get_level_display())

View File

@@ -1,4 +1,4 @@
{% extends 'base_rigs.html' %}
{% extends request.is_ajax|yesno:'base_ajax.html,base_training.html' %}
{% load static %}
{% load widget_tweaks %}
@@ -21,10 +21,9 @@
{% endblock %}
{% block content %}
{% if form.errors %}
{% include 'form_errors.html' %}
{% endif %}
<form role="form" action="{{ form.action|default:request.path }}" method="POST">{% csrf_token %}
<form role="form" action="{{ form.action|default:request.path }}" method="POST" id="add_record_form">
{% include 'form_errors.html' %}
{% csrf_token %}
{% render_field form.trainee|attr:'hidden' value=form.trainee.initial %}
<div class="form-group form-row">
<label for="item_id" class="col-sm-2 col-form-label">Item</label>
@@ -42,9 +41,10 @@
</div>
<div class="form-group form-row">
<label for="date" class="col-sm-2 col-form-label">Training Date</label>
<div class="col-sm-10">
<div class="col-sm-8">
{% render_field form.date|add_class:'form-control'|attr:'type="date"' value=form.date.initial %}
</div>
<button class="btn btn-info col-sm-2" onclick="var date = new Date(); $('#id_date').val([date.getFullYear(), ('0' + (date.getMonth()+1)).slice(-2), ('0' + date.getDate()).slice(-2)].join('-'))" tabindex="-1" type="button">Today</button>
</div>
<div class="form-group form-row">
<label for="item_description" class="col-sm-2 col-form-label">Notes</label>
@@ -53,8 +53,16 @@
id="notes" rows="3"></textarea>
</div>
</div>
<div class="col-sm-12 text-right pr-0"}>
{% if not request.is_ajax %}
<div class="col-sm-12 text-right pr-0">
{% button 'submit' %}
</div>
{% endif %}
</form>
{% endblock %}
{% block footer %}
<div class="col-sm-12 text-right pr-0">
<button type="submit" class="btn btn-primary" title="Save" form="add_record_form"><span class="fas fa-save align-middle"></span> <span class="d-none d-sm-inline align-middle">Save</span></button>
</div>
{% endblock %}

View File

@@ -1,5 +1,8 @@
{% extends 'base_training.html' %}
{% load user_has_qualification from tags %}
{% load user_level_if_present from tags %}
{% block content %}
{% if edit or True %}
<div class="col-sm-12 text-right pr-0">
@@ -19,14 +22,17 @@
<div class="card-body">
<div class="card-columns">
{% for user in users_with %}
<div class="card w-50">
{% 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%}>
<img src="{{user.profile_picture}}" class="card-img-top" />
<div class="card-body">
<h5 class="card-title">{{user}}</h5>
<p>Qualified on... </p>
{% if level_qualification.confirmed_on %}<p class="card-text"><small>Qualified on {{ level_qualification.confirmed_on }}</small></p>{%else%}Unconfirmed{%endif%}
</div>
<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...
{% endfor %}
</div>
</div>
@@ -43,12 +49,29 @@
</thead>
<tbody>
<tr>
<td><ul class="list-unstyled">{% for req in object.started_requirements %}<li>{{ req.item }} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-danger btn-sm" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-times-circle"></span></a>{% endif %}</li>{% endfor %}</ul></td>
<td><ul class="list-unstyled">{% for req in object.complete_requirements %}<li>{{ req.item }} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-danger btn-sm" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-times-circle"></span></a>{% endif %}</li>{% endfor %}</ul></td>
<td><ul class="list-unstyled">{% for req in object.passed_out_requirements %}<li>{{ req.item }} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-danger btn-sm" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-times-circle"></span></a>{%endif%}</li>{% endfor %}</ul></td>
<td><ul class="list-unstyled">{% for req in object.started_requirements %}<li>{{ req.item }} {% user_has_qualification request.user req.item 0 %} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-danger btn-sm" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-times-circle"></span></a>{% endif %}</li>{% endfor %}</ul></td>
<td><ul class="list-unstyled">{% for req in object.complete_requirements %}<li>{{ req.item }} {% user_has_qualification request.user req.item 1 %} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-danger btn-sm" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-times-circle"></span></a>{% endif %}</li>{% endfor %}</ul></td>
<td><ul class="list-unstyled">{% for req in object.passed_out_requirements %}<li>{{ req.item }} {% user_has_qualification request.user req.item 2 %} {% if request.user.is_supervisor or perms.training.change_traininglevel %}<a type="button" class="btn btn-danger btn-sm" href="{% url 'remove_requirement' pk=req.pk %}"><span class="fas fa-times-circle"></span></a>{%endif%}</li>{% endfor %}</ul></td>
</tr>
</tbody>
</table>
<h4 class="card-header">Prerequisite Levels:</h4>
<div class="card-body">
<ul>
{% for level in object.prerequisite_levels.all %}
{% 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 %}
<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>
{% endfor %}
{% empty %}
None
{% endfor %}
</ul>
</div>
</div>
{% include 'partials/last_edited.html' with target="traininglevel_history" %}
{% endblock %}

View File

@@ -1,15 +1,56 @@
{% extends 'base_rigs.html' %}
{% load static %}
{% load user_has_qualification from tags %}
{% load percentage_complete from tags %}
{% 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) {
e.preventDefault();
var url = $(this).attr("href");
$.ajax({
url: url,
success: function(){
$link = $(this);
// Anti modal inception
if ($link.parents('#modal').length === 0) {
modaltarget = $link.data('target');
modalobject = "";
$('#modal').load(url, function (e) {
$('#modal').modal();
$(".selectpicker").selectpicker().each(function(){initPicker($(this))});
});
}
}
});
});
});
</script>
{% endblock %}
{% block content %}
<div class="col-sm-12 text-right">
<a type="button" class="btn btn-success" href="{% url 'edit_record' pk=request.user.pk %}">
<span class="fas fa-plus"></span> Add New Training Record
</a>
<div class="row">
<div class="col-sm-12 text-right">
<a type="button" class="btn btn-success" href="{% url 'edit_record' object.pk %}" id="add_record">
<span class="fas fa-plus"></span> Add New Training Record
</a>
</div>
</div>
<div class="row mb-3">
<h2 class="col-12">Training Levels</h2>
@@ -29,31 +70,8 @@
<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>
<button class="btn btn-link p-0" type="button" data-toggle="collapse" data-target=".reqs_{{level.pk}}" aria-expanded="false" aria-controls="reqs_{{level.pk}}">
Requirements <span class="fas fa-caret-right reqs_{{level.pk}} collapse show"></span><span class="fas fa-caret-down collapse reqs_{{level.pk}}"></span>
</button>
<div class="collapse reqs_{{level.pk}}">
<table class="table table-sm">
<thead>
<tr>
<th scope="col" class="table-warning">Training Started</th>
<th scope="col" class="table-success">Training Complete</th>
<th scope="col" class="table-info">Passed Out</th>
</tr>
</thead>
<tbody>
<tr>
<td><ul class="list-unstyled">{% for req in level.started_requirements %}<li>{{ req.item }} {% user_has_qualification object req.item 0 %}</li>{% endfor %}</ul></td>
<td><ul class="list-unstyled">{% for req in level.complete_requirements %}<li>{{ req.item }} {% user_has_qualification object req.item 1 %}</li>{% endfor %}</ul></td>
<td><ul class="list-unstyled">{% for req in level.passed_out_requirements %}<li>{{ req.item }} {% user_has_qualification object req.item 2 %}</li>{% endfor %}</ul></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="card-footer text-right">
{% user_level_if_present object level as level_qualification %}

View File

@@ -3,7 +3,7 @@ import reversion
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views import generic
from PyRIGS.views import OEmbedView, is_ajax
from PyRIGS.views import OEmbedView, is_ajax, ModalURLMixin
from training import models, forms
from django.utils import timezone
from django.db import transaction
@@ -21,7 +21,7 @@ class ItemList(generic.ListView):
return context
class TraineeDetail(views.ProfileDetail):
class TraineeDetail(views.ProfileDetail, ModalURLMixin):
template_name = "trainee_detail.html"
model = models.Trainee
@@ -36,6 +36,9 @@ class TraineeDetail(views.ProfileDetail):
context[str(i)] = self.object.get_records_of_depth(i)
return context
def get_success_url(self):
return self.get_close_url('trainee_detail', 'trainee_detail')
class TraineeItemDetail(generic.ListView):
model = models.TrainingItemQualification