workflows: display triggers dynamically in external workflow action (#51244) #970
|
@ -3005,6 +3005,8 @@ def test_workflows_external_workflow_action_config(pub):
|
|||
trigger = action.append_trigger('webservice')
|
||||
trigger.identifier = 'test'
|
||||
action.add_action('remove')
|
||||
trigger = action.append_trigger('webservice')
|
||||
trigger.identifier = 'test2'
|
||||
external_wf.store()
|
||||
|
||||
FormDef.wipe()
|
||||
|
@ -3013,6 +3015,11 @@ def test_workflows_external_workflow_action_config(pub):
|
|||
formdef.workflow = external_wf
|
||||
formdef.store()
|
||||
|
||||
formdef2 = FormDef()
|
||||
formdef2.name = 'other'
|
||||
formdef2.workflow = external_wf
|
||||
formdef2.store()
|
||||
|
||||
wf = Workflow(name='foo')
|
||||
st = wf.add_status('New')
|
||||
st.add_action('external_workflow_global_action')
|
||||
|
@ -3020,21 +3027,16 @@ def test_workflows_external_workflow_action_config(pub):
|
|||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (wf.id, st.id))
|
||||
# only action error: custom error message
|
||||
resp.forms[0]['slug'] = 'formdef:external'
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert 'There were errors processing your form. See below for details.' not in resp
|
||||
assert 'This action is configured in two steps. See below for details.' in resp
|
||||
assert 'required field' in resp
|
||||
# multiple errors: do as usual
|
||||
resp.forms[0]['slug'] = 'formdef:external'
|
||||
resp.forms[0]['condition$type'] = 'django'
|
||||
resp.forms[0]['condition$value_django'] = '{{ 42 }}'
|
||||
assert [
|
||||
(x.attrib.get('value'), x.attrib.get('data-slugs'))
|
||||
for x in resp.pyquery('#form_trigger_id option[data-slugs]')
|
||||
] == [
|
||||
('action:test', 'formdef:external|formdef:other'),
|
||||
('action:test2', 'formdef:external|formdef:other'),
|
||||
]
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert 'There were errors processing your form. See below for details.' in resp
|
||||
assert 'This action is configured in two steps. See below for details.' not in resp
|
||||
assert 'required field' in resp
|
||||
assert "syntax error: Could not parse the remainder: '{{' from '{{'" in resp
|
||||
|
||||
|
||||
def test_workflows_create_formdata(pub):
|
||||
|
|
|
@ -44,6 +44,35 @@ $(function() {
|
|||
this.jumpto_button.hide();
|
||||
}
|
||||
}).trigger('change');
|
||||
$('[data-filter-trigger-select]').on('change', function() {
|
||||
var option = $(this).val();
|
||||
$('#form_trigger_id option').each(function(idx, elem) {
|
||||
if (elem.dataset.slugs === undefined) return;
|
||||
var option_slugs = elem.dataset.slugs.split('|');
|
||||
if (option == '' || option_slugs.indexOf(option) == -1) {
|
||||
$(elem).hide();
|
||||
} else {
|
||||
$(elem).show();
|
||||
}
|
||||
});
|
||||
if ($('#form_trigger_id option:selected')[0].style.display == 'none') {
|
||||
$('#form_trigger_id').val('');
|
||||
}
|
||||
});
|
||||
if ($('#form_trigger_id').length) {
|
||||
var current_objectdef = $('[data-filter-trigger-select]').val();
|
||||
var current_val = $('#form_trigger_id').val();
|
||||
$('[data-filter-trigger-select]').trigger('change');
|
||||
if (current_val) { // may have been reset when filtering
|
||||
$('#form_trigger_id option').each(function(idx, elem) {
|
||||
if (elem.dataset.slugs === undefined) return;
|
||||
var option_slugs = elem.dataset.slugs.split('|');
|
||||
if (elem.value == current_val && option_slugs.indexOf(current_objectdef) !== -1) {
|
||||
$('#form_trigger_id')[0].selectedIndex = idx;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* focus tab with error */
|
||||
$('.form-with-tabs .error').first().closest('[role=tabpanel]').each(function(idx, elem) {
|
||||
|
|
|
@ -22,7 +22,7 @@ from quixote.html import TemplateIO, htmltext
|
|||
from wcs.carddef import CardDef
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.qommon import _
|
||||
from wcs.qommon.form import ComputedExpressionWidget, Form, RadiobuttonsWidget, SingleSelectWidget
|
||||
from wcs.qommon.form import ComputedExpressionWidget, RadiobuttonsWidget, SingleSelectWidget
|
||||
from wcs.variables import LazyFormData, LazyFormDefObjectsManager
|
||||
from wcs.workflows import (
|
||||
AbortOnRemovalException,
|
||||
|
@ -115,22 +115,51 @@ class ExternalWorkflowGlobalAction(WorkflowStatusItem):
|
|||
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
|
||||
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
|
||||
|
||||
if 'slug' in parameters:
|
||||
if 'slug' in parameters or 'trigger_id' in parameters:
|
||||
objects = [(None, '---', '', {})]
|
||||
trigger_options = []
|
||||
is_admin_accessible = {
|
||||
'forms': get_publisher().get_backoffice_root().is_accessible('forms'),
|
||||
'cards': get_publisher().get_backoffice_root().is_accessible('cards'),
|
||||
}
|
||||
for wf in Workflow.select():
|
||||
if any(self.get_workflow_webservice_triggers(wf)):
|
||||
for objectdef in wf.formdefs(lightweight=True) + wf.carddefs(lightweight=True):
|
||||
object_slug = '%s:%s' % (objectdef.__class__.__name__.lower(), objectdef.url_name)
|
||||
objects.append((object_slug, objectdef.name, object_slug, {}))
|
||||
if is_admin_accessible[objectdef.backoffice_section]:
|
||||
objects[-1][-1]['data-goto-url'] = objectdef.get_admin_url()
|
||||
|
||||
# preload all cards/forms
|
||||
objectdefs = FormDef.select(order_by='id', lightweight=True) + CardDef.select(
|
||||
order_by='id', lightweight=True
|
||||
)
|
||||
|
||||
# get workflows with external actions
|
||||
workflows = {}
|
||||
for workflow in Workflow.select(ignore_migration=True):
|
||||
external_triggers = list(self.get_workflow_webservice_triggers(workflow))
|
||||
if external_triggers:
|
||||
workflows[workflow.id] = workflow
|
||||
for trigger in external_triggers:
|
||||
object_slugs = [
|
||||
f'{x.__class__.__name__.lower()}:{x.url_name}'
|
||||
for x in objectdefs
|
||||
if x.workflow_id == workflow.id
|
||||
]
|
||||
trigger_id = 'action:%s' % trigger.identifier
|
||||
trigger_options.append(
|
||||
(trigger_id, trigger.parent.name, trigger_id, {'data-slugs': '|'.join(object_slugs)})
|
||||
)
|
||||
|
||||
# list cards/forms with workflows with external actions
|
||||
for objectdef in objectdefs:
|
||||
workflow = workflows.get(objectdef.workflow_id)
|
||||
if not workflow:
|
||||
continue
|
||||
object_slug = '%s:%s' % (objectdef.__class__.__name__.lower(), objectdef.url_name)
|
||||
objects.append((object_slug, objectdef.name, object_slug, {}))
|
||||
if is_admin_accessible[objectdef.backoffice_section]:
|
||||
objects[-1][-1]['data-goto-url'] = objectdef.get_admin_url()
|
||||
|
||||
if len(objects) == 1:
|
||||
form.add_global_errors([_('No workflow with external triggerable global action.')])
|
||||
return
|
||||
|
||||
if 'slug' in parameters:
|
||||
objects.sort(key=lambda x: x[1])
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
|
@ -139,6 +168,7 @@ class ExternalWorkflowGlobalAction(WorkflowStatusItem):
|
|||
value=self.slug,
|
||||
required=True,
|
||||
options=objects,
|
||||
**{'data-filter-trigger-select': 'true'},
|
||||
)
|
||||
|
||||
if 'target_mode' in parameters:
|
||||
|
@ -169,32 +199,20 @@ class ExternalWorkflowGlobalAction(WorkflowStatusItem):
|
|||
allow_python=getattr(self, 'allow_python', True),
|
||||
)
|
||||
|
||||
if 'trigger_id' in parameters and form.get('%sslug' % prefix):
|
||||
object_def = self.get_object_def(form.get('%sslug' % prefix))
|
||||
if not object_def:
|
||||
return
|
||||
triggers_names = [(None, '---', '')]
|
||||
for trigger in self.get_workflow_webservice_triggers(object_def.workflow):
|
||||
trigger_id = 'action:%s' % trigger.identifier
|
||||
triggers_names.append((trigger_id, trigger.parent.name, trigger_id))
|
||||
if 'trigger_id' in parameters:
|
||||
trigger_options.sort(key=lambda x: x[1])
|
||||
form.add(
|
||||
SingleSelectWidget,
|
||||
'%strigger_id' % prefix,
|
||||
title=_('Action'),
|
||||
value=self.trigger_id,
|
||||
required=True,
|
||||
options=triggers_names,
|
||||
options=[(None, '---', '', {})] + trigger_options,
|
||||
)
|
||||
|
||||
if kwargs.get('orig') == 'variable_widget':
|
||||
return
|
||||
|
||||
errors = [w.name for w in form.get_all_widgets() if w.has_error()]
|
||||
if set(errors) == {'%strigger_id' % prefix}:
|
||||
form.ERROR_NOTICE = _('This action is configured in two steps. See below for details.')
|
||||
else:
|
||||
form.ERROR_NOTICE = Form.ERROR_NOTICE
|
||||
|
||||
def get_line_details(self):
|
||||
if self.slug and self.trigger_id:
|
||||
objectdef = self.get_object_def()
|
||||
|
|
Loading…
Reference in New Issue