Commit 4a1af9c8 authored by Jérome Perrin's avatar Jérome Perrin

Rework 'mass workflow transition'

In the first dialog you still select which action to do on which objects, now
you can only select one action. The second dialog is the actual dialog from the
workflow rendered on the context of one document from documents grouped by
state and portal type. This means that if the workflow uses a custom dialog to
set workflow variables, this dialog will be shown and the variables will be
passed to all documents.
Of course some workflows dialog fields have no meaning in a multi-document
transition, that's why there is a mass_workflow_action=True request parameter
to detect this situation and behave accordingly in such case.
parent 9b292489
......@@ -267,9 +267,11 @@ if (not(can_redirect) or len(url_params_string) > 2000):\n
if deferred_portal_skin:\n
request.set(\'deferred_portal_skin\', deferred_portal_skin)\n
# and to cleanup formulator\'s special key in request\n
for key in list(request.keys()):\n
if key.startswith(\'field\') or key.startswith(\'subfield\'):\n
request.form.pop(key, None)\n
# XXX unless we are in Folder_modifyWorkflowStatus which validates again !\n
if dialog_method != \'Folder_modifyWorkflowStatus\':\n
  • Maybe if you have to modify general-purpose script just to support your action ... maybe there is a better way of doing it

  • This "exception" was made because "which form to use in validation" is dynamically selected.

    I have not tried too hard to make this use Base_callDialogMethod like other standard actions because it's a general-purpose action applying to all modules.

Please register or sign in to reply
for key in list(request.keys()):\n
if key.startswith(\'field\') or key.startswith(\'subfield\'):\n
request.form.pop(key, None)\n
\n
# If we cannot redirect, then call the form directly.\n
dialog_form = getattr(context, dialog_method)\n
......
......@@ -57,8 +57,9 @@ for action in context.portal_actions.listFilteredActionsFor(brain).get(\'workflo
if transition is not None:\n
workflow_id = action[\'transition\'].aq_parent.aq_parent.getId()\n
if workflow_id == brain.workflow_id:\n
dialog_id = action[\'url\'].split(\'?\', 1)[0].split(\'/\')[-1]\n
item_list.append((Base_translateString(action[\'title\']),\n
\'%s/%s\' % (workflow_id, action[\'id\'])))\n
\'%s/%s/%s\' % (workflow_id, action[\'id\'], dialog_id)))\n
\n
return item_list\n
</string> </value>
......
......@@ -50,27 +50,22 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>selection_name = \'workflow_action_dialog_proxy_selection\'\n
selection_tool = context.getPortalObject().portal_selections\n
<value> <string>if len([choice for choice in editor.values() if choice[\'workflow_action\']]) == 1:\n
return True\n
\n
selection_tool.setSelectionParamsFor(selection_name,\n
dict(proxy_form_id=form_id))\n
\n
request = container.REQUEST\n
request.set(\'proxy_form_id\', form_id)\n
request.set(\'reset\', 1)\n
request.set(\'ignore_hide_rows\', 1)\n
\n
return context.Folder_viewWorkflowActionDocumentListDialogRenderer(REQUEST=request)\n
from Products.ERP5Type.Message import translateString\n
# XXX listbox validator does not show the validation failed message, so use portal status message instead\n
container.REQUEST.set(\'portal_status_message\', translateString("You must select one action."))\n
  • Why user can select multiple actions when it is actually forbidden? Why there is not-that-helpful message?

  • I don't see how we could prevent user from selecting multiple actions, but I might be missing your point.

    What's not possible is to select actions that use different dialog form for their workflow transitions. If we want to make this more user friendly, we could improve this by allowing users to execute together actions that would be using the same dialog.

Please register or sign in to reply
return False\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>form_id=\'\', **kw</string> </value>
<value> <string>editor, request</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Folder_viewWorkflowActionDocumentListDialog</string> </value>
<value> <string>Base_validateFolderWorkflowActionDialog</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -50,36 +50,90 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from Products.ERP5Type.Message import translateString\n
<value> <string>from Products.Formulator.Errors import FormValidationError\n
from Products.ERP5Type.Message import translateString\n
portal = context.getPortalObject()\n
request = context.REQUEST\n
\n
if listbox is None:\n
listbox = []\n
target_context = portal.restrictedTraverse(choosen_action[\'relative_url\'])\n
target_form = getattr(target_context, choosen_action[\'workflow_action\'].split(\'/\')[-1])\n
\n
request = context.REQUEST\n
portal = context.getPortalObject()\n
real_form = getattr(context, dialog_id)\n
\n
# Validate the forms\n
for form in (real_form, target_form):\n
try:\n
# It is necessary to force editable_mode before validating\n
# data. Otherwise, field appears as non editable.\n
# This is the pending of form_dialog.\n
editable_mode = request.get(\'editable_mode\', 1)\n
request.set(\'editable_mode\', 1)\n
form.validate_all_to_request(request)\n
request.set(\'editable_mode\', editable_mode)\n
except FormValidationError, validation_errors:\n
# Pack errors into the request\n
field_errors = form.ErrorFields(validation_errors)\n
request.set(\'field_errors\', field_errors)\n
return real_form(request)\n
\n
# XXX: this is a duplication from form validation code in Base_callDialogMethod\n
# Correct fix is to factorise this script with Base_callDialogMethod, not to\n
# fix XXXs here.\n
do_action_for_param_dict = {}\n
MARKER = []\n
for f in form.get_fields():\n
k = f.id\n
v = getattr(request, k, MARKER)\n
if v is not MARKER:\n
if k.startswith(\'your_\'):\n
k=k[5:]\n
elif k.startswith(\'my_\'): # compat\n
k=k[3:]\n
do_action_for_param_dict[k] = v\n
\n
listbox = request.get(\'listbox\') # XXX: hardcoded field name\n
if listbox is not None:\n
listbox_line_list = []\n
listbox = getattr(request,\'listbox\',None) # XXX: hardcoded field name\n
listbox_keys = listbox.keys()\n
listbox_keys.sort()\n
for key in listbox_keys:\n
listbox_line = listbox[key]\n
listbox_line[\'listbox_key\'] = key\n
listbox_line_list.append(listbox[key])\n
listbox_line_list = tuple(listbox_line_list)\n
do_action_for_param_dict[\'listbox\'] = listbox_line_list # XXX: hardcoded field name\n
\n
assert \'workflow_action\' in do_action_for_param_dict\n
\n
# generate a random tag\n
tag = \'folder_workflow_action_%s\' % random.randint(0, 1000)\n
\n
for parameters in listbox:\n
doc = portal.restrictedTraverse(parameters[\'listbox_key\'])\n
if same_type(parameters[\'workflow_action\'], \'\'):\n
doc.activate(tag=tag).Base_workflowStatusModify(batch=1,\n
workflow_action=parameters[\'workflow_action\'],\n
workflow_id=parameters[\'workflow_id\'],\n
comment=comment)\n
else:\n
for workflow_action, workflow_id in zip(\n
parameters[\'workflow_action\'], parameters[\'workflow_id\']):\n
doc.activate(activity=\'SQLQueue\', tag=tag).Base_workflowStatusModify(batch=1,\n
workflow_action=workflow_action,\n
workflow_id=workflow_id,\n
comment=comment)\n
# get the list of objects we are about to modify\n
selection_uid_list = portal.portal_selections.getSelectionCheckedUidsFor(selection_name)\n
selection_params = portal.portal_selections.getSelectionParamsFor(selection_name).copy()\n
selection_params[choosen_action[\'state_var\']] = choosen_action[\'workflow_state\']\n
selection_params[\'portal_type\'] = choosen_action[\'portal_type\']\n
if selection_uid_list:\n
selection_params[\'uid\'] = selection_uid_list\n
\n
path_list = [brain.path for brain in\n
portal.portal_selections.callSelectionFor(selection_name, params=selection_params)]\n
\n
batch_size = 100 # XXX\n
priority = 2 # XXX \n
path_list_len = len(path_list)\n
\n
for i in xrange(0, path_list_len, batch_size):\n
current_path_list = path_list[i:i+batch_size]\n
context.activate(activity=\'SQLQueue\', priority=priority, tag=tag).callMethodOnObjectList(\n
current_path_list, \'Base_workflowStatusModify\', batch_mode=True, **do_action_for_param_dict)\n
\n
# activate something on the module after everything, so that user can know that something is happening in the background\n
# activate something on the module after everything, so that user can know that\n
# something is happening in the background\n
context.activate(after_tag=tag).getTitle()\n
\n
# reset selection checked uids\n
# reset selection checked uids \n
context.portal_selections.setSelectionCheckedUidsFor(selection_name, [])\n
\n
return context.Base_redirect(form_id,\n
......@@ -88,7 +142,7 @@ return context.Base_redirect(form_id,\n
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>listbox=None, comment=\'\', form_id=\'view\', selection_name=\'\', **kw</string> </value>
<value> <string>form_id, dialog_id, selection_name, choosen_action, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -35,7 +35,7 @@
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Folder_viewWorkflowActionDocumentListDialog</string> </value>
<value> <string>Folder_viewWorkflowActionDialogSecondStep</string> </value>
</item>
<item>
<key> <string>description</string> </key>
......@@ -73,7 +73,7 @@
<key> <string>bottom</string> </key>
<value>
<list>
<string>listbox</string>
<string>workflow_action_listbox</string>
</list>
</value>
</item>
......@@ -81,10 +81,11 @@
<key> <string>hidden</string> </key>
<value>
<list>
<string>listbox_portal_type</string>
<string>listbox_state_var</string>
<string>listbox_workflow_action</string>
<string>listbox_workflow_state</string>
<string>workflow_action_listbox_portal_type</string>
<string>workflow_action_listbox_state_var</string>
<string>workflow_action_listbox_workflow_action</string>
<string>workflow_action_listbox_workflow_state</string>
<string>workflow_action_listbox_relative_url</string>
</list>
</value>
</item>
......@@ -92,8 +93,8 @@
<key> <string>left</string> </key>
<value>
<list>
<string>your_comment</string>
<string>your_module_selection_name</string>
<string>your_enable_detail_list</string>
</list>
</value>
</item>
......
......@@ -10,17 +10,18 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
<string>columns</string>
<string>editable_columns</string>
<string>external_validator</string>
<string>list_method</string>
<string>selection_name</string>
<string>editable_columns</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox</string> </value>
<value> <string>workflow_action_listbox</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......@@ -111,6 +112,10 @@
<string>workflow_state</string>
<string></string>
</tuple>
<tuple>
<string>relative_url</string>
<string></string>
</tuple>
</list>
</value>
</item>
......@@ -134,9 +139,19 @@
<string>workflow_action</string>
<string>Workflow Action</string>
</tuple>
<tuple>
<string>relative_url</string>
<string>relative_url</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox</string> </value>
......@@ -148,7 +163,7 @@
<item>
<key> <string>list_method</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
......@@ -170,6 +185,19 @@
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>method_name</string> </key>
<value> <string>Base_validateFolderWorkflowActionDialog</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="Method" module="Products.Formulator.MethodField"/>
</pickle>
......
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_portal_type</string> </value>
<value> <string>workflow_action_listbox_portal_type</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_state_var</string> </value>
<value> <string>workflow_action_listbox_state_var</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_workflow_action</string> </value>
<value> <string>workflow_action_listbox_workflow_action</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_workflow_state</string> </value>
<value> <string>workflow_action_listbox_workflow_state</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="CheckBoxField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>your_enable_detail_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Show Detailed List of Documents</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -53,17 +53,15 @@
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string>multipart/form-data</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
<string>bottom</string>
</list>
</value>
</item>
......@@ -76,16 +74,9 @@
<value>
<list>
<string>listbox</string>
<string>your_comment</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
......@@ -101,18 +92,12 @@
<list/>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Folder_viewWorkflowActionDocumentListDialogRenderer</string> </value>
<value> <string>Folder_viewWorkflowActionDialogSecondStep</string> </value>
</item>
<item>
<key> <string>method</string> </key>
......@@ -120,11 +105,11 @@
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Folder_viewWorkflowActionDocumentListDialog</string> </value>
<value> <string>Folder_viewWorkflowActionDialog</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
<value> <string>folder_workflow_action_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
......
......@@ -10,19 +10,25 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>lines</string>
<string>columns</string>
<string>all_columns</string>
<string>search_columns</string>
<string>sort_columns</string>
<string>list_method</string>
<string>columns</string>
<string>count_method</string>
<string>selection_name</string>
<string>domain_root_list</string>
<string>domain_tree</string>
<string>editable</string>
<string>editable_columns</string>
<string>enabled</string>
<string>hide_rows_on_no_search_criterion</string>
<string>lines</string>
<string>list_method</string>
<string>report_root_list</string>
<string>report_tree</string>
<string>search</string>
<string>search_columns</string>
<string>select</string>
<string>editable_columns</string>
<string>selection_name</string>
<string>sort_columns</string>
<string>stat_columns</string>
<string>editable</string>
</list>
</value>
</item>
......@@ -78,10 +84,28 @@
<key> <string>count_method</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>domain_root_list</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>domain_tree</string> </key>