Refactor batch execution options to use colander/deform

This commit is contained in:
Lance Edgar 2018-02-11 22:37:17 -06:00
parent 2cbacd6187
commit dd04459748
12 changed files with 87 additions and 99 deletions

View file

@ -697,7 +697,7 @@ class Form(object):
context = kwargs
context['form'] = self
context['dform'] = dform
context['form_kwargs'] = {}
context.setdefault('form_kwargs', {})
# TODO: deprecate / remove the latter option here
if self.auto_disable_save or self.auto_disable:
context['form_kwargs']['class_'] = 'autodisable'

View file

@ -261,6 +261,18 @@
that.grid.gridcore();
that.element.unmask();
});
},
results_count: function(as_text) {
var count = null;
var match = /showing \d+ thru \d+ of (\S+)/.exec(this.element.find('.pager .showing').text());
if (match) {
count = match[1];
if (!as_text) {
count = parseInt(count, 10);
}
}
return count;
}
});

View file

@ -10,8 +10,6 @@
$(function() {
$('.grid-wrapper').gridwrapper();
$('#execute-batch').click(function() {
if (has_execution_options) {
$('#execution-options-dialog').dialog({

View file

@ -6,8 +6,6 @@
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.batch.js'))}
<script type="text/javascript">
var has_execution_options = ${'true' if master.has_execution_options(batch) else 'false'};
$(function() {
$('#save-refresh').click(function() {
@ -55,13 +53,3 @@
<div class="form-wrapper">
${form.render()|n}
</div>
<div id="execution-options-dialog" style="display: none;">
${h.form(url('{}.execute'.format(route_prefix), uuid=batch.uuid), name='batch-execution')}
% if master.has_execution_options(batch):
${rendered_execution_options|n}
% endif
${h.end_form()}
</div>

View file

@ -1,3 +0,0 @@
## -*- coding: utf-8 -*-
${form.field_div('action', form.select('action', options=ACTION_OPTIONS), label="Action to Perform")}

View file

@ -12,6 +12,11 @@
$(function() {
$('#execute-results-button').click(function() {
var count = $('.grid-wrapper').gridwrapper('results_count');
if (!count) {
alert("There are no batch results to execute.");
return;
}
var form = $('form[name="execute-results"]');
if (has_execution_options) {
$('#execution-options-dialog').dialog({
@ -66,16 +71,11 @@ ${parent.body()}
% if master.results_executable and request.has_perm('{}.execute_multiple'.format(permission_prefix)):
<div id="execution-options-dialog" style="display: none;">
${h.form(url('{}.execute_results'.format(route_prefix)), name='execute-results')}
${h.csrf_token(request)}
<br />
<p>
Please be advised, you are about to execute multiple batches!
</p>
<br />
% if master.has_execution_options(batch):
${rendered_execution_options|n}
% endif
${h.end_form()}
${execute_form.render_deform(form_kwargs={'name': 'execute-results'}, buttons=False)|n}
</div>
% endif

View file

@ -3,7 +3,7 @@
<%def name="extra_javascript()">
${parent.extra_javascript()}
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.batch.js'))}
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.batch.js') + '?ver={}'.format(tailbone.__version__))}
<script type="text/javascript">
var has_execution_options = ${'true' if master.has_execution_options(batch) else 'false'};
@ -84,13 +84,6 @@ ${rows_grid|n}
% if not batch.executed:
<div id="execution-options-dialog" style="display: none;">
${h.form(url('{}.execute'.format(route_prefix), uuid=batch.uuid), name='batch-execution')}
${h.csrf_token(request)}
% if master.has_execution_options(batch):
${rendered_execution_options|n}
% endif
${h.end_form()}
${execute_form.render_deform(form_kwargs={'name': 'batch-execution'}, buttons=False)|n}
</div>
% endif

View file

@ -43,11 +43,8 @@
% if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
$('form[name="bulk-delete"] button').click(function() {
var count = 0;
var match = /showing \d+ thru \d+ of (\S+)/.exec($('.pager .showing').text());
if (match) {
count = match[1];
} else {
var count = $('.grid-wrapper').gridwrapper('results_count', true);
if (count === null) {
alert("There don't seem to be any results to delete!");
return;
}

View file

@ -29,6 +29,7 @@ from __future__ import unicode_literals, absolute_import
import os
import datetime
import logging
import tempfile
from cStringIO import StringIO
import six
@ -39,13 +40,16 @@ from rattail.db import model, Session as RattailSession
from rattail.threads import Thread
from rattail.util import load_object, prettify
import colander
import deform
from deform import widget as dfwidget
from pyramid import httpexceptions
from pyramid.renderers import render_to_response
from pyramid.response import FileResponse
from pyramid_simpleform import Form
from pyramid_deform import SessionFileUploadTempStore
from webhelpers2.html import HTML, tags
from tailbone import forms, grids
from tailbone import forms2 as forms, grids
from tailbone.db import Session
from tailbone.views import MasterView
from tailbone.progress import SessionProgress
@ -133,8 +137,9 @@ class BatchMasterView(MasterView):
kwargs['handler'] = self.handler
kwargs['execute_title'] = self.get_execute_title(batch)
kwargs['execute_enabled'] = self.instance_executable(batch)
if kwargs['execute_enabled'] and self.has_execution_options(batch):
kwargs['rendered_execution_options'] = self.render_execution_options(batch)
if kwargs['execute_enabled']:
url = self.get_action_url('execute', batch)
kwargs['execute_form'] = self.make_execute_form(batch, action_url=url)
return kwargs
def allow_worksheet(self, batch):
@ -179,22 +184,12 @@ class BatchMasterView(MasterView):
return batch.id_str
def template_kwargs_index(self, **kwargs):
kwargs['execute_enabled'] = self.instance_executable(None)
if kwargs['execute_enabled'] and self.has_execution_options():
kwargs['rendered_execution_options'] = self.render_execution_options()
route_prefix = self.get_route_prefix()
if self.results_executable:
url = self.request.route_url('{}.execute_results'.format(route_prefix))
kwargs['execute_form'] = self.make_execute_form(action_url=url)
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,
'form': forms.FormRenderer(form),
}
kwargs = self.get_exec_options_kwargs(**kwargs)
return self.render('exec_options', kwargs)
def get_exec_options_kwargs(self, **kwargs):
return kwargs
@ -422,10 +417,6 @@ class BatchMasterView(MasterView):
def template_kwargs_edit(self, **kwargs):
batch = kwargs['instance']
kwargs['batch'] = batch
kwargs['execute_title'] = self.get_execute_title(batch)
kwargs['execute_enabled'] = self.instance_executable(batch)
if kwargs['execute_enabled'] and self.has_execution_options(batch):
kwargs['rendered_execution_options'] = self.render_execution_options(batch)
return kwargs
def mobile_mark_complete(self):
@ -609,19 +600,28 @@ class BatchMasterView(MasterView):
# TODO
execution_options_schema = None
def make_execution_options_form(self, batch=None):
def make_execute_schema(self):
return self.execution_options_schema()
def make_execute_form(self, batch=None, **kwargs):
"""
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)
if key in self.request.session:
defaults[field] = self.request.session[key]
return Form(self.request, schema=self.execution_options_schema,
defaults=defaults or None)
route_prefix = self.get_route_prefix()
if self.has_execution_options(batch):
if batch is None:
batch = self.model_class
schema = self.make_execute_schema()
for field in schema:
key = 'batch.{}.execute_option.{}'.format(batch.batch_key, field.name)
if key in self.request.session:
defaults[field.name] = self.request.session[key]
else:
schema = colander.Schema()
return forms.Form(schema=schema, request=self.request, defaults=defaults, **kwargs)
def get_execute_title(self, batch):
if hasattr(self.handler, 'get_execute_title'):
@ -855,7 +855,8 @@ class BatchMasterView(MasterView):
"""
batch = self.get_instance()
query = self.get_effective_row_data(sort=False)
batch.rowcount -= query.count()
if batch.rowcount is not None:
batch.rowcount -= query.count()
query.update({'removed': True}, synchronize_session=False)
return self.redirect(self.get_action_url('view', batch))
@ -865,17 +866,14 @@ class BatchMasterView(MasterView):
displays a progress indicator page.
"""
batch = self.get_instance()
if self.request.method == 'POST':
self.executing = True
form = self.make_execute_form(batch)
if form.validate(newstyle=True):
kwargs = dict(form.validated)
kwargs = {}
if self.has_execution_options(batch):
form = self.make_execution_options_form(batch)
assert form.validate() # TODO
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(batch.batch_key, key)] = value
# cache options to use as defaults next time
for key, value in form.validated.items():
self.request.session['batch.{}.execute_option.{}'.format(batch.batch_key, key)] = value
key = '{}.execute'.format(self.model_class.__tablename__)
progress = SessionProgress(self.request, key)
@ -888,7 +886,7 @@ class BatchMasterView(MasterView):
'cancel_msg': "Batch execution was canceled.",
})
self.request.session.flash("Sorry, you must POST to execute a batch.", 'error')
self.request.session.flash("Invalid request: {}".format(form.make_deform_form().error), 'error')
return self.redirect(self.get_action_url('view', batch))
def execute_error_message(self, error):
@ -949,18 +947,13 @@ class BatchMasterView(MasterView):
Starts a separate thread for the execution, and displays a progress
indicator page.
"""
if self.request.method == 'POST':
form = self.make_execute_form()
if form.validate(newstyle=True):
kwargs = dict(form.validated)
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)] = value
# cache options to use as defaults next time
for key, value in form.validated.items():
self.request.session['batch.{}.execute_option.{}'.format(self.model_class.batch_key, key)] = value
key = '{}.execute_results'.format(self.model_class.__tablename__)
batches = self.get_effective_data()
@ -974,7 +967,7 @@ class BatchMasterView(MasterView):
'cancel_msg': "Batch execution was canceled",
})
self.request.session.flash("Sorry, you must POST to execute batches", 'error')
self.request.session.flash("Invalid request: {}".format(form.make_deform_form().error), 'error')
return self.redirect(self.get_index_url())
def execute_results_thread(self, batches, user_uuid, progress=None, **kwargs):

View file

@ -31,9 +31,10 @@ import os
from rattail.db import model
from rattail.util import OrderedDict
import formencode as fe
import colander
from webhelpers2.html import tags
from tailbone import forms2 as forms
from tailbone.db import Session
from tailbone.views.batch import FileBatchMasterView
@ -44,10 +45,12 @@ ACTION_OPTIONS = OrderedDict([
])
class ExecutionOptions(fe.Schema):
allow_extra_fields = True
filter_extra_fields = True
action = fe.validators.OneOf(ACTION_OPTIONS)
class ExecutionOptions(colander.Schema):
action = colander.SchemaNode(
colander.String(),
validator=colander.OneOf(ACTION_OPTIONS),
widget=forms.widgets.PlainSelectWidget(values=ACTION_OPTIONS.items()))
class HandheldBatchView(FileBatchMasterView):
@ -207,6 +210,9 @@ class HandheldBatchView(FileBatchMasterView):
return super(HandheldBatchView, self).get_execute_success_url(batch)
def get_execute_results_success_url(self, result, **kwargs):
if result is True:
# no batches were actually executed
return self.get_index_url()
batch = result
return self.get_execute_success_url(batch, result, **kwargs)

View file

@ -95,6 +95,7 @@ class MasterView(View):
viewing = False
editing = False
deleting = False
executing = False
has_pk_fields = False
row_attrs = {}

View file

@ -58,23 +58,26 @@ class VendorCatalogsView(FileBatchMasterView):
rows_bulk_deletable = True
grid_columns = [
'id',
'created',
'created_by',
'vendor',
'effective',
'filename',
'rowcount',
'executed',
]
form_fields = [
'id',
'vendor',
'filename',
'effective',
'created',
'created_by',
'rowcount',
'executed',
'executed_by',
'rowcount',
]
row_grid_columns = [