Fix list templates

TODO: Sensible place to define the 'expected answer' stuff.
This commit is contained in:
2020-09-03 12:38:52 +01:00
parent c1182efa54
commit e602058771
12 changed files with 128 additions and 222 deletions

View File

@@ -4,6 +4,7 @@ from django.utils import timezone
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.urls import reverse_lazy from django.urls import reverse_lazy
from reversion import revisions as reversion from reversion import revisions as reversion
from django.db.models import AutoField, ManyToOneRel
class EventRiskAssessmentCreate(generic.CreateView): class EventRiskAssessmentCreate(generic.CreateView):
@@ -70,7 +71,17 @@ class EventRiskAssessmentDetail(generic.DetailView):
class EventRiskAssessmentList(generic.ListView): class EventRiskAssessmentList(generic.ListView):
paginate_by = 20 paginate_by = 20
model = models.RiskAssessment model = models.RiskAssessment
template_name = 'risk_assessment_list.html' template_name = 'hs_object_list.html'
def get_context_data(self, **kwargs):
context = super(EventRiskAssessmentList, self).get_context_data(**kwargs)
context['title'] = 'Risk Assessment'
context['view'] = 'ra_detail'
context['edit'] = 'ra_edit'
context['review'] = 'ra_review'
context['perm'] = 'perms.RIGS.review_riskassessment'
context['fields'] = [n.name for n in list(self.model._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created ]
return context
class EventRiskAssessmentReview(generic.View): class EventRiskAssessmentReview(generic.View):
@@ -149,7 +160,17 @@ class EventChecklistCreate(generic.CreateView):
class EventChecklistList(generic.ListView): class EventChecklistList(generic.ListView):
paginate_by = 20 paginate_by = 20
model = models.EventChecklist model = models.EventChecklist
template_name = 'event_checklist_list.html' template_name = 'hs_object_list.html'
def get_context_data(self, **kwargs):
context = super(EventChecklistList, self).get_context_data(**kwargs)
context['title'] = 'Event Checklist'
context['view'] = 'ec_detail'
context['edit'] = 'ec_edit'
context['review'] = 'ec_review'
context['perm'] = 'perms.RIGS.review_eventchecklist'
context['fields'] = [n.name for n in list(self.model._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created ]
return context
class EventChecklistReview(generic.View): class EventChecklistReview(generic.View):

View File

@@ -465,7 +465,7 @@ class Event(models.Model, RevisionMixin):
return reverse_lazy('event_detail', kwargs={'pk': self.pk}) return reverse_lazy('event_detail', kwargs={'pk': self.pk})
def __str__(self): def __str__(self):
return str(self.pk) + ": " + self.name return self.display_id + ": " + self.name
def clean(self): def clean(self):
if self.end_date and self.start_date > self.end_date: if self.end_date and self.start_date > self.end_date:
@@ -585,14 +585,6 @@ class Payment(models.Model):
return "%s: %d" % (self.get_method_display(), self.amount) return "%s: %d" % (self.get_method_display(), self.amount)
# Probably shouldn't be doing HTML at the python level but hey...they say not to do logic in templates! :P
def get_review_string(obj, review_link):
if obj.reviewed_by:
return "<span class='badge badge-success py-2'>Reviewed by <a href='{}'>{}</a> at {}</span>".format(reverse_lazy('profile_detail', kwargs={'pk': obj.reviewed_by.pk}), obj.reviewed_by, obj.reviewed_at.strftime("%d/%m/%Y %H:%M"))
else:
return "<a class='btn btn-success my-2' href='{}'>Mark Reviewed</a>".format(reverse_lazy(review_link, kwargs={'pk': obj.pk}))
@reversion.register @reversion.register
class RiskAssessment(models.Model, RevisionMixin): class RiskAssessment(models.Model, RevisionMixin):
event = models.OneToOneField('Event', on_delete=models.CASCADE) event = models.OneToOneField('Event', on_delete=models.CASCADE)
@@ -637,10 +629,14 @@ class RiskAssessment(models.Model, RevisionMixin):
reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
verbose_name="Reviewer", on_delete=models.CASCADE) verbose_name="Reviewer", on_delete=models.CASCADE)
inverted_fields = ['nonstandard_equipment','nonstandard_use', 'contractors', 'other_companies', 'crew_fatigue', 'big_power',
'generators', 'other_companies_power', 'nonstandard_equipment_power','multiple_electrical_environments','noise_monitoring'
'special_structures', 'suspended_structures']
class Meta: class Meta:
ordering = ['event'] ordering = ['event']
permissions = [ permissions = [
('riskassessment_review', 'Can review RAs') ('review_riskassessment', 'Review Risk Assessments')
] ]
def clean(self): def clean(self):
@@ -652,10 +648,6 @@ class RiskAssessment(models.Model, RevisionMixin):
if errdict != {}: # If there was an error when validation if errdict != {}: # If there was an error when validation
raise ValidationError(errdict) raise ValidationError(errdict)
@property
def review_string(self):
return get_review_string(self, 'ra_review')
@property @property
def activity_feed_string(self): def activity_feed_string(self):
return str(self.event) return str(self.event)
@@ -725,10 +717,12 @@ class EventChecklist(models.Model, RevisionMixin):
reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
verbose_name="Reviewer", on_delete=models.CASCADE) verbose_name="Reviewer", on_delete=models.CASCADE)
inverted_fields = []
class Meta: class Meta:
ordering = ['event'] ordering = ['event']
permissions = [ permissions = [
('eventchecklist_review', 'Can review ECs') ('review_eventchecklist', 'Review Event Checklists')
] ]
def clean(self): def clean(self):
@@ -749,10 +743,6 @@ class EventChecklist(models.Model, RevisionMixin):
if errdict != {}: # If there was an error when validation if errdict != {}: # If there was an error when validation
raise ValidationError(errdict) raise ValidationError(errdict)
@property
def review_string(self):
return get_review_string(self, 'ec_review')
@property @property
def activity_feed_string(self): def activity_feed_string(self):
return str(self.event) return str(self.event)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -42,7 +42,7 @@
a { a {
color: $blue; color: $blue;
} }
.badge, .btn-success { .badge, .btn-success, .bg-warning {
color: black; color: black;
} }
.badge-dark, .badge-secondary, .btn-primary { .badge-dark, .badge-secondary, .btn-primary {

View File

@@ -114,6 +114,11 @@ svg {
white-space: no-wrap; white-space: no-wrap;
} }
input[required]::after,select[required]::after {
content: '*';
color: red;
}
html.embedded { html.embedded {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -158,8 +163,3 @@ html.embedded {
max-width: 3em; max-width: 3em;
} }
} }
(input,select)[required]::after {
content: '*';
color: red;
}

