snapshot: compare inspect of 2 versions (#66565)
gitea-wip/wcs/pipeline/head Build started... Details

This commit is contained in:
Lauréline Guérin 2022-06-24 08:47:23 +02:00
parent da3e9a5118
commit 451b9a95b5
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
12 changed files with 405 additions and 157 deletions

1
debian/control vendored
View File

@ -24,6 +24,7 @@ Depends: graphviz,
python3-dnspython,
python3-hobo,
python3-lasso,
python3-lxml,
python3-pil,
python3-psycopg2,
python3-pyproj,

View File

@ -178,7 +178,9 @@ setup(
'XStatic-Leaflet-GestureHandling',
'XStatic-Select2',
'pyproj',
'pyquery',
'unidecode',
'lxml',
],
package_dir={'wcs': 'wcs'},
packages=find_packages(),

View File

@ -149,94 +149,6 @@ def test_snapshot_basics(pub):
assert [int(f.id) for f in snapshot6.instance.fields] == list(range(0, 12))
def test_snapshot_diff(pub):
create_superuser(pub)
create_role(pub)
formdef = FormDef()
formdef.name = 'testform'
formdef.fields = []
formdef.store()
assert pub.snapshot_class.count() == 1
snapshot1 = pub.snapshot_class.get_latest('formdef', formdef.id)
formdef.fields = [StringField(id=1, label='Test', type='string')]
formdef.store()
assert pub.snapshot_class.count() == 2
snapshot2 = pub.snapshot_class.get_latest('formdef', formdef.id)
formdef.fields += [StringField(id=2, label='Test bis', type='string')]
formdef.store()
assert pub.snapshot_class.count() == 3
snapshot3 = pub.snapshot_class.get_latest('formdef', formdef.id)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/history/' % formdef.id)
assert 'name="version1" value="%s"' % snapshot3.id in resp
assert 'name="version2" value="%s"' % snapshot3.id not in resp
assert 'name="version1" value="%s"' % snapshot2.id in resp
assert 'name="version2" value="%s"' % snapshot2.id in resp
assert 'name="version1" value="%s"' % snapshot1.id not in resp
assert 'name="version2" value="%s"' % snapshot1.id in resp
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s'
% (formdef.id, snapshot1.id, snapshot3.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot1.id, snapshot1.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert resp.text.count('diff_sub') == 1
assert resp.text.count('diff_add') == 24
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s'
% (formdef.id, snapshot3.id, snapshot1.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot1.id, snapshot1.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert resp.text.count('diff_sub') == 1
assert resp.text.count('diff_add') == 24
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s'
% (formdef.id, snapshot2.id, snapshot3.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot2.id, snapshot2.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert resp.text.count('diff_sub') == 0
assert resp.text.count('diff_add') == 11
formdef.fields = [StringField(id=1, label='Test', type='string')]
formdef.store()
assert pub.snapshot_class.count() == 4
snapshot4 = pub.snapshot_class.get_latest('formdef', formdef.id)
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s'
% (formdef.id, snapshot3.id, snapshot4.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot4.id, snapshot4.id) in resp
assert resp.text.count('diff_sub') == 11
assert resp.text.count('diff_add') == 0
resp = app.get('/backoffice/forms/%s/history/compare' % (formdef.id), status=404)
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s' % (formdef.id, snapshot4.id), status=404
)
resp = app.get(
'/backoffice/forms/%s/history/compare?version2=%s' % (formdef.id, snapshot4.id), status=404
)
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s' % (formdef.id, snapshot3.id, 0),
status=404,
)
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s' % (formdef.id, 0, snapshot4.id),
status=404,
)
def test_snapshot_instance(pub):
formdef = FormDef()
formdef.name = 'testform'
@ -296,6 +208,100 @@ def test_snapshot_user(pub):
assert str(snapshot.user) == 'unknown user'
def test_form_snapshot_diff(pub):
create_superuser(pub)
create_role(pub)
formdef = FormDef()
formdef.name = 'testform'
formdef.fields = []
formdef.store()
assert pub.snapshot_class.count() == 1
snapshot1 = pub.snapshot_class.get_latest('formdef', formdef.id)
formdef.fields = [StringField(id=1, label='Test', type='string')]
formdef.store()
assert pub.snapshot_class.count() == 2
snapshot2 = pub.snapshot_class.get_latest('formdef', formdef.id)
formdef.fields += [StringField(id=2, label='Test bis', type='string')]
formdef.store()
assert pub.snapshot_class.count() == 3
snapshot3 = pub.snapshot_class.get_latest('formdef', formdef.id)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/history/' % formdef.id)
assert 'name="version1" value="%s"' % snapshot3.id in resp
assert 'name="version2" value="%s"' % snapshot3.id not in resp
assert 'name="version1" value="%s"' % snapshot2.id in resp
assert 'name="version2" value="%s"' % snapshot2.id in resp
assert 'name="version1" value="%s"' % snapshot1.id not in resp
assert 'name="version2" value="%s"' % snapshot1.id in resp
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s'
% (formdef.id, snapshot1.id, snapshot3.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot1.id, snapshot1.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert resp.text.count('diff_sub') == 1
assert resp.text.count('diff_add') == 24
resp = resp.click('Compare inspect')
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot1.id, snapshot1.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert 'http://example.net/backoffice/forms/%s/fields/1/' % formdef.id in resp
assert 'http://example.net/backoffice/forms/%s/fields/2/' % formdef.id in resp
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s'
% (formdef.id, snapshot3.id, snapshot1.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot1.id, snapshot1.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert resp.text.count('diff_sub') == 1
assert resp.text.count('diff_add') == 24
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s'
% (formdef.id, snapshot2.id, snapshot3.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot2.id, snapshot2.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert resp.text.count('diff_sub') == 0
assert resp.text.count('diff_add') == 11
formdef.fields = [StringField(id=1, label='Test', type='string')]
formdef.store()
assert pub.snapshot_class.count() == 4
snapshot4 = pub.snapshot_class.get_latest('formdef', formdef.id)
resp = app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s'
% (formdef.id, snapshot3.id, snapshot4.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot4.id, snapshot4.id) in resp
assert resp.text.count('diff_sub') == 11
assert resp.text.count('diff_add') == 0
app.get('/backoffice/forms/%s/history/compare' % (formdef.id), status=404)
app.get('/backoffice/forms/%s/history/compare?version1=%s' % (formdef.id, snapshot4.id), status=404)
app.get('/backoffice/forms/%s/history/compare?version2=%s' % (formdef.id, snapshot4.id), status=404)
app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s' % (formdef.id, snapshot3.id, 0),
status=404,
)
app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s' % (formdef.id, 0, snapshot4.id),
status=404,
)
app.get(
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s&mode=foobar'
% (formdef.id, snapshot1.id, snapshot3.id),
status=404,
)
def test_form_snapshot_comments(pub):
create_superuser(pub)
create_role(pub)
@ -587,6 +593,70 @@ def test_form_snapshot_browse_with_import_error(pub):
assert 'Can not display snapshot (Unknown referenced objects [Unknown field types: foobar])' in resp
def test_workflow_snapshot_diff(pub):
create_superuser(pub)
create_role(pub)
Workflow.wipe()
workflow = Workflow(name='test')
workflow.store()
assert pub.snapshot_class.count() == 1
snapshot1 = pub.snapshot_class.get_latest('workflow', workflow.id)
workflow.add_status('Status1', 'st1')
workflow.store()
assert pub.snapshot_class.count() == 2
snapshot2 = pub.snapshot_class.get_latest('workflow', workflow.id)
ac1 = workflow.add_global_action('Action', 'ac1')
trigger = ac1.triggers[0]
assert trigger.key == 'manual'
trigger.roles = ['foobar']
workflow.store()
assert pub.snapshot_class.count() == 3
snapshot3 = pub.snapshot_class.get_latest('workflow', workflow.id)
workflow.global_actions = []
workflow.store()
assert pub.snapshot_class.count() == 4
snapshot4 = pub.snapshot_class.get_latest('workflow', workflow.id)
app = login(get_app(pub))
resp = app.get(
'/backoffice/workflows/%s/history/compare?version1=%s&version2=%s&mode=inspect'
% (workflow.id, snapshot1.id, snapshot2.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot1.id, snapshot1.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot2.id, snapshot2.id) in resp
assert 'id="tab-statuses"' in resp
assert 'id="tab-global-actions"' not in resp
resp = app.get(
'/backoffice/workflows/%s/history/compare?version1=%s&version2=%s&mode=inspect'
% (workflow.id, snapshot2.id, snapshot3.id)
)
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot2.id, snapshot2.id) in resp
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp
assert 'http://example.net/backoffice/workflows/%s/global-actions/ac1/' % (workflow.id) in resp
assert 'http://example.net/backoffice/workflows/%s/status/st1/' % workflow.id in resp
assert 'id="tab-statuses"' in resp
assert 'id="tab-global-actions"' in resp
resp = app.get(
'/backoffice/workflows/%s/history/compare?version1=%s&version2=%s&mode=inspect'
% (workflow.id, snapshot3.id, snapshot4.id)
)
assert 'id="tab-statuses"' in resp
assert 'id="tab-global-actions"' in resp
resp = app.get(
'/backoffice/workflows/%s/history/compare?version1=%s&version2=%s&mode=inspect'
% (workflow.id, snapshot1.id, snapshot4.id)
)
assert 'id="tab-statuses"' in resp
assert 'id="tab-global-actions"' not in resp
def test_workflow_snapshot_browse(pub):
create_superuser(pub)
create_role(pub)
@ -1003,6 +1073,24 @@ def test_mail_template_snapshot_restore(pub):
mail_template2 = MailTemplate.get(resp.location.split('/')[-2])
assert mail_template2.id == mail_template.id
snapshot1 = pub.snapshot_class.select_object_history(mail_template)[0]
snapshot2 = pub.snapshot_class.select_object_history(mail_template)[1]
app.get(
'/backoffice/workflows/mail-templates/%s/history/compare?version1=%s&version2=%s&mode=xml'
% (mail_template.id, snapshot1.id, snapshot2.id),
status=200,
)
app.get(
'/backoffice/workflows/mail-templates/%s/history/compare?version1=%s&version2=%s&mode=inspect'
% (mail_template.id, snapshot1.id, snapshot2.id),
status=404,
)
app.get(
'/backoffice/workflows/mail-templates/%s/history/compare?version1=%s&version2=%s&mode=foobar'
% (mail_template.id, snapshot1.id, snapshot2.id),
status=404,
)
def test_mail_template_snapshot_browse(pub):
create_superuser(pub)

View File

@ -58,7 +58,8 @@ class BlockDirectory(FieldsDirectory):
fields_count_total_hard_limit = 60
def __init__(self, section='forms', *args, **kwargs):
if kwargs.pop('component', None): # snapshot
kwargs.pop('component', None) # snapshot
if 'instance' in kwargs:
kwargs['objectdef'] = kwargs.pop('instance')
self.section = section
super().__init__(*args, **kwargs)
@ -211,6 +212,9 @@ class BlockDirectory(FieldsDirectory):
def inspect(self):
self.html_top(self.objectdef.name)
get_response().breadcrumb.append(('inspect', _('Inspector')))
return self.render_inspect()
def render_inspect(self):
context = {'blockdef': self.objectdef, 'view': self}
return template.QommonTemplateResponse(
templates=['wcs/backoffice/block-inspect.html'], context=context

View File

@ -647,7 +647,8 @@ class FormDefPage(Directory):
except KeyError:
raise TraversalError()
self.formdefui = self.formdef_ui_class(self.formdef)
get_response().breadcrumb.append((component + '/', self.formdef.name))
if component:
get_response().breadcrumb.append((component + '/', self.formdef.name))
self.fields = self.fields_directory_class(self.formdef)
self.fields.html_top = self.html_top
self.role = WorkflowRoleDirectory(self.formdef)
@ -1647,6 +1648,9 @@ class FormDefPage(Directory):
def inspect(self):
self.html_top(self.formdef.name)
get_response().breadcrumb.append(('inspect', _('Inspector')))
return self.render_inspect()
def render_inspect(self):
context = {'formdef': self.formdef, 'view': self}
if self.formdef.workflow.variables_formdef:
context['workflow_options'] = {}

View File

@ -1602,7 +1602,8 @@ class WorkflowPage(Directory):
self.criticality_levels_dir = CriticalityLevelsDirectory(self.workflow)
self.logged_errors_dir = LoggedErrorsDirectory(parent_dir=self, workflow_id=self.workflow.id)
self.snapshots_dir = SnapshotsDirectory(self.workflow)
get_response().breadcrumb.append((component + '/', self.workflow.name))
if component:
get_response().breadcrumb.append((component + '/', self.workflow.name))
def html_top(self, title):
return html_top('workflows', title)
@ -1707,6 +1708,9 @@ class WorkflowPage(Directory):
def inspect(self):
self.html_top(self.workflow.name)
get_response().breadcrumb.append(('inspect', _('Inspector')))
return self.render_inspect()
def render_inspect(self):
context = {'workflow': self.workflow, 'view': self}
return template.QommonTemplateResponse(
templates=['wcs/backoffice/workflow-inspect.html'], context=context

View File

@ -15,8 +15,11 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import difflib
import re
from django.utils.module_loading import import_string
from lxml.html.diff import htmldiff # pylint: disable=no-name-in-module
from pyquery import PyQuery as pq
from quixote import get_publisher, get_request, get_response, get_session, redirect
from quixote.directory import Directory
from quixote.html import TemplateIO, htmltext
@ -70,10 +73,14 @@ class SnapshotsDirectory(Directory):
get_response().breadcrumb.append(('compare/', _('Compare')))
html_top('', _('Compare'))
mode = get_request().form.get('mode') or 'xml'
id1 = get_request().form.get('version1')
id2 = get_request().form.get('version2')
if not id1 or not id2:
raise errors.TraversalError()
if mode not in ['xml', 'inspect']:
raise errors.TraversalError()
snapshot1 = get_publisher().snapshot_class.get(id1, ignore_errors=True)
snapshot2 = get_publisher().snapshot_class.get(id2, ignore_errors=True)
@ -82,37 +89,128 @@ class SnapshotsDirectory(Directory):
if snapshot1.timestamp > snapshot2.timestamp:
snapshot1, snapshot2 = snapshot2, snapshot1
def snapshot_desc(snapshot):
label_or_comment = ''
if snapshot.label:
label_or_comment = snapshot.label
elif snapshot.comment:
label_or_comment = snapshot.comment
return '{name} <a href="{pk}/view/">{pk}</a><br />{label_or_comment}<br />({user}{timestamp})'.format(
name=_('Snapshot'),
pk=snapshot.id,
label_or_comment=label_or_comment,
user='%s ' % snapshot.user if snapshot.user_id else '',
timestamp=misc.strftime(misc.datetime_format(), snapshot.timestamp),
)
klass = snapshot1.get_object_class()
backoffice_class = import_string(klass.backoffice_class)
has_inspect = hasattr(backoffice_class, 'render_inspect')
if mode == 'inspect' and not has_inspect:
raise errors.TraversalError()
context = getattr(self, 'get_compare_%s_context' % mode)(snapshot1, snapshot2)
context.update(
{
'mode': mode,
'has_inspect': has_inspect,
'snapshot1': snapshot1,
'snapshot2': snapshot2,
}
)
return template.QommonTemplateResponse(
templates=['wcs/backoffice/snapshots_compare.html'],
context=context,
)
def snapshot_desc(self, snapshot):
label_or_comment = ''
if snapshot.label:
label_or_comment = snapshot.label
elif snapshot.comment:
label_or_comment = snapshot.comment
return '{name} <a href="{pk}/view/">{pk}</a> - {label_or_comment} ({user}{timestamp})'.format(
name=_('Snapshot'),
pk=snapshot.id,
label_or_comment=label_or_comment,
user='%s ' % snapshot.user if snapshot.user_id else '',
timestamp=misc.strftime(misc.datetime_format(), snapshot.timestamp),
)
def get_compare_xml_context(self, snapshot1, snapshot2):
serialization1 = snapshot1.get_serialization(indented=True)
serialization2 = snapshot2.get_serialization(indented=True)
diff_serialization = difflib.HtmlDiff(wrapcolumn=160).make_table(
fromlines=serialization1.splitlines(True),
tolines=serialization2.splitlines(True),
fromdesc=snapshot_desc(snapshot1),
todesc=snapshot_desc(snapshot2),
)
return template.QommonTemplateResponse(
templates=['wcs/backoffice/snapshots_compare.html'],
context={
'snapshot1': snapshot1,
'snapshot2': snapshot2,
'diff_serialization': diff_serialization,
},
)
return {
'fromdesc': self.snapshot_desc(snapshot1),
'todesc': self.snapshot_desc(snapshot2),
'diff_serialization': diff_serialization,
}
def get_compare_inspect_context(self, snapshot1, snapshot2):
klass = snapshot1.get_object_class()
backoffice_class = import_string(klass.backoffice_class)
def clean_panel(tab):
panel = pq(tab)
# remove quicknavs
panel.find('.inspect--quicknav').remove()
# remove page & field counters, for formdef
panel.find('.page-field-counters').remove()
# remove status colors
panel.find('.inspect-status--colour').remove()
return panel.html().strip('\n')
def fix_result(panel_diff):
if not panel_diff:
return panel_diff
panel = pq(panel_diff)
# remove "Link" added by htmldiff
for link in panel.find('a'):
d = pq(link)
text = d.html()
new_text = re.sub(r' Link: .*$', '', text)
d.html(new_text)
# remove empty ins and del tags
for elem in panel.find('ins, del'):
d = pq(elem)
if not d.html().strip():
d.remove()
# prevent auto-closing behaviour of pyquery .html() method
for elem in panel.find('span, ul, div'):
d = pq(elem)
if not d.html():
d.html(' ')
# sometimes status section are misplaced by htmldiff, fix it
for elem in panel.find('div.section.status'):
d = pq(elem)
parents = d.parents('div.section.status')
if parents:
pq(parents[0]).after(d.remove())
return panel.html()
inspect1 = backoffice_class(component=None, instance=snapshot1.instance).render_inspect()
inspect1 = template.render(inspect1.templates, inspect1.context)
d1 = pq(str(inspect1))
inspect2 = backoffice_class(component=None, instance=snapshot2.instance).render_inspect()
inspect2 = template.render(inspect2.templates, inspect2.context)
d2 = pq(str(inspect2))
panels_attrs = [tab.attrib for tab in d1('[role="tabpanel"]')]
panels1 = [clean_panel(tab) for tab in d1('[role="tabpanel"]')]
panels2 = [clean_panel(tab) for tab in d2('[role="tabpanel"]')]
# build tab list (merge version 1 and version2)
tabs1 = d1.find('[role="tab"]')
tabs2 = d2.find('[role="tab"]')
tabs_order = [t.get('id') for t in panels_attrs]
tabs = {}
for tab in tabs1 + tabs2:
tab_id = pq(tab).attr('aria-controls')
tabs[tab_id] = pq(tab).outer_html()
tabs = [tabs[k] for k in tabs_order if k in tabs]
# build diff of each panel
panels_diff = list(map(htmldiff, panels1, panels2))
panels_diff = [fix_result(t) for t in panels_diff]
return {
'fromdesc': self.snapshot_desc(snapshot1),
'todesc': self.snapshot_desc(snapshot2),
'tabs': tabs,
'panels': zip(panels_attrs, panels_diff),
'tab_class_names': d1('.pk-tabs').attr('class'),
}
def snapshots(self):
current_date = None

View File

@ -969,7 +969,7 @@ div.full-screen-link {
text-align: right;
}
p.last-modification {
p.last-modification, p.snapshot-description {
font-size: 80%;
margin: 0;
}
@ -2374,8 +2374,8 @@ div.timetable-widget {
min-width: 4em;
}
.section.diff {
background: transparent;
div.diff {
margin: 1em 0;
}
table.diff {
@ -2396,6 +2396,7 @@ table.diff {
*/
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top;
}
.diff_header {
background: #f7f7f7;
@ -2419,6 +2420,30 @@ table.diff {
}
}
ins {
text-decoration: none;
background-color: #d4fcbc;
}
del {
text-decoration: line-through;
background-color: #fbb6c2;
color: #555;
}
.inspect-tabs h3 {
del, ins {
font-weight: bold;
background-color: transparent;
}
del, del a {
color: #fbb6c2 !important;
}
ins, ins a {
color: #d4fcbc !important;
}
}
#sidebar .operator-and-value-widget {
.title-and-operator {
display: flex;

View File

@ -22,7 +22,7 @@
<div id="inspect-fields" role="tabpanel" tabindex="0" aria-labelledby="tab-fields" hidden>
{% for field in blockdef.fields %}
{% include "wcs/backoffice/includes/inspect-field.html" %}
{% include "wcs/backoffice/includes/inspect-field.html" with path=blockdef.get_admin_url %}
{% endfor %}
</div>
</div>

View File

@ -29,7 +29,7 @@
<li><span class="parameter">{% trans "Options" %}{% trans ":" %}</span> {% if not workflow_options %}-{% else %}<ul>
{% for label, value in workflow_options.items %}
{% if value == '__title__' or value == '__subtitle__' %}<li><strong>{{ label }}</strong></li>
{% elif value == '__comment__' %}<li><{{ label }}</li>
{% elif value == '__comment__' %}<li>{{ label }}</li>
{% else %}
<li>{{ label }} → {{ value|safe|default:"-" }}</li>
{% endif %}
@ -73,12 +73,12 @@
</div>
<div id="inspect-fields" role="tabpanel" tabindex="0" aria-labelledby="tab-fields" hidden>
<div class="pk-information"><p>
<div class="pk-information page-field-counters"><p>
{% blocktrans count page_count=formdef.page_count %}{{ page_count }} page{% plural %}{{ page_count }} pages{% endblocktrans %},
{% blocktrans count fields_count=formdef.fields|count %}{{ fields_count }} field{% plural %}{{ fields_count }} fields.{% endblocktrans %}
</p></div>
{% for field in formdef.fields %}
{% include "wcs/backoffice/includes/inspect-field.html" %}
{% include "wcs/backoffice/includes/inspect-field.html" with path=formdef.get_admin_url|add:"fields/" %}
{% endfor %}
</div>
</div>

View File

@ -1,11 +1,33 @@
{% extends "wcs/backoffice/base.html" %}
{% load i18n %}
{% block body %}
<div id="appbar">
<h2>{% trans "Compare snapshots" %}</h2>
</div>
{% block appbar-title %}{% trans "Compare snapshots" %}{% if has_inspect %} ({% if mode == 'xml' %}{% trans "XML" %}{% else %}{% trans "Inspect" %}{% endif %}){% endif %}{% endblock %}
{% block appbar-actions %}
{% if has_inspect %}
<a href="?version1={{ snapshot1.id }}&version2={{ snapshot2.id }}&mode=inspect">{% trans "Compare inspect" %}</a>
<a href="?version1={{ snapshot1.id }}&version2={{ snapshot2.id }}&mode=xml">{% trans "Compare XML" %}</a>
{% endif %}
{% endblock %}
<div class="section diff">
{{ diff_serialization|safe }}
{% block content %}
<p class="snapshot-description">{{ fromdesc|safe }} ➔ {{ todesc|safe }}</p>
<div class="diff">
{% if mode == 'xml' %}
{{ diff_serialization|safe }}
{% else %}
<div class="{{ tab_class_names }}">
<div class="pk-tabs--tab-list" role="tablist">
{% for tab in tabs %}{{ tab|safe }}{% endfor %}
{{ tab_list|safe }}
</div>
<div class="pk-tabs--container">
{% for attrs, panel in panels %}
<div{% for k, v in attrs.items %} {{ k }}="{{ v }}"{% endfor %}>
{{ panel|safe }}
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
{% endblock %}

View File

@ -24,32 +24,6 @@
</div>
<div class="pk-tabs--container">
<div id="inspect-functions" role="tabpanel" tabindex="0" aria-labelledby="tab-functions" hidden>
<ul>
{% for label in workflow.roles.values %}
<li>{{ label }}</li>
{% endfor %}
</ul>
</div>
<div id="inspect-variables" role="tabpanel" tabindex="0" aria-labelledby="tab-variables" hidden>
{% for field in workflow.variables_formdef.fields %}
{% include "wcs/backoffice/includes/inspect-field.html" with path="variables/fields/" %}
{% endfor %}
</div>
<div id="inspect-fields" role="tabpanel" tabindex="0" aria-labelledby="tab-fields" hidden>
{% for field in workflow.backoffice_fields_formdef.fields %}
{% include "wcs/backoffice/includes/inspect-field.html" with path="backoffice-fields/fields/" %}
{% endfor %}
</div>
<div id="inspect-criticality" role="tabpanel" tabindex="0" aria-labelledby="tab-criticality" hidden>
<ul>
{% for level in workflow.criticality_levels %}<li>{{ level.name }}</li>{% endfor %}
</ul>
</div>
<div id="inspect-statuses" role="tabpanel" tabindex="0" aria-labelledby="tab-statuses">
<nav class="inspect--quicknav"><span class="inspect--jumpto">{% trans "Jump to:" %}</span><ul class="inspect--quicklinks">
{% for status in workflow.possible_status %}
@ -60,12 +34,12 @@
{% for status in workflow.possible_status %}
<div class="section status">
<h3 id="status-{{ status.id }}"
><a href="status/{{ status.id }}/" class="inspect-status--link">
><a href="{{ workflow.get_admin_url }}status/{{ status.id }}/" class="inspect-status--link">
<span class="inspect-status--colour" style="background-color: #{{ status.colour|default:"fff" }}"></span>
{{ status.name }}</a></h3>
{% if status.backoffice_info_text %}<div>{{ status.backoffice_info_text|safe }}</div>{% endif %}
{% for item in status.items %}
<h4><a href="status/{{ status.id }}/items/{{ item.id }}/">{{ item.description }}</a></h4>
<h4><a href="{{ workflow.get_admin_url }}status/{{ status.id }}/items/{{ item.id }}/">{{ item.description }}</a></h4>
{{ item.get_parameters_view|safe }}
{% empty %}
<p>{% trans "No actions in this status." %}</p>
@ -84,11 +58,11 @@
<div class="expanded-statuses">
{% for action in workflow.global_actions %}
<div class="section global-action">
<h3><a id="action-{{ action.id }}" href="global-actions/{{ action.id }}/">{{ action.name }}</a></h3>
<h3><a id="action-{{ action.id }}" href="{{ workflow.get_admin_url }}global-actions/{{ action.id }}/">{{ action.name }}</a></h3>
<h4>{% trans "Triggers" %}</h4>
<ul>{% for trigger in action.triggers %}<li>{{ trigger.render_as_line }}</li>{% endfor %}</ul>
{% for item in action.items %}
<h4><a href="global-actions/{{ action.id }}/items/{{ item.id }}/">{{ item.description }}</a></h4>
<h4><a href="{{ workflow.get_admin_url }}global-actions/{{ action.id }}/items/{{ item.id }}/">{{ item.description }}</a></h4>
{{ item.get_parameters_view|safe }}
{% endfor %}
</div>
@ -96,6 +70,32 @@
</div>
</div>
<div id="inspect-functions" role="tabpanel" tabindex="0" aria-labelledby="tab-functions" hidden>
<ul>
{% for label in workflow.roles.values %}
<li>{{ label }}</li>
{% endfor %}
</ul>
</div>
<div id="inspect-variables" role="tabpanel" tabindex="0" aria-labelledby="tab-variables" hidden>
{% for field in workflow.variables_formdef.fields %}
{% include "wcs/backoffice/includes/inspect-field.html" with path=workflow.get_admin_url|add:"variables/fields/" %}
{% endfor %}
</div>
<div id="inspect-fields" role="tabpanel" tabindex="0" aria-labelledby="tab-fields" hidden>
{% for field in workflow.backoffice_fields_formdef.fields %}
{% include "wcs/backoffice/includes/inspect-field.html" with path=workflow.get_admin_url|add:"backoffice-fields/fields/" %}
{% endfor %}
</div>
<div id="inspect-criticality" role="tabpanel" tabindex="0" aria-labelledby="tab-criticality" hidden>
<ul>
{% for level in workflow.criticality_levels %}<li>{{ level.name }}</li>{% endfor %}
</ul>
</div>
</div> <!-- pk-tabs-container -->
</div> <!-- pk-tabs -->
{% endblock %}