applications: compare elements definitions (#81496)
gitea/hobo/pipeline/head This commit looks good
Details
gitea/hobo/pipeline/head This commit looks good
Details
This commit is contained in:
parent
ee8ee01378
commit
8107b3083e
|
@ -7,12 +7,33 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans "Compare versions" %}</h2>
|
||||
<h2>{% trans 'Compare versions' %} ({% if mode == 'manifest' %}{% trans "Manifest" %}{% else %}{% trans "Elements definitions" %}{% endif %})</h2>
|
||||
<span class="actions">
|
||||
<a href="?version1={{ version1.pk }}&version2={{ version2.pk }}&mode=elements">{% trans "Compare elements definitions" %}</a>
|
||||
<a href="?version1={{ version1.pk }}&version2={{ version2.pk }}&mode=manifest">{% trans "Compare manifest" %}</a>
|
||||
</span>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p class="version-description">{{ fromdesc|safe }} ➔ {{ todesc|safe }}</p>
|
||||
<div class="diff">
|
||||
{{ diff_serialization|safe }}
|
||||
{% if mode == 'manifest' %}
|
||||
{{ diff_serialization|safe }}
|
||||
{% else %}
|
||||
<ul class="objects-list single-links application-content">
|
||||
{% for element in elements %}
|
||||
<li>
|
||||
<a>
|
||||
{% if not element.real_element %}<span class="tag tag-error">{% trans "Element not found" %}</span> {% endif %}{{ element.name }} <span class="extra-info">- {{ element.type_label }}</span>
|
||||
{% if element.real_element.get_redirect_url %}
|
||||
<a class="link-action-icon link" href="{{ element.real_element.get_redirect_url }}?application={{ app.slug }}&version1={{ version1.number }}&version2={{ version2.number }}&compare">
|
||||
{% trans "see" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -181,8 +181,11 @@ class VersionCompareView(DetailView):
|
|||
|
||||
id1 = self.request.GET.get('version1')
|
||||
id2 = self.request.GET.get('version2')
|
||||
mode = self.request.GET.get('mode') or 'manifest'
|
||||
if not id1 or not id2:
|
||||
raise Http404
|
||||
if mode not in ['manifest', 'elements']:
|
||||
raise Http404
|
||||
|
||||
version1 = get_object_or_404(Version, pk=id1, application=self.object)
|
||||
version2 = get_object_or_404(Version, pk=id2, application=self.object)
|
||||
|
@ -190,11 +193,12 @@ class VersionCompareView(DetailView):
|
|||
if version1.last_update_timestamp > version2.last_update_timestamp:
|
||||
version1, version2 = version2, version1
|
||||
|
||||
kwargs['mode'] = mode
|
||||
kwargs['version1'] = version1
|
||||
kwargs['version2'] = version2
|
||||
kwargs['fromdesc'] = self.get_version_desc(version1)
|
||||
kwargs['todesc'] = self.get_version_desc(version2)
|
||||
kwargs.update(self.get_compare_context(version1, version2))
|
||||
kwargs.update(getattr(self, 'get_compare_%s_context' % mode)(version1, version2))
|
||||
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
@ -212,7 +216,7 @@ class VersionCompareView(DetailView):
|
|||
)
|
||||
return manifest
|
||||
|
||||
def get_compare_context(self, version1, version2):
|
||||
def get_compare_manifest_context(self, version1, version2):
|
||||
manifest1 = self.get_manifest(version1)
|
||||
s1 = json.dumps(manifest1, sort_keys=True, indent=2)
|
||||
manifest2 = self.get_manifest(version2)
|
||||
|
@ -226,6 +230,37 @@ class VersionCompareView(DetailView):
|
|||
'diff_serialization': diff_serialization,
|
||||
}
|
||||
|
||||
def get_compare_elements_context(self, version1, version2):
|
||||
type_labels = {}
|
||||
object_types = get_object_types()
|
||||
types = [o['id'] for o in object_types]
|
||||
for object_type in object_types:
|
||||
type_labels[object_type['id']] = object_type['singular']
|
||||
|
||||
# take more recent version
|
||||
bundle = version2.bundle.read()
|
||||
tar_io = io.BytesIO(bundle)
|
||||
with tarfile.open(fileobj=tar_io) as tar:
|
||||
manifest = json.loads(tar.extractfile('manifest.json').read().decode())
|
||||
# and extract elements
|
||||
elements = manifest.get('elements') or []
|
||||
# exclude roles, impossible to diff
|
||||
elements = [e for e in elements if e['type'] != 'roles']
|
||||
# sort elements
|
||||
elements = sorted(
|
||||
elements, key=lambda a: (a['auto-dependency'], types.index(a['type']), slugify(a['name']))
|
||||
)
|
||||
# and complete with real elements to have more information, such as redirect url
|
||||
for element in elements:
|
||||
element['type_label'] = type_labels.get(element['type'])
|
||||
try:
|
||||
real_element = Element.objects.get(type=element['type'], slug=element['slug'])
|
||||
except Element.DoesNotExist:
|
||||
element['real_element'] = None
|
||||
continue
|
||||
element['real_element'] = real_element
|
||||
return {'elements': elements}
|
||||
|
||||
def get_version_desc(self, version):
|
||||
return '{name} {number} ({timestamp})'.format(
|
||||
name=_('Version'),
|
||||
|
|
|
@ -361,6 +361,10 @@ ul.objects-list.application-content {
|
|||
}
|
||||
}
|
||||
|
||||
ul.objects-list.single-links li a.link::before {
|
||||
content: "\f08e"; /* fa-external-link */
|
||||
}
|
||||
|
||||
#versions {
|
||||
.version {
|
||||
background: white;
|
||||
|
|
|
@ -460,6 +460,41 @@ def test_create_application(app, admin_user, settings, analyze):
|
|||
resp = resp.follow()
|
||||
assert 'Version 2.0' in resp
|
||||
assert 'Version 1.0' in resp
|
||||
resp = resp.click('Compare elements definitions')
|
||||
assert 'Version 2.0' in resp
|
||||
assert 'Version 1.0' in resp
|
||||
assert (
|
||||
'https://wcs.example.invalid/api/export-import/forms/test-form/redirect/?application=test&version1=2.0&version2=1.0&compare'
|
||||
in resp
|
||||
)
|
||||
assert (
|
||||
'https://wcs.example.invalid/api/export-import/cards/test-card/redirect/?application=test&version1=2.0&version2=1.0&compare'
|
||||
in resp
|
||||
)
|
||||
assert 'Test Form <span class="extra-info">- Form</span>' in resp
|
||||
assert 'Test Card <span class="extra-info">- Card Model</span>' in resp
|
||||
assert 'Element not found' not in resp
|
||||
|
||||
Element.objects.filter(type='cards').delete()
|
||||
resp = app.get(
|
||||
'/applications/manifest/test/version/compare/?version1=%s&version2=%s&mode=elements'
|
||||
% (new_version.pk, version.pk)
|
||||
)
|
||||
assert 'Version 2.0' in resp
|
||||
assert 'Version 1.0' in resp
|
||||
assert (
|
||||
'https://wcs.example.invalid/api/export-import/forms/test-form/redirect/?application=test&version1=2.0&version2=1.0&compare'
|
||||
in resp
|
||||
)
|
||||
assert (
|
||||
'https://wcs.example.invalid/api/export-import/cards/test-card/redirect/?application=test&version1=2.0&version2=1.0&compare'
|
||||
not in resp
|
||||
)
|
||||
assert 'Test Form <span class="extra-info">- Form</span>' in resp
|
||||
assert (
|
||||
'<span class="tag tag-error">Element not found</span> Test Card <span class="extra-info">- Card Model</span>'
|
||||
in resp
|
||||
)
|
||||
|
||||
def response_content(url, request):
|
||||
if url.path == '/api/export-import/bundle-declare/':
|
||||
|
|
Loading…
Reference in New Issue