diff --git a/tailbone/templates/master/index.mako b/tailbone/templates/master/index.mako
index 460aa9d0..85252961 100644
--- a/tailbone/templates/master/index.mako
+++ b/tailbone/templates/master/index.mako
@@ -57,6 +57,38 @@
% endif
+ % if master.supports_set_enabled_toggle and request.has_perm('{}.enable_disable_set'.format(permission_prefix)):
+ $('form[name="enable-set"] button').click(function() {
+ var form = $(this).parents('form');
+ var uuids = $('.grid').gridcore('selected_uuids');
+ if (! uuids.length) {
+ alert("You must first select one or more objects to enable.");
+ return false;
+ }
+ if (! confirm("Are you sure you wish to ENABLE the " + uuids.length + " selected objects?")) {
+ return false;
+ }
+ form.find('[name="uuids"]').val(uuids.toString());
+ disable_button(this);
+ form.submit();
+ });
+
+ $('form[name="disable-set"] button').click(function() {
+ var form = $(this).parents('form');
+ var uuids = $('.grid').gridcore('selected_uuids');
+ if (! uuids.length) {
+ alert("You must first select one or more objects to disable.");
+ return false;
+ }
+ if (! confirm("Are you sure you wish to DISABLE the " + uuids.length + " selected objects?")) {
+ return false;
+ }
+ form.find('[name="uuids"]').val(uuids.toString());
+ disable_button(this);
+ form.submit();
+ });
+ % endif
+
% if master.set_deletable and request.has_perm('{}.delete_set'.format(permission_prefix)):
$('form[name="delete-set"] button').click(function() {
var form = $(this).parents('form');
@@ -65,7 +97,7 @@
alert("You must first select one or more objects to delete.");
return false;
}
- if (! confirm("Are you sure you wish to delete the " + uuids.length + " selected objects?")) {
+ if (! confirm("Are you sure you wish to DELETE the " + uuids.length + " selected objects?")) {
return false;
}
form.find('[name="uuids"]').val(uuids.toString());
@@ -104,11 +136,18 @@
${h.end_form()}
% endif
- ## delete search results
- % if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
- ${h.form(url('{}.bulk_delete'.format(route_prefix)), name='bulk-delete')}
+ ## enable / disable selected objects
+ % if master.supports_set_enabled_toggle and request.has_perm('{}.enable_disable_set'.format(permission_prefix)):
+ ${h.form(url('{}.enable_set'.format(route_prefix)), name='enable-set')}
${h.csrf_token(request)}
-
+ ${h.hidden('uuids')}
+
+ ${h.end_form()}
+
+ ${h.form(url('{}.disable_set'.format(route_prefix)), name='disable-set')}
+ ${h.csrf_token(request)}
+ ${h.hidden('uuids')}
+
${h.end_form()}
% endif
@@ -121,6 +160,14 @@
${h.end_form()}
% endif
+ ## delete search results
+ % if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
+ ${h.form(url('{}.bulk_delete'.format(route_prefix)), name='bulk-delete')}
+ ${h.csrf_token(request)}
+
+ ${h.end_form()}
+ % endif
+
%def>
${grid.render_complete(tools=capture(self.grid_tools).strip(), context_menu=capture(self.context_menu_items).strip())|n}
diff --git a/tailbone/views/master.py b/tailbone/views/master.py
index d16a2e73..5eca8b63 100644
--- a/tailbone/views/master.py
+++ b/tailbone/views/master.py
@@ -83,6 +83,7 @@ class MasterView(View):
deletable = True
bulk_deletable = False
set_deletable = False
+ supports_set_enabled_toggle = False
populatable = False
mergeable = False
downloadable = False
@@ -332,6 +333,8 @@ class MasterView(View):
checkboxes = self.checkboxes
if not checkboxes and self.mergeable and self.request.has_perm('{}.merge'.format(permission_prefix)):
checkboxes = True
+ if not checkboxes and self.supports_set_enabled_toggle and self.request.has_perm('{}.enable_disable_set'.format(permission_prefix)):
+ checkboxes = True
if not checkboxes and self.set_deletable and self.request.has_perm('{}.delete_set'.format(permission_prefix)):
checkboxes = True
@@ -1630,9 +1633,9 @@ class MasterView(View):
progress.session['success_url'] = self.get_index_url()
progress.session.save()
- def delete_set(self):
+ def obtain_set(self):
"""
- View which can delete a specific set of records.
+ Obtain the effective "set" (selection) of records from POST data.
"""
# TODO: should have a cleaner way to parse object uuids?
uuids = self.request.POST.get('uuids')
@@ -1640,14 +1643,53 @@ class MasterView(View):
uuids = uuids.split(',')
# TODO: probably need to allow override of fetcher callable
fetcher = lambda uuid: self.Session.query(self.model_class).get(uuid)
- deleted = 0
+ objects = []
for uuid in uuids:
obj = fetcher(uuid)
if obj:
- self.delete_instance(obj)
- deleted += 1
+ objects.append(obj)
+ return objects
+
+ def enable_set(self):
+ """
+ View which can turn ON the 'enabled' flag for a specific set of records.
+ """
+ objects = self.obtain_set()
+ if objects:
+ enabled = 0
+ for obj in objects:
+ if not obj.enabled:
+ obj.enabled = True
+ enabled += 1
model_title_plural = self.get_model_title_plural()
- self.request.session.flash("Deleted {} {}".format(deleted, model_title_plural))
+ self.request.session.flash("Enabled {} {}".format(enabled, model_title_plural))
+ return self.redirect(self.get_index_url())
+
+ def disable_set(self):
+ """
+ View which can turn OFF the 'enabled' flag for a specific set of records.
+ """
+ objects = self.obtain_set()
+ if objects:
+ disabled = 0
+ for obj in objects:
+ if obj.enabled:
+ obj.enabled = False
+ disabled += 1
+ model_title_plural = self.get_model_title_plural()
+ self.request.session.flash("Disabled {} {}".format(disabled, model_title_plural))
+ return self.redirect(self.get_index_url())
+
+ def delete_set(self):
+ """
+ View which can delete a specific set of records.
+ """
+ objects = self.obtain_set()
+ if objects:
+ for obj in objects:
+ self.delete_instance(obj)
+ model_title_plural = self.get_model_title_plural()
+ self.request.session.flash("Deleted {} {}".format(len(objects), model_title_plural))
return self.redirect(self.get_index_url())
def oneoff_import(self, importer, host_object=None):
@@ -3079,14 +3121,18 @@ class MasterView(View):
config.add_view(cls, attr='populate', route_name='{}.populate'.format(route_prefix),
permission='{}.create'.format(permission_prefix))
- # bulk delete
- if cls.bulk_deletable:
- config.add_route('{}.bulk_delete'.format(route_prefix), '{}/bulk-delete'.format(url_prefix),
+ # enable/disable set
+ if cls.supports_set_enabled_toggle:
+ config.add_tailbone_permission(permission_prefix, '{}.enable_disable_set'.format(permission_prefix),
+ "Enable / disable set (selection) of {}".format(model_title_plural))
+ config.add_route('{}.enable_set'.format(route_prefix), '{}/enable-set'.format(url_prefix),
request_method='POST')
- config.add_view(cls, attr='bulk_delete', route_name='{}.bulk_delete'.format(route_prefix),
- permission='{}.bulk_delete'.format(permission_prefix))
- config.add_tailbone_permission(permission_prefix, '{}.bulk_delete'.format(permission_prefix),
- "Bulk delete {}".format(model_title_plural))
+ config.add_view(cls, attr='enable_set', route_name='{}.enable_set'.format(route_prefix),
+ permission='{}.enable_disable_set'.format(permission_prefix))
+ config.add_route('{}.disable_set'.format(route_prefix), '{}/disable-set'.format(url_prefix),
+ request_method='POST')
+ config.add_view(cls, attr='disable_set', route_name='{}.disable_set'.format(route_prefix),
+ permission='{}.enable_disable_set'.format(permission_prefix))
# delete set
if cls.set_deletable:
@@ -3097,6 +3143,15 @@ class MasterView(View):
config.add_view(cls, attr='delete_set', route_name='{}.delete_set'.format(route_prefix),
permission='{}.delete_set'.format(permission_prefix))
+ # bulk delete
+ if cls.bulk_deletable:
+ config.add_route('{}.bulk_delete'.format(route_prefix), '{}/bulk-delete'.format(url_prefix),
+ request_method='POST')
+ config.add_view(cls, attr='bulk_delete', route_name='{}.bulk_delete'.format(route_prefix),
+ permission='{}.bulk_delete'.format(permission_prefix))
+ config.add_tailbone_permission(permission_prefix, '{}.bulk_delete'.format(permission_prefix),
+ "Bulk delete {}".format(model_title_plural))
+
# merge
if cls.mergeable:
config.add_route('{}.merge'.format(route_prefix), '{}/merge'.format(url_prefix))