Add workflows per document type view

Make workflows, workflows states, workflow transitions column
sortable. Show completion and intial state in the workflow
proxy instance menu list.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2019-05-04 21:26:12 -04:00
parent c9b5d2794e
commit 99b180f269
9 changed files with 148 additions and 31 deletions

View File

@@ -227,6 +227,12 @@
the new AddRemove view. the new AddRemove view.
* Add the workflow created and edited events. * Add the workflow created and edited events.
* Remove AssignRemove View. * Remove AssignRemove View.
* Add view to setup workflows per document type
from the document type side.
* Make workflows, workflows states, workflow
transitions column sortable.
* Show completion and intial state in the
workflow proxy instance menu list.
3.1.11 (2019-04-XX) 3.1.11 (2019-04-XX)
=================== ===================

View File

@@ -260,6 +260,12 @@ Other changes
the new AddRemove view. the new AddRemove view.
* Add the workflow created and edited events. * Add the workflow created and edited events.
* Remove AssignRemove View. * Remove AssignRemove View.
* Add view to setup workflows per document type
from the document type side.
* Make workflows, workflows states, workflow
transitions column sortable.
* Show completion and intial state in the
workflow proxy instance menu list.
Removals Removals
-------- --------

View File

@@ -31,10 +31,11 @@ from .handlers import (
handler_index_document, handler_launch_workflow, handler_trigger_transition handler_index_document, handler_launch_workflow, handler_trigger_transition
) )
from .links import ( from .links import (
link_document_workflow_instance_list, link_setup_workflow_document_types, link_document_workflow_instance_list, link_setup_document_type_workflows,
link_setup_workflow_create, link_setup_workflow_delete, link_setup_workflow_document_types, link_setup_workflow_create,
link_setup_workflow_edit, link_setup_workflow_list, link_setup_workflow_delete, link_setup_workflow_edit,
link_setup_workflow_states, link_setup_workflow_state_action_delete, link_setup_workflow_list, link_setup_workflow_states,
link_setup_workflow_state_action_delete,
link_setup_workflow_state_action_edit, link_setup_workflow_state_action_edit,
link_setup_workflow_state_action_list, link_setup_workflow_state_action_list,
link_setup_workflow_state_action_selection, link_setup_workflow_state_action_selection,
@@ -74,6 +75,9 @@ class DocumentStatesApp(MayanAppConfig):
Document = apps.get_model( Document = apps.get_model(
app_label='documents', model_name='Document' app_label='documents', model_name='Document'
) )
DocumentType = apps.get_model(
app_label='documents', model_name='DocumentType'
)
ErrorLogEntry = apps.get_model( ErrorLogEntry = apps.get_model(
app_label='common', model_name='ErrorLogEntry' app_label='common', model_name='ErrorLogEntry'
) )
@@ -158,15 +162,14 @@ class DocumentStatesApp(MayanAppConfig):
) )
SourceColumn( SourceColumn(
source=Workflow, label=_('Label'), attribute='label' attribute='label', is_sortable=True, source=Workflow
) )
SourceColumn( SourceColumn(
source=Workflow, label=_('Internal name'), attribute='internal_name', is_sortable=True, source=Workflow
attribute='internal_name'
) )
SourceColumn( SourceColumn(
source=Workflow, label=_('Initial state'), attribute='get_initial_state', empty_value=_('None'),
func=lambda context: context['object'].get_initial_state() or _('None') source=Workflow
) )
SourceColumn( SourceColumn(
@@ -213,36 +216,42 @@ class DocumentStatesApp(MayanAppConfig):
) )
SourceColumn( SourceColumn(
attribute='initial', label=_('Is initial state?'), attribute='label', is_sortable=True, source=WorkflowState
source=WorkflowState, widget=TwoStateWidget
) )
SourceColumn( SourceColumn(
source=WorkflowState, label=_('Completion'), attribute='completion' attribute='initial', is_sortable=True, source=WorkflowState,
widget=TwoStateWidget
)
SourceColumn(
attribute='completion', source=WorkflowState, is_sortable=True,
) )
SourceColumn( SourceColumn(
source=WorkflowStateAction, label=_('Label'), attribute='label' attribute='label', is_sortable=True, source=WorkflowStateAction
) )
SourceColumn( SourceColumn(
attribute='enabled', label=_('Enabled?'), attribute='enabled', is_sortable=True, source=WorkflowStateAction,
source=WorkflowStateAction, widget=TwoStateWidget widget=TwoStateWidget
) )
SourceColumn( SourceColumn(
source=WorkflowStateAction, label=_('When?'), attribute='get_when_display', label=_('When?'),
attribute='get_when_display' source=WorkflowStateAction
) )
SourceColumn( SourceColumn(
source=WorkflowStateAction, label=_('Action type'), attribute='get_class_label', label=_('Action type'),
attribute='get_class_label' source=WorkflowStateAction
) )
SourceColumn( SourceColumn(
source=WorkflowTransition, label=_('Origin state'), attribute='label', is_sortable=True, source=WorkflowTransition,
attribute='origin_state'
) )
SourceColumn( SourceColumn(
source=WorkflowTransition, label=_('Destination state'), attribute='origin_state', is_sortable=True,
attribute='destination_state' source=WorkflowTransition
)
SourceColumn(
attribute='destination_state', is_sortable=True,
source=WorkflowTransition
) )
SourceColumn( SourceColumn(
source=WorkflowTransition, label=_('Triggers'), source=WorkflowTransition, label=_('Triggers'),
@@ -271,6 +280,7 @@ class DocumentStatesApp(MayanAppConfig):
menu_facet.bind_links( menu_facet.bind_links(
links=(link_document_workflow_instance_list,), sources=(Document,) links=(link_document_workflow_instance_list,), sources=(Document,)
) )
menu_list_facet.bind_links( menu_list_facet.bind_links(
links=( links=(
link_acl_list, link_events_for_object, link_acl_list, link_events_for_object,
@@ -280,6 +290,12 @@ class DocumentStatesApp(MayanAppConfig):
link_workflow_preview link_workflow_preview
), sources=(Workflow,) ), sources=(Workflow,)
) )
menu_list_facet.bind_links(
links=(
link_setup_document_type_workflows,
), sources=(DocumentType,)
)
menu_main.bind_links(links=(link_workflow_runtime_proxy_list,), position=10) menu_main.bind_links(links=(link_workflow_runtime_proxy_list,), position=10)
menu_object.bind_links( menu_object.bind_links(
links=( links=(

View File

@@ -3,6 +3,11 @@ from __future__ import absolute_import, unicode_literals
from mayan.apps.appearance.classes import Icon from mayan.apps.appearance.classes import Icon
from mayan.apps.documents.icons import icon_document_type from mayan.apps.documents.icons import icon_document_type
icon_workflow = Icon(driver_name='fontawesome', symbol='sitemap')
icon_document_type_workflow_list = icon_workflow
icon_document_workflow_instance_list = Icon( icon_document_workflow_instance_list = Icon(
driver_name='fontawesome', symbol='sitemap' driver_name='fontawesome', symbol='sitemap'
) )

View File

@@ -2,6 +2,7 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from mayan.apps.documents.permissions import permission_document_type_edit
from mayan.apps.navigation.classes import Link from mayan.apps.navigation.classes import Link
from .permissions import ( from .permissions import (
@@ -10,6 +11,12 @@ from .permissions import (
permission_workflow_view, permission_workflow_view,
) )
link_setup_document_type_workflows = Link(
args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_document_type_workflow_list',
permissions=(permission_document_type_edit,), text=_('Workflows'),
view='document_states:document_type_workflows',
)
link_setup_workflow_create = Link( link_setup_workflow_create = Link(
icon_class_path='mayan.apps.document_states.icons.icon_workflow_create', icon_class_path='mayan.apps.document_states.icons.icon_workflow_create',
permissions=(permission_workflow_create,), permissions=(permission_workflow_create,),
@@ -67,17 +74,21 @@ link_setup_workflow_state_action_selection = Link(
) )
link_setup_workflow_state_create = Link( link_setup_workflow_state_create = Link(
args='resolved_object.pk', args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_state', icon_class_path='mayan.apps.document_states.icons.icon_workflow_state_create',
permissions=(permission_workflow_edit,), text=_('Create state'), permissions=(permission_workflow_edit,), text=_('Create state'),
view='document_states:setup_workflow_state_create', view='document_states:setup_workflow_state_create',
) )
link_setup_workflow_state_delete = Link( link_setup_workflow_state_delete = Link(
args='object.pk', permissions=(permission_workflow_edit,), args='object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_state_delete',
permissions=(permission_workflow_edit,),
tags='dangerous', text=_('Delete'), tags='dangerous', text=_('Delete'),
view='document_states:setup_workflow_state_delete', view='document_states:setup_workflow_state_delete',
) )
link_setup_workflow_state_edit = Link( link_setup_workflow_state_edit = Link(
args='resolved_object.pk', permissions=(permission_workflow_edit,), args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_state_edit',
permissions=(permission_workflow_edit,),
text=_('Edit'), view='document_states:setup_workflow_state_edit', text=_('Edit'), view='document_states:setup_workflow_state_edit',
) )
link_setup_workflow_states = Link( link_setup_workflow_states = Link(
@@ -88,17 +99,21 @@ link_setup_workflow_states = Link(
) )
link_setup_workflow_transition_create = Link( link_setup_workflow_transition_create = Link(
args='resolved_object.pk', args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition', icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition_create',
permissions=(permission_workflow_edit,), text=_('Create transition'), permissions=(permission_workflow_edit,), text=_('Create transition'),
view='document_states:setup_workflow_transition_create', view='document_states:setup_workflow_transition_create',
) )
link_setup_workflow_transition_delete = Link( link_setup_workflow_transition_delete = Link(
args='resolved_object.pk', permissions=(permission_workflow_edit,), args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition_delete',
permissions=(permission_workflow_edit,),
tags='dangerous', text=_('Delete'), tags='dangerous', text=_('Delete'),
view='document_states:setup_workflow_transition_delete', view='document_states:setup_workflow_transition_delete',
) )
link_setup_workflow_transition_edit = Link( link_setup_workflow_transition_edit = Link(
args='resolved_object.pk', permissions=(permission_workflow_edit,), args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition_edit',
permissions=(permission_workflow_edit,),
text=_('Edit'), view='document_states:setup_workflow_transition_edit', text=_('Edit'), view='document_states:setup_workflow_transition_edit',
) )
link_setup_workflow_transitions = Link( link_setup_workflow_transitions = Link(
@@ -108,7 +123,9 @@ link_setup_workflow_transitions = Link(
view='document_states:setup_workflow_transition_list', view='document_states:setup_workflow_transition_list',
) )
link_workflow_transition_events = Link( link_workflow_transition_events = Link(
args='resolved_object.pk', permissions=(permission_workflow_edit,), args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition_triggers',
permissions=(permission_workflow_edit,),
text=_('Transition triggers'), text=_('Transition triggers'),
view='document_states:setup_workflow_transition_events' view='document_states:setup_workflow_transition_events'
) )

View File

@@ -71,6 +71,7 @@ class Workflow(models.Model):
return self.states.get(initial=True) return self.states.get(initial=True)
except self.states.model.DoesNotExist: except self.states.model.DoesNotExist:
return None return None
get_initial_state.short_description = _('Initial state')
def launch_for(self, document): def launch_for(self, document):
try: try:

View File

@@ -25,6 +25,15 @@ from .views import (
WorkflowImageView, WorkflowInstanceTransitionView, WorkflowListView, WorkflowImageView, WorkflowInstanceTransitionView, WorkflowListView,
WorkflowPreviewView, WorkflowStateDocumentListView, WorkflowStateListView, WorkflowPreviewView, WorkflowStateDocumentListView, WorkflowStateListView,
) )
from .views.workflow_views import SetupDocumentTypeWorkflowsView
urlpatterns_workflows = [
url(
regex=r'^document_type/(?P<pk>\d+)/workflows/$',
view=SetupDocumentTypeWorkflowsView.as_view(),
name='document_type_workflows'
),
]
urlpatterns = [ urlpatterns = [
url( url(
@@ -174,6 +183,7 @@ urlpatterns = [
name='workflow_state_document_list' name='workflow_state_document_list'
), ),
] ]
urlpatterns.extend(urlpatterns_workflows)
api_urls = [ api_urls = [
url( url(

View File

@@ -131,8 +131,8 @@ class WorkflowStateListView(SingleObjectListView):
def get_extra_context(self): def get_extra_context(self):
return { return {
'hide_columns': True,
'hide_link': True, 'hide_link': True,
'hide_object': True,
'no_results_main_link': link_setup_workflow_state_create.resolve( 'no_results_main_link': link_setup_workflow_state_create.resolve(
context=RequestContext( context=RequestContext(
request=self.request, dict_={'object': self.get_workflow()} request=self.request, dict_={'object': self.get_workflow()}

View File

@@ -64,6 +64,60 @@ __all__ = (
) )
class SetupDocumentTypeWorkflowsView(AddRemoveView):
main_object_permission = permission_document_type_edit
main_object_model = DocumentType
main_object_pk_url_kwarg = 'pk'
secondary_object_model = Workflow
secondary_object_permission = permission_workflow_edit
list_available_title = _('Available workflows')
list_added_title = _('Workflows assigned this document type')
related_field = 'workflows'
def get_actions_extra_kwargs(self):
return {'_user': self.request.user}
def get_extra_context(self):
return {
'object': self.main_object,
'subtitle': _(
'Removing a workflow from a document type will also '
'remove all running instances of that workflow.'
),
'title': _(
'Workflows assigned the document type: %s'
) % self.main_object,
}
def action_add(self, queryset, _user):
with transaction.atomic():
event_document_type_edited.commit(
actor=_user, target=self.main_object
)
for obj in queryset:
self.main_object.workflows.add(obj)
event_workflow_edited.commit(
action_object=self.main_object, actor=_user, target=obj
)
def action_remove(self, queryset, _user):
with transaction.atomic():
event_document_type_edited.commit(
actor=_user, target=self.main_object
)
for obj in queryset:
self.main_object.workflows.remove(obj)
event_workflow_edited.commit(
action_object=self.main_object, actor=_user,
target=obj
)
obj.instances.filter(
document__document_type=self.main_object
).delete()
class SetupWorkflowListView(SingleObjectListView): class SetupWorkflowListView(SingleObjectListView):
model = Workflow model = Workflow
object_permission = permission_workflow_view object_permission = permission_workflow_view
@@ -449,6 +503,7 @@ class SetupWorkflowStateListView(SingleObjectListView):
def get_extra_context(self): def get_extra_context(self):
return { return {
'hide_link': True, 'hide_link': True,
'hide_object': True,
'no_results_icon': icon_workflow_state, 'no_results_icon': icon_workflow_state,
'no_results_main_link': link_setup_workflow_state_create.resolve( 'no_results_main_link': link_setup_workflow_state_create.resolve(
context=RequestContext( context=RequestContext(
@@ -577,6 +632,7 @@ class SetupWorkflowTransitionListView(SingleObjectListView):
def get_extra_context(self): def get_extra_context(self):
return { return {
'hide_link': True, 'hide_link': True,
'hide_object': True,
'no_results_icon': icon_workflow_transition, 'no_results_icon': icon_workflow_transition,
'no_results_main_link': link_setup_workflow_transition_create.resolve( 'no_results_main_link': link_setup_workflow_transition_create.resolve(
context=RequestContext( context=RequestContext(