0002-backoffice-add-checkboxes-to-run-global-actions-on-m.patch
tests/test_backoffice_pages.py | ||
---|---|---|
985 | 985 |
assert '<h2>Filters</h2>' in resp.body |
986 | 986 |
assert 'End: 2013-01-01' in resp.body |
987 | 987 | |
988 |
def test_backoffice_multi_actions(pub): |
|
989 |
create_superuser(pub) |
|
990 |
create_environment(pub) |
|
991 |
formdef = FormDef.get_by_urlname('form-title') |
|
992 | ||
993 |
app = login(get_app(pub)) |
|
994 |
resp = app.get('/backoffice/management/form-title/') |
|
995 |
assert not 'id="multi-actions"' in resp.body |
|
996 | ||
997 |
workflow = Workflow.get_default_workflow() |
|
998 |
workflow.id = '2' |
|
999 |
action = workflow.add_global_action('FOOBAR') |
|
1000 |
jump = action.append_item('jump') |
|
1001 |
jump.status = 'finished' |
|
1002 |
trigger = action.triggers[0] |
|
1003 |
trigger.roles = ['whatever'] |
|
1004 | ||
1005 |
workflow.store() |
|
1006 |
formdef.workflow_id = workflow.id |
|
1007 |
formdef.store() |
|
1008 | ||
1009 |
resp = app.get('/backoffice/management/form-title/') |
|
1010 |
assert not 'id="multi-actions"' in resp.body |
|
1011 | ||
1012 |
trigger.roles = [x.id for x in Role.select() if x.name == 'foobar'] |
|
1013 |
workflow.store() |
|
1014 | ||
1015 |
resp = app.get('/backoffice/management/form-title/') |
|
1016 |
assert 'id="multi-actions"' in resp.body |
|
1017 |
ids = [] |
|
1018 |
for checkbox in resp.forms[0].fields['select[]'][1:6]: |
|
1019 |
ids.append(checkbox._value) |
|
1020 |
checkbox.checked = True |
|
1021 |
resp = resp.forms[0].submit('button-action-1') |
|
1022 |
assert '?job=' in resp.location |
|
1023 |
resp = resp.follow() |
|
1024 |
assert 'Executing task "FOOBAR" on forms' in resp.body |
|
1025 |
assert '>completed<' in resp.body |
|
1026 |
for id in ids: |
|
1027 |
assert formdef.data_class().get(id).status == 'wf-finished' |
|
1028 | ||
1029 |
draft_ids = [x.id for x in formdef.data_class().select() if x.status == 'draft'] |
|
1030 |
resp = app.get('/backoffice/management/form-title/') |
|
1031 |
assert resp.forms[0].fields['select[]'][0]._value == '_all' |
|
1032 |
resp.forms[0].fields['select[]'][0].checked = True |
|
1033 |
resp = resp.forms[0].submit('button-action-1') |
|
1034 |
for formdata in formdef.data_class().select(): |
|
1035 |
if formdata.id in draft_ids: |
|
1036 |
assert formdata.status == 'draft' |
|
1037 |
else: |
|
1038 |
assert formdata.status == 'wf-finished' |
|
1039 | ||
1040 |
for formdata in formdef.data_class().select(): |
|
1041 |
if formdata.status != 'draft': |
|
1042 |
formdata.jump_status('new') |
|
1043 |
formdata.store() |
|
1044 | ||
1045 |
# action for other role |
|
1046 |
action2 = workflow.add_global_action('OTHER ACTION') |
|
1047 |
jump = action2.append_item('jump') |
|
1048 |
jump.status = 'accepted' |
|
1049 |
trigger = action2.triggers[0] |
|
1050 |
trigger.roles = ['whatever'] |
|
1051 |
workflow.store() |
|
1052 |
resp = app.get('/backoffice/management/form-title/') |
|
1053 |
assert 'id="multi-actions"' in resp.body |
|
1054 |
assert not 'OTHER ACTION' in resp.body |
|
1055 | ||
1056 |
# action for function |
|
1057 |
trigger.roles = ['_foobar'] |
|
1058 |
workflow.store() |
|
1059 | ||
1060 |
resp = app.get('/backoffice/management/form-title/') |
|
1061 |
assert 'id="multi-actions"' in resp.body |
|
1062 |
assert 'OTHER ACTION' not in resp.body |
|
1063 | ||
1064 |
workflow.roles['_foobar'] = 'Foobar' |
|
1065 |
workflow.store() |
|
1066 | ||
1067 |
resp = app.get('/backoffice/management/form-title/') |
|
1068 |
assert 'id="multi-actions"' in resp.body |
|
1069 |
assert 'OTHER ACTION' in resp.body |
|
1070 | ||
1071 |
# alter some formdata to simulate dispatch action |
|
1072 |
stable_ids = [] |
|
1073 |
for checkbox in resp.forms[0].fields['select[]'][1:6]: |
|
1074 |
formdata = formdef.data_class().get(checkbox._value) |
|
1075 |
formdata.workflow_roles = {'_foobar': formdef.workflow_roles['_receiver']} |
|
1076 |
formdata.store() |
|
1077 |
stable_ids.append(formdata.id) |
|
1078 | ||
1079 |
resp = app.get('/backoffice/management/form-title/') |
|
1080 |
assert 'OTHER ACTION' in resp.body |
|
1081 | ||
1082 |
resp.forms[0].fields['select[]'][0].checked = True # _all |
|
1083 |
resp = resp.forms[0].submit('button-action-2') |
|
1084 |
assert '?job=' in resp.location |
|
1085 |
resp = resp.follow() |
|
1086 |
assert 'Executing task "OTHER ACTION" on forms' in resp.body |
|
1087 |
# check only dispatched formdata have been moved by global action executed |
|
1088 |
# on all formdatas |
|
1089 |
for formdata in formdef.data_class().select(): |
|
1090 |
if formdata.id in draft_ids: |
|
1091 |
assert formdata.status == 'draft' |
|
1092 |
elif formdata.id in stable_ids: |
|
1093 |
assert formdata.status == 'wf-accepted' |
|
1094 |
else: |
|
1095 |
assert formdata.status != 'wf-accepted' |
|
1096 | ||
988 | 1097 |
def test_backoffice_statistics_status_filter(pub): |
989 | 1098 |
create_superuser(pub) |
990 | 1099 |
create_environment(pub) |
wcs/backoffice/management.py | ||
---|---|---|
1330 | 1330 |
def listing_top_actions(self): |
1331 | 1331 |
return '' |
1332 | 1332 | |
1333 |
def get_multi_actions(self, user): |
|
1334 |
global_actions = self.formdef.workflow.get_global_manual_actions() |
|
1335 |
workflow_roles = self.formdef.workflow.roles or {} |
|
1336 |
mass_actions = [] |
|
1337 |
for action_dict in global_actions: |
|
1338 |
action_dict['roles'] = [x for x in user.get_roles() if x in action_dict.get('roles') or []] |
|
1339 |
if action_dict['functions'] or action_dict['roles']: |
|
1340 |
mass_actions.append(action_dict) |
|
1341 |
return mass_actions |
|
1342 | ||
1333 | 1343 |
def _q_index(self): |
1334 | 1344 |
self.check_access() |
1335 | 1345 |
get_logger().info('backoffice - form %s - listing' % self.formdef.name) |
1336 | 1346 | |
1347 |
if 'job' in get_request().form: |
|
1348 |
return self.job_multi() |
|
1349 | ||
1337 | 1350 |
fields = self.get_fields_from_query() |
1338 | 1351 |
selected_filter = self.get_filter_from_query() |
1339 | 1352 |
criterias = self.get_criterias_from_query() |
... | ... | |
1354 | 1367 |
if get_request().get_query(): |
1355 | 1368 |
qs = '?' + get_request().get_query() |
1356 | 1369 | |
1370 |
multi_actions = self.get_multi_actions(get_request().user) |
|
1371 |
if not get_request().form.get('ajax') == 'true': |
|
1372 |
multi_form = Form(id='multi-actions') |
|
1373 |
for action in multi_actions: |
|
1374 |
attrs = {} |
|
1375 |
if action.get('functions'): |
|
1376 |
for function in action.get('functions'): |
|
1377 |
attrs['data-visible_for_%s' % function] = 'true' |
|
1378 |
else: |
|
1379 |
attrs['data-visible_for_all'] = 'true' |
|
1380 |
multi_form.add_submit('button-action-%s' % action['action'].id, action['action'].name, attrs=attrs) |
|
1381 |
if multi_form.is_submitted() and get_request().form.get('select[]'): |
|
1382 |
for action in multi_actions: |
|
1383 |
if multi_form.get_submit() == 'button-action-%s' % action['action'].id: |
|
1384 |
return self.submit_multi( |
|
1385 |
action, |
|
1386 |
selected_filter=selected_filter, |
|
1387 |
query=query, |
|
1388 |
criterias=criterias) |
|
1389 | ||
1357 | 1390 |
table = FormDefUI(self.formdef).listing(fields=fields, |
1358 | 1391 |
selected_filter=selected_filter, |
1359 | 1392 |
limit=int(limit), offset=int(offset), query=query, |
1360 |
order_by=order_by, criterias=criterias) |
|
1393 |
order_by=order_by, criterias=criterias, |
|
1394 |
include_checkboxes=bool(multi_actions)) |
|
1361 | 1395 |
if get_response().status_code == 302: |
1362 | 1396 |
# catch early redirect |
1363 | 1397 |
return table |
... | ... | |
1373 | 1407 |
r += get_session().display_message() |
1374 | 1408 |
r += self.listing_top_actions() |
1375 | 1409 |
r += htmltext('</div>') |
1376 |
r += table |
|
1410 |
if multi_actions: |
|
1411 |
multi_form.widgets.append(HtmlWidget(table)) |
|
1412 |
r += multi_form.render() |
|
1413 |
else: |
|
1414 |
r += table |
|
1377 | 1415 | |
1378 | 1416 |
get_response().filter['sidebar'] = self.get_formdata_sidebar(qs) + \ |
1379 | 1417 |
self.get_fields_sidebar(selected_filter, fields, limit=limit, |
... | ... | |
1382 | 1420 | |
1383 | 1421 |
return r.getvalue() |
1384 | 1422 | |
1423 |
def submit_multi(self, action, selected_filter, query, criterias): |
|
1424 |
class ActionJob(object): |
|
1425 |
def __init__(self, formdef, query_string, action, item_ids): |
|
1426 |
self.formdef = formdef |
|
1427 |
self.query_string = query_string |
|
1428 |
self.action = action |
|
1429 |
self.item_ids = item_ids |
|
1430 |
self.user = get_request().user |
|
1431 | ||
1432 |
def execute(self, job=None): |
|
1433 |
formdatas = self.formdef.data_class().get_ids(self.item_ids) |
|
1434 |
publisher = get_publisher() |
|
1435 |
for formdata in formdatas: |
|
1436 |
publisher.substitutions.reset() |
|
1437 |
publisher.substitutions.feed(publisher) |
|
1438 |
publisher.substitutions.feed(self.formdef) |
|
1439 |
publisher.substitutions.feed(formdata) |
|
1440 |
formdata.perform_global_action(self.action['action'].id, self.user) |
|
1441 | ||
1442 |
item_ids = get_request().form['select[]'] |
|
1443 |
if '_all' in item_ids: |
|
1444 |
item_ids = FormDefUI(self.formdef).get_listing_item_ids( |
|
1445 |
selected_filter, user=get_request().user, query=query, |
|
1446 |
criterias=criterias) |
|
1447 |
action_job = ActionJob(self.formdef, get_request().get_query(), action, item_ids) |
|
1448 |
job = get_response().add_after_job( |
|
1449 |
N_('Executing task "%s" on forms') % action['action'].name, |
|
1450 |
action_job.execute) |
|
1451 |
job.query_string = get_request().get_query() |
|
1452 |
job.store() |
|
1453 |
return redirect('./?job=%s' % job.id) |
|
1454 | ||
1455 |
def job_multi(self): |
|
1456 |
try: |
|
1457 |
job = AfterJob.get(get_request().form.get('job')) |
|
1458 |
except KeyError: |
|
1459 |
return redirect('.') |
|
1460 | ||
1461 |
html_top('management', title=_('Executing Task')) |
|
1462 |
r = TemplateIO(html=True) |
|
1463 |
r += get_session().display_message() |
|
1464 |
get_response().add_javascript(['jquery.js', 'afterjob.js']) |
|
1465 |
r += htmltext('<dl class="job-status">') |
|
1466 |
r += htmltext('<dt>') |
|
1467 |
r += _(job.label) |
|
1468 |
r += htmltext('</dt>') |
|
1469 |
r += htmltext('<dd>') |
|
1470 |
r += htmltext('<span class="afterjob" id="%s">') % job.id |
|
1471 |
r += _(job.status) |
|
1472 |
r += htmltext('</span>') |
|
1473 |
r += htmltext('</dd>') |
|
1474 |
r += htmltext('</dl>') |
|
1475 | ||
1476 |
r += htmltext('<div class="done">') |
|
1477 |
r += htmltext('<a data-redirect-auto="true" href="./?%s">%s</a>') % (job.query_string, _('Back to Listing')) |
|
1478 |
r += htmltext('</div>') |
|
1479 |
return r.getvalue() |
|
1480 | ||
1385 | 1481 |
def csv_tuple_heading(self, fields): |
1386 | 1482 |
heading_fields = [] # '#id', _('time'), _('userlabel'), _('status')] |
1387 | 1483 |
for field in fields: |
wcs/compat.py | ||
---|---|---|
116 | 116 |
params['charset'] = site_charset |
117 | 117 |
if not self.form: |
118 | 118 |
self.form = {} |
119 |
for k, v in self.django_request.POST.items():
|
|
119 |
for k in self.django_request.POST:
|
|
120 | 120 |
if isinstance(k, unicode): |
121 | 121 |
k = k.encode(site_charset) |
122 |
if isinstance(v, unicode): |
|
123 |
v = v.encode(site_charset) |
|
122 |
if k.endswith('[]'): |
|
123 |
v = [x.encode(site_charset) for x in self.django_request.POST.getlist(k)] |
|
124 |
else: |
|
125 |
v = self.django_request.POST[k] |
|
126 |
if isinstance(v, unicode): |
|
127 |
v = v.encode(site_charset) |
|
124 | 128 |
self.form[k] = v |
125 | 129 | |
126 | 130 |
for k, upload_file in self.django_request.FILES.items(): |
wcs/formdata.py | ||
---|---|---|
480 | 480 |
url = perform_items(wf_status.items, self) |
481 | 481 |
return url |
482 | 482 | |
483 |
def perform_global_action(self, action_id, user): |
|
484 |
from wcs.workflows import perform_items |
|
485 |
for action in self.formdef.workflow.get_global_actions_for_user(self, user): |
|
486 |
if action.id != action_id: |
|
487 |
continue |
|
488 |
perform_items(action.items, self) |
|
489 |
break |
|
490 | ||
483 | 491 |
def get_workflow_messages(self, position='top'): |
484 | 492 |
wf_status = self.get_status() |
485 | 493 |
if not wf_status: |
wcs/forms/backoffice.py | ||
---|---|---|
31 | 31 | |
32 | 32 |
def listing(self, fields, selected_filter='all', url_action=None, |
33 | 33 |
items=None, offset=0, limit=0, |
34 |
query=None, order_by=None, criterias=None): |
|
34 |
query=None, order_by=None, criterias=None, |
|
35 |
include_checkboxes=False): |
|
35 | 36 | |
36 | 37 |
partial_display = False |
37 | 38 | |
... | ... | |
68 | 69 |
r += htmltext('<table id="listing" class="main compact">') |
69 | 70 | |
70 | 71 |
r += htmltext('<colgroup>') |
72 |
if include_checkboxes: |
|
73 |
r += htmltext('<col/>') # checkbox |
|
71 | 74 |
r += htmltext('<col/>') # lock |
72 | 75 |
r += htmltext('<col/>') |
73 | 76 |
r += htmltext('<col/>') |
... | ... | |
78 | 81 |
using_postgresql = get_publisher().is_using_postgresql() |
79 | 82 | |
80 | 83 |
r += htmltext('<thead><tr>') |
84 |
if include_checkboxes: |
|
85 |
r += htmltext('<th class="select"><input type="checkbox" name="select[]" value="_all"/></th>') |
|
81 | 86 |
if self.formdef.workflow.criticality_levels and using_postgresql: |
82 | 87 |
r += htmltext('<th style="width: 4ex;" data-field-sort-key="criticality_level"><span></span></th>') |
83 | 88 |
else: |
... | ... | |
105 | 110 |
r += htmltext('</th>') |
106 | 111 |
r += htmltext('</tr></thead>') |
107 | 112 |
r += htmltext('<tbody>') |
108 |
r += htmltext(self.tbody(fields, items, url_action)) |
|
113 |
r += htmltext(self.tbody(fields, items, url_action, |
|
114 |
include_checkboxes=include_checkboxes)) |
|
109 | 115 |
r += htmltext('</tbody>') |
110 | 116 |
r += htmltext('</table>') |
111 | 117 | |
... | ... | |
115 | 121 | |
116 | 122 |
return r.getvalue() |
117 | 123 | |
118 |
def get_listing_items(self, selected_filter='all', offset=None, |
|
119 |
limit=None, query=None, order_by=None, user=None, criterias=None, anonymise=False): |
|
120 |
user = user or get_request().user |
|
124 |
def get_listing_item_ids(self, selected_filter='all', query=None, order_by=None, user=None, criterias=None, anonymise=False): |
|
121 | 125 |
formdata_class = self.formdef.data_class() |
122 | 126 |
if selected_filter == 'all': |
123 | 127 |
item_ids = formdata_class.keys() |
... | ... | |
161 | 165 |
'concerned_roles', str(role))) |
162 | 166 |
item_ids = list(set(item_ids).intersection(concerned_ids)) |
163 | 167 | |
168 |
return item_ids |
|
169 | ||
170 |
def get_listing_items(self, selected_filter='all', offset=None, |
|
171 |
limit=None, query=None, order_by=None, user=None, criterias=None, anonymise=False): |
|
172 |
user = user or get_request().user |
|
173 |
formdata_class = self.formdef.data_class() |
|
174 | ||
175 |
item_ids = self.get_listing_item_ids( |
|
176 |
selected_filter=selected_filter, |
|
177 |
query=query, |
|
178 |
user=user, |
|
179 |
criterias=criterias, |
|
180 |
anonymise=anonymise) |
|
181 | ||
164 | 182 |
if order_by and not hasattr(formdata_class, 'get_sorted_ids'): |
165 | 183 |
# get_sorted_ids is only implemented in the SQL backend |
166 | 184 |
order_by = None |
... | ... | |
186 | 204 |
return (items, total_count) |
187 | 205 | |
188 | 206 | |
189 |
def tbody(self, fields=None, items=None, url_action=None): |
|
207 |
def tbody(self, fields=None, items=None, url_action=None, include_checkboxes=False):
|
|
190 | 208 |
r = TemplateIO(html=True) |
191 | 209 |
if url_action: |
192 | 210 |
pass |
... | ... | |
194 | 212 |
else: |
195 | 213 |
url_action = '' |
196 | 214 |
root_url = get_publisher().get_root_url() |
197 |
visited_objects = get_publisher().get_visited_objects(exclude_user=get_session().user) |
|
215 |
user = get_request().user |
|
216 |
visited_objects = get_publisher().get_visited_objects(exclude_user=user.id) |
|
198 | 217 |
include_criticality_level = bool(self.formdef.workflow.criticality_levels) |
199 | 218 |
for i, filled in enumerate(items): |
200 | 219 |
classes = ['status-%s-%s' % (filled.formdef.workflow.id, filled.status)] |
... | ... | |
224 | 243 |
if filled.anonymised: |
225 | 244 |
data += ' data-anonymised="true"' |
226 | 245 |
r += htmltext('<tr class="%s"%s>' % (' '.join(classes), data)) |
246 |
if include_checkboxes: |
|
247 |
r += htmltext('<td class="select"><input type="checkbox" name="select[]" ') |
|
248 |
r += htmltext('value="%s"') % filled.id |
|
249 |
workflow_roles = {} |
|
250 |
workflow_roles.update(self.formdef.workflow_roles) |
|
251 |
if filled.workflow_roles: |
|
252 |
workflow_roles.update(filled.workflow_roles) |
|
253 |
for function_key, function_value in workflow_roles.items(): |
|
254 |
if function_value in user.get_roles(): |
|
255 |
r += htmltext(' data-is-%s="true" ' % function_key) |
|
256 |
r += htmltext('/></td>') |
|
227 | 257 |
if include_criticality_level: |
228 | 258 |
r += htmltext('<td %s></td>' % style) # criticality_level |
229 | 259 |
else: |
wcs/qommon/static/css/dc2/admin.css | ||
---|---|---|
395 | 395 |
opacity: 0.5; |
396 | 396 |
} |
397 | 397 | |
398 |
#listing tbody tr td { |
|
399 |
cursor: pointer; |
|
400 |
} |
|
401 | ||
402 |
#listing tbody tr td.select { |
|
403 |
cursor: default; |
|
404 |
} |
|
405 | ||
398 | 406 |
#listing tbody tr:hover td { |
399 | 407 |
background: #dde; |
400 |
cursor: pointer; |
|
401 | 408 |
} |
402 | 409 | |
403 | 410 |
#listing.main th, |
... | ... | |
413 | 420 |
cursor: inherit; |
414 | 421 |
} |
415 | 422 | |
423 |
table#listing .select { |
|
424 |
width: 1rem; |
|
425 |
text-align: center; |
|
426 |
} |
|
427 | ||
428 |
table#listing .select input { |
|
429 |
margin: 2px 0; |
|
430 |
} |
|
431 | ||
416 | 432 |
table.main th[data-field-sort-key] span:after { |
417 | 433 |
padding-left: 1ex; |
418 | 434 |
content: "\f0dc"; /* sort */ |
... | ... | |
1807 | 1823 |
a.button.button-paragraph:hover p { |
1808 | 1824 |
color: white; |
1809 | 1825 |
} |
1826 | ||
1827 |
#main-content form#multi-actions { |
|
1828 |
padding: 0; |
|
1829 |
} |
|
1830 | ||
1831 |
#main-content form#multi-actions div.buttons { |
|
1832 |
padding: 0 0.5rem; |
|
1833 |
} |
|
1834 | ||
1835 |
table#listing tr.checked td { |
|
1836 |
background: #ddf; |
|
1837 |
} |
wcs/qommon/static/js/afterjob.js | ||
---|---|---|
8 | 8 |
function () { |
9 | 9 |
var current_text = $(this).text(); |
10 | 10 |
if (current_text.indexOf('completed') == 0) { |
11 |
if ($('div.done a[data-redirect-auto]').length) { |
|
12 |
window.location = $('div.done a[data-redirect-auto]').attr('href'); |
|
13 |
} |
|
11 | 14 |
$(this).text(current_text.substr(10, current_text.length)); |
12 | 15 |
$(this).addClass('activity-done'); |
13 | 16 |
$('.afterjob-running').hide(); |
wcs/qommon/static/js/wcs.listing.js | ||
---|---|---|
12 | 12 |
event.stopPropagation(); |
13 | 13 |
}); |
14 | 14 |
$('#listing tbody tr').on('mouseup', function(event) { |
15 |
var $target = $(event.target); |
|
16 |
if ($target.is('input[type=checkbox]')) { |
|
17 |
return false; |
|
18 |
} |
|
19 |
if ($target.is('td.select')) { |
|
20 |
$target.find('input').click(); |
|
21 |
return false; |
|
22 |
} |
|
15 | 23 |
var data_link = $(this).data('link'); |
16 | 24 |
if (data_link) { |
17 | 25 |
if (data_link.indexOf('http://') == -1 && data_link.indexOf('https://') == -1) { |
... | ... | |
25 | 33 |
return false; |
26 | 34 |
} |
27 | 35 |
}); |
36 |
if ($('#listing tbody input[type=checkbox]:checked').length == 0) { |
|
37 |
$('form#multi-actions div.buttons').hide(); |
|
38 |
} else { |
|
39 |
$('form#multi-actions div.buttons').show(); |
|
40 |
} |
|
41 |
$('#listing tbody input[type=checkbox]').each(function() { |
|
42 |
if ($(this).is(':checked')) { |
|
43 |
$(this).parents('tr').addClass('checked'); |
|
44 |
} else { |
|
45 |
$(this).parents('tr').removeClass('checked'); |
|
46 |
} |
|
47 |
}); |
|
48 |
$('#listing input[type=checkbox]').on('change', function() { |
|
49 |
if ($(this).is(':checked')) { |
|
50 |
if ($(this).is('[value=_all]')) { |
|
51 |
$(this).parents('table').find('tbody td.select input').prop('checked', true); |
|
52 |
$(this).parents('table').find('tbody tr').addClass('checked'); |
|
53 |
} else { |
|
54 |
$(this).parents('tr').addClass('checked'); |
|
55 |
} |
|
56 |
} else { |
|
57 |
if ($(this).is('[value=_all]')) { |
|
58 |
$(this).parents('table').find('tbody td.select input').prop('checked', false); |
|
59 |
$(this).parents('table').find('tbody tr').removeClass('checked'); |
|
60 |
} else { |
|
61 |
$(this).parents('tr').removeClass('checked'); |
|
62 |
$('#listing input[type=checkbox][value=_all]').prop('checked', false); |
|
63 |
} |
|
64 |
} |
|
65 |
if ($('#listing tbody input[type=checkbox]:checked').length == 0) { |
|
66 |
$('form#multi-actions div.buttons').hide(); |
|
67 |
return; |
|
68 |
} else { |
|
69 |
$('form#multi-actions div.buttons button').each(function(idx, elem) { |
|
70 |
var visible = false; |
|
71 |
for (var key in $(elem).first().data()) { |
|
72 |
if (key == 'visible_for_all') { |
|
73 |
visible = true; |
|
74 |
break; |
|
75 |
} |
|
76 |
if ($('input[type=checkbox][data-is-' + key.substr(12) + ']:checked').length) { |
|
77 |
visible = true; |
|
78 |
break; |
|
79 |
} |
|
80 |
} |
|
81 |
if (visible) { |
|
82 |
$(elem).parents('div.widget').show(); |
|
83 |
} else { |
|
84 |
$(elem).parents('div.widget').hide(); |
|
85 |
} |
|
86 |
}); |
|
87 |
$('form#multi-actions div.buttons').show(); |
|
88 |
} |
|
89 |
}); |
|
28 | 90 |
} |
29 | 91 | |
30 | 92 |
function prepare_column_headers() { |
... | ... | |
61 | 123 |
} |
62 | 124 | |
63 | 125 |
function autorefresh_table() { |
126 |
if ($('#multi-actions input:checked').length) { |
|
127 |
// disable autorefresh when multiselection is enabled |
|
128 |
return; |
|
129 |
} |
|
64 | 130 |
$(document).trigger('backoffice-filter-change', |
65 | 131 |
{qs: $('form#listing-settings').serialize(), auto: true}); |
66 | 132 |
} |
wcs/workflows.py | ||
---|---|---|
413 | 413 |
self.global_actions.append(action) |
414 | 414 |
return action |
415 | 415 | |
416 |
def get_global_manual_actions(self): |
|
417 |
actions = [] |
|
418 |
for action in self.global_actions or []: |
|
419 |
roles = [] |
|
420 |
for trigger in action.triggers or []: |
|
421 |
if not isinstance(trigger, WorkflowGlobalActionManualTrigger): |
|
422 |
continue |
|
423 |
roles.extend(trigger.roles or []) |
|
424 |
functions = [x for x in roles if x in self.roles] |
|
425 |
roles = [x for x in roles if x not in self.roles] |
|
426 |
if functions or roles: |
|
427 |
actions.append({'action': action, 'roles': roles, 'functions': functions}) |
|
428 |
return actions |
|
429 | ||
430 | ||
416 | 431 |
def get_global_actions_for_user(self, formdata, user): |
417 | 432 |
if not user: |
418 | 433 |
return [] |
419 |
- |