Added a donut chart to the quota view

Moved morris.js out of the statistics plugin
This commit is contained in:
Raphael Michel
2016-09-18 19:11:44 +02:00
parent ebbd9aaee9
commit f8ce3523dc
13 changed files with 74 additions and 33 deletions
+1
View File
@@ -3,3 +3,4 @@ src/static/lightbox/* linguist-vendored
src/static/typeahead/* linguist-vendored src/static/typeahead/* linguist-vendored
src/static/moment/* linguist-vendored src/static/moment/* linguist-vendored
src/static/datetimepicker/* linguist-vendored src/static/datetimepicker/* linguist-vendored
src/static/charts/* linguist-vendored
@@ -17,9 +17,12 @@
<script type="text/javascript" src="{% static "bootstrap/js/bootstrap.js" %}"></script> <script type="text/javascript" src="{% static "bootstrap/js/bootstrap.js" %}"></script>
<script type="text/javascript" src="{% static "moment/moment-with-locales.js" %}"></script> <script type="text/javascript" src="{% static "moment/moment-with-locales.js" %}"></script>
<script type="text/javascript" src="{% static "datetimepicker/bootstrap-datetimepicker.js" %}"></script> <script type="text/javascript" src="{% static "datetimepicker/bootstrap-datetimepicker.js" %}"></script>
<script type="text/javascript" src="{% static "charts/raphael-min.js" %}"></script>
<script type="text/javascript" src="{% static "charts/morris.min.js" %}"></script>
<script type="text/javascript" src="{% static "pretixcontrol/js/metisMenu.min.js" %}"></script> <script type="text/javascript" src="{% static "pretixcontrol/js/metisMenu.min.js" %}"></script>
<script type="text/javascript" src="{% static "pretixcontrol/js/sb-admin-2.js" %}"></script> <script type="text/javascript" src="{% static "pretixcontrol/js/sb-admin-2.js" %}"></script>
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/main.js" %}"></script> <script type="text/javascript" src="{% static "pretixcontrol/js/ui/main.js" %}"></script>
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/quota.js" %}"></script>
{% endcompress %} {% endcompress %}
{{ html_head|safe }} {{ html_head|safe }}
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@@ -46,9 +46,13 @@
</fieldset> </fieldset>
</div> </div>
{% if quota.pk and quota.size != None %} {% if quota.pk and quota.size != None %}
<div class="col-xs-12 col-lg-3"> <div class="col-xs-12 col-lg-3" id="quota-stats">
<fieldset> <fieldset>
<legend>{% trans "Availability calculation" %}</legend> <legend>{% trans "Availability calculation" %}</legend>
<div class="chart" id="quota_chart">
</div>
<div class="row"> <div class="row">
<div class="col-xs-9">{% trans "Total quota" %}</div> <div class="col-xs-9">{% trans "Total quota" %}</div>
<div class="col-xs-3 text-right">{{ quota.size }}</div> <div class="col-xs-3 text-right">{{ quota.size }}</div>
@@ -75,6 +79,7 @@
</div> </div>
</fieldset> </fieldset>
</div> </div>
<script type="application/json" id="quota-chart-data">{{ quota_chart_data|safe }}</script>
{% endif %} {% endif %}
</div> </div>
<div class="form-group submit-group"> <div class="form-group submit-group">
+9
View File
@@ -26,3 +26,12 @@ class UpdateView(EventBasedFormMixin, edit.UpdateView):
properly. properly.
""" """
pass pass
class ChartContainingView:
def get(self, request, *args, **kwargs):
resp = super().get(request, *args, **kwargs)
# required by raphael.js
resp['Content-Security-Policy'] = "script-src {static} 'unsafe-eval'; style-src {static} 'unsafe-inline'"
return resp
+31 -3
View File
@@ -1,3 +1,5 @@
import json
from django.contrib import messages from django.contrib import messages
from django.core.files import File from django.core.files import File
from django.core.urlresolvers import resolve, reverse from django.core.urlresolvers import resolve, reverse
@@ -6,7 +8,7 @@ from django.forms.models import ModelMultipleChoiceField, inlineformset_factory
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext, ugettext_lazy as _
from django.views.generic import ListView from django.views.generic import ListView
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
@@ -24,7 +26,7 @@ from pretix.control.permissions import (
EventPermissionRequiredMixin, event_permission_required, EventPermissionRequiredMixin, event_permission_required,
) )
from . import CreateView, UpdateView from . import ChartContainingView, CreateView, UpdateView
class ItemList(ListView): class ItemList(ListView):
@@ -525,13 +527,39 @@ class QuotaCreate(EventPermissionRequiredMixin, QuotaEditorMixin, CreateView):
return ret return ret
class QuotaUpdate(EventPermissionRequiredMixin, QuotaEditorMixin, UpdateView): class QuotaUpdate(EventPermissionRequiredMixin, QuotaEditorMixin, ChartContainingView, UpdateView):
model = Quota model = Quota
form_class = QuotaForm form_class = QuotaForm
template_name = 'pretixcontrol/items/quota.html' template_name = 'pretixcontrol/items/quota.html'
permission = 'can_change_items' permission = 'can_change_items'
context_object_name = 'quota' context_object_name = 'quota'
def get_context_data(self, *args, **kwargs):
ctx = super().get_context_data()
ctx['quota_chart_data'] = json.dumps([
{
'label': ugettext('Paid orders'),
'value': self.object.count_paid_orders()
},
{
'label': ugettext('Pending orders'),
'value': self.object.count_pending_orders()
},
{
'label': ugettext('Vouchers'),
'value': self.object.count_blocking_vouchers()
},
{
'label': ugettext('Current user\'s carts'),
'value': self.object.count_in_cart()
},
{
'label': ugettext('Current availability'),
'value': self.object.availability()[1]
}
])
return ctx
def get_object(self, queryset=None) -> Quota: def get_object(self, queryset=None) -> Quota:
try: try:
return self.request.event.quotas.get( return self.request.event.quotas.get(
+1 -14
View File
@@ -1,11 +1,9 @@
from django.core.urlresolvers import resolve, reverse from django.core.urlresolvers import resolve, reverse
from django.dispatch import receiver from django.dispatch import receiver
from django.template import Context
from django.template.loader import get_template
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from pretix.base.signals import order_paid, order_placed from pretix.base.signals import order_paid, order_placed
from pretix.control.signals import html_head, nav_event from pretix.control.signals import nav_event
@receiver(nav_event, dispatch_uid="statistics_nav") @receiver(nav_event, dispatch_uid="statistics_nav")
@@ -26,17 +24,6 @@ def control_nav_import(sender, request=None, **kwargs):
] ]
@receiver(html_head, dispatch_uid="statistics_html_head")
def html_head_presale(sender, request=None, **kwargs):
url = resolve(request.path_info)
if url.namespace == 'plugins:statistics':
template = get_template('pretixplugins/statistics/control_head.html')
ctx = Context({})
return template.render(ctx)
else:
return ""
def clear_cache(sender, *args, **kwargs): def clear_cache(sender, *args, **kwargs):
cache = sender.get_cache() cache = sender.get_cache()
cache.delete('statistics_obd_data') cache.delete('statistics_obd_data')
@@ -1,8 +0,0 @@
{% load staticfiles %}
{% load compress %}
{% compress css %}
<link type="text/css" rel="stylesheet" href="{% static "pretixplugins/statistics/morris.css" %}">
{% endcompress %}
<script type="text/javascript" src="{% static "pretixplugins/statistics/raphael-min.js" %}"></script>
<script type="text/javascript" src="{% static "pretixplugins/statistics/morris.min.js" %}"></script>
+2 -7
View File
@@ -9,19 +9,14 @@ from django.views.generic import TemplateView
from pretix.base.models import Item, Order, OrderPosition from pretix.base.models import Item, Order, OrderPosition
from pretix.control.permissions import EventPermissionRequiredMixin from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.control.views import ChartContainingView
from pretix.plugins.statistics.signals import clear_cache from pretix.plugins.statistics.signals import clear_cache
class IndexView(EventPermissionRequiredMixin, TemplateView): class IndexView(EventPermissionRequiredMixin, ChartContainingView, TemplateView):
template_name = 'pretixplugins/statistics/index.html' template_name = 'pretixplugins/statistics/index.html'
permission = 'can_view_orders' permission = 'can_view_orders'
def get(self, request, *args, **kwargs):
resp = super().get(request, *args, **kwargs)
# required by raphael.js
resp['Content-Security-Policy'] = "script-src {static} 'unsafe-eval'; style-src {static} 'unsafe-inline'"
return resp
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
tz = timezone.get_current_timezone() tz = timezone.get_current_timezone()
+20
View File
@@ -0,0 +1,20 @@
/*globals $, Morris, gettext*/
$(function () {
if (!$("#quota-stats").length) {
return;
}
$(".chart").css("height", "250px");
new Morris.Donut({
element: 'quota_chart',
data: JSON.parse($("#quota-chart-data").html()),
resize: true,
colors: [
'#0044CC', // paid
'#0088CC', // pending
'#BD362F', // vouchers
'#F89406', // carts
'#51A351' // available
]
});
});
+1
View File
@@ -4,6 +4,7 @@ $fa-font-path: static("fontawesome/fonts");
@import "../../fontawesome/scss/font-awesome.scss"; @import "../../fontawesome/scss/font-awesome.scss";
@import "../../typeahead/typeahead.css"; @import "../../typeahead/typeahead.css";
@import "../css/metisMenu.min.css"; @import "../css/metisMenu.min.css";
@import "../../charts/morris.css";
@import "../../datetimepicker/_bootstrap-datetimepicker.scss"; @import "../../datetimepicker/_bootstrap-datetimepicker.scss";
@import "_sb-admin-2.scss"; @import "_sb-admin-2.scss";
@import "_forms.scss"; @import "_forms.scss";