backoffice: add checkboxes to run global actions on many items at once (#7865)
This commit is contained in:
parent
a3c3ec6b21
commit
281b020996
|
@ -985,6 +985,115 @@ def test_backoffice_statistics(pub):
|
|||
assert '<h2>Filters</h2>' in resp.body
|
||||
assert 'End: 2013-01-01' in resp.body
|
||||
|
||||
def test_backoffice_multi_actions(pub):
|
||||
create_superuser(pub)
|
||||
create_environment(pub)
|
||||
formdef = FormDef.get_by_urlname('form-title')
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert not 'id="multi-actions"' in resp.body
|
||||
|
||||
workflow = Workflow.get_default_workflow()
|
||||
workflow.id = '2'
|
||||
action = workflow.add_global_action('FOOBAR')
|
||||
jump = action.append_item('jump')
|
||||
jump.status = 'finished'
|
||||
trigger = action.triggers[0]
|
||||
trigger.roles = ['whatever']
|
||||
|
||||
workflow.store()
|
||||
formdef.workflow_id = workflow.id
|
||||
formdef.store()
|
||||
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert not 'id="multi-actions"' in resp.body
|
||||
|
||||
trigger.roles = [x.id for x in Role.select() if x.name == 'foobar']
|
||||
workflow.store()
|
||||
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert 'id="multi-actions"' in resp.body
|
||||
ids = []
|
||||
for checkbox in resp.forms[0].fields['select[]'][1:6]:
|
||||
ids.append(checkbox._value)
|
||||
checkbox.checked = True
|
||||
resp = resp.forms[0].submit('button-action-1')
|
||||
assert '?job=' in resp.location
|
||||
resp = resp.follow()
|
||||
assert 'Executing task "FOOBAR" on forms' in resp.body
|
||||
assert '>completed<' in resp.body
|
||||
for id in ids:
|
||||
assert formdef.data_class().get(id).status == 'wf-finished'
|
||||
|
||||
draft_ids = [x.id for x in formdef.data_class().select() if x.status == 'draft']
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert resp.forms[0].fields['select[]'][0]._value == '_all'
|
||||
resp.forms[0].fields['select[]'][0].checked = True
|
||||
resp = resp.forms[0].submit('button-action-1')
|
||||
for formdata in formdef.data_class().select():
|
||||
if formdata.id in draft_ids:
|
||||
assert formdata.status == 'draft'
|
||||
else:
|
||||
assert formdata.status == 'wf-finished'
|
||||
|
||||
for formdata in formdef.data_class().select():
|
||||
if formdata.status != 'draft':
|
||||
formdata.jump_status('new')
|
||||
formdata.store()
|
||||
|
||||
# action for other role
|
||||
action2 = workflow.add_global_action('OTHER ACTION')
|
||||
jump = action2.append_item('jump')
|
||||
jump.status = 'accepted'
|
||||
trigger = action2.triggers[0]
|
||||
trigger.roles = ['whatever']
|
||||
workflow.store()
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert 'id="multi-actions"' in resp.body
|
||||
assert not 'OTHER ACTION' in resp.body
|
||||
|
||||
# action for function
|
||||
trigger.roles = ['_foobar']
|
||||
workflow.store()
|
||||
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert 'id="multi-actions"' in resp.body
|
||||
assert 'OTHER ACTION' not in resp.body
|
||||
|
||||
workflow.roles['_foobar'] = 'Foobar'
|
||||
workflow.store()
|
||||
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert 'id="multi-actions"' in resp.body
|
||||
assert 'OTHER ACTION' in resp.body
|
||||
|
||||
# alter some formdata to simulate dispatch action
|
||||
stable_ids = []
|
||||
for checkbox in resp.forms[0].fields['select[]'][1:6]:
|
||||
formdata = formdef.data_class().get(checkbox._value)
|
||||
formdata.workflow_roles = {'_foobar': formdef.workflow_roles['_receiver']}
|
||||
formdata.store()
|
||||
stable_ids.append(formdata.id)
|
||||
|
||||
resp = app.get('/backoffice/management/form-title/')
|
||||
assert 'OTHER ACTION' in resp.body
|
||||
|
||||
resp.forms[0].fields['select[]'][0].checked = True # _all
|
||||
resp = resp.forms[0].submit('button-action-2')
|
||||
assert '?job=' in resp.location
|
||||
resp = resp.follow()
|
||||
assert 'Executing task "OTHER ACTION" on forms' in resp.body
|
||||
# check only dispatched formdata have been moved by global action executed
|
||||
# on all formdatas
|
||||
for formdata in formdef.data_class().select():
|
||||
if formdata.id in draft_ids:
|
||||
assert formdata.status == 'draft'
|
||||
elif formdata.id in stable_ids:
|
||||
assert formdata.status == 'wf-accepted'
|
||||
else:
|
||||
assert formdata.status != 'wf-accepted'
|
||||
|
||||
def test_backoffice_statistics_status_filter(pub):
|
||||
create_superuser(pub)
|
||||
create_environment(pub)
|
||||
|
|
|
@ -1330,10 +1330,23 @@ class FormPage(Directory):
|
|||
def listing_top_actions(self):
|
||||
return ''
|
||||
|
||||
def get_multi_actions(self, user):
|
||||
global_actions = self.formdef.workflow.get_global_manual_actions()
|
||||
workflow_roles = self.formdef.workflow.roles or {}
|
||||
mass_actions = []
|
||||
for action_dict in global_actions:
|
||||
action_dict['roles'] = [x for x in user.get_roles() if x in action_dict.get('roles') or []]
|
||||
if action_dict['functions'] or action_dict['roles']:
|
||||
mass_actions.append(action_dict)
|
||||
return mass_actions
|
||||
|
||||
def _q_index(self):
|
||||
self.check_access()
|
||||
get_logger().info('backoffice - form %s - listing' % self.formdef.name)
|
||||
|
||||
if 'job' in get_request().form:
|
||||
return self.job_multi()
|
||||
|
||||
fields = self.get_fields_from_query()
|
||||
selected_filter = self.get_filter_from_query()
|
||||
criterias = self.get_criterias_from_query()
|
||||
|
@ -1354,10 +1367,31 @@ class FormPage(Directory):
|
|||
if get_request().get_query():
|
||||
qs = '?' + get_request().get_query()
|
||||
|
||||
multi_actions = self.get_multi_actions(get_request().user)
|
||||
if not get_request().form.get('ajax') == 'true':
|
||||
multi_form = Form(id='multi-actions')
|
||||
for action in multi_actions:
|
||||
attrs = {}
|
||||
if action.get('functions'):
|
||||
for function in action.get('functions'):
|
||||
attrs['data-visible_for_%s' % function] = 'true'
|
||||
else:
|
||||
attrs['data-visible_for_all'] = 'true'
|
||||
multi_form.add_submit('button-action-%s' % action['action'].id, action['action'].name, attrs=attrs)
|
||||
if multi_form.is_submitted() and get_request().form.get('select[]'):
|
||||
for action in multi_actions:
|
||||
if multi_form.get_submit() == 'button-action-%s' % action['action'].id:
|
||||
return self.submit_multi(
|
||||
action,
|
||||
selected_filter=selected_filter,
|
||||
query=query,
|
||||
criterias=criterias)
|
||||
|
||||
table = FormDefUI(self.formdef).listing(fields=fields,
|
||||
selected_filter=selected_filter,
|
||||
limit=int(limit), offset=int(offset), query=query,
|
||||
order_by=order_by, criterias=criterias)
|
||||
order_by=order_by, criterias=criterias,
|
||||
include_checkboxes=bool(multi_actions))
|
||||
if get_response().status_code == 302:
|
||||
# catch early redirect
|
||||
return table
|
||||
|
@ -1373,7 +1407,11 @@ class FormPage(Directory):
|
|||
r += get_session().display_message()
|
||||
r += self.listing_top_actions()
|
||||
r += htmltext('</div>')
|
||||
r += table
|
||||
if multi_actions:
|
||||
multi_form.widgets.append(HtmlWidget(table))
|
||||
r += multi_form.render()
|
||||
else:
|
||||
r += table
|
||||
|
||||
get_response().filter['sidebar'] = self.get_formdata_sidebar(qs) + \
|
||||
self.get_fields_sidebar(selected_filter, fields, limit=limit,
|
||||
|
@ -1382,6 +1420,64 @@ class FormPage(Directory):
|
|||
|
||||
return r.getvalue()
|
||||
|
||||
def submit_multi(self, action, selected_filter, query, criterias):
|
||||
class ActionJob(object):
|
||||
def __init__(self, formdef, query_string, action, item_ids):
|
||||
self.formdef = formdef
|
||||
self.query_string = query_string
|
||||
self.action = action
|
||||
self.item_ids = item_ids
|
||||
self.user = get_request().user
|
||||
|
||||
def execute(self, job=None):
|
||||
formdatas = self.formdef.data_class().get_ids(self.item_ids)
|
||||
publisher = get_publisher()
|
||||
for formdata in formdatas:
|
||||
publisher.substitutions.reset()
|
||||
publisher.substitutions.feed(publisher)
|
||||
publisher.substitutions.feed(self.formdef)
|
||||
publisher.substitutions.feed(formdata)
|
||||
formdata.perform_global_action(self.action['action'].id, self.user)
|
||||
|
||||
item_ids = get_request().form['select[]']
|
||||
if '_all' in item_ids:
|
||||
item_ids = FormDefUI(self.formdef).get_listing_item_ids(
|
||||
selected_filter, user=get_request().user, query=query,
|
||||
criterias=criterias)
|
||||
action_job = ActionJob(self.formdef, get_request().get_query(), action, item_ids)
|
||||
job = get_response().add_after_job(
|
||||
N_('Executing task "%s" on forms') % action['action'].name,
|
||||
action_job.execute)
|
||||
job.query_string = get_request().get_query()
|
||||
job.store()
|
||||
return redirect('./?job=%s' % job.id)
|
||||
|
||||
def job_multi(self):
|
||||
try:
|
||||
job = AfterJob.get(get_request().form.get('job'))
|
||||
except KeyError:
|
||||
return redirect('.')
|
||||
|
||||
html_top('management', title=_('Executing Task'))
|
||||
r = TemplateIO(html=True)
|
||||
r += get_session().display_message()
|
||||
get_response().add_javascript(['jquery.js', 'afterjob.js'])
|
||||
r += htmltext('<dl class="job-status">')
|
||||
r += htmltext('<dt>')
|
||||
r += _(job.label)
|
||||
r += htmltext('</dt>')
|
||||
r += htmltext('<dd>')
|
||||
r += htmltext('<span class="afterjob" id="%s">') % job.id
|
||||
r += _(job.status)
|
||||
r += htmltext('</span>')
|
||||
r += htmltext('</dd>')
|
||||
r += htmltext('</dl>')
|
||||
|
||||
r += htmltext('<div class="done">')
|
||||
r += htmltext('<a data-redirect-auto="true" href="./?%s">%s</a>') % (job.query_string, _('Back to Listing'))
|
||||
r += htmltext('</div>')
|
||||
return r.getvalue()
|
||||
|
||||
def csv_tuple_heading(self, fields):
|
||||
heading_fields = [] # '#id', _('time'), _('userlabel'), _('status')]
|
||||
for field in fields:
|
||||
|
|
|
@ -116,11 +116,15 @@ class CompatHTTPRequest(HTTPRequest):
|
|||
params['charset'] = site_charset
|
||||
if not self.form:
|
||||
self.form = {}
|
||||
for k, v in self.django_request.POST.items():
|
||||
for k in self.django_request.POST:
|
||||
if isinstance(k, unicode):
|
||||
k = k.encode(site_charset)
|
||||
if isinstance(v, unicode):
|
||||
v = v.encode(site_charset)
|
||||
if k.endswith('[]'):
|
||||
v = [x.encode(site_charset) for x in self.django_request.POST.getlist(k)]
|
||||
else:
|
||||
v = self.django_request.POST[k]
|
||||
if isinstance(v, unicode):
|
||||
v = v.encode(site_charset)
|
||||
self.form[k] = v
|
||||
|
||||
for k, upload_file in self.django_request.FILES.items():
|
||||
|
|
|
@ -480,6 +480,14 @@ class FormData(StorableObject):
|
|||
url = perform_items(wf_status.items, self)
|
||||
return url
|
||||
|
||||
def perform_global_action(self, action_id, user):
|
||||
from wcs.workflows import perform_items
|
||||
for action in self.formdef.workflow.get_global_actions_for_user(formdata=self, user=user):
|
||||
if action.id != action_id:
|
||||
continue
|
||||
perform_items(action.items, self)
|
||||
break
|
||||
|
||||
def get_workflow_messages(self, position='top'):
|
||||
wf_status = self.get_status()
|
||||
if not wf_status:
|
||||
|
|
|
@ -31,7 +31,8 @@ class FormDefUI(object):
|
|||
|
||||
def listing(self, fields, selected_filter='all', url_action=None,
|
||||
items=None, offset=0, limit=0,
|
||||
query=None, order_by=None, criterias=None):
|
||||
query=None, order_by=None, criterias=None,
|
||||
include_checkboxes=False):
|
||||
|
||||
partial_display = False
|
||||
|
||||
|
@ -68,6 +69,8 @@ class FormDefUI(object):
|
|||
r += htmltext('<table id="listing" class="main compact">')
|
||||
|
||||
r += htmltext('<colgroup>')
|
||||
if include_checkboxes:
|
||||
r += htmltext('<col/>') # checkbox
|
||||
r += htmltext('<col/>') # lock
|
||||
r += htmltext('<col/>')
|
||||
r += htmltext('<col/>')
|
||||
|
@ -78,6 +81,10 @@ class FormDefUI(object):
|
|||
using_postgresql = get_publisher().is_using_postgresql()
|
||||
|
||||
r += htmltext('<thead><tr>')
|
||||
if include_checkboxes:
|
||||
r += htmltext('<th class="select"><input type="checkbox" name="select[]" value="_all"/>')
|
||||
r += htmltext(' <span id="info-all-rows">%s</span></th>') % _(
|
||||
'Do note the selected action will run on all pages when this is checked.')
|
||||
if self.formdef.workflow.criticality_levels and using_postgresql:
|
||||
r += htmltext('<th style="width: 4ex;" data-field-sort-key="criticality_level"><span></span></th>')
|
||||
else:
|
||||
|
@ -105,7 +112,8 @@ class FormDefUI(object):
|
|||
r += htmltext('</th>')
|
||||
r += htmltext('</tr></thead>')
|
||||
r += htmltext('<tbody>')
|
||||
r += htmltext(self.tbody(fields, items, url_action))
|
||||
r += htmltext(self.tbody(fields, items, url_action,
|
||||
include_checkboxes=include_checkboxes))
|
||||
r += htmltext('</tbody>')
|
||||
r += htmltext('</table>')
|
||||
|
||||
|
@ -115,9 +123,7 @@ class FormDefUI(object):
|
|||
|
||||
return r.getvalue()
|
||||
|
||||
def get_listing_items(self, selected_filter='all', offset=None,
|
||||
limit=None, query=None, order_by=None, user=None, criterias=None, anonymise=False):
|
||||
user = user or get_request().user
|
||||
def get_listing_item_ids(self, selected_filter='all', query=None, order_by=None, user=None, criterias=None, anonymise=False):
|
||||
formdata_class = self.formdef.data_class()
|
||||
if selected_filter == 'all':
|
||||
item_ids = formdata_class.keys()
|
||||
|
@ -161,6 +167,20 @@ class FormDefUI(object):
|
|||
'concerned_roles', str(role)))
|
||||
item_ids = list(set(item_ids).intersection(concerned_ids))
|
||||
|
||||
return item_ids
|
||||
|
||||
def get_listing_items(self, selected_filter='all', offset=None,
|
||||
limit=None, query=None, order_by=None, user=None, criterias=None, anonymise=False):
|
||||
user = user or get_request().user
|
||||
formdata_class = self.formdef.data_class()
|
||||
|
||||
item_ids = self.get_listing_item_ids(
|
||||
selected_filter=selected_filter,
|
||||
query=query,
|
||||
user=user,
|
||||
criterias=criterias,
|
||||
anonymise=anonymise)
|
||||
|
||||
if order_by and not hasattr(formdata_class, 'get_sorted_ids'):
|
||||
# get_sorted_ids is only implemented in the SQL backend
|
||||
order_by = None
|
||||
|
@ -186,7 +206,7 @@ class FormDefUI(object):
|
|||
return (items, total_count)
|
||||
|
||||
|
||||
def tbody(self, fields=None, items=None, url_action=None):
|
||||
def tbody(self, fields=None, items=None, url_action=None, include_checkboxes=False):
|
||||
r = TemplateIO(html=True)
|
||||
if url_action:
|
||||
pass
|
||||
|
@ -194,7 +214,8 @@ class FormDefUI(object):
|
|||
else:
|
||||
url_action = ''
|
||||
root_url = get_publisher().get_root_url()
|
||||
visited_objects = get_publisher().get_visited_objects(exclude_user=get_session().user)
|
||||
user = get_request().user
|
||||
visited_objects = get_publisher().get_visited_objects(exclude_user=user.id)
|
||||
include_criticality_level = bool(self.formdef.workflow.criticality_levels)
|
||||
for i, filled in enumerate(items):
|
||||
classes = ['status-%s-%s' % (filled.formdef.workflow.id, filled.status)]
|
||||
|
@ -224,6 +245,17 @@ class FormDefUI(object):
|
|||
if filled.anonymised:
|
||||
data += ' data-anonymised="true"'
|
||||
r += htmltext('<tr class="%s"%s>' % (' '.join(classes), data))
|
||||
if include_checkboxes:
|
||||
r += htmltext('<td class="select"><input type="checkbox" name="select[]" ')
|
||||
r += htmltext('value="%s"') % filled.id
|
||||
workflow_roles = {}
|
||||
workflow_roles.update(self.formdef.workflow_roles)
|
||||
if filled.workflow_roles:
|
||||
workflow_roles.update(filled.workflow_roles)
|
||||
for function_key, function_value in workflow_roles.items():
|
||||
if function_value in user.get_roles():
|
||||
r += htmltext(' data-is-%s="true" ' % function_key)
|
||||
r += htmltext('/></td>')
|
||||
if include_criticality_level:
|
||||
r += htmltext('<td %s></td>' % style) # criticality_level
|
||||
else:
|
||||
|
|
|
@ -390,14 +390,41 @@ ul.biglist, table#listing {
|
|||
transition: opacity 500ms ease-out;
|
||||
}
|
||||
|
||||
table#listing {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#listing.activity ul.biglist,
|
||||
table#listing.activity {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#listing tbody tr td {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#listing tbody tr td.select {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#listing thead tr th.select span {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: -17px;
|
||||
background: white;
|
||||
padding: 5px 1rem;
|
||||
border: 1px solid #666;
|
||||
border-radius: 5px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#listing thead tr th.select input:checked + span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#listing tbody tr:hover td {
|
||||
background: #dde;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#listing.main th,
|
||||
|
@ -413,6 +440,15 @@ table.main th.nosort {
|
|||
cursor: inherit;
|
||||
}
|
||||
|
||||
table#listing .select {
|
||||
width: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table#listing .select input {
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
table.main th[data-field-sort-key] span:after {
|
||||
padding-left: 1ex;
|
||||
content: "\f0dc"; /* sort */
|
||||
|
@ -1807,3 +1843,15 @@ a.button.button-paragraph p:last-child {
|
|||
a.button.button-paragraph:hover p {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#main-content form#multi-actions {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#main-content form#multi-actions div.buttons {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
table#listing tr.checked td {
|
||||
background: #ddf;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ function updateStatus()
|
|||
function () {
|
||||
var current_text = $(this).text();
|
||||
if (current_text.indexOf('completed') == 0) {
|
||||
if ($('div.done a[data-redirect-auto]').length) {
|
||||
window.location = $('div.done a[data-redirect-auto]').attr('href');
|
||||
}
|
||||
$(this).text(current_text.substr(10, current_text.length));
|
||||
$(this).addClass('activity-done');
|
||||
$('.afterjob-running').hide();
|
||||
|
|
|
@ -12,6 +12,14 @@ function prepare_row_links() {
|
|||
event.stopPropagation();
|
||||
});
|
||||
$('#listing tbody tr').on('mouseup', function(event) {
|
||||
var $target = $(event.target);
|
||||
if ($target.is('input[type=checkbox]')) {
|
||||
return false;
|
||||
}
|
||||
if ($target.is('td.select')) {
|
||||
$target.find('input').click();
|
||||
return false;
|
||||
}
|
||||
var data_link = $(this).data('link');
|
||||
if (data_link) {
|
||||
if (data_link.indexOf('http://') == -1 && data_link.indexOf('https://') == -1) {
|
||||
|
@ -25,6 +33,60 @@ function prepare_row_links() {
|
|||
return false;
|
||||
}
|
||||
});
|
||||
if ($('#listing tbody input[type=checkbox]:checked').length == 0) {
|
||||
$('form#multi-actions div.buttons').hide();
|
||||
} else {
|
||||
$('form#multi-actions div.buttons').show();
|
||||
}
|
||||
$('#listing tbody input[type=checkbox]').each(function() {
|
||||
if ($(this).is(':checked')) {
|
||||
$(this).parents('tr').addClass('checked');
|
||||
} else {
|
||||
$(this).parents('tr').removeClass('checked');
|
||||
}
|
||||
});
|
||||
$('#listing input[type=checkbox]').on('change', function() {
|
||||
if ($(this).is(':checked')) {
|
||||
if ($(this).is('[value=_all]')) {
|
||||
$(this).parents('table').find('tbody td.select input').prop('checked', true);
|
||||
$(this).parents('table').find('tbody tr').addClass('checked');
|
||||
} else {
|
||||
$(this).parents('tr').addClass('checked');
|
||||
}
|
||||
} else {
|
||||
if ($(this).is('[value=_all]')) {
|
||||
$(this).parents('table').find('tbody td.select input').prop('checked', false);
|
||||
$(this).parents('table').find('tbody tr').removeClass('checked');
|
||||
} else {
|
||||
$(this).parents('tr').removeClass('checked');
|
||||
$('#listing input[type=checkbox][value=_all]').prop('checked', false);
|
||||
}
|
||||
}
|
||||
if ($('#listing tbody input[type=checkbox]:checked').length == 0) {
|
||||
$('form#multi-actions div.buttons').hide();
|
||||
return;
|
||||
} else {
|
||||
$('form#multi-actions div.buttons button').each(function(idx, elem) {
|
||||
var visible = false;
|
||||
for (var key in $(elem).first().data()) {
|
||||
if (key == 'visible_for_all') {
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
if ($('input[type=checkbox][data-is-' + key.substr(12) + ']:checked').length) {
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (visible) {
|
||||
$(elem).parents('div.widget').show();
|
||||
} else {
|
||||
$(elem).parents('div.widget').hide();
|
||||
}
|
||||
});
|
||||
$('form#multi-actions div.buttons').show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function prepare_column_headers() {
|
||||
|
@ -61,6 +123,10 @@ function prepare_column_headers() {
|
|||
}
|
||||
|
||||
function autorefresh_table() {
|
||||
if ($('#multi-actions input:checked').length) {
|
||||
// disable autorefresh when multiselection is enabled
|
||||
return;
|
||||
}
|
||||
$(document).trigger('backoffice-filter-change',
|
||||
{qs: $('form#listing-settings').serialize(), auto: true});
|
||||
}
|
||||
|
|
|
@ -413,6 +413,21 @@ class Workflow(StorableObject):
|
|||
self.global_actions.append(action)
|
||||
return action
|
||||
|
||||
def get_global_manual_actions(self):
|
||||
actions = []
|
||||
for action in self.global_actions or []:
|
||||
roles = []
|
||||
for trigger in action.triggers or []:
|
||||
if not isinstance(trigger, WorkflowGlobalActionManualTrigger):
|
||||
continue
|
||||
roles.extend(trigger.roles or [])
|
||||
functions = [x for x in roles if x in self.roles]
|
||||
roles = [x for x in roles if x not in self.roles]
|
||||
if functions or roles:
|
||||
actions.append({'action': action, 'roles': roles, 'functions': functions})
|
||||
return actions
|
||||
|
||||
|
||||
def get_global_actions_for_user(self, formdata, user):
|
||||
if not user:
|
||||
return []
|
||||
|
|
Loading…
Reference in New Issue