0001-snapshot-compare-inspect-of-2-versions-66565.patch
debian/control | ||
---|---|---|
24 | 24 |
python3-dnspython, |
25 | 25 |
python3-hobo, |
26 | 26 |
python3-lasso, |
27 |
python3-lxml, |
|
27 | 28 |
python3-pil, |
28 | 29 |
python3-psycopg2, |
29 | 30 |
python3-pyproj, |
setup.py | ||
---|---|---|
179 | 179 |
'XStatic-Select2', |
180 | 180 |
'pyproj', |
181 | 181 |
'unidecode', |
182 |
'lxml', |
|
182 | 183 |
], |
183 | 184 |
package_dir={'wcs': 'wcs'}, |
184 | 185 |
packages=find_packages(), |
tests/test_snapshots.py | ||
---|---|---|
152 | 152 |
assert [int(f.id) for f in snapshot6.instance.fields] == list(range(0, 12)) |
153 | 153 | |
154 | 154 | |
155 |
def test_snapshot_diff(pub): |
|
155 |
def test_snapshot_instance(pub): |
|
156 |
formdef = FormDef() |
|
157 |
formdef.name = 'testform' |
|
158 |
formdef.fields = [] |
|
159 |
formdef.store() |
|
160 | ||
161 |
carddef = CardDef() |
|
162 |
carddef.name = 'testcard' |
|
163 |
carddef.fields = [] |
|
164 |
carddef.store() |
|
165 | ||
166 |
# remove existing snapshots as they may be duplicated if table_name was |
|
167 |
# generated in a different second. |
|
168 |
pub.snapshot_class.wipe() |
|
169 | ||
170 |
carddef.name = 'testcard2' |
|
171 |
carddef.store() |
|
172 | ||
173 |
for i in range(10): |
|
174 |
formdef.name = 'testform %s' % i |
|
175 |
formdef.store() |
|
176 | ||
177 |
assert pub.snapshot_class.count() == 11 |
|
178 | ||
179 |
snapshots = pub.snapshot_class.select_object_history(formdef) |
|
180 |
assert len(snapshots) == 10 |
|
181 |
for i in range(10): |
|
182 |
assert snapshots[i].serialization is None # not loaded |
|
183 |
assert snapshots[i].patch is None # not loaded |
|
184 |
assert pub.snapshot_class.get(snapshots[i].id).instance.name == 'testform %s' % (9 - i) |
|
185 | ||
186 |
snapshots = pub.snapshot_class.select_object_history(carddef) |
|
187 |
assert len(snapshots) == 1 |
|
188 | ||
189 | ||
190 |
def test_snapshot_user(pub): |
|
191 |
user = pub.user_class() |
|
192 |
user.name = 'User Name' |
|
193 |
user.email = 'foo@localhost' |
|
194 |
user.store() |
|
195 | ||
196 |
carddef = CardDef() |
|
197 |
carddef.name = 'testcard' |
|
198 |
carddef.fields = [] |
|
199 |
carddef.store() |
|
200 |
snapshot = pub.snapshot_class.select_object_history(carddef)[0] |
|
201 |
assert snapshot.user is None |
|
202 | ||
203 |
snapshot.user_id = user.id |
|
204 |
snapshot.store() |
|
205 |
snapshot = pub.snapshot_class.select_object_history(carddef)[0] |
|
206 |
assert str(snapshot.user) == 'User Name' |
|
207 | ||
208 |
snapshot.user_id = 'nope' |
|
209 |
snapshot.store() |
|
210 |
snapshot = pub.snapshot_class.select_object_history(carddef)[0] |
|
211 |
assert str(snapshot.user) == 'unknown user' |
|
212 | ||
213 | ||
214 |
def test_form_snapshot_diff(pub): |
|
156 | 215 |
create_superuser(pub) |
157 | 216 |
create_role(pub) |
158 | 217 | |
... | ... | |
190 | 249 |
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp |
191 | 250 |
assert resp.text.count('diff_sub') == 1 |
192 | 251 |
assert resp.text.count('diff_add') == 24 |
252 |
resp = resp.click('Compare inspect') |
|
253 |
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot1.id, snapshot1.id) in resp |
|
254 |
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp |
|
255 |
assert 'http://example.net/backoffice/forms/%s/fields/1/' % formdef.id in resp |
|
256 |
assert 'http://example.net/backoffice/forms/%s/fields/2/' % formdef.id in resp |
|
193 | 257 | |
194 | 258 |
resp = app.get( |
195 | 259 |
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s' |
... | ... | |
223 | 287 |
assert resp.text.count('diff_sub') == 11 |
224 | 288 |
assert resp.text.count('diff_add') == 0 |
225 | 289 | |
226 |
resp = app.get('/backoffice/forms/%s/history/compare' % (formdef.id), status=404) |
|
227 |
resp = app.get( |
|
228 |
'/backoffice/forms/%s/history/compare?version1=%s' % (formdef.id, snapshot4.id), status=404 |
|
229 |
) |
|
230 |
resp = app.get( |
|
231 |
'/backoffice/forms/%s/history/compare?version2=%s' % (formdef.id, snapshot4.id), status=404 |
|
232 |
) |
|
233 |
resp = app.get( |
|
290 |
app.get('/backoffice/forms/%s/history/compare' % (formdef.id), status=404) |
|
291 |
app.get('/backoffice/forms/%s/history/compare?version1=%s' % (formdef.id, snapshot4.id), status=404) |
|
292 |
app.get('/backoffice/forms/%s/history/compare?version2=%s' % (formdef.id, snapshot4.id), status=404) |
|
293 |
app.get( |
|
234 | 294 |
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s' % (formdef.id, snapshot3.id, 0), |
235 | 295 |
status=404, |
236 | 296 |
) |
237 |
resp = app.get(
|
|
297 |
app.get( |
|
238 | 298 |
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s' % (formdef.id, 0, snapshot4.id), |
239 | 299 |
status=404, |
240 | 300 |
) |
241 | ||
242 | ||
243 |
def test_snapshot_instance(pub): |
|
244 |
formdef = FormDef() |
|
245 |
formdef.name = 'testform' |
|
246 |
formdef.fields = [] |
|
247 |
formdef.store() |
|
248 | ||
249 |
carddef = CardDef() |
|
250 |
carddef.name = 'testcard' |
|
251 |
carddef.fields = [] |
|
252 |
carddef.store() |
|
253 | ||
254 |
# remove existing snapshots as they may be duplicated if table_name was |
|
255 |
# generated in a different second. |
|
256 |
pub.snapshot_class.wipe() |
|
257 | ||
258 |
carddef.name = 'testcard2' |
|
259 |
carddef.store() |
|
260 | ||
261 |
for i in range(10): |
|
262 |
formdef.name = 'testform %s' % i |
|
263 |
formdef.store() |
|
264 | ||
265 |
assert pub.snapshot_class.count() == 11 |
|
266 | ||
267 |
snapshots = pub.snapshot_class.select_object_history(formdef) |
|
268 |
assert len(snapshots) == 10 |
|
269 |
for i in range(10): |
|
270 |
assert snapshots[i].serialization is None # not loaded |
|
271 |
assert snapshots[i].patch is None # not loaded |
|
272 |
assert pub.snapshot_class.get(snapshots[i].id).instance.name == 'testform %s' % (9 - i) |
|
273 | ||
274 |
snapshots = pub.snapshot_class.select_object_history(carddef) |
|
275 |
assert len(snapshots) == 1 |
|
276 | ||
277 | ||
278 |
def test_snapshot_user(pub): |
|
279 |
user = pub.user_class() |
|
280 |
user.name = 'User Name' |
|
281 |
user.email = 'foo@localhost' |
|
282 |
user.store() |
|
283 | ||
284 |
carddef = CardDef() |
|
285 |
carddef.name = 'testcard' |
|
286 |
carddef.fields = [] |
|
287 |
carddef.store() |
|
288 |
snapshot = pub.snapshot_class.select_object_history(carddef)[0] |
|
289 |
assert snapshot.user is None |
|
290 | ||
291 |
snapshot.user_id = user.id |
|
292 |
snapshot.store() |
|
293 |
snapshot = pub.snapshot_class.select_object_history(carddef)[0] |
|
294 |
assert str(snapshot.user) == 'User Name' |
|
295 | ||
296 |
snapshot.user_id = 'nope' |
|
297 |
snapshot.store() |
|
298 |
snapshot = pub.snapshot_class.select_object_history(carddef)[0] |
|
299 |
assert str(snapshot.user) == 'unknown user' |
|
301 |
app.get( |
|
302 |
'/backoffice/forms/%s/history/compare?version1=%s&version2=%s&mode=foobar' |
|
303 |
% (formdef.id, snapshot1.id, snapshot3.id), |
|
304 |
status=404, |
|
305 |
) |
|
300 | 306 | |
301 | 307 | |
302 | 308 |
def test_form_snapshot_comments(pub): |
... | ... | |
588 | 594 |
assert 'Can not display snapshot (Unknown referenced objects [Unknown field types: foobar])' in resp |
589 | 595 | |
590 | 596 | |
597 |
def test_workflow_snapshot_diff(pub): |
|
598 |
create_superuser(pub) |
|
599 |
create_role(pub) |
|
600 | ||
601 |
Workflow.wipe() |
|
602 |
workflow = Workflow(name='test') |
|
603 |
workflow.store() |
|
604 |
assert pub.snapshot_class.count() == 1 |
|
605 |
snapshot1 = pub.snapshot_class.get_latest('workflow', workflow.id) |
|
606 | ||
607 |
workflow.add_status('Status1', 'st1') |
|
608 |
workflow.store() |
|
609 |
assert pub.snapshot_class.count() == 2 |
|
610 |
snapshot2 = pub.snapshot_class.get_latest('workflow', workflow.id) |
|
611 | ||
612 |
ac1 = workflow.add_global_action('Action', 'ac1') |
|
613 |
trigger = ac1.triggers[0] |
|
614 |
assert trigger.key == 'manual' |
|
615 |
trigger.roles = ['foobar'] |
|
616 |
workflow.store() |
|
617 |
assert pub.snapshot_class.count() == 3 |
|
618 |
snapshot3 = pub.snapshot_class.get_latest('workflow', workflow.id) |
|
619 | ||
620 |
workflow.global_actions = [] |
|
621 |
workflow.store() |
|
622 |
assert pub.snapshot_class.count() == 4 |
|
623 |
snapshot4 = pub.snapshot_class.get_latest('workflow', workflow.id) |
|
624 | ||
625 |
app = login(get_app(pub)) |
|
626 |
resp = app.get( |
|
627 |
'/backoffice/workflows/%s/history/compare?version1=%s&version2=%s&mode=inspect' |
|
628 |
% (workflow.id, snapshot1.id, snapshot2.id) |
|
629 |
) |
|
630 |
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot1.id, snapshot1.id) in resp |
|
631 |
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot2.id, snapshot2.id) in resp |
|
632 |
assert 'id="tab-statuses"' in resp |
|
633 |
assert 'id="tab-global-actions"' not in resp |
|
634 | ||
635 |
resp = app.get( |
|
636 |
'/backoffice/workflows/%s/history/compare?version1=%s&version2=%s&mode=inspect' |
|
637 |
% (workflow.id, snapshot2.id, snapshot3.id) |
|
638 |
) |
|
639 |
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot2.id, snapshot2.id) in resp |
|
640 |
assert 'Snapshot <a href="%s/view/">%s</a>' % (snapshot3.id, snapshot3.id) in resp |
|
641 |
assert 'http://example.net/backoffice/workflows/%s/global-actions/ac1/' % (workflow.id) in resp |
|
642 |
assert 'http://example.net/backoffice/workflows/%s/status/st1/' % workflow.id in resp |
|
643 |
assert 'id="tab-statuses"' in resp |
|
644 |
assert 'id="tab-global-actions"' in resp |
|
645 | ||
646 |
resp = app.get( |
|
647 |
'/backoffice/workflows/%s/history/compare?version1=%s&version2=%s&mode=inspect' |
|
648 |
% (workflow.id, snapshot3.id, snapshot4.id) |
|
649 |
) |
|
650 |
assert 'id="tab-statuses"' in resp |
|
651 |
assert 'id="tab-global-actions"' in resp |
|
652 | ||
653 |
resp = app.get( |
|
654 |
'/backoffice/workflows/%s/history/compare?version1=%s&version2=%s&mode=inspect' |
|
655 |
% (workflow.id, snapshot1.id, snapshot4.id) |
|
656 |
) |
|
657 |
assert 'id="tab-statuses"' in resp |
|
658 |
assert 'id="tab-global-actions"' not in resp |
|
659 | ||
660 | ||
591 | 661 |
def test_workflow_snapshot_browse(pub): |
592 | 662 |
create_superuser(pub) |
593 | 663 |
create_role(pub) |
... | ... | |
1004 | 1074 |
mail_template2 = MailTemplate.get(resp.location.split('/')[-2]) |
1005 | 1075 |
assert mail_template2.id == mail_template.id |
1006 | 1076 | |
1077 |
snapshot1 = pub.snapshot_class.select_object_history(mail_template)[0] |
|
1078 |
snapshot2 = pub.snapshot_class.select_object_history(mail_template)[1] |
|
1079 |
app.get( |
|
1080 |
'/backoffice/workflows/mail-templates/%s/history/compare?version1=%s&version2=%s&mode=xml' |
|
1081 |
% (mail_template.id, snapshot1.id, snapshot2.id), |
|
1082 |
status=200, |
|
1083 |
) |
|
1084 |
app.get( |
|
1085 |
'/backoffice/workflows/mail-templates/%s/history/compare?version1=%s&version2=%s&mode=inspect' |
|
1086 |
% (mail_template.id, snapshot1.id, snapshot2.id), |
|
1087 |
status=404, |
|
1088 |
) |
|
1089 |
app.get( |
|
1090 |
'/backoffice/workflows/mail-templates/%s/history/compare?version1=%s&version2=%s&mode=foobar' |
|
1091 |
% (mail_template.id, snapshot1.id, snapshot2.id), |
|
1092 |
status=404, |
|
1093 |
) |
|
1094 | ||
1007 | 1095 | |
1008 | 1096 |
def test_mail_template_snapshot_browse(pub): |
1009 | 1097 |
create_superuser(pub) |
wcs/admin/blocks.py | ||
---|---|---|
58 | 58 |
fields_count_total_hard_limit = 30 |
59 | 59 | |
60 | 60 |
def __init__(self, section='forms', *args, **kwargs): |
61 |
if kwargs.pop('component', None): # snapshot |
|
61 |
kwargs.pop('component', None) # snapshot |
|
62 |
if 'instance' in kwargs: |
|
62 | 63 |
kwargs['objectdef'] = kwargs.pop('instance') |
63 | 64 |
self.section = section |
64 | 65 |
super().__init__(*args, **kwargs) |
... | ... | |
211 | 212 |
def inspect(self): |
212 | 213 |
self.html_top(self.objectdef.name) |
213 | 214 |
get_response().breadcrumb.append(('inspect', _('Inspector'))) |
215 |
return self.render_inspect() |
|
216 | ||
217 |
def render_inspect(self): |
|
214 | 218 |
context = {'blockdef': self.objectdef, 'view': self} |
215 | 219 |
return template.QommonTemplateResponse( |
216 | 220 |
templates=['wcs/backoffice/block-inspect.html'], context=context |
wcs/admin/forms.py | ||
---|---|---|
650 | 650 |
except KeyError: |
651 | 651 |
raise TraversalError() |
652 | 652 |
self.formdefui = self.formdef_ui_class(self.formdef) |
653 |
get_response().breadcrumb.append((component + '/', self.formdef.name)) |
|
653 |
if component: |
|
654 |
get_response().breadcrumb.append((component + '/', self.formdef.name)) |
|
654 | 655 |
self.fields = self.fields_directory_class(self.formdef) |
655 | 656 |
self.fields.html_top = self.html_top |
656 | 657 |
self.role = WorkflowRoleDirectory(self.formdef) |
... | ... | |
1753 | 1754 |
def inspect(self): |
1754 | 1755 |
self.html_top(self.formdef.name) |
1755 | 1756 |
get_response().breadcrumb.append(('inspect', _('Inspector'))) |
1757 |
return self.render_inspect() |
|
1758 | ||
1759 |
def render_inspect(self): |
|
1756 | 1760 |
context = {'formdef': self.formdef, 'view': self} |
1757 | 1761 |
if self.formdef.workflow.variables_formdef: |
1758 | 1762 |
context['workflow_options'] = {} |
wcs/admin/workflows.py | ||
---|---|---|
1586 | 1586 |
self.criticality_levels_dir = CriticalityLevelsDirectory(self.workflow) |
1587 | 1587 |
self.logged_errors_dir = LoggedErrorsDirectory(parent_dir=self, workflow_id=self.workflow.id) |
1588 | 1588 |
self.snapshots_dir = SnapshotsDirectory(self.workflow) |
1589 |
get_response().breadcrumb.append((component + '/', self.workflow.name)) |
|
1589 |
if component: |
|
1590 |
get_response().breadcrumb.append((component + '/', self.workflow.name)) |
|
1590 | 1591 | |
1591 | 1592 |
def html_top(self, title): |
1592 | 1593 |
return html_top('workflows', title) |
... | ... | |
1679 | 1680 |
def inspect(self): |
1680 | 1681 |
self.html_top(self.workflow.name) |
1681 | 1682 |
get_response().breadcrumb.append(('inspect', _('Inspector'))) |
1683 |
return self.render_inspect() |
|
1684 | ||
1685 |
def render_inspect(self): |
|
1682 | 1686 |
context = {'workflow': self.workflow, 'view': self} |
1683 | 1687 |
return template.QommonTemplateResponse( |
1684 | 1688 |
templates=['wcs/backoffice/workflow-inspect.html'], context=context |
wcs/backoffice/snapshots.py | ||
---|---|---|
15 | 15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | 17 |
import difflib |
18 |
import re |
|
18 | 19 | |
19 | 20 |
from django.utils.module_loading import import_string |
21 |
from lxml.html.diff import htmldiff |
|
22 |
from pyquery import PyQuery as pq |
|
20 | 23 |
from quixote import get_publisher, get_request, get_response, get_session, redirect |
21 | 24 |
from quixote.directory import Directory |
22 | 25 |
from quixote.html import TemplateIO, htmltext |
... | ... | |
70 | 73 |
get_response().breadcrumb.append(('compare/', _('Compare'))) |
71 | 74 |
html_top('', _('Compare')) |
72 | 75 | |
76 |
mode = get_request().form.get('mode') or 'xml' |
|
77 | ||
73 | 78 |
id1 = get_request().form.get('version1') |
74 | 79 |
id2 = get_request().form.get('version2') |
75 | 80 |
if not id1 or not id2: |
76 | 81 |
raise errors.TraversalError() |
82 |
if mode not in ['xml', 'inspect']: |
|
83 |
raise errors.TraversalError() |
|
77 | 84 | |
78 | 85 |
snapshot1 = get_publisher().snapshot_class.get(id1, ignore_errors=True) |
79 | 86 |
snapshot2 = get_publisher().snapshot_class.get(id2, ignore_errors=True) |
... | ... | |
82 | 89 |
if snapshot1.timestamp > snapshot2.timestamp: |
83 | 90 |
snapshot1, snapshot2 = snapshot2, snapshot1 |
84 | 91 | |
85 |
def snapshot_desc(snapshot): |
|
86 |
label_or_comment = '' |
|
87 |
if snapshot.label: |
|
88 |
label_or_comment = snapshot.label |
|
89 |
elif snapshot.comment: |
|
90 |
label_or_comment = snapshot.comment |
|
91 |
return '{name} <a href="{pk}/view/">{pk}</a><br />{label_or_comment}<br />({user}{timestamp})'.format( |
|
92 |
name=_('Snapshot'), |
|
93 |
pk=snapshot.id, |
|
94 |
label_or_comment=label_or_comment, |
|
95 |
user='%s ' % snapshot.user if snapshot.user_id else '', |
|
96 |
timestamp=misc.strftime(misc.datetime_format(), snapshot.timestamp), |
|
97 |
) |
|
92 |
klass = snapshot1.get_object_class() |
|
93 |
backoffice_class = import_string(klass.backoffice_class) |
|
94 |
has_inspect = hasattr(backoffice_class, 'render_inspect') |
|
95 | ||
96 |
if mode == 'inspect' and not has_inspect: |
|
97 |
raise errors.TraversalError() |
|
98 | ||
99 |
context = getattr(self, 'get_compare_%s_context' % mode)(snapshot1, snapshot2) |
|
100 |
context.update( |
|
101 |
{ |
|
102 |
'mode': mode, |
|
103 |
'has_inspect': has_inspect, |
|
104 |
'snapshot1': snapshot1, |
|
105 |
'snapshot2': snapshot2, |
|
106 |
} |
|
107 |
) |
|
108 |
return template.QommonTemplateResponse( |
|
109 |
templates=['wcs/backoffice/snapshots_compare.html'], |
|
110 |
context=context, |
|
111 |
) |
|
112 | ||
113 |
def snapshot_desc(self, snapshot): |
|
114 |
label_or_comment = '' |
|
115 |
if snapshot.label: |
|
116 |
label_or_comment = snapshot.label |
|
117 |
elif snapshot.comment: |
|
118 |
label_or_comment = snapshot.comment |
|
119 |
return '{name} <a href="{pk}/view/">{pk}</a> - {label_or_comment} ({user}{timestamp})'.format( |
|
120 |
name=_('Snapshot'), |
|
121 |
pk=snapshot.id, |
|
122 |
label_or_comment=label_or_comment, |
|
123 |
user='%s ' % snapshot.user if snapshot.user_id else '', |
|
124 |
timestamp=misc.strftime(misc.datetime_format(), snapshot.timestamp), |
|
125 |
) |
|
98 | 126 | |
127 |
def get_compare_xml_context(self, snapshot1, snapshot2): |
|
99 | 128 |
serialization1 = snapshot1.get_serialization(indented=True) |
100 | 129 |
serialization2 = snapshot2.get_serialization(indented=True) |
101 | 130 |
diff_serialization = difflib.HtmlDiff(wrapcolumn=160).make_table( |
102 | 131 |
fromlines=serialization1.splitlines(True), |
103 | 132 |
tolines=serialization2.splitlines(True), |
104 |
fromdesc=snapshot_desc(snapshot1),
|
|
105 |
todesc=snapshot_desc(snapshot2),
|
|
133 |
fromdesc=None,
|
|
134 |
todesc=None,
|
|
106 | 135 |
) |
107 | 136 | |
108 |
return template.QommonTemplateResponse( |
|
109 |
templates=['wcs/backoffice/snapshots_compare.html'], |
|
110 |
context={ |
|
111 |
'snapshot1': snapshot1, |
|
112 |
'snapshot2': snapshot2, |
|
113 |
'diff_serialization': diff_serialization, |
|
114 |
}, |
|
115 |
) |
|
137 |
return { |
|
138 |
'fromdesc': self.snapshot_desc(snapshot1), |
|
139 |
'todesc': self.snapshot_desc(snapshot2), |
|
140 |
'diff_serialization': diff_serialization, |
|
141 |
} |
|
142 | ||
143 |
def get_compare_inspect_context(self, snapshot1, snapshot2): |
|
144 |
klass = snapshot1.get_object_class() |
|
145 |
backoffice_class = import_string(klass.backoffice_class) |
|
146 | ||
147 |
def fix_result(panel_diff): |
|
148 |
if not panel_diff: |
|
149 |
return panel_diff |
|
150 |
panel = pq(panel_diff) |
|
151 |
# remove "Link" added by htmldiff |
|
152 |
for link in panel.find('a'): |
|
153 |
d = pq(link) |
|
154 |
text = d.html() |
|
155 |
new_text = re.sub(r' Link: .*$', '', text) |
|
156 |
d.html(new_text) |
|
157 |
# remove empty ins and del tags |
|
158 |
for elem in panel.find('ins, del'): |
|
159 |
d = pq(elem) |
|
160 |
if not d.html().strip(): |
|
161 |
d.remove() |
|
162 |
# prevent auto-closing behaviour of pyquery .html() method |
|
163 |
for elem in panel.find('span, ul, div'): |
|
164 |
d = pq(elem) |
|
165 |
if not d.html(): |
|
166 |
d.html(' ') |
|
167 |
return panel.html() |
|
168 | ||
169 |
inspect1 = backoffice_class(component=None, instance=snapshot1.instance).render_inspect() |
|
170 |
inspect1 = template.render(inspect1.templates, inspect1.context) |
|
171 |
d1 = pq(str(inspect1)) |
|
172 |
inspect2 = backoffice_class(component=None, instance=snapshot2.instance).render_inspect() |
|
173 |
inspect2 = template.render(inspect2.templates, inspect2.context) |
|
174 |
d2 = pq(str(inspect2)) |
|
175 |
panels_attrs = [tab.attrib for tab in d1('[role="tabpanel"]')] |
|
176 |
panels1 = [pq(tab).html().strip('\n') for tab in d1('[role="tabpanel"]')] |
|
177 |
panels2 = [pq(tab).html().strip('\n') for tab in d2('[role="tabpanel"]')] |
|
178 | ||
179 |
# build tab list (merge version 1 and version2) |
|
180 |
tabs1 = d1.find('[role="tab"]') |
|
181 |
tabs2 = d2.find('[role="tab"]') |
|
182 |
tabs_order = [t.get('id') for t in panels_attrs] |
|
183 |
tabs = {} |
|
184 |
for tab in tabs1 + tabs2: |
|
185 |
tab_id = pq(tab).attr('aria-controls') |
|
186 |
tabs[tab_id] = pq(tab).outer_html() |
|
187 |
tabs = [tabs[k] for k in tabs_order if k in tabs] |
|
188 | ||
189 |
# build diff of each panel |
|
190 |
panels_diff = list(map(htmldiff, panels1, panels2)) |
|
191 |
panels_diff = [fix_result(t) for t in panels_diff] |
|
192 | ||
193 |
return { |
|
194 |
'fromdesc': self.snapshot_desc(snapshot1), |
|
195 |
'todesc': self.snapshot_desc(snapshot2), |
|
196 |
'tabs': tabs, |
|
197 |
'panels': zip(panels_attrs, panels_diff), |
|
198 |
'tab_class_names': d1('.pk-tabs').attr('class'), |
|
199 |
} |
|
116 | 200 | |
117 | 201 |
def snapshots(self): |
118 | 202 |
current_date = None |
wcs/qommon/static/css/dc2/admin.scss | ||
---|---|---|
969 | 969 |
text-align: right; |
970 | 970 |
} |
971 | 971 | |
972 |
p.last-modification { |
|
972 |
p.last-modification, p.snapshot-description {
|
|
973 | 973 |
font-size: 80%; |
974 | 974 |
margin: 0; |
975 | 975 |
} |
... | ... | |
2370 | 2370 |
min-width: 4em; |
2371 | 2371 |
} |
2372 | 2372 | |
2373 |
.section.diff {
|
|
2374 |
background: transparent;
|
|
2373 |
div.diff {
|
|
2374 |
margin: 1em 0;
|
|
2375 | 2375 |
} |
2376 | 2376 | |
2377 | 2377 |
table.diff { |
... | ... | |
2392 | 2392 |
*/ |
2393 | 2393 |
overflow: hidden; |
2394 | 2394 |
text-overflow: ellipsis; |
2395 |
vertical-align: top; |
|
2395 | 2396 |
} |
2396 | 2397 |
.diff_header { |
2397 | 2398 |
background: #f7f7f7; |
... | ... | |
2414 | 2415 |
background-color: #ffaaaa; |
2415 | 2416 |
} |
2416 | 2417 |
} |
2418 |
ins { |
|
2419 |
text-decoration: none; |
|
2420 |
background-color: #d4fcbc; |
|
2421 |
} |
|
2422 | ||
2423 |
del { |
|
2424 |
text-decoration: line-through; |
|
2425 |
background-color: #fbb6c2; |
|
2426 |
color: #555; |
|
2427 |
} |
|
2417 | 2428 | |
2418 | 2429 |
#sidebar .operator-and-value-widget { |
2419 | 2430 |
.title-and-operator { |
wcs/templates/wcs/backoffice/block-inspect.html | ||
---|---|---|
22 | 22 | |
23 | 23 |
<div id="inspect-fields" role="tabpanel" tabindex="0" aria-labelledby="tab-fields" hidden> |
24 | 24 |
{% for field in blockdef.fields %} |
25 |
{% include "wcs/backoffice/includes/inspect-field.html" %} |
|
25 |
{% include "wcs/backoffice/includes/inspect-field.html" with path=blockdef.get_admin_url %}
|
|
26 | 26 |
{% endfor %} |
27 | 27 |
</div> |
28 | 28 |
</div> |
wcs/templates/wcs/backoffice/formdef-inspect.html | ||
---|---|---|
29 | 29 |
<li><span class="parameter">{% trans "Options" %}{% trans ":" %}</span> {% if not workflow_options %}-{% else %}<ul> |
30 | 30 |
{% for label, value in workflow_options.items %} |
31 | 31 |
{% if value == '__title__' or value == '__subtitle__' %}<li><strong>{{ label }}</strong></li> |
32 |
{% elif value == '__comment__' %}<li><{{ label }}</li>
|
|
32 |
{% elif value == '__comment__' %}<li>{{ label }}</li> |
|
33 | 33 |
{% else %} |
34 | 34 |
<li>{{ label }} → {{ value|safe|default:"-" }}</li> |
35 | 35 |
{% endif %} |
... | ... | |
78 | 78 |
{% blocktrans count fields_count=formdef.fields|count %}{{ fields_count }} field{% plural %}{{ fields_count }} fields.{% endblocktrans %} |
79 | 79 |
</p></div> |
80 | 80 |
{% for field in formdef.fields %} |
81 |
{% include "wcs/backoffice/includes/inspect-field.html" %} |
|
81 |
{% include "wcs/backoffice/includes/inspect-field.html" with path=formdef.get_admin_url|add:"fields/" %}
|
|
82 | 82 |
{% endfor %} |
83 | 83 |
</div> |
84 | 84 |
</div> |
wcs/templates/wcs/backoffice/snapshots_compare.html | ||
---|---|---|
1 |
{% extends "wcs/backoffice/base.html" %} |
|
1 | 2 |
{% load i18n %} |
2 | 3 | |
3 |
{% block body %} |
|
4 |
<div id="appbar"> |
|
5 |
<h2>{% trans "Compare snapshots" %}</h2> |
|
6 |
</div> |
|
4 |
{% block appbar-title %}{% trans "Compare snapshots" %}{% if has_inspect %} ({% if mode == 'xml' %}{% trans "XML" %}{% else %}{% trans "Inspect" %}{% endif %}){% endif %}{% endblock %} |
|
5 |
{% block appbar-actions %} |
|
6 |
{% if has_inspect %} |
|
7 |
<a href="?version1={{ snapshot1.id }}&version2={{ snapshot2.id }}&mode=inspect">{% trans "Compare inspect" %}</a> |
|
8 |
<a href="?version1={{ snapshot1.id }}&version2={{ snapshot2.id }}&mode=xml">{% trans "Compare XML" %}</a> |
|
9 |
{% endif %} |
|
10 |
{% endblock %} |
|
7 | 11 | |
8 |
<div class="section diff"> |
|
9 |
{{ diff_serialization|safe }} |
|
12 |
{% block content %} |
|
13 |
<p class="snapshot-description">{{ fromdesc|safe }} ➔ {{ todesc|safe }}</p> |
|
14 |
<div class="diff"> |
|
15 |
{% if mode == 'xml' %} |
|
16 |
{{ diff_serialization|safe }} |
|
17 |
{% else %} |
|
18 |
<div class="{{ tab_class_names }}"> |
|
19 |
<div class="pk-tabs--tab-list" role="tablist"> |
|
20 |
{% for tab in tabs %}{{ tab|safe }}{% endfor %} |
|
21 |
{{ tab_list|safe }} |
|
22 |
</div> |
|
23 |
<div class="pk-tabs--container"> |
|
24 |
{% for attrs, panel in panels %} |
|
25 |
<div{% for k, v in attrs.items %} {{ k }}="{{ v }}"{% endfor %}> |
|
26 |
{{ panel|safe }} |
|
27 |
</div> |
|
28 |
{% endfor %} |
|
29 |
</div> |
|
30 |
</div> |
|
31 |
{% endif %} |
|
10 | 32 |
</div> |
11 | 33 |
{% endblock %} |
wcs/templates/wcs/backoffice/workflow-inspect.html | ||
---|---|---|
24 | 24 |
</div> |
25 | 25 |
<div class="pk-tabs--container"> |
26 | 26 | |
27 |
<div id="inspect-functions" role="tabpanel" tabindex="0" aria-labelledby="tab-functions" hidden> |
|
28 |
<ul> |
|
29 |
{% for label in workflow.roles.values %} |
|
30 |
<li>{{ label }}</li> |
|
31 |
{% endfor %} |
|
32 |
</ul> |
|
33 |
</div> |
|
34 | ||
35 |
<div id="inspect-variables" role="tabpanel" tabindex="0" aria-labelledby="tab-variables" hidden> |
|
36 |
{% for field in workflow.variables_formdef.fields %} |
|
37 |
{% include "wcs/backoffice/includes/inspect-field.html" with path="variables/fields/" %} |
|
38 |
{% endfor %} |
|
39 |
</div> |
|
40 | ||
41 |
<div id="inspect-fields" role="tabpanel" tabindex="0" aria-labelledby="tab-fields" hidden> |
|
42 |
{% for field in workflow.backoffice_fields_formdef.fields %} |
|
43 |
{% include "wcs/backoffice/includes/inspect-field.html" with path="backoffice-fields/fields/" %} |
|
44 |
{% endfor %} |
|
45 |
</div> |
|
46 | ||
47 |
<div id="inspect-criticality" role="tabpanel" tabindex="0" aria-labelledby="tab-criticality" hidden> |
|
48 |
<ul> |
|
49 |
{% for level in workflow.criticality_levels %}<li>{{ level.name }}</li>{% endfor %} |
|
50 |
</ul> |
|
51 |
</div> |
|
52 | ||
53 | 27 |
<div id="inspect-statuses" role="tabpanel" tabindex="0" aria-labelledby="tab-statuses"> |
54 | 28 |
<nav class="inspect--quicknav"><span class="inspect--jumpto">{% trans "Jump to:" %}</span><ul class="inspect--quicklinks"> |
55 | 29 |
{% for status in workflow.possible_status %} |
... | ... | |
60 | 34 |
{% for status in workflow.possible_status %} |
61 | 35 |
<div class="section status"> |
62 | 36 |
<h3 id="status-{{ status.id }}" |
63 |
><a href="status/{{ status.id }}/" class="inspect-status--link"> |
|
37 |
><a href="{{ workflow.get_admin_url }}status/{{ status.id }}/" class="inspect-status--link">
|
|
64 | 38 |
<span class="inspect-status--colour" style="background-color: #{{ status.colour|default:"fff" }}"></span> |
65 | 39 |
{{ status.name }}</a></h3> |
66 | 40 |
{% if status.backoffice_info_text %}<div>{{ status.backoffice_info_text|safe }}</div>{% endif %} |
67 | 41 |
{% for item in status.items %} |
68 |
<h4><a href="status/{{ status.id }}/items/{{ item.id }}/">{{ item.description }}</a></h4> |
|
42 |
<h4><a href="{{ workflow.get_admin_url }}status/{{ status.id }}/items/{{ item.id }}/">{{ item.description }}</a></h4>
|
|
69 | 43 |
{{ item.get_parameters_view|safe }} |
70 | 44 |
{% empty %} |
71 | 45 |
<p>{% trans "No actions in this status." %}</p> |
... | ... | |
84 | 58 |
<div class="expanded-statuses"> |
85 | 59 |
{% for action in workflow.global_actions %} |
86 | 60 |
<div class="section global-action"> |
87 |
<h3><a id="action-{{ action.id }}" href="global-actions/{{ action.id }}/">{{ action.name }}</a></h3> |
|
61 |
<h3><a id="action-{{ action.id }}" href="{{ workflow.get_admin_url }}global-actions/{{ action.id }}/">{{ action.name }}</a></h3>
|
|
88 | 62 |
<h4>{% trans "Triggers" %}</h4> |
89 | 63 |
<ul>{% for trigger in action.triggers %}<li>{{ trigger.render_as_line }}</li>{% endfor %}</ul> |
90 | 64 |
{% for item in action.items %} |
91 |
<h4><a href="global-actions/{{ action.id }}/items/{{ item.id }}/">{{ item.description }}</a></h4> |
|
65 |
<h4><a href="{{ workflow.get_admin_url }}global-actions/{{ action.id }}/items/{{ item.id }}/">{{ item.description }}</a></h4>
|
|
92 | 66 |
{{ item.get_parameters_view|safe }} |
93 | 67 |
{% endfor %} |
94 | 68 |
</div> |
... | ... | |
96 | 70 |
</div> |
97 | 71 |
</div> |
98 | 72 | |
73 |
<div id="inspect-functions" role="tabpanel" tabindex="0" aria-labelledby="tab-functions" hidden> |
|
74 |
<ul> |
|
75 |
{% for label in workflow.roles.values %} |
|
76 |
<li>{{ label }}</li> |
|
77 |
{% endfor %} |
|
78 |
</ul> |
|
79 |
</div> |
|
80 | ||
81 |
<div id="inspect-variables" role="tabpanel" tabindex="0" aria-labelledby="tab-variables" hidden> |
|
82 |
{% for field in workflow.variables_formdef.fields %} |
|
83 |
{% include "wcs/backoffice/includes/inspect-field.html" with path=workflow.get_admin_url|add:"variables/fields/" %} |
|
84 |
{% endfor %} |
|
85 |
</div> |
|
86 | ||
87 |
<div id="inspect-fields" role="tabpanel" tabindex="0" aria-labelledby="tab-fields" hidden> |
|
88 |
{% for field in workflow.backoffice_fields_formdef.fields %} |
|
89 |
{% include "wcs/backoffice/includes/inspect-field.html" with path=workflow.get_admin_url|add:"backoffice-fields/fields/" %} |
|
90 |
{% endfor %} |
|
91 |
</div> |
|
92 | ||
93 |
<div id="inspect-criticality" role="tabpanel" tabindex="0" aria-labelledby="tab-criticality" hidden> |
|
94 |
<ul> |
|
95 |
{% for level in workflow.criticality_levels %}<li>{{ level.name }}</li>{% endfor %} |
|
96 |
</ul> |
|
97 |
</div> |
|
98 | ||
99 | 99 |
</div> <!-- pk-tabs-container --> |
100 | 100 |
</div> <!-- pk-tabs --> |
101 | 101 |
{% endblock %} |
102 |
- |