Add new class based dashboard widget. This new widget supports subclassing and is template based. All exising widgets have been converted. ACL filtering was added to the widget results.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2018-08-23 03:30:06 -04:00
parent 26b31da443
commit f11eef7445
10 changed files with 188 additions and 110 deletions

View File

@@ -97,6 +97,9 @@
ActionError exception.
- Add favorite documents per user. Adds new setting option
DOCUMENTS_FAVORITE_COUNT.
- Add new class based dashboard widget. This new widget supports
subclassing and is template based. All exising widgets have been
converted. ACL filtering was added to the widget results.
3.0.3 (2018-08-17)
==================

View File

@@ -67,11 +67,6 @@
</div>
</div>
{% get_dashboard 'main' as dashboard %}
<div class="row">
{% for widget in dashboard.get_widgets %}
{% include 'appearance/dashboard_widget.html' %}
{% endfor %}
</div>
{% render_dashboard 'main' %}
{% endblock %}

View File

@@ -0,0 +1,5 @@
<div class="row">
{% for widget in widgets %}
{{ widget }}
{% endfor %}
</div>

View File

@@ -5,28 +5,24 @@
<div class="panel-heading">
<div class="row">
<div class="col-xs-2">
{% if widget.icon %}
<i class="dashboard-widget-icon {{ widget.icon }}"></i>
{% elif widget.icon_class %}
{% if icon %}
<i class="dashboard-widget-icon {{ icon }}"></i>
{% elif icon_class %}
<div class="dashboard-widget-icon">
{{ widget.icon_class.render }}
{{ icon_class.render }}
</div>
{% endif %}
</div>
<div class="col-xs-10 text-right">
<strong>{{ widget.label }}</strong>
<strong>{{ label }}</strong>
<div class="huge">
{% if widget.func %}
{{ widget.func }}
{% else %}
{{ widget.queryset.count }}
{% endif %}
{{ count }}
</div>
</div>
</div>
</div>
{% if widget.link %}
<a href="{{ widget.link }}">
{% if link %}
<a href="{{ link }}">
<div class="panel-footer">
<span class="pull-left">{% trans 'View details' %}</span>
<span class="pull-right"><i class="fa fa-external-link-alt"></i></span>
@@ -36,3 +32,4 @@
{% endif %}
</div>
</div>

View File

@@ -14,7 +14,7 @@ from common.dashboards import dashboard_main
from events import ModelEventType
from mayan.celery import app
from .dashboard_widgets import widget_checkouts
from .dashboard_widgets import DashboardWidgetTotalCheckouts
from .events import (
event_document_auto_check_in, event_document_check_in,
event_document_check_out, event_document_forceful_check_in
@@ -117,7 +117,9 @@ class CheckoutsApp(MayanAppConfig):
}
)
dashboard_main.add_widget(order=-1, widget=widget_checkouts)
dashboard_main.add_widget(
widget=DashboardWidgetTotalCheckouts, order=-1
)
menu_facet.bind_links(links=(link_checkout_info,), sources=(Document,))
menu_main.bind_links(links=(link_checkout_list,), position=98)

View File

@@ -4,21 +4,33 @@ from django.apps import apps
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from common.classes import DashboardWidget
from common.classes import DashboardWidgetNumeric
from documents.permissions import permission_document_view
from .icons import icon_dashboard_checkouts
from .permissions import permission_document_checkout_detail_view
def checkedout_documents_queryset():
class DashboardWidgetTotalCheckouts(DashboardWidgetNumeric):
icon_class = icon_dashboard_checkouts
label = _('Checkedout documents')
link = reverse_lazy('checkouts:checkout_list')
def render(self, request):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
DocumentCheckout = apps.get_model(
app_label='checkouts', model_name='DocumentCheckout'
)
return DocumentCheckout.objects.all()
widget_checkouts = DashboardWidget(
icon_class=icon_dashboard_checkouts,
label=_('Checkedout documents'),
link=reverse_lazy('checkouts:checkout_list'),
queryset=checkedout_documents_queryset
queryset = AccessControlList.objects.filter_by_access(
permission=permission_document_checkout_detail_view,
user=request.user,
queryset=DocumentCheckout.objects.checked_out_documents()
)
queryset = AccessControlList.objects.filter_by_access(
permission=permission_document_view, user=request.user,
queryset=queryset
)
self.count = queryset.count()
return super(DashboardWidgetTotalCheckouts, self).render(request)

View File

@@ -2,6 +2,7 @@ from __future__ import unicode_literals
from django.apps import apps
from django.db import models
from django.template import loader
from django.urls import reverse
from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.translation import ugettext
@@ -83,24 +84,57 @@ class Dashboard(object):
def remove_widget(self, widget):
self.removed_widgets.append(widget)
def render(self, request):
rendered_widgets = [widget().render(request=request) for widget in self.get_widgets()]
class DashboardWidget(object):
_registry = []
return loader.render_to_string(
template_name='dashboard/dashboard.html', context={
'widgets': rendered_widgets
}
)
class BaseDashboardWidget(object):
_registry = {}
context = {}
template_name = None
@classmethod
def get(cls, name):
return cls._registry[name]
@classmethod
def get_all(cls):
return cls._registry
return cls._registry.items()
def __init__(self, label, func=None, icon=None, icon_class=None, link=None, queryset=None, statistic_slug=None):
self.label = label
self.icon = icon
self.icon_class = icon_class
self.link = link
self.queryset = queryset
self.func = func
self.statistic_slug = statistic_slug
@classmethod
def register(cls, klass):
cls._registry[klass.name] = klass
self.__class__._registry.append(self)
def get_context(self):
return self.context
def render(self, request):
if self.template_name:
return loader.render_to_string(
template_name=self.template_name, context=self.get_context(),
)
class DashboardWidgetNumeric(BaseDashboardWidget):
count = 0
icon_class = None
label = None
link = None
template_name = 'dashboard/numeric_widget.html'
def get_context(self):
return {
'count': self.count,
'icon_class': self.icon_class,
'label': self.label,
'link': self.link,
}
@python_2_unicode_compatible

View File

@@ -45,12 +45,6 @@ def check_sqlite():
def get_collections():
return Collection.get_all()
@register.simple_tag
def get_dashboard(name):
return Dashboard.get(name=name)
@register.filter
def get_encoded_parameter(item, parameters_dict):
result = {}
@@ -74,6 +68,11 @@ def project_information(attribute_name):
return getattr(mayan, attribute_name)
@register.simple_tag(takes_context=True)
def render_dashboard(context, name):
return Dashboard.get(name=name).render(request=context.request)
@register.simple_tag(takes_context=True)
def render_subtemplate(context, template_name, template_context):
"""

View File

@@ -35,9 +35,9 @@ from navigation import SourceColumn
from rest_api.fields import DynamicSerializerField
from .dashboard_widgets import (
widget_document_types, widget_documents_in_trash,
widget_new_documents_this_month, widget_pages_per_month,
widget_total_documents
DashboardWidgetDocumentsInTrash, DashboardWidgetDocumentsNewThisMonth,
DashboardWidgetDocumentsPagesNewThisMonth, DashboardWidgetDocumentsTotal,
DashboardWidgetDocumentsTypesTotal,
)
from .events import (
event_document_create, event_document_download,
@@ -195,7 +195,7 @@ class DocumentsApp(MayanAppConfig):
model=Document, related='document_type',
)
ModelPermission.register_inheritance(
model=DocumentPage, related='document',
model=DocumentPage, related='document_version__document',
)
ModelPermission.register_inheritance(
model=DocumentPageResult, related='document_version__document',
@@ -389,11 +389,21 @@ class DocumentsApp(MayanAppConfig):
}
)
dashboard_main.add_widget(widget=widget_document_types)
dashboard_main.add_widget(widget=widget_documents_in_trash)
dashboard_main.add_widget(widget=widget_new_documents_this_month)
dashboard_main.add_widget(widget=widget_pages_per_month)
dashboard_main.add_widget(widget=widget_total_documents)
dashboard_main.add_widget(
widget=DashboardWidgetDocumentsTotal, order=0
)
dashboard_main.add_widget(
widget=DashboardWidgetDocumentsInTrash, order=1
)
dashboard_main.add_widget(
widget=DashboardWidgetDocumentsTypesTotal, order=2
)
dashboard_main.add_widget(
widget=DashboardWidgetDocumentsNewThisMonth, order=3
)
dashboard_main.add_widget(
widget=DashboardWidgetDocumentsPagesNewThisMonth, order=4
)
menu_documents.bind_links(
links=(

View File

@@ -4,78 +4,99 @@ from django.apps import apps
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from common.classes import DashboardWidget
from common.classes import DashboardWidgetNumeric
from .icons import (
icon_dashboard_documents_in_trash, icon_dashboard_document_types,
icon_dashboard_pages_per_month, icon_dashboard_new_documents_this_month,
icon_dashboard_total_document
)
from .permissions import (
permission_document_view, permission_document_type_view
)
from .statistics import (
new_document_pages_this_month, new_documents_this_month,
)
def get_total_documents_queryset():
class DashboardWidgetDocumentsTotal(DashboardWidgetNumeric):
icon_class = icon_dashboard_total_document
label = _('Total documents')
link = reverse_lazy('documents:document_list')
def render(self, request):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
Document = apps.get_model(
app_label='documents', model_name='Document'
)
return Document.objects.all()
self.count = AccessControlList.objects.filter_by_access(
permission=permission_document_view, user=request.user,
queryset=Document.objects.filter(is_stub=False)
).count()
return super(DashboardWidgetDocumentsTotal, self).render(request)
def get_document_types_queryset():
DocumentType = apps.get_model(
app_label='documents', model_name='DocumentType'
class DashboardWidgetDocumentsInTrash(DashboardWidgetNumeric):
icon_class = icon_dashboard_documents_in_trash
label = _('Documents in trash')
link = reverse_lazy('documents:document_list_deleted')
def render(self, request):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
return DocumentType.objects.all()
def get_deleted_documents_queryset():
DeletedDocument = apps.get_model(
app_label='documents', model_name='DeletedDocument'
)
return DeletedDocument.objects.all()
self.count = AccessControlList.objects.filter_by_access(
permission=permission_document_view, user=request.user,
queryset=DeletedDocument.objects.all()
).count()
return super(DashboardWidgetDocumentsInTrash, self).render(request)
widget_pages_per_month = DashboardWidget(
func=new_document_pages_this_month,
icon_class=icon_dashboard_pages_per_month,
label=_('New pages this month'),
link=reverse_lazy(
'statistics:statistic_detail',
args=('new-document-pages-per-month',)
class DashboardWidgetDocumentsTypesTotal(DashboardWidgetNumeric):
icon_class = icon_dashboard_document_types
label = _('Document types')
link = reverse_lazy('documents:document_type_list')
def render(self, request):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
DocumentType = apps.get_model(
app_label='documents', model_name='DocumentType'
)
self.count = AccessControlList.objects.filter_by_access(
permission=permission_document_type_view, user=request.user,
queryset=DocumentType.objects.all()
).count()
return super(DashboardWidgetDocumentsTypesTotal, self).render(request)
widget_new_documents_this_month = DashboardWidget(
func=new_documents_this_month,
icon_class=icon_dashboard_new_documents_this_month,
label=_('New documents this month'),
class DashboardWidgetDocumentsNewThisMonth(DashboardWidgetNumeric):
icon_class = icon_dashboard_new_documents_this_month
label = _('New documents this month')
link=reverse_lazy(
'statistics:statistic_detail',
args=('new-documents-per-month',)
)
def render(self, request):
self.count = new_documents_this_month(user=request.user)
return super(DashboardWidgetDocumentsNewThisMonth, self).render(request)
class DashboardWidgetDocumentsPagesNewThisMonth(DashboardWidgetNumeric):
icon_class = icon_dashboard_pages_per_month
label = _('New pages this month')
link=reverse_lazy(
'statistics:statistic_detail',
args=('new-document-pages-per-month',)
)
widget_total_documents = DashboardWidget(
icon_class=icon_dashboard_total_document,
queryset=get_total_documents_queryset,
label=_('Total documents'),
link=reverse_lazy('documents:document_list')
)
widget_document_types = DashboardWidget(
icon_class=icon_dashboard_document_types,
queryset=get_document_types_queryset,
label=_('Document types'),
link=reverse_lazy('documents:document_type_list')
)
widget_documents_in_trash = DashboardWidget(
icon_class=icon_dashboard_documents_in_trash,
queryset=get_deleted_documents_queryset,
label=_('Documents in trash'),
link=reverse_lazy('documents:document_list_deleted')
)
def render(self, request):
self.count = new_document_pages_this_month(user=request.user)
return super(DashboardWidgetDocumentsPagesNewThisMonth, self).render(request)