workflows: add generic status options to global action manual trigger (#77926)
gitea/wcs/pipeline/head This commit looks good
Details
gitea/wcs/pipeline/head This commit looks good
Details
This commit is contained in:
parent
ccc87a959c
commit
a07ac2a8b3
|
@ -856,6 +856,144 @@ def test_backoffice_multi_actions_some_status(pub):
|
|||
assert len(resp.pyquery('[data-status_accepted]')) == 5
|
||||
|
||||
|
||||
def test_backoffice_multi_actions_generic_status(pub):
|
||||
create_superuser(pub)
|
||||
Workflow.wipe()
|
||||
FormDef.wipe()
|
||||
|
||||
workflow = Workflow.get_default_workflow()
|
||||
workflow.id = '2'
|
||||
action1 = workflow.add_global_action('FOOBAR')
|
||||
register_comment = action1.add_action('register-comment')
|
||||
register_comment.comment = 'hello'
|
||||
trigger = action1.triggers[0]
|
||||
trigger.statuses = ['_endpoint_status']
|
||||
trigger.roles = ['_receiver']
|
||||
assert set(trigger.get_statuses_ids()) == {'rejected', 'finished'}
|
||||
assert trigger.render_as_line() == 'Manual, from final status, by Recipient'
|
||||
|
||||
action2 = workflow.add_global_action('FOOBAR2')
|
||||
register_comment = action2.add_action('register-comment')
|
||||
register_comment.comment = 'hello2'
|
||||
trigger = action2.triggers[0]
|
||||
trigger.statuses = ['_waitpoint_status']
|
||||
trigger.roles = ['_receiver']
|
||||
assert set(trigger.get_statuses_ids()) == {'new', 'accepted'}
|
||||
assert trigger.render_as_line() == 'Manual, from pause status, by Recipient'
|
||||
|
||||
action3 = workflow.add_global_action('FOOBAR3')
|
||||
register_comment = action3.add_action('register-comment')
|
||||
register_comment.comment = 'hello3'
|
||||
trigger = action3.triggers[0]
|
||||
trigger.statuses = ['_transition_status']
|
||||
trigger.roles = ['_receiver']
|
||||
assert set(trigger.get_statuses_ids()) == {'just_submitted'}
|
||||
assert trigger.render_as_line() == 'Manual, from transition status, by Recipient'
|
||||
|
||||
trigger.statuses = ['_transition_status', 'xxx'] # check with invalid status
|
||||
assert trigger.render_as_line() == 'Manual, from transition status, by Recipient'
|
||||
|
||||
workflow.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
formdef.workflow_roles = {'_receiver': 1}
|
||||
formdef.workflow_id = workflow.id
|
||||
formdef.store()
|
||||
|
||||
for i in range(15):
|
||||
formdata = formdef.data_class()()
|
||||
formdata.just_created()
|
||||
if i < 5:
|
||||
formdata.jump_status('accepted')
|
||||
elif i % 3 == 0:
|
||||
formdata.jump_status('new')
|
||||
else:
|
||||
formdata.jump_status('finished')
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/management/form-title/?filter=all')
|
||||
ids = []
|
||||
for checkbox in resp.forms[0].fields['select[]']:
|
||||
if checkbox._value == '_all':
|
||||
continue
|
||||
# check them all
|
||||
ids.append(checkbox._value)
|
||||
checkbox.checked = True
|
||||
|
||||
assert len(resp.pyquery('[data-status_new]')) == 3
|
||||
assert len(resp.pyquery('[data-status_finished]')) == 7
|
||||
assert len(resp.pyquery('[data-status_accepted]')) == 5
|
||||
|
||||
assert resp.pyquery(
|
||||
f'form#multi-actions button[name="button-action-{action1.id}"]'
|
||||
'[data-visible_status_finished]'
|
||||
'[data-visible_status_rejected]'
|
||||
':not([data-visible_status_new])'
|
||||
':not([data-visible_status_accepted])'
|
||||
':not([data-visible_status_just_submitted])'
|
||||
)
|
||||
|
||||
assert resp.pyquery(
|
||||
f'form#multi-actions button[name="button-action-{action2.id}"]'
|
||||
':not([data-visible_status_finished])'
|
||||
':not([data-visible_status_rejected])'
|
||||
'[data-visible_status_new]'
|
||||
'[data-visible_status_accepted]'
|
||||
':not([data-visible_status_just_submitted])'
|
||||
)
|
||||
|
||||
assert resp.pyquery(
|
||||
f'form#multi-actions button[name="button-action-{action3.id}"]'
|
||||
':not([data-visible_status_finished])'
|
||||
':not([data-visible_status_rejected])'
|
||||
':not([data-visible_status_new])'
|
||||
':not([data-visible_status_accepted])'
|
||||
'[data-visible_status_just_submitted]'
|
||||
)
|
||||
|
||||
resp = resp.forms[0].submit(f'button-action-{action1.id}')
|
||||
assert '?job=' in resp.location
|
||||
resp = resp.follow()
|
||||
assert 'Executing task "FOOBAR" on forms' in resp.text
|
||||
assert '>completed<' in resp.text
|
||||
for id in ids:
|
||||
formdata = formdef.data_class().get(id)
|
||||
comments = [x.content for x in formdata.iter_evolution_parts(JournalEvolutionPart)]
|
||||
# check action was only executed on "finished"
|
||||
if formdata.status == 'wf-finished':
|
||||
assert comments == ['<p>hello</p>']
|
||||
else:
|
||||
assert comments == []
|
||||
|
||||
# check not end point status
|
||||
resp = app.get('/backoffice/management/form-title/?filter=all')
|
||||
ids = []
|
||||
for checkbox in resp.forms[0].fields['select[]']:
|
||||
if checkbox._value == '_all':
|
||||
continue
|
||||
# check them all
|
||||
ids.append(checkbox._value)
|
||||
checkbox.checked = True
|
||||
|
||||
assert len(resp.pyquery('[data-status_new]')) == 3
|
||||
assert len(resp.pyquery('[data-status_finished]')) == 7
|
||||
assert len(resp.pyquery('[data-status_accepted]')) == 5
|
||||
resp = resp.forms[0].submit(f'button-action-{action2.id}')
|
||||
assert '?job=' in resp.location
|
||||
resp = resp.follow()
|
||||
assert 'Executing task "FOOBAR2" on forms' in resp.text
|
||||
assert '>completed<' in resp.text
|
||||
for id in ids:
|
||||
formdata = formdef.data_class().get(id)
|
||||
comments = [x.content for x in formdata.iter_evolution_parts(JournalEvolutionPart)]
|
||||
# check action was only executed on not final status
|
||||
if formdata.status in ('wf-finished', 'wf-rejected'):
|
||||
assert comments == ['<p>hello</p>']
|
||||
else:
|
||||
assert comments == ['<p>hello2</p>']
|
||||
|
||||
|
||||
def test_backoffice_multi_actions_confirmation(pub):
|
||||
create_superuser(pub)
|
||||
Workflow.wipe()
|
||||
|
|
|
@ -1098,7 +1098,7 @@ class Workflow(StorableObject):
|
|||
if not trigger.allow_as_mass_action:
|
||||
continue
|
||||
roles.extend(trigger.roles or [])
|
||||
statuses.extend(trigger.statuses or [])
|
||||
statuses.extend(trigger.get_statuses_ids())
|
||||
action.require_confirmation = trigger.require_confirmation
|
||||
action.confirmation_text = trigger.confirmation_text
|
||||
functions = [x for x in roles if x in self.roles]
|
||||
|
@ -1786,12 +1786,35 @@ class WorkflowGlobalActionManualTrigger(WorkflowGlobalActionTrigger):
|
|||
def get_parameters(self):
|
||||
return ('roles', 'statuses', 'allow_as_mass_action', 'require_confirmation', 'confirmation_text')
|
||||
|
||||
def get_statuses_ids(self):
|
||||
statuses = self.statuses or []
|
||||
for status in self.get_workflow().possible_status or []:
|
||||
if status in statuses:
|
||||
yield status.id
|
||||
if '_endpoint_status' in statuses and status.is_endpoint():
|
||||
yield status.id
|
||||
if '_waitpoint_status' in statuses and (status.is_waitpoint() and not status.is_endpoint()):
|
||||
yield status.id
|
||||
if '_transition_status' in statuses and not (status.is_waitpoint() or status.is_endpoint()):
|
||||
yield status.id
|
||||
|
||||
def get_status_option_label(self, status_id):
|
||||
if status_id == '_endpoint_status':
|
||||
return _('from final status')
|
||||
if status_id == '_waitpoint_status':
|
||||
return _('from pause status')
|
||||
if status_id == '_transition_status':
|
||||
return _('from transition status')
|
||||
try:
|
||||
return _('from status "%s"') % self.get_workflow().get_status(status_id).name
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def render_as_line(self):
|
||||
parts = [_('Manual')]
|
||||
if self.statuses:
|
||||
labels = [x.name for x in self.get_workflow().possible_status if x.id in self.statuses]
|
||||
if labels:
|
||||
parts.append(_('from status %s') % _(' or ').join([_('"%s"') % x for x in labels]))
|
||||
status_labels = [self.get_status_option_label(x) for x in self.statuses or []]
|
||||
if status_labels:
|
||||
parts.append(_(' or ').join([str(x) for x in status_labels if x]))
|
||||
if self.roles:
|
||||
parts.append(_('by %s') % render_list_of_roles(self.get_workflow(), self.roles))
|
||||
else:
|
||||
|
@ -1838,7 +1861,13 @@ class WorkflowGlobalActionManualTrigger(WorkflowGlobalActionTrigger):
|
|||
add_element_label=workflow.get_add_role_label(),
|
||||
element_kwargs={'render_br': False, 'options': options},
|
||||
)
|
||||
status_options = [(None, '---', None)]
|
||||
status_options = [
|
||||
(None, '---', ''),
|
||||
('_waitpoint_status', _('Pause status'), '_wait_status'),
|
||||
('_endpoint_status', _('Final status'), '_endpoint_status'),
|
||||
('_transition_status', _('Transition status'), '_transition_status'),
|
||||
(None, '---', ''),
|
||||
]
|
||||
status_options += [(str(x.id), x.name, str(x.id)) for x in self.get_workflow().possible_status]
|
||||
form.add(
|
||||
WidgetList,
|
||||
|
@ -2635,7 +2664,7 @@ class WorkflowGlobalAction(SerieOfActionsMixin):
|
|||
for trigger in self.triggers or []:
|
||||
self.trigger = trigger # attach trigger to action, to have trigger options available in form
|
||||
if trigger.key == 'manual':
|
||||
if trigger.statuses and current_status_id not in trigger.statuses:
|
||||
if trigger.statuses and current_status_id not in trigger.get_statuses_ids():
|
||||
continue
|
||||
if '_submitter' in (trigger.roles or []) and formdata.is_submitter(user):
|
||||
return True
|
||||
|
|
Loading…
Reference in New Issue