View File

@@ -1,67 +0,0 @@
{% extends 'base_rigs.html' %}
{% load paginator from filters %}
{% load help_text from filters %}
{% load verbose_name from filters %}
{% block title %}Event Checklist List{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<h2>Event Checklist List</h2>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="table-responsive">
<table class="table mb-0">
<thead>
<tr>
<th scope="col">Event</th>
{# mmm hax #}
{% if object_list.0 %}
<th scope="col" class="">{{ object_list.0|verbose_name:'power_mic'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'vehicles'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'safe_parking'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'safe_packing'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'exits'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'trip_hazard'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'warning_signs'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'ear_plugs'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'hs_location'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'extinguishers_location'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'rcds'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'supply_test'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'earthing'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'pat'|title }}</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
{# General #}
<th scope="row" class="{% if object.reviewed_by %}bg-success{%endif%}"><a href="{% url 'event_detail' object.event.pk %}">N{{ object.event.pk|stringformat:"05d" }} {{ object.event.name }}</a></th>
<td>{{object.power_mic.name}}</td>
{# Buttons #}
<td>
<a class="btn btn-primary" href="{% url 'ra_detail' object.pk %}">View</a>
{{ object.review_string|safe }}
</td>
</tr>
{% empty %}
<tr class="bg-warning text-dark">
<td colspan="6">No checklists found</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% if is_paginated %}
<div class="row justify-content-center">
{% paginator %}
</div>
{% endif %}
{% endblock %}

View File

@@ -25,8 +25,8 @@
<br><span><strong>{{ event.end_date|date:"D d/m/Y" }}</strong></span> <br><span><strong>{{ event.end_date|date:"D d/m/Y" }}</strong></span>
{% endif %} {% endif %}
</td> </td>
<td>{% include 'partials/hs_status.html' with event=event object=event.riskassessment view='ra_detail' edit='ra_edit' create='event_ra' %}</td> <td>{% include 'partials/hs_status.html' with event=event object=event.riskassessment view='ra_detail' edit='ra_edit' create='event_ra' review='ra_review' perm=perms.RIGS.review_riskassessment %}</td>
<td>{% include 'partials/hs_status.html' with event=event object=event.eventchecklist view='ec_detail' edit='ec_edit' create='event_ec' %}</td> <td>{% include 'partials/hs_status.html' with event=event object=event.eventchecklist view='ec_detail' edit='ec_edit' create='event_ec' review='ec_review' perm=perms.RIGS.review_eventchecklist %}</td>
</tr> </tr>
{% empty %} {% empty %}
<tr class="bg-warning text-dark"> <tr class="bg-warning text-dark">

View File

@@ -0,0 +1,57 @@
{% extends 'base_rigs.html' %}
{% load paginator from filters %}
{% load help_text from filters %}
{% load verbose_name from filters %}
{% load get_field from filters %}
{% block title %}{{ title }} List{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<h2>{{title}} List</h2>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="table-responsive">
<table class="table mb-0">
<thead>
<tr>
<th scope="col">Event</th>
{# mmm hax #}
{% for field in fields %}
<th scope="col">{{ object_list.0|verbose_name:field|title }}</th>
{% endfor %}
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr class="{% if object.reviewed_by %}table-success{%endif%}">
{# General #}
<th scope="row"><a href="{% url 'event_detail' object.event.pk %}">{{ object.event }}</a></th>
{% for field in fields %}
<td>{{ object|get_field:field }}</td>
{% endfor %}
{# Buttons #}
<td>
{% include 'partials/hs_status.html' %}
</td>
</tr>
{% empty %}
<tr class="bg-warning">
<td colspan="6">Nothing found</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% if is_paginated %}
<div class="row justify-content-center">
{% paginator %}
</div>
{% endif %}
{% endblock %}

View File

@@ -1,12 +1,14 @@
{% load to_class_name from filters %}
{% if object.pk != None %} {% if object.pk != None %}
{#<span class="badge badge-success my-3"><span class="fas fa-check"></span> Completed</span><br/>#} <div class="btn-group">
<div class="btn-group"> <a href="{% url view object.pk %}" class="btn btn-primary"><span class="fas fa-eye"></span> <span class="hidden-xs"> View</span>
<a href="{% url view object.pk %}" class="btn btn-primary"><span class="fas fa-eye"></span> <span class="hidden-xs"> View</span> <a href="{% url edit object.pk %}" class="btn btn-warning"><span class="fas fa-edit"></span><span class="hidden-xs"> Edit</span></a>
<a href="{% url edit object.pk %}" class="btn btn-warning"><span class="fas fa-edit"></span><span class="hidden-xs"> Edit</span></a> </div>
</div> {% if object.reviewed_by %}
{{ object.review_string|safe }} <span class='badge badge-success py-2'>Reviewed by <a href='{% url 'profile_detail' object.reviewed_by.pk %}'>{{object.reviewed_by}}</a> at {{object.reviewed_at}}</span>
{% else %} {% elif perm %}
<a class='btn btn-success my-2' href='{% url review object.pk %}'>Mark Reviewed</a>
{% endif %}
{% elif event != None %}
<a href="{% url create event.pk %}" class="btn btn-info"><span class="fas fa-paperclip"></span> <span <a href="{% url create event.pk %}" class="btn btn-info"><span class="fas fa-paperclip"></span> <span
class="hidden-xs">Create</span></a> class="hidden-xs">Create</span></a>
{% endif %} {% endif %}

View File

@@ -1,105 +0,0 @@
{% extends 'base_rigs.html' %}
{% load paginator from filters %}
{% load help_text from filters %}
{% load verbose_name from filters %}
{% block title %}Risk Assessment List{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<h2>Risk Assessment List</h2>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="table-responsive">
<table class="table mb-0">
<thead>
<tr>
<th scope="col">Event</th>
{# mmm hax #}
{% if object_list.0 %}
<th scope="col" class="">{{ object_list.0|verbose_name:'nonstandard_equipment'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'nonstandard_use'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'contractors'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'other_companies'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'crew_fatigue'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'general_notes'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'big_power'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'power_mic'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'generators'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'other_companies_power'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'nonstandard_equipment_power'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'multiple_electrical_environments'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'power_notes'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'noise_monitoring'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'sound_notes'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'known_venue'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'safe_loading'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'safe_storage'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'area_outside_of_control'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'nonstandard_emergency_procedure'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'barrier_required'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'special_structures'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'persons_responsible_structures'|title }}</th>
<th scope="col">{{ object_list.0|verbose_name:'suspended_structures'|title }}</th>
<th scope="col"></th>
{% endif %}
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
{# General #}
<th scope="row" class="{% if object.reviewed_by %}bg-success{%endif%}"><a href="{% url 'event_detail' object.event.pk %}">N{{ object.event.pk|stringformat:"05d" }} {{ object.event.name }}</a></th>
<td class="{% if object.nonstandard_equipment%}bg-danger text-white{%endif%}">{{object.nonstandard_equipment|yesno|title}}</td>
<td class="{% if object.nonstandard_use%}bg-danger text-white{%endif%}">{{object.nonstandard_use|yesno|title}}</td>
<td class="{% if object.contractors%}bg-danger text-white{%endif%}">{{object.contractors|yesno|title}}</td>
<td class="{% if object.other_companies%}bg-danger text-white{%endif%}">{{object.other_companies|yesno|title}}</td>
<td class="{% if object.crew_fatigue%}bg-danger text-white{%endif%}">{{object.crew_fatigue|yesno|title}}</td>
<td><span class="text-truncate d-inline-block">{{ object.general_notes|default:'N/A'|linebreaks }}</span></td>
{# Power #}
<td class="{% if object.big_power%}bg-danger text-white{%endif%}">{{object.big_power|yesno|title}}</td>
<td>{{ object.power_mic.name|default:'N/A' }}</td>
<td class="{% if object.generators%}bg-danger text-white{%endif%}">{{object.generators|yesno|title}}</td>
<td class="{% if object.other_companies_power%}bg-danger text-white{%endif%}">{{object.other_companies_power|yesno|title}}</td>
<td class="{% if object.nonstandard_equipment_power%}bg-danger text-white{%endif%}">{{object.nonstandard_equipment_power|yesno|title}}</td>
<td class="{% if object.multiple_electrical_environments%}bg-danger text-white{%endif%}">{{object.multiple_electrical_environments|yesno|title}}</td>
<td><span class="text-truncate d-inline-block">{{ object.power_notes|default:'N/A'|linebreaks }}</span></td>
{# Sound #}
<td class="{% if object.noise_monitoring%}bg-danger text-white{%endif%}">{{object.noise_monitoring|yesno|title}}</td>
<td><span class="text-truncate d-inline-block">{{ object.sound_notes|default:'N/A'|linebreaks }}</span></td>
{# Venue #}
<td class="{% if not object.known_venue%}bg-danger text-white{%endif%}">{{object.known_venue|yesno|title}}</td>
<td class="{% if not object.safe_loading%}bg-danger text-white{%endif%}">{{object.safe_loading|yesno|title}}</td>
<td class="{% if object.safe_storage%}bg-danger text-white{%endif%}">{{object.safe_storage|yesno|title}}</td>
<td class="{% if object.area_outside_of_control%}bg-danger text-white{%endif%}">{{object.area_outside_of_control|yesno|title}}</td>
<td class="{% if object.nonstandard_emergency_procedure%}bg-danger text-white{%endif%}">{{object.nonstandard_emergency_procedure|yesno|title}}</td>
<td class="{% if object.barrier_required%}bg-danger text-white{%endif%}">{{object.barrier_required|yesno|title}}</td>
{# Rigging #}
<td class="{% if object.special_structures%}bg-danger text-white{%endif%}">{{object.special_structures|yesno|title}}</td>
<td>{{ object.persons_responsible_structures|default:'N/A'|linebreaks }}</td>
<td class="{% if object.suspended_structures%}bg-danger text-white{%endif%}">{{object.suspended_structures|yesno|title}}</td>
{# Buttons #}
<td>
<a class="btn btn-primary" href="{% url 'ra_detail' object.pk %}">View</a>
{{ object.review_string|safe }}
</td>
</tr>
{% empty %}
<tr class="bg-warning text-dark">
<td colspan="6">No risk assessments found</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% if is_paginated %}
<div class="row justify-content-center">
{% paginator %}
</div>
{% endif %}
{% endblock %}

View File

@@ -8,7 +8,7 @@ from django.utils.safestring import SafeData, mark_safe
from django.utils.html import escape from django.utils.html import escape
from RIGS import models from RIGS import models
import json import json
from django.template.defaultfilters import yesno, title from django.template.defaultfilters import yesno, title, truncatewords
from django.urls import reverse_lazy from django.urls import reverse_lazy
register = template.Library() register = template.Library()
@@ -119,6 +119,15 @@ def orderby(request, field, attr):
# Used for accessing outside of a form, i.e. in detail views of RiskAssessment and EventChecklist # Used for accessing outside of a form, i.e. in detail views of RiskAssessment and EventChecklist
@register.filter(needs_autoescape=True)
def get_field(obj, field, autoescape=True):
value = getattr(obj, field)
if(type(value)==bool):
value = yesnoi(value, field in obj.inverted_fields)
elif(type(value)==str):
value = truncatewords(value, 20)
return mark_safe(value)
@register.filter @register.filter
def help_text(obj, field): def help_text(obj, field):
if hasattr(obj, '_meta'): if hasattr(obj, '_meta'):
@@ -127,8 +136,8 @@ def help_text(obj, field):
@register.filter @register.filter
def verbose_name(obj, field): def verbose_name(obj, field):
return obj._meta.get_field(field).verbose_name if hasattr(obj._meta.get_field(field), 'verbose_name'):
return obj._meta.get_field(field).verbose_name
@register.filter @register.filter
def get_list(dictionary, key): def get_list(dictionary, key):
@@ -157,8 +166,7 @@ def next(alist, current_index):
@register.filter(needs_autoescape=True) @register.filter(needs_autoescape=True)
def yesnoi(boolean, invert=False, autoescape=True): def yesnoi(boolean, invert=False, autoescape=True):
value = yesno(boolean) value = title(yesno(boolean))
value = title(value)
if invert: if invert:
boolean = not boolean boolean = not boolean
if boolean: if boolean: