Add dashboard feature
This commit is contained in:
@@ -159,3 +159,12 @@ hr {
|
|||||||
a i {
|
a i {
|
||||||
padding-right: 3px;
|
padding-right: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-dashboard-widget {
|
||||||
|
box-shadow: 1px 1px 1px rgba(0,0,0,0.3);
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-dashboard-widget .panel-heading i {
|
||||||
|
text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
|
||||||
|
<div class="panel panel-secondary panel-dashboard-widget">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-2">
|
||||||
|
<i class="fa fa-{{ widget.icon }} fa-2x"></i>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-10 text-right">
|
||||||
|
<strong>{{ widget.label }}</strong>
|
||||||
|
<div class="huge">
|
||||||
|
{% if widget.func %}
|
||||||
|
{{ widget.func }}
|
||||||
|
{% else %}
|
||||||
|
{{ widget.queryset.count }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if widget.link %}
|
||||||
|
<a href="{{ widget.link }}">
|
||||||
|
<div class="panel-footer">
|
||||||
|
<span class="pull-left">{% trans 'View Details' %}</span>
|
||||||
|
<span class="pull-right"><i class="fa fa-external-link"></i></span>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
|
{% load common_tags %}
|
||||||
{% load navigation_tags %}
|
{% load navigation_tags %}
|
||||||
|
|
||||||
{% block title %}{% trans 'Home' %}{% endblock %}
|
{% block title %}{% trans 'Home' %}{% endblock %}
|
||||||
@@ -53,30 +54,21 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<div class="panel panel-default center-block">
|
<div class="panel panel-default center-block">
|
||||||
<div class="panel-heading">{% trans 'Search pages' %}</div>
|
<div class="panel-heading">{% trans 'Search' %}</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form action="{% url 'search:results' search_model='documents.DocumentPageResult' %}" method="get" role="search">
|
<form action="{% url 'search:results' search_model='documents.DocumentPageResult' %}" method="get" role="search">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input class="form-control" name="q" placeholder="{% trans 'Space separated terms' %}" type="text" value="{{ search_terms|default:'' }}">
|
<input class="form-control" name="q" placeholder="{% trans 'Search pages' %}" type="text" value="{{ search_terms|default:'' }}">
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-default" type="submit">{% trans 'Search' %}</button>
|
<button class="btn btn-default" type="submit">{% trans 'Search' %}</button>
|
||||||
<a class="btn btn-primary" href="{% url 'search:search_advanced' search_model='documents.DocumentPageResult' %}">{% trans 'Advanced' %}</a>
|
<a class="btn btn-primary" href="{% url 'search:search_advanced' search_model='documents.DocumentPageResult' %}">{% trans 'Advanced' %}</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
<br/>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-12">
|
|
||||||
<div class="panel panel-default center-block">
|
|
||||||
<div class="panel-heading">{% trans 'Search documents' %}</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<form action="{% url 'search:results' search_model='documents.Document' %}" method="get" role="search">
|
<form action="{% url 'search:results' search_model='documents.Document' %}" method="get" role="search">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input class="form-control" name="q" placeholder="{% trans 'Space separated terms' %}" type="text" value="{{ search_terms|default:'' }}">
|
<input class="form-control" name="q" placeholder="{% trans 'Search documents' %}" type="text" value="{{ search_terms|default:'' }}">
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-default" type="submit">{% trans 'Search' %}</button>
|
<button class="btn btn-default" type="submit">{% trans 'Search' %}</button>
|
||||||
<a class="btn btn-primary" href="{% url 'search:search_advanced' search_model='documents.Document' %}">{% trans 'Advanced' %}</a>
|
<a class="btn btn-primary" href="{% url 'search:search_advanced' search_model='documents.Document' %}">{% trans 'Advanced' %}</a>
|
||||||
@@ -88,4 +80,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% get_dashboard_widgets as dashboard_widgets %}
|
||||||
|
<div class="row">
|
||||||
|
{% for widget in dashboard_widgets %}
|
||||||
|
{% include 'appearance/dashboard_widget.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -5,6 +5,24 @@ from django.db import models
|
|||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
|
|
||||||
|
class DashboardWidget(object):
|
||||||
|
_registry = []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_all(cls):
|
||||||
|
return cls._registry
|
||||||
|
|
||||||
|
def __init__(self, label, func=None, icon=None, link=None, queryset=None, statistic_slug=None):
|
||||||
|
self.label = label
|
||||||
|
self.icon = icon
|
||||||
|
self.link = link
|
||||||
|
self.queryset = queryset
|
||||||
|
self.func = func
|
||||||
|
self.statistic_slug = statistic_slug
|
||||||
|
|
||||||
|
self.__class__._registry.append(self)
|
||||||
|
|
||||||
|
|
||||||
class ModelAttribute(object):
|
class ModelAttribute(object):
|
||||||
__registry = {}
|
__registry = {}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from django.template.loader import get_template
|
|||||||
|
|
||||||
import mayan
|
import mayan
|
||||||
|
|
||||||
|
from ..classes import DashboardWidget
|
||||||
from ..utils import return_attrib
|
from ..utils import return_attrib
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
@@ -22,6 +23,11 @@ except sh.CommandNotFound:
|
|||||||
DATE = None
|
DATE = None
|
||||||
|
|
||||||
|
|
||||||
|
@register.assignment_tag
|
||||||
|
def get_dashboard_widgets():
|
||||||
|
return DashboardWidget.get_all()
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def get_encoded_parameter(item, parameters_dict):
|
def get_encoded_parameter(item, parameters_dict):
|
||||||
result = {}
|
result = {}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from datetime import timedelta
|
|||||||
|
|
||||||
from kombu import Exchange, Queue
|
from kombu import Exchange, Queue
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from acls import ModelPermission
|
from acls import ModelPermission
|
||||||
@@ -13,7 +14,7 @@ from common import (
|
|||||||
MayanAppConfig, MissingItem, menu_facet, menu_front_page, menu_object,
|
MayanAppConfig, MissingItem, menu_facet, menu_front_page, menu_object,
|
||||||
menu_secondary, menu_setup, menu_sidebar, menu_multi_item, menu_tools
|
menu_secondary, menu_setup, menu_sidebar, menu_multi_item, menu_tools
|
||||||
)
|
)
|
||||||
from common.classes import ModelAttribute
|
from common.classes import DashboardWidget, ModelAttribute
|
||||||
from common.signals import post_initial_setup
|
from common.signals import post_initial_setup
|
||||||
from common.widgets import two_state_template
|
from common.widgets import two_state_template
|
||||||
from converter.links import link_transformation_list
|
from converter.links import link_transformation_list
|
||||||
@@ -71,6 +72,7 @@ from .search import document_search, document_page_search # NOQA
|
|||||||
from .settings import setting_display_size, setting_thumbnail_size
|
from .settings import setting_display_size, setting_thumbnail_size
|
||||||
from .statistics import (
|
from .statistics import (
|
||||||
new_documents_per_month, new_document_pages_per_month,
|
new_documents_per_month, new_document_pages_per_month,
|
||||||
|
new_document_pages_this_month, new_documents_this_month,
|
||||||
new_document_versions_per_month, total_document_per_month,
|
new_document_versions_per_month, total_document_per_month,
|
||||||
total_document_page_per_month, total_document_version_per_month
|
total_document_page_per_month, total_document_version_per_month
|
||||||
)
|
)
|
||||||
@@ -96,6 +98,41 @@ class DocumentsApp(MayanAppConfig):
|
|||||||
DocumentTypeFilename = self.get_model('DocumentTypeFilename')
|
DocumentTypeFilename = self.get_model('DocumentTypeFilename')
|
||||||
DocumentVersion = self.get_model('DocumentVersion')
|
DocumentVersion = self.get_model('DocumentVersion')
|
||||||
|
|
||||||
|
DashboardWidget(
|
||||||
|
func=new_document_pages_this_month, icon='fa fa-calendar',
|
||||||
|
label=_('New pages this month'),
|
||||||
|
link=reverse_lazy(
|
||||||
|
'statistics:statistic_detail',
|
||||||
|
args=('new-document-pages-per-month',)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
DashboardWidget(
|
||||||
|
func=new_documents_this_month, icon='fa fa-calendar',
|
||||||
|
label=_('New documents this month'),
|
||||||
|
link=reverse_lazy(
|
||||||
|
'statistics:statistic_detail',
|
||||||
|
args=('new-documents-per-month',)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
DashboardWidget(
|
||||||
|
icon='fa fa-file', queryset=Document.objects.all(),
|
||||||
|
label=_('Total documents'),
|
||||||
|
link=reverse_lazy('documents:document_list')
|
||||||
|
)
|
||||||
|
|
||||||
|
DashboardWidget(
|
||||||
|
icon='fa fa-book', queryset=DocumentType.objects.all(),
|
||||||
|
label=_('Document types'),
|
||||||
|
link=reverse_lazy('documents:document_type_list')
|
||||||
|
)
|
||||||
|
|
||||||
|
DashboardWidget(
|
||||||
|
icon='fa fa-trash', queryset=DeletedDocument.objects.all(),
|
||||||
|
label=_('Documents in trash'),
|
||||||
|
link=reverse_lazy('documents:document_list_deleted')
|
||||||
|
)
|
||||||
|
|
||||||
MissingItem(
|
MissingItem(
|
||||||
label=_('Create a document type'),
|
label=_('Create a document type'),
|
||||||
description=_(
|
description=_(
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
|
||||||
import qsstats
|
import qsstats
|
||||||
|
|
||||||
|
|
||||||
def new_documents_per_month():
|
def new_documents_per_month():
|
||||||
from .models import Document
|
Document = apps.get_model(app_label='documents', model_name='Document')
|
||||||
|
|
||||||
qss = qsstats.QuerySetStats(Document.passthrough.all(), 'date_added')
|
qss = qsstats.QuerySetStats(Document.passthrough.all(), 'date_added')
|
||||||
|
|
||||||
@@ -15,43 +17,78 @@ def new_documents_per_month():
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
'series': {
|
'series': {
|
||||||
'Documents': map(lambda x: {x[0].month: x[1]}, qss.time_series(start=this_year, end=today, interval='months'))
|
'Documents': map(
|
||||||
}
|
lambda x: {x[0].month: x[1]},
|
||||||
}
|
qss.time_series(start=this_year, end=today, interval='months')
|
||||||
|
)
|
||||||
|
|
||||||
def new_document_versions_per_month():
|
|
||||||
from .models import DocumentVersion
|
|
||||||
|
|
||||||
qss = qsstats.QuerySetStats(DocumentVersion.objects.all(), 'document__date_added')
|
|
||||||
|
|
||||||
today = datetime.date.today()
|
|
||||||
this_year = datetime.date(year=today.year, month=1, day=1)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'series': {
|
|
||||||
'Versions': map(lambda x: {x[0].month: x[1]}, qss.time_series(start=this_year, end=today, interval='months'))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def new_document_pages_per_month():
|
def new_document_pages_per_month():
|
||||||
from .models import DocumentPage
|
DocumentPage = apps.get_model(
|
||||||
|
app_label='documents', model_name='DocumentPage'
|
||||||
|
)
|
||||||
|
|
||||||
qss = qsstats.QuerySetStats(DocumentPage.objects.all(), 'document_version__document__date_added')
|
qss = qsstats.QuerySetStats(
|
||||||
|
DocumentPage.objects.all(), 'document_version__document__date_added'
|
||||||
|
)
|
||||||
|
|
||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
this_year = datetime.date(year=today.year, month=1, day=1)
|
this_year = datetime.date(year=today.year, month=1, day=1)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'series': {
|
'series': {
|
||||||
'Pages': map(lambda x: {x[0].month: x[1]}, qss.time_series(start=this_year, end=today, interval='months'))
|
'Pages': map(
|
||||||
|
lambda x: {x[0].month: x[1]},
|
||||||
|
qss.time_series(start=this_year, end=today, interval='months')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def new_documents_this_month():
|
||||||
|
Document = apps.get_model(app_label='documents', model_name='Document')
|
||||||
|
|
||||||
|
qss = qsstats.QuerySetStats(Document.objects.all(), 'date_added')
|
||||||
|
return qss.this_month() or '0'
|
||||||
|
|
||||||
|
|
||||||
|
def new_document_versions_per_month():
|
||||||
|
DocumentVersion = apps.get_model(
|
||||||
|
app_label='documents', model_name='DocumentVersion'
|
||||||
|
)
|
||||||
|
|
||||||
|
qss = qsstats.QuerySetStats(
|
||||||
|
DocumentVersion.objects.all(), 'document__date_added'
|
||||||
|
)
|
||||||
|
|
||||||
|
today = datetime.date.today()
|
||||||
|
this_year = datetime.date(year=today.year, month=1, day=1)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'series': {
|
||||||
|
'Versions': map(
|
||||||
|
lambda x: {x[0].month: x[1]},
|
||||||
|
qss.time_series(start=this_year, end=today, interval='months')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def new_document_pages_this_month():
|
||||||
|
DocumentPage = apps.get_model(
|
||||||
|
app_label='documents', model_name='DocumentPage'
|
||||||
|
)
|
||||||
|
|
||||||
|
qss = qsstats.QuerySetStats(
|
||||||
|
DocumentPage.objects.all(), 'document_version__document__date_added'
|
||||||
|
)
|
||||||
|
return qss.this_month() or '0'
|
||||||
|
|
||||||
|
|
||||||
def total_document_per_month():
|
def total_document_per_month():
|
||||||
from .models import Document
|
Document = apps.get_model(app_label='documents', model_name='Document')
|
||||||
|
|
||||||
qss = qsstats.QuerySetStats(Document.objects.all(), 'date_added')
|
qss = qsstats.QuerySetStats(Document.objects.all(), 'date_added')
|
||||||
this_year = datetime.date.today().year
|
this_year = datetime.date.today().year
|
||||||
@@ -78,9 +115,13 @@ def total_document_per_month():
|
|||||||
|
|
||||||
|
|
||||||
def total_document_version_per_month():
|
def total_document_version_per_month():
|
||||||
from .models import DocumentVersion
|
DocumentVersion = apps.get_model(
|
||||||
|
app_label='documents', model_name='DocumentVersion'
|
||||||
|
)
|
||||||
|
|
||||||
qss = qsstats.QuerySetStats(DocumentVersion.objects.all(), 'document__date_added')
|
qss = qsstats.QuerySetStats(
|
||||||
|
DocumentVersion.objects.all(), 'document__date_added'
|
||||||
|
)
|
||||||
this_year = datetime.date.today().year
|
this_year = datetime.date.today().year
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
@@ -105,9 +146,13 @@ def total_document_version_per_month():
|
|||||||
|
|
||||||
|
|
||||||
def total_document_page_per_month():
|
def total_document_page_per_month():
|
||||||
from .models import DocumentPage
|
DocumentPage = apps.get_model(
|
||||||
|
app_label='documents', model_name='DocumentPage'
|
||||||
|
)
|
||||||
|
|
||||||
qss = qsstats.QuerySetStats(DocumentPage.objects.all(), 'document_version__document__date_added')
|
qss = qsstats.QuerySetStats(
|
||||||
|
DocumentPage.objects.all(), 'document_version__document__date_added'
|
||||||
|
)
|
||||||
this_year = datetime.date.today().year
|
this_year = datetime.date.today().year
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
|
|||||||
Reference in New Issue
Block a user