Proof of concept of the workflow instance context

Add support for workflow instance JSON context.
Add support for two step workflow transition.
Add support for dynamic form creation for transition execution.

Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2019-06-30 09:51:22 -04:00
parent 42db8255d1
commit e1a63064dc
9 changed files with 499 additions and 97 deletions

View File

@@ -40,6 +40,10 @@ from .links import (
link_setup_workflow_state_edit, link_setup_workflow_transitions,
link_setup_workflow_transition_create,
link_setup_workflow_transition_delete, link_setup_workflow_transition_edit,
link_setup_workflow_transition_field_create,
link_setup_workflow_transition_field_delete,
link_setup_workflow_transition_field_edit,
link_setup_workflow_transition_field_list,
link_tool_launch_all_workflows, link_workflow_instance_detail,
link_workflow_instance_transition, link_workflow_runtime_proxy_document_list,
link_workflow_runtime_proxy_list, link_workflow_preview,
@@ -86,6 +90,7 @@ class DocumentStatesApp(MayanAppConfig):
WorkflowStateAction = self.get_model('WorkflowStateAction')
WorkflowStateRuntimeProxy = self.get_model('WorkflowStateRuntimeProxy')
WorkflowTransition = self.get_model('WorkflowTransition')
WorkflowTransitionField = self.get_model('WorkflowTransitionField')
WorkflowTransitionTriggerEvent = self.get_model(
'WorkflowTransitionTriggerEvent'
)
@@ -257,6 +262,18 @@ class DocumentStatesApp(MayanAppConfig):
)
)
SourceColumn(
attribute='name', is_identifier=True, is_sortable=True,
source=WorkflowTransitionField
)
SourceColumn(
attribute='label', is_sortable=True, source=WorkflowTransitionField
)
SourceColumn(
attribute='required', is_sortable=True, source=WorkflowTransitionField,
widget=TwoStateWidget
)
SourceColumn(
source=WorkflowRuntimeProxy, label=_('Documents'),
func=lambda context: context['object'].get_document_count(
@@ -305,10 +322,18 @@ class DocumentStatesApp(MayanAppConfig):
menu_object.bind_links(
links=(
link_setup_workflow_transition_edit,
link_workflow_transition_events, link_acl_list,
link_workflow_transition_events,
link_setup_workflow_transition_field_list,
link_acl_list,
link_setup_workflow_transition_delete
), sources=(WorkflowTransition,)
)
menu_object.bind_links(
links=(
link_setup_workflow_transition_field_delete,
link_setup_workflow_transition_field_edit
), sources=(WorkflowTransitionField,)
)
menu_object.bind_links(
links=(
link_workflow_instance_detail,
@@ -342,6 +367,12 @@ class DocumentStatesApp(MayanAppConfig):
'document_states:setup_workflow_list'
)
)
menu_secondary.bind_links(
links=(link_setup_workflow_transition_field_create,),
sources=(
WorkflowTransition,
)
)
menu_secondary.bind_links(
links=(link_workflow_runtime_proxy_list,),
sources=(

View File

@@ -165,11 +165,11 @@ WorkflowTransitionTriggerEventRelationshipFormSet = formset_factory(
)
class WorkflowInstanceTransitionForm(forms.Form):
class WorkflowInstanceTransitionSelectForm(forms.Form):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
workflow_instance = kwargs.pop('workflow_instance')
super(WorkflowInstanceTransitionForm, self).__init__(*args, **kwargs)
super(WorkflowInstanceTransitionSelectForm, self).__init__(*args, **kwargs)
self.fields[
'transition'
].queryset = workflow_instance.get_transition_choices(_user=user)
@@ -177,14 +177,6 @@ class WorkflowInstanceTransitionForm(forms.Form):
transition = forms.ModelChoiceField(
label=_('Transition'), queryset=WorkflowTransition.objects.none()
)
comment = forms.CharField(
help_text=_('Optional comment to attach to the transition.'),
label=_('Comment'), required=False, widget=forms.widgets.Textarea(
attrs={
'rows': 3
}
)
)
class WorkflowPreviewForm(forms.Form):

View File

@@ -76,6 +76,16 @@ icon_workflow_transition_delete = Icon(driver_name='fontawesome', symbol='times'
icon_workflow_transition_edit = Icon(
driver_name='fontawesome', symbol='pencil-alt'
)
icon_workflow_transition_field = Icon(driver_name='fontawesome', symbol='code')
icon_workflow_transition_field_delete = Icon(driver_name='fontawesome', symbol='times')
icon_workflow_transition_field_edit = Icon(driver_name='fontawesome', symbol='pencil-alt')
icon_workflow_transition_field_create = Icon(
driver_name='fontawesome-dual', primary_symbol='code',
secondary_symbol='plus'
)
icon_workflow_transition_field_list = Icon(driver_name='fontawesome', symbol='code')
icon_workflow_transition_triggers = Icon(
driver_name='fontawesome', symbol='bolt'
)

View File

@@ -129,6 +129,35 @@ link_workflow_transition_events = Link(
text=_('Transition triggers'),
view='document_states:setup_workflow_transition_events'
)
# Workflow transition fields
link_setup_workflow_transition_field_create = Link(
args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition_field',
permissions=(permission_workflow_edit,), text=_('Create field'),
view='document_states:setup_workflow_transition_field_create',
)
link_setup_workflow_transition_field_delete = Link(
args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition_field_delete',
permissions=(permission_workflow_edit,),
tags='dangerous', text=_('Delete'),
view='document_states:setup_workflow_transition_field_delete',
)
link_setup_workflow_transition_field_edit = Link(
args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition_field_edit',
permissions=(permission_workflow_edit,),
text=_('Edit'), view='document_states:setup_workflow_transition_field_edit',
)
link_setup_workflow_transition_field_list = Link(
args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_transition_field_list',
permissions=(permission_workflow_edit,),
text=_('Fields'),
view='document_states:setup_workflow_transition_field_list',
)
link_workflow_preview = Link(
args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_preview',
@@ -159,7 +188,7 @@ link_workflow_instance_transition = Link(
args='resolved_object.pk',
icon_class_path='mayan.apps.document_states.icons.icon_workflow_instance_transition',
text=_('Transition'),
view='document_states:workflow_instance_transition',
view='document_states:workflow_instance_transition_selection',
)
# Runtime proxies

View File

@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-06-30 13:31
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('document_states', '0013_auto_20190423_0810'),
]
operations = [
migrations.CreateModel(
name='WorkflowTransitionField',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, verbose_name='Internal name')),
('label', models.CharField(max_length=128, verbose_name='Label')),
('help_text', models.TextField(blank=True, verbose_name='Help text')),
('required', models.BooleanField(default=False, verbose_name='Required')),
('transition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fields', to='document_states.WorkflowTransition', verbose_name='Transition')),
],
options={
'verbose_name': 'Workflow transition trigger event',
'verbose_name_plural': 'Workflow transitions trigger events',
},
),
migrations.AddField(
model_name='workflowinstance',
name='context',
field=models.TextField(blank=True, verbose_name='Backend data'),
),
migrations.AlterUniqueTogether(
name='workflowtransitionfield',
unique_together=set([('transition', 'name')]),
),
]

View File

@@ -257,8 +257,8 @@ class WorkflowState(models.Model):
def save(self, *args, **kwargs):
# Solve issue #557 "Break workflows with invalid input"
# without using a migration.
# Remove blank=True, remove this, and create a migration in the next
# minor version.
# TODO: Remove blank=True, remove this, and create a migration in the
# next minor version.
try:
self.completion = int(self.completion)
@@ -363,6 +363,44 @@ class WorkflowTransition(models.Model):
return self.label
@python_2_unicode_compatible
class WorkflowTransitionField(models.Model):
transition = models.ForeignKey(
on_delete=models.CASCADE, related_name='fields',
to=WorkflowTransition, verbose_name=_('Transition')
)
name = models.CharField(
help_text=_(
'The name that will be used to identify this field in other parts '
'of the workflow system.'
), max_length=128, verbose_name=_('Internal name')
)
label = models.CharField(
help_text=_(
'The field name that will be shown on the user interface.'
), max_length=128, verbose_name=_('Label'))
help_text = models.TextField(
blank=True, help_text=_(
'An optional message that will help users better understand the '
'purpose of the field and data to provide.'
), verbose_name=_('Help text')
)
required = models.BooleanField(
default=False, help_text=_(
'Whether this fields needs to be filled out or not to proceed.'
), verbose_name=_('Required')
)
#TODO: widget, widget kwargs
class Meta:
unique_together = ('transition', 'name')
verbose_name = _('Workflow transition trigger event')
verbose_name_plural = _('Workflow transitions trigger events')
def __str__(self):
return self.label
@python_2_unicode_compatible
class WorkflowTransitionTriggerEvent(models.Model):
transition = models.ForeignKey(
@@ -392,6 +430,9 @@ class WorkflowInstance(models.Model):
on_delete=models.CASCADE, related_name='workflows', to=Document,
verbose_name=_('Document')
)
context = models.TextField(
blank=True, verbose_name=_('Backend data')
)
class Meta:
ordering = ('workflow',)
@@ -402,15 +443,30 @@ class WorkflowInstance(models.Model):
def __str__(self):
return force_text(self.workflow)
def do_transition(self, transition, user=None, comment=None):
try:
if transition in self.get_current_state().origin_transitions.all():
self.log_entries.create(
comment=comment or '', transition=transition, user=user
)
except AttributeError:
# No initial state has been set for this workflow
pass
def do_transition(self, transition, extra_data=None, user=None, comment=None):
with transaction.atomic():
try:
if transition in self.get_current_state().origin_transitions.all():
self.log_entries.create(
comment=comment or '', transition=transition, user=user
)
if extra_data:
data = self.loads()
data.update(extra_data)
self.dumps(data=data)
except AttributeError:
# No initial state has been set for this workflow
pass
# TODO: execute transition event target = document,
# action_object = self
def dumps(self, data):
"""
Serialize the context data.
"""
self.context = json.dumps(data)
self.save()
def get_absolute_url(self):
return reverse(
@@ -420,10 +476,12 @@ class WorkflowInstance(models.Model):
)
def get_context(self):
return {
context = {
'document': self.document, 'workflow': self.workflow,
'workflow_instance': self,
}
context['workflow_instance_context'] = self.loads()
return context
def get_current_state(self):
"""
@@ -489,6 +547,12 @@ class WorkflowInstance(models.Model):
"""
return WorkflowTransition.objects.none()
def loads(self):
"""
Deserialize the context data.
"""
return json.loads(self.context or '{}')
@python_2_unicode_compatible
class WorkflowInstanceLogEntry(models.Model):
@@ -529,31 +593,32 @@ class WorkflowInstanceLogEntry(models.Model):
raise ValidationError(_('Not a valid transition choice.'))
def save(self, *args, **kwargs):
result = super(WorkflowInstanceLogEntry, self).save(*args, **kwargs)
context = self.workflow_instance.get_context()
context.update(
{
'entry_log': self
}
)
for action in self.transition.origin_state.exit_actions.filter(enabled=True):
with transaction.atomic():
result = super(WorkflowInstanceLogEntry, self).save(*args, **kwargs)
context = self.workflow_instance.get_context()
context.update(
{
'action': action,
'entry_log': self
}
)
action.execute(context=context)
for action in self.transition.destination_state.entry_actions.filter(enabled=True):
context.update(
{
'action': action,
}
)
action.execute(context=context)
for action in self.transition.origin_state.exit_actions.filter(enabled=True):
context.update(
{
'action': action,
}
)
action.execute(context=context)
return result
for action in self.transition.destination_state.entry_actions.filter(enabled=True):
context.update(
{
'action': action,
}
)
action.execute(context=context)
return result
class WorkflowRuntimeProxy(Workflow):

View File

@@ -22,19 +22,86 @@ from .views import (
SetupWorkflowTransitionEditView,
SetupWorkflowTransitionTriggerEventListView, ToolLaunchAllWorkflows,
WorkflowDocumentListView, WorkflowInstanceDetailView,
WorkflowImageView, WorkflowInstanceTransitionView, WorkflowListView,
WorkflowImageView, WorkflowInstanceTransitionExecuteView,
WorkflowInstanceTransitionSelectView, WorkflowListView,
WorkflowPreviewView, WorkflowStateDocumentListView, WorkflowStateListView,
)
from .views.workflow_views import SetupDocumentTypeWorkflowsView
from .views.workflow_views import (
SetupDocumentTypeWorkflowsView, SetupWorkflowTransitionFieldCreateView,
SetupWorkflowTransitionFieldDeleteView,
SetupWorkflowTransitionFieldEditView, SetupWorkflowTransitionFieldListView
)
urlpatterns_workflows = [
url(
regex=r'^document_type/(?P<pk>\d+)/workflows/$',
regex=r'^setup/workflows/$', view=SetupWorkflowListView.as_view(),
name='setup_workflow_list'
),
url(
regex=r'^setup/workflows/create/$', view=SetupWorkflowCreateView.as_view(),
name='setup_workflow_create'
),
url(
regex=r'^setup/workflows/(?P<pk>\d+)/delete/$',
view=SetupWorkflowDeleteView.as_view(), name='setup_workflow_delete'
),
url(
regex=r'^setup/workflows/(?P<pk>\d+)/edit/$',
view=SetupWorkflowEditView.as_view(), name='setup_workflow_edit'
),
url(
regex=r'^setup/document_types/(?P<pk>\d+)/workflows/$',
view=SetupDocumentTypeWorkflowsView.as_view(),
name='document_type_workflows'
),
]
urlpatterns_workflow_states = [
url(
regex=r'^setup/workflow/(?P<pk>\d+)/states/$',
view=SetupWorkflowStateListView.as_view(),
name='setup_workflow_state_list'
),
url(
regex=r'^setup/workflow/(?P<pk>\d+)/states/create/$',
view=SetupWorkflowStateCreateView.as_view(),
name='setup_workflow_state_create'
),
url(
regex=r'^setup/workflow/state/(?P<pk>\d+)/delete/$',
view=SetupWorkflowStateDeleteView.as_view(),
name='setup_workflow_state_delete'
),
url(
regex=r'^setup/workflow/state/(?P<pk>\d+)/edit/$',
view=SetupWorkflowStateEditView.as_view(),
name='setup_workflow_state_edit'
),
]
urlpatterns_workflow_transition_fields = [
url(
regex=r'^setup/workflows/transitions/(?P<pk>\d+)/fields/create/$',
view=SetupWorkflowTransitionFieldCreateView.as_view(),
name='setup_workflow_transition_field_create'
),
url(
regex=r'^setup/workflows/transitions/(?P<pk>\d+)/fields/$',
view=SetupWorkflowTransitionFieldListView.as_view(),
name='setup_workflow_transition_field_list'
),
url(
regex=r'^setup/workflows/transitions/fields/(?P<pk>\d+)/delete/$',
view=SetupWorkflowTransitionFieldDeleteView.as_view(),
name='setup_workflow_transition_field_delete'
),
url(
regex=r'^setup/workflows/transitions/fields/(?P<pk>\d+)/edit/$',
view=SetupWorkflowTransitionFieldEditView.as_view(),
name='setup_workflow_transition_field_edit'
),
]
urlpatterns = [
url(
regex=r'^document/(?P<pk>\d+)/workflows/$',
@@ -47,25 +114,14 @@ urlpatterns = [
name='workflow_instance_detail'
),
url(
regex=r'^document/workflows/(?P<pk>\d+)/transition/$',
view=WorkflowInstanceTransitionView.as_view(),
name='workflow_instance_transition'
regex=r'^document/workflows/(?P<pk>\d+)/transitions/select/$',
view=WorkflowInstanceTransitionSelectView.as_view(),
name='workflow_instance_transition_selection'
),
url(
regex=r'^setup/all/$', view=SetupWorkflowListView.as_view(),
name='setup_workflow_list'
),
url(
regex=r'^setup/create/$', view=SetupWorkflowCreateView.as_view(),
name='setup_workflow_create'
),
url(
regex=r'^setup/workflow/(?P<pk>\d+)/edit/$',
view=SetupWorkflowEditView.as_view(), name='setup_workflow_edit'
),
url(
regex=r'^setup/workflow/(?P<pk>\d+)/delete/$',
view=SetupWorkflowDeleteView.as_view(), name='setup_workflow_delete'
regex=r'^document/workflows/(?P<workflow_instance_pk>\d+)/transitions/(?P<workflow_transition_pk>\d+)/execute/$',
view=WorkflowInstanceTransitionExecuteView.as_view(),
name='workflow_instance_transition_execute'
),
url(
regex=r'^setup/workflow/(?P<pk>\d+)/documents/$',
@@ -77,16 +133,6 @@ urlpatterns = [
view=SetupWorkflowDocumentTypesView.as_view(),
name='setup_workflow_document_types'
),
url(
regex=r'^setup/workflow/(?P<pk>\d+)/states/$',
view=SetupWorkflowStateListView.as_view(),
name='setup_workflow_state_list'
),
url(
regex=r'^setup/workflow/(?P<pk>\d+)/states/create/$',
view=SetupWorkflowStateCreateView.as_view(),
name='setup_workflow_state_create'
),
url(
regex=r'^setup/workflow/(?P<pk>\d+)/transitions/$',
view=SetupWorkflowTransitionListView.as_view(),
@@ -98,20 +144,10 @@ urlpatterns = [
name='setup_workflow_transition_create'
),
url(
regex=r'^setup/workflow/(?P<pk>\d+)/transitions/events/$',
regex=r'^setup/workflow/transitions/(?P<pk>\d+)/events/$',
view=SetupWorkflowTransitionTriggerEventListView.as_view(),
name='setup_workflow_transition_events'
),
url(
regex=r'^setup/workflow/state/(?P<pk>\d+)/delete/$',
view=SetupWorkflowStateDeleteView.as_view(),
name='setup_workflow_state_delete'
),
url(
regex=r'^setup/workflow/state/(?P<pk>\d+)/edit/$',
view=SetupWorkflowStateEditView.as_view(),
name='setup_workflow_state_edit'
),
url(
regex=r'^setup/workflow/state/(?P<pk>\d+)/actions/$',
view=SetupWorkflowStateActionListView.as_view(),
@@ -184,6 +220,8 @@ urlpatterns = [
),
]
urlpatterns.extend(urlpatterns_workflows)
urlpatterns.extend(urlpatterns_workflow_states)
urlpatterns.extend(urlpatterns_workflow_transition_fields)
api_urls = [
url(

View File

@@ -4,13 +4,16 @@ from django.contrib import messages
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.translation import ugettext_lazy as _
from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.forms import DynamicForm
from mayan.apps.common.generics import FormView, SingleObjectListView
from mayan.apps.common.mixins import ExternalObjectMixin
from mayan.apps.documents.models import Document
from ..forms import WorkflowInstanceTransitionForm
from ..forms import WorkflowInstanceTransitionSelectForm
from ..icons import icon_workflow_instance_detail, icon_workflow_list
from ..links import link_workflow_instance_transition
from ..models import WorkflowInstance
@@ -18,7 +21,8 @@ from ..permissions import permission_workflow_view
__all__ = (
'DocumentWorkflowInstanceListView', 'WorkflowInstanceDetailView',
'WorkflowInstanceTransitionView'
'WorkflowInstanceTransitionSelectView',
'WorkflowInstanceTransitionExecuteView'
)
@@ -100,14 +104,17 @@ class WorkflowInstanceDetailView(SingleObjectListView):
return get_object_or_404(klass=WorkflowInstance, pk=self.kwargs['pk'])
class WorkflowInstanceTransitionView(FormView):
form_class = WorkflowInstanceTransitionForm
class WorkflowInstanceTransitionExecuteView(FormView):
form_class = DynamicForm
template_name = 'appearance/generic_form.html'
def form_valid(self, form):
form_data = form.cleaned_data
comment = form_data.pop('comment')
self.get_workflow_instance().do_transition(
comment=form.cleaned_data['comment'],
transition=form.cleaned_data['transition'], user=self.request.user
comment=comment, extra_data=form_data,
transition=self.get_workflow_transition(), user=self.request.user,
)
messages.success(
self.request, _(
@@ -122,19 +129,96 @@ class WorkflowInstanceTransitionView(FormView):
'object': self.get_workflow_instance().document,
'submit_label': _('Submit'),
'title': _(
'Do transition for workflow: %s'
) % self.get_workflow_instance(),
'Execute transition "%(transition)s" for workflow: %(workflow)s'
) % {
'transition': self.get_workflow_transition(),
'workflow': self.get_workflow_instance(),
},
'workflow_instance': self.get_workflow_instance(),
}
def get_form_extra_kwargs(self):
return {
'user': self.request.user,
'workflow_instance': self.get_workflow_instance()
schema = {
'fields': {
'comment': {
'label': _('Comment'),
'class': 'django.forms.CharField', 'kwargs': {
'help_text': _(
'Optional comment to attach to the transition.'
),
'required': False,
}
}
},
'widgets': {
'comment': {
'class': 'django.forms.widgets.Textarea',
'kwargs': {
'attrs': {
'rows': 3
}
}
}
}
}
for field in self.get_workflow_transition().fields.all():
schema['fields'][field.name] = {
'label': field.label,
'class': 'django.forms.CharField', 'kwargs': {
}
}
return {'schema': schema}
def get_success_url(self):
return self.get_workflow_instance().get_absolute_url()
def get_workflow_instance(self):
return get_object_or_404(klass=WorkflowInstance, pk=self.kwargs['pk'])
return get_object_or_404(
klass=WorkflowInstance, pk=self.kwargs['workflow_instance_pk']
)
def get_workflow_transition(self):
return get_object_or_404(
klass=self.get_workflow_instance().get_transition_choices(
_user=self.request.user
), pk=self.kwargs['workflow_transition_pk']
)
class WorkflowInstanceTransitionSelectView(ExternalObjectMixin, FormView):
external_object_class = WorkflowInstance
form_class = WorkflowInstanceTransitionSelectForm
template_name = 'appearance/generic_form.html'
def form_valid(self, form):
return HttpResponseRedirect(
redirect_to=reverse(
viewname='document_states:workflow_instance_transition_execute',
kwargs={
'workflow_instance_pk': self.external_object.pk,
'workflow_transition_pk': form.cleaned_data['transition'].pk
}
)
)
def get_extra_context(self):
return {
'navigation_object_list': ('object', 'workflow_instance'),
'object': self.external_object.document,
'submit_label': _('Select'),
'title': _(
'Select transition for workflow: %s'
) % self.external_object,
'workflow_instance': self.external_object,
}
def get_form_extra_kwargs(self):
return {
'user': self.request.user,
'workflow_instance': self.external_object
}
#def get_workflow_instance(self):
# return get_object_or_404(klass=WorkflowInstance, pk=self.kwargs['pk'])

View File

@@ -39,7 +39,8 @@ from ..links import (
link_setup_workflow_transition_create
)
from ..models import (
Workflow, WorkflowState, WorkflowStateAction, WorkflowTransition
Workflow, WorkflowState, WorkflowStateAction, WorkflowTransition,
WorkflowTransitionField
)
from ..permissions import (
permission_workflow_create, permission_workflow_delete,
@@ -732,6 +733,118 @@ class SetupWorkflowTransitionTriggerEventListView(ExternalObjectMixin, FormView)
)
# Transition fields
class SetupWorkflowTransitionFieldCreateView(ExternalObjectMixin, SingleObjectCreateView):
external_object_class = WorkflowTransition
external_object_permission = permission_workflow_edit
fields = ('name', 'label', 'help_text', 'required')
#object_permission = permission_workflow_edit
def get_extra_context(self):
return {
'navigation_object_list': ('transition', 'workflow'),
'transition': self.external_object,
'title': _(
'Create a field for workflow transition: %s'
) % self.external_object,
'workflow': self.external_object.workflow
}
def get_instance_extra_data(self):
return {
'transition': self.external_object,
}
def get_queryset(self):
return self.external_object.fields.all()
def get_post_action_redirect(self):
return reverse(
viewname='document_states:setup_workflow_transition_field_list',
kwargs={'pk': self.external_object.pk}
)
class SetupWorkflowTransitionFieldDeleteView(SingleObjectDeleteView):
model = WorkflowTransitionField
object_permission = permission_workflow_edit
def get_extra_context(self):
return {
'navigation_object_list': (
'object', 'workflow_transition', 'workflow'
),
'object': self.object,
'title': _('Delete workflow transition field: %s') % self.object,
'workflow': self.object.transition.workflow,
'workflow_transition': self.object.transition,
}
def get_post_action_redirect(self):
return reverse(
viewname='document_states:setup_workflow_transition_field_list',
kwargs={'pk': self.object.transition.pk}
)
class SetupWorkflowTransitionFieldEditView(SingleObjectEditView):
fields = ('name', 'label', 'help_text', 'required',)
model = WorkflowTransitionField
object_permission = permission_workflow_edit
def get_extra_context(self):
return {
'navigation_object_list': (
'object', 'workflow_transition', 'workflow'
),
'object': self.object,
'title': _('Edit workflow transition field: %s') % self.object,
'workflow': self.object.transition.workflow,
'workflow_transition': self.object.transition,
}
def get_post_action_redirect(self):
return reverse(
viewname='document_states:setup_workflow_transition_field_list',
kwargs={'pk': self.object.transition.pk}
)
class SetupWorkflowTransitionFieldListView(ExternalObjectMixin, SingleObjectListView):
external_object_class = WorkflowTransition
external_object_permission = permission_workflow_edit
def get_extra_context(self):
return {
'hide_object': True,
'navigation_object_list': ('object', 'workflow'),
#'no_results_icon': icon_workflow_transition_action,
#'no_results_main_link': link_setup_workflow_transition_action_selection.resolve(
# context=RequestContext(
# request=self.request, dict_={
# 'object': self.get_workflow_transition()
# }
# )
#),
#'no_results_text': _(
# 'Workflow state actions are macros that get executed when '
# 'documents enters or leaves the state in which they reside.'
#),
#'no_results_title': _(
# 'There are no actions for this workflow state'
#),
'object': self.external_object,
'title': _(
'Fields for workflow transition: %s'
) % self.external_object,
'workflow': self.external_object.workflow,
}
def get_source_queryset(self):
return self.external_object.fields.all()
class ToolLaunchAllWorkflows(ConfirmView):
extra_context = {
'title': _('Launch all workflows?'),