Improve merge support for records with no uuid
for now we "pretend" they have a uuid still, custom view is responsible for determining the value for each row if needed
This commit is contained in:
parent
58354e7adf
commit
214f3d9b1e
|
@ -170,6 +170,21 @@ class Grid(object):
|
|||
'myfield': myrender,
|
||||
},
|
||||
)
|
||||
|
||||
.. attribute row_uuid_getter::
|
||||
|
||||
Optional callable to obtain the "UUID" (sic) value for each
|
||||
data row. The default assumption as that each row object has a
|
||||
``uuid`` attribute, but when that isn't the case, *and* the
|
||||
grid needs to support checkboxes, we must "pretend" by
|
||||
injecting some custom value to the ``uuid`` of the row data.
|
||||
|
||||
If necssary, set this to a callable like so::
|
||||
|
||||
def fake_uuid(row):
|
||||
return row.some_custom_key
|
||||
|
||||
grid.row_uuid_getter = fake_uuid
|
||||
"""
|
||||
|
||||
def __init__(self, key, data, columns=None, width='auto', request=None,
|
||||
|
@ -182,7 +197,7 @@ class Grid(object):
|
|||
sortable=False, sorters={}, default_sortkey=None, default_sortdir='asc',
|
||||
pageable=False, default_pagesize=None, default_page=1,
|
||||
checkboxes=False, checked=None, check_handler=None, check_all_handler=None,
|
||||
checkable=None,
|
||||
checkable=None, row_uuid_getter=None,
|
||||
clicking_row_checks_box=False, click_handlers=None,
|
||||
main_actions=[], more_actions=[], delete_speedbump=False,
|
||||
ajax_data_url=None, component='tailbone-grid',
|
||||
|
@ -243,6 +258,7 @@ class Grid(object):
|
|||
self.check_handler = check_handler
|
||||
self.check_all_handler = check_all_handler
|
||||
self.checkable = checkable
|
||||
self.row_uuid_getter = row_uuid_getter
|
||||
self.clicking_row_checks_box = clicking_row_checks_box
|
||||
|
||||
self.click_handlers = click_handlers or {}
|
||||
|
@ -1425,6 +1441,16 @@ class Grid(object):
|
|||
})
|
||||
return columns
|
||||
|
||||
def get_uuid_for_row(self, rowobj):
|
||||
|
||||
# use custom getter if set
|
||||
if self.row_uuid_getter:
|
||||
return self.row_uuid_getter(rowobj)
|
||||
|
||||
# otherwise fallback to normal uuid, if present
|
||||
if hasattr(rowobj, 'uuid'):
|
||||
return rowobj.uuid
|
||||
|
||||
def get_buefy_data(self):
|
||||
"""
|
||||
Returns a list of data rows for the grid, for use with Buefy table.
|
||||
|
@ -1481,8 +1507,9 @@ class Grid(object):
|
|||
|
||||
# maybe add UUID for convenience
|
||||
if 'uuid' not in self.columns:
|
||||
if hasattr(rowobj, 'uuid'):
|
||||
row['uuid'] = rowobj.uuid
|
||||
uuid = self.get_uuid_for_row(rowobj)
|
||||
if uuid:
|
||||
row['uuid'] = uuid
|
||||
|
||||
# set action URL(s) for row, as needed
|
||||
self.set_action_urls(row, rowobj, i)
|
||||
|
|
|
@ -192,7 +192,7 @@
|
|||
% if grid.check_all_handler:
|
||||
@check-all="${grid.check_all_handler}"
|
||||
% endif
|
||||
% if isinstance(grid.checkable, six.string_types):
|
||||
% if isinstance(grid.checkable, str):
|
||||
:is-row-checkable="${grid.row_checkable}"
|
||||
% elif grid.checkable:
|
||||
:is-row-checkable="row => row._checkable"
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
<div class="level-item">
|
||||
${h.form(request.current_route_url(), **{'@submit': 'submitSwapForm'})}
|
||||
${h.csrf_token(request)}
|
||||
${h.hidden('uuids', value='{},{}'.format(object_to_keep.uuid, object_to_remove.uuid))}
|
||||
${h.hidden('uuids', value=f'{keeping_uuid},{removing_uuid}')}
|
||||
<b-button native-type="submit"
|
||||
:disabled="swapFormSubmitting">
|
||||
{{ swapFormButtonText }}
|
||||
|
@ -134,7 +134,7 @@
|
|||
<div class="level-item">
|
||||
${h.form(request.current_route_url(), **{'@submit': 'submitMergeForm'})}
|
||||
${h.csrf_token(request)}
|
||||
${h.hidden('uuids', value='{},{}'.format(object_to_remove.uuid, object_to_keep.uuid))}
|
||||
${h.hidden('uuids', value=f'{removing_uuid},{keeping_uuid}')}
|
||||
${h.hidden('commit-merge', value='yes')}
|
||||
<b-button type="is-primary"
|
||||
native-type="submit"
|
||||
|
|
|
@ -441,6 +441,7 @@ class MasterView(View):
|
|||
'checkable': self.checkbox,
|
||||
'clicking_row_checks_box': self.clicking_row_checks_box,
|
||||
'assume_local_times': self.has_local_times,
|
||||
'row_uuid_getter': self.get_uuid_for_grid_row,
|
||||
}
|
||||
|
||||
if self.sortable or self.pageable or self.filterable:
|
||||
|
@ -453,6 +454,16 @@ class MasterView(View):
|
|||
defaults.update(kwargs)
|
||||
return defaults
|
||||
|
||||
def get_uuid_for_grid_row(self, obj):
|
||||
"""
|
||||
If possible, this should return a "UUID" value to uniquely
|
||||
identify the given object. Default of course is to use the
|
||||
actual ``uuid`` attribute of the object, if present. This
|
||||
value is needed by grids when checkboxes are used.
|
||||
"""
|
||||
if hasattr(obj, 'uuid'):
|
||||
return obj.uuid
|
||||
|
||||
def configure_grid(self, grid):
|
||||
"""
|
||||
Perform "final" configuration for the main data grid.
|
||||
|
@ -2046,17 +2057,31 @@ class MasterView(View):
|
|||
|
||||
return []
|
||||
|
||||
def get_merge_objects(self):
|
||||
"""
|
||||
Must return 2 objects, obtained somehow from the request,
|
||||
which are to be (potentially) merged.
|
||||
|
||||
:returns: 2-tuple of ``(object_to_remove, object_to_keep)``,
|
||||
or ``None``.
|
||||
"""
|
||||
uuids = self.request.POST.get('uuids', '').split(',')
|
||||
if len(uuids) == 2:
|
||||
cls = self.get_model_class()
|
||||
object_to_remove = self.Session.get(cls, uuids[0])
|
||||
object_to_keep = self.Session.get(cls, uuids[1])
|
||||
if object_to_remove and object_to_keep:
|
||||
return object_to_remove, object_to_keep
|
||||
|
||||
def merge(self):
|
||||
"""
|
||||
Preview and execute a merge of two records.
|
||||
"""
|
||||
object_to_remove = object_to_keep = None
|
||||
if self.request.method == 'POST':
|
||||
uuids = self.request.POST.get('uuids', '').split(',')
|
||||
if len(uuids) == 2:
|
||||
object_to_remove = self.Session.get(self.get_model_class(), uuids[0])
|
||||
object_to_keep = self.Session.get(self.get_model_class(), uuids[1])
|
||||
|
||||
objects = self.get_merge_objects()
|
||||
if objects:
|
||||
object_to_remove, object_to_keep = objects
|
||||
if object_to_remove and object_to_keep and self.request.POST.get('commit-merge') == 'yes':
|
||||
msg = str(object_to_remove)
|
||||
try:
|
||||
|
@ -2073,13 +2098,17 @@ class MasterView(View):
|
|||
|
||||
remove = self.get_merge_data(object_to_remove)
|
||||
keep = self.get_merge_data(object_to_keep)
|
||||
return self.render_to_response('merge', {'object_to_remove': object_to_remove,
|
||||
'object_to_keep': object_to_keep,
|
||||
'view_url': lambda obj: self.get_action_url('view', obj),
|
||||
'merge_fields': self.get_merge_fields(),
|
||||
'remove_data': remove,
|
||||
'keep_data': keep,
|
||||
'resulting_data': self.get_merge_resulting_data(remove, keep)})
|
||||
return self.render_to_response('merge', {
|
||||
'object_to_remove': object_to_remove,
|
||||
'object_to_keep': object_to_keep,
|
||||
'removing_uuid': self.get_uuid_for_grid_row(object_to_remove),
|
||||
'keeping_uuid': self.get_uuid_for_grid_row(object_to_keep),
|
||||
'view_url': lambda obj: self.get_action_url('view', obj),
|
||||
'merge_fields': self.get_merge_fields(),
|
||||
'remove_data': remove,
|
||||
'keep_data': keep,
|
||||
'resulting_data': self.get_merge_resulting_data(remove, keep),
|
||||
})
|
||||
|
||||
def validate_merge(self, removing, keeping):
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue