Add smarts to show display text for some version diff fields
e.g. show `str(customer)` along with `customer_uuid` since almost nobody will "care" about the uuid so much, they just want the name
This commit is contained in:
parent
edb5393cdc
commit
9efe767654
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2019 Lance Edgar
|
||||
# Copyright © 2010-2023 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -24,7 +24,8 @@
|
|||
Tools for displaying data diffs
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
from pyramid.renderers import render
|
||||
from webhelpers2.html import HTML
|
||||
|
@ -36,7 +37,7 @@ class Diff(object):
|
|||
"""
|
||||
|
||||
def __init__(self, old_data, new_data, columns=None, fields=None,
|
||||
render_field=None, render_value=None,
|
||||
render_field=None, render_value=None, nature='dirty',
|
||||
monospace=False, extra_row_attrs=None):
|
||||
"""
|
||||
Constructor. You must provide the old and new data sets, and
|
||||
|
@ -64,6 +65,7 @@ class Diff(object):
|
|||
self.fields = fields or self.make_fields()
|
||||
self._render_field = render_field or self.render_field_default
|
||||
self.render_value = render_value or self.render_value_default
|
||||
self.nature = nature
|
||||
self.monospace = monospace
|
||||
self.extra_row_attrs = extra_row_attrs
|
||||
|
||||
|
@ -126,3 +128,80 @@ class Diff(object):
|
|||
def render_new_value(self, field):
|
||||
value = self.new_value(field)
|
||||
return self.render_value(field, value)
|
||||
|
||||
|
||||
class VersionDiff(Diff):
|
||||
"""
|
||||
Special diff class, for use with version history views
|
||||
"""
|
||||
|
||||
def __init__(self, version, *args, **kwargs):
|
||||
self.title = kwargs.pop('title', None)
|
||||
|
||||
if 'nature' not in kwargs:
|
||||
if version.previous and version.operation_type == continuum.Operation.DELETE:
|
||||
kwargs['nature'] = 'deleted'
|
||||
elif version.previous:
|
||||
kwargs['nature'] = 'dirty'
|
||||
else:
|
||||
kwargs['nature'] = 'new'
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.version = version
|
||||
self.mapper = sa.inspect(continuum.parent_class(type(self.version)))
|
||||
|
||||
def render_version_value(self, field, value, version):
|
||||
text = HTML.tag('span', c=[repr(value)],
|
||||
style='font-family: monospace;')
|
||||
|
||||
for prop in self.mapper.relationships:
|
||||
if prop.uselist:
|
||||
continue
|
||||
|
||||
for col in prop.local_columns:
|
||||
if col.name != field:
|
||||
continue
|
||||
|
||||
if not hasattr(version, prop.key):
|
||||
continue
|
||||
|
||||
if col in self.mapper.primary_key:
|
||||
continue
|
||||
|
||||
ref = getattr(version, prop.key)
|
||||
if ref:
|
||||
ref = ref.version_parent
|
||||
if ref:
|
||||
return HTML.tag('span', c=[
|
||||
text,
|
||||
HTML.tag('span', c=[str(ref)],
|
||||
style='margin-left: 2rem; font-style: italic; font-weight: bold;'),
|
||||
])
|
||||
|
||||
return text
|
||||
|
||||
def render_old_value(self, field):
|
||||
if self.nature == 'new':
|
||||
return ''
|
||||
value = self.old_value(field)
|
||||
return self.render_version_value(field, value, self.version.previous)
|
||||
|
||||
def render_new_value(self, field):
|
||||
if self.nature == 'deleted':
|
||||
return ''
|
||||
value = self.new_value(field)
|
||||
return self.render_version_value(field, value, self.version)
|
||||
|
||||
def as_struct(self):
|
||||
values = {}
|
||||
for field in self.fields:
|
||||
values[field] = {'before': self.render_old_value(field),
|
||||
'after': self.render_new_value(field)}
|
||||
return {
|
||||
'key': id(self.version),
|
||||
'model_title': self.title,
|
||||
'diff_class': self.nature,
|
||||
'fields': self.fields,
|
||||
'values': values,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
<table class="diff dirty${' monospace' if diff.monospace else ''}">
|
||||
<table class="diff ${diff.nature} ${' monospace' if diff.monospace else ''}">
|
||||
<thead>
|
||||
<tr>
|
||||
% for column in diff.columns:
|
||||
|
|
|
@ -50,71 +50,12 @@
|
|||
</div><!-- form-wrapper -->
|
||||
|
||||
<div class="versions-wrapper">
|
||||
% for version in versions:
|
||||
|
||||
<h2>${title_for_version(version)}</h2>
|
||||
|
||||
% if version.previous and version.operation_type == continuum.Operation.DELETE:
|
||||
<table class="diff monospace deleted">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>field name</th>
|
||||
<th>old value</th>
|
||||
<th>new value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
% for field in fields_for_version(version):
|
||||
<tr>
|
||||
<td class="field">${field}</td>
|
||||
<td class="value old-value">${render_old_value(version, field)}</td>
|
||||
<td class="value new-value"> </td>
|
||||
</tr>
|
||||
% endfor
|
||||
</tbody>
|
||||
</table>
|
||||
% elif version.previous:
|
||||
<table class="diff monospace dirty">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>field name</th>
|
||||
<th>old value</th>
|
||||
<th>new value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
% for field in fields_for_version(version):
|
||||
<tr${' class="diff"' if getattr(version, field) != getattr(version.previous, field) else ''|n}>
|
||||
<td class="field">${field}</td>
|
||||
<td class="value old-value">${render_old_value(version, field)}</td>
|
||||
<td class="value new-value">${render_new_value(version, field, 'dirty')}</td>
|
||||
</tr>
|
||||
% endfor
|
||||
</tbody>
|
||||
</table>
|
||||
% else:
|
||||
<table class="diff monospace new">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>field name</th>
|
||||
<th>old value</th>
|
||||
<th>new value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
% for field in fields_for_version(version):
|
||||
<tr>
|
||||
<td class="field">${field}</td>
|
||||
<td class="value old-value"> </td>
|
||||
<td class="value new-value">${render_new_value(version, field, 'new')}</td>
|
||||
</tr>
|
||||
% endfor
|
||||
</tbody>
|
||||
</table>
|
||||
% endif
|
||||
|
||||
% for diff in version_diffs:
|
||||
<h2>${diff.title}</h2>
|
||||
${diff.render_html()}
|
||||
% endfor
|
||||
</div>
|
||||
|
||||
</%def>
|
||||
|
||||
|
||||
|
|
|
@ -1456,8 +1456,8 @@
|
|||
:class="{diff: version.values[field].after != version.values[field].before}"
|
||||
v-show="revisionShowAllFields || version.values[field].after != version.values[field].before">
|
||||
<td class="field">{{ field }}</td>
|
||||
<td class="old-value">{{ version.values[field].before }}</td>
|
||||
<td class="new-value">{{ version.values[field].after }}</td>
|
||||
<td class="old-value" v-html="version.values[field].before"></td>
|
||||
<td class="new-value" v-html="version.values[field].after"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -1361,6 +1361,20 @@ class MasterView(View):
|
|||
if newer:
|
||||
next_url = self.request.route_url('{}.version'.format(route_prefix), uuid=instance.uuid, txnid=newer.id)
|
||||
|
||||
version_diffs = []
|
||||
versions = self.get_relevant_versions(transaction, instance)
|
||||
for version in versions:
|
||||
|
||||
old_data = {}
|
||||
new_data = {}
|
||||
fields = self.fields_for_version(version)
|
||||
for field in fields:
|
||||
if version.previous:
|
||||
old_data[field] = getattr(version.previous, field)
|
||||
new_data[field] = getattr(version, field)
|
||||
diff = self.make_version_diff(version, old_data, new_data, fields=fields)
|
||||
version_diffs.append(diff)
|
||||
|
||||
return self.render_to_response('view_version', {
|
||||
'instance': instance,
|
||||
'instance_title': "{} (history)".format(instance_title),
|
||||
|
@ -1368,7 +1382,7 @@ class MasterView(View):
|
|||
'instance_url': self.get_action_url('versions', instance),
|
||||
'transaction': transaction,
|
||||
'changed': localtime(self.rattail_config, transaction.issued_at, from_utc=True),
|
||||
'versions': self.get_relevant_versions(transaction, instance),
|
||||
'version_diffs': version_diffs,
|
||||
'show_prev_next': True,
|
||||
'prev_url': prev_url,
|
||||
'next_url': next_url,
|
||||
|
@ -4815,6 +4829,11 @@ class MasterView(View):
|
|||
def make_diff(self, old_data, new_data, **kwargs):
|
||||
return diffs.Diff(old_data, new_data, **kwargs)
|
||||
|
||||
def make_version_diff(self, version, old_data, new_data, **kwargs):
|
||||
if 'title' not in kwargs:
|
||||
kwargs['title'] = self.title_for_version(version)
|
||||
return diffs.VersionDiff(version, old_data, new_data, **kwargs)
|
||||
|
||||
##############################
|
||||
# Configuration Views
|
||||
##############################
|
||||
|
|
|
@ -1398,25 +1398,15 @@ class PersonView(MasterView):
|
|||
# also organize final transaction/versions (diff) map
|
||||
vmap = {}
|
||||
for version in versions:
|
||||
|
||||
if version.previous and version.operation_type == continuum.Operation.DELETE:
|
||||
diff_class = 'deleted'
|
||||
elif version.previous:
|
||||
diff_class = 'dirty'
|
||||
else:
|
||||
diff_class = 'new'
|
||||
|
||||
# collect before/after field values for version
|
||||
fields = self.fields_for_version(version)
|
||||
values = {}
|
||||
|
||||
old_data = {}
|
||||
new_data = {}
|
||||
for field in fields:
|
||||
before = ''
|
||||
after = ''
|
||||
if diff_class != 'new':
|
||||
before = repr(getattr(version.previous, field))
|
||||
if diff_class != 'deleted':
|
||||
after = repr(getattr(version, field))
|
||||
values[field] = {'before': before, 'after': after}
|
||||
if version.previous:
|
||||
old_data[field] = getattr(version.previous, field)
|
||||
new_data[field] = getattr(version, field)
|
||||
diff = self.make_version_diff(version, old_data, new_data, fields=fields)
|
||||
|
||||
if version.transaction_id not in vmap:
|
||||
txn = version.transaction
|
||||
|
@ -1439,13 +1429,7 @@ class PersonView(MasterView):
|
|||
'versions': [],
|
||||
}
|
||||
|
||||
vmap[version.transaction_id]['versions'].append({
|
||||
'key': id(version),
|
||||
'model_title': self.title_for_version(version),
|
||||
'diff_class': diff_class,
|
||||
'fields': fields,
|
||||
'values': values,
|
||||
})
|
||||
vmap[version.transaction_id]['versions'].append(diff.as_struct())
|
||||
|
||||
return {'data': data, 'vmap': vmap}
|
||||
|
||||
|
|
Loading…
Reference in a new issue