Add way to execute multiple handheld batches at once
This commit is contained in:
parent
a63f2e3623
commit
5a0fa20e03
60
tailbone/templates/batch/handheld/index.mako
Normal file
60
tailbone/templates/batch/handheld/index.mako
Normal file
|
@ -0,0 +1,60 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
<%inherit file="/newbatch/index.mako" />
|
||||
|
||||
<%def name="extra_javascript()">
|
||||
${parent.extra_javascript()}
|
||||
<script type="text/javascript">
|
||||
|
||||
var has_execution_options = ${'true' if master.has_execution_options else 'false'};
|
||||
|
||||
$(function() {
|
||||
|
||||
$('#execute-results-button').click(function() {
|
||||
var form = $('form[name="execute-results"]');
|
||||
if (has_execution_options) {
|
||||
$('#execution-options-dialog').dialog({
|
||||
title: "Execution Options",
|
||||
width: 500,
|
||||
height: 300,
|
||||
modal: true,
|
||||
buttons: [
|
||||
{
|
||||
text: "Execute",
|
||||
click: function(event) {
|
||||
dialog_button(event).button('option', 'label', "Executing, please wait...").button('disable');
|
||||
form.submit();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Cancel",
|
||||
click: function() {
|
||||
$(this).dialog('close');
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
} else {
|
||||
$(this).button('option', 'label', "Executing, please wait...").button('disable');
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
<%def name="grid_tools()">
|
||||
<button type="button" id="execute-results-button">Execute Results</button>
|
||||
</%def>
|
||||
|
||||
${parent.body()}
|
||||
|
||||
<div id="execution-options-dialog" style="display: none;">
|
||||
${h.form(url('{}.execute_results'.format(route_prefix)), name='execute-results')}
|
||||
${h.csrf_token(request)}
|
||||
% if master.has_execution_options:
|
||||
${rendered_execution_options|n}
|
||||
% endif
|
||||
${h.end_form()}
|
||||
</div>
|
|
@ -34,6 +34,7 @@ import datetime
|
|||
import logging
|
||||
from cStringIO import StringIO
|
||||
|
||||
import six
|
||||
from sqlalchemy import orm
|
||||
|
||||
from rattail.db import model, Session as RattailSession
|
||||
|
@ -110,7 +111,15 @@ class BatchMasterView(MasterView):
|
|||
kwargs['rendered_execution_options'] = self.render_execution_options(batch)
|
||||
return kwargs
|
||||
|
||||
def render_execution_options(self, batch):
|
||||
def template_kwargs_index(self, **kwargs):
|
||||
kwargs['execute_enabled'] = self.executable()
|
||||
if kwargs['execute_enabled'] and self.has_execution_options:
|
||||
kwargs['rendered_execution_options'] = self.render_execution_options()
|
||||
return kwargs
|
||||
|
||||
def render_execution_options(self, batch=None):
|
||||
if batch is None:
|
||||
batch = self.model_class
|
||||
form = self.make_execution_options_form(batch)
|
||||
kwargs = {
|
||||
'batch': batch,
|
||||
|
@ -434,7 +443,7 @@ class BatchMasterView(MasterView):
|
|||
def editable_instance(self, batch):
|
||||
return not bool(batch.executed)
|
||||
|
||||
def executable(self, batch):
|
||||
def executable(self, batch=None):
|
||||
return self.handler.executable(batch)
|
||||
|
||||
def batch_refreshable(self, batch):
|
||||
|
@ -460,10 +469,12 @@ class BatchMasterView(MasterView):
|
|||
# TODO
|
||||
execution_options_schema = None
|
||||
|
||||
def make_execution_options_form(self, batch):
|
||||
def make_execution_options_form(self, batch=None):
|
||||
"""
|
||||
Return a proper Form for execution options.
|
||||
"""
|
||||
if batch is None:
|
||||
batch = self.model_class
|
||||
defaults = {}
|
||||
for field in self.execution_options_schema.fields:
|
||||
key = 'batch.{}.execute_option.{}'.format(batch.batch_key, field)
|
||||
|
@ -819,6 +830,82 @@ class BatchMasterView(MasterView):
|
|||
def get_execute_success_url(self, batch, result, **kwargs):
|
||||
return self.get_action_url('view', batch)
|
||||
|
||||
def execute_results(self):
|
||||
"""
|
||||
Execute all batches which are returned from the current index query.
|
||||
Starts a separate thread for the execution, and displays a progress
|
||||
indicator page.
|
||||
"""
|
||||
if self.request.method == 'POST':
|
||||
|
||||
kwargs = {}
|
||||
if self.has_execution_options:
|
||||
form = self.make_execution_options_form()
|
||||
if not form.validate():
|
||||
raise RuntimeError("Execution options form did not validate")
|
||||
kwargs.update(form.data)
|
||||
|
||||
# cache options to use as defaults next time
|
||||
for key, value in form.data.iteritems():
|
||||
self.request.session['batch.{}.execute_option.{}'.format(self.model_class.batch_key, key)] = six.text_type(value)
|
||||
|
||||
key = '{}.execute_results'.format(self.model_class.__tablename__)
|
||||
batches = self.get_effective_data()
|
||||
kwargs['progress'] = SessionProgress(self.request, key)
|
||||
thread = Thread(target=self.execute_results_thread, args=(batches, self.request.user.uuid), kwargs=kwargs)
|
||||
thread.start()
|
||||
|
||||
return self.render_progress({
|
||||
'key': key,
|
||||
'cancel_url': self.get_index_url(),
|
||||
'cancel_msg': "Batch execution was canceled",
|
||||
})
|
||||
|
||||
self.request.session.flash("Sorry, you must POST to execute batches", 'error')
|
||||
return self.redirect(self.get_index_url())
|
||||
|
||||
def execute_results_thread(self, batches, user_uuid, progress=None, **kwargs):
|
||||
"""
|
||||
Thread target for executing multiple batches with progress indicator.
|
||||
"""
|
||||
session = RattailSession()
|
||||
batches = batches.with_session(session).all()
|
||||
user = session.query(model.User).get(user_uuid)
|
||||
try:
|
||||
result = self.handler.execute_many(batches, user=user, progress=progress, **kwargs)
|
||||
|
||||
# If anything goes wrong, rollback and log the error etc.
|
||||
except Exception as error:
|
||||
session.rollback()
|
||||
log.exception("execution failed for batch: {}".format(batch))
|
||||
session.close()
|
||||
if progress:
|
||||
progress.session.load()
|
||||
progress.session['error'] = True
|
||||
progress.session['error_msg'] = self.execute_error_message(error)
|
||||
progress.session.save()
|
||||
|
||||
# If no error, check result flag (false means user canceled).
|
||||
else:
|
||||
if result:
|
||||
now = datetime.datetime.utcnow()
|
||||
for batch in batches:
|
||||
batch.executed = now
|
||||
batch.executed_by = user
|
||||
session.commit()
|
||||
# TODO: this doesn't always work...?
|
||||
self.request.session.flash("{} {} were executed".format(
|
||||
len(batches), self.get_model_title_plural()))
|
||||
else:
|
||||
session.rollback()
|
||||
session.close()
|
||||
|
||||
if progress:
|
||||
progress.session.load()
|
||||
progress.session['complete'] = True
|
||||
progress.session['success_url'] = self.get_index_url()
|
||||
progress.session.save()
|
||||
|
||||
def csv(self):
|
||||
"""
|
||||
Download batch data as CSV.
|
||||
|
@ -913,6 +1000,13 @@ class BatchMasterView(MasterView):
|
|||
config.add_tailbone_permission(permission_prefix, '{}.execute'.format(permission_prefix),
|
||||
"Execute {}".format(model_title))
|
||||
|
||||
# execute (multiple) batch results
|
||||
config.add_route('{}.execute_results'.format(route_prefix), '{}/execute-results'.format(url_prefix))
|
||||
config.add_view(cls, attr='execute_results', route_name='{}.execute_results'.format(route_prefix),
|
||||
permission='{}.execute_multiple'.format(permission_prefix))
|
||||
config.add_tailbone_permission(permission_prefix, '{}.execute_multiple'.format(permission_prefix),
|
||||
"Execute multiple {}".format(model_title_plural))
|
||||
|
||||
# download rows as CSV
|
||||
if cls.rows_downloadable:
|
||||
config.add_route('{}.csv'.format(route_prefix), '{}/{{uuid}}/csv'.format(url_prefix))
|
||||
|
|
Loading…
Reference in a new issue