Show full version history within the "view" page
avoid full page loads when navigating version history
This commit is contained in:
parent
44112a3a4b
commit
4328b9e385
9 changed files with 498 additions and 130 deletions
|
@ -1172,6 +1172,12 @@ class MasterView(View):
|
|||
context['rows_grid'] = grid
|
||||
context['rows_grid_tools'] = HTML(self.make_row_grid_tools(instance) or '').strip()
|
||||
|
||||
context['expose_versions'] = (self.has_versions
|
||||
and self.request.rattail_config.versioning_enabled()
|
||||
and self.has_perm('versions'))
|
||||
if context['expose_versions']:
|
||||
context['versions_grid'] = self.make_revisions_grid(instance, empty_data=True)
|
||||
|
||||
return self.render_to_response('view', context)
|
||||
|
||||
def image(self):
|
||||
|
@ -1300,7 +1306,7 @@ class MasterView(View):
|
|||
return cls.version_grid_key
|
||||
return '{}.history'.format(cls.get_route_prefix())
|
||||
|
||||
def get_version_data(self, instance):
|
||||
def get_version_data(self, instance, order_by=True):
|
||||
"""
|
||||
Generate the base data set for the version grid.
|
||||
"""
|
||||
|
@ -1308,7 +1314,9 @@ class MasterView(View):
|
|||
transaction_class = continuum.transaction_class(model_class)
|
||||
query = model_transaction_query(self.Session(), instance, model_class,
|
||||
child_classes=self.normalize_version_child_classes())
|
||||
return query.order_by(transaction_class.issued_at.desc())
|
||||
if order_by:
|
||||
query = query.order_by(transaction_class.issued_at.desc())
|
||||
return query
|
||||
|
||||
def get_version_child_classes(self):
|
||||
"""
|
||||
|
@ -1330,6 +1338,114 @@ class MasterView(View):
|
|||
classes.append(cls)
|
||||
return classes
|
||||
|
||||
def make_revisions_grid(self, obj, empty_data=False):
|
||||
route_prefix = self.get_route_prefix()
|
||||
row_url = lambda txn, i: self.request.route_url(f'{route_prefix}.version',
|
||||
uuid=obj.uuid,
|
||||
txnid=txn.id)
|
||||
|
||||
kwargs = {
|
||||
'component': 'versions-grid',
|
||||
'ajax_data_url': self.get_action_url('revisions_data', obj),
|
||||
'sortable': True,
|
||||
'default_sortkey': 'changed',
|
||||
'default_sortdir': 'desc',
|
||||
'main_actions': [
|
||||
self.make_action('view', icon='eye', url='#',
|
||||
click_handler='viewRevision(props.row)'),
|
||||
self.make_action('view_separate', url=row_url, target='_blank',
|
||||
icon='external-link-alt', ),
|
||||
],
|
||||
}
|
||||
|
||||
if empty_data:
|
||||
|
||||
# TODO: surely there is a better way to have empty initial
|
||||
# data..? but so much logic depends on a query, can't
|
||||
# just pass empty list here
|
||||
txn_class = continuum.transaction_class(self.get_model_class())
|
||||
meta_class = continuum.versioning_manager.transaction_meta_cls
|
||||
kwargs['data'] = self.Session.query(txn_class)\
|
||||
.outerjoin(meta_class,
|
||||
meta_class.transaction_id == txn_class.id)\
|
||||
.filter(txn_class.id == -1)
|
||||
|
||||
else:
|
||||
kwargs['data'] = self.get_version_data(obj, order_by=False)
|
||||
|
||||
grid = self.make_version_grid(**kwargs)
|
||||
|
||||
grid.set_joiner('user', lambda q: q.outerjoin(self.model.User))
|
||||
grid.set_sorter('user', self.model.User.username)
|
||||
|
||||
grid.set_link('remote_addr')
|
||||
|
||||
grid.append('id')
|
||||
grid.set_label('id', "TXN ID")
|
||||
grid.set_link('id')
|
||||
|
||||
return grid
|
||||
|
||||
def revisions_data(self):
|
||||
"""
|
||||
AJAX view to fetch revision data for current instance.
|
||||
"""
|
||||
txnid = self.request.GET.get('txnid')
|
||||
if txnid:
|
||||
# return single txn data
|
||||
|
||||
app = self.get_rattail_app()
|
||||
obj = self.get_instance()
|
||||
cls = self.get_model_class()
|
||||
txn_cls = continuum.transaction_class(cls)
|
||||
route_prefix = self.get_route_prefix()
|
||||
|
||||
transactions = model_transaction_query(
|
||||
self.Session(), obj, cls,
|
||||
child_classes=self.normalize_version_child_classes())
|
||||
|
||||
txn = transactions.filter(txn_cls.id == txnid).first()
|
||||
if not txn:
|
||||
return self.notfound()
|
||||
|
||||
older = transactions.filter(txn_cls.issued_at <= txn.issued_at)\
|
||||
.filter(txn_cls.id != txnid)\
|
||||
.order_by(txn_cls.issued_at.desc())\
|
||||
.first()
|
||||
newer = transactions.filter(txn_cls.issued_at >= txn.issued_at)\
|
||||
.filter(txn_cls.id != txnid)\
|
||||
.order_by(txn_cls.issued_at)\
|
||||
.first()
|
||||
|
||||
version_diffs = []
|
||||
for version in self.get_relevant_versions(txn, obj):
|
||||
diff = self.make_version_diff(version)
|
||||
version_diffs.append(diff.as_struct())
|
||||
|
||||
changed_raw = app.render_datetime(app.localtime(txn.issued_at, from_utc=True))
|
||||
changed_ago = app.render_time_ago(app.make_utc() - txn.issued_at)
|
||||
|
||||
changed_by = str(txn.user)
|
||||
if self.request.has_perm('users.view'):
|
||||
changed_by = tags.link_to(changed_by, self.request.route_url('users.view', uuid=txn.user.uuid))
|
||||
|
||||
return {
|
||||
'txnid': txn.id,
|
||||
'changed': f"{changed_raw} ({changed_ago})",
|
||||
'changed_by': changed_by,
|
||||
'remote_addr': txn.remote_addr,
|
||||
'comment': txn.meta.get('comment'),
|
||||
'versions': version_diffs,
|
||||
'url': self.request.route_url(f'{route_prefix}.version', uuid=obj.uuid, txnid=txnid),
|
||||
'prev_txnid': older.id if older else None,
|
||||
'next_txnid': newer.id if newer else None,
|
||||
}
|
||||
|
||||
else: # no txnid, return grid data
|
||||
obj = self.get_instance()
|
||||
grid = self.make_revisions_grid(obj)
|
||||
return grid.get_buefy_data()
|
||||
|
||||
def view_version(self):
|
||||
"""
|
||||
View showing diff details of a particular object version.
|
||||
|
@ -4829,10 +4945,10 @@ 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):
|
||||
def make_version_diff(self, version, *args, **kwargs):
|
||||
if 'title' not in kwargs:
|
||||
kwargs['title'] = self.title_for_version(version)
|
||||
return diffs.VersionDiff(version, old_data, new_data, **kwargs)
|
||||
return diffs.VersionDiff(version, *args, **kwargs)
|
||||
|
||||
##############################
|
||||
# Configuration Views
|
||||
|
@ -5576,6 +5692,16 @@ class MasterView(View):
|
|||
route_name='{}.version'.format(route_prefix),
|
||||
permission='{}.versions'.format(permission_prefix))
|
||||
|
||||
# revisions data (AJAX)
|
||||
config.add_route(f'{route_prefix}.revisions_data',
|
||||
f'{instance_url_prefix}/revisions-data',
|
||||
request_method='GET')
|
||||
config.add_view(cls, attr='revisions_data',
|
||||
route_name=f'{route_prefix}.revisions_data',
|
||||
permission=f'{permission_prefix}.versions',
|
||||
renderer='json')
|
||||
|
||||
|
||||
@classmethod
|
||||
def _defaults_edit_help(cls, config, **kwargs):
|
||||
route_prefix = cls.get_route_prefix()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue