Add support for extended templates when there are no results. Add help messages and useful links to several apps when there are no results available.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2018-08-23 19:36:15 -04:00
parent 2a45f52eb9
commit 9273eccbd6
23 changed files with 440 additions and 47 deletions

View File

@@ -109,6 +109,9 @@
- Improve statistics subclassing. Split class module into classes
and renderers.
- Sort facet link, object, secondady and sidebar actions.
- Add support for extended templates when there are no results.
- Add help messages and useful links to several apps when there
are no results available.
3.0.3 (2018-08-17)
==================

View File

@@ -6,6 +6,7 @@ import logging
from django.contrib.contenttypes.models import ContentType
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
@@ -18,6 +19,8 @@ from permissions import PermissionNamespace, Permission
from permissions.models import StoredPermission
from .classes import ModelPermission
from .icons import icon_acl_list
from .links import link_acl_create
from .models import AccessControlList
from .permissions import permission_acl_edit, permission_acl_view
@@ -135,6 +138,19 @@ class ACLListView(SingleObjectListView):
def get_extra_context(self):
return {
'hide_object': True,
'no_results_icon': icon_acl_list,
'no_results_main_link': link_acl_create.resolve(
context=RequestContext(
self.request, {'resolved_object': self.content_object}
)
),
'no_results_title': _(
'There are no ACLs for this object'
),
'no_results_text': _(
'ACL stands for Access Control List and is a precise method '
' to control user access to objects in the system.'
),
'object': self.content_object,
'title': _('Access control lists for: %s' % self.content_object),
}

View File

@@ -58,7 +58,11 @@
{% include 'appearance/generic_form_instance.html' %}
{% empty %}
<tr><td class="text-center" colspan=99>
{% if form_empty_label %}{{ form_empty_label }}{% else %}{% trans 'No results' %}{% endif %}
{% if form_empty_label %}{{ form_empty_label }}{% else %}
{% include 'appearance/no_results.html' %}
{% endif %}
</td></tr>
{% endfor %}
@@ -72,23 +76,26 @@
{% include 'appearance/generic_form_instance.html' %}
{% endif %}
{% if not read_only %}
<div class="form-group">
<button class="btn btn-primary" name="{% if form.prefix %}{{ form.prefix }}-submit{% else %}submit{% endif %}" type="submit">
{% if submit_icon_class %}
{{ submit_icon_class.render }}
{% elif submit_icon %}
<i class="{{ submit_icon }}"></i>
{% else %}
<i class="fa fa-check"></i>
{% if not form.management_form or wizard.management_form or form.forms %}
{# Is a normal form, a wizard form, or a formset with at least one form #}
<div class="form-group">
<button class="btn btn-primary" name="{% if form.prefix %}{{ form.prefix }}-submit{% else %}submit{% endif %}" type="submit">
{% if submit_icon_class %}
{{ submit_icon_class.render }}
{% elif submit_icon %}
<i class="{{ submit_icon }}"></i>
{% else %}
<i class="fa fa-check"></i>
{% endif %}
{% if submit_label %}{{ submit_label }}{% else %}{% if object %}{% trans 'Save' %}{% else %}{% trans 'Submit' %}{% endif %}{% endif %}
</button>
{% if previous %}
&nbsp;<a class="btn btn-default" onclick='history.back();'>
<i class="fa fa-times"></i> {% if cancel_label %}{{ cancel_label }}{% else %}{% trans 'Cancel' %}{% endif %}
</a>
{% endif %}
{% if submit_label %}{{ submit_label }}{% else %}{% if object %}{% trans 'Save' %}{% else %}{% trans 'Submit' %}{% endif %}{% endif %}
</button>
{% if previous %}
&nbsp;<a class="btn btn-default" onclick='history.back();'>
<i class="fa fa-times"></i> {% if cancel_label %}{{ cancel_label }}{% else %}{% trans 'Cancel' %}{% endif %}
</a>
{% endif %}
</div>
</div>
{% endif %}
{% endif %}
</form>
</div>

View File

@@ -14,7 +14,9 @@
{% for object_navigation_links in resolved_links %}
{% include 'navigation/generic_navigation.html' %}
{% empty %}
<p class="text-center" colspan=99>{% trans 'No results' %}</p>
<p class="text-center" colspan=99>
{% include 'appearance/no_results.html' %}
</p>
{% endfor %}
{% endwith %}
</div>

View File

@@ -102,7 +102,7 @@
</div>
{% empty %}
<div class="col-xs-12">
<p class="text-center">{% trans 'No results' %}</p>
{% include 'appearance/no_results.html' %}
</div>
{% endfor %}

View File

@@ -108,7 +108,11 @@
{% endif %}
</tr>
{% empty %}
<tr><td class="text-center" colspan=99>{% trans 'No results' %}</td></tr>
<tr>
<td class="text-center" colspan=99>
{% include 'appearance/no_results.html' %}
</td>
</tr>
{% endfor %}
</tbody>
</table>

View File

@@ -0,0 +1,38 @@
{% load i18n %}
<div class="text-center">
<div style="font-size: 150%;">
{% if no_results_icon %}
{{ no_results_icon.render }}
{% else %}
<i class="fa fa-times"></i>
{% endif %}
</div>
{% trans 'No results' as default_title %}
<h4>{{ no_results_title|default:default_title }}</h4>
{% if no_results_text %}
<p class="small">{{ no_results_text }}</p>
{% endif %}
{% if no_results_main_link %}
<div>
{% with no_results_main_link as link %}
{% with 'btn btn-primary btn-sm' as link_classes %}
{% include 'navigation/generic_subnavigation.html' %}
{% endwith %}
{% endwith %}
</div>
{% endif %}
{% if no_results_secondary_links %}
<div>
{% for link in no_results_secondary_links %}
{% with 'btn btn-default btn-sm' as link_classes %}
{% include 'navigation/generic_subnavigation.html' %}
{% endwith %}
{% endfor %}
</div>
{% endif %}
</div>

View File

@@ -2,5 +2,6 @@ from __future__ import absolute_import, unicode_literals
from appearance.classes import Icon
icon_cabinet = Icon(driver_name='fontawesome', symbol='columns')
icon_cabinet_create = Icon(driver_name='fontawesome', symbol='plus')
icon_cabinet_list = Icon(driver_name='fontawesome', symbol='columns')

View File

@@ -4,6 +4,7 @@ import logging
from django.contrib import messages
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _, ungettext
@@ -17,6 +18,10 @@ from documents.models import Document
from documents.views import DocumentListView
from .forms import CabinetListForm
from .icons import icon_cabinet
from .links import (
link_cabinet_add_document, link_cabinet_child_add, link_cabinet_create
)
from .models import Cabinet
from .permissions import (
permission_cabinet_add_document, permission_cabinet_create,
@@ -108,6 +113,18 @@ class CabinetDetailView(DocumentListView):
jstree_data(node=cabinet.get_root(), selected_node=cabinet)
),
'list_as_items': True,
'no_results_icon': icon_cabinet,
'no_results_main_link': link_cabinet_child_add.resolve(
context=RequestContext(
request=self.request, dict_={'object': cabinet}
)
),
'no_results_text': _(
'Cabinets level can contain documents or other '
'cabinet sub levels. Documents can be added from '
'the document\'s cabinet section.'
),
'no_results_title': _('This cabinet level is empty'),
'object': cabinet,
'title': _('Details of cabinet: %s') % cabinet.get_full_path(),
}
@@ -151,6 +168,16 @@ class CabinetListView(SingleObjectListView):
return {
'hide_link': True,
'title': _('Cabinets'),
'no_results_icon': icon_cabinet,
'no_results_main_link': link_cabinet_create.resolve(
context=RequestContext(request=self.request)
),
'no_results_text': _(
'Cabinets are a multi-level method to organize '
'documents. Each cabinet can contain documents as '
'well as other sub level cabinets.'
),
'no_results_title': _('No cabinets available'),
}
def get_object_list(self):
@@ -175,6 +202,18 @@ class DocumentCabinetListView(CabinetListView):
def get_extra_context(self):
return {
'hide_link': True,
'no_results_icon': icon_cabinet,
'no_results_main_link': link_cabinet_add_document.resolve(
context=RequestContext(
request=self.request, dict_={'object': self.document}
)
),
'no_results_text': _(
'Documents can be added to many cabinets.'
),
'no_results_title': _(
'This document is not in any cabinet'
),
'object': self.document,
'title': _('Cabinets containing document: %s') % self.document,
}

View File

@@ -17,6 +17,7 @@ from common.utils import encapsulate
from .exceptions import DocumentAlreadyCheckedOut, DocumentNotCheckedOut
from .forms import DocumentCheckoutForm, DocumentCheckoutDefailForm
from .icons import icon_checkout_info
from .models import DocumentCheckout
from .permissions import (
permission_document_checkin, permission_document_checkin_override,
@@ -103,6 +104,13 @@ class CheckoutListView(DocumentListView):
)
},
),
'no_results_icon': icon_checkout_info,
'no_results_text': _(
'Checking out a document blocks certain document '
'operations for a predetermined amount of '
'time.'
),
'no_results_title': _('No documents have been checked out'),
}
)
return context

View File

@@ -29,6 +29,7 @@ from .generics import ( # NOQA
SingleObjectDynamicFormEditView, SingleObjectDownloadView,
SingleObjectEditView, SingleObjectListView, SimpleView
)
from .icons import icon_setup
from .menus import menu_tools, menu_setup
from .permissions_runtime import permission_error_log_view
from .utils import check_version
@@ -253,10 +254,18 @@ class SetupListView(TemplateView):
data = super(SetupListView, self).get_context_data(**kwargs)
context = RequestContext(self.request)
context['request'] = self.request
data.update({
'resolved_links': menu_setup.resolve(context=context),
'title': _('Setup items'),
})
data.update(
{
'no_results_icon': icon_setup,
'no_results_label': _('No setup options available.'),
'no_results_text': _(
'No results here means that don\'t have the required '
'permissions to perform administrative task.'
),
'resolved_links': menu_setup.resolve(context=context),
'title': _('Setup items'),
}
)
return data

View File

@@ -0,0 +1,5 @@
from __future__ import absolute_import, unicode_literals
from appearance.classes import Icon
icon_transformation = Icon(driver_name='fontawesome', symbol='crop')

View File

@@ -5,6 +5,7 @@ from django.utils.translation import ugettext_lazy as _
from navigation import Link
from .icons import icon_transformation
from .permissions import (
permission_transformation_create, permission_transformation_delete,
permission_transformation_edit, permission_transformation_view
@@ -43,6 +44,7 @@ link_transformation_edit = Link(
text=_('Edit'), view='converter:transformation_edit'
)
link_transformation_list = Link(
icon_class=icon_transformation,
kwargs=get_kwargs_factory('resolved_object'),
permissions=(permission_transformation_view,), text=_('Transformations'),
view='converter:transformation_list'

View File

@@ -5,6 +5,7 @@ import logging
from django.contrib.contenttypes.models import ContentType
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
@@ -14,6 +15,8 @@ from common.views import (
SingleObjectListView
)
from .icons import icon_transformation
from .links import link_transformation_create
from .models import Transformation
from .permissions import (
permission_transformation_create, permission_transformation_delete,
@@ -210,6 +213,18 @@ class TransformationListView(SingleObjectListView):
'hide_link': True,
'hide_object': True,
'navigation_object_list': ('content_object',),
'no_results_icon': icon_transformation,
'no_results_main_link': link_transformation_create.resolve(
context=RequestContext(
self.request, {'content_object': self.content_object,}
)
),
'no_results_text': _(
'Transformations allow changing the visual appearance '
'of documents without making permanent changes to the '
'document file themselves.'
),
'no_results_title': _('No transformations'),
'title': _('Transformations for: %s') % self.content_object,
}

View File

@@ -1,6 +1,7 @@
from __future__ import absolute_import, unicode_literals
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
@@ -10,6 +11,8 @@ from common.generics import (
)
from documents.models import Document
from .icons import icon_comments_for_document
from .links import link_comment_add
from .models import Comment
from .permissions import (
permission_comment_create, permission_comment_delete,
@@ -93,6 +96,15 @@ class DocumentCommentListView(SingleObjectListView):
return {
'hide_link': True,
'hide_object': True,
'no_results_icon': icon_comments_for_document,
'no_results_text': _(
'Document comments are timestamped text entries from users. '
'They are great for collaboration.'
),
'no_results_main_link': link_comment_add.resolve(
RequestContext(self.request, {'object': self.get_document()})
),
'no_results_title': _('There are no comments'),
'object': self.get_document(),
'title': _('Comments for document: %s') % self.get_document(),
}

View File

@@ -6,6 +6,7 @@ from django.contrib import messages
from django.core.files import File
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
@@ -24,6 +25,12 @@ from .forms import (
DocumentVersionSignatureCreateForm,
DocumentVersionSignatureDetailForm
)
from .icons import icon_document_signature_list
from .links import (
link_document_version_signature_detached_create,
link_document_version_signature_embedded_create,
link_document_version_signature_upload
)
from .models import DetachedSignature, SignatureBaseModel
from .permissions import (
permission_document_version_sign_detached,
@@ -294,6 +301,31 @@ class DocumentVersionSignatureListView(SingleObjectListView):
def get_extra_context(self):
return {
'hide_object': True,
'no_results_icon': icon_document_signature_list,
'no_results_text': _(
'Signatures help provide authorship evidence and tamper '
'detection. They are very secure and hard to '
'forge. A signature can be embedded as part of the document '
'itself or uploaded as a separate file.'
),
'no_results_secondary_links': [
link_document_version_signature_detached_create.resolve(
RequestContext(
self.request, {'object': self.get_document_version()}
)
),
link_document_version_signature_embedded_create.resolve(
RequestContext(
self.request, {'object': self.get_document_version()}
)
),
link_document_version_signature_upload.resolve(
RequestContext(
self.request, {'object': self.get_document_version()}
)
),
],
'no_results_title': _('There are no signatures for this document.'),
'object': self.get_document_version(),
'title': _(
'Signatures for document version: %s'

View File

@@ -12,3 +12,12 @@ icon_tool_launch_all_workflows = Icon(
icon_workflow_list = Icon(
driver_name='fontawesome', symbol='sitemap'
)
icon_workflow_state = Icon(
driver_name='fontawesome', symbol='circle'
)
icon_workflow_state_action = Icon(
driver_name='fontawesome', symbol='code'
)
icon_workflow_transition = Icon(
driver_name='fontawesome', symbol='arrows-alt-h'
)

View File

@@ -6,7 +6,8 @@ from navigation import Link
from .icons import (
icon_document_workflow_instance_list, icon_setup_workflow_list,
icon_tool_launch_all_workflows, icon_workflow_list
icon_tool_launch_all_workflows, icon_workflow_list,
icon_workflow_state, icon_workflow_state_action, icon_workflow_transition
)
from .permissions import (
permission_workflow_create, permission_workflow_delete,
@@ -20,8 +21,8 @@ link_document_workflow_instance_list = Link(
view='document_states:document_workflow_instance_list',
)
link_setup_workflow_create = Link(
permissions=(permission_workflow_create,), text=_('Create workflow'),
view='document_states:setup_workflow_create'
icon_class=icon_workflow_list, permissions=(permission_workflow_create,),
text=_('Create workflow'), view='document_states:setup_workflow_create'
)
link_setup_workflow_delete = Link(
args='resolved_object.pk', permissions=(permission_workflow_delete,),
@@ -57,13 +58,13 @@ link_setup_workflow_state_action_list = Link(
view='document_states:setup_workflow_state_action_list',
)
link_setup_workflow_state_action_selection = Link(
args='resolved_object.pk', permissions=(permission_workflow_edit,),
text=_('Create action'),
args='resolved_object.pk', icon_class=icon_workflow_state_action,
permissions=(permission_workflow_edit,), text=_('Create action'),
view='document_states:setup_workflow_state_action_selection',
)
link_setup_workflow_state_create = Link(
args='resolved_object.pk', permissions=(permission_workflow_edit,),
text=_('Create state'),
args='resolved_object.pk', icon_class=icon_workflow_state,
permissions=(permission_workflow_edit,), text=_('Create state'),
view='document_states:setup_workflow_state_create',
)
link_setup_workflow_state_delete = Link(
@@ -76,12 +77,13 @@ link_setup_workflow_state_edit = Link(
text=_('Edit'), view='document_states:setup_workflow_state_edit',
)
link_setup_workflow_states = Link(
args='resolved_object.pk', permissions=(permission_workflow_view,),
text=_('States'), view='document_states:setup_workflow_state_list',
args='resolved_object.pk', icon_class=icon_workflow_state,
permissions=(permission_workflow_view,), text=_('States'),
view='document_states:setup_workflow_state_list',
)
link_setup_workflow_transition_create = Link(
args='resolved_object.pk', permissions=(permission_workflow_edit,),
text=_('Create transition'),
args='resolved_object.pk', icon_class=icon_workflow_transition,
permissions=(permission_workflow_edit,), text=_('Create transition'),
view='document_states:setup_workflow_transition_create',
)
link_setup_workflow_transition_delete = Link(
@@ -94,8 +96,8 @@ link_setup_workflow_transition_edit = Link(
text=_('Edit'), view='document_states:setup_workflow_transition_edit',
)
link_setup_workflow_transitions = Link(
args='resolved_object.pk', permissions=(permission_workflow_view,),
text=_('Transitions'),
args='resolved_object.pk', icon_class=icon_workflow_transition,
permissions=(permission_workflow_view,), text=_('Transitions'),
view='document_states:setup_workflow_transition_list',
)
link_tool_launch_all_workflows = Link(

View File

@@ -6,6 +6,7 @@ from django.db import transaction
from django.db.utils import IntegrityError
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy as _
@@ -27,6 +28,15 @@ from .forms import (
WorkflowPreviewForm, WorkflowStateActionDynamicForm, WorkflowStateForm,
WorkflowTransitionForm, WorkflowTransitionTriggerEventRelationshipFormSet
)
from .icons import (
icon_workflow_list, icon_workflow_state, icon_workflow_state_action,
icon_workflow_transition
)
from .links import (
link_setup_workflow_create, link_setup_workflow_state_create,
link_setup_workflow_state_action_selection,
link_setup_workflow_transition_create
)
from .models import (
Workflow, WorkflowInstance, WorkflowState, WorkflowStateAction,
WorkflowTransition, WorkflowRuntimeProxy, WorkflowStateRuntimeProxy,
@@ -138,13 +148,27 @@ class WorkflowInstanceTransitionView(FormView):
# Setup
class SetupWorkflowListView(SingleObjectListView):
extra_context = {
'title': _('Workflows'),
'hide_object': True,
}
model = Workflow
object_permission = permission_workflow_view
def get_extra_context(self):
return {
'hide_object': True,
'no_results_icon': icon_workflow_list,
'no_results_main_link': link_setup_workflow_create.resolve(
context=RequestContext(request=self.request)
),
'no_results_text': _(
'Workflows store a series for states and keep track of the '
'current state of a document. Transitions are used to change the '
'current state to a new one.'
),
'no_results_title': _(
'No workflows have been defined.'
),
'title': _('Workflows'),
}
class SetupWorkflowCreateView(SingleObjectCreateView):
form_class = WorkflowForm
@@ -324,6 +348,21 @@ class SetupWorkflowStateActionListView(SingleObjectListView):
return {
'hide_object': True,
'navigation_object_list': ('object', 'workflow'),
'no_results_icon': icon_workflow_state_action,
'no_results_main_link': link_setup_workflow_state_action_selection.resolve(
context=RequestContext(
request=self.request, dict_={
'object': self.get_workflow_state()
}
)
),
'no_results_title': _(
'There are no actions for this workflow state.'
),
'no_results_text': _(
'Workflow state actions are macros that get executed when '
'enters or leaves the state in which they reside.'
),
'object': self.get_workflow_state(),
'title': _(
'Actions for workflow state: %s'
@@ -469,6 +508,18 @@ class SetupWorkflowStateListView(SingleObjectListView):
def get_extra_context(self):
return {
'hide_link': True,
'no_results_icon': icon_workflow_state,
'no_results_main_link': link_setup_workflow_state_create.resolve(
context=RequestContext(
self.request, {'object': self.get_workflow()}
)
),
'no_results_title': _(
'This workflow doesn\'t have any states'
),
'no_results_text': _(
'Create states and link them using transitions.'
),
'object': self.get_workflow(),
'title': _('States of workflow: %s') % self.get_workflow()
}
@@ -584,6 +635,19 @@ class SetupWorkflowTransitionListView(SingleObjectListView):
def get_extra_context(self):
return {
'hide_link': True,
'no_results_icon': icon_workflow_transition,
'no_results_main_link': link_setup_workflow_transition_create.resolve(
context=RequestContext(
self.request, {'object': self.get_workflow()}
)
),
'no_results_text': _(
'Create a transition and use it to move a workflow from '
' one state to another.'
),
'no_results_title': _(
'This workflow doesn\'t have any transitions'
),
'object': self.get_workflow(),
'title': _(
'Transitions of workflow: %s'
@@ -606,7 +670,18 @@ class WorkflowListView(SingleObjectListView):
def get_extra_context(self):
return {
'hide_object': True,
'title': _('Workflows')
'no_results_main_link': link_setup_workflow_create.resolve(
context=RequestContext(
self.request, {}
)
),
'no_results_title': _('There are no workflows'),
'no_results_text': _(
'Create some workflows and associated them with a document '
'type. Active workflows will be shown here and the documents '
'for which they are executing.'
),
'title': _('Workflows'),
}
def get_object_list(self):
@@ -635,6 +710,13 @@ class WorkflowDocumentListView(DocumentListView):
context = super(WorkflowDocumentListView, self).get_extra_context()
context.update(
{
'no_results_title': _(
'There are documents executing this workflow'
),
'no_results_text': _(
'Associate a workflow with some document types and '
'documents of those types will be listed in this view.'
),
'object': self.workflow,
'title': _('Documents with the workflow: %s') % self.workflow
}
@@ -653,14 +735,17 @@ class WorkflowStateDocumentListView(DocumentListView):
{
'object': workflow_state,
'navigation_object_list': ('object', 'workflow'),
'workflow': WorkflowRuntimeProxy.objects.get(
pk=workflow_state.workflow.pk
'no_results_title': _(
'There are documents in this workflow state'
),
'title': _(
'Documents in the workflow "%s", state "%s"'
) % (
workflow_state.workflow, workflow_state
)
),
'workflow': WorkflowRuntimeProxy.objects.get(
pk=workflow_state.workflow.pk
),
}
)
return context
@@ -693,6 +778,17 @@ class WorkflowStateListView(SingleObjectListView):
return {
'hide_columns': True,
'hide_link': True,
'no_results_main_link': link_setup_workflow_state_create.resolve(
context=RequestContext(
self.request, {'object': self.get_workflow()}
)
),
'no_results_title': _(
'This workflow doesn\'t have any state.'
),
'no_results_text': _(
'Create states and link them using transitions.'
),
'object': self.get_workflow(),
'title': _('States of workflow: %s') % self.get_workflow()
}
@@ -751,6 +847,10 @@ class SetupWorkflowTransitionTriggerEventListView(FormView):
'form_display_mode_table': True,
'navigation_object_list': ('object', 'workflow'),
'object': self.get_object(),
'subtitle': _(
'Triggers are events that cause this transition to execute '
'automatically.'
),
'title': _(
'Workflow transition trigger events for: %s'
) % self.get_object(),

View File

@@ -5,6 +5,7 @@ from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
@@ -19,6 +20,8 @@ from .classes import EventType, ModelEventType
from .forms import (
EventTypeUserRelationshipFormSet, ObjectEventTypeUserRelationshipFormSet
)
from .icons import icon_user_notifications_list
from .links import link_event_types_subscriptions_list
from .models import StoredEventType
from .permissions import permission_events_view
from .widgets import event_object_link
@@ -109,6 +112,17 @@ class NotificationListView(SingleObjectListView):
def get_extra_context(self):
return {
'hide_object': True,
'no_results_icon': icon_user_notifications_list,
'no_results_main_link': link_event_types_subscriptions_list.resolve(
context=RequestContext(
self.request, {}
)
),
'no_results_text': _(
'Subscribe to global or object events to receive '
'notifications.'
),
'no_results_title': _('There are no notifications'),
'object': self.request.user,
'title': _('Notifications'),
}

View File

@@ -11,4 +11,5 @@ icon_document_metadata_edit_submit = Icon(
icon_document_metadata_remove_submit = Icon(
driver_name='fontawesome', symbol='minus'
)
icon_metadata = Icon(driver_name='fontawesome', symbol='pencil-alt')
icon_metadata_view = Icon(driver_name='fontawesome', symbol='pencil-alt')

View File

@@ -5,6 +5,7 @@ from django.contrib import messages
from django.core.exceptions import ValidationError
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse, reverse_lazy
from django.utils.encoding import force_text
from django.utils.http import urlencode
@@ -28,7 +29,11 @@ from .forms import (
)
from .icons import (
icon_document_metadata_add_submit, icon_document_metadata_edit_submit,
icon_document_metadata_remove_submit
icon_document_metadata_remove_submit, icon_metadata
)
from .links import (
link_metadata_add, link_metadata_multiple_add,
link_setup_metadata_type_create
)
from .models import DocumentMetadata, MetadataType
from .permissions import (
@@ -262,8 +267,29 @@ class DocumentMetadataEditView(MultipleObjectFormActionView):
def get_extra_context(self):
queryset = self.get_queryset()
if queryset.count() == 1:
no_results_main_link = link_metadata_add.resolve(
context=RequestContext(
request=self.request, dict_={'object': queryset.first()}
)
)
else:
no_results_main_link = link_metadata_multiple_add.resolve(
context=RequestContext(request=self.request)
)
no_results_main_link.url = '{}?id_list={}'.format(
no_results_main_link.url, id_list
)
result = {
'form_display_mode_table': True,
'no_results_icon': icon_metadata,
'no_results_main_link': no_results_main_link,
'no_results_text': _(
'Add metadata types available for this document\'s type '
'and assign them corresponding values.'
),
'no_results_title': _('There is no metadata to edit'),
'submit_icon_class': icon_document_metadata_edit_submit,
'submit_label': _('Edit'),
'title': ungettext(
@@ -371,9 +397,23 @@ class DocumentMetadataListView(SingleObjectListView):
return {
'hide_link': True,
'object': document,
'no_results_icon': icon_metadata,
'no_results_main_link': link_metadata_add.resolve(
context=RequestContext(
request=self.request, dict_={'object': document}
)
),
'no_results_text': _(
'Add metadata types this document\'s type '
'to be able to add them to individual documents. '
'Once added to individual document, you can then edit their '
'values.'
),
'no_results_title': _('This document doesn\'t have any metadata'),
'title': _('Metadata for document: %s') % document,
}
def get_object_list(self):
return self.get_document().metadata.all()
@@ -579,6 +619,19 @@ class MetadataTypeListView(SingleObjectListView):
},
),
'hide_link': True,
'no_results_icon': icon_metadata,
'no_results_main_link': link_setup_metadata_type_create.resolve(
context=RequestContext(request=self.request)
),
'no_results_text': _(
'Metadata types are users defined properties that can be '
'assigned values. Once created they must be associated to '
'document types, either as optional or required, for each. '
'Setting a metadata type as required for a document type '
'will block the upload of documents of that type until a '
'metadata value is provided.'
),
'no_results_title': _('There are no metadata types'),
'title': _('Metadata types'),
}

View File

@@ -4,6 +4,7 @@ import logging
from django.contrib import messages
from django.shortcuts import get_object_or_404, reverse
from django.template import RequestContext
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _, ungettext
@@ -17,7 +18,10 @@ from documents.views import DocumentListView
from documents.permissions import permission_document_view
from .forms import TagMultipleSelectionForm
from .icons import icon_tag_delete_submit, icon_tag_remove_submit
from .icons import (
icon_menu_tags, icon_tag_delete_submit, icon_tag_remove_submit
)
from .links import link_tag_attach, link_tag_create
from .models import Tag
from .permissions import (
permission_tag_attach, permission_tag_create, permission_tag_delete,
@@ -190,6 +194,17 @@ class TagListView(SingleObjectListView):
return {
'hide_link': True,
'hide_object': True,
'no_results_icon': icon_menu_tags,
'no_results_text': _(
'Tags are color coded properties that can be attached or '
'removed from documents.'
),
'no_results_title': _('No tags available'),
'no_results_main_link': link_tag_create.resolve(
context=RequestContext(
self.request, {}
)
),
'title': _('Tags'),
}
@@ -237,6 +252,12 @@ class DocumentTagListView(TagListView):
context.update(
{
'hide_link': True,
'no_results_title': _('Document has no tags attached'),
'no_results_main_link': link_tag_attach.resolve(
context=RequestContext(
self.request, {'object': self.document}
)
),
'object': self.document,
'title': _('Tags for document: %s') % self.document,
}