0002-backoffice-add-tracing-information-to-inspect-page-5.patch
tests/backoffice_pages/test_all.py | ||
---|---|---|
5022 | 5022 |
) |
5023 | 5023 | |
5024 | 5024 | |
5025 |
def test_inspect_page_actions_traces(pub): |
|
5026 |
create_environment(pub) |
|
5027 |
create_user(pub, is_admin=True) |
|
5028 | ||
5029 |
formdef = FormDef.get_by_urlname('form-title') |
|
5030 | ||
5031 |
formdef.data_class().wipe() |
|
5032 |
formdata = formdef.data_class()() |
|
5033 |
formdata.data = {} |
|
5034 |
formdata.just_created() |
|
5035 |
formdata.perform_workflow() |
|
5036 |
formdata.store() |
|
5037 | ||
5038 |
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True), status=200) |
|
5039 |
resp = resp.click('Data Inspector') |
|
5040 |
assert '<h2>Actions Tracing</h2>' in resp |
|
5041 |
assert [x.text for x in resp.pyquery('#inspect-timeline strong')] == ['Just Submitted', 'New'] |
|
5042 |
assert [x.text for x in resp.pyquery('#inspect-timeline a.tracing-link') if x.text] == [ |
|
5043 |
'Email', |
|
5044 |
'Email', |
|
5045 |
'Automatic Jump', |
|
5046 |
] |
|
5047 | ||
5048 | ||
5025 | 5049 |
def test_workflow_jump_previous(pub): |
5026 | 5050 |
user = create_user(pub) |
5027 | 5051 |
create_environment(pub) |
wcs/backoffice/management.py | ||
---|---|---|
42 | 42 |
from wcs.forms.common import FormStatusPage |
43 | 43 |
from wcs.roles import logged_users_role |
44 | 44 |
from wcs.variables import LazyFieldVar |
45 |
from wcs.workflows import WorkflowStatusItem, template_on_formdata
|
|
45 |
from wcs.workflows import ActionsTracingEvolutionPart, WorkflowStatusItem, item_classes, template_on_formdata
|
|
46 | 46 | |
47 | 47 |
from ..qommon import _, emails, errors, ezt, force_str, get_cfg, get_logger, misc, ngettext, ods, sms |
48 | 48 |
from ..qommon.admin.emails import EmailsDirectory |
... | ... | |
3427 | 3427 |
r += htmltext('</ul>') |
3428 | 3428 |
r += htmltext('</div>') |
3429 | 3429 | |
3430 |
has_tracing = False |
|
3431 |
for evolution in self.filled.evolution or []: |
|
3432 |
if evolution.parts and any(isinstance(x, ActionsTracingEvolutionPart) for x in evolution.parts): |
|
3433 |
has_tracing = True |
|
3434 |
break |
|
3435 | ||
3436 |
if has_tracing: |
|
3437 |
action_classes = {x.key: x.description for x in item_classes} |
|
3438 |
r += htmltext('<div id="inspect-timeline" class="section">') |
|
3439 |
r += htmltext('<h2>%s</h2></li>\n') % _('Actions Tracing') |
|
3440 |
r += htmltext('<ul class="form-inspector biglist">') |
|
3441 |
wf_status = None |
|
3442 |
status_admin_base_url = '#' |
|
3443 |
for evolution in self.filled.evolution: |
|
3444 |
if evolution.status and evolution.status != wf_status: |
|
3445 |
for part in evolution.parts or []: |
|
3446 |
if isinstance(part, ActionsTracingEvolutionPart): |
|
3447 |
if part.actions: |
|
3448 |
r += ( |
|
3449 |
htmltext('<li><span class="event">%s</span></li>') |
|
3450 |
% part.get_event_label() |
|
3451 |
) |
|
3452 |
break |
|
3453 |
try: |
|
3454 |
status = self.filled.formdef.workflow.get_status(evolution.status) |
|
3455 |
status_label = status.name |
|
3456 |
status_admin_base_url = status.get_admin_url() |
|
3457 |
except KeyError: |
|
3458 |
status_label = _('Unavailable status (%s)') % evolution.status |
|
3459 |
status_admin_base_url = '#missing' |
|
3460 |
r += htmltext( |
|
3461 |
'<li><span class="datetime">%s</span> ' |
|
3462 |
'<a class="tracing-link" href="%s"><strong>%s</strong></a></li>' |
|
3463 |
) % ( |
|
3464 |
time.strftime('%Y-%m-%d %H:%M:%S', evolution.time) if evolution.time else '-', |
|
3465 |
status_admin_base_url, |
|
3466 |
status_label, |
|
3467 |
) |
|
3468 |
if evolution.status: |
|
3469 |
wf_status = evolution.status |
|
3470 |
first_part = True |
|
3471 |
for part in evolution.parts or []: |
|
3472 |
if isinstance(part, ActionsTracingEvolutionPart): |
|
3473 |
if not first_part and part.actions: |
|
3474 |
r += htmltext('<li><span class="event">%s</span></li>') % part.get_event_label() |
|
3475 |
first_part = False |
|
3476 |
for action_ts, action_key, action_id in part.actions: |
|
3477 |
action_label = action_classes.get(action_key, action_key) |
|
3478 |
try: |
|
3479 |
url = '%sitems/%s/' % ( |
|
3480 |
part.get_base_url(self.filled.formdef.workflow, wf_status), |
|
3481 |
action_id, |
|
3482 |
) |
|
3483 |
except KeyError: |
|
3484 |
url = '#missing-%s' % action_id |
|
3485 |
r += htmltext( |
|
3486 |
'<li><span class="datetime">%s</span> ' |
|
3487 |
'<a class="tracing-link" href="%s">%s</a></li>' |
|
3488 |
) % ( |
|
3489 |
action_ts.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3], |
|
3490 |
url, |
|
3491 |
action_label, |
|
3492 |
) |
|
3493 | ||
3494 |
r += htmltext('</ul>') |
|
3495 |
r += htmltext('</div>') |
|
3496 | ||
3430 | 3497 |
# markers stack |
3431 | 3498 |
if '_markers_stack' in (self.filled.workflow_data or {}): |
3432 | 3499 |
r += htmltext('<div id="inspect-markers" class="section">') |
wcs/qommon/static/css/dc2/admin.scss | ||
---|---|---|
1662 | 1662 |
font-size: 100%; |
1663 | 1663 |
} |
1664 | 1664 | |
1665 |
ul.form-inspector li span.datetime { |
|
1666 |
padding: 0 1ex; |
|
1667 |
} |
|
1668 | ||
1669 |
ul.form-inspector li a.tracing-link { |
|
1670 |
display: inline; |
|
1671 |
padding: 0; |
|
1672 |
&:hover { |
|
1673 |
background: transparent; |
|
1674 |
text-decoration: underline; |
|
1675 |
} |
|
1676 |
} |
|
1677 | ||
1665 | 1678 |
ul.form-inspector li span.status { |
1666 | 1679 |
padding: 0 1ex; |
1667 | 1680 |
} |
1668 | 1681 | |
1682 |
ul.form-inspector span.event { |
|
1683 |
padding: 0 1ex; |
|
1684 |
font-style: italic; |
|
1685 |
} |
|
1686 | ||
1669 | 1687 |
ul.form-inspector li div.value { |
1670 | 1688 |
display: block; |
1671 | 1689 |
padding: 0 0 0 1em; |
wcs/workflows.py | ||
---|---|---|
80 | 80 |
continue |
81 | 81 |
if not item.check_condition(formdata): |
82 | 82 |
continue |
83 |
performed_actions.append((datetime.datetime.now(), item.id)) |
|
83 |
performed_actions.append((datetime.datetime.now(), item.key, item.id))
|
|
84 | 84 |
try: |
85 | 85 |
url = item.perform(formdata) or url |
86 | 86 |
except AbortActionException as e: |
... | ... | |
340 | 340 |
self.event_args = None |
341 | 341 |
self.actions = actions |
342 | 342 | |
343 |
def get_event_label(self): |
|
344 |
return { |
|
345 |
'api-created': _('Created (by API)'), |
|
346 |
'api-post-edit-action': _('Actions after edit action (by APIà'), |
|
347 |
'api-trigger': _('API Trigger'), |
|
348 |
'backoffice-created': _('Created (backoffice submission)'), |
|
349 |
'continuation': _('Continuation'), |
|
350 |
'csv-import-created': _('Created (by CSV import)'), |
|
351 |
'edit-action': _('Actions after edit action'), |
|
352 |
'frontoffice-created': _('Created (frontoffice submission)'), |
|
353 |
'global-action-button': _('Click on a global action button'), |
|
354 |
'global-action': _('Global action'), |
|
355 |
'global-action-timeout': _('Global action timeout'), |
|
356 |
'timeout-jump': _('Timeout jump'), |
|
357 |
'workflow-created': _('Created (by workflow action)'), |
|
358 |
'workflow-form-submit': _('Action in workflow form'), |
|
359 |
}.get(self.event, self.event) |
|
360 | ||
361 |
def is_global_event(self): |
|
362 |
return bool(self.event and self.event.startswith('global-')) |
|
363 | ||
364 |
def get_base_url(self, workflow, status_id): |
|
365 |
if self.is_global_event(): |
|
366 |
return '%sglobal-actions/%s/' % (workflow.get_admin_url(), self.event_args[0]) |
|
367 |
status = workflow.get_status(status_id) |
|
368 |
return status.get_admin_url() |
|
369 | ||
343 | 370 | |
344 | 371 |
class DuplicateGlobalActionNameError(Exception): |
345 | 372 |
pass |
346 |
- |