Remove all deprecated use_buefy logic

also remove some static files no longer used, etc.
This commit is contained in:
Lance Edgar 2023-02-03 12:05:17 -06:00
parent 01e5eee981
commit 9faaea881d
112 changed files with 2079 additions and 7039 deletions

View file

@ -24,12 +24,9 @@
Forms Core Forms Core
""" """
from __future__ import unicode_literals, absolute_import
import json import json
import logging import logging
import six
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import orm from sqlalchemy import orm
from sqlalchemy.ext.associationproxy import AssociationProxy, ASSOCIATION_PROXY from sqlalchemy.ext.associationproxy import AssociationProxy, ASSOCIATION_PROXY
@ -338,7 +335,7 @@ class Form(object):
model_instance=None, model_class=None, appstruct=UNSPECIFIED, nodes={}, enums={}, labels={}, model_instance=None, model_class=None, appstruct=UNSPECIFIED, nodes={}, enums={}, labels={},
assume_local_times=False, renderers=None, renderer_kwargs={}, assume_local_times=False, renderers=None, renderer_kwargs={},
hidden={}, widgets={}, defaults={}, validators={}, required={}, helptext={}, focus_spec=None, hidden={}, widgets={}, defaults={}, validators={}, required={}, helptext={}, focus_spec=None,
action_url=None, cancel_url=None, use_buefy=True, component='tailbone-form', action_url=None, cancel_url=None, component='tailbone-form',
vuejs_field_converters={}, vuejs_field_converters={},
# TODO: ugh this is getting out hand! # TODO: ugh this is getting out hand!
can_edit_help=False, edit_help_url=None, route_prefix=None, can_edit_help=False, edit_help_url=None, route_prefix=None,
@ -377,7 +374,6 @@ class Form(object):
self.focus_spec = focus_spec self.focus_spec = focus_spec
self.action_url = action_url self.action_url = action_url
self.cancel_url = cancel_url self.cancel_url = cancel_url
self.use_buefy = use_buefy
self.component = component self.component = component
self.vuejs_field_converters = vuejs_field_converters or {} self.vuejs_field_converters = vuejs_field_converters or {}
self.can_edit_help = can_edit_help self.can_edit_help = can_edit_help
@ -758,10 +754,7 @@ class Form(object):
def render(self, template=None, **kwargs): def render(self, template=None, **kwargs):
if not template: if not template:
if self.readonly and not self.use_buefy: template = '/forms/form.mako'
template = '/forms/form_readonly.mako'
else:
template = '/forms/form.mako'
context = kwargs context = kwargs
context['form'] = self context['form'] = self
return render(template, context) return render(template, context)
@ -806,10 +799,7 @@ class Form(object):
def render_deform(self, dform=None, template=None, **kwargs): def render_deform(self, dform=None, template=None, **kwargs):
if not template: if not template:
if self.use_buefy: template = '/forms/deform_buefy.mako'
template = '/forms/deform_buefy.mako'
else:
template = '/forms/deform.mako'
if dform is None: if dform is None:
dform = self.make_deform_form() dform = self.make_deform_form()
@ -829,11 +819,8 @@ class Form(object):
context.setdefault('form_kwargs', {}) context.setdefault('form_kwargs', {})
# TODO: deprecate / remove the latter option here # TODO: deprecate / remove the latter option here
if self.auto_disable_save or self.auto_disable: if self.auto_disable_save or self.auto_disable:
if self.use_buefy: context['form_kwargs'].setdefault('ref', self.component_studly)
context['form_kwargs'].setdefault('ref', self.component_studly) context['form_kwargs']['@submit'] = 'submit{}'.format(self.component_studly)
context['form_kwargs']['@submit'] = 'submit{}'.format(self.component_studly)
else:
context['form_kwargs']['class_'] = 'autodisable'
if self.focus_spec: if self.focus_spec:
context['form_kwargs']['data-focus'] = self.focus_spec context['form_kwargs']['data-focus'] = self.focus_spec
context['request'] = self.request context['request'] = self.request
@ -975,8 +962,7 @@ class Form(object):
if self.readonly or fieldname in self.readonly_fields: if self.readonly or fieldname in self.readonly_fields:
html = self.render_field_value(fieldname) or HTML.tag('span') html = self.render_field_value(fieldname) or HTML.tag('span')
elif field: elif field:
html = field.serialize(use_buefy=True, html = field.serialize(**self.get_renderer_kwargs(fieldname))
**self.get_renderer_kwargs(fieldname))
html = HTML.literal(html) html = HTML.literal(html)
# may need a complex label # may need a complex label
@ -1064,7 +1050,7 @@ class Form(object):
value = self.obtain_value(record, field_name) value = self.obtain_value(record, field_name)
if value is None: if value is None:
return "" return ""
return six.text_type(value) return str(value)
def render_datetime(self, record, field_name): def render_datetime(self, record, field_name):
value = self.obtain_value(record, field_name) value = self.obtain_value(record, field_name)
@ -1099,7 +1085,7 @@ class Form(object):
return "(${:0,.2f})".format(0 - value) return "(${:0,.2f})".format(0 - value)
return "${:0,.2f}".format(value) return "${:0,.2f}".format(value)
except ValueError: except ValueError:
return six.text_type(value) return str(value)
def render_quantity(self, obj, field): def render_quantity(self, obj, field):
value = self.obtain_value(obj, field) value = self.obtain_value(obj, field)
@ -1124,8 +1110,8 @@ class Form(object):
return "" return ""
enum = self.enums.get(field_name) enum = self.enums.get(field_name)
if enum and value in enum: if enum and value in enum:
return six.text_type(enum[value]) return str(enum[value])
return six.text_type(value) return str(value)
def render_codeblock(self, record, field_name): def render_codeblock(self, record, field_name):
value = self.obtain_value(record, field_name) value = self.obtain_value(record, field_name)
@ -1193,8 +1179,8 @@ class Form(object):
controls[i][1] = 'true' controls[i][1] = 'true'
elif value is False: elif value is False:
controls[i][1] = 'false' controls[i][1] = 'false'
elif not isinstance(value, six.string_types): elif not isinstance(value, str):
controls[i][1] = six.text_type(value) controls[i][1] = str(value)
dform = self.make_deform_form() dform = self.make_deform_form()
try: try:

View file

@ -1,69 +0,0 @@
ul.tagit {
padding: 1px 5px;
overflow: auto;
margin-left: inherit; /* usually we don't want the regular ul margins. */
margin-right: inherit;
}
ul.tagit li {
display: block;
float: left;
margin: 2px 5px 2px 0;
}
ul.tagit li.tagit-choice {
position: relative;
line-height: inherit;
}
input.tagit-hidden-field {
display: none;
}
ul.tagit li.tagit-choice-read-only {
padding: .2em .5em .2em .5em;
}
ul.tagit li.tagit-choice-editable {
padding: .2em 18px .2em .5em;
}
ul.tagit li.tagit-new {
padding: .25em 4px .25em 0;
}
ul.tagit li.tagit-choice a.tagit-label {
cursor: pointer;
text-decoration: none;
}
ul.tagit li.tagit-choice .tagit-close {
cursor: pointer;
position: absolute;
right: .1em;
top: 50%;
margin-top: -8px;
line-height: 17px;
}
/* used for some custom themes that don't need image icons */
ul.tagit li.tagit-choice .tagit-close .text-icon {
display: none;
}
ul.tagit li.tagit-choice input {
display: block;
float: left;
margin: 2px 5px 2px 0;
}
ul.tagit input[type="text"] {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
border: none;
margin: 0;
padding: 0;
width: inherit;
background-color: inherit;
outline: none;
}

View file

@ -1,48 +0,0 @@
/******************************
* login.css
******************************/
.logo img,
#logo {
display: block;
margin: 40px auto;
max-height: 350px;
max-width: 800px;
}
div.form {
margin: auto;
float: none;
text-align: center;
}
div.field-wrapper {
margin: 10px auto;
width: 300px;
}
div.field-wrapper label {
text-align: right;
width: auto;
}
div.field-wrapper div.field input[type="text"],
div.field-wrapper div.field input[type="password"] {
margin-left: 1em;
width: 150px;
}
div.buttons {
display: block;
}
div.buttons input {
margin: auto 5px;
}
/* this is for "login as chuck" tip in demo mode */
.tips {
margin-top: 2em;
text-align: center;
}

View file

@ -1,17 +0,0 @@
(function(b){b.widget("ui.tagit",{options:{allowDuplicates:!1,caseSensitive:!0,fieldName:"tags",placeholderText:null,readOnly:!1,removeConfirmation:!1,tagLimit:null,availableTags:[],autocomplete:{},showAutocompleteOnFocus:!1,allowSpaces:!1,singleField:!1,singleFieldDelimiter:",",singleFieldNode:null,animate:!0,tabIndex:null,beforeTagAdded:null,afterTagAdded:null,beforeTagRemoved:null,afterTagRemoved:null,onTagClicked:null,onTagLimitExceeded:null,onTagAdded:null,onTagRemoved:null,tagSource:null},_create:function(){var a=
this;this.element.is("input")?(this.tagList=b("<ul></ul>").insertAfter(this.element),this.options.singleField=!0,this.options.singleFieldNode=this.element,this.element.addClass("tagit-hidden-field")):this.tagList=this.element.find("ul, ol").andSelf().last();this.tagInput=b('<input type="text" />').addClass("ui-widget-content");this.options.readOnly&&this.tagInput.attr("disabled","disabled");this.options.tabIndex&&this.tagInput.attr("tabindex",this.options.tabIndex);this.options.placeholderText&&this.tagInput.attr("placeholder",
this.options.placeholderText);this.options.autocomplete.source||(this.options.autocomplete.source=function(a,e){var d=a.term.toLowerCase(),c=b.grep(this.options.availableTags,function(a){return 0===a.toLowerCase().indexOf(d)});this.options.allowDuplicates||(c=this._subtractArray(c,this.assignedTags()));e(c)});this.options.showAutocompleteOnFocus&&(this.tagInput.focus(function(b,d){a._showAutocomplete()}),"undefined"===typeof this.options.autocomplete.minLength&&(this.options.autocomplete.minLength=
0));b.isFunction(this.options.autocomplete.source)&&(this.options.autocomplete.source=b.proxy(this.options.autocomplete.source,this));b.isFunction(this.options.tagSource)&&(this.options.tagSource=b.proxy(this.options.tagSource,this));this.tagList.addClass("tagit").addClass("ui-widget ui-widget-content ui-corner-all").append(b('<li class="tagit-new"></li>').append(this.tagInput)).click(function(d){var c=b(d.target);c.hasClass("tagit-label")?(c=c.closest(".tagit-choice"),c.hasClass("removed")||a._trigger("onTagClicked",
d,{tag:c,tagLabel:a.tagLabel(c)})):a.tagInput.focus()});var c=!1;if(this.options.singleField)if(this.options.singleFieldNode){var d=b(this.options.singleFieldNode),f=d.val().split(this.options.singleFieldDelimiter);d.val("");b.each(f,function(b,d){a.createTag(d,null,!0);c=!0})}else this.options.singleFieldNode=b('<input type="hidden" style="display:none;" value="" name="'+this.options.fieldName+'" />'),this.tagList.after(this.options.singleFieldNode);c||this.tagList.children("li").each(function(){b(this).hasClass("tagit-new")||
(a.createTag(b(this).text(),b(this).attr("class"),!0),b(this).remove())});this.tagInput.keydown(function(c){if(c.which==b.ui.keyCode.BACKSPACE&&""===a.tagInput.val()){var d=a._lastTag();!a.options.removeConfirmation||d.hasClass("remove")?a.removeTag(d):a.options.removeConfirmation&&d.addClass("remove ui-state-highlight")}else a.options.removeConfirmation&&a._lastTag().removeClass("remove ui-state-highlight");if(c.which===b.ui.keyCode.COMMA&&!1===c.shiftKey||c.which===b.ui.keyCode.ENTER||c.which==
b.ui.keyCode.TAB&&""!==a.tagInput.val()||c.which==b.ui.keyCode.SPACE&&!0!==a.options.allowSpaces&&('"'!=b.trim(a.tagInput.val()).replace(/^s*/,"").charAt(0)||'"'==b.trim(a.tagInput.val()).charAt(0)&&'"'==b.trim(a.tagInput.val()).charAt(b.trim(a.tagInput.val()).length-1)&&0!==b.trim(a.tagInput.val()).length-1))c.which===b.ui.keyCode.ENTER&&""===a.tagInput.val()||c.preventDefault(),a.options.autocomplete.autoFocus&&a.tagInput.data("autocomplete-open")||(a.tagInput.autocomplete("close"),a.createTag(a._cleanedInput()))}).blur(function(b){a.tagInput.data("autocomplete-open")||
a.createTag(a._cleanedInput())});if(this.options.availableTags||this.options.tagSource||this.options.autocomplete.source)d={select:function(b,c){a.createTag(c.item.value);return!1}},b.extend(d,this.options.autocomplete),d.source=this.options.tagSource||d.source,this.tagInput.autocomplete(d).bind("autocompleteopen.tagit",function(b,c){a.tagInput.data("autocomplete-open",!0)}).bind("autocompleteclose.tagit",function(b,c){a.tagInput.data("autocomplete-open",!1)}),this.tagInput.autocomplete("widget").addClass("tagit-autocomplete")},
destroy:function(){b.Widget.prototype.destroy.call(this);this.element.unbind(".tagit");this.tagList.unbind(".tagit");this.tagInput.removeData("autocomplete-open");this.tagList.removeClass("tagit ui-widget ui-widget-content ui-corner-all tagit-hidden-field");this.element.is("input")?(this.element.removeClass("tagit-hidden-field"),this.tagList.remove()):(this.element.children("li").each(function(){b(this).hasClass("tagit-new")?b(this).remove():(b(this).removeClass("tagit-choice ui-widget-content ui-state-default ui-state-highlight ui-corner-all remove tagit-choice-editable tagit-choice-read-only"),
b(this).text(b(this).children(".tagit-label").text()))}),this.singleFieldNode&&this.singleFieldNode.remove());return this},_cleanedInput:function(){return b.trim(this.tagInput.val().replace(/^"(.*)"$/,"$1"))},_lastTag:function(){return this.tagList.find(".tagit-choice:last:not(.removed)")},_tags:function(){return this.tagList.find(".tagit-choice:not(.removed)")},assignedTags:function(){var a=this,c=[];this.options.singleField?(c=b(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter),
""===c[0]&&(c=[])):this._tags().each(function(){c.push(a.tagLabel(this))});return c},_updateSingleTagsField:function(a){b(this.options.singleFieldNode).val(a.join(this.options.singleFieldDelimiter)).trigger("change")},_subtractArray:function(a,c){for(var d=[],f=0;f<a.length;f++)-1==b.inArray(a[f],c)&&d.push(a[f]);return d},tagLabel:function(a){return this.options.singleField?b(a).find(".tagit-label:first").text():b(a).find("input:first").val()},_showAutocomplete:function(){this.tagInput.autocomplete("search",
"")},_findTagByLabel:function(a){var c=this,d=null;this._tags().each(function(f){if(c._formatStr(a)==c._formatStr(c.tagLabel(this)))return d=b(this),!1});return d},_isNew:function(a){return!this._findTagByLabel(a)},_formatStr:function(a){return this.options.caseSensitive?a:b.trim(a.toLowerCase())},_effectExists:function(a){return Boolean(b.effects&&(b.effects[a]||b.effects.effect&&b.effects.effect[a]))},createTag:function(a,c,d){var f=this;a=b.trim(a);this.options.preprocessTag&&(a=this.options.preprocessTag(a));
if(""===a)return!1;if(!this.options.allowDuplicates&&!this._isNew(a))return a=this._findTagByLabel(a),!1!==this._trigger("onTagExists",null,{existingTag:a,duringInitialization:d})&&this._effectExists("highlight")&&a.effect("highlight"),!1;if(this.options.tagLimit&&this._tags().length>=this.options.tagLimit)return this._trigger("onTagLimitExceeded",null,{duringInitialization:d}),!1;var g=b(this.options.onTagClicked?'<a class="tagit-label"></a>':'<span class="tagit-label"></span>').text(a),e=b("<li></li>").addClass("tagit-choice ui-widget-content ui-state-default ui-corner-all").addClass(c).append(g);
this.options.readOnly?e.addClass("tagit-choice-read-only"):(e.addClass("tagit-choice-editable"),c=b("<span></span>").addClass("ui-icon ui-icon-close"),c=b('<a><span class="text-icon">\u00d7</span></a>').addClass("tagit-close").append(c).click(function(a){f.removeTag(e)}),e.append(c));this.options.singleField||(g=g.html(),e.append('<input type="hidden" value="'+g+'" name="'+this.options.fieldName+'" class="tagit-hidden-field" />'));!1!==this._trigger("beforeTagAdded",null,{tag:e,tagLabel:this.tagLabel(e),
duringInitialization:d})&&(this.options.singleField&&(g=this.assignedTags(),g.push(a),this._updateSingleTagsField(g)),this._trigger("onTagAdded",null,e),this.tagInput.val(""),this.tagInput.parent().before(e),this._trigger("afterTagAdded",null,{tag:e,tagLabel:this.tagLabel(e),duringInitialization:d}),this.options.showAutocompleteOnFocus&&!d&&setTimeout(function(){f._showAutocomplete()},0))},removeTag:function(a,c){c="undefined"===typeof c?this.options.animate:c;a=b(a);this._trigger("onTagRemoved",
null,a);if(!1!==this._trigger("beforeTagRemoved",null,{tag:a,tagLabel:this.tagLabel(a)})){if(this.options.singleField){var d=this.assignedTags(),f=this.tagLabel(a),d=b.grep(d,function(a){return a!=f});this._updateSingleTagsField(d)}if(c){a.addClass("removed");var d=this._effectExists("blind")?["blind",{direction:"horizontal"},"fast"]:["fast"],g=this;d.push(function(){a.remove();g._trigger("afterTagRemoved",null,{tag:a,tagLabel:g.tagLabel(a)})});a.fadeOut("fast").hide.apply(a,d).dequeue()}else a.remove(),
this._trigger("afterTagRemoved",null,{tag:a,tagLabel:this.tagLabel(a)})}},removeTagByLabel:function(a,b){var d=this._findTagByLabel(a);if(!d)throw"No such tag exists with the name '"+a+"'";this.removeTag(d,b)},removeAll:function(){var a=this;this._tags().each(function(b,d){a.removeTag(d,!1)})}})})(jQuery);

View file

@ -1,32 +0,0 @@
$(function() {
$('input[name="username"]').keydown(function(event) {
if (event.which == 13) {
$('input[name="password"]').focus().select();
return false;
}
return true;
});
$('form').submit(function() {
if (! $('input[name="username"]').val()) {
with ($('input[name="username"]').get(0)) {
select();
focus();
}
return false;
}
if (! $('input[name="password"]').val()) {
with ($('input[name="password"]').get(0)) {
select();
focus();
}
return false;
}
return true;
});
$('input[name="username"]').focus();
});

View file

@ -1,29 +0,0 @@
/************************************************************
*
* tailbone.appsettings.js
*
* Logic for App Settings page.
*
************************************************************/
function show_group(group) {
if (group == "(All)") {
$('.panel').show();
} else {
$('.panel').hide();
$('.panel[data-groupname="' + group + '"]').show();
}
}
$(function() {
$('#settings-group').on('selectmenuchange', function(event, ui) {
show_group(ui.item.value);
});
show_group($('#settings-group').val());
});

View file

@ -1,41 +0,0 @@
/************************************************************
*
* tailbone.batch.js
*
* Common logic for view/edit batch pages
*
************************************************************/
$(function() {
$('#execute-batch').click(function() {
if (has_execution_options) {
$('#execution-options-dialog').dialog({
title: "Execution Options",
width: 600,
modal: true,
buttons: [
{
text: "Execute",
click: function(event) {
dialog_button(event).button('option', 'label', "Executing, please wait...").button('disable');
$('form[name="batch-execution"]').submit();
}
},
{
text: "Cancel",
click: function() {
$(this).dialog('close');
}
}
]
});
} else {
$(this).button('option', 'label', "Executing, please wait...").button('disable');
$('form[name="batch-execution"]').submit();
}
});
});

View file

@ -24,8 +24,6 @@
Event Subscribers Event Subscribers
""" """
from __future__ import unicode_literals, absolute_import
import six import six
import json import json
import datetime import datetime
@ -42,7 +40,7 @@ from tailbone import helpers
from tailbone.db import Session from tailbone.db import Session
from tailbone.config import csrf_header_name, should_expose_websockets from tailbone.config import csrf_header_name, should_expose_websockets
from tailbone.menus import make_simple_menus from tailbone.menus import make_simple_menus
from tailbone.util import should_use_buefy, get_global_search_options from tailbone.util import get_global_search_options
def new_request(event): def new_request(event):
@ -156,23 +154,20 @@ def before_render(event):
renderer_globals['background_color'] = request.rattail_config.get( renderer_globals['background_color'] = request.rattail_config.get(
'tailbone', 'background_color') 'tailbone', 'background_color')
# buefy themes get some extra treatment # TODO: remove this hack once nothing references it
if should_use_buefy(request): renderer_globals['buefy_0_8'] = False
# TODO: remove this hack once nothing references it # maybe set custom stylesheet
renderer_globals['buefy_0_8'] = False css = None
if request.user:
css = request.rattail_config.get('tailbone.{}'.format(request.user.uuid),
'buefy_css')
if not css:
css = request.rattail_config.get('tailbone', 'theme.falafel.buefy_css')
renderer_globals['buefy_css'] = css
# maybe set custom stylesheet # add global search data for quick access
css = None renderer_globals['global_search_data'] = get_global_search_options(request)
if request.user:
css = request.rattail_config.get('tailbone.{}'.format(request.user.uuid),
'buefy_css')
if not css:
css = request.rattail_config.get('tailbone', 'theme.falafel.buefy_css')
renderer_globals['buefy_css'] = css
# add global search data for quick access
renderer_globals['global_search_data'] = get_global_search_options(request)
# here we globally declare widths for grid filter pseudo-columns # here we globally declare widths for grid filter pseudo-columns
widths = request.rattail_config.get('tailbone', 'grids.filters.column_widths') widths = request.rattail_config.get('tailbone', 'grids.filters.column_widths')

View file

@ -5,34 +5,6 @@
<%def name="content_title()"></%def> <%def name="content_title()"></%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.appsettings.js') + '?ver={}'.format(tailbone.__version__))}
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if not use_buefy:
<style type="text/css">
div.form {
float: none;
}
div.panel {
width: 85%;
}
.field-wrapper {
margin-bottom: 2em;
}
.panel .field-wrapper label {
font-family: monospace;
width: 50em;
}
</style>
% endif
</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
% if request.has_perm('settings.list'): % if request.has_perm('settings.list'):
<li>${h.link_to("View Raw Settings", url('settings'))}</li> <li>${h.link_to("View Raw Settings", url('settings'))}</li>
@ -223,76 +195,4 @@
</%def> </%def>
% if use_buefy: ${parent.body()}
${parent.body()}
% else:
## legacy / not buefy
<div class="form">
${h.form(form.action_url, id=dform.formid, method='post', class_='autodisable')}
${h.csrf_token(request)}
% if dform.error:
<div class="error-messages">
<div class="ui-state-error ui-corner-all">
<span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-alert"></span>
Please see errors below.
</div>
<div class="ui-state-error ui-corner-all">
<span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-alert"></span>
${dform.error}
</div>
</div>
% endif
<div class="group-picker">
<div class="field-wrapper">
<label for="settings-group">Showing Group</label>
<div class="field select">
${h.select('settings-group', current_group, group_options, **{'auto-enhance': 'true'})}
</div>
</div>
</div>
% for group in groups:
<div class="panel" data-groupname="${group}">
<h2>${group}</h2>
<div class="panel-body">
% for setting in settings:
% if setting.group == group:
<% field = dform[setting.node_name] %>
<div class="field-wrapper ${field.name} ${'with-error' if field.error else ''}">
% if field.error:
<div class="field-error">
% for msg in field.error.messages():
<span class="error-msg">${msg}</span>
% endfor
</div>
% endif
<div class="field-row">
<label for="${field.oid}">${form.get_label(field.name)}</label>
<div class="field">
${field.serialize()|n}
</div>
</div>
% if form.has_helptext(field.name):
<span class="instructions">${form.render_helptext(field.name)}</span>
% endif
</div>
% endif
% endfor
</div><!-- panel-body -->
</div><! -- panel -->
% endfor
<div class="buttons">
${h.submit('save', getattr(form, 'submit_label', getattr(form, 'save_label', "Submit")), class_='button is-primary')}
${h.link_to("Cancel", form.cancel_url, class_='cancel button{}'.format(' autodisable' if form.auto_disable_cancel else ''))}
</div>
${h.end_form()}
</div>
% endif

View file

@ -76,12 +76,5 @@
</div> </div>
</%def> </%def>
<%def name="render_form()">
${parent.render_form()}
% if not use_buefy:
${self.field_diff_table()}
% endif
</%def>
${parent.body()} ${parent.body()}

View file

@ -1,150 +1,66 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/index.mako" /> <%inherit file="/master/index.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
% if master.results_executable and master.has_perm('execute_multiple'):
<script type="text/javascript">
var has_execution_options = ${'true' if master.has_execution_options(batch) else 'false'};
var dialog_opened = false;
$(function() {
$('#refresh-results-button').click(function() {
var count = $('.grid-wrapper').gridwrapper('results_count');
if (!count) {
alert("There are no batch results to refresh.");
return;
}
var form = $('form[name="refresh-results"]');
$(this).button('option', 'label', "Refreshing, please wait...").button('disable');
form.submit();
});
$('#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({
title: "Execution Options",
width: 550,
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');
}
}
],
open: function() {
if (! dialog_opened) {
$('#execution-options-dialog select[auto-enhance="true"]').selectmenu();
$('#execution-options-dialog select[auto-enhance="true"]').on('selectmenuopen', function(event, ui) {
show_all_options($(this));
});
dialog_opened = true;
}
}
});
} else {
$(this).button('option', 'label', "Executing, please wait...").button('disable');
form.submit();
}
});
});
</script>
% endif
% endif
</%def>
<%def name="grid_tools()"> <%def name="grid_tools()">
${parent.grid_tools()} ${parent.grid_tools()}
## Refresh Results ## Refresh Results
% if master.results_refreshable and master.has_perm('refresh'): % if master.results_refreshable and master.has_perm('refresh'):
% if use_buefy: <b-button type="is-primary"
<b-button type="is-primary" :disabled="refreshResultsButtonDisabled"
:disabled="refreshResultsButtonDisabled" icon-pack="fas"
icon-pack="fas" icon-left="fas fa-redo"
icon-left="fas fa-redo" @click="refreshResults()">
@click="refreshResults()"> {{ refreshResultsButtonText }}
{{ refreshResultsButtonText }} </b-button>
</b-button> ${h.form(url('{}.refresh_results'.format(route_prefix)), ref='refreshResultsForm')}
${h.form(url('{}.refresh_results'.format(route_prefix)), ref='refreshResultsForm')} ${h.csrf_token(request)}
${h.csrf_token(request)} ${h.end_form()}
${h.end_form()}
% else:
<button type="button" id="refresh-results-button">
Refresh Results
</button>
% endif
% endif % endif
## Execute Results ## Execute Results
% if master.results_executable and master.has_perm('execute_multiple'): % if master.results_executable and master.has_perm('execute_multiple'):
% if use_buefy: <b-button type="is-primary"
<b-button type="is-primary" @click="executeResults()"
@click="executeResults()" icon-pack="fas"
icon-pack="fas" icon-left="arrow-circle-right"
icon-left="arrow-circle-right" :disabled="!total">
:disabled="!total"> Execute Results
Execute Results </b-button>
</b-button>
<b-modal has-modal-card <b-modal has-modal-card
:active.sync="showExecutionOptions"> :active.sync="showExecutionOptions">
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
<p class="modal-card-title">Execution Options</p> <p class="modal-card-title">Execution Options</p>
</header> </header>
<section class="modal-card-body">
<p>
Please be advised, you are about to execute {{ total }} batches!
</p>
<br />
<div class="form-wrapper">
<div class="form">
<${execute_form.component} ref="executeResultsForm"></${execute_form.component}>
</div>
</div>
</section>
<footer class="modal-card-foot">
<b-button @click="showExecutionOptions = false">
Cancel
</b-button>
<once-button type="is-primary"
@click="submitExecuteResults()"
icon-left="arrow-circle-right"
:text="'Execute ' + total + ' Batches'">
</once-button>
</footer>
<section class="modal-card-body">
<p>
Please be advised, you are about to execute {{ total }} batches!
</p>
<br />
<div class="form-wrapper">
<div class="form">
<${execute_form.component} ref="executeResultsForm"></${execute_form.component}>
</div>
</div> </div>
</b-modal> </section>
% else: <footer class="modal-card-foot">
<button type="button" id="execute-results-button">Execute Results</button> <b-button @click="showExecutionOptions = false">
% endif Cancel
</b-button>
<once-button type="is-primary"
@click="submitExecuteResults()"
icon-left="arrow-circle-right"
:text="'Execute ' + total + ' Batches'">
</once-button>
</footer>
</div>
</b-modal>
% endif % endif
</%def> </%def>
@ -224,24 +140,3 @@
${parent.body()} ${parent.body()}
% if not use_buefy:
## Refresh Results
% if master.results_refreshable and master.has_perm('refresh'):
${h.form(url('{}.refresh_results'.format(route_prefix)), name='refresh-results')}
${h.csrf_token(request)}
${h.end_form()}
% endif
% if master.results_executable and master.has_perm('execute_multiple'):
<div id="execution-options-dialog" style="display: none;">
<br />
<p>
Please be advised, you are about to execute multiple batches!
</p>
<br />
${execute_form.render_deform(form_kwargs={'name': 'execute-results'}, buttons=False)|n}
</div>
% endif
% endif

View file

@ -3,298 +3,67 @@
<%def name="title()">Inventory Form</%def> <%def name="title()">Inventory Form</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
<script type="text/javascript">
function assert_quantity() {
% if allow_cases:
var cases = parseFloat($('#cases').val());
if (!isNaN(cases)) {
if (cases > 999999) {
alert("Case amount is invalid!");
$('#cases').select().focus();
return false;
}
return true;
}
% endif
var units = parseFloat($('#units').val());
if (!isNaN(units)) {
if (units > 999999) {
alert("Unit amount is invalid!");
$('#units').select().focus();
return false;
}
return true;
}
alert("Please provide case and/or unit quantity");
% if allow_cases:
$('#cases').select().focus();
% else:
$('#units').select().focus();
% endif
return false;
}
function invalid_product(msg) {
$('#product-info p').text(msg);
$('#product-info img').hide();
$('#upc').focus().select();
% if allow_cases:
$('.field-wrapper.cases input').prop('disabled', true);
% endif
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
}
function pretty_quantity(cases, units) {
if (cases && units) {
return cases + " cases, " + units + " units";
} else if (cases) {
return cases + " cases";
} else if (units) {
return units + " units";
}
return '';
}
function show_quantity(name, cases, units) {
var quantity = pretty_quantity(cases, units);
var field = $('.field-wrapper.quantity_' + name);
field.find('.field').text(quantity);
if (quantity || name == 'ordered') {
field.show();
} else {
field.hide();
}
}
$(function() {
$('#upc').keydown(function(event) {
if (key_allowed(event)) {
return true;
}
if (key_modifies(event)) {
$('#product').val('');
$('#product-info p').html("please ENTER a scancode");
$('#product-info img').hide();
$('#product-info .warning').hide();
$('.product-fields').hide();
// $('.receiving-fields').hide();
% if allow_cases:
$('.field-wrapper.cases input').prop('disabled', true);
% endif
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
return true;
}
// when user presses ENTER, do product lookup
if (event.which == 13) {
var upc = $(this).val();
var data = {'upc': upc};
$.get('${url('batch.inventory.desktop_lookup', uuid=batch.uuid)}', data, function(data) {
if (data.error) {
alert(data.error);
if (data.redirect) {
$('#inventory-form').mask("Redirecting...");
location.href = data.redirect;
}
} else if (data.product) {
$('#upc').val(data.product.upc_pretty);
$('#product').val(data.product.uuid);
$('#brand_name').val(data.product.brand_name);
$('#description').val(data.product.description);
$('#size').val(data.product.size);
$('#case_quantity').val(data.product.case_quantity);
if (data.force_unit_item) {
$('#product-info .warning.force-unit').show();
}
if (data.already_present_in_batch) {
$('#product-info .warning.present').show();
$('#cases').val(data.cases);
$('#units').val(data.units);
} else if (data.product.type2) {
$('#units').val(data.product.units);
}
$('#product-info p').text(data.product.full_description);
$('#product-info img').attr('src', data.product.image_url).show();
if (! data.product.uuid) {
// $('#product-info .warning.notfound').show();
$('.product-fields').show();
}
$('#product-info .warning.notordered').show();
% if allow_cases:
$('.field-wrapper.cases input').prop('disabled', false);
% endif
$('.field-wrapper.units input').prop('disabled', false);
$('.buttons button').button('enable');
if (data.product.type2) {
$('#units').focus().select();
} else {
% if allow_cases and prefer_cases:
if ($('#cases').val()) {
$('#cases').focus().select();
} else if ($('#units').val()) {
$('#units').focus().select();
} else {
$('#cases').focus().select();
}
% else:
$('#units').focus().select();
% endif
}
// TODO: this is maybe useful if "new products" may be added via inventory batch
// } else if (data.upc) {
// $('#upc').val(data.upc_pretty);
// $('#product-info p').text("product not found in our system");
// $('#product-info img').attr('src', data.image_url).show();
// $('#product').val('');
// $('#brand_name').val('');
// $('#description').val('');
// $('#size').val('');
// $('#case_quantity').val('');
// $('#product-info .warning.notfound').show();
// $('.product-fields').show();
// $('#brand_name').focus();
// $('.field-wrapper.cases input').prop('disabled', false);
// $('.field-wrapper.units input').prop('disabled', false);
// $('.buttons button').button('enable');
} else {
invalid_product('product not found');
}
});
}
return false;
});
$('#inventory-form').submit(function() {
if (! assert_quantity()) {
return false;
}
disable_submit_button(this);
$(this).mask("Working...");
});
$('#upc').focus();
% if allow_cases:
$('.field-wrapper.cases input').prop('disabled', true);
% endif
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if not use_buefy:
<style type="text/css">
#product-info {
margin-top: 0.5em;
text-align: center;
}
#product-info p {
margin-left: 0.5em;
}
#product-info .img-wrapper {
height: 150px;
margin: 0.5em 0;
}
#product-info .warning {
background: #f66;
display: none;
}
</style>
% endif
</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
${parent.context_menu_items()} ${parent.context_menu_items()}
<li>${h.link_to("Back to Inventory Batch", url('batch.inventory.view', uuid=batch.uuid))}</li> <li>${h.link_to("Back to Inventory Batch", url('batch.inventory.view', uuid=batch.uuid))}</li>
</%def> </%def>
<%def name="render_form()"> <%def name="render_form()">
% if use_buefy: <script type="text/x-template" id="${form.component}-template">
<div class="product-info">
<script type="text/x-template" id="${form.component}-template"> ${h.form(form.action_url, **{'@submit': 'handleSubmit'})}
<div class="product-info"> ${h.csrf_token(request)}
${h.form(form.action_url, **{'@submit': 'handleSubmit'})} ${h.hidden('product', **{':value': 'productInfo.uuid'})}
${h.csrf_token(request)} ${h.hidden('upc', **{':value': 'productInfo.upc'})}
${h.hidden('brand_name', **{':value': 'productInfo.brand_name'})}
${h.hidden('description', **{':value': 'productInfo.description'})}
${h.hidden('size', **{':value': 'productInfo.size'})}
${h.hidden('case_quantity', **{':value': 'productInfo.case_quantity'})}
${h.hidden('product', **{':value': 'productInfo.uuid'})} <b-field label="Product UPC" horizontal>
${h.hidden('upc', **{':value': 'productInfo.upc'})} <div style="display: flex; flex-direction: column;">
${h.hidden('brand_name', **{':value': 'productInfo.brand_name'})} <b-input v-model="productUPC"
${h.hidden('description', **{':value': 'productInfo.description'})} ref="productUPC"
${h.hidden('size', **{':value': 'productInfo.size'})} @input="productChanged"
${h.hidden('case_quantity', **{':value': 'productInfo.case_quantity'})} @keydown.native="productKeydown">
</b-input>
<div class="has-text-centered block">
<b-field label="Product UPC" horizontal> <p v-if="!productInfo.uuid"
<div style="display: flex; flex-direction: column;"> class="block">
<b-input v-model="productUPC" please ENTER a scancode
ref="productUPC" </p>
@input="productChanged"
@keydown.native="productKeydown">
</b-input>
<div class="has-text-centered block">
<p v-if="!productInfo.uuid" <p v-if="productInfo.uuid"
class="block"> class="block">
please ENTER a scancode {{ productInfo.full_description }}
</p> </p>
<p v-if="productInfo.uuid" <div style="min-height: 150px; margin: 0.5rem 0;">
class="block"> <img v-if="productInfo.uuid"
{{ productInfo.full_description }} :src="productInfo.image_url" />
</p> </div>
<div style="min-height: 150px; margin: 0.5rem 0;"> <div v-if="alreadyPresentInBatch"
<img v-if="productInfo.uuid" class="has-background-danger">
:src="productInfo.image_url" /> product already exists in batch, please confirm count
</div> </div>
<div v-if="alreadyPresentInBatch" <div v-if="forceUnitItem"
class="has-background-danger"> class="has-background-danger">
product already exists in batch, please confirm count pack item scanned, but must count units instead
</div> </div>
<div v-if="forceUnitItem"
class="has-background-danger">
pack item scanned, but must count units instead
</div>
## <div v-if="productNotFound" ## <div v-if="productNotFound"
## class="has-background-danger"> ## class="has-background-danger">
## please confirm UPC and provide more details ## please confirm UPC and provide more details
## </div> ## </div>
</div> </div>
</div> </div>
</b-field> </b-field>
## <div v-if="productNotFound" ## <div v-if="productNotFound"
## ## class="product-fields" ## ## class="product-fields"
@ -322,243 +91,176 @@
## ##
## </div> ## </div>
% if allow_cases: % if allow_cases:
<b-field label="Cases" horizontal> <b-field label="Cases" horizontal>
<b-input name="cases" <b-input name="cases"
v-model="productCases" v-model="productCases"
ref="productCases" ref="productCases"
:disabled="!productInfo.uuid">
</b-input>
</b-field>
% endif
<b-field label="Units" horizontal>
<b-input name="units"
v-model="productUnits"
ref="productUnits"
:disabled="!productInfo.uuid"> :disabled="!productInfo.uuid">
</b-input> </b-input>
</b-field> </b-field>
% endif
<b-button type="is-primary" <b-field label="Units" horizontal>
native-type="submit" <b-input name="units"
:disabled="submitting"> v-model="productUnits"
{{ submitting ? "Working, please wait..." : "Submit" }} ref="productUnits"
</b-button> :disabled="!productInfo.uuid">
</b-input>
</b-field>
${h.end_form()} <b-button type="is-primary"
</div> native-type="submit"
</script> :disabled="submitting">
{{ submitting ? "Working, please wait..." : "Submit" }}
</b-button>
<script type="text/javascript"> ${h.end_form()}
</div>
</script>
let ${form.component_studly} = { <script type="text/javascript">
template: '#${form.component}-template',
mounted() { let ${form.component_studly} = {
this.$refs.productUPC.focus() template: '#${form.component}-template',
mounted() {
this.$refs.productUPC.focus()
},
methods: {
clearProduct() {
this.productInfo = {}
## this.productNotFound = false
this.alreadyPresentInBatch = false
this.forceUnitItem = false
this.productCases = null
this.productUnits = null
}, },
methods: { assertQuantity() {
clearProduct() { % if allow_cases:
this.productInfo = {} let cases = parseFloat(this.productCases)
## this.productNotFound = false if (!isNaN(cases)) {
this.alreadyPresentInBatch = false if (cases > 999999) {
this.forceUnitItem = false alert("Case amount is invalid!")
this.productCases = null this.$refs.productCases.focus()
this.productUnits = null
},
assertQuantity() {
% if allow_cases:
let cases = parseFloat(this.productCases)
if (!isNaN(cases)) {
if (cases > 999999) {
alert("Case amount is invalid!")
this.$refs.productCases.focus()
return false
}
return true
}
% endif
let units = parseFloat(this.productUnits)
if (!isNaN(units)) {
if (units > 999999) {
alert("Unit amount is invalid!")
this.$refs.productUnits.focus()
return false return false
} }
return true return true
} }
% endif
alert("Please provide case and/or unit quantity") let units = parseFloat(this.productUnits)
% if allow_cases: if (!isNaN(units)) {
this.$refs.productCases.focus() if (units > 999999) {
% else: alert("Unit amount is invalid!")
this.$refs.productUnits.focus() this.$refs.productUnits.focus()
% endif return false
},
handleSubmit(event) {
if (!this.assertQuantity()) {
event.preventDefault()
return
} }
this.submitting = true return true
}, }
productChanged() { alert("Please provide case and/or unit quantity")
this.clearProduct() % if allow_cases:
}, this.$refs.productCases.focus()
% else:
productKeydown(event) { this.$refs.productUnits.focus()
if (event.which == 13) { // ENTER % endif
this.productLookup()
event.preventDefault()
}
},
productLookup() {
let url = '${url('batch.inventory.desktop_lookup', uuid=batch.uuid)}'
let params = {
upc: this.productUPC,
}
this.$http.get(url, {params: params}).then(response => {
if (response.data.error) {
alert(response.data.error)
if (response.data.redirect) {
location.href = response.data.redirect
}
} else if (response.data.product.uuid) {
this.productUPC = response.data.product.upc_pretty
this.productInfo = response.data.product
this.forceUnitItem = response.data.force_unit_item
this.alreadyPresentInBatch = response.data.already_present_in_batch
if (this.alreadyPresentInBatch) {
this.productCases = response.data.cases
this.productUnits = response.data.units
} else if (this.productInfo.type2) {
this.productUnits = this.productInfo.units
}
this.$nextTick(() => {
if (this.productInfo.type2) {
this.$refs.productUnits.focus()
} else {
% if allow_cases and prefer_cases:
if (this.productCases) {
this.$refs.productCases.focus()
} else if (this.productUnits) {
this.$refs.productUnits.focus()
} else {
this.$refs.productCases.focus()
}
% else:
this.$refs.productUnits.focus()
% endif
}
})
} else {
## this.productNotFound = true
alert("Product not found!")
}
})
},
}, },
}
let ${form.component_studly}Data = { handleSubmit(event) {
submitting: false, if (!this.assertQuantity()) {
event.preventDefault()
return
}
this.submitting = true
},
productUPC: null, productChanged() {
## productNotFound: false, this.clearProduct()
productInfo: {}, },
% if allow_cases: productKeydown(event) {
productCases: null, if (event.which == 13) { // ENTER
% endif this.productLookup()
productUnits: null, event.preventDefault()
}
},
alreadyPresentInBatch: false, productLookup() {
forceUnitItem: false, let url = '${url('batch.inventory.desktop_lookup', uuid=batch.uuid)}'
} let params = {
upc: this.productUPC,
}
this.$http.get(url, {params: params}).then(response => {
</script> if (response.data.error) {
alert(response.data.error)
if (response.data.redirect) {
location.href = response.data.redirect
}
% else: } else if (response.data.product.uuid) {
## not buefy
<div class="form-wrapper"> this.productUPC = response.data.product.upc_pretty
${h.form(form.action_url, id='inventory-form')} this.productInfo = response.data.product
${h.csrf_token(request)} this.forceUnitItem = response.data.force_unit_item
this.alreadyPresentInBatch = response.data.already_present_in_batch
<div class="field-wrapper"> if (this.alreadyPresentInBatch) {
<label for="upc">Product UPC</label> this.productCases = response.data.cases
<div class="field"> this.productUnits = response.data.units
${h.hidden('product')} } else if (this.productInfo.type2) {
<div>${h.text('upc', autocomplete='off')}</div> this.productUnits = this.productInfo.units
<div id="product-info"> }
<p>please ENTER a scancode</p>
<div class="img-wrapper"><img /></div>
<div class="warning notfound">please confirm UPC and provide more details</div>
<div class="warning present">product already exists in batch, please confirm count</div>
<div class="warning force-unit">pack item scanned, but must count units instead</div>
</div>
</div>
</div>
<div class="product-fields" style="display: none;"> this.$nextTick(() => {
if (this.productInfo.type2) {
this.$refs.productUnits.focus()
} else {
% if allow_cases and prefer_cases:
if (this.productCases) {
this.$refs.productCases.focus()
} else if (this.productUnits) {
this.$refs.productUnits.focus()
} else {
this.$refs.productCases.focus()
}
% else:
this.$refs.productUnits.focus()
% endif
}
})
<div class="field-wrapper brand_name"> } else {
<label for="brand_name">Brand Name</label> ## this.productNotFound = true
<div class="field">${h.text('brand_name')}</div> alert("Product not found!")
</div> }
})
},
},
}
<div class="field-wrapper description"> let ${form.component_studly}Data = {
<label for="description">Description</label> submitting: false,
<div class="field">${h.text('description')}</div>
</div>
<div class="field-wrapper size"> productUPC: null,
<label for="size">Size</label> ## productNotFound: false,
<div class="field">${h.text('size')}</div> productInfo: {},
</div>
<div class="field-wrapper case_quantity">
<label for="case_quantity">Units in Case</label>
<div class="field">${h.text('case_quantity')}</div>
</div>
</div>
% if allow_cases: % if allow_cases:
<div class="field-wrapper cases"> productCases: null,
<label for="cases">Cases</label>
<div class="field">${h.text('cases', autocomplete='off')}</div>
</div>
% endif % endif
productUnits: null,
<div class="field-wrapper units"> alreadyPresentInBatch: false,
<label for="units">Units</label> forceUnitItem: false,
<div class="field">${h.text('units', autocomplete='off')}</div> }
</div>
<div class="buttons"> </script>
${h.submit('submit', "Submit")}
</div>
${h.end_form()}
</div>
% endif
</%def> </%def>

View file

@ -1,59 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/batch/create.mako" /> <%inherit file="/batch/create.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
var vendormap = {
% for i, parser in enumerate(parsers, 1):
'${parser.key}': ${parser.vendormap_value|n}${',' if i < len(parsers) else ''}
% endfor
};
$(function() {
if ($('select[name="parser_key"] option:first').is(':selected')) {
$('.vendor_uuid .autocomplete-container').hide();
} else {
$('.vendor_uuid input[name="vendor_uuid"]').val('');
$('.vendor_uuid .autocomplete-display').hide();
$('.vendor_uuid .autocomplete-display button').show();
$('.vendor_uuid .autocomplete-textbox').val('');
$('.vendor_uuid .autocomplete-textbox').show();
$('.vendor_uuid .autocomplete-container').show();
}
$('select[name="parser_key"]').on('selectmenuchange', function() {
if ($(this).find('option:first').is(':selected')) {
$('.vendor_uuid .autocomplete-container').hide();
} else {
var vendor = vendormap[$(this).val()];
if (vendor) {
$('.vendor_uuid input[name="vendor_uuid"]').val(vendor.uuid);
$('.vendor_uuid .autocomplete-textbox').hide();
$('.vendor_uuid .autocomplete-display span:first').text(vendor.name);
$('.vendor_uuid .autocomplete-display button').hide();
$('.vendor_uuid .autocomplete-display').show();
$('.vendor_uuid .autocomplete-container').show();
} else {
$('.vendor_uuid input[name="vendor_uuid"]').val('');
$('.vendor_uuid .autocomplete-display').hide();
$('.vendor_uuid .autocomplete-display button').show();
$('.vendor_uuid .autocomplete-textbox').val('');
$('.vendor_uuid .autocomplete-textbox').show();
$('.vendor_uuid .autocomplete-container').show();
$('.vendor_uuid .autocomplete-textbox').focus();
}
}
});
});
</script>
% endif
</%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()} ${parent.modify_this_page_vars()}
<script type="text/javascript"> <script type="text/javascript">

View file

@ -1,68 +1,8 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${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'};
$(function() {
% if master.has_worksheet and master.allow_worksheet(batch) and master.has_perm('worksheet'):
$('.load-worksheet').click(function() {
disable_button(this);
location.href = '${url('{}.worksheet'.format(route_prefix), uuid=batch.uuid)}';
});
% endif
% if master.batch_refreshable(batch) and master.has_perm('refresh'):
$('#refresh-data').click(function() {
$(this)
.button('option', 'disabled', true)
.button('option', 'label', "Working, please wait...");
location.href = '${url('{}.refresh'.format(route_prefix), uuid=batch.uuid)}';
});
% endif
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
$('.upload-worksheet').click(function() {
$('#upload-worksheet-dialog').dialog({
title: "Upload Worksheet",
width: 600,
modal: true,
buttons: [
{
text: "Upload & Update Batch",
click: function(event) {
var form = $('form[name="upload-worksheet"]');
var field = form.find('input[type="file"]').get(0);
if (!field.value) {
alert("Please choose a file to upload.");
return
}
disable_button(dialog_button(event));
form.submit();
}
},
{
text: "Cancel",
click: function() {
$(this).dialog('close');
}
}
]
});
});
% endif
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
% if use_buefy:
<style type="text/css"> <style type="text/css">
.modal-card-body label { .modal-card-body label {
@ -74,19 +14,6 @@
} }
</style> </style>
% else:
<style type="text/css">
.grid-wrapper {
margin-top: 10px;
}
.complete form {
display: inline;
}
</style>
% endif
</%def> </%def>
<%def name="buttons()"> <%def name="buttons()">
@ -99,52 +26,39 @@
<%def name="leading_buttons()"> <%def name="leading_buttons()">
% if master.has_worksheet and master.allow_worksheet(batch) and master.has_perm('worksheet'): % if master.has_worksheet and master.allow_worksheet(batch) and master.has_perm('worksheet'):
% if use_buefy: <once-button type="is-primary"
<once-button type="is-primary" tag="a" href="${url('{}.worksheet'.format(route_prefix), uuid=batch.uuid)}"
tag="a" href="${url('{}.worksheet'.format(route_prefix), uuid=batch.uuid)}" icon-left="edit"
icon-left="edit" text="Edit as Worksheet">
text="Edit as Worksheet"> </once-button>
</once-button>
% else:
<button type="button" class="load-worksheet">Edit as Worksheet</button>
% endif
% endif % endif
</%def> </%def>
<%def name="refresh_button()"> <%def name="refresh_button()">
% if master.batch_refreshable(batch) and master.has_perm('refresh'): % if master.batch_refreshable(batch) and master.has_perm('refresh'):
% if use_buefy: ## TODO: this should surely use a POST request?
## TODO: this should surely use a POST request? <once-button type="is-primary"
<once-button type="is-primary" tag="a" href="${url('{}.refresh'.format(route_prefix), uuid=batch.uuid)}"
tag="a" href="${url('{}.refresh'.format(route_prefix), uuid=batch.uuid)}" text="Refresh Data"
text="Refresh Data" icon-left="redo">
icon-left="redo"> </once-button>
</once-button>
% else:
<button type="button" class="button" id="refresh-data">Refresh Data</button>
% endif
% endif % endif
</%def> </%def>
<%def name="trailing_buttons()"> <%def name="trailing_buttons()">
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'): % if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
% if use_buefy: <b-button tag="a"
<b-button tag="a" href="${master.get_action_url('download_worksheet', batch)}"
href="${master.get_action_url('download_worksheet', batch)}" icon-pack="fas"
icon-pack="fas" icon-left="fas fa-download">
icon-left="fas fa-download"> Download Worksheet
Download Worksheet </b-button>
</b-button> <b-button type="is-primary"
<b-button type="is-primary" icon-pack="fas"
icon-pack="fas" icon-left="fas fa-upload"
icon-left="fas fa-upload" @click="$emit('show-upload')">
@click="$emit('show-upload')"> Upload Worksheet
Upload Worksheet </b-button>
</b-button>
% else:
${h.link_to("Download Worksheet", master.get_action_url('download_worksheet', batch), class_='button')}
<button type="button" class="upload-worksheet">Upload Worksheet</button>
% endif
% endif % endif
</%def> </%def>
@ -154,34 +68,12 @@
</%def> </%def>
<%def name="render_status_breakdown()"> <%def name="render_status_breakdown()">
% if use_buefy: <div class="object-helper">
<div class="object-helper"> <h3>Row Status Breakdown</h3>
<h3>Row Status Breakdown</h3> <div class="object-helper-content">
<div class="object-helper-content"> ${status_breakdown_grid}
${status_breakdown_grid} </div>
</div> </div>
</div>
% elif status_breakdown is not Undefined and status_breakdown is not None:
<div class="object-helper">
<h3>Row Status Breakdown</h3>
<div class="object-helper-content">
% if status_breakdown:
<div class="grid full">
<table>
% for i, (status, count) in enumerate(status_breakdown):
<tr class="${'even' if i % 2 == 0 else 'odd'}">
<td>${status}</td>
<td>${count}</td>
</tr>
% endfor
</table>
</div>
% else:
<p>Nothing to report yet.</p>
% endif
</div>
</div>
% endif
</%def> </%def>
<%def name="render_execute_helper()"> <%def name="render_execute_helper()">
@ -197,22 +89,21 @@
% elif master.handler.executable(batch): % elif master.handler.executable(batch):
% if master.has_perm('execute'): % if master.has_perm('execute'):
<p>Batch has not yet been executed.</p> <p>Batch has not yet been executed.</p>
% if use_buefy: <br />
<br /> <b-button type="is-primary"
<b-button type="is-primary" % if not execute_enabled:
% if not execute_enabled: disabled
disabled % if why_not_execute:
% if why_not_execute: title="${why_not_execute}"
title="${why_not_execute}" % endif
% endif % endif
% endif @click="showExecutionDialog = true"
@click="showExecutionDialog = true" icon-pack="fas"
icon-pack="fas" icon-left="arrow-circle-right">
icon-left="arrow-circle-right"> ${execute_title}
${execute_title} </b-button>
</b-button>
% if execute_enabled: % if execute_enabled:
<b-modal has-modal-card <b-modal has-modal-card
:active.sync="showExecutionDialog"> :active.sync="showExecutionDialog">
<div class="modal-card"> <div class="modal-card">
@ -245,22 +136,8 @@
</div> </div>
</b-modal> </b-modal>
% endif
% else:
## no buefy, do legacy thing
<button type="button"
% if not execute_enabled:
disabled="disabled"
% endif
% if why_not_execute:
title="${why_not_execute}"
% endif
class="button is-primary"
id="execute-batch">
${execute_title}
</button>
% endif % endif
% else: % else:
<p>TODO: batch *may* be executed, but not by *you*</p> <p>TODO: batch *may* be executed, but not by *you*</p>
% endif % endif
@ -281,71 +158,51 @@
${parent.render_this_page()} ${parent.render_this_page()}
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'): % if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
% if use_buefy: <b-modal has-modal-card
<b-modal has-modal-card :active.sync="showUploadDialog">
:active.sync="showUploadDialog"> <div class="modal-card">
<div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
<p class="modal-card-title">Upload Worksheet</p> <p class="modal-card-title">Upload Worksheet</p>
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
<p>
This will <span class="has-text-weight-bold">update</span>
the batch data with the worksheet file you provide.&nbsp;
Please be certain to use the right one!
</p>
<br />
<${upload_worksheet_form.component} ref="uploadForm">
</${upload_worksheet_form.component}>
</section>
<footer class="modal-card-foot">
<b-button @click="showUploadDialog = false">
Cancel
</b-button>
<b-button type="is-primary"
@click="submitUpload()"
icon-pack="fas"
icon-left="fas fa-upload"
:disabled="uploadButtonDisabled">
{{ uploadButtonText }}
</b-button>
</footer>
</div>
</b-modal>
% else:
<div id="upload-worksheet-dialog" style="display: none;">
<p> <p>
This will <strong>update</strong> the batch data with the worksheet This will <span class="has-text-weight-bold">update</span>
file you provide.&nbsp; Please be certain to use the right one! the batch data with the worksheet file you provide.&nbsp;
Please be certain to use the right one!
</p> </p>
${upload_worksheet_form.render_deform(buttons=False, form_kwargs={'name': 'upload-worksheet'})|n} <br />
</div> <${upload_worksheet_form.component} ref="uploadForm">
% endif </${upload_worksheet_form.component}>
% endif </section>
% if not use_buefy: <footer class="modal-card-foot">
% if master.handler.executable(batch) and master.has_perm('execute'): <b-button @click="showUploadDialog = false">
<div id="execution-options-dialog" style="display: none;"> Cancel
${execute_form.render_deform(form_kwargs={'name': 'batch-execution'}, buttons=False)|n} </b-button>
</div> <b-button type="is-primary"
% endif @click="submitUpload()"
icon-pack="fas"
icon-left="fas fa-upload"
:disabled="uploadButtonDisabled">
{{ uploadButtonText }}
</b-button>
</footer>
</div>
</b-modal>
% endif % endif
</%def> </%def>
<%def name="render_this_page_template()"> <%def name="render_this_page_template()">
${parent.render_this_page_template()} ${parent.render_this_page_template()}
% if use_buefy: % if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'): ${upload_worksheet_form.render_deform(buttons=False, form_kwargs={'ref': 'actualUploadForm'})|n}
${upload_worksheet_form.render_deform(buttons=False, form_kwargs={'ref': 'actualUploadForm'})|n} % endif
% endif % if master.handler.executable(batch) and master.has_perm('execute'):
% if master.handler.executable(batch) and master.has_perm('execute'): ${execute_form.render_deform(form_kwargs={'ref': 'actualExecuteForm'}, buttons=False)|n}
${execute_form.render_deform(form_kwargs={'ref': 'actualExecuteForm'}, buttons=False)|n}
% endif
% endif % endif
</%def> </%def>
@ -358,7 +215,7 @@
<%def name="render_row_grid_tools()"> <%def name="render_row_grid_tools()">
${parent.render_row_grid_tools()} ${parent.render_row_grid_tools()}
% if use_buefy and master.rows_bulk_deletable and not batch.executed and master.has_perm('delete_rows'): % if master.rows_bulk_deletable and not batch.executed and master.has_perm('delete_rows'):
<b-button type="is-danger" <b-button type="is-danger"
@click="deleteResultsInit()" @click="deleteResultsInit()"
:disabled="!total" :disabled="!total"

View file

@ -1,26 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/page.mako" /> <%inherit file="/page.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('.worksheet .current-entry input').focus(function(event) {
$(this).parents('tr:first').addClass('active');
});
$('.worksheet .current-entry input').blur(function(event) {
$(this).parents('tr:first').removeClass('active');
});
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
<style type="text/css"> <style type="text/css">

View file

@ -4,22 +4,16 @@
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
% if use_buefy: <style type="text/css">
<style type="text/css"> .this-page-content {
.this-page-content { flex-grow: 1;
flex-grow: 1; }
} </style>
</style>
% endif
</%def> </%def>
<%def name="page_content()"> <%def name="page_content()">
<br /> <br />
% if use_buefy: <customer-order-creator></customer-order-creator>
<customer-order-creator></customer-order-creator>
% else:
<p>Sorry, but this page is not supported by your current theme configuration.</p>
% endif
</%def> </%def>
<%def name="order_form_buttons()"> <%def name="order_form_buttons()">

View file

@ -12,38 +12,22 @@
${parent.grid_tools()} ${parent.grid_tools()}
% if request.has_perm('datasync.restart'): % if request.has_perm('datasync.restart'):
% if use_buefy:
${h.form(url('datasync.restart'), name='restart-datasync', class_='control', **{'@submit': 'submitRestartDatasyncForm'})} ${h.form(url('datasync.restart'), name='restart-datasync', class_='control', **{'@submit': 'submitRestartDatasyncForm'})}
% else:
${h.form(url('datasync.restart'), name='restart-datasync', class_='autodisable')}
% endif
${h.csrf_token(request)} ${h.csrf_token(request)}
% if use_buefy:
<b-button native-type="submit" <b-button native-type="submit"
:disabled="restartDatasyncFormSubmitting"> :disabled="restartDatasyncFormSubmitting">
{{ restartDatasyncFormButtonText }} {{ restartDatasyncFormButtonText }}
</b-button> </b-button>
% else:
${h.submit('submit', "Restart DataSync", data_working_label="Restarting DataSync", class_='button')}
% endif
${h.end_form()} ${h.end_form()}
% endif % endif
% if allow_filemon_restart and request.has_perm('filemon.restart'): % if allow_filemon_restart and request.has_perm('filemon.restart'):
% if use_buefy:
${h.form(url('filemon.restart'), name='restart-filemon', class_='control', **{'@submit': 'submitRestartFilemonForm'})} ${h.form(url('filemon.restart'), name='restart-filemon', class_='control', **{'@submit': 'submitRestartFilemonForm'})}
% else:
${h.form(url('filemon.restart'), name='restart-filemon', class_='autodisable')}
% endif
${h.csrf_token(request)} ${h.csrf_token(request)}
% if use_buefy:
<b-button native-type="submit" <b-button native-type="submit"
:disabled="restartFilemonFormSubmitting"> :disabled="restartFilemonFormSubmitting">
{{ restartFilemonFormButtonText }} {{ restartFilemonFormButtonText }}
</b-button> </b-button>
% else:
${h.submit('submit', "Restart FileMon", data_working_label="Restarting FileMon", class_='button')}
% endif
${h.end_form()} ${h.end_form()}
% endif % endif

View file

@ -3,109 +3,10 @@
oid oid|field.oid; oid oid|field.oid;
field_display field_display; field_display field_display;
style style|field.widget.style; style style|field.widget.style;
url url|field.widget.service_url; url url|field.widget.service_url;"
use_buefy use_buefy|0;"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" <div tal:define="vmodel vmodel|'field_model_' + name;"
id="${oid}-container"
class="autocomplete-container">
<input type="hidden"
name="${name}"
id="${oid}"
value="${cstruct}" />
<input type="text"
name="${oid}-textbox"
id="${oid}-textbox"
value="${field_display}"
class="autocomplete-textbox"
style="display: none;" />
<div id="${oid}-display"
class="autocomplete-display"
style="display: none;">
<span>${field_display or ''}</span>
<button type="button" id="${oid}-change" class="autocomplete-change">Change</button>
</div>
<script type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-textbox').autocomplete(${options});
$('#' + oid + '-textbox').on('autocompleteselect', function (event, ui) {
$('#' + oid).val(ui.item.value);
$('#' + oid + '-display span:first').text(ui.item.label);
$('#' + oid + '-textbox').hide();
$('#' + oid + '-display').show();
$('#' + oid + '-textbox').trigger('autocompletevalueselected',
[ui.item.value, ui.item.label]);
return false;
});
$('#' + oid + '-change').click(function() {
$('#' + oid).val('');
$('#' + oid + '-display').hide();
with ($('#' + oid + '-textbox')) {
val('');
show();
focus();
}
$('#' + oid + '-textbox').trigger('autocompletevaluecleared');
});
}
);
</script>
<script tal:condition="cleared_callback" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-textbox').on('autocompletevaluecleared', function() {
${cleared_callback}();
});
}
);
</script>
<script tal:condition="selected_callback" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-textbox').on('autocompletevalueselected', function(event, uuid, label) {
${selected_callback}(uuid, label);
});
}
);
</script>
<script tal:condition="cstruct" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-display').show();
}
);
</script>
<script tal:condition="not cstruct" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-textbox').show();
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag=""> tal:omit-tag="">
<tailbone-autocomplete name="${name}" <tailbone-autocomplete name="${name}"
ref="${ref}" ref="${ref}"

View file

@ -2,38 +2,11 @@
<div tal:define="oid oid|field.oid; <div tal:define="oid oid|field.oid;
name name|field.name; name name|field.name;
css_class css_class|field.widget.css_class; css_class css_class|field.widget.css_class;
style style|field.widget.style; style style|field.widget.style;"
use_buefy use_buefy|0;"
i18n:domain="deform" i18n:domain="deform"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:define="vmodel vmodel|'field_model_' + name;"
${field.start_mapping()}
<div>
<input type="text" name="cases" value="${cases}"
tal:attributes="style style;
class string: form-control ${css_class or ''};
cases_attributes|field.widget.cases_attributes|{};"
placeholder="cases"
autocomplete="off"
id="${oid}-cases"/>
Cases
</div>
<div>
<input type="text" name="units" value="${units}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
units_attributes|field.widget.units_attributes|{};"
placeholder="units"
autocomplete="off"
id="${oid}-units"/>
Units
</div>
${field.end_mapping()}
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag=""> tal:omit-tag="">
${field.start_mapping()} ${field.start_mapping()}

View file

@ -2,21 +2,10 @@
true_val true_val|field.widget.true_val; true_val true_val|field.widget.true_val;
css_class css_class|field.widget.css_class; css_class css_class|field.widget.css_class;
style style|field.widget.style; style style|field.widget.style;
oid oid|field.oid; oid oid|field.oid;"
use_buefy use_buefy|0;"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" class="checkbox"> <div tal:define="vmodel vmodel|'field_model_' + name;">
<input type="checkbox"
name="${name}" value="${true_val}"
id="${oid}"
tal:attributes="checked cstruct == true_val;
class css_class;
style style;" />
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;">
<b-checkbox name="${name}" <b-checkbox name="${name}"
v-model="${vmodel}" v-model="${vmodel}"
native-value="${true_val}"> native-value="${true_val}">

View file

@ -2,37 +2,9 @@
tal:define="oid oid|field.oid; tal:define="oid oid|field.oid;
name name|field.name; name name|field.name;
css_class css_class|field.widget.css_class; css_class css_class|field.widget.css_class;
style style|field.widget.style; style style|field.widget.style;">
use_buefy use_buefy|0;">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div>
${field.start_mapping()}
<div>
<input type="password"
name="${name}"
value="${field.widget.redisplay and cstruct or ''}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"
i18n:attributes="placeholder"
placeholder="Password"/>
</div>
<div>
<input type="password"
name="${name}-confirm"
value="${field.widget.redisplay and confirm or ''}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
confirm_attributes|field.widget.confirm_attributes|{};"
id="${oid}-confirm"
i18n:attributes="placeholder"
placeholder="Confirm Password"/>
</div>
${field.end_mapping()}
</div>
<div tal:condition="use_buefy">
${field.start_mapping()} ${field.start_mapping()}
<b-input type="password" <b-input type="password"
name="${name}" name="${name}"

View file

@ -3,40 +3,10 @@
oid oid|field.oid; oid oid|field.oid;
field_name field_name|field.name; field_name field_name|field.name;
style style|field.widget.style; style style|field.widget.style;
type_name type_name|field.widget.type_name; type_name type_name|field.widget.type_name;"
use_buefy use_buefy|0;"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()}
<input type="${type_name}"
name="date"
value="${cstruct}"
tal:attributes="class string: ${css_class or ''} form-control;
style style"
id="${oid}"/>
${field.end_mapping()}
<script type="text/javascript">
deform.addCallback(
'${oid}',
function deform_cb(oid) {
$('#' + oid).datepicker(${options_json});
}
);
</script>
<script tal:condition="selected_callback" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid).datepicker('option', 'onSelect', ${selected_callback});
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()} ${field.start_mapping()}
<tailbone-datepicker name="date" <tailbone-datepicker name="date"
id="${oid}" id="${oid}"

View file

@ -2,29 +2,9 @@
<tal:block tal:define="oid oid|field.oid; <tal:block tal:define="oid oid|field.oid;
css_class css_class|field.widget.css_class; css_class css_class|field.widget.css_class;
style style|field.widget.style; style style|field.widget.style;
field_name field_name|field.name; field_name field_name|field.name;">
use_buefy use_buefy|0;">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()}
<input type="file" name="upload" id="${oid}"
tal:attributes="style style;
accept accept|field.widget.accept;
data-filename cstruct.get('filename');
attributes|field.widget.attributes|{};"/>
<input tal:define="uid cstruct.get('uid')"
tal:condition="uid"
type="hidden" name="uid" value="${uid}"/>
${field.end_mapping()}
<script type="text/javascript">
deform.addCallback('${oid}', function (oid) {
$('#' + oid).upload();
});
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()} ${field.start_mapping()}
<b-field class="file"> <b-field class="file">
<b-upload name="upload" <b-upload name="upload"

View file

@ -3,21 +3,9 @@
oid oid|field.oid; oid oid|field.oid;
mask mask|field.widget.mask; mask mask|field.widget.mask;
mask_placeholder mask_placeholder|field.widget.mask_placeholder; mask_placeholder mask_placeholder|field.widget.mask_placeholder;
style style|field.widget.style; style style|field.widget.style;"
use_buefy use_buefy|0;"
tal:omit-tag=""> tal:omit-tag="">
<div tal:define="vmodel vmodel|'field_model_' + name;"
<input tal:condition="not use_buefy"
type="password"
name="${name}"
value="${field.widget.redisplay and cstruct or ''}"
tal:attributes="style style;
class string: form-control ${css_class or ''};
attributes|field.widget.attributes|{};"
id="${oid}" />
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag=""> tal:omit-tag="">
<b-input name="${name}" <b-input name="${name}"
v-model="${vmodel}" v-model="${vmodel}"

View file

@ -8,26 +8,7 @@
autocomplete autocomplete|field.widget.autocomplete|'off';" autocomplete autocomplete|field.widget.autocomplete|'off';"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:define="vmodel vmodel|'field_model_' + field_name;">
<input type="text" name="${name}" value="${cstruct}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
autocomplete autocomplete;
"
id="${oid}"/>
%
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{placeholder:"${mask_placeholder}"});
});
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
<!-- TODO: need to handle mask somehow? --> <!-- TODO: need to handle mask somehow? -->
<b-input name="${field_name}" <b-input name="${field_name}"
id="${oid}" id="${oid}"

View file

@ -1,41 +1,8 @@
<div tal:define="oid oid|field.oid; <div tal:define="oid oid|field.oid;
true_val true_val|field.widget.true_val; true_val true_val|field.widget.true_val;"
use_buefy use_buefy|0;"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" <div>
tal:omit-tag="">
${field.start_mapping()}
<div class="permissions-outer">
<tal:loop tal:repeat="groupkey sorted(permissions, key=lambda k: permissions[k]['label'].lower())">
<div tal:define="perms permissions[groupkey]['perms'];"
class="permissions-group">
<p class="group-label">${permissions[groupkey]['label']}</p>
<tal:loop tal:repeat="key sorted(perms, key=lambda p: perms[p]['label'].lower())">
<div class="perm">
<label>
<input type="checkbox"
name="${key}"
id="${oid}-${key}"
value="${true_val}"
tal:attributes="checked python:field.widget.get_checked_value(cstruct, key);" />
${perms[key]['label']}
</label>
</div>
</tal:loop>
</div>
</tal:loop>
</div>
${field.end_mapping()}
</div>
<div tal:condition="use_buefy">
${field.start_mapping()} ${field.start_mapping()}
<div class="level"> <div class="level">

View file

@ -7,58 +7,10 @@
unicode unicode|str; unicode unicode|str;
optgroup_class optgroup_class|field.widget.optgroup_class; optgroup_class optgroup_class|field.widget.optgroup_class;
multiple multiple|field.widget.multiple; multiple multiple|field.widget.multiple;
use_buefy use_buefy|0;
input_handler input_handler|'';" input_handler input_handler|'';"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:define="vmodel vmodel|'field_model_' + name;">
<input type="hidden" name="__start__" value="${name}:sequence"
tal:condition="multiple" />
<div class="select">
<select tal:attributes="
name name;
id oid;
class string: form-control ${css_class or ''};
multiple multiple;
size size;
style style;">
<tal:loop tal:repeat="item values">
<optgroup tal:condition="isinstance(item, optgroup_class)"
tal:attributes="label item.label">
<option tal:repeat="(value, description) item.options"
tal:attributes="
selected python:field.widget.get_select_value(cstruct, value);
class css_class;
label field.widget.long_label_generator and description;
value value"
tal:content="field.widget.long_label_generator and field.widget.long_label_generator(item.label, description) or description"/>
</optgroup>
<option tal:condition="not isinstance(item, optgroup_class)"
tal:attributes="
selected python:field.widget.get_select_value(cstruct, item[0]);
class css_class;
value item[0]">${item[1]}</option>
</tal:loop>
</select>
</div>
<input type="hidden" name="__end__" value="${name}:sequence"
tal:condition="multiple" />
<script tal:condition="not multiple" type="text/javascript">
deform.addCallback(
'${oid}',
function(oid) {
$('#' + oid).selectmenu();
$('#' + oid).on('selectmenuopen', function(event, ui) {
show_all_options($(this));
});
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
>
<input type="hidden" name="__start__" value="${name}:sequence" <input type="hidden" name="__start__" value="${name}:sequence"
tal:condition="multiple" /> tal:condition="multiple" />
<b-select tal:attributes="name name; <b-select tal:attributes="name name;

View file

@ -3,22 +3,10 @@
css_class css_class|field.widget.css_class; css_class css_class|field.widget.css_class;
oid oid|field.oid; oid oid|field.oid;
name name|field.name; name name|field.name;
style style|field.widget.style; style style|field.widget.style;"
use_buefy use_buefy|0;"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:define="vmodel vmodel|'field_model_' + name;">
<textarea tal:attributes="rows rows;
cols cols;
class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"
name="${name}">${cstruct}</textarea>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;">
<b-input type="textarea" <b-input type="textarea"
name="${name}" name="${name}"
v-model="${vmodel}"> v-model="${vmodel}">

View file

@ -4,29 +4,10 @@
mask mask|field.widget.mask; mask mask|field.widget.mask;
mask_placeholder mask_placeholder|field.widget.mask_placeholder; mask_placeholder mask_placeholder|field.widget.mask_placeholder;
style style|field.widget.style; style style|field.widget.style;
use_buefy use_buefy|0;
placeholder placeholder|getattr(field.widget, 'placeholder', ''); placeholder placeholder|getattr(field.widget, 'placeholder', '');
autocomplete autocomplete|getattr(field.widget, 'autocomplete', 'on');" autocomplete autocomplete|getattr(field.widget, 'autocomplete', 'on');"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:define="vmodel vmodel|'field_model_' + name;"
<input type="text" name="${name}" value="${cstruct}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
autocomplete="${autocomplete}"
id="${oid}"/>
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{placeholder:"${mask_placeholder}"});
});
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag=""> tal:omit-tag="">
<b-input tal:attributes="name name; <b-input tal:attributes="name name;
v-model vmodel; v-model vmodel;

View file

@ -4,32 +4,10 @@
oid oid|field.oid; oid oid|field.oid;
style style|field.widget.style|None; style style|field.widget.style|None;
type_name type_name|field.widget.type_name; type_name type_name|field.widget.type_name;
field_name field_name|field.name; field_name field_name|field.name;"
use_buefy use_buefy|0;"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()}
<input type="${type_name}"
name="time"
value="${cstruct}"
tal:attributes="size size;
class string: ${css_class or ''} form-control;
style style"
id="${oid}"/>
${field.end_mapping()}
<script type="text/javascript">
deform.addCallback(
'${oid}',
function(oid) {
$('#' + oid).timepicker(${options_json});
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()} ${field.start_mapping()}
<tailbone-timepicker name="time" <tailbone-timepicker name="time"
id="${oid}" id="${oid}"

View file

@ -1,20 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%def name="page_content()">
${parent.page_content()}
% if not use_buefy:
<h2>Employees</h2>
% if employees:
<p>The following employees are assigned to this department:</p>
${employees.render_grid()|n}
% else:
<p>No employees are assigned to this department.</p>
% endif
% endif
</%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()} ${parent.modify_this_page_vars()}
<script type="text/javascript"> <script type="text/javascript">

View file

@ -3,36 +3,8 @@
## TODO: this page still uses jQuery but should use Vue.js ## TODO: this page still uses jQuery but should use Vue.js
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
function autosize_message(scrolldown) {
var msg = $('#message');
var height = $(window).height() - msg.offset().top - 50;
msg.height(height);
if (scrolldown) {
msg.animate({scrollTop: msg.get(0).scrollHeight - height}, 250);
}
}
$(function () {
autosize_message(true);
$('#message').focus();
});
$(window).resize(function() {
autosize_message(false);
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
% if use_buefy:
<style type="text/css"> <style type="text/css">
.email-message-body { .email-message-body {
border: 1px solid #000000; border: 1px solid #000000;
@ -40,81 +12,48 @@
height: 500px; height: 500px;
} }
</style> </style>
% else:
<style type="text/css">
#message {
border: 1px solid #000000;
height: 400px;
overflow: auto;
padding: 4px;
}
</style>
% endif
</%def> </%def>
<%def name="object_helpers()"> <%def name="object_helpers()">
${parent.object_helpers()} ${parent.object_helpers()}
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Processing</p>
<p class="panel-heading">Processing</p> <div class="panel-block">
<div class="panel-block"> <div class="display: flex; flex-align: column;">
<div class="display: flex; flex-align: column;"> % if bounce.processed:
% if bounce.processed: <p class="block">
<p class="block"> This bounce was processed
This bounce was processed ${h.pretty_datetime(request.rattail_config, bounce.processed)}
${h.pretty_datetime(request.rattail_config, bounce.processed)} by ${bounce.processed_by}
by ${bounce.processed_by} </p>
</p> % if master.has_perm('unprocess'):
% if master.has_perm('unprocess'): <once-button type="is-warning"
<once-button type="is-warning" tag="a" href="${url('emailbounces.unprocess', uuid=bounce.uuid)}"
tag="a" href="${url('emailbounces.unprocess', uuid=bounce.uuid)}" text="Mark this bounce as UN-processed">
text="Mark this bounce as UN-processed"> </once-button>
</once-button>
% endif
% else:
<p class="block">
This bounce has NOT yet been processed.
</p>
% if master.has_perm('process'):
<once-button type="is-primary"
tag="a" href="${url('emailbounces.process', uuid=bounce.uuid)}"
text="Mark this bounce as Processed">
</once-button>
% endif
% endif % endif
</div> % else:
</div> <p class="block">
</nav> This bounce has NOT yet been processed.
% endif </p>
</%def> % if master.has_perm('process'):
<once-button type="is-primary"
<%def name="context_menu_items()"> tag="a" href="${url('emailbounces.process', uuid=bounce.uuid)}"
${parent.context_menu_items()} text="Mark this bounce as Processed">
% if not use_buefy: </once-button>
% if not bounce.processed and request.has_perm('emailbounces.process'): % endif
<li>${h.link_to("Mark this Email Bounce as Processed", url('emailbounces.process', uuid=bounce.uuid))}</li> % endif
% elif bounce.processed and request.has_perm('emailbounces.unprocess'): </div>
<li>${h.link_to("Mark this Email Bounce as UN-processed", url('emailbounces.unprocess', uuid=bounce.uuid))}</li> </div>
% endif </nav>
% endif
</%def>
<%def name="page_content()">
${parent.page_content()}
% if not use_buefy:
<pre id="message">
${message}
</pre>
% endif
</%def> </%def>
<%def name="render_this_page()"> <%def name="render_this_page()">
${parent.render_this_page()} ${parent.render_this_page()}
% if use_buefy: <pre class="email-message-body">
<pre class="email-message-body"> ${message}
${message} </pre>
</pre>
% endif
</%def> </%def>
${parent.body()} ${parent.body()}

View file

@ -22,12 +22,8 @@
<%def name="page_content()"> <%def name="page_content()">
<div class="form-wrapper"> <div class="form-wrapper">
% if use_buefy: <br />
<br /> ${self.render_buefy_form()}
${self.render_buefy_form()}
% else:
${self.render_form()}
% endif
</div> </div>
</%def> </%def>

View file

@ -1,8 +1,2 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
% if form.use_buefy: ${form.render_deform(buttons=buttons)|n}
${form.render_deform(buttons=buttons)|n}
% else:
<div class="form">
${form.render_deform(buttons=buttons)|n}
</div>
% endif

View file

@ -4,36 +4,27 @@
<%def name="title()">Login</%def> <%def name="title()">Login</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
${h.javascript_link(request.static_url('tailbone:static/js/login.js'))}
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
% if use_buefy: <style type="text/css">
<style type="text/css"> .logo img {
.logo img { display: block;
display: block; margin: 3rem auto;
margin: 3rem auto; max-height: 350px;
max-height: 350px; max-width: 800px;
max-width: 800px; }
}
/* must force a particular label with, in order to make sure */ /* must force a particular label with, in order to make sure */
/* the username and password inputs are the same size */ /* the username and password inputs are the same size */
.field.is-horizontal .field-label .label { .field.is-horizontal .field-label .label {
text-align: left; text-align: left;
width: 6rem; width: 6rem;
} }
.buttons { .buttons {
justify-content: right; justify-content: right;
} }
</style> </style>
% else:
${h.stylesheet_link(request.static_url('tailbone:static/css/login.css'))}
% endif
</%def> </%def>
<%def name="logo()"> <%def name="logo()">
@ -55,21 +46,15 @@
${self.logo()} ${self.logo()}
</div> </div>
% if use_buefy: <div class="columns is-centered">
<div class="column is-narrow">
<div class="columns is-centered"> <div class="card">
<div class="column is-narrow"> <div class="card-content">
<div class="card"> <tailbone-form></tailbone-form>
<div class="card-content">
<tailbone-form></tailbone-form>
</div>
</div>
</div> </div>
</div> </div>
</div>
% else: </div>
${self.login_form()}
% endif
</%def> </%def>

View file

@ -5,49 +5,31 @@
<%def name="render_buefy_form()"> <%def name="render_buefy_form()">
<br /> <br />
% if use_buefy: <b-notification :closable="false">
<b-notification :closable="false"> You are about to clone the following ${model_title} as a new record:
You are about to clone the following ${model_title} as a new record: </b-notification>
</b-notification>
% else:
<p>You are about to clone the following ${model_title} as a new record:</p>
% endif
${parent.render_buefy_form()} ${parent.render_buefy_form()}
</%def> </%def>
<%def name="render_form_buttons()"> <%def name="render_form_buttons()">
<br /> <br />
% if use_buefy: <b-notification :closable="false">
<b-notification :closable="false"> Are you sure about this?
Are you sure about this? </b-notification>
</b-notification>
% else:
<p>Are you sure about this?</p>
% endif
<br /> <br />
% if use_buefy:
${h.form(request.current_route_url(), **{'@submit': 'submitForm'})} ${h.form(request.current_route_url(), **{'@submit': 'submitForm'})}
% else:
${h.form(request.current_route_url(), class_='autodisable')}
% endif
${h.csrf_token(request)} ${h.csrf_token(request)}
${h.hidden('clone', value='clone')} ${h.hidden('clone', value='clone')}
<div class="buttons"> <div class="buttons">
% if use_buefy: <once-button tag="a" href="${form.cancel_url}"
<once-button tag="a" href="${form.cancel_url}" text="Whoops, nevermind...">
text="Whoops, nevermind..."> </once-button>
</once-button> <b-button type="is-primary"
<b-button type="is-primary" native-type="submit"
native-type="submit" :disabled="formSubmitting">
:disabled="formSubmitting"> {{ submitButtonText }}
{{ submitButtonText }} </b-button>
</b-button>
% else:
${h.link_to("Whoops, nevermind...", form.cancel_url, class_='button autodisable')}
${h.submit('submit', "Yes, please clone away")}
% endif
</div> </div>
${h.end_form()} ${h.end_form()}
</%def> </%def>

View file

@ -3,66 +3,32 @@
<%def name="title()">Delete ${model_title}: ${instance_title}</%def> <%def name="title()">Delete ${model_title}: ${instance_title}</%def>
<%def name="context_menu_items()">
% if not use_buefy and master.viewable and master.has_perm('view'):
<li>${h.link_to("View this {}".format(model_title), action_url('view', instance))}</li>
% endif
% if not use_buefy and master.editable and master.has_perm('edit'):
<li>${h.link_to("Edit this {}".format(model_title), action_url('edit', instance))}</li>
% endif
% if not use_buefy and master.creatable and master.show_create_link and master.has_perm('create'):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
% else:
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif
% endif
</%def>
<%def name="render_buefy_form()"> <%def name="render_buefy_form()">
<br /> <br />
% if use_buefy: <b-notification type="is-danger" :closable="false">
<b-notification type="is-danger" :closable="false"> You are about to delete the following ${model_title} and all associated data:
You are about to delete the following ${model_title} and all associated data: </b-notification>
</b-notification>
% else:
<p>You are about to delete the following ${model_title} and all associated data:</p>
% endif
${parent.render_buefy_form()} ${parent.render_buefy_form()}
</%def> </%def>
<%def name="render_form_buttons()"> <%def name="render_form_buttons()">
<br /> <br />
% if use_buefy: <b-notification type="is-danger" :closable="false">
<b-notification type="is-danger" :closable="false"> Are you sure about this?
Are you sure about this? </b-notification>
</b-notification>
% else:
<p>Are you sure about this?</p>
% endif
<br /> <br />
% if use_buefy:
${h.form(request.current_route_url(), **{'@submit': 'submitForm'})} ${h.form(request.current_route_url(), **{'@submit': 'submitForm'})}
% else:
${h.form(request.current_route_url(), class_='autodisable')}
% endif
${h.csrf_token(request)} ${h.csrf_token(request)}
<div class="buttons"> <div class="buttons">
% if use_buefy: <once-button tag="a" href="${form.cancel_url}"
<once-button tag="a" href="${form.cancel_url}" text="Whoops, nevermind...">
text="Whoops, nevermind..."> </once-button>
</once-button> <b-button type="is-primary is-danger"
<b-button type="is-primary is-danger" native-type="submit"
native-type="submit" :disabled="formSubmitting">
:disabled="formSubmitting"> {{ formButtonText }}
{{ formButtonText }} </b-button>
</b-button>
% else:
<a class="button" href="${form.cancel_url}">Whoops, nevermind...</a>
${h.submit('submit', "Yes, please DELETE this data forever!", class_='button is-primary')}
% endif
</div> </div>
${h.end_form()} ${h.end_form()}
</%def> </%def>

View file

@ -3,38 +3,5 @@
<%def name="title()">Edit: ${instance_title}</%def> <%def name="title()">Edit: ${instance_title}</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('form').submit(function() {
var submit = $(this).find('input[type="submit"]');
if (submit.length) {
submit.button('disable').button('option', 'label', "Saving, please wait...");
}
});
});
</script>
% endif
</%def>
<%def name="context_menu_items()">
% if not use_buefy and master.viewable and master.has_perm('view'):
<li>${h.link_to("View this {}".format(model_title), action_url('view', instance))}</li>
% endif
${self.context_menu_item_delete()}
% if not use_buefy and master.creatable and master.show_create_link and master.has_perm('create'):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
% else:
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif
% endif
</%def>
${parent.body()} ${parent.body()}

View file

@ -1,31 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/form.mako" /> <%inherit file="/form.mako" />
<%def name="context_menu_item_delete()">
% if not use_buefy and master.deletable and instance_deletable and master.has_perm('delete'):
% if master.delete_confirm == 'simple':
<li>
## note, the `ref` here is for buefy only
${h.form(action_url('delete', instance), ref='deleteObjectForm')}
${h.csrf_token(request)}
<a href="${action_url('delete', instance)}"
% if use_buefy:
@click.prevent="deleteObject"
% else:
class="delete-instance"
% endif
>
Delete this ${model_title}
</a>
${h.end_form()}
</li>
% else:
## assuming here that: delete_confirm == 'full'
<li>${h.link_to("Delete this {}".format(model_title), action_url('delete', instance))}</li>
% endif
% endif
</%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()} ${parent.modify_this_page_vars()}
% if master.deletable and instance_deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple': % if master.deletable and instance_deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':

View file

@ -12,142 +12,6 @@
<%def name="content_title()"></%def> <%def name="content_title()"></%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
% if download_results_rows_path:
function downloadResultsRowsRedirect() {
location.href = '${url('{}.download_results_rows'.format(route_prefix))}?filename=${h.os.path.basename(download_results_rows_path)}';
}
// we give this 1 second before attempting the redirect; so this
// way the page should fully render before redirecting
window.setTimeout(downloadResultsRowsRedirect, 1000);
% endif
$('.grid-wrapper').gridwrapper();
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
$('.grid-wrapper').on('click', '.grid .actions a.delete', function() {
if (confirm("Are you sure you wish to delete this ${model_title}?")) {
var link = $(this).get(0);
var form = $('#delete-object-form').get(0);
form.action = link.href;
form.submit();
}
return false;
});
% endif
% if master.mergeable and master.has_perm('merge'):
$('form[name="merge-things"] button').button('option', 'disabled', $('.grid').gridcore('count_selected') != 2);
$('.grid-wrapper').on('gridchecked', '.grid', function(event, count) {
$('form[name="merge-things"] button').button('option', 'disabled', count != 2);
});
$('form[name="merge-things"]').submit(function() {
var uuids = $('.grid').gridcore('selected_uuids');
if (uuids.length != 2) {
return false;
}
$(this).find('[name="uuids"]').val(uuids.toString());
$(this).find('button')
.button('option', 'label', "Preparing to Merge...")
.button('disable');
});
% endif
% if master.has_rows and master.results_rows_downloadable:
$('#download-row-results-button').click(function() {
if (confirm("This will generate an Excel file which contains "
+ "not the results themselves, but the *rows* for "
+ "each.\n\nAre you sure you want this?")) {
disable_button(this);
var form = $(this).parents('form');
form.submit();
}
});
% endif
% if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
$('form[name="bulk-delete"] button').click(function() {
var count = $('.grid-wrapper').gridwrapper('results_count', true);
if (count === null) {
alert("There don't seem to be any results to delete!");
return;
}
if (! confirm("You are about to delete " + count + " ${model_title_plural}.\n\nAre you sure?")) {
return
}
$(this).button('disable').button('option', 'label', "Deleting Results...");
$('form[name="bulk-delete"]').submit();
});
% 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');
var uuids = $('.grid').gridcore('selected_uuids');
if (! uuids.length) {
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?")) {
return false;
}
form.find('[name="uuids"]').val(uuids.toString());
disable_button(this);
form.submit();
});
% endif
});
</script>
% endif
</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
% if master.results_downloadable_csv and request.has_perm('{}.results_csv'.format(permission_prefix)): % if master.results_downloadable_csv and request.has_perm('{}.results_csv'.format(permission_prefix)):
<li>${h.link_to("Download results as CSV", url('{}.results_csv'.format(route_prefix)))}</li> <li>${h.link_to("Download results as CSV", url('{}.results_csv'.format(route_prefix)))}</li>
@ -155,13 +19,6 @@
% if master.results_downloadable_xlsx and request.has_perm('{}.results_xlsx'.format(permission_prefix)): % if master.results_downloadable_xlsx and request.has_perm('{}.results_xlsx'.format(permission_prefix)):
<li>${h.link_to("Download results as XLSX", url('{}.results_xlsx'.format(route_prefix)))}</li> <li>${h.link_to("Download results as XLSX", url('{}.results_xlsx'.format(route_prefix)))}</li>
% endif % endif
% if not use_buefy and master.creatable and master.show_create_link and master.has_perm('create'):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
% else:
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif
% endif
% if master.has_input_file_templates and master.has_perm('create'): % if master.has_input_file_templates and master.has_perm('create'):
% for template in six.itervalues(input_file_templates): % for template in six.itervalues(input_file_templates):
<li>${h.link_to("Download {} Template".format(template['label']), template['effective_url'])}</li> <li>${h.link_to("Download {} Template".format(template['label']), template['effective_url'])}</li>
@ -173,284 +30,233 @@
## download search results ## download search results
% if master.results_downloadable and master.has_perm('download_results'): % if master.results_downloadable and master.has_perm('download_results'):
% if use_buefy: <b-button type="is-primary"
<b-button type="is-primary" icon-pack="fas"
icon-pack="fas" icon-left="fas fa-download"
icon-left="fas fa-download" @click="showDownloadResultsDialog = true"
@click="showDownloadResultsDialog = true" :disabled="!total">
:disabled="!total"> Download Results
Download Results </b-button>
</b-button>
${h.form(url('{}.download_results'.format(route_prefix)), ref='download_results_form')} ${h.form(url('{}.download_results'.format(route_prefix)), ref='download_results_form')}
${h.csrf_token(request)} ${h.csrf_token(request)}
<input type="hidden" name="fmt" :value="downloadResultsFormat" /> <input type="hidden" name="fmt" :value="downloadResultsFormat" />
<input type="hidden" name="fields" :value="downloadResultsFieldsIncluded" /> <input type="hidden" name="fields" :value="downloadResultsFieldsIncluded" />
${h.end_form()} ${h.end_form()}
<b-modal :active.sync="showDownloadResultsDialog"> <b-modal :active.sync="showDownloadResultsDialog">
<div class="card"> <div class="card">
<div class="card-content"> <div class="card-content">
<p> <p>
There are There are
<span class="is-size-4 has-text-weight-bold"> <span class="is-size-4 has-text-weight-bold">
{{ total.toLocaleString('en') }} ${model_title_plural} {{ total.toLocaleString('en') }} ${model_title_plural}
</span> </span>
matching your current filters. matching your current filters.
</p> </p>
<p> <p>
You may download this set as a single data file if you like. You may download this set as a single data file if you like.
</p> </p>
<br /> <br />
<b-notification type="is-warning" :closable="false" <b-notification type="is-warning" :closable="false"
v-if="downloadResultsFormat == 'xlsx' && total >= 1000"> v-if="downloadResultsFormat == 'xlsx' && total >= 1000">
Excel downloads for large data sets can take a long time to Excel downloads for large data sets can take a long time to
generate, and bog down the server in the meantime. You are generate, and bog down the server in the meantime. You are
encouraged to choose CSV for a large data set, even though encouraged to choose CSV for a large data set, even though
the end result (file size) may be larger with CSV. the end result (file size) may be larger with CSV.
</b-notification> </b-notification>
<div style="display: flex; justify-content: space-between"> <div style="display: flex; justify-content: space-between">
<div> <div>
<b-field horizontal label="Format"> <b-field horizontal label="Format">
<b-select v-model="downloadResultsFormat"> <b-select v-model="downloadResultsFormat">
% for key, label in six.iteritems(master.download_results_supported_formats()): % for key, label in six.iteritems(master.download_results_supported_formats()):
<option value="${key}">${label}</option> <option value="${key}">${label}</option>
% endfor % endfor
</b-select> </b-select>
</b-field> </b-field>
</div> </div>
<div> <div>
<div v-show="downloadResultsFieldsMode != 'choose'" <div v-show="downloadResultsFieldsMode != 'choose'"
class="has-text-right"> class="has-text-right">
<p v-if="downloadResultsFieldsMode == 'default'"> <p v-if="downloadResultsFieldsMode == 'default'">
Will use DEFAULT fields. Will use DEFAULT fields.
</p> </p>
<p v-if="downloadResultsFieldsMode == 'all'"> <p v-if="downloadResultsFieldsMode == 'all'">
Will use ALL fields. Will use ALL fields.
</p> </p>
<br />
</div>
<div class="buttons is-right">
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'default'"
@click="downloadResultsUseDefaultFields()">
Use Default Fields
</b-button>
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'all'"
@click="downloadResultsUseAllFields()">
Use All Fields
</b-button>
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'choose'"
@click="downloadResultsFieldsMode = 'choose'">
Choose Fields
</b-button>
</div>
<div v-show="downloadResultsFieldsMode == 'choose'">
<div style="display: flex;">
<div>
<b-field label="Excluded Fields">
<b-select multiple native-size="8"
expanded
ref="downloadResultsExcludedFields">
<option v-for="field in downloadResultsFieldsAvailable"
v-if="!downloadResultsFieldsIncluded.includes(field)"
:key="field"
:value="field">
{{ field }}
</option>
</b-select>
</b-field>
</div>
<div>
<br /><br />
<b-button style="margin: 0.5rem;"
@click="downloadResultsExcludeFields()">
&lt;
</b-button>
<br /> <br />
</div> <b-button style="margin: 0.5rem;"
@click="downloadResultsIncludeFields()">
<div class="buttons is-right"> &gt;
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'default'"
@click="downloadResultsUseDefaultFields()">
Use Default Fields
</b-button>
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'all'"
@click="downloadResultsUseAllFields()">
Use All Fields
</b-button>
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'choose'"
@click="downloadResultsFieldsMode = 'choose'">
Choose Fields
</b-button> </b-button>
</div> </div>
<div>
<div v-show="downloadResultsFieldsMode == 'choose'"> <b-field label="Included Fields">
<div style="display: flex;"> <b-select multiple native-size="8"
<div> expanded
<b-field label="Excluded Fields"> ref="downloadResultsIncludedFields">
<b-select multiple native-size="8" <option v-for="field in downloadResultsFieldsIncluded"
expanded :key="field"
ref="downloadResultsExcludedFields"> :value="field">
<option v-for="field in downloadResultsFieldsAvailable" {{ field }}
v-if="!downloadResultsFieldsIncluded.includes(field)" </option>
:key="field" </b-select>
:value="field"> </b-field>
{{ field }}
</option>
</b-select>
</b-field>
</div>
<div>
<br /><br />
<b-button style="margin: 0.5rem;"
@click="downloadResultsExcludeFields()">
&lt;
</b-button>
<br />
<b-button style="margin: 0.5rem;"
@click="downloadResultsIncludeFields()">
&gt;
</b-button>
</div>
<div>
<b-field label="Included Fields">
<b-select multiple native-size="8"
expanded
ref="downloadResultsIncludedFields">
<option v-for="field in downloadResultsFieldsIncluded"
:key="field"
:value="field">
{{ field }}
</option>
</b-select>
</b-field>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> <!-- card-content -->
<footer class="modal-card-foot"> </div>
<b-button @click="showDownloadResultsDialog = false">
Cancel
</b-button>
<once-button type="is-primary"
@click="downloadResultsSubmit()"
icon-pack="fas"
icon-left="fas fa-download"
:disabled="!downloadResultsFieldsIncluded.length"
text="Download Results">
</once-button>
</footer>
</div> </div>
</b-modal> </div> <!-- card-content -->
% endif
<footer class="modal-card-foot">
<b-button @click="showDownloadResultsDialog = false">
Cancel
</b-button>
<once-button type="is-primary"
@click="downloadResultsSubmit()"
icon-pack="fas"
icon-left="fas fa-download"
:disabled="!downloadResultsFieldsIncluded.length"
text="Download Results">
</once-button>
</footer>
</div>
</b-modal>
% endif % endif
## download rows for search results ## download rows for search results
% if master.has_rows and master.results_rows_downloadable and master.has_perm('download_results_rows'): % if master.has_rows and master.results_rows_downloadable and master.has_perm('download_results_rows'):
% if use_buefy: <b-button type="is-primary"
<b-button type="is-primary" icon-pack="fas"
icon-pack="fas" icon-left="fas fa-download"
icon-left="fas fa-download" @click="downloadResultsRows()"
@click="downloadResultsRows()" :disabled="downloadResultsRowsButtonDisabled">
:disabled="downloadResultsRowsButtonDisabled"> {{ downloadResultsRowsButtonText }}
{{ downloadResultsRowsButtonText }} </b-button>
</b-button> ${h.form(url('{}.download_results_rows'.format(route_prefix)), ref='downloadResultsRowsForm')}
${h.form(url('{}.download_results_rows'.format(route_prefix)), ref='downloadResultsRowsForm')} ${h.csrf_token(request)}
${h.csrf_token(request)} ${h.end_form()}
${h.end_form()}
% else:
${h.form(url('{}.download_results_rows'.format(route_prefix)))}
${h.csrf_token(request)}
<button type="button" id="download-row-results-button">
Download Rows for Results
</button>
${h.end_form()}
% endif
% endif % endif
## merge 2 objects ## merge 2 objects
% if master.mergeable and request.has_perm('{}.merge'.format(permission_prefix)): % if master.mergeable and request.has_perm('{}.merge'.format(permission_prefix)):
% if use_buefy:
${h.form(url('{}.merge'.format(route_prefix)), class_='control', **{'@submit': 'submitMergeForm'})} ${h.form(url('{}.merge'.format(route_prefix)), class_='control', **{'@submit': 'submitMergeForm'})}
% else:
${h.form(url('{}.merge'.format(route_prefix)), name='merge-things')}
% endif
${h.csrf_token(request)} ${h.csrf_token(request)}
% if use_buefy: <input type="hidden"
<input type="hidden" name="uuids"
name="uuids" :value="checkedRowUUIDs()" />
:value="checkedRowUUIDs()" /> <b-button type="is-primary"
<b-button type="is-primary" native-type="submit"
native-type="submit" icon-pack="fas"
icon-pack="fas" icon-left="object-ungroup"
icon-left="object-ungroup" :disabled="mergeFormSubmitting || checkedRows.length != 2">
:disabled="mergeFormSubmitting || checkedRows.length != 2"> {{ mergeFormButtonText }}
{{ mergeFormButtonText }} </b-button>
</b-button>
% else:
${h.hidden('uuids')}
<button type="submit" class="button">Merge 2 ${model_title_plural}</button>
% endif
${h.end_form()} ${h.end_form()}
% endif % endif
## enable / disable selected objects ## enable / disable selected objects
% if master.supports_set_enabled_toggle and master.has_perm('enable_disable_set'): % if master.supports_set_enabled_toggle and master.has_perm('enable_disable_set'):
% if use_buefy: ${h.form(url('{}.enable_set'.format(route_prefix)), class_='control', ref='enable_selected_form')}
${h.form(url('{}.enable_set'.format(route_prefix)), class_='control', ref='enable_selected_form')} ${h.csrf_token(request)}
${h.csrf_token(request)} ${h.hidden('uuids', v_model='selected_uuids')}
${h.hidden('uuids', v_model='selected_uuids')} <b-button :disabled="enableSelectedDisabled"
<b-button :disabled="enableSelectedDisabled" @click="enableSelectedSubmit()">
@click="enableSelectedSubmit()"> {{ enableSelectedText }}
{{ enableSelectedText }} </b-button>
</b-button> ${h.end_form()}
${h.end_form()}
% else:
${h.form(url('{}.enable_set'.format(route_prefix)), name='enable-set', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids')}
<button type="button" class="button">Enable Selected</button>
${h.end_form()}
% endif
% if use_buefy: ${h.form(url('{}.disable_set'.format(route_prefix)), ref='disable_selected_form', class_='control')}
${h.form(url('{}.disable_set'.format(route_prefix)), ref='disable_selected_form', class_='control')} ${h.csrf_token(request)}
${h.csrf_token(request)} ${h.hidden('uuids', v_model='selected_uuids')}
${h.hidden('uuids', v_model='selected_uuids')} <b-button :disabled="disableSelectedDisabled"
<b-button :disabled="disableSelectedDisabled" @click="disableSelectedSubmit()">
@click="disableSelectedSubmit()"> {{ disableSelectedText }}
{{ disableSelectedText }} </b-button>
</b-button> ${h.end_form()}
${h.end_form()}
% else:
${h.form(url('{}.disable_set'.format(route_prefix)), name='disable-set', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids')}
<button type="button" class="button">Disable Selected</button>
${h.end_form()}
% endif
% endif % endif
## delete selected objects ## delete selected objects
% if master.set_deletable and master.has_perm('delete_set'): % if master.set_deletable and master.has_perm('delete_set'):
% if use_buefy: ${h.form(url('{}.delete_set'.format(route_prefix)), ref='delete_selected_form', class_='control')}
${h.form(url('{}.delete_set'.format(route_prefix)), ref='delete_selected_form', class_='control')} ${h.csrf_token(request)}
${h.csrf_token(request)} ${h.hidden('uuids', v_model='selected_uuids')}
${h.hidden('uuids', v_model='selected_uuids')} <b-button type="is-danger"
<b-button type="is-danger" :disabled="deleteSelectedDisabled"
:disabled="deleteSelectedDisabled" @click="deleteSelectedSubmit()"
@click="deleteSelectedSubmit()" icon-pack="fas"
icon-pack="fas" icon-left="trash">
icon-left="trash"> {{ deleteSelectedText }}
{{ deleteSelectedText }} </b-button>
</b-button> ${h.end_form()}
${h.end_form()}
% else:
${h.form(url('{}.delete_set'.format(route_prefix)), name='delete-set', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids')}
<button type="button" class="button">Delete Selected</button>
${h.end_form()}
% endif
% endif % endif
## delete search results ## delete search results
% if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)): % if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
% if use_buefy: ${h.form(url('{}.bulk_delete'.format(route_prefix)), ref='delete_results_form', class_='control')}
${h.form(url('{}.bulk_delete'.format(route_prefix)), ref='delete_results_form', class_='control')} ${h.csrf_token(request)}
${h.csrf_token(request)} <b-button type="is-danger"
<b-button type="is-danger" :disabled="deleteResultsDisabled"
:disabled="deleteResultsDisabled" :title="total ? null : 'There are no results to delete'"
:title="total ? null : 'There are no results to delete'" @click="deleteResultsSubmit()"
@click="deleteResultsSubmit()" icon-pack="fas"
icon-pack="fas" icon-left="trash">
icon-left="trash"> {{ deleteResultsText }}
{{ deleteResultsText }} </b-button>
</b-button> ${h.end_form()}
${h.end_form()}
% else:
${h.form(url('{}.bulk_delete'.format(route_prefix)), name='bulk-delete', class_='control')}
${h.csrf_token(request)}
<button type="button">Delete Results</button>
${h.end_form()}
% endif
% endif % endif
</%def> </%def>
@ -516,7 +322,7 @@
<script type="text/javascript"> <script type="text/javascript">
## maybe auto-redirect to download latest results file ## maybe auto-redirect to download latest results file
% if download_results_path and use_buefy: % if download_results_path:
ThisPage.methods.downloadResultsRedirect = function() { ThisPage.methods.downloadResultsRedirect = function() {
location.href = '${url('{}.download_results'.format(route_prefix))}?filename=${h.os.path.basename(download_results_path)}'; location.href = '${url('{}.download_results'.format(route_prefix))}?filename=${h.os.path.basename(download_results_path)}';
} }
@ -529,7 +335,7 @@
% endif % endif
## maybe auto-redirect to download latest "rows for results" file ## maybe auto-redirect to download latest "rows for results" file
% if download_results_rows_path and use_buefy: % if download_results_rows_path:
ThisPage.methods.downloadResultsRowsRedirect = function() { ThisPage.methods.downloadResultsRowsRedirect = function() {
location.href = '${url('{}.download_results_rows'.format(route_prefix))}?filename=${h.os.path.basename(download_results_rows_path)}'; location.href = '${url('{}.download_results_rows'.format(route_prefix))}?filename=${h.os.path.basename(download_results_rows_path)}';
} }
@ -541,13 +347,12 @@
} }
% endif % endif
## TODO: stop checking for buefy here once we only have the one session.pop() % if request.session.pop('{}.results_csv.generated'.format(route_prefix), False):
% if use_buefy and request.session.pop('{}.results_csv.generated'.format(route_prefix), False):
ThisPage.mounted = function() { ThisPage.mounted = function() {
location.href = '${url('{}.results_csv_download'.format(route_prefix))}'; location.href = '${url('{}.results_csv_download'.format(route_prefix))}';
} }
% endif % endif
% if use_buefy and request.session.pop('{}.results_xlsx.generated'.format(route_prefix), False): % if request.session.pop('{}.results_xlsx.generated'.format(route_prefix), False):
ThisPage.mounted = function() { ThisPage.mounted = function() {
location.href = '${url('{}.results_xlsx_download'.format(route_prefix))}'; location.href = '${url('{}.results_xlsx_download'.format(route_prefix))}';
} }
@ -793,44 +598,4 @@
</%def> </%def>
% if use_buefy: ${parent.body()}
${parent.body()}
% else:
## no buefy, so do the traditional thing
% if download_results_rows_path:
<div class="flash-messages">
<div class="ui-state-highlight ui-corner-all">
<span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-info"></span>
Your download should start automatically, or you can
${h.link_to("click here", '{}?filename={}'.format(url('{}.download_results_rows'.format(route_prefix)), h.os.path.basename(download_results_rows_path)))}
</div>
</div>
% endif
${grid.render_complete(tools=capture(self.grid_tools).strip(), context_menu=capture(self.context_menu_items).strip())|n}
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
${h.form('#', id='delete-object-form')}
${h.csrf_token(request)}
${h.end_form()}
% endif
## TODO: can stop checking for buefy above once this legacy chunk is gone
% if request.session.pop('{}.results_csv.generated'.format(route_prefix), False):
<script type="text/javascript">
$(function() {
location.href = '${url('{}.results_csv_download'.format(route_prefix))}';
});
</script>
% endif
% if request.session.pop('{}.results_xlsx.generated'.format(route_prefix), False):
<script type="text/javascript">
$(function() {
location.href = '${url('{}.results_xlsx_download'.format(route_prefix))}';
});
</script>
% endif
% endif

View file

@ -3,36 +3,6 @@
<%def name="title()">Merge 2 ${model_title_plural}</%def> <%def name="title()">Merge 2 ${model_title_plural}</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('button.swap').click(function() {
$(this).button('disable').button('option', 'label', "Swapping, please wait...");
var form = $(this).parents('form');
var input = form.find('input[name="uuids"]');
var uuids = input.val().split(',');
uuids.reverse();
input.val(uuids.join(','));
form.submit();
});
$('form.merge input[type="submit"]').click(function() {
$(this).button('disable').button('option', 'label', "Merging, please wait...");
var form = $(this).parents('form');
form.append($('<input type="hidden" name="commit-merge" value="yes" />'));
form.submit();
});
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
<style type="text/css"> <style type="text/css">
@ -92,66 +62,51 @@
</%def> </%def>
<%def name="page_content()"> <%def name="page_content()">
<p>
You are about to <strong>merge</strong> two ${model_title} records,
(possibly) along with various related data.&nbsp; The tool you are using now
is somewhat generic and is not able to give you the full picture of the
implications of this merge.&nbsp; You are urged to proceed with caution!&nbsp;
</p>
<p> <p class="warning">
You are about to <strong>merge</strong> two ${model_title} records, <strong>Unless you know what you're doing, a good rule of thumb (though still no
(possibly) along with various related data.&nbsp; The tool you are using now guarantee) is to merge <em>only</em> if the "resulting" column is all-white.</strong>&nbsp;
is somewhat generic and is not able to give you the full picture of the (You may be able to swap kept/removed in order to achieve this.)
implications of this merge.&nbsp; You are urged to proceed with caution!&nbsp; </p>
</p>
<p class="warning"> <p>
<strong>Unless you know what you're doing, a good rule of thumb (though still no The ${h.link_to("{} on the left".format(model_title), view_url(object_to_remove), target='_blank', class_='merge-object')}
guarantee) is to merge <em>only</em> if the "resulting" column is all-white.</strong>&nbsp; will be <strong>deleted</strong>
(You may be able to swap kept/removed in order to achieve this.) and the ${h.link_to("{} on the right".format(model_title), view_url(object_to_keep), target='_blank', class_='merge-object')}
</p> will be <strong>kept</strong>.&nbsp; The one which is to be kept may also
be updated to reflect certain aspects of the one being deleted; however again
the details are up to the app logic for this type of merge and aren't fully
known to the generic tool which you're using now.
</p>
<p> <table class="diff">
The ${h.link_to("{} on the left".format(model_title), view_url(object_to_remove), target='_blank', class_='merge-object')} <thead>
will be <strong>deleted</strong> <tr>
and the ${h.link_to("{} on the right".format(model_title), view_url(object_to_keep), target='_blank', class_='merge-object')} <th>field name</th>
will be <strong>kept</strong>.&nbsp; The one which is to be kept may also <th>deleting ${model_title}</th>
be updated to reflect certain aspects of the one being deleted; however again <th>keeping ${model_title}</th>
the details are up to the app logic for this type of merge and aren't fully <th>resulting ${model_title}</th>
known to the generic tool which you're using now. </tr>
</p> </thead>
<tbody>
% for field in sorted(merge_fields):
<tr${' class="diff"' if keep_data[field] != remove_data[field] else ''|n}>
<td class="field">${field}</td>
<td class="value remove-value">${repr(remove_data[field])}</td>
<td class="value keep-value">${repr(keep_data[field])}</td>
<td class="value result-value${' diff' if resulting_data[field] != keep_data[field] else ''}">${repr(resulting_data[field])}</td>
</tr>
% endfor
</tbody>
</table>
<table class="diff"> <merge-buttons></merge-buttons>
<thead>
<tr>
<th>field name</th>
<th>deleting ${model_title}</th>
<th>keeping ${model_title}</th>
<th>resulting ${model_title}</th>
</tr>
</thead>
<tbody>
% for field in sorted(merge_fields):
<tr${' class="diff"' if keep_data[field] != remove_data[field] else ''|n}>
<td class="field">${field}</td>
<td class="value remove-value">${repr(remove_data[field])}</td>
<td class="value keep-value">${repr(keep_data[field])}</td>
<td class="value result-value${' diff' if resulting_data[field] != keep_data[field] else ''}">${repr(resulting_data[field])}</td>
</tr>
% endfor
</tbody>
</table>
% if use_buefy:
<merge-buttons></merge-buttons>
% else:
## no buefy; do legacy stuff
${h.form(request.current_route_url(), class_='merge')}
${h.csrf_token(request)}
<div class="buttons">
${h.hidden('uuids', value='{},{}'.format(object_to_remove.uuid, object_to_keep.uuid))}
<a class="button" href="${index_url}">Whoops, nevermind</a>
<button type="button" class="swap">Swap which ${model_title} is kept/removed</button>
${h.submit('merge', "Yes, perform this merge")}
</div>
${h.end_form()}
% endif
</%def> </%def>
<%def name="render_this_page_template()"> <%def name="render_this_page_template()">
@ -177,11 +132,7 @@ ${h.end_form()}
</div> </div>
<div class="level-item"> <div class="level-item">
% if use_buefy:
${h.form(request.current_route_url(), **{'@submit': 'submitMergeForm'})} ${h.form(request.current_route_url(), **{'@submit': 'submitMergeForm'})}
% else:
${h.form(request.current_route_url())}
% endif
${h.csrf_token(request)} ${h.csrf_token(request)}
${h.hidden('uuids', value='{},{}'.format(object_to_remove.uuid, object_to_keep.uuid))} ${h.hidden('uuids', value='{},{}'.format(object_to_remove.uuid, object_to_keep.uuid))}
${h.hidden('commit-merge', value='yes')} ${h.hidden('commit-merge', value='yes')}

View file

@ -46,12 +46,8 @@
</%def> </%def>
<%def name="page_content()"> <%def name="page_content()">
% if use_buefy: <tailbone-grid :csrftoken="csrftoken">
<tailbone-grid :csrftoken="csrftoken"> </tailbone-grid>
</tailbone-grid>
% else:
${grid.render_complete()|n}
% endif
</%def> </%def>
${parent.body()} ${parent.body()}

View file

@ -3,46 +3,6 @@
<%def name="title()">${index_title} &raquo; ${instance_title}</%def> <%def name="title()">${index_title} &raquo; ${instance_title}</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
% if master.deletable and instance_deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
<script type="text/javascript">
$(function () {
$('#context-menu a.delete-instance').on('click', function() {
if (confirm("Are you sure you wish to delete this ${model_title}?")) {
$(this).parents('form').submit();
}
return false;
});
});
</script>
% endif
% if master.has_rows:
<script type="text/javascript">
$(function() {
$('.grid-wrapper').gridwrapper();
});
</script>
% endif
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if master.has_rows and not use_buefy:
<style type="text/css">
.grid-wrapper {
margin-top: 10px;
}
</style>
% endif
</%def>
<%def name="content_title()"> <%def name="content_title()">
${instance_title} ${instance_title}
</%def> </%def>
@ -54,33 +14,19 @@
<%def name="render_xref_helper()"> <%def name="render_xref_helper()">
% if xref_buttons or xref_links: % if xref_buttons or xref_links:
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Cross-Reference</p>
<p class="panel-heading">Cross-Reference</p> <div class="panel-block buttons">
<div class="panel-block buttons"> <div style="display: flex; flex-direction: column;">
<div style="display: flex; flex-direction: column;"> % for button in xref_buttons:
% for button in xref_buttons: ${button}
${button} % endfor
% endfor % for link in xref_links:
% for link in xref_links: ${link}
${link} % endfor
% endfor
</div>
</div>
</nav>
% else:
<div class="object-helper">
<h3>Cross-Reference</h3>
<div class="object-helper-content">
% for button in xref_buttons:
${button}
% endfor
% for link in xref_links:
${link}
% endfor
</div>
</div> </div>
% endif </div>
</nav>
% endif % endif
</%def> </%def>
@ -91,63 +37,37 @@
% if master.has_versions and request.rattail_config.versioning_enabled() and request.has_perm('{}.versions'.format(permission_prefix)): % if master.has_versions and request.rattail_config.versioning_enabled() and request.has_perm('{}.versions'.format(permission_prefix)):
<li>${h.link_to("Version History", action_url('versions', instance))}</li> <li>${h.link_to("Version History", action_url('versions', instance))}</li>
% endif % endif
% if not use_buefy and master.editable and instance_editable and master.has_perm('edit'):
<li>${h.link_to("Edit this {}".format(model_title), action_url('edit', instance))}</li>
% endif
${self.context_menu_item_delete()}
% if not use_buefy and master.creatable and master.show_create_link and master.has_perm('create'):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
% else:
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif
% endif
% if not use_buefy and master.cloneable and master.has_perm('clone'):
<li>${h.link_to("Clone this as new {}".format(model_title), url('{}.clone'.format(route_prefix), uuid=instance.uuid))}</li>
% endif
% if master.touchable and request.has_perm('{}.touch'.format(permission_prefix)): % if master.touchable and request.has_perm('{}.touch'.format(permission_prefix)):
<li>${h.link_to("\"Touch\" this {}".format(model_title), master.get_action_url('touch', instance))}</li> <li>${h.link_to("\"Touch\" this {}".format(model_title), master.get_action_url('touch', instance))}</li>
% endif % endif
% if not use_buefy and master.has_rows and master.rows_downloadable_csv and master.has_perm('row_results_csv'):
<li>${h.link_to("Download row results as CSV", master.get_action_url('row_results_csv', instance))}</li>
% endif
% if not use_buefy and master.has_rows and master.rows_downloadable_xlsx and master.has_perm('row_results_xlsx'):
<li>${h.link_to("Download row results as XLSX", master.get_action_url('row_results_xlsx', instance))}</li>
% endif
</%def> </%def>
<%def name="render_row_grid_tools()"> <%def name="render_row_grid_tools()">
${rows_grid_tools} ${rows_grid_tools}
% if use_buefy: % if master.rows_downloadable_xlsx and master.has_perm('row_results_xlsx'):
% if master.rows_downloadable_xlsx and master.has_perm('row_results_xlsx'): <b-button tag="a" href="${master.get_action_url('row_results_xlsx', instance)}"
<b-button tag="a" href="${master.get_action_url('row_results_xlsx', instance)}" icon-pack="fas"
icon-pack="fas" icon-left="download">
icon-left="download"> Download Results XLSX
Download Results XLSX </b-button>
</b-button> % endif
% endif % if master.rows_downloadable_csv and master.has_perm('row_results_csv'):
% if master.rows_downloadable_csv and master.has_perm('row_results_csv'): <b-button tag="a" href="${master.get_action_url('row_results_csv', instance)}"
<b-button tag="a" href="${master.get_action_url('row_results_csv', instance)}" icon-pack="fas"
icon-pack="fas" icon-left="download">
icon-left="download"> Download Results CSV
Download Results CSV </b-button>
</b-button>
% endif
% endif % endif
</%def> </%def>
<%def name="render_this_page()"> <%def name="render_this_page()">
${parent.render_this_page()} ${parent.render_this_page()}
% if master.has_rows: % if master.has_rows:
% if use_buefy: <br />
<br /> % if rows_title:
% if rows_title: <h4 class="block is-size-4">${rows_title}</h4>
<h4 class="block is-size-4">${rows_title}</h4>
% endif
${self.render_row_grid_component()}
% else:
${rows_grid|n}
% endif % endif
${self.render_row_grid_component()}
% endif % endif
</%def> </%def>

View file

@ -12,9 +12,6 @@
% if master.rows_editable and instance_editable and request.has_perm('{}.edit'.format(permission_prefix)): % if master.rows_editable and instance_editable and request.has_perm('{}.edit'.format(permission_prefix)):
<li>${h.link_to("Edit this {}".format(model_title), action_url('edit', instance))}</li> <li>${h.link_to("Edit this {}".format(model_title), action_url('edit', instance))}</li>
% endif % endif
% if not use_buefy and instance_deletable and master.has_perm('delete_row'):
<li>${h.link_to("Delete this {}".format(model_title), action_url('delete', instance))}</li>
% endif
% if rows_creatable and request.has_perm('{}.create'.format(permission_prefix)): % if rows_creatable and request.has_perm('{}.create'.format(permission_prefix)):
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li> <li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif % endif

View file

@ -3,15 +3,6 @@
<%def name="title()">Message Archive</%def> <%def name="title()">Message Archive</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
destination = "Inbox";
</script>
% endif
</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
${parent.context_menu_items()} ${parent.context_menu_items()}
<li>${h.link_to("Go to my Message Inbox", url('messages.inbox'))}</li> <li>${h.link_to("Go to my Message Inbox", url('messages.inbox'))}</li>

View file

@ -2,148 +2,26 @@
<%inherit file="/master/create.mako" /> <%inherit file="/master/create.mako" />
<%namespace file="/messages/recipients.mako" import="message_recipients_template" /> <%namespace file="/messages/recipients.mako" import="message_recipients_template" />
<%def name="content_title()">${parent.content_title() if not use_buefy else ''}</%def> <%def name="content_title()"></%def>
<%def name="extra_javascript()"> <%def name="extra_javascript()">
${parent.extra_javascript()} ${parent.extra_javascript()}
% if use_buefy: ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.message_recipients.js'))}
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.message_recipients.js'))}
% else:
${h.javascript_link(request.static_url('tailbone:static/js/lib/tag-it.min.js'))}
<script type="text/javascript">
var recipient_mappings = new Map([
<% last = len(available_recipients) %>
% for i, recip in enumerate(available_recipients, 1):
<% uuid, entry = recip %>
['${uuid}', ${json.dumps(entry)|n}]${',' if i < last else ''}
% endfor
]);
// validate message before sending
function validate_message_form() {
var form = $('#deform');
if (! form.find('input[name="set_recipients"]').val()) {
alert("You must specify some recipient(s) for the message.");
$('.set_recipients input').data('ui-tagit').tagInput.focus();
return false;
}
if (! form.find('input[name="subject"]').val()) {
alert("You must provide a subject for the message.");
form.find('input[name="subject"]').focus();
return false;
}
return true;
}
$(function() {
var recipients = $('.set_recipients input');
recipients.tagit({
autocomplete: {
delay: 0,
minLength: 2,
autoFocus: true,
removeConfirmation: true,
source: function(request, response) {
var term = request.term.toLowerCase();
var data = [];
recipient_mappings.forEach(function(name, uuid) {
if (!name.toLowerCase && name.name) {
name = name.name;
}
if (name.toLowerCase().indexOf(term) >= 0) {
data.push({value: uuid, label: name});
}
});
response(data);
}
},
beforeTagAdded: ${self.before_tag_added()},
beforeTagRemoved: function(event, ui) {
// Unfortunately we're responsible for cleaning up the hidden
// field, since the values there do not match the tag labels.
var tags = recipients.tagit('assignedTags');
var uuid = ui.tag.data('uuid');
tags = tags.filter(function(element) {
return element != uuid;
});
recipients.data('ui-tagit')._updateSingleTagsField(tags);
}
});
// set focus to recipients field
recipients.data('ui-tagit').tagInput.focus();
});
</script>
${self.validate_message_js()}
% endif
</%def>
<%def name="validate_message_js()">
<script type="text/javascript">
$(function() {
$('#new-message').submit(function() {
return validate_message_form();
});
});
</script>
</%def> </%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
.this-page-content {
width: 100%;
}
.this-page-content .buttons {
margin-left: 20rem;
}
</style>
% else:
${h.stylesheet_link(request.static_url('tailbone:static/css/jquery.tagit.css'))}
<style type="text/css"> <style type="text/css">
.recipients input { .this-page-content {
min-width: 525px; width: 100%;
} }
.subject input { .this-page-content .buttons {
min-width: 540px; margin-left: 20rem;
}
.body textarea {
min-width: 540px;
} }
</style> </style>
% endif
</%def>
<%def name="before_tag_added()">
function(event, ui) {
// Lookup the name in cached mapping, and show that on the tag, instead
// of the UUID. The tagit widget should take care of keeping the
// hidden field in sync for us, still using the UUID.
var uuid = ui.tagLabel;
var name = recipient_mappings.get(uuid);
ui.tag.find('.tagit-label').html(name);
}
</%def> </%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">

View file

@ -3,15 +3,6 @@
<%def name="title()">Message Inbox</%def> <%def name="title()">Message Inbox</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
destination = "Archive";
</script>
% endif
</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
${parent.context_menu_items()} ${parent.context_menu_items()}
<li>${h.link_to("Go to my Message Archive", url('messages.archive'))}</li> <li>${h.link_to("Go to my Message Archive", url('messages.archive'))}</li>

View file

@ -1,52 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/index.mako" /> <%inherit file="/master/index.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
var destination = null;
function update_move_button() {
var count = $('.grid tr:not(.header) td.checkbox input:checked').length;
$('form[name="move-selected"] button')
.button('option', 'label', "Move " + count + " selected to " + destination)
.button('option', 'disabled', count < 1);
}
$(function() {
update_move_button();
$('.grid-wrapper').on('change', 'tr.header td.checkbox input', function() {
update_move_button();
});
$('.grid-wrapper').on('click', 'tr:not(.header) td.checkbox input', function() {
update_move_button();
});
$('form[name="move-selected"]').submit(function() {
var uuids = [];
$('.grid tr:not(.header) td.checkbox input:checked').each(function() {
uuids.push($(this).parents('tr:first').data('uuid'));
});
if (! uuids.length) {
return false;
}
$(this).find('[name="uuids"]').val(uuids.toString());
$(this).find('button')
.button('option', 'label', "Moving " + uuids.length + " messages to " + destination + "...")
.button('disable');
});
});
</script>
% endif
</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
% if request.has_perm('messages.create'): % if request.has_perm('messages.create'):
<li>${h.link_to("Send a new Message", url('messages.create'))}</li> <li>${h.link_to("Send a new Message", url('messages.create'))}</li>
@ -55,25 +9,16 @@
<%def name="grid_tools()"> <%def name="grid_tools()">
% if request.matched_route.name in ('messages.inbox', 'messages.archive'): % if request.matched_route.name in ('messages.inbox', 'messages.archive'):
% if use_buefy: ${h.form(url('messages.move_bulk'), **{'@submit': 'moveMessagesSubmit'})}
${h.form(url('messages.move_bulk'), **{'@submit': 'moveMessagesSubmit'})} ${h.csrf_token(request)}
${h.csrf_token(request)} ${h.hidden('destination', value='archive' if request.matched_route.name == 'messages.inbox' else 'inbox')}
${h.hidden('destination', value='archive' if request.matched_route.name == 'messages.inbox' else 'inbox')} ${h.hidden('uuids', v_model='selected_uuids')}
${h.hidden('uuids', v_model='selected_uuids')} <b-button type="is-primary"
<b-button type="is-primary" native-type="submit"
native-type="submit" :disabled="moveMessagesSubmitting || !checkedRows.length">
:disabled="moveMessagesSubmitting || !checkedRows.length"> {{ moveMessagesTextCurrent }}
{{ moveMessagesTextCurrent }} </b-button>
</b-button> ${h.end_form()}
${h.end_form()}
% else:
${h.form(url('messages.move_bulk'), name='move-selected')}
${h.csrf_token(request)}
${h.hidden('destination', value='archive' if request.matched_route.name == 'messages.inbox' else 'inbox')}
${h.hidden('uuids')}
<button type="submit">Move 0 selected to ${'Archive' if request.matched_route.name == 'messages.inbox' else 'Inbox'}</button>
${h.end_form()}
% endif
% endif % endif
</%def> </%def>

View file

@ -1,66 +1,20 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('.field-wrapper.recipients .more').click(function() {
$(this).hide();
$(this).siblings('.everyone').css('display', 'inline-block');
return false;
});
$('.field-wrapper.recipients .everyone').click(function() {
$(this).hide();
$(this).siblings('.more').show();
});
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
.everyone {
cursor: pointer;
}
.tailbone-message-body {
margin: 1rem auto;
min-height: 10rem;
}
.tailbone-message-body p {
margin-bottom: 1rem;
}
</style>
% else:
<style type="text/css"> <style type="text/css">
.recipients .everyone { .everyone {
cursor: pointer; cursor: pointer;
display: none;
} }
.message-tools { .tailbone-message-body {
margin-bottom: 15px; margin: 1rem auto;
min-height: 10rem;
} }
.message-body { .tailbone-message-body p {
border-top: 1px solid black; margin-bottom: 1rem;
border-bottom: 1px solid black;
margin-bottom: 15px;
padding: 0 5em;
white-space: pre-line;
}
.message-body p {
margin-bottom: 15px;
} }
</style> </style>
% endif
</%def> </%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
@ -86,43 +40,29 @@
<%def name="message_tools()"> <%def name="message_tools()">
% if recipient: % if recipient:
% if use_buefy: <div class="buttons">
<div class="buttons"> % if request.has_perm('messages.create'):
% if request.has_perm('messages.create'): <once-button type="is-primary"
<once-button type="is-primary" tag="a" href="${url('messages.reply', uuid=instance.uuid)}"
tag="a" href="${url('messages.reply', uuid=instance.uuid)}" text="Reply">
text="Reply"> </once-button>
</once-button> <once-button type="is-primary"
<once-button type="is-primary" tag="a" href="${url('messages.reply_all', uuid=instance.uuid)}"
tag="a" href="${url('messages.reply_all', uuid=instance.uuid)}" text="Reply to All">
text="Reply to All"> </once-button>
</once-button> % endif
% endif % if recipient.status == enum.MESSAGE_STATUS_INBOX:
% if recipient.status == enum.MESSAGE_STATUS_INBOX: <once-button type="is-primary"
<once-button type="is-primary" tag="a" href="${url('messages.move', uuid=instance.uuid)}?dest=archive"
tag="a" href="${url('messages.move', uuid=instance.uuid)}?dest=archive" text="Move to Archive">
text="Move to Archive"> </once-button>
</once-button> % else:
% else: <once-button type="is-primary"
<once-button type="is-primary" tag="a" href="${url('messages.move', uuid=instance.uuid)}?dest=inbox"
tag="a" href="${url('messages.move', uuid=instance.uuid)}?dest=inbox" text="Move to Inbox">
text="Move to Inbox"> </once-button>
</once-button> % endif
% endif </div>
</div>
% else:
<div class="message-tools">
% if request.has_perm('messages.create'):
${h.link_to("Reply", url('messages.reply', uuid=instance.uuid), class_='button')}
${h.link_to("Reply to All", url('messages.reply_all', uuid=instance.uuid), class_='button')}
% endif
% if recipient.status == enum.MESSAGE_STATUS_INBOX:
${h.link_to("Move to Archive", url('messages.move', uuid=instance.uuid) + '?dest=archive', class_='button')}
% else:
${h.link_to("Move to Inbox", url('messages.move', uuid=instance.uuid) + '?dest=inbox', class_='button')}
% endif
</div>
% endif
% endif % endif
</%def> </%def>
@ -132,22 +72,14 @@
<%def name="page_content()"> <%def name="page_content()">
${parent.page_content()} ${parent.page_content()}
% if use_buefy: <br />
<br /> <div style="margin-left: 5rem;">
<div style="margin-left: 5rem;"> ${self.message_tools()}
${self.message_tools()} <div class="tailbone-message-body">
<div class="tailbone-message-body"> ${self.message_body()}
${self.message_body()} </div>
</div> ${self.message_tools()}
${self.message_tools()} </div>
</div>
% else:
${self.message_tools()}
<div class="message-body">
${self.message_body()}
</div>
${self.message_tools()}
% endif
</%def> </%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">

View file

@ -1,82 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/batch/create.mako" /> <%inherit file="/batch/create.mako" />
<%def name="extra_javascript()"> ## TODO: deprecate / remove
${parent.extra_javascript()}
% if not use_buefy:
${self.func_show_mode()}
<script type="text/javascript">
var purchases_field = '${purchases_field}';
var purchases = null; // TODO: where is this used?
function vendor_selected(uuid, name) {
## var mode = $('.mode select').val();
## if (mode == ${enum.PURCHASE_BATCH_MODE_RECEIVING} || mode == ${enum.PURCHASE_BATCH_MODE_COSTING}) {
## var purchases = $('.purchase_uuid select');
## purchases.empty();
##
## var data = {'vendor_uuid': uuid, 'mode': mode};
## $.get('${url('purchases.batch.eligible_purchases')}', data, function(data) {
## if (data.error) {
## alert(data.error);
## } else {
## $.each(data.purchases, function(i, purchase) {
## purchases.append($('<option value="' + purchase.key + '">' + purchase.display + '</option>'));
## });
## }
## });
##
## // TODO: apparently refresh doesn't work right?
## // http://stackoverflow.com/a/10280078
## // purchases.selectmenu('refresh');
## purchases.selectmenu('destroy').selectmenu();
## }
}
function vendor_cleared() {
var purchases = $('.purchase_uuid select');
purchases.empty();
// TODO: apparently refresh doesn't work right?
// http://stackoverflow.com/a/10280078
// purchases.selectmenu('refresh');
purchases.selectmenu('destroy').selectmenu();
}
$(function() {
$('.field-wrapper.mode select').selectmenu({
change: function(event, ui) {
show_mode(ui.item.value);
}
});
show_mode(${enum.PURCHASE_BATCH_MODE_ORDERING});
});
</script>
% endif
</%def>
<%def name="func_show_mode()">
<script type="text/javascript">
// TODO: mode is presumably null here..
function show_mode(mode) {
$('.field-wrapper.store_uuid').show();
$('.field-wrapper.' + purchases_field).hide();
$('.field-wrapper.department_uuid').show();
$('.field-wrapper.buyer_uuid').show();
$('.field-wrapper.date_ordered').show();
$('.field-wrapper.date_received').hide();
$('.field-wrapper.po_number').show();
$('.field-wrapper.invoice_date').hide();
$('.field-wrapper.invoice_number').hide();
}
</script>
</%def>
${parent.body()} ${parent.body()}

View file

@ -3,63 +3,6 @@
<%def name="title()">Ordering Worksheet</%def> <%def name="title()">Ordering Worksheet</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
<script type="text/javascript">
var submitting = false;
$(function() {
$('.order-form td.current-order input').focus(function(event) {
$(this).parents('tr:first').addClass('active');
});
$('.order-form td.current-order input').blur(function(event) {
$(this).parents('tr:first').removeClass('active');
});
$('.order-form td.current-order input').keydown(function(event) {
if (key_allowed(event) || key_modifies(event)) {
return true;
}
if (event.which == 13) {
if (! submitting) {
submitting = true;
var row = $(this).parents('tr:first');
var form = $('#item-update-form');
form.find('[name="product_uuid"]').val(row.data('uuid'));
form.find('[name="cases_ordered"]').val(row.find('input[name^="cases_ordered_"]').val() || '0');
form.find('[name="units_ordered"]').val(row.find('input[name^="units_ordered_"]').val() || '0');
$.post(form.attr('action'), form.serialize(), function(data) {
if (data.error) {
alert(data.error);
} else {
if (data.row_cases_ordered || data.row_units_ordered) {
row.find('input[name^="cases_ordered_"]').val(data.row_cases_ordered);
row.find('input[name^="units_ordered_"]').val(data.row_units_ordered);
row.find('td.po-total').html(data.row_po_total_calculated);
} else {
row.find('input[name^="cases_ordered_"]').val('');
row.find('input[name^="units_ordered_"]').val('');
row.find('td.po-total').html('');
}
$('.po-total .field').html(data.batch_po_total_calculated);
}
submitting = false;
});
}
}
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
<style type="text/css"> <style type="text/css">
@ -187,10 +130,7 @@
<tbody> <tbody>
% for i, cost in enumerate(subdepartment._order_costs, 1): % for i, cost in enumerate(subdepartment._order_costs, 1):
<tr data-uuid="${cost.product_uuid}" class="${'even' if i % 2 == 0 else 'odd'}" <tr data-uuid="${cost.product_uuid}" class="${'even' if i % 2 == 0 else 'odd'}"
% if use_buefy: :class="{active: activeUUID == '${cost.uuid}'}">
:class="{active: activeUUID == '${cost.uuid}'}"
% endif
>
${self.order_form_row(cost)} ${self.order_form_row(cost)}
% for data in history: % for data in history:
<td class="scratch_pad"> <td class="scratch_pad">
@ -216,34 +156,21 @@
% endfor % endfor
% if not ignore_cases: % if not ignore_cases:
<td class="current-order"> <td class="current-order">
% if use_buefy: <numeric-input v-model="worksheet.cost_${cost.uuid}_cases"
<numeric-input v-model="worksheet.cost_${cost.uuid}_cases"
@focus="activeUUID = '${cost.uuid}'; $event.target.select()"
@blur="activeUUID = null"
@keydown.native="inputKeydown($event, '${cost.uuid}', '${cost.product_uuid}')">
</numeric-input>
% else:
${h.text('cases_ordered_{}'.format(cost.uuid), value=int(cost._batchrow.cases_ordered or 0) if cost._batchrow else None)}
% endif
</td>
% endif
<td class="current-order">
% if use_buefy:
<numeric-input v-model="worksheet.cost_${cost.uuid}_units"
@focus="activeUUID = '${cost.uuid}'; $event.target.select()" @focus="activeUUID = '${cost.uuid}'; $event.target.select()"
@blur="activeUUID = null" @blur="activeUUID = null"
@keydown.native="inputKeydown($event, '${cost.uuid}', '${cost.product_uuid}')"> @keydown.native="inputKeydown($event, '${cost.uuid}', '${cost.product_uuid}')">
</numeric-input> </numeric-input>
% else: </td>
${h.text('units_ordered_{}'.format(cost.uuid), value=int(cost._batchrow.units_ordered or 0) if cost._batchrow else None)}
% endif
</td>
## TODO: should not fall back to po_total
% if use_buefy:
<td class="po-total">{{ worksheet.cost_${cost.uuid}_total_display }}</td>
% else:
<td class="po-total">${'${:0,.2f}'.format(cost._batchrow.po_total_calculated or cost._batchrow.po_total or 0) if cost._batchrow else ''}</td>
% endif % endif
<td class="current-order">
<numeric-input v-model="worksheet.cost_${cost.uuid}_units"
@focus="activeUUID = '${cost.uuid}'; $event.target.select()"
@blur="activeUUID = null"
@keydown.native="inputKeydown($event, '${cost.uuid}', '${cost.product_uuid}')">
</numeric-input>
</td>
<td class="po-total">{{ worksheet.cost_${cost.uuid}_total_display }}</td>
${self.extra_td(cost)} ${self.extra_td(cost)}
</tr> </tr>
% endfor % endfor
@ -269,55 +196,7 @@
</%def> </%def>
<%def name="page_content()"> <%def name="page_content()">
% if use_buefy: <ordering-worksheet></ordering-worksheet>
<ordering-worksheet></ordering-worksheet>
% else:
<div class="form-wrapper">
<div class="field-wrapper">
<label>Vendor</label>
<div class="field">${h.link_to(vendor, url('vendors.view', uuid=vendor.uuid))}</div>
</div>
<div class="field-wrapper">
<label>Vendor Email</label>
<div class="field">${vendor.email or ''}</div>
</div>
<div class="field-wrapper">
<label>Vendor Fax</label>
<div class="field">${vendor.fax_number or ''}</div>
</div>
<div class="field-wrapper">
<label>Vendor Contact</label>
<div class="field">${vendor.contact or ''}</div>
</div>
<div class="field-wrapper">
<label>Vendor Phone</label>
<div class="field">${vendor.phone or ''}</div>
</div>
${self.extra_vendor_fields()}
<div class="field-wrapper po-total">
<label>PO Total</label>
## TODO: should not fall back to po_total
<div class="field">$${'{:0,.2f}'.format(batch.po_total_calculated or batch.po_total or 0)}</div>
</div>
</div><!-- form-wrapper -->
${self.order_form_grid()}
${h.form(url('ordering.worksheet_update', uuid=batch.uuid), id='item-update-form', style='display: none;')}
${h.csrf_token(request)}
${h.hidden('product_uuid')}
${h.hidden('cases_ordered')}
${h.hidden('units_ordered')}
${h.end_form()}
% endif
</%def> </%def>
<%def name="render_this_page_template()"> <%def name="render_this_page_template()">

View file

@ -4,7 +4,6 @@
<%def name="grid_tools()"> <%def name="grid_tools()">
% if master.mergeable and master.has_perm('request_merge'): % if master.mergeable and master.has_perm('request_merge'):
% if use_buefy:
<b-button @click="showMergeRequest()" <b-button @click="showMergeRequest()"
icon-pack="fas" icon-pack="fas"
icon-left="object-ungroup" icon-left="object-ungroup"
@ -57,7 +56,6 @@
</footer> </footer>
</div> </div>
</b-modal> </b-modal>
% endif
% endif % endif
${parent.grid_tools()} ${parent.grid_tools()}

View file

@ -4,7 +4,6 @@
<%def name="page_content()"> <%def name="page_content()">
${parent.page_content()} ${parent.page_content()}
% if not instance.merged and request.has_perm('people.merge'): % if not instance.merged and request.has_perm('people.merge'):
% if use_buefy:
${h.form(url('people.merge'), **{'@submit': 'submitMergeForm'})} ${h.form(url('people.merge'), **{'@submit': 'submitMergeForm'})}
${h.csrf_token(request)} ${h.csrf_token(request)}
${h.hidden('uuids', value=','.join([instance.removing_uuid, instance.keeping_uuid]))} ${h.hidden('uuids', value=','.join([instance.removing_uuid, instance.keeping_uuid]))}
@ -16,7 +15,6 @@
{{ mergeFormButtonText }} {{ mergeFormButtonText }}
</b-button> </b-button>
${h.end_form()} ${h.end_form()}
% endif
% endif % endif
</%def> </%def>

View file

@ -2,25 +2,6 @@
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%namespace file="/util.mako" import="view_profiles_helper" /> <%namespace file="/util.mako" import="view_profiles_helper" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and not instance.users and request.has_perm('users.create'):
<script type="text/javascript">
## TODO: should do this differently for Buefy themes
$(function() {
$('#make-user').click(function() {
if (confirm("Really make a user account for this person?")) {
% if not use_buefy:
disable_button(this);
% endif
$('form[name="make-user-form"]').submit();
}
});
});
</script>
% endif
</%def>
<%def name="object_helpers()"> <%def name="object_helpers()">
${parent.object_helpers()} ${parent.object_helpers()}
${view_profiles_helper([instance])} ${view_profiles_helper([instance])}
@ -52,11 +33,7 @@
<%def name="page_content()"> <%def name="page_content()">
${parent.page_content()} ${parent.page_content()}
% if not instance.users and request.has_perm('users.create'): % if not instance.users and request.has_perm('users.create'):
% if use_buefy: ${h.form(url('people.make_user'), ref='makeUserForm')}
${h.form(url('people.make_user'), ref='makeUserForm')}
% else:
${h.form(url('people.make_user'), name='make-user-form')}
% endif
${h.csrf_token(request)} ${h.csrf_token(request)}
${h.hidden('person_uuid', value=instance.uuid)} ${h.hidden('person_uuid', value=instance.uuid)}
${h.end_form()} ${h.end_form()}

View file

@ -3,77 +3,10 @@
<%def name="title()">Find ${model_title_plural} by Permission</%def> <%def name="title()">Find ${model_title_plural} by Permission</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
<% gcount = len(permissions) %>
var permissions_by_group = {
% for g, (gkey, group) in enumerate(permissions, 1):
<% pcount = len(group['perms']) %>
'${gkey}': {
% for p, (pkey, perm) in enumerate(group['perms'], 1):
'${pkey}': "${perm['label']}"${',' if p < pcount else ''}
% endfor
}${',' if g < gcount else ''}
% endfor
};
$(function() {
$('#permission_group').selectmenu({
change: function(event, ui) {
var perms = $('#permission');
perms.find('option:first').siblings('option').remove();
$.each(permissions_by_group[ui.item.value], function(key, label) {
perms.append($('<option value="' + key + '">' + label + '</option>'));
});
perms.selectmenu('refresh');
}
});
$('#permission').selectmenu();
$('#find-by-perm-form').submit(function() {
$('.grid').remove();
$(this).find('#submit').button('disable').button('option', 'label', "Searching, please wait...");
});
});
</script>
% endif
</%def>
<%def name="page_content()"> <%def name="page_content()">
% if use_buefy: <find-principals :permission-groups="permissionGroups"
<find-principals :permission-groups="permissionGroups" :sorted-groups="sortedGroups">
:sorted-groups="sortedGroups"> </find-principals>
</find-principals>
% else:
## not buefy
${h.form(request.current_route_url(), id='find-by-perm-form')}
${h.csrf_token(request)}
<div class="form">
${self.wtfield(form, 'permission_group')}
${self.wtfield(form, 'permission')}
<div class="buttons">
${h.submit('submit', "Find {}".format(model_title_plural))}
</div>
</div>
${h.end_form()}
% if principals is not None:
<div class="grid half">
<br />
<h2>${model_title_plural} with that permission (${len(principals)} total):</h2>
${self.principal_table()}
</div>
% endif
% endif
</%def> </%def>
<%def name="render_this_page_template()"> <%def name="render_this_page_template()">

View file

@ -7,66 +7,22 @@
<li>${h.link_to("Back to Products", url('products'))}</li> <li>${h.link_to("Back to Products", url('products'))}</li>
</%def> </%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('select[name="batch_type"]').on('selectmenuchange', function(event, ui) {
$('.params-wrapper').hide();
$('.params-wrapper.' + ui.item.value).show();
});
$('.params-wrapper.' + $('select[name="batch_type"]').val()).show();
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if not use_buefy:
<style type="text/css">
.params-wrapper {
display: none;
}
</style>
% endif
</%def>
<%def name="render_deform_field(form, field)"> <%def name="render_deform_field(form, field)">
% if use_buefy: <b-field horizontal
<b-field horizontal % if field.description:
% if field.description: message="${field.description}"
message="${field.description}" % endif
% endif % if field.error:
% if field.error: type="is-danger"
type="is-danger" :message='${form.messages_json(field.error.messages())|n}'
:message='${form.messages_json(field.error.messages())|n}' % endif
% endif label="${field.title}">
label="${field.title}"> ${field.serialize()|n}
${field.serialize(use_buefy=True)|n} </b-field>
</b-field>
% else:
<div class="field-wrapper ${field.name}">
<div class="field-row">
<label for="${field.oid}">${field.title}</label>
<div class="field">
${field.serialize()|n}
</div>
</div>
</div>
% endif
</%def> </%def>
<%def name="render_form_innards()"> <%def name="render_form_innards()">
% if use_buefy:
${h.form(request.current_route_url(), **{'@submit': 'submit{}'.format(form.component_studly)})} ${h.form(request.current_route_url(), **{'@submit': 'submit{}'.format(form.component_studly)})}
% else:
${h.form(request.current_route_url(), class_='autodisable')}
% endif
${h.csrf_token(request)} ${h.csrf_token(request)}
<section> <section>
@ -75,53 +31,33 @@
${render_deform_field(form, dform['notes'])} ${render_deform_field(form, dform['notes'])}
% for key, pform in six.iteritems(params_forms): % for key, pform in six.iteritems(params_forms):
% if use_buefy: <div v-show="field_model_batch_type == '${key}'">
<div v-show="field_model_batch_type == '${key}'"> % for field in pform.make_deform_form():
% for field in pform.make_deform_form(): ${render_deform_field(pform, field)}
${render_deform_field(pform, field)} % endfor
% endfor </div>
</div>
% else:
<div class="params-wrapper ${key}">
## TODO: hacky to use deform? at least is explicit..
% for field in pform.make_deform_form():
${render_deform_field(pform, field)}
% endfor
</div>
% endif
% endfor % endfor
</section> </section>
<br /> <br />
<div class="buttons"> <div class="buttons">
% if use_buefy: <b-button type="is-primary"
<b-button type="is-primary" native-type="submit"
native-type="submit" :disabled="${form.component_studly}Submitting">
:disabled="${form.component_studly}Submitting"> {{ ${form.component_studly}ButtonText }}
{{ ${form.component_studly}ButtonText }} </b-button>
</b-button> <b-button tag="a" href="${url('products')}">
<b-button tag="a" href="${url('products')}"> Cancel
Cancel </b-button>
</b-button>
% else:
${h.submit('make-batch', "Create Batch")}
${h.link_to("Cancel", url('products'), class_='button')}
% endif
</div> </div>
${h.end_form()} ${h.end_form()}
</%def> </%def>
<%def name="render_form()"> <%def name="render_form()">
% if use_buefy: <script type="text/x-template" id="${form.component}-template">
<script type="text/x-template" id="${form.component}-template"> ${self.render_form_innards()}
${self.render_form_innards()} </script>
</script>
% else:
<div class="form">
${self.render_form_innards()}
</div>
% endif
</%def> </%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">

View file

@ -1,133 +1,26 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/index.mako" /> <%inherit file="/master/index.mako" />
<%def name="extra_styles()">
${parent.extra_styles()}
% if not use_buefy:
<style type="text/css">
table.label-printing th {
font-weight: normal;
padding: 0px 0px 2px 4px;
text-align: left;
}
table.label-printing td {
padding: 0px 0px 0px 4px;
}
table.label-printing #label-quantity {
text-align: right;
width: 30px;
}
div.grid table tbody td.size,
div.grid table tbody td.regular_price_uuid,
div.grid table tbody td.current_price_uuid {
padding-right: 6px;
text-align: right;
}
div.grid table tbody td.labels {
text-align: center;
}
</style>
% endif
</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and label_profiles and master.has_perm('print_labels'):
<script type="text/javascript">
$(function() {
$('.grid-wrapper .grid-header .tools select').selectmenu();
$('.grid-wrapper').on('click', 'a.print_label', function() {
var tr = $(this).parents('tr:first');
var quantity = $('table.label-printing #label-quantity');
if (isNaN(quantity.val())) {
alert("You must provide a valid label quantity.");
quantity.select();
quantity.focus();
} else {
quantity = quantity.val();
var threshold = ${json.dumps(quick_label_speedbump_threshold)|n};
if (threshold && parseInt(quantity) >= threshold) {
if (!confirm("Are you sure you want to print " + quantity + " labels?")) {
return false;
}
}
var data = {
product: tr.data('uuid'),
profile: $('#label-profile').val(),
quantity: quantity
};
$.get('${url('products.print_labels')}', data, function(data) {
if (data.error) {
alert("An error occurred while attempting to print:\n\n" + data.error);
} else if (quantity == '1') {
alert("1 label has been printed.");
} else {
alert(quantity + " labels have been printed.");
}
});
}
return false;
});
});
</script>
% endif
</%def>
<%def name="grid_tools()"> <%def name="grid_tools()">
${parent.grid_tools()} ${parent.grid_tools()}
% if label_profiles and master.has_perm('print_labels'): % if label_profiles and master.has_perm('print_labels'):
% if use_buefy: <b-field grouped>
<b-field grouped> <b-field label="Label">
<b-field label="Label"> <b-select v-model="quickLabelProfile">
<b-select v-model="quickLabelProfile"> % for profile in label_profiles:
% for profile in label_profiles: <option value="${profile.uuid}">
<option value="${profile.uuid}"> ${profile.description}
${profile.description} </option>
</option> % endfor
% endfor </b-select>
</b-select> </b-field>
</b-field> <b-field label="Qty.">
<b-field label="Qty."> <b-input v-model="quickLabelQuantity"
<b-input v-model="quickLabelQuantity" ref="quickLabelQuantityInput"
ref="quickLabelQuantityInput" style="width: 4rem;">
style="width: 4rem;"> </b-input>
</b-input> </b-field>
</b-field> </b-field>
</b-field>
% else:
<table class="label-printing">
<thead>
<tr>
<th>Label</th>
<th>Qty.</th>
</tr>
</thead>
<tbody>
<td>
<select name="label-profile" id="label-profile">
% for profile in label_profiles:
<option value="${profile.uuid}">${profile.description}</option>
% endfor
</select>
</td>
<td>
<input type="text" name="label-quantity" id="label-quantity" value="1" />
</td>
</tbody>
</table>
% endif
% endif % endif
</%def> </%def>

View file

@ -1,94 +1,16 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<script type="text/javascript">
function showPriceHistory(typ) {
var dialog = $('#' + typ + '-price-history-dialog');
dialog.dialog({
title: typ[0].toUpperCase() + typ.slice(1) + " Price History",
width: 600,
height: 300,
modal: true,
buttons: [
{
text: "Close",
click: function() {
dialog.dialog('close');
}
}
]
});
}
function showCostHistory() {
var dialog = $('#cost-history-dialog');
dialog.dialog({
title: "Cost History",
width: 600,
height: 300,
modal: true,
buttons: [
{
text: "Close",
click: function() {
dialog.dialog('close');
}
}
]
});
}
$(function() {
$('#view-regular-price-history').on('click', function() {
showPriceHistory('regular');
return false;
});
$('#view-current-price-history').on('click', function() {
showPriceHistory('current');
return false;
});
$('#view-suggested-price-history').on('click', function() {
showPriceHistory('suggested');
return false;
});
$('#view-cost-history').on('click', function() {
showCostHistory();
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
<style type="text/css"> <style type="text/css">
% if use_buefy: #main-product-panel {
#main-product-panel { margin-right: 2em;
margin-right: 2em; margin-top: 1em;
margin-top: 1em; }
} #pricing-panel .field-wrapper .field {
#pricing-panel .field-wrapper .field { white-space: nowrap;
white-space: nowrap; }
}
% else:
.price-history-dialog {
display: none;
}
.price-history-dialog .grid {
color: black;
}
% endif
</style> </style>
</%def> </%def>
@ -100,37 +22,22 @@
</%def> </%def>
<%def name="left_column()"> <%def name="left_column()">
% if use_buefy: <nav class="panel" id="pricing-panel">
<nav class="panel" id="pricing-panel"> <p class="panel-heading">Pricing</p>
<p class="panel-heading">Pricing</p> <div class="panel-block">
<div class="panel-block"> <div>
<div> ${self.render_price_fields(form)}
${self.render_price_fields(form)} </div>
</div>
</div>
</nav>
<nav class="panel">
<p class="panel-heading">Flags</p>
<div class="panel-block">
<div>
${self.render_flag_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Pricing</h2>
<div class="panel-body">
${self.render_price_fields(form)}
</div> </div>
</div> </nav>
<div class="panel"> <nav class="panel">
<h2>Flags</h2> <p class="panel-heading">Flags</p>
<div class="panel-body"> <div class="panel-block">
${self.render_flag_fields(form)} <div>
${self.render_flag_fields(form)}
</div>
</div> </div>
</div> </nav>
% endif
${self.extra_left_panels()} ${self.extra_left_panels()}
</%def> </%def>
@ -147,23 +54,14 @@
<%def name="extra_main_fields(form)"></%def> <%def name="extra_main_fields(form)"></%def>
<%def name="organization_panel()"> <%def name="organization_panel()">
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Organization</p>
<p class="panel-heading">Organization</p> <div class="panel-block">
<div class="panel-block"> <div>
<div> ${self.render_organization_fields(form)}
${self.render_organization_fields(form)} </div>
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Organization</h2>
<div class="panel-body">
${self.render_organization_fields(form)}
</div> </div>
</div> </nav>
% endif
</%def> </%def>
<%def name="render_organization_fields(form)"> <%def name="render_organization_fields(form)">
@ -195,23 +93,14 @@
</%def> </%def>
<%def name="movement_panel()"> <%def name="movement_panel()">
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Movement</p>
<p class="panel-heading">Movement</p> <div class="panel-block">
<div class="panel-block"> <div>
<div> ${self.render_movement_fields(form)}
${self.render_movement_fields(form)} </div>
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Movement</h2>
<div class="panel-body">
${self.render_movement_fields(form)}
</div> </div>
</div> </nav>
% endif
</%def> </%def>
<%def name="render_movement_fields(form)"> <%def name="render_movement_fields(form)">
@ -219,9 +108,7 @@
</%def> </%def>
<%def name="lookup_codes_grid()"> <%def name="lookup_codes_grid()">
% if use_buefy: ${lookup_codes['grid'].render_buefy_table_element(data_prop='lookupCodesData')|n}
${lookup_codes['grid'].render_buefy_table_element(data_prop='lookupCodesData')|n}
% else:
<div class="grid full no-border"> <div class="grid full no-border">
<table> <table>
<thead> <thead>
@ -238,29 +125,19 @@
</tbody> </tbody>
</table> </table>
</div> </div>
% endif
</%def> </%def>
<%def name="lookup_codes_panel()"> <%def name="lookup_codes_panel()">
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Additional Lookup Codes</p>
<p class="panel-heading">Additional Lookup Codes</p> <div class="panel-block">
<div class="panel-block"> ${self.lookup_codes_grid()}
${self.lookup_codes_grid()} </div>
</div> </nav>
</nav>
% else:
<div class="panel-grid" id="product-codes">
<h2>Additional Lookup Codes</h2>
${self.lookup_codes_grid()}
</div>
% endif
</%def> </%def>
<%def name="sources_grid()"> <%def name="sources_grid()">
% if use_buefy: ${vendor_sources['grid'].render_buefy_table_element(data_prop='vendorSourcesData')|n}
${vendor_sources['grid'].render_buefy_table_element(data_prop='vendorSourcesData')|n}
% else:
<div class="grid full no-border"> <div class="grid full no-border">
<table> <table>
<thead> <thead>
@ -293,71 +170,40 @@
</tbody> </tbody>
</table> </table>
</div> </div>
% endif
</%def> </%def>
<%def name="sources_panel()"> <%def name="sources_panel()">
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">
<p class="panel-heading">
Vendor Sources
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<a href="#" @click.prevent="showCostHistory()">
(view cost history)
</a>
% endif
</p>
<div class="panel-block">
${self.sources_grid()}
</div>
</nav>
% else:
<div class="panel-grid" id="product-costs">
<h2>
Vendor Sources Vendor Sources
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'): % if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<a id="view-cost-history" href="#">(view cost history)</a> <a href="#" @click.prevent="showCostHistory()">
(view cost history)
</a>
% endif % endif
</h2> </p>
${self.sources_grid()} <div class="panel-block">
</div> ${self.sources_grid()}
% endif </div>
</nav>
</%def> </%def>
<%def name="notes_panel()"> <%def name="notes_panel()">
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Notes</p>
<p class="panel-heading">Notes</p> <div class="panel-block">
<div class="panel-block">
<div class="field">${form.render_field_readonly('notes')}</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Notes</h2>
<div class="panel-body">
<div class="field">${form.render_field_readonly('notes')}</div> <div class="field">${form.render_field_readonly('notes')}</div>
</div> </div>
</div> </nav>
% endif
</%def> </%def>
<%def name="ingredients_panel()"> <%def name="ingredients_panel()">
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Ingredients</p>
<p class="panel-heading">Ingredients</p> <div class="panel-block">
<div class="panel-block">
${form.render_field_readonly('ingredients')}
</div>
</nav>
% else:
<div class="panel">
<h2>Ingredients</h2>
<div class="panel-body">
${form.render_field_readonly('ingredients')} ${form.render_field_readonly('ingredients')}
</div> </div>
</div> </nav>
% endif
</%def> </%def>
<%def name="extra_left_panels()"></%def> <%def name="extra_left_panels()"></%def>
@ -366,7 +212,7 @@
<%def name="render_this_page()"> <%def name="render_this_page()">
${parent.render_this_page()} ${parent.render_this_page()}
% if use_buefy and request.rattail_config.versioning_enabled() and master.has_perm('versions'): % if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<b-modal :active.sync="showingPriceHistory_regular" <b-modal :active.sync="showingPriceHistory_regular"
has-modal-card> has-modal-card>
@ -447,83 +293,34 @@
</%def> </%def>
<%def name="page_content()"> <%def name="page_content()">
% if use_buefy:
<div style="display: flex; flex-direction: column;"> <div style="display: flex; flex-direction: column;">
<nav class="panel" id="main-product-panel"> <nav class="panel" id="main-product-panel">
<p class="panel-heading">Product</p> <p class="panel-heading">Product</p>
<div class="panel-block"> <div class="panel-block">
<div style="display: flex; justify-content: space-between; width: 100%;"> <div style="display: flex; justify-content: space-between; width: 100%;">
<div> <div>
${self.render_main_fields(form)} ${self.render_main_fields(form)}
</div>
<div>
% if image_url:
${h.image(image_url, "Product Image", id='product-image', width=150, height=150)}
% endif
</div>
</div>
</div>
</nav>
<div style="display: flex;">
<div class="panel-wrapper"> <!-- left column -->
${self.left_column()}
</div> <!-- left column -->
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div> <!-- right column -->
</div>
</div> </div>
<div>
% else: % if image_url:
## legacy / not buefy ${h.image(image_url, "Product Image", id='product-image', width=150, height=150)}
% endif
<div style="display: flex; flex-direction: column;">
<div class="panel" id="product-main">
<h2>Product</h2>
<div class="panel-body">
<div style="display: flex; justify-content: space-between;">
<div>
${self.render_main_fields(form)}
</div>
<div>
% if image_url:
${h.image(image_url, "Product Image", id='product-image', width=150, height=150)}
% endif
</div>
</div>
</div>
</div> </div>
<div style="display: flex;">
<div class="panel-wrapper"> <!-- left column -->
${self.left_column()}
</div> <!-- left column -->
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div> <!-- right column -->
</div>
</div> </div>
</div>
</nav>
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'): <div style="display: flex;">
<div class="price-history-dialog" id="regular-price-history-dialog"> <div class="panel-wrapper"> <!-- left column -->
${regular_price_history_grid.render_grid()|n} ${self.left_column()}
</div> </div> <!-- left column -->
<div class="price-history-dialog" id="current-price-history-dialog"> <div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${current_price_history_grid.render_grid()|n} ${self.right_column()}
</div> </div> <!-- right column -->
<div class="price-history-dialog" id="suggested-price-history-dialog"> </div>
${suggested_price_history_grid.render_grid()|n}
</div> </div>
<div class="price-history-dialog" id="cost-history-dialog">
${cost_history_grid.render_grid()|n}
</div>
% endif
% endif
% if buttons: % if buttons:
${buttons|n} ${buttons|n}

View file

@ -1,468 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/base.mako" />
<%def name="title()">Receiving Form (${batch.vendor})</%def>
<%def name="head_tags()">
${parent.head_tags()}
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
<script type="text/javascript">
function assert_quantity() {
if ($('#cases').val() && parseFloat($('#cases').val())) {
return true;
}
if ($('#units').val() && parseFloat($('#units').val())) {
return true;
}
alert("Please provide case and/or unit quantity");
$('#cases').select().focus();
return false;
}
function invalid_product(msg) {
$('#received-product-info p').text(msg);
$('#received-product-info img').hide();
$('#upc').focus().select();
$('.field-wrapper.cases input').prop('disabled', true);
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
}
function pretty_quantity(cases, units) {
if (cases && units) {
return cases + " cases, " + units + " units";
} else if (cases) {
return cases + " cases";
} else if (units) {
return units + " units";
}
return '';
}
function show_quantity(name, cases, units) {
var quantity = pretty_quantity(cases, units);
var field = $('.field-wrapper.quantity_' + name);
field.find('.field').text(quantity);
if (quantity || name == 'ordered') {
field.show();
} else {
field.hide();
}
}
$(function() {
$('#upc').keydown(function(event) {
if (key_allowed(event)) {
return true;
}
if (key_modifies(event)) {
$('#product').val('');
$('#received-product-info p').html("please ENTER a scancode");
$('#received-product-info img').hide();
$('#received-product-info .warning').hide();
$('.product-fields').hide();
$('.receiving-fields').hide();
$('.field-wrapper.cases input').prop('disabled', true);
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
return true;
}
// when user presses ENTER, do product lookup
if (event.which == 13) {
var upc = $(this).val();
var data = {'upc': upc};
$.get('${url('purchases.batch.receiving_lookup', uuid=batch.uuid)}', data, function(data) {
if (data.error) {
alert(data.error);
if (data.redirect) {
$('#receiving-form').mask("Redirecting...");
location.href = data.redirect;
}
} else if (data.product) {
$('#upc').val(data.product.upc_pretty);
$('#product').val(data.product.uuid);
$('#brand_name').val(data.product.brand_name);
$('#description').val(data.product.description);
$('#size').val(data.product.size);
$('#case_quantity').val(data.product.case_quantity);
$('#received-product-info p').text(data.product.full_description);
$('#received-product-info img').attr('src', data.product.image_url).show();
if (! data.product.uuid) {
// $('#received-product-info .warning.notfound').show();
$('.product-fields').show();
}
if (data.product.found_in_batch) {
show_quantity('ordered', data.product.cases_ordered, data.product.units_ordered);
show_quantity('received', data.product.cases_received, data.product.units_received);
show_quantity('damaged', data.product.cases_damaged, data.product.units_damaged);
show_quantity('expired', data.product.cases_expired, data.product.units_expired);
show_quantity('mispick', data.product.cases_mispick, data.product.units_mispick);
$('.receiving-fields').show();
} else {
$('#received-product-info .warning.notordered').show();
}
$('.field-wrapper.cases input').prop('disabled', false);
$('.field-wrapper.units input').prop('disabled', false);
$('.buttons button').button('enable');
$('#cases').focus().select();
} else if (data.upc) {
$('#upc').val(data.upc_pretty);
$('#received-product-info p').text("product not found in our system");
$('#received-product-info img').attr('src', data.image_url).show();
$('#product').val('');
$('#brand_name').val('');
$('#description').val('');
$('#size').val('');
$('#case_quantity').val('');
$('#received-product-info .warning.notfound').show();
$('.product-fields').show();
$('#brand_name').focus();
$('.field-wrapper.cases input').prop('disabled', false);
$('.field-wrapper.units input').prop('disabled', false);
$('.buttons button').button('enable');
} else {
invalid_product('product not found');
}
});
}
return false;
});
$('#received').click(function() {
if (! assert_quantity()) {
return;
}
$(this).button('disable').button('option', 'label', "Working...");
$('#mode').val('received');
$('#receiving-form').submit();
});
$('#damaged').click(function() {
if (! assert_quantity()) {
return;
}
$(this).button('disable').button('option', 'label', "Working...");
$('#mode').val('damaged');
$('#damaged-dialog').dialog({
title: "Damaged Product",
modal: true,
width: '500px',
buttons: [
{
text: "OK",
click: function() {
$('#damaged-dialog').dialog('close');
$('#receiving-form #trash').val($('#damaged-dialog #trash').is(':checked') ? '1' : '');
$('#receiving-form').submit();
}
},
{
text: "Cancel",
click: function() {
$('#damaged').button('option', 'label', "Damaged").button('enable');
$('#damaged-dialog').dialog('close');
}
}
]
});
});
$('#expiration input[type="date"]').datepicker();
$('#expired').click(function() {
if (! assert_quantity()) {
return;
}
$(this).button('disable').button('option', 'label', "Working...");
$('#mode').val('expired');
$('#expiration').dialog({
title: "Expired / Short Date",
modal: true,
width: '500px',
buttons: [
{
text: "OK",
click: function() {
$('#expiration').dialog('close');
$('#receiving-form #expiration_date').val(
$('#expiration input[type="date"]').val());
$('#receiving-form #trash').val($('#expiration #trash').is(':checked') ? '1' : '');
$('#receiving-form').submit();
}
},
{
text: "Cancel",
click: function() {
$('#expired').button('option', 'label', "Expired").button('enable');
$('#expiration').dialog('close');
}
}
]
});
});
$('#mispick').click(function() {
if (! assert_quantity()) {
return;
}
$(this).button('disable').button('option', 'label', "Working...");
$('#ordered-product').val('');
$('#ordered-product-textbox').val('');
$('#ordered-product-info p').html("please ENTER a scancode");
$('#ordered-product-info img').hide();
$('#mispick-dialog').dialog({
title: "Mispick - Ordered Product",
modal: true,
width: 400,
buttons: [
{
text: "OK",
click: function() {
if ($('#ordered-product-info .warning').is(':visible')) {
alert("You must choose a product which was ordered.");
$('#ordered-product-textbox').select().focus();
return;
}
$('#mispick-dialog').dialog('close');
$('#mode').val('mispick');
$('#receiving-form').submit();
}
},
{
text: "Cancel",
click: function() {
$('#mispick').button('option', 'label', "Mispick").button('enable');
$('#mispick-dialog').dialog('close');
}
}
]
});
});
$('#ordered-product-textbox').keydown(function(event) {
if (key_allowed(event)) {
return true;
}
if (key_modifies(event)) {
$('#ordered_product').val('');
$('#ordered-product-info p').html("please ENTER a scancode");
$('#ordered-product-info img').hide();
$('#ordered-product-info .warning').hide();
return true;
}
if (event.which == 13) {
var input = $(this);
var data = {upc: input.val()};
$.get('${url('purchases.batch.receiving_lookup', uuid=batch.uuid)}', data, function(data) {
if (data.error) {
alert(data.error);
if (data.redirect) {
$('#mispick-dialog').mask("Redirecting...");
location.href = data.redirect;
}
} else if (data.product) {
input.val(data.product.upc_pretty);
$('#ordered_product').val(data.product.uuid);
$('#ordered-product-info p').text(data.product.full_description);
$('#ordered-product-info img').attr('src', data.product.image_url).show();
if (data.product.found_in_batch) {
$('#ordered-product-info .warning').hide();
} else {
$('#ordered-product-info .warning').show();
}
} else {
$('#ordered-product-info p').text("product not found");
$('#ordered-product-info img').hide();
$('#ordered-product-info .warning').hide();
}
});
}
return false;
});
$('#receiving-form').submit(function() {
$(this).mask("Working...");
});
$('#upc').focus();
$('.field-wrapper.cases input').prop('disabled', true);
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
});
</script>
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">
.product-info {
margin-top: 0.5em;
text-align: center;
}
.product-info p {
margin-left: 0.5em;
}
.product-info .img-wrapper {
height: 150px;
margin: 0.5em 0;
}
#received-product-info .warning {
background: #f66;
display: none;
}
#mispick-dialog input[type="text"],
#ordered-product-info {
width: 320px;
}
#ordered-product-info .warning {
background: #f66;
display: none;
}
</style>
</%def>
<%def name="context_menu_items()">
<li>${h.link_to("Back to Purchase Batch", url('purchases.batch.view', uuid=batch.uuid))}</li>
</%def>
<ul id="context-menu">
${self.context_menu_items()}
</ul>
<div class="form-wrapper">
${form.begin(id='receiving-form')}
${form.csrf_token()}
${h.hidden('mode')}
${h.hidden('expiration_date')}
${h.hidden('trash')}
${h.hidden('ordered_product')}
<div class="field-wrapper">
<label for="upc">Receiving UPC</label>
<div class="field">
${h.hidden('product')}
<div>${h.text('upc', autocomplete='off')}</div>
<div id="received-product-info" class="product-info">
<p>please ENTER a scancode</p>
<div class="img-wrapper"><img /></div>
<div class="warning notfound">please confirm UPC and provide more details</div>
<div class="warning notordered">warning: product not found on current purchase</div>
</div>
</div>
</div>
<div class="product-fields" style="display: none;">
<div class="field-wrapper brand_name">
<label for="brand_name">Brand Name</label>
<div class="field">${h.text('brand_name')}</div>
</div>
<div class="field-wrapper description">
<label for="description">Description</label>
<div class="field">${h.text('description')}</div>
</div>
<div class="field-wrapper size">
<label for="size">Size</label>
<div class="field">${h.text('size')}</div>
</div>
<div class="field-wrapper case_quantity">
<label for="case_quantity">Units in Case</label>
<div class="field">${h.text('case_quantity')}</div>
</div>
</div>
<div class="receiving-fields" style="display: none;">
<div class="field-wrapper quantity_ordered">
<label for="quantity_ordered">Ordered</label>
<div class="field"></div>
</div>
<div class="field-wrapper quantity_received">
<label for="quantity_received">Received</label>
<div class="field"></div>
</div>
<div class="field-wrapper quantity_damaged">
<label for="quantity_damaged">Damaged</label>
<div class="field"></div>
</div>
<div class="field-wrapper quantity_expired">
<label for="quantity_expired">Expired</label>
<div class="field"></div>
</div>
<div class="field-wrapper quantity_mispick">
<label for="quantity_mispick">Mispick</label>
<div class="field"></div>
</div>
</div>
<div class="field-wrapper cases">
<label for="cases">Cases</label>
<div class="field">${h.text('cases', autocomplete='off')}</div>
</div>
<div class="field-wrapper units">
<label for="units">Units</label>
<div class="field">${h.text('units', autocomplete='off')}</div>
</div>
<div class="buttons">
<button type="button" id="received">Received</button>
<button type="button" id="damaged">Damaged</button>
<button type="button" id="expired">Expired</button>
<!-- <button type="button" id="mispick">Mispick</button> -->
</div>
${form.end()}
</div>
<div id="damaged-dialog" style="display: none;">
<div class="field-wrapper trash">${h.checkbox('trash', label="Product will be discarded and cannot be returned", checked=False)}</div>
</div>
<div id="expiration" style="display: none;">
<div class="field-wrapper expiration-date">
<label for="expiration-date">Expiration Date</label>
<div class="field">${h.text('expiration-date', type='date')}</div>
</div>
<div class="field-wrapper trash">${h.checkbox('trash', label="Product will be discarded and cannot be returned", checked=False)}</div>
</div>
<div id="mispick-dialog" style="display: none;">
<div>${h.text('ordered-product-textbox', autocomplete='off')}</div>
<div id="ordered-product-info" class="product-info">
<p>please ENTER a scancode</p>
<div class="img-wrapper"><img /></div>
<div class="warning">warning: product not found on current purchase</div>
</div>
</div>

View file

@ -1,80 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/batch/create.mako" /> <%inherit file="/batch/create.mako" />
<%def name="extra_javascript()"> ## TODO: deprecate / remove this
${parent.extra_javascript()}
% if not use_buefy:
${self.func_show_batch_type()}
<script type="text/javascript">
% if master.handler.allow_truck_dump_receiving():
var batch_vendor_map = ${json.dumps(batch_vendor_map)|n};
% endif
$(function() {
$('.batch_type select').on('selectmenuchange', function(event, ui) {
show_batch_type(ui.item.value);
});
$('.truck_dump_batch_uuid select').on('selectmenuchange', function(event, ui) {
var form = $(this).parents('form');
var uuid = ui.item.value ? batch_vendor_map[ui.item.value] : '';
form.find('input[name="vendor_uuid"]').val(uuid);
});
show_batch_type();
});
</script>
% endif
</%def>
<%def name="func_show_batch_type()">
<script type="text/javascript">
function show_batch_type(batch_type) {
if (batch_type === undefined) {
batch_type = $('.field-wrapper.batch_type select').val();
}
if (batch_type == 'from_scratch') {
$('.field-wrapper.truck_dump_batch_uuid').hide();
$('.field-wrapper.invoice_file').hide();
$('.field-wrapper.invoice_parser_key').hide();
$('.field-wrapper.vendor_uuid').show();
$('.field-wrapper.date_ordered').show();
$('.field-wrapper.date_received').show();
$('.field-wrapper.po_number').show();
$('.field-wrapper.invoice_date').show();
$('.field-wrapper.invoice_number').show();
} else if (batch_type == 'truck_dump_children_first') {
$('.field-wrapper.truck_dump_batch_uuid').hide();
$('.field-wrapper.invoice_file').hide();
$('.field-wrapper.invoice_parser_key').hide();
$('.field-wrapper.vendor_uuid').show();
$('.field-wrapper.date_ordered').hide();
$('.field-wrapper.date_received').show();
$('.field-wrapper.po_number').hide();
$('.field-wrapper.invoice_date').hide();
$('.field-wrapper.invoice_number').hide();
} else if (batch_type == 'truck_dump_children_last') {
$('.field-wrapper.truck_dump_batch_uuid').hide();
$('.field-wrapper.invoice_file').hide();
$('.field-wrapper.invoice_parser_key').hide();
$('.field-wrapper.vendor_uuid').show();
$('.field-wrapper.date_ordered').hide();
$('.field-wrapper.date_received').show();
$('.field-wrapper.po_number').hide();
$('.field-wrapper.invoice_date').hide();
$('.field-wrapper.invoice_number').hide();
}
}
</script>
</%def>
${parent.body()} ${parent.body()}

View file

@ -11,35 +11,6 @@
% endif % endif
</%def> </%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
function toggleFields(creditType) {
if (creditType === undefined) {
creditType = $('select[name="credit_type"]').val();
}
if (creditType == 'expired') {
$('.field-wrapper.expiration_date').show();
} else {
$('.field-wrapper.expiration_date').hide();
}
}
$(function() {
toggleFields();
$('select[name="credit_type"]').on('selectmenuchange', function(event, ui) {
toggleFields(ui.item.value);
});
});
</script>
% endif
</%def>
<%def name="render_buefy_form()"> <%def name="render_buefy_form()">
<p class="block"> <p class="block">
@ -75,30 +46,7 @@
</%def> </%def>
<%def name="render_form()"> <%def name="render_form()">
% if use_buefy: ${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
% else:
<p style="padding: 1em;">
Please select the "state" of the product, and enter the appropriate
quantity.
</p>
<p style="padding: 1em;">
Note that this tool will <strong>deduct</strong> from the "received"
quantity, and <strong>add</strong> to the corresponding credit quantity.
</p>
<p style="padding: 1em;">
Please see ${h.link_to("Receive Row", url('{}.receive_row'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid))}
if you need to "receive" instead of "convert" the product.
</p>
${parent.render_form()}
% endif
</%def> </%def>

View file

@ -11,35 +11,6 @@
% endif % endif
</%def> </%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
function toggleFields(mode) {
if (mode === undefined) {
mode = $('select[name="mode"]').val();
}
if (mode == 'expired') {
$('.field-wrapper.expiration_date').show();
} else {
$('.field-wrapper.expiration_date').hide();
}
}
$(function() {
toggleFields();
$('select[name="mode"]').on('selectmenuchange', function(event, ui) {
toggleFields(ui.item.value);
});
});
</script>
% endif
</%def>
<%def name="render_buefy_form()"> <%def name="render_buefy_form()">
<p class="block"> <p class="block">
@ -72,30 +43,7 @@
</%def> </%def>
<%def name="render_form()"> <%def name="render_form()">
% if use_buefy: ${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
% else:
<p style="padding: 1em;">
Please select the "state" of the product, and enter the appropriate
quantity.
</p>
<p style="padding: 1em;">
Note that this tool will <strong>add</strong> the corresponding
quantities for the row.
</p>
<p style="padding: 1em;">
Please see ${h.link_to("Declare Credit", url('{}.declare_credit'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid))}
if you need to "convert" some already-received amount, into a credit.
</p>
${parent.render_form()}
% endif
</%def> </%def>

View file

@ -1,311 +1,32 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/batch/view.mako" /> <%inherit file="/batch/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and master.has_perm('edit_row'):
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
<script type="text/javascript">
% if not batch.executed:
// keep track of which cost value is currently being edited
var editing_catalog_cost = null;
var editing_invoice_cost = null;
function start_editing(td) {
var value = null;
var text = td.text().replace(/^\s+|\s+$/g, '');
if (text) {
td.data('previous-value', text);
td.text('');
value = parseFloat(text.replace('$', ''));
}
var input = $('<input type="text" />');
td.append(input);
value = value ? value.toString() : '';
input.val(value).select().focus();
}
function start_editing_catalog_cost(td) {
start_editing(td);
editing_catalog_cost = td;
}
function start_editing_invoice_cost(td) {
start_editing(td);
editing_invoice_cost = td;
}
function start_editing_next_catalog_cost() {
var tr = editing_catalog_cost.parents('tr:first');
var next = tr.next('tr:first');
if (next.length) {
start_editing_catalog_cost(next.find('td.catalog_unit_cost'));
} else {
editing_catalog_cost = null;
}
}
function start_editing_next_invoice_cost() {
var tr = editing_invoice_cost.parents('tr:first');
var next = tr.next('tr:first');
if (next.length) {
start_editing_invoice_cost(next.find('td.invoice_unit_cost'));
} else {
editing_invoice_cost = null;
}
}
function cancel_edit(td) {
var input = td.find('input');
input.blur();
input.remove();
var value = td.data('previous-value');
if (value) {
td.text(value);
}
}
function cancel_edit_catalog_cost() {
cancel_edit(editing_catalog_cost);
editing_catalog_cost = null;
}
function cancel_edit_invoice_cost() {
cancel_edit(editing_invoice_cost);
editing_invoice_cost = null;
}
% endif
$(function() {
% if not batch.executed:
$('.grid-wrapper').on('click', '.grid td.catalog_unit_cost', function() {
if (editing_catalog_cost) {
editing_catalog_cost.find('input').focus();
return
}
if (editing_invoice_cost) {
editing_invoice_cost.find('input').focus();
return
}
var td = $(this);
start_editing_catalog_cost(td);
});
$('.grid-wrapper').on('click', '.grid td.invoice_unit_cost', function() {
if (editing_invoice_cost) {
editing_invoice_cost.find('input').focus();
return
}
if (editing_catalog_cost) {
editing_catalog_cost.find('input').focus();
return
}
var td = $(this);
start_editing_invoice_cost(td);
});
$('.grid-wrapper').on('keyup', '.grid td.catalog_unit_cost input', function(event) {
var input = $(this);
// let numeric keys modify input value
if (! key_modifies(event)) {
// when user presses Enter while editing cost value, submit
// value to server for immediate persistence
if (event.which == 13) {
$('.grid-wrapper').mask("Updating cost...");
var url = '${url('receiving.update_row_cost', uuid=batch.uuid)}';
var td = input.parents('td:first');
var tr = td.parents('tr:first');
var data = {
'_csrf': $('[name="_csrf"]').val(),
'row_uuid': tr.data('uuid'),
'catalog_unit_cost': input.val()
};
$.post(url, data, function(data) {
if (data.error) {
alert(data.error);
} else {
var total = null;
// update catalog cost for row
td.text(data.row.catalog_unit_cost);
// mark cost as confirmed
if (data.row.catalog_cost_confirmed) {
tr.addClass('catalog_cost_confirmed');
}
input.blur();
input.remove();
start_editing_next_catalog_cost();
}
$('.grid-wrapper').unmask();
});
// When user presses Escape while editing totals, cancel the edit.
} else if (event.which == 27) {
cancel_edit_catalog_cost();
// Most other keys at this point should be unwanted...
} else if (! key_allowed(event)) {
return false;
}
}
});
$('.grid-wrapper').on('keyup', '.grid td.invoice_unit_cost input', function(event) {
var input = $(this);
// let numeric keys modify input value
if (! key_modifies(event)) {
// when user presses Enter while editing cost value, submit
// value to server for immediate persistence
if (event.which == 13) {
$('.grid-wrapper').mask("Updating cost...");
var url = '${url('receiving.update_row_cost', uuid=batch.uuid)}';
var td = input.parents('td:first');
var tr = td.parents('tr:first');
var data = {
'_csrf': $('[name="_csrf"]').val(),
'row_uuid': tr.data('uuid'),
'invoice_unit_cost': input.val()
};
$.post(url, data, function(data) {
if (data.error) {
alert(data.error);
} else {
var total = null;
// update unit cost for row
td.text(data.row.invoice_unit_cost);
// update invoice total for row
total = tr.find('td.invoice_total_calculated');
total.text('$' + data.row.invoice_total_calculated);
// update invoice total for batch
total = $('.form .field-wrapper.invoice_total_calculated .field');
total.text('$' + data.batch.invoice_total_calculated);
// mark cost as confirmed
if (data.row.invoice_cost_confirmed) {
tr.addClass('invoice_cost_confirmed');
}
input.blur();
input.remove();
start_editing_next_invoice_cost();
}
$('.grid-wrapper').unmask();
});
// When user presses Escape while editing totals, cancel the edit.
} else if (event.which == 27) {
cancel_edit_invoice_cost();
// Most other keys at this point should be unwanted...
} else if (! key_allowed(event)) {
return false;
}
}
});
% endif
$('.grid-wrapper').on('click', '.grid .actions a.transform', function() {
var form = $('form[name="transform-unit-form"]');
var row_uuid = $(this).parents('tr:first').data('uuid');
form.find('[name="row_uuid"]').val(row_uuid);
$.get(form.attr('action'), {row_uuid: row_uuid}, function(data) {
if (typeof(data) == 'object') {
alert(data.error);
} else {
$('#transform-unit-dialog').html(data);
$('#transform-unit-dialog').dialog({
title: "Transform Pack to Unit Item",
width: 800,
height: 450,
modal: true,
buttons: [
{
text: "Transform",
click: function(event) {
disable_button(dialog_button(event));
form.submit();
}
},
{
text: "Cancel",
click: function() {
$(this).dialog('close');
}
}
]
});
}
});
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
% if use_buefy: <style type="text/css">
<style type="text/css"> % if allow_edit_catalog_unit_cost:
% if allow_edit_catalog_unit_cost: td.c_catalog_unit_cost {
td.c_catalog_unit_cost { cursor: pointer;
cursor: pointer; background-color: #fcc;
background-color: #fcc;
}
tr.catalog_cost_confirmed td.c_catalog_unit_cost {
background-color: #cfc;
}
% endif
% if allow_edit_invoice_unit_cost:
td.c_invoice_unit_cost {
cursor: pointer;
background-color: #fcc;
}
tr.invoice_cost_confirmed td.c_invoice_unit_cost {
background-color: #cfc;
}
% endif
</style>
% elif not use_buefy and not batch.executed and master.has_perm('edit_row'):
<style type="text/css">
.grid tr:not(.header) td.catalog_unit_cost,
.grid tr:not(.header) td.invoice_unit_cost {
cursor: pointer;
background-color: #fcc;
} }
.grid tr.catalog_cost_confirmed:not(.header) td.catalog_unit_cost, tr.catalog_cost_confirmed td.c_catalog_unit_cost {
.grid tr.invoice_cost_confirmed:not(.header) td.invoice_unit_cost { background-color: #cfc;
background-color: #cfc;
} }
.grid td.catalog_unit_cost input, % endif
.grid td.invoice_unit_cost input { % if allow_edit_invoice_unit_cost:
width: 4rem; td.c_invoice_unit_cost {
cursor: pointer;
background-color: #fcc;
} }
</style> tr.invoice_cost_confirmed td.c_invoice_unit_cost {
% endif background-color: #cfc;
}
% endif
</style>
</%def> </%def>
<%def name="render_po_vs_invoice_helper()"> <%def name="render_po_vs_invoice_helper()">
% if use_buefy and master.handler.has_purchase_order(batch) and master.handler.has_invoice_file(batch): % if master.handler.has_purchase_order(batch) and master.handler.has_invoice_file(batch):
<div class="object-helper"> <div class="object-helper">
<h3>PO vs. Invoice</h3> <h3>PO vs. Invoice</h3>
<div class="object-helper-content"> <div class="object-helper-content">
@ -321,60 +42,51 @@
<div class="object-helper"> <div class="object-helper">
<h3>Tools</h3> <h3>Tools</h3>
<div class="object-helper-content"> <div class="object-helper-content">
% if use_buefy: <b-button type="is-primary"
<b-button type="is-primary" @click="autoReceiveShowDialog = true"
@click="autoReceiveShowDialog = true" icon-pack="fas"
icon-pack="fas" icon-left="check">
icon-left="check"> Auto-Receive All Items
Auto-Receive All Items </b-button>
</b-button>
% else:
${h.form(url('{}.auto_receive'.format(route_prefix), uuid=batch.uuid), class_='autodisable')}
${h.csrf_token(request)}
${h.submit('submit', "Auto-Receive All Items")}
${h.end_form()}
% endif
</div> </div>
</div> </div>
% if use_buefy: <b-modal has-modal-card
<b-modal has-modal-card :active.sync="autoReceiveShowDialog">
:active.sync="autoReceiveShowDialog"> <div class="modal-card">
<div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
<p class="modal-card-title">Auto-Receive All Items</p> <p class="modal-card-title">Auto-Receive All Items</p>
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
<p class="block"> <p class="block">
You can automatically set the "received" quantity to You can automatically set the "received" quantity to
match the "shipped" quantity for all items, based on match the "shipped" quantity for all items, based on
the invoice. the invoice.
</p> </p>
<p class="block"> <p class="block">
Would you like to do so? Would you like to do so?
</p> </p>
</section> </section>
<footer class="modal-card-foot"> <footer class="modal-card-foot">
<b-button @click="autoReceiveShowDialog = false"> <b-button @click="autoReceiveShowDialog = false">
Cancel Cancel
</b-button> </b-button>
${h.form(url('{}.auto_receive'.format(route_prefix), uuid=batch.uuid), **{'@submit': 'autoReceiveSubmitting = true'})} ${h.form(url('{}.auto_receive'.format(route_prefix), uuid=batch.uuid), **{'@submit': 'autoReceiveSubmitting = true'})}
${h.csrf_token(request)} ${h.csrf_token(request)}
<b-button type="is-primary" <b-button type="is-primary"
native-type="submit" native-type="submit"
:disabled="autoReceiveSubmitting" :disabled="autoReceiveSubmitting"
icon-pack="fas" icon-pack="fas"
icon-left="check"> icon-left="check">
{{ autoReceiveSubmitting ? "Working, please wait..." : "Auto-Receive All Items" }} {{ autoReceiveSubmitting ? "Working, please wait..." : "Auto-Receive All Items" }}
</b-button> </b-button>
${h.end_form()} ${h.end_form()}
</footer> </footer>
</div> </div>
</b-modal> </b-modal>
% endif
% endif % endif
</%def> </%def>
@ -607,14 +319,3 @@
${parent.body()} ${parent.body()}
% if not use_buefy and master.handler.allow_truck_dump_receiving() and master.has_perm('edit_row'):
${h.form(url('{}.transform_unit_row'.format(route_prefix), uuid=batch.uuid), name='transform-unit-form')}
${h.csrf_token(request)}
${h.hidden('row_uuid')}
${h.end_form()}
<div id="transform-unit-dialog" style="display: none;">
<p>hello world</p>
</div>
% endif

View file

@ -4,479 +4,456 @@
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
<style type="text/css"> <style type="text/css">
% if use_buefy:
nav.panel { nav.panel {
margin: 0.5rem; margin: 0.5rem;
} }
.header-fields { .header-fields {
margin-top: 1rem; margin-top: 1rem;
} }
.header-fields .field.is-horizontal { .header-fields .field.is-horizontal {
margin-left: 3rem; margin-left: 3rem;
} }
.header-fields .field.is-horizontal .field-label .label { .header-fields .field.is-horizontal .field-label .label {
white-space: nowrap; white-space: nowrap;
} }
.quantity-form-fields { .quantity-form-fields {
margin: 2rem; margin: 2rem;
} }
.quantity-form-fields .field.is-horizontal .field-label .label { .quantity-form-fields .field.is-horizontal .field-label .label {
text-align: left; text-align: left;
width: 8rem; width: 8rem;
} }
.remove-credit .field.is-horizontal .field-label .label { .remove-credit .field.is-horizontal .field-label .label {
white-space: nowrap; white-space: nowrap;
} }
% endif
</style> </style>
</%def> </%def>
<%def name="object_helpers()"> <%def name="page_content()">
${parent.object_helpers()}
% if not use_buefy and master.row_editable(row) and not batch.is_truck_dump_child(): <b-field grouped class="header-fields">
<div class="object-helper">
<h3>Receiving Tools</h3> <b-field label="Sequence" horizontal>
<div class="object-helper-content"> {{ rowData.sequence }}
<div style="white-space: nowrap;"> </b-field>
${h.link_to("Receive Product", url('{}.receive_row'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid), class_='button autodisable')}
${h.link_to("Declare Credit", url('{}.declare_credit'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid), class_='button autodisable')} <b-field label="Status" horizontal>
{{ rowData.status }}
</b-field>
<b-field label="Calculated Total" horizontal>
{{ rowData.invoice_total_calculated }}
</b-field>
</b-field>
<div style="display: flex;">
<nav class="panel">
<p class="panel-heading">Product</p>
<div class="panel-block">
<div style="display: flex;">
<div>
${form.render_field_readonly('item_entry')}
% if row.product:
${form.render_field_readonly(product_key_field)}
${form.render_field_readonly('product')}
% else:
${form.render_field_readonly(product_key_field)}
% if product_key_field != 'upc':
${form.render_field_readonly('upc')}
% endif
${form.render_field_readonly('brand_name')}
${form.render_field_readonly('description')}
${form.render_field_readonly('size')}
% endif
${form.render_field_readonly('vendor_code')}
${form.render_field_readonly('case_quantity')}
${form.render_field_readonly('catalog_unit_cost')}
</div> </div>
% if image_url:
<div class="is-pulled-right">
${h.image(image_url, "Product Image", width=150, height=150)}
</div>
% endif
</div> </div>
</div> </div>
% endif </nav>
</%def>
<%def name="page_content()"> <nav class="panel">
% if use_buefy: <p class="panel-heading">Quantities</p>
<div class="panel-block">
<b-field grouped class="header-fields"> <div>
<div class="quantity-form-fields">
<b-field label="Sequence" horizontal>
{{ rowData.sequence }}
</b-field>
<b-field label="Status" horizontal>
{{ rowData.status }}
</b-field>
<b-field label="Calculated Total" horizontal>
{{ rowData.invoice_total_calculated }}
</b-field>
</b-field>
<div style="display: flex;">
<nav class="panel">
<p class="panel-heading">Product</p>
<div class="panel-block">
<div style="display: flex;">
<div>
${form.render_field_readonly('item_entry')}
% if row.product:
${form.render_field_readonly(product_key_field)}
${form.render_field_readonly('product')}
% else:
${form.render_field_readonly(product_key_field)}
% if product_key_field != 'upc':
${form.render_field_readonly('upc')}
% endif
${form.render_field_readonly('brand_name')}
${form.render_field_readonly('description')}
${form.render_field_readonly('size')}
% endif
${form.render_field_readonly('vendor_code')}
${form.render_field_readonly('case_quantity')}
${form.render_field_readonly('catalog_unit_cost')}
</div>
% if image_url:
<div class="is-pulled-right">
${h.image(image_url, "Product Image", width=150, height=150)}
</div>
% endif
</div>
</div>
</nav>
<nav class="panel">
<p class="panel-heading">Quantities</p>
<div class="panel-block">
<div>
<div class="quantity-form-fields">
<b-field label="Ordered" horizontal>
{{ rowData.ordered }}
</b-field>
<hr />
<b-field label="Shipped" horizontal>
{{ rowData.shipped }}
</b-field>
<hr />
<b-field label="Received" horizontal
v-if="rowData.received">
{{ rowData.received }}
</b-field>
<b-field label="Damaged" horizontal
v-if="rowData.damaged">
{{ rowData.damaged }}
</b-field>
<b-field label="Expired" horizontal
v-if="rowData.expired">
{{ rowData.expired }}
</b-field>
<b-field label="Mispick" horizontal
v-if="rowData.mispick">
{{ rowData.mispick }}
</b-field>
<b-field label="Missing" horizontal
v-if="rowData.missing">
{{ rowData.missing }}
</b-field>
</div>
% if master.has_perm('edit_row') and master.row_editable(row):
<div class="buttons">
<b-button type="is-primary"
@click="accountForProductInit()"
icon-pack="fas"
icon-left="check">
Account for Product
</b-button>
<b-button type="is-warning"
@click="declareCreditInit()"
:disabled="!rowData.received"
icon-pack="fas"
icon-left="thumbs-down">
Declare Credit
</b-button>
</div>
% endif
</div>
</div>
</nav>
</div>
<b-modal has-modal-card
:active.sync="accountForProductShowDialog">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Account for Product</p>
</header>
<section class="modal-card-body">
<p class="block">
This is for declaring that you have encountered some
amount of the product.&nbsp; Ideally you will just
"receive" it normally, but you can indicate a "credit"
state if there is something amiss.
</p>
<b-field grouped>
% if allow_cases:
<b-field label="Case Qty.">
<span class="control">
{{ rowData.case_quantity }}
</span>
</b-field>
<span class="control">
&nbsp;
</span>
% endif
<b-field label="Product State"
:type="accountForProductMode ? null : 'is-danger'">
<b-select v-model="accountForProductMode">
<option v-for="mode in possibleReceivingModes"
:key="mode"
:value="mode">
{{ mode }}
</option>
</b-select>
</b-field>
<b-field label="Expiration Date"
v-show="accountForProductMode == 'expired'"
:type="accountForProductExpiration ? null : 'is-danger'">
<tailbone-datepicker v-model="accountForProductExpiration">
</tailbone-datepicker>
</b-field>
<b-field label="Ordered" horizontal>
{{ rowData.ordered }}
</b-field> </b-field>
<div class="level"> <hr />
<div class="level-left">
<div class="level-item"> <b-field label="Shipped" horizontal>
<numeric-input v-model="accountForProductQuantity" {{ rowData.shipped }}
ref="accountForProductQuantityInput"> </b-field>
</numeric-input>
</div>
<div class="level-item"> <hr />
% if allow_cases:
<b-field>
<b-radio-button v-model="accountForProductUOM"
@click.native="accountForProductUOMClicked('units')"
native-value="units">
Units
</b-radio-button>
<b-radio-button v-model="accountForProductUOM"
@click.native="accountForProductUOMClicked('cases')"
native-value="cases">
Cases
</b-radio-button>
</b-field>
% else:
<b-field>
<input type="hidden" v-model="accountForProductUOM" />
Units
</b-field>
% endif
</div>
% if allow_cases: <b-field label="Received" horizontal
<div class="level-item" v-if="rowData.received">
v-if="accountForProductUOM == 'cases' && accountForProductQuantity"> {{ rowData.received }}
= {{ accountForProductTotalUnits }} </b-field>
</div>
% endif
<b-field label="Damaged" horizontal
v-if="rowData.damaged">
{{ rowData.damaged }}
</b-field>
<b-field label="Expired" horizontal
v-if="rowData.expired">
{{ rowData.expired }}
</b-field>
<b-field label="Mispick" horizontal
v-if="rowData.mispick">
{{ rowData.mispick }}
</b-field>
<b-field label="Missing" horizontal
v-if="rowData.missing">
{{ rowData.missing }}
</b-field>
</div>
% if master.has_perm('edit_row') and master.row_editable(row):
<div class="buttons">
<b-button type="is-primary"
@click="accountForProductInit()"
icon-pack="fas"
icon-left="check">
Account for Product
</b-button>
<b-button type="is-warning"
@click="declareCreditInit()"
:disabled="!rowData.received"
icon-pack="fas"
icon-left="thumbs-down">
Declare Credit
</b-button>
</div> </div>
</div> % endif
</section>
<footer class="modal-card-foot">
<b-button @click="accountForProductShowDialog = false">
Cancel
</b-button>
<b-button type="is-primary"
@click="accountForProductSubmit()"
:disabled="accountForProductSubmitDisabled"
icon-pack="fas"
icon-left="check">
{{ accountForProductSubmitting ? "Working, please wait..." : "Account for Product" }}
</b-button>
</footer>
</div> </div>
</b-modal> </div>
</nav>
<b-modal has-modal-card </div>
:active.sync="declareCreditShowDialog">
<div class="modal-card">
<header class="modal-card-head"> <b-modal has-modal-card
<p class="modal-card-title">Declare Credit</p> :active.sync="accountForProductShowDialog">
</header> <div class="modal-card">
<section class="modal-card-body"> <header class="modal-card-head">
<p class="modal-card-title">Account for Product</p>
</header>
<p class="block"> <section class="modal-card-body">
This is for <span class="is-italic">converting</span>
some amount you <span class="is-italic">already
received</span>, and now declaring there is something
wrong with it.
</p>
<b-field grouped> <p class="block">
This is for declaring that you have encountered some
amount of the product.&nbsp; Ideally you will just
"receive" it normally, but you can indicate a "credit"
state if there is something amiss.
</p>
<b-field label="Received"> <b-field grouped>
% if allow_cases:
<b-field label="Case Qty.">
<span class="control"> <span class="control">
{{ rowData.received }} {{ rowData.case_quantity }}
</span> </span>
</b-field> </b-field>
<span class="control"> <span class="control">
&nbsp; &nbsp;
</span> </span>
% endif
<b-field label="Credit Type" <b-field label="Product State"
:type="declareCreditType ? null : 'is-danger'"> :type="accountForProductMode ? null : 'is-danger'">
<b-select v-model="declareCreditType"> <b-select v-model="accountForProductMode">
<option v-for="typ in possibleCreditTypes" <option v-for="mode in possibleReceivingModes"
:key="typ" :key="mode"
:value="typ"> :value="mode">
{{ typ }} {{ mode }}
</option> </option>
</b-select> </b-select>
</b-field> </b-field>
<b-field label="Expiration Date" <b-field label="Expiration Date"
v-show="declareCreditType == 'expired'" v-show="accountForProductMode == 'expired'"
:type="declareCreditExpiration ? null : 'is-danger'"> :type="accountForProductExpiration ? null : 'is-danger'">
<tailbone-datepicker v-model="declareCreditExpiration"> <tailbone-datepicker v-model="accountForProductExpiration">
</tailbone-datepicker> </tailbone-datepicker>
</b-field> </b-field>
</b-field> </b-field>
<div class="level"> <div class="level">
<div class="level-left"> <div class="level-left">
<div class="level-item"> <div class="level-item">
<numeric-input v-model="declareCreditQuantity" <numeric-input v-model="accountForProductQuantity"
ref="declareCreditQuantityInput"> ref="accountForProductQuantityInput">
</numeric-input> </numeric-input>
</div>
<div class="level-item">
% if allow_cases:
<b-field>
<b-radio-button v-model="declareCreditUOM"
@click.native="declareCreditUOMClicked('units')"
native-value="units">
Units
</b-radio-button>
<b-radio-button v-model="declareCreditUOM"
@click.native="declareCreditUOMClicked('cases')"
native-value="cases">
Cases
</b-radio-button>
</b-field>
% else:
<b-field>
<input type="hidden" v-model="declareCreditUOM" />
Units
</b-field>
% endif
</div>
% if allow_cases:
<div class="level-item"
v-if="declareCreditUOM == 'cases' && declareCreditQuantity">
= {{ declareCreditTotalUnits }}
</div>
% endif
</div>
</div> </div>
</section> <div class="level-item">
% if allow_cases:
<b-field>
<b-radio-button v-model="accountForProductUOM"
@click.native="accountForProductUOMClicked('units')"
native-value="units">
Units
</b-radio-button>
<b-radio-button v-model="accountForProductUOM"
@click.native="accountForProductUOMClicked('cases')"
native-value="cases">
Cases
</b-radio-button>
</b-field>
% else:
<b-field>
<input type="hidden" v-model="accountForProductUOM" />
Units
</b-field>
% endif
</div>
<footer class="modal-card-foot"> % if allow_cases:
<b-button @click="declareCreditShowDialog = false"> <div class="level-item"
Cancel v-if="accountForProductUOM == 'cases' && accountForProductQuantity">
</b-button> = {{ accountForProductTotalUnits }}
<b-button type="is-warning" </div>
@click="declareCreditSubmit()" % endif
:disabled="declareCreditSubmitDisabled"
icon-pack="fas"
icon-left="thumbs-down">
{{ declareCreditSubmitting ? "Working, please wait..." : "Declare this Credit" }}
</b-button>
</footer>
</div>
</b-modal>
<nav class="panel" >
<p class="panel-heading">Credits</p>
<div class="panel-block">
<div>
${form.render_field_value('credits')}
</div> </div>
</div> </div>
</nav>
<b-modal has-modal-card </section>
:active.sync="removeCreditShowDialog">
<div class="modal-card remove-credit">
<header class="modal-card-head"> <footer class="modal-card-foot">
<p class="modal-card-title">Un-Declare Credit</p> <b-button @click="accountForProductShowDialog = false">
</header> Cancel
</b-button>
<b-button type="is-primary"
@click="accountForProductSubmit()"
:disabled="accountForProductSubmitDisabled"
icon-pack="fas"
icon-left="check">
{{ accountForProductSubmitting ? "Working, please wait..." : "Account for Product" }}
</b-button>
</footer>
</div>
</b-modal>
<section class="modal-card-body"> <b-modal has-modal-card
:active.sync="declareCreditShowDialog">
<div class="modal-card">
<p class="block"> <header class="modal-card-head">
If you un-declare this credit, the quantity below will <p class="modal-card-title">Declare Credit</p>
be added back to the </header>
<span class="has-text-weight-bold">Received</span> tally.
</p>
<b-field label="Credit Type" horizontal> <section class="modal-card-body">
{{ removeCreditRow.credit_type }}
</b-field>
<b-field label="Quantity" horizontal> <p class="block">
{{ removeCreditRow.shorted }} This is for <span class="is-italic">converting</span>
</b-field> some amount you <span class="is-italic">already
received</span>, and now declaring there is something
wrong with it.
</p>
</section> <b-field grouped>
<footer class="modal-card-foot"> <b-field label="Received">
<b-button @click="removeCreditShowDialog = false"> <span class="control">
Cancel {{ rowData.received }}
</b-button> </span>
<b-button type="is-danger" </b-field>
@click="removeCreditSubmit()"
:disabled="removeCreditSubmitting" <span class="control">
icon-pack="fas" &nbsp;
icon-left="trash"> </span>
{{ removeCreditSubmitting ? "Working, please wait..." : "Un-Declare this Credit" }}
</b-button> <b-field label="Credit Type"
</footer> :type="declareCreditType ? null : 'is-danger'">
<b-select v-model="declareCreditType">
<option v-for="typ in possibleCreditTypes"
:key="typ"
:value="typ">
{{ typ }}
</option>
</b-select>
</b-field>
<b-field label="Expiration Date"
v-show="declareCreditType == 'expired'"
:type="declareCreditExpiration ? null : 'is-danger'">
<tailbone-datepicker v-model="declareCreditExpiration">
</tailbone-datepicker>
</b-field>
</b-field>
<div class="level">
<div class="level-left">
<div class="level-item">
<numeric-input v-model="declareCreditQuantity"
ref="declareCreditQuantityInput">
</numeric-input>
</div>
<div class="level-item">
% if allow_cases:
<b-field>
<b-radio-button v-model="declareCreditUOM"
@click.native="declareCreditUOMClicked('units')"
native-value="units">
Units
</b-radio-button>
<b-radio-button v-model="declareCreditUOM"
@click.native="declareCreditUOMClicked('cases')"
native-value="cases">
Cases
</b-radio-button>
</b-field>
% else:
<b-field>
<input type="hidden" v-model="declareCreditUOM" />
Units
</b-field>
% endif
</div>
% if allow_cases:
<div class="level-item"
v-if="declareCreditUOM == 'cases' && declareCreditQuantity">
= {{ declareCreditTotalUnits }}
</div>
% endif
</div>
</div> </div>
</b-modal>
<div style="display: flex;"> </section>
% if master.batch_handler.has_purchase_order(batch): <footer class="modal-card-foot">
<nav class="panel" > <b-button @click="declareCreditShowDialog = false">
<p class="panel-heading">Purchase Order</p> Cancel
<div class="panel-block"> </b-button>
<div> <b-button type="is-warning"
${form.render_field_readonly('po_line_number')} @click="declareCreditSubmit()"
${form.render_field_readonly('po_unit_cost')} :disabled="declareCreditSubmitDisabled"
${form.render_field_readonly('po_case_size')} icon-pack="fas"
${form.render_field_readonly('po_total')} icon-left="thumbs-down">
</div> {{ declareCreditSubmitting ? "Working, please wait..." : "Declare this Credit" }}
</div> </b-button>
</nav> </footer>
% endif </div>
</b-modal>
% if master.batch_handler.has_invoice_file(batch):
<nav class="panel" >
<p class="panel-heading">Invoice</p>
<div class="panel-block">
<div>
${form.render_field_readonly('invoice_line_number')}
${form.render_field_readonly('invoice_unit_cost')}
${form.render_field_readonly('invoice_case_size')}
${form.render_field_readonly('invoice_total', label="Invoice Total")}
</div>
</div>
</nav>
% endif
<nav class="panel" >
<p class="panel-heading">Credits</p>
<div class="panel-block">
<div>
${form.render_field_value('credits')}
</div> </div>
</div>
</nav>
% else: <b-modal has-modal-card
## legacy / not buefy :active.sync="removeCreditShowDialog">
${parent.page_content()} <div class="modal-card remove-credit">
% endif
<header class="modal-card-head">
<p class="modal-card-title">Un-Declare Credit</p>
</header>
<section class="modal-card-body">
<p class="block">
If you un-declare this credit, the quantity below will
be added back to the
<span class="has-text-weight-bold">Received</span> tally.
</p>
<b-field label="Credit Type" horizontal>
{{ removeCreditRow.credit_type }}
</b-field>
<b-field label="Quantity" horizontal>
{{ removeCreditRow.shorted }}
</b-field>
</section>
<footer class="modal-card-foot">
<b-button @click="removeCreditShowDialog = false">
Cancel
</b-button>
<b-button type="is-danger"
@click="removeCreditSubmit()"
:disabled="removeCreditSubmitting"
icon-pack="fas"
icon-left="trash">
{{ removeCreditSubmitting ? "Working, please wait..." : "Un-Declare this Credit" }}
</b-button>
</footer>
</div>
</b-modal>
<div style="display: flex;">
% if master.batch_handler.has_purchase_order(batch):
<nav class="panel" >
<p class="panel-heading">Purchase Order</p>
<div class="panel-block">
<div>
${form.render_field_readonly('po_line_number')}
${form.render_field_readonly('po_unit_cost')}
${form.render_field_readonly('po_case_size')}
${form.render_field_readonly('po_total')}
</div>
</div>
</nav>
% endif
% if master.batch_handler.has_invoice_file(batch):
<nav class="panel" >
<p class="panel-heading">Invoice</p>
<div class="panel-block">
<div>
${form.render_field_readonly('invoice_line_number')}
${form.render_field_readonly('invoice_unit_cost')}
${form.render_field_readonly('invoice_case_size')}
${form.render_field_readonly('invoice_total', label="Invoice Total")}
</div>
</div>
</nav>
% endif
</div>
</%def> </%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">

View file

@ -1,47 +1,14 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/create.mako" /> <%inherit file="/master/create.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
var report_descriptions = ${json.dumps(report_descriptions)|n};
function show_description(key) {
var desc = report_descriptions[key];
$('#report-description').text(desc);
}
$(function() {
var report_type = $('select[name="report_type"]');
report_type.change(function(event) {
show_description(report_type.val());
});
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
<style type="text/css"> <style type="text/css">
% if use_form: % if use_form:
% if use_buefy: #report-description {
#report-description { margin-left: 2em;
margin-left: 2em; }
}
% else:
#report-description {
margin-top: 2em;
margin-left: 2em;
}
% endif
% else: % else:
.report-selection { .report-selection {
margin-left: 10em; margin-left: 10em;
@ -69,19 +36,7 @@
<%def name="page_content()"> <%def name="page_content()">
% if use_form: % if use_form:
% if use_buefy: ${parent.page_content()}
${parent.page_content()}
% else:
<div class="form-wrapper">
<p>Please select the type of report you wish to generate.</p>
<div style="display: flex;">
${form.render()|n}
<div id="report-description"></div>
</div>
</div><!-- form-wrapper -->
% endif
% else: % else:
<div> <div>
<br /> <br />

View file

@ -24,11 +24,5 @@
</div> </div>
</%def> </%def>
<%def name="render_form()">
% if not use_buefy:
<p style="padding: 1em;">${report.__doc__}</p>
% endif
${parent.render_form()}
</%def>
${parent.body()} ${parent.body()}

View file

@ -4,83 +4,47 @@
<%def name="title()">Report : Inventory Worksheet</%def> <%def name="title()">Report : Inventory Worksheet</%def>
<%def name="page_content()"> <%def name="page_content()">
% if use_buefy:
<p class="block"> <p class="block">
Please provide the following criteria to generate your report: Please provide the following criteria to generate your report:
</p> </p>
${h.form(request.current_route_url())} ${h.form(request.current_route_url())}
${h.csrf_token(request)} ${h.csrf_token(request)}
<b-field label="Department"> <b-field label="Department">
<b-select name="department"> <b-select name="department">
<option v-for="dept in departments" <option v-for="dept in departments"
:key="dept.uuid" :key="dept.uuid"
:value="dept.uuid"> :value="dept.uuid">
{{ dept.name }} {{ dept.name }}
</option> </option>
</b-select> </b-select>
</b-field> </b-field>
<b-field> <b-field>
<b-checkbox name="weighted-only" native-value="1"> <b-checkbox name="weighted-only" native-value="1">
Only include items which are sold by weight. Only include items which are sold by weight.
</b-checkbox> </b-checkbox>
</b-field> </b-field>
<b-field> <b-field>
<b-checkbox name="exclude-not-for-sale" :value="true" <b-checkbox name="exclude-not-for-sale" :value="true"
native-value="1"> native-value="1">
Exclude items marked "not for sale". Exclude items marked "not for sale".
</b-checkbox> </b-checkbox>
</b-field> </b-field>
<div class="buttons"> <div class="buttons">
<b-button type="is-primary" <b-button type="is-primary"
native-type="submit" native-type="submit"
icon-pack="fas" icon-pack="fas"
icon-left="arrow-circle-right"> icon-left="arrow-circle-right">
Generate Report Generate Report
</b-button> </b-button>
</div> </div>
${h.end_form()} ${h.end_form()}
% else:
<p>Please provide the following criteria to generate your report:</p>
<br />
${h.form(request.current_route_url())}
${h.csrf_token(request)}
<div class="field-wrapper">
<label for="department">Department</label>
<div class="field">
<select name="department">
% for department in departments:
<option value="${department.uuid}">${department.name}</option>
% endfor
</select>
</div>
</div>
<div class="field-wrapper">
${h.checkbox('weighted-only', label="Only include items which are sold by weight.")}
</div>
<div class="field-wrapper">
${h.checkbox('exclude-not-for-sale', label="Exclude items marked \"not for sale\".", checked=True)}
</div>
<div class="buttons">
${h.submit('submit', "Generate Report")}
</div>
${h.end_form()}
% endif
</%def> </%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">

View file

@ -6,24 +6,6 @@
${h.stylesheet_link(request.static_url('tailbone:static/css/perms.css'))} ${h.stylesheet_link(request.static_url('tailbone:static/css/perms.css'))}
</%def> </%def>
<%def name="page_content()">
${parent.page_content()}
% if not use_buefy:
<h2>Users</h2>
% if instance is guest_role:
<p>The guest role is implied for all anonymous users, i.e. when not logged in.</p>
% elif instance is authenticated_role:
<p>The authenticated role is implied for all users, but only when logged in.</p>
% elif users:
<p>The following users are assigned to this role:</p>
${users.render_grid()|n}
% else:
<p>There are no users assigned to this role.</p>
% endif
% endif
</%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()} ${parent.modify_this_page_vars()}
<script type="text/javascript"> <script type="text/javascript">

View file

@ -1,41 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
% if not email.get_template('html'):
$(function() {
$('#preview-html').button('disable');
$('#preview-html').attr('title', "There is no HTML template on file for this email.");
});
% endif
% if not email.get_template('txt'):
$(function() {
$('#preview-txt').button('disable');
$('#preview-txt').attr('title', "There is no TXT template on file for this email.");
});
% endif
</script>
% endif
</%def>
<%def name="render_form()">
${parent.render_form()}
% if not use_buefy:
${h.form(url('email.preview'), name='send-email-preview', class_='autodisable')}
${h.csrf_token(request)}
${h.hidden('email_key', value=instance['key'])}
${h.link_to("Preview HTML", '{}?key={}&type=html'.format(url('email.preview'), instance['key']), id='preview-html', class_='button', target='_blank')}
${h.link_to("Preview TXT", '{}?key={}&type=txt'.format(url('email.preview'), instance['key']), id='preview-txt', class_='button', target='_blank')}
or
${h.text('recipient', value=request.user.email_address or '')}
${h.submit('send_{}'.format(instance['key']), value="Send Preview Email")}
${h.end_form()}
% endif
</%def>
<%def name="render_buefy_form()"> <%def name="render_buefy_form()">
${parent.render_buefy_form()} ${parent.render_buefy_form()}
<email-preview-tools></email-preview-tools> <email-preview-tools></email-preview-tools>

View file

@ -1,20 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('#restart-client').click(function() {
disable_button(this);
location.href = '${url('tempmon.clients.restart', uuid=instance.uuid)}';
});
});
</script>
% endif
</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
${parent.context_menu_items()} ${parent.context_menu_items()}
% if request.has_perm('tempmon.appliances.dashboard'): % if request.has_perm('tempmon.appliances.dashboard'):
@ -27,14 +13,10 @@
<div class="object-helper"> <div class="object-helper">
<h3>Client Tools</h3> <h3>Client Tools</h3>
<div class="object-helper-content"> <div class="object-helper-content">
% if use_buefy: <once-button tag="a" href="${url('{}.restart'.format(route_prefix), uuid=instance.uuid)}"
<once-button tag="a" href="${url('{}.restart'.format(route_prefix), uuid=instance.uuid)}" type="is-primary"
type="is-primary" text="Restart tempmon-client daemon">
text="Restart tempmon-client daemon"> </once-button>
</once-button>
% else:
<button type="button" id="restart-client">Restart tempmon-client daemon</button>
% endif
</div> </div>
</div> </div>
% endif % endif

View file

@ -8,178 +8,54 @@
<%def name="extra_javascript()"> <%def name="extra_javascript()">
${parent.extra_javascript()} ${parent.extra_javascript()}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script>
% if not use_buefy:
<script type="text/javascript">
var contexts = {};
var charts = {};
function fetchReadings(appliance_uuid) {
if (appliance_uuid === undefined) {
appliance_uuid = $('#appliance_uuid').val();
}
$('.form-wrapper').mask("Fetching data");
if (Object.keys(charts).length) {
Object.keys(charts).forEach(function(key) {
charts[key].destroy();
delete charts[key];
});
}
var url = '${url("tempmon.dashboard.readings")}';
var params = {'appliance_uuid': appliance_uuid};
$.get(url, params, function(data) {
if (data.probes) {
data.probes.forEach(function(probe) {
charts[probe.uuid] = new Chart(contexts[probe.uuid], {
type: 'scatter',
data: {
datasets: [{
label: probe.description,
data: probe.readings
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {unit: 'minute'},
position: 'bottom'
}]
}
}
});
});
} else {
// TODO: should improve this
alert(data.error);
}
$('.form-wrapper').unmask();
});
}
$(function() {
% for probe in appliance.probes:
contexts['${probe.uuid}'] = $('#tempchart-${probe.uuid}');
% endfor
$('#appliance_uuid').selectmenu({
change: function(event, ui) {
$('.form-wrapper').mask("Fetching data");
$(this).parents('form').submit();
}
});
fetchReadings();
});
</script>
% endif
</%def> </%def>
<%def name="render_this_page()"> <%def name="render_this_page()">
% if use_buefy: ${h.form(request.current_route_url(), ref='applianceForm')}
${h.csrf_token(request)}
<div class="level-left">
${h.form(request.current_route_url(), ref='applianceForm')} <div class="level-item">
${h.csrf_token(request)} <b-field label="Appliance" horizontal>
<div class="level-left"> <b-select name="appliance_uuid"
v-model="applianceUUID"
<div class="level-item"> @input="$refs.applianceForm.submit()">
<b-field label="Appliance" horizontal> <option v-for="appliance in appliances"
<b-select name="appliance_uuid" :key="appliance.uuid"
v-model="applianceUUID" :value="appliance.uuid">
@input="$refs.applianceForm.submit()"> {{ appliance.name }}
<option v-for="appliance in appliances" </option>
:key="appliance.uuid" </b-select>
:value="appliance.uuid"> </b-field>
{{ appliance.name }}
</option>
</b-select>
</b-field>
</div>
% if appliance:
<div class="level-item">
<a href="${url('tempmon.appliances.view', uuid=appliance.uuid)}">
${h.image(url('tempmon.appliances.thumbnail', uuid=appliance.uuid), "")}
</a>
</div>
% endif
</div>
${h.end_form()}
% if appliance and appliance.probes:
% for probe in appliance.probes:
<h4 class="is-size-4">
Probe:&nbsp; ${h.link_to(probe.description, url('tempmon.probes.graph', uuid=probe.uuid))}
(status: ${enum.TEMPMON_PROBE_STATUS[probe.status]})
</h4>
% if probe.enabled:
<canvas ref="tempchart-${probe.uuid}" width="400" height="60"></canvas>
% else:
<p>This probe is not enabled.</p>
% endif
% endfor
% elif appliance:
<h3>This appliance has no probes configured!</h3>
% else:
<h3>Please choose an appliance.</h3>
% endif
% else:
## not buefy
<div style="display: flex;">
<div class="form-wrapper">
<div class="form">
${h.form(request.current_route_url())}
${h.csrf_token(request)}
% if use_buefy:
<b-field horizontal label="Appliance">
${appliance_select}
</b-field>
% else:
<div class="field-wrapper">
<label>Appliance</label>
<div class="field">
${appliance_select}
</div>
</div>
% endif
${h.end_form()}
</div>
</div> </div>
<a href="${url('tempmon.appliances.view', uuid=appliance.uuid)}"> % if appliance:
${h.image(url('tempmon.appliances.thumbnail', uuid=appliance.uuid), "")} <div class="level-item">
</a> <a href="${url('tempmon.appliances.view', uuid=appliance.uuid)}">
</div> ${h.image(url('tempmon.appliances.thumbnail', uuid=appliance.uuid), "")}
</a>
</div>
% endif
% if appliance.probes: </div>
${h.end_form()}
% if appliance and appliance.probes:
% for probe in appliance.probes: % for probe in appliance.probes:
<h3> <h4 class="is-size-4">
Probe:&nbsp; ${h.link_to(probe.description, url('tempmon.probes.graph', uuid=probe.uuid))} Probe:&nbsp; ${h.link_to(probe.description, url('tempmon.probes.graph', uuid=probe.uuid))}
(status: ${enum.TEMPMON_PROBE_STATUS[probe.status]}) (status: ${enum.TEMPMON_PROBE_STATUS[probe.status]})
</h3> </h4>
% if probe.enabled: % if probe.enabled:
% if use_buefy: <canvas ref="tempchart-${probe.uuid}" width="400" height="60"></canvas>
<canvas ref="tempchart" width="400" height="150"></canvas>
% else:
<canvas id="tempchart-${probe.uuid}" width="400" height="60"></canvas>
% endif
% else: % else:
<p>This probe is not enabled.</p> <p>This probe is not enabled.</p>
% endif % endif
% endfor % endfor
% else: % elif appliance:
<h3>This appliance has no probes configured!</h3> <h3>This appliance has no probes configured!</h3>
% endif % else:
<h3>Please choose an appliance.</h3>
% endif % endif
</%def> </%def>

View file

@ -6,71 +6,6 @@
<%def name="extra_javascript()"> <%def name="extra_javascript()">
${parent.extra_javascript()} ${parent.extra_javascript()}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script>
% if not use_buefy:
<script type="text/javascript">
var ctx = null;
var chart = null;
function fetchReadings(timeRange) {
if (timeRange === undefined) {
timeRange = $('#time-range').val();
}
var timeUnit;
if (timeRange == 'last hour') {
timeUnit = 'minute';
} else if (['last 6 hours', 'last day'].includes(timeRange)) {
timeUnit = 'hour';
} else {
timeUnit = 'day';
}
$('.form-wrapper').mask("Fetching data");
if (chart) {
chart.destroy();
}
$.get('${url('{}.graph_readings'.format(route_prefix), uuid=probe.uuid)}', {'time-range': timeRange}, function(data) {
chart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
label: "${probe.description}",
data: data
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {unit: timeUnit},
position: 'bottom'
}]
}
}
});
$('.form-wrapper').unmask();
});
}
$(function() {
ctx = $('#tempchart');
$('#time-range').selectmenu({
change: function(event, ui) {
fetchReadings(ui.item.value);
}
});
fetchReadings();
});
</script>
% endif
</%def> </%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
@ -89,50 +24,23 @@
<div class="form-wrapper"> <div class="form-wrapper">
<div class="form"> <div class="form">
% if use_buefy: <b-field horizontal label="Appliance">
<b-field horizontal label="Appliance"> <div>
<div> % if probe.appliance:
% if probe.appliance: <a href="${url('tempmon.appliances.view', uuid=probe.appliance.uuid)}">${probe.appliance}</a>
<a href="${url('tempmon.appliances.view', uuid=probe.appliance.uuid)}">${probe.appliance}</a> % endif
% endif </div>
</div> </b-field>
</b-field>
% else:
<div class="field-wrapper">
<label>Appliance</label>
<div class="field">
% if probe.appliance:
<a href="${url('tempmon.appliances.view', uuid=probe.appliance.uuid)}">${probe.appliance}</a>
% endif
</div>
</div>
% endif
% if use_buefy: <b-field horizontal label="Probe Location">
<b-field horizontal label="Probe Location"> <div>
<div> ${probe.location or ""}
${probe.location or ""} </div>
</div> </b-field>
</b-field>
% else:
<div class="field-wrapper">
<label>Probe Location</label>
<div class="field">${probe.location or ""}</div>
</div>
% endif
% if use_buefy: <b-field horizontal label="Showing">
<b-field horizontal label="Showing"> ${time_range}
${time_range} </b-field>
</b-field>
% else:
<div class="field-wrapper">
<label>Showing</label>
<div class="field">
${time_range}
</div>
</div>
% endif
</div> </div>
</div> </div>
@ -149,11 +57,7 @@
</div> </div>
% if use_buefy: <canvas ref="tempchart" width="400" height="150"></canvas>
<canvas ref="tempchart" width="400" height="150"></canvas>
% else:
<canvas id="tempchart" width="400" height="150"></canvas>
% endif
</%def> </%def>
<%def name="modify_this_page_vars()"> <%def name="modify_this_page_vars()">

View file

@ -2,86 +2,48 @@
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%def name="render_form_complete()"> <%def name="render_form_complete()">
% if use_buefy:
## ${self.render_form()} ## ${self.render_form()}
<script type="text/x-template" id="form-page-template"> <script type="text/x-template" id="form-page-template">
<div style="display: flex; justify-content: space-between;"> <div style="display: flex; justify-content: space-between;">
<div class="form-wrapper"> <div class="form-wrapper">
<div style="display: flex; flex-direction: column;"> <div style="display: flex; flex-direction: column;">
<nav class="panel" id="probe-main"> <nav class="panel" id="probe-main">
<p class="panel-heading">General</p> <p class="panel-heading">General</p>
<div class="panel-block"> <div class="panel-block">
<div> <div>
${self.render_main_fields(form)} ${self.render_main_fields(form)}
</div>
</div>
</nav>
<div style="display: flex;">
<div class="panel-wrapper">
${self.left_column()}
</div>
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div>
</div> </div>
</div>
</nav>
<div style="display: flex;">
<div class="panel-wrapper">
${self.left_column()}
</div>
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div> </div>
</div> </div>
<ul id="context-menu">
${self.context_menu_items()}
</ul>
</div> </div>
</script>
<div id="form-page-app">
<form-page></form-page>
</div> </div>
% else: <ul id="context-menu">
## legacy / not buefy ${self.context_menu_items()}
</ul>
<div style="display: flex; justify-content: space-between;"> </div>
</script>
<div class="form-wrapper"> <div id="form-page-app">
<form-page></form-page>
<div style="display: flex; flex-direction: column;"> </div>
<div class="panel" id="probe-main">
<h2>General</h2>
<div class="panel-body">
<div>
${self.render_main_fields(form)}
</div>
</div>
</div>
<div style="display: flex;">
<div class="panel-wrapper">
${self.left_column()}
</div>
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div>
</div>
</div>
</div>
<ul id="context-menu">
${self.context_menu_items()}
</ul>
</div>
% endif
</%def> </%def>
@ -113,43 +75,25 @@
</%def> </%def>
<%def name="left_column()"> <%def name="left_column()">
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Temperatures</p>
<p class="panel-heading">Temperatures</p> <div class="panel-block">
<div class="panel-block"> <div>
<div> ${self.render_temperature_fields(form)}
${self.render_temperature_fields(form)} </div>
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Temperatures</h2>
<div class="panel-body">
${self.render_temperature_fields(form)}
</div> </div>
</div> </nav>
% endif
</%def> </%def>
<%def name="right_column()"> <%def name="right_column()">
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Timeouts</p>
<p class="panel-heading">Timeouts</p> <div class="panel-block">
<div class="panel-block"> <div>
<div> ${self.render_timeout_fields(form)}
${self.render_timeout_fields(form)} </div>
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Timeouts</h2>
<div class="panel-body">
${self.render_timeout_fields(form)}
</div> </div>
</div> </nav>
% endif
</%def> </%def>
<%def name="render_temperature_fields(form)"> <%def name="render_temperature_fields(form)">

View file

@ -353,14 +353,10 @@
<div class="level"> <div class="level">
<div class="level-right"> <div class="level-right">
<div class="level-item"> <div class="level-item">
% if use_buefy: <b-input name="entry"
<b-input name="entry" placeholder="${quickie.placeholder}"
placeholder="${quickie.placeholder}" autocomplete="off">
autocomplete="off"> </b-input>
</b-input>
% else:
${h.text('entry', placeholder=quickie.placeholder, autocomplete='off')}
% endif
</div> </div>
<div class="level-item"> <div class="level-item">
<button type="submit" class="button is-primary"> <button type="submit" class="button is-primary">
@ -706,54 +702,38 @@
% if show_prev_next is not Undefined and show_prev_next: % if show_prev_next is not Undefined and show_prev_next:
% if prev_url: % if prev_url:
<div class="level-item"> <div class="level-item">
% if use_buefy: <b-button tag="a" href="${prev_url}"
<b-button tag="a" href="${prev_url}" icon-pack="fas"
icon-pack="fas" icon-left="arrow-left">
icon-left="arrow-left"> Older
Older </b-button>
</b-button>
% else:
${h.link_to(u"« Older", prev_url, class_='button autodisable')}
% endif
</div> </div>
% else: % else:
<div class="level-item"> <div class="level-item">
% if use_buefy: <b-button tag="a" href="#"
<b-button tag="a" href="#" disabled
disabled icon-pack="fas"
icon-pack="fas" icon-left="arrow-left">
icon-left="arrow-left"> Older
Older </b-button>
</b-button>
% else:
${h.link_to(u"« Older", '#', class_='button', disabled='disabled')}
% endif
</div> </div>
% endif % endif
% if next_url: % if next_url:
<div class="level-item"> <div class="level-item">
% if use_buefy: <b-button tag="a" href="${next_url}"
<b-button tag="a" href="${next_url}" icon-pack="fas"
icon-pack="fas" icon-left="arrow-right">
icon-left="arrow-right"> Newer
Newer </b-button>
</b-button>
% else:
${h.link_to(u"Newer »", next_url, class_='button autodisable')}
% endif
</div> </div>
% else: % else:
<div class="level-item"> <div class="level-item">
% if use_buefy: <b-button tag="a" href="#"
<b-button tag="a" href="#" disabled
disabled icon-pack="fas"
icon-pack="fas" icon-left="arrow-right">
icon-left="arrow-right"> Newer
Newer </b-button>
</b-button>
% else:
${h.link_to(u"Newer »", '#', class_='button', disabled='disabled')}
% endif
</div> </div>
% endif % endif
% endif % endif

View file

@ -1,43 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" /> <%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
function show_packages(type) {
if (type == 'all') {
$('.showing .diffs').css('font-weight', 'normal');
$('table.diff tbody tr').show();
$('.showing .all').css('font-weight', 'bold');
} else if (type == 'diffs') {
$('.showing .all').css('font-weight', 'normal');
$('table.diff tbody tr:not(.diff)').hide();
$('.showing .diffs').css('font-weight', 'bold');
}
}
$(function() {
show_packages('diffs');
$('.showing .all').click(function() {
show_packages('all');
return false;
});
$('.showing .diffs').click(function() {
show_packages('diffs')
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${parent.extra_styles()} ${parent.extra_styles()}
% if master.has_perm('execute'): % if master.has_perm('execute'):
@ -132,7 +95,7 @@
% if instance_executable and master.has_perm('execute'): % if instance_executable and master.has_perm('execute'):
<div class="buttons"> <div class="buttons">
% if instance.enabled and not instance.executing: % if instance.enabled and not instance.executing:
% if use_buefy and expose_websockets: % if expose_websockets:
<b-button type="is-primary" <b-button type="is-primary"
icon-pack="fas" icon-pack="fas"
icon-left="arrow-circle-right" icon-left="arrow-circle-right"
@ -140,7 +103,7 @@
@click="$emit('execute-upgrade-click')"> @click="$emit('execute-upgrade-click')">
{{ upgradeExecuting ? "Working, please wait..." : "Execute this upgrade" }} {{ upgradeExecuting ? "Working, please wait..." : "Execute this upgrade" }}
</b-button> </b-button>
% elif use_buefy: % else:
${h.form(url('{}.execute'.format(route_prefix), uuid=instance.uuid), **{'@submit': 'submitForm'})} ${h.form(url('{}.execute'.format(route_prefix), uuid=instance.uuid), **{'@submit': 'submitForm'})}
${h.csrf_token(request)} ${h.csrf_token(request)}
<b-button type="is-primary" <b-button type="is-primary"
@ -151,11 +114,6 @@
{{ formSubmitting ? "Working, please wait..." : "Execute this upgrade" }} {{ formSubmitting ? "Working, please wait..." : "Execute this upgrade" }}
</b-button> </b-button>
${h.end_form()} ${h.end_form()}
% else:
${h.form(url('{}.execute'.format(route_prefix), uuid=instance.uuid), class_='autodisable')}
${h.csrf_token(request)}
${h.submit('execute', "Execute this upgrade", class_='button is-primary')}
${h.end_form()}
% endif % endif
% elif instance.enabled: % elif instance.enabled:
<button type="button" class="button is-primary" disabled="disabled" title="This upgrade is currently executing">Execute this upgrade</button> <button type="button" class="button is-primary" disabled="disabled" title="This upgrade is currently executing">Execute this upgrade</button>

View file

@ -2,43 +2,27 @@
<%def name="view_profile_button(person)"> <%def name="view_profile_button(person)">
<div class="buttons"> <div class="buttons">
% if use_buefy: <b-button type="is-primary"
<b-button type="is-primary" tag="a" href="${url('people.view_profile', uuid=person.uuid)}"
tag="a" href="${url('people.view_profile', uuid=person.uuid)}" icon-pack="fas"
icon-pack="fas" icon-left="user">
icon-left="user"> ${person}
${person} </b-button>
</b-button>
% else:
${h.link_to(person, url('people.view_profile', uuid=person.uuid), class_='button is-primary')}
% endif
</div> </div>
</%def> </%def>
<%def name="view_profiles_helper(people)"> <%def name="view_profiles_helper(people)">
% if request.has_perm('people.view_profile'): % if request.has_perm('people.view_profile'):
% if use_buefy: <nav class="panel">
<nav class="panel"> <p class="panel-heading">Profiles</p>
<p class="panel-heading">Profiles</p> <div class="panel-block">
<div class="panel-block"> <div style="display: flex; flex-direction: column;">
<div style="display: flex; flex-direction: column;"> <p class="block">View full profile for:</p>
<p class="block">View full profile for:</p> % for person in people:
% for person in people: ${view_profile_button(person)}
${view_profile_button(person)} % endfor
% endfor
</div>
</div>
</nav>
% else:
<div class="object-helper">
<h3>Profiles</h3>
<div class="object-helper-content">
<p>View full profile for:</p>
% for person in people:
${view_profile_button(person)}
% endfor
</div>
</div> </div>
% endif </div>
</nav>
% endif % endif
</%def> </%def>

View file

@ -24,11 +24,8 @@
Utilities Utilities
""" """
from __future__ import unicode_literals, absolute_import
import datetime import datetime
import six
import pytz import pytz
import humanize import humanize
import logging import logging
@ -198,26 +195,6 @@ def get_liburl(request, key, fallback=True):
return 'https://code.jquery.com/ui/{}/themes/dark-hive/jquery-ui.css'.format(version) return 'https://code.jquery.com/ui/{}/themes/dark-hive/jquery-ui.css'.format(version)
def should_use_buefy(request):
"""
Returns a flag indicating whether or not the current theme supports (and
therefore should use) the Buefy JS library.
"""
# first check theme-specific setting, if one has been defined
theme = request.registry.settings['tailbone.theme']
buefy = request.rattail_config.getbool('tailbone', 'themes.{}.use_buefy'.format(theme))
if buefy is not None:
return buefy
# TODO: should not hard-code this surely, but works for now...
if theme == 'falafel':
return True
# TODO: probably should not use this fallback? it was the first setting
# i tested with, but is poorly named to say the least
return request.rattail_config.getbool('tailbone', 'grids.use_buefy', default=False)
def pretty_datetime(config, value): def pretty_datetime(config, value):
""" """
Formats a datetime as a "pretty" human-readable string, with a tooltip Formats a datetime as a "pretty" human-readable string, with a tooltip
@ -284,7 +261,7 @@ def raw_datetime(config, value, verbose=False, as_date=False):
else: else:
kwargs['c'] = value.strftime('%Y-%m-%d %I:%M:%S %p') kwargs['c'] = value.strftime('%Y-%m-%d %I:%M:%S %p')
else: else:
kwargs['c'] = six.text_type(value) kwargs['c'] = str(value)
time_diff = app.render_time_ago(time_ago, fallback=None) time_diff = app.render_time_ago(time_ago, fallback=None)
if time_diff is not None: if time_diff is not None:

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,8 +24,6 @@
Auth Views Auth Views
""" """
from __future__ import unicode_literals, absolute_import
from rattail.db.auth import authenticate_user, set_user_password from rattail.db.auth import authenticate_user, set_user_password
import colander import colander
@ -101,9 +99,7 @@ class AuthenticationView(View):
self.request.session.flash("{} is already logged in".format(self.request.user), 'error') self.request.session.flash("{} is already logged in".format(self.request.user), 'error')
return self.redirect(referrer) return self.redirect(referrer)
use_buefy = self.get_use_buefy() form = forms.Form(schema=UserLogin(), request=self.request)
form = forms.Form(schema=UserLogin(), request=self.request,
use_buefy=use_buefy)
form.save_label = "Login" form.save_label = "Login"
form.auto_disable_save = False form.auto_disable_save = False
form.auto_disable = False # TODO: deprecate / remove this form.auto_disable = False # TODO: deprecate / remove this
@ -126,16 +122,13 @@ class AuthenticationView(View):
'tailbone', 'main_image_url', 'tailbone', 'main_image_url',
default=self.request.static_url('tailbone:static/img/home_logo.png')) default=self.request.static_url('tailbone:static/img/home_logo.png'))
context = { return {
'form': form, 'form': form,
'referrer': referrer, 'referrer': referrer,
'image_url': image_url, 'image_url': image_url,
'use_buefy': use_buefy, 'index_title': self.rattail_config.node_title(),
'help_url': global_help_url(self.rattail_config), 'help_url': global_help_url(self.rattail_config),
} }
if use_buefy:
context['index_title'] = self.rattail_config.node_title()
return context
def authenticate_user(self, username, password): def authenticate_user(self, username, password):
app = self.get_rattail_app() app = self.get_rattail_app()
@ -177,15 +170,14 @@ class AuthenticationView(View):
self.request.session.flash("Cannot change password for user: {}".format(self.request.user)) self.request.session.flash("Cannot change password for user: {}".format(self.request.user))
return self.redirect(self.request.get_referrer()) return self.redirect(self.request.get_referrer())
use_buefy = self.get_use_buefy()
schema = ChangePassword().bind(user=self.request.user, request=self.request) schema = ChangePassword().bind(user=self.request.user, request=self.request)
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy) form = forms.Form(schema=schema, request=self.request)
if form.validate(newstyle=True): if form.validate(newstyle=True):
set_user_password(self.request.user, form.validated['new_password']) set_user_password(self.request.user, form.validated['new_password'])
self.request.session.flash("Your password has been changed.") self.request.session.flash("Your password has been changed.")
return self.redirect(self.request.get_referrer()) return self.redirect(self.request.get_referrer())
return {'form': form, 'use_buefy': use_buefy} return {'form': form}
def become_root(self): def become_root(self):
""" """

View file

@ -24,8 +24,6 @@
Base views for maintaining "new-style" batches. Base views for maintaining "new-style" batches.
""" """
from __future__ import unicode_literals, absolute_import
import os import os
import sys import sys
import json import json
@ -37,7 +35,6 @@ import tempfile
from six import StringIO from six import StringIO
import json import json
import six
import markdown import markdown
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import orm from sqlalchemy import orm
@ -172,7 +169,6 @@ class BatchMasterView(MasterView):
def template_kwargs_view(self, **kwargs): def template_kwargs_view(self, **kwargs):
kwargs = super(BatchMasterView, self).template_kwargs_view(**kwargs) kwargs = super(BatchMasterView, self).template_kwargs_view(**kwargs)
use_buefy = self.get_use_buefy()
batch = kwargs['instance'] batch = kwargs['instance']
kwargs['batch'] = batch kwargs['batch'] = batch
kwargs['handler'] = self.handler kwargs['handler'] = self.handler
@ -194,30 +190,22 @@ class BatchMasterView(MasterView):
breakdown = self.make_status_breakdown(batch) breakdown = self.make_status_breakdown(batch)
if use_buefy: factory = self.get_grid_factory()
factory = self.get_grid_factory() g = factory('batch_row_status_breakdown', [],
g = factory('batch_row_status_breakdown', [], columns=['title', 'count'])
columns=['title', 'count']) g.set_click_handler('title', "autoFilterStatus(props.row)")
g.set_click_handler('title', "autoFilterStatus(props.row)") kwargs['status_breakdown_data'] = breakdown
kwargs['status_breakdown_data'] = breakdown kwargs['status_breakdown_grid'] = HTML.literal(
kwargs['status_breakdown_grid'] = HTML.literal( g.render_buefy_table_element(data_prop='statusBreakdownData',
g.render_buefy_table_element(data_prop='statusBreakdownData', empty_labels=True))
empty_labels=True))
else:
kwargs['status_breakdown'] = [
(status['title'], status['count'])
for status in breakdown]
return kwargs return kwargs
def make_upload_worksheet_form(self, batch): def make_upload_worksheet_form(self, batch):
action_url = self.get_action_url('upload_worksheet', batch) action_url = self.get_action_url('upload_worksheet', batch)
use_buefy = self.get_use_buefy()
form = forms.Form(schema=UploadWorksheet(), form = forms.Form(schema=UploadWorksheet(),
request=self.request, request=self.request,
action_url=action_url, action_url=action_url,
use_buefy=use_buefy,
component='upload-worksheet-form') component='upload-worksheet-form')
form.set_type('worksheet_file', 'file') form.set_type('worksheet_file', 'file')
# TODO: must set these to avoid some default Buefy code # TODO: must set these to avoid some default Buefy code
@ -431,7 +419,6 @@ class BatchMasterView(MasterView):
return dict(batch.params or {}) return dict(batch.params or {})
def render_complete(self, batch, field): def render_complete(self, batch, field):
use_buefy = self.get_use_buefy()
text = "Yes" if batch.complete else "No" text = "Yes" if batch.complete else "No"
if batch.executed or not self.has_perm('edit'): if batch.executed or not self.has_perm('edit'):
@ -446,18 +433,13 @@ class BatchMasterView(MasterView):
url = self.get_action_url('toggle_complete', batch) url = self.get_action_url('toggle_complete', batch)
kwargs = {'@submit': 'togglingBatchComplete = true'} kwargs = {'@submit': 'togglingBatchComplete = true'}
if not use_buefy:
kwargs['class_'] = 'autodisable'
begin_form = tags.form(url, **kwargs) begin_form = tags.form(url, **kwargs)
if use_buefy: label = HTML.literal(
label = HTML.literal( '{{{{ togglingBatchComplete ? "Working, please wait..." : "{}" }}}}'.format(label))
'{{{{ togglingBatchComplete ? "Working, please wait..." : "{}" }}}}'.format(label)) submit = self.make_buefy_button(label, is_primary=True,
submit = self.make_buefy_button(label, is_primary=True, native_type='submit',
native_type='submit', **{':disabled': 'togglingBatchComplete'})
**{':disabled': 'togglingBatchComplete'})
else:
submit = tags.submit('submit', label)
form = [ form = [
begin_form, begin_form,
@ -467,23 +449,16 @@ class BatchMasterView(MasterView):
tags.end_form(), tags.end_form(),
] ]
if use_buefy: text = HTML.tag('div', class_='control', c=text)
text = HTML.tag('div', class_='control', c=text) form = HTML.tag('div', class_='control', c=form)
form = HTML.tag('div', class_='control', c=form) content = [
content = [ HTML.tag('nav', class_='level',
HTML.tag('nav', class_='level', c=[HTML.tag('div', class_='level-left', c=[
c=[HTML.tag('div', class_='level-left', c=[ text,
text, HTML.literal(' &nbsp; &nbsp; '),
HTML.literal(' &nbsp; &nbsp; '), form,
form, ])]),
])]), ]
]
else:
content = [
text,
HTML.literal(' &nbsp; '),
] + form
return HTML.tag('div', c=content) return HTML.tag('div', c=content)
@ -491,7 +466,7 @@ class BatchMasterView(MasterView):
user = getattr(batch, field) user = getattr(batch, field)
if not user: if not user:
return "" return ""
title = six.text_type(user) title = str(user)
url = self.request.route_url('users.view', uuid=user.uuid) url = self.request.route_url('users.view', uuid=user.uuid)
return tags.link_to(title, url) return tags.link_to(title, url)
@ -513,7 +488,7 @@ class BatchMasterView(MasterView):
# TODO: this needs work yet surely...why is this an issue? # TODO: this needs work yet surely...why is this an issue?
# treat 'filename' field specially, for some reason it can be a filedict? # treat 'filename' field specially, for some reason it can be a filedict?
if 'filename' in kwargs and not isinstance(kwargs['filename'], six.string_types): if 'filename' in kwargs and not isinstance(kwargs['filename'], str):
kwargs['filename'] = '' # null not allowed kwargs['filename'] = '' # null not allowed
# TODO: is this still necessary with colander? # TODO: is this still necessary with colander?
@ -533,7 +508,7 @@ class BatchMasterView(MasterView):
os.remove(upload['temp_path']) os.remove(upload['temp_path'])
os.rmdir(upload['tempdir']) os.rmdir(upload['tempdir'])
for key, upload in six.iteritems(uploads): for key, upload in uploads.items():
if isinstance(upload, dict): if isinstance(upload, dict):
process(upload, key) process(upload, key)
else: else:
@ -657,7 +632,7 @@ class BatchMasterView(MasterView):
code = row.status_code code = row.status_code
if code is None: if code is None:
return "" return ""
text = self.get_row_status_enum().get(code, six.text_type(code)) text = self.get_row_status_enum().get(code, str(code))
if row.status_text: if row.status_text:
return HTML.tag('span', title=row.status_text, c=text) return HTML.tag('span', title=row.status_text, c=text)
return text return text
@ -707,21 +682,12 @@ class BatchMasterView(MasterView):
permission_prefix = self.get_permission_prefix() permission_prefix = self.get_permission_prefix()
if self.request.has_perm('{}.create_row'.format(permission_prefix)): if self.request.has_perm('{}.create_row'.format(permission_prefix)):
url = self.get_action_url('create_row', batch) url = self.get_action_url('create_row', batch)
if self.get_use_buefy(): return self.make_buefy_button("New Row", url=url,
return self.make_buefy_button("New Row", url=url, is_primary=True,
is_primary=True, icon_left='plus')
icon_left='plus')
else:
text = "Create a new {}".format(self.get_row_model_title())
link = tags.link_to(text, url)
return HTML.tag('p', c=[link])
def make_batch_row_grid_tools(self, batch): def make_batch_row_grid_tools(self, batch):
if self.get_use_buefy(): pass
return
if self.rows_bulk_deletable and not batch.executed and self.request.has_perm('{}.delete_rows'.format(self.get_permission_prefix())):
url = self.request.route_url('{}.delete_rows'.format(self.get_route_prefix()), uuid=batch.uuid)
return HTML.tag('p', c=[tags.link_to("Delete all rows matching current search", url)])
def make_row_grid_kwargs(self, **kwargs): def make_row_grid_kwargs(self, **kwargs):
""" """
@ -733,21 +699,19 @@ class BatchMasterView(MasterView):
# TODO: most of this logic is copied from MasterView, should refactor/merge somehow... # TODO: most of this logic is copied from MasterView, should refactor/merge somehow...
if 'main_actions' not in kwargs: if 'main_actions' not in kwargs:
actions = [] actions = []
use_buefy = self.get_use_buefy()
# view action # view action
if self.rows_viewable: if self.rows_viewable:
view = lambda r, i: self.get_row_action_url('view', r) view = lambda r, i: self.get_row_action_url('view', r)
icon = 'eye' if use_buefy else 'zoomin' actions.append(self.make_action('view', icon='eye', url=view))
actions.append(self.make_action('view', icon=icon, url=view))
# edit and delete are NOT allowed after execution, or if batch is "complete" # edit and delete are NOT allowed after execution, or if batch is "complete"
if not batch.executed and not batch.complete: if not batch.executed and not batch.complete:
# edit action # edit action
if self.rows_editable and self.has_perm('edit_row'): if self.rows_editable and self.has_perm('edit_row'):
icon = 'edit' if use_buefy else 'pencil' actions.append(self.make_action('edit', icon='edit',
actions.append(self.make_action('edit', icon=icon, url=self.row_edit_action_url)) url=self.row_edit_action_url))
# delete action # delete action
if self.rows_deletable and self.has_perm('delete_row'): if self.rows_deletable and self.has_perm('delete_row'):
@ -793,7 +757,7 @@ class BatchMasterView(MasterView):
# nb. must make new session, separate from main thread # nb. must make new session, separate from main thread
session = app.make_session() session = app.make_session()
batch = self.get_instance_for_key(key, session) batch = self.get_instance_for_key(key, session)
batch_str = six.text_type(batch) batch_str = str(batch)
try: try:
# try to delete batch # try to delete batch
@ -869,7 +833,6 @@ class BatchMasterView(MasterView):
""" """
defaults = {} defaults = {}
route_prefix = self.get_route_prefix() route_prefix = self.get_route_prefix()
use_buefy = self.get_use_buefy()
schema = None schema = None
if self.has_execution_options(batch): if self.has_execution_options(batch):
@ -891,13 +854,12 @@ class BatchMasterView(MasterView):
labels[field.name] = field.title labels[field.name] = field.title
# auto-convert select widgets for buefy theme # auto-convert select widgets for buefy theme
if use_buefy and isinstance(field.widget, forms.widgets.PlainSelectWidget): if isinstance(field.widget, forms.widgets.PlainSelectWidget):
field.widget = dfwidget.SelectWidget(values=field.widget.values) field.widget = dfwidget.SelectWidget(values=field.widget.values)
if not schema: if not schema:
schema = colander.Schema() schema = colander.Schema()
kwargs['use_buefy'] = use_buefy
kwargs['component'] = 'execute-form' kwargs['component'] = 'execute-form'
form = forms.Form(schema=schema, request=self.request, defaults=defaults, **kwargs) form = forms.Form(schema=schema, request=self.request, defaults=defaults, **kwargs)
self.configure_execute_form(form) self.configure_execute_form(form)
@ -1051,8 +1013,7 @@ class BatchMasterView(MasterView):
data = json.dumps({ data = json.dumps({
'everything_complete': True, 'everything_complete': True,
}) })
if six.PY3: data = data.encode('utf_8')
data = data.encode('utf_8')
cxn.send(data) cxn.send(data)
cxn.send(suffix) cxn.send(suffix)
cxn.close() cxn.close()
@ -1061,7 +1022,7 @@ class BatchMasterView(MasterView):
with short_session() as s: with short_session() as s:
batch = s.query(self.model_class).get(batch_uuid) batch = s.query(self.model_class).get(batch_uuid)
batch_id = batch.id_str batch_id = batch.id_str
description = six.text_type(batch) description = str(batch)
self.launch_subprocess( self.launch_subprocess(
port=port, username=username, port=port, username=username,

View file

@ -24,8 +24,6 @@
Views for importer batches Views for importer batches
""" """
from __future__ import unicode_literals, absolute_import
import sqlalchemy as sa import sqlalchemy as sa
from rattail.db import model from rattail.db import model
@ -139,7 +137,6 @@ class ImporterBatchView(BatchMasterView):
def configure_row_grid(self, g): def configure_row_grid(self, g):
super(ImporterBatchView, self).configure_row_grid(g) super(ImporterBatchView, self).configure_row_grid(g)
use_buefy = self.get_use_buefy()
def make_filter(field, **kwargs): def make_filter(field, **kwargs):
column = getattr(self.current_row_table.c, field) column = getattr(self.current_row_table.c, field)
@ -150,11 +147,8 @@ class ImporterBatchView(BatchMasterView):
# for some reason we have to do this differently for Buefy? # for some reason we have to do this differently for Buefy?
kwargs = {} kwargs = {}
if not use_buefy:
kwargs['value_enum'] = self.enum.IMPORTER_BATCH_ROW_STATUS
make_filter('status_code', label="Status", **kwargs) make_filter('status_code', label="Status", **kwargs)
if use_buefy: g.filters['status_code'].set_choices(self.enum.IMPORTER_BATCH_ROW_STATUS)
g.filters['status_code'].set_choices(self.enum.IMPORTER_BATCH_ROW_STATUS)
def make_sorter(field): def make_sorter(field):
column = getattr(self.current_row_table.c, field) column = getattr(self.current_row_table.c, field)

View file

@ -24,14 +24,10 @@
Views for inventory batches Views for inventory batches
""" """
from __future__ import unicode_literals, absolute_import
import re import re
import decimal import decimal
import logging import logging
import six
from rattail import pod from rattail import pod
from rattail.db import model from rattail.db import model
from rattail.db.util import make_full_description from rattail.db.util import make_full_description
@ -234,9 +230,8 @@ class InventoryBatchView(BatchMasterView):
if batch.executed: if batch.executed:
return self.redirect(self.get_action_url('view', batch)) return self.redirect(self.get_action_url('view', batch))
use_buefy = self.get_use_buefy()
schema = DesktopForm().bind(session=self.Session()) schema = DesktopForm().bind(session=self.Session())
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy) form = forms.Form(schema=schema, request=self.request)
if self.request.method == 'POST': if self.request.method == 'POST':
if form.validate(newstyle=True): if form.validate(newstyle=True):
@ -273,7 +268,7 @@ class InventoryBatchView(BatchMasterView):
else: else:
dform = form.make_deform_form() dform = form.make_deform_form()
msg = "Form did not validate: {}".format(six.text_type(dform.error)) msg = "Form did not validate: {}".format(str(dform.error))
self.request.session.flash(msg, 'error') self.request.session.flash(msg, 'error')
title = self.get_instance_title(batch) title = self.get_instance_title(batch)
@ -345,7 +340,7 @@ class InventoryBatchView(BatchMasterView):
upc = re.sub(r'\D', '', entry.strip()) upc = re.sub(r'\D', '', entry.strip())
if upc: if upc:
upc = GPC(upc) upc = GPC(upc)
result['upc'] = six.text_type(upc) result['upc'] = str(upc)
result['upc_pretty'] = upc.pretty() result['upc_pretty'] = upc.pretty()
result['image_url'] = pod.get_image_url(self.rattail_config, upc) result['image_url'] = pod.get_image_url(self.rattail_config, upc)
@ -374,10 +369,10 @@ class InventoryBatchView(BatchMasterView):
data = {} data = {}
if product and (not product.deleted or self.request.has_perm('products.view_deleted')): if product and (not product.deleted or self.request.has_perm('products.view_deleted')):
data['uuid'] = product.uuid data['uuid'] = product.uuid
data['upc'] = six.text_type(product.upc) data['upc'] = str(product.upc)
data['upc_pretty'] = product.upc.pretty() data['upc_pretty'] = product.upc.pretty()
data['full_description'] = product.full_description data['full_description'] = product.full_description
data['brand_name'] = six.text_type(product.brand or '') data['brand_name'] = str(product.brand or '')
data['description'] = product.description data['description'] = product.description
data['size'] = product.size data['size'] = product.size
data['case_quantity'] = 1 # default data['case_quantity'] = 1 # default

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,12 +24,8 @@
Views for maintaining vendor catalogs Views for maintaining vendor catalogs
""" """
from __future__ import unicode_literals, absolute_import
import logging import logging
import six
from rattail.db import model from rattail.db import model
import colander import colander
@ -196,9 +192,6 @@ class VendorCatalogView(FileBatchMasterView):
values = [(p.key, p.display) for p in parsers] values = [(p.key, p.display) for p in parsers]
if len(values) == 1: if len(values) == 1:
f.set_default('parser_key', parsers[0].key) f.set_default('parser_key', parsers[0].key)
use_buefy = self.get_use_buefy()
if not use_buefy:
values.insert(0, ('', "(please choose)"))
f.set_widget('parser_key', dfwidget.SelectWidget(values=values)) f.set_widget('parser_key', dfwidget.SelectWidget(values=values))
else: else:
f.set_readonly('parser_key') f.set_readonly('parser_key')
@ -235,7 +228,7 @@ class VendorCatalogView(FileBatchMasterView):
vendor = self.Session.query(model.Vendor).get( vendor = self.Session.query(model.Vendor).get(
self.request.POST['vendor_uuid']) self.request.POST['vendor_uuid'])
if vendor: if vendor:
vendor_display = six.text_type(vendor) vendor_display = str(vendor)
f.set_widget('vendor_uuid', f.set_widget('vendor_uuid',
forms.widgets.JQueryAutocompleteWidget( forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, field_display=vendor_display,
@ -275,35 +268,20 @@ class VendorCatalogView(FileBatchMasterView):
return parser.display return parser.display
def template_kwargs_create(self, **kwargs): def template_kwargs_create(self, **kwargs):
use_buefy = self.get_use_buefy()
app = self.get_rattail_app() app = self.get_rattail_app()
vendor_handler = app.get_vendor_handler() vendor_handler = app.get_vendor_handler()
parsers = self.get_parsers() parsers = self.get_parsers()
parsers_data = {} parsers_data = {}
for parser in parsers: for parser in parsers:
if use_buefy: pdata = {'key': parser.key,
pdata = {'key': parser.key, 'vendor_key': parser.vendor_key}
'vendor_key': parser.vendor_key} if parser.vendor_key:
if parser.vendor_key: vendor = vendor_handler.get_vendor(self.Session(),
vendor = vendor_handler.get_vendor(self.Session(), parser.vendor_key)
parser.vendor_key) if vendor:
if vendor: pdata['vendor_uuid'] = vendor.uuid
pdata['vendor_uuid'] = vendor.uuid pdata['vendor_name'] = vendor.name
pdata['vendor_name'] = vendor.name parsers_data[parser.key] = pdata
parsers_data[parser.key] = pdata
else:
if parser.vendor_key:
vendor = vendor_handler.get_vendor(self.Session(),
parser.vendor_key)
if vendor:
parser.vendormap_value = "{{uuid: '{}', name: '{}'}}".format(
vendor.uuid, vendor.name.replace("'", "\\'"))
else:
log.warning("vendor '{}' not found for parser: {}".format(
parser.vendor_key, parser.key))
parser.vendormap_value = 'null'
else:
parser.vendormap_value = 'null'
kwargs['parsers'] = parsers kwargs['parsers'] = parsers
kwargs['parsers_data'] = parsers_data kwargs['parsers_data'] = parsers_data
return kwargs return kwargs

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,10 +24,7 @@
Various common views Various common views
""" """
from __future__ import unicode_literals, absolute_import
import os import os
import six
from rattail.batch import consume_batch_id from rattail.batch import consume_batch_id
from rattail.util import OrderedDict, simple_error, import_module_path from rattail.util import OrderedDict, simple_error, import_module_path
@ -62,14 +59,11 @@ class CommonView(View):
'tailbone', 'main_image_url', 'tailbone', 'main_image_url',
default=self.request.static_url('tailbone:static/img/home_logo.png')) default=self.request.static_url('tailbone:static/img/home_logo.png'))
use_buefy = self.get_use_buefy()
context = { context = {
'image_url': image_url, 'image_url': image_url,
'use_buefy': use_buefy, 'index_title': self.rattail_config.node_title(),
'help_url': global_help_url(self.rattail_config), 'help_url': global_help_url(self.rattail_config),
} }
if use_buefy:
context['index_title'] = self.rattail_config.node_title()
if self.expose_quickie_search: if self.expose_quickie_search:
context['quickie'] = self.get_quickie_context() context['quickie'] = self.get_quickie_context()
@ -83,12 +77,8 @@ class CommonView(View):
with open(self.robots_txt_path, 'rt') as f: with open(self.robots_txt_path, 'rt') as f:
content = f.read() content = f.read()
response = self.request.response response = self.request.response
if six.PY3: response.text = content
response.text = content response.content_type = 'text/plain'
response.content_type = 'text/plain'
else:
response.body = content
response.content_type = b'text/plain'
return response return response
def get_project_title(self): def get_project_title(self):
@ -114,16 +104,12 @@ class CommonView(View):
""" """
Generic view to show "about project" info page. Generic view to show "about project" info page.
""" """
use_buefy = self.get_use_buefy() return {
context = {
'project_title': self.get_project_title(), 'project_title': self.get_project_title(),
'project_version': self.get_project_version(), 'project_version': self.get_project_version(),
'packages': self.get_packages(), 'packages': self.get_packages(),
'use_buefy': use_buefy, 'index_title': self.rattail_config.node_title(),
} }
if use_buefy:
context['index_title'] = self.rattail_config.node_title()
return context
def get_packages(self): def get_packages(self):
""" """
@ -203,7 +189,6 @@ class CommonView(View):
if not self.request.is_root: if not self.request.is_root:
raise self.forbidden() raise self.forbidden()
use_buefy = self.get_use_buefy()
app = self.get_rattail_app() app = self.get_rattail_app()
app_title = self.rattail_config.app_title() app_title = self.rattail_config.app_title()
poser_handler = app.get_poser_handler() poser_handler = app.get_poser_handler()
@ -253,7 +238,6 @@ class CommonView(View):
poser_error = simple_error(error) poser_error = simple_error(error)
return { return {
'use_buefy': use_buefy,
'app_title': app_title, 'app_title': app_title,
'index_title': app_title, 'index_title': app_title,
'poser_dir': poser_dir, 'poser_dir': poser_dir,

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,12 +24,8 @@
Base View Class Base View Class
""" """
from __future__ import unicode_literals, absolute_import
import os import os
import six
from rattail.db import model from rattail.db import model
from rattail.core import Object from rattail.core import Object
from rattail.util import progress_loop from rattail.util import progress_loop
@ -41,7 +37,6 @@ from pyramid.response import FileResponse
from tailbone.db import Session from tailbone.db import Session
from tailbone.auth import logout_user from tailbone.auth import logout_user
from tailbone.progress import SessionProgress from tailbone.progress import SessionProgress
from tailbone.util import should_use_buefy
from tailbone.config import protected_usernames from tailbone.config import protected_usernames
@ -94,13 +89,6 @@ class View(object):
def notfound(self): def notfound(self):
return httpexceptions.HTTPNotFound() return httpexceptions.HTTPNotFound()
def get_use_buefy(self):
"""
Returns a flag indicating whether or not the current theme supports
(and therefore should use) the Buefy JS library.
"""
return should_use_buefy(self.request)
def late_login_user(self): def late_login_user(self):
""" """
Returns the :class:`rattail:rattail.db.model.User` instance Returns the :class:`rattail:rattail.db.model.User` instance
@ -170,8 +158,6 @@ class View(object):
if attachment: if attachment:
if not filename: if not filename:
filename = os.path.basename(path) filename = os.path.basename(path)
if six.PY2:
filename = filename.encode('ascii', 'replace')
response.content_disposition = str('attachment; filename="{}"'.format(filename)) response.content_disposition = str('attachment; filename="{}"'.format(filename))
return response return response

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,9 +24,6 @@
Customer Views Customer Views
""" """
from __future__ import unicode_literals, absolute_import
import six
import sqlalchemy as sa import sqlalchemy as sa
import colander import colander
@ -205,7 +202,6 @@ class CustomerView(MasterView):
super(CustomerView, self).configure_common_form(f) super(CustomerView, self).configure_common_form(f)
customer = f.model_instance customer = f.model_instance
permission_prefix = self.get_permission_prefix() permission_prefix = self.get_permission_prefix()
use_buefy = self.get_use_buefy()
f.set_renderer('default_email', self.render_default_email) f.set_renderer('default_email', self.render_default_email)
if not self.creating and customer.emails: if not self.creating and customer.emails:
@ -251,12 +247,7 @@ class CustomerView(MasterView):
# people # people
if self.viewing: if self.viewing:
if use_buefy: f.set_renderer('people', self.render_people_buefy)
f.set_renderer('people', self.render_people_buefy)
elif self.people_detachable and self.has_perm('detach_person'):
f.set_renderer('people', self.render_people_removable)
else:
f.set_renderer('people', self.render_people)
else: else:
f.remove('people') f.remove('people')
@ -288,30 +279,28 @@ class CustomerView(MasterView):
kwargs['show_profiles_helper'] = self.show_profiles_helper kwargs['show_profiles_helper'] = self.show_profiles_helper
use_buefy = self.get_use_buefy() customer = kwargs['instance']
if use_buefy: people = []
customer = kwargs['instance'] for person in customer.people:
people = [] data = {
for person in customer.people: 'uuid': person.uuid,
data = { 'full_name': person.display_name,
'uuid': person.uuid, 'first_name': person.first_name,
'full_name': person.display_name, 'last_name': person.last_name,
'first_name': person.first_name, '_action_url_view': self.request.route_url('people.view',
'last_name': person.last_name, uuid=person.uuid),
'_action_url_view': self.request.route_url('people.view', }
uuid=person.uuid), if self.editable and self.request.has_perm('people.edit'):
} data['_action_url_edit'] = self.request.route_url(
if self.editable and self.request.has_perm('people.edit'): 'people.edit',
data['_action_url_edit'] = self.request.route_url( uuid=person.uuid)
'people.edit', if self.people_detachable and self.has_perm('detach_person'):
uuid=person.uuid) data['_action_url_detach'] = self.request.route_url(
if self.people_detachable and self.has_perm('detach_person'): 'customers.detach_person',
data['_action_url_detach'] = self.request.route_url( uuid=customer.uuid,
'customers.detach_person', person_uuid=person.uuid)
uuid=customer.uuid, people.append(data)
person_uuid=person.uuid) kwargs['people_data'] = people
people.append(data)
kwargs['people_data'] = people
return kwargs return kwargs
@ -326,20 +315,20 @@ class CustomerView(MasterView):
def render_default_address(self, customer, field): def render_default_address(self, customer, field):
if customer.addresses: if customer.addresses:
return six.text_type(customer.addresses[0]) return str(customer.addresses[0])
def grid_render_person(self, customer, field): def grid_render_person(self, customer, field):
person = getattr(customer, field) person = getattr(customer, field)
if not person: if not person:
return "" return ""
return six.text_type(person) return str(person)
def form_render_person(self, customer, field): def form_render_person(self, customer, field):
person = getattr(customer, field) person = getattr(customer, field)
if not person: if not person:
return "" return ""
text = six.text_type(person) text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid) url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -350,12 +339,13 @@ class CustomerView(MasterView):
items = [] items = []
for person in people: for person in people:
text = six.text_type(person) text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid) url = self.request.route_url('people.view', uuid=person.uuid)
link = tags.link_to(text, url) link = tags.link_to(text, url)
items.append(HTML.tag('li', c=[link])) items.append(HTML.tag('li', c=[link]))
return HTML.tag('ul', c=items) return HTML.tag('ul', c=items)
# TODO: remove if no longer used
def render_people_removable(self, customer, field): def render_people_removable(self, customer, field):
people = customer.people people = customer.people
if not people: if not people:
@ -431,7 +421,7 @@ class CustomerView(MasterView):
return "" return ""
items = [] items = []
for member in members: for member in members:
text = six.text_type(member) text = str(member)
url = self.request.route_url('members.view', uuid=member.uuid) url = self.request.route_url('members.view', uuid=member.uuid)
items.append(HTML.tag('li', tags.link_to(text, url))) items.append(HTML.tag('li', tags.link_to(text, url)))
return HTML.tag('ul', HTML.literal('').join(items)) return HTML.tag('ul', HTML.literal('').join(items))
@ -587,7 +577,7 @@ class PendingCustomerView(MasterView):
g.set_enum('status_code', self.enum.PENDING_CUSTOMER_STATUS) g.set_enum('status_code', self.enum.PENDING_CUSTOMER_STATUS)
g.filters['status_code'].default_active = True g.filters['status_code'].default_active = True
g.filters['status_code'].default_verb = 'not_equal' g.filters['status_code'].default_verb = 'not_equal'
g.filters['status_code'].default_value = six.text_type(self.enum.PENDING_CUSTOMER_STATUS_RESOLVED) g.filters['status_code'].default_value = str(self.enum.PENDING_CUSTOMER_STATUS_RESOLVED)
g.set_sort_defaults('display_name') g.set_sort_defaults('display_name')
g.set_link('id') g.set_link('id')

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,11 +24,8 @@
Customer order item views Customer order item views
""" """
from __future__ import unicode_literals, absolute_import
import datetime import datetime
import six
from sqlalchemy import orm from sqlalchemy import orm
from rattail.db import model from rattail.db import model
@ -156,7 +153,7 @@ class CustomerOrderItemView(MasterView):
def render_person_text(self, item, field): def render_person_text(self, item, field):
person = item.order.person person = item.order.person
if person: if person:
text = six.text_type(person) text = str(person)
return text return text
def render_order_created(self, item, column): def render_order_created(self, item, column):
@ -165,14 +162,13 @@ class CustomerOrderItemView(MasterView):
def render_status_code_column(self, item, field): def render_status_code_column(self, item, field):
text = self.enum.CUSTORDER_ITEM_STATUS.get(item.status_code, text = self.enum.CUSTORDER_ITEM_STATUS.get(item.status_code,
six.text_type(item.status_code)) str(item.status_code))
if item.status_text: if item.status_text:
return HTML.tag('span', title=item.status_text, c=[text]) return HTML.tag('span', title=item.status_text, c=[text])
return text return text
def configure_form(self, f): def configure_form(self, f):
super(CustomerOrderItemView, self).configure_form(f) super(CustomerOrderItemView, self).configure_form(f)
use_buefy = self.get_use_buefy()
item = f.model_instance item = f.model_instance
# order # order
@ -222,10 +218,7 @@ class CustomerOrderItemView(MasterView):
f.set_renderer('status_code', self.render_status_code) f.set_renderer('status_code', self.render_status_code)
# notes # notes
if use_buefy: f.set_renderer('notes', self.render_notes)
f.set_renderer('notes', self.render_notes)
else:
f.remove('notes')
def highlight_pending_field(self, item, field, value=None): def highlight_pending_field(self, item, field, value=None):
if value is None: if value is None:
@ -271,13 +264,12 @@ class CustomerOrderItemView(MasterView):
return outer return outer
def render_status_code(self, item, field): def render_status_code(self, item, field):
use_buefy = self.get_use_buefy()
text = self.enum.CUSTORDER_ITEM_STATUS[item.status_code] text = self.enum.CUSTORDER_ITEM_STATUS[item.status_code]
if item.status_text: if item.status_text:
text = "{} ({})".format(text, item.status_text) text = "{} ({})".format(text, item.status_text)
items = [HTML.tag('span', c=[text])] items = [HTML.tag('span', c=[text])]
if use_buefy and self.has_perm('change_status'): if self.has_perm('change_status'):
button = HTML.tag('b-button', type='is-primary', c="Change Status", button = HTML.tag('b-button', type='is-primary', c="Change Status",
style='margin-left: 1rem;', style='margin-left: 1rem;',
icon_pack='fas', icon_left='edit', icon_pack='fas', icon_left='edit',
@ -484,14 +476,14 @@ class CustomerOrderItemView(MasterView):
order = item.order order = item.order
if not order: if not order:
return "" return ""
text = six.text_type(order) text = str(order)
url = self.request.route_url('custorders.view', uuid=order.uuid) url = self.request.route_url('custorders.view', uuid=order.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
def render_person(self, item, field): def render_person(self, item, field):
person = item.order.person person = item.order.person
if person: if person:
text = six.text_type(person) text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid) url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)

View file

@ -24,15 +24,10 @@
Department Views Department Views
""" """
from __future__ import unicode_literals, absolute_import
import six
from rattail.db import model from rattail.db import model
from webhelpers2.html import HTML from webhelpers2.html import HTML
from tailbone import grids
from tailbone.views import MasterView from tailbone.views import MasterView
@ -99,11 +94,10 @@ class DepartmentView(MasterView):
def configure_form(self, f): def configure_form(self, f):
super(DepartmentView, self).configure_form(f) super(DepartmentView, self).configure_form(f)
use_buefy = self.get_use_buefy()
f.remove_field('subdepartments') f.remove_field('subdepartments')
if not use_buefy or self.creating or self.editing: if self.creating or self.editing:
f.remove('employees') f.remove('employees')
else: else:
f.set_renderer('employees', self.render_employees) f.set_renderer('employees', self.render_employees)
@ -137,33 +131,20 @@ class DepartmentView(MasterView):
def template_kwargs_view(self, **kwargs): def template_kwargs_view(self, **kwargs):
kwargs = super(DepartmentView, self).template_kwargs_view(**kwargs) kwargs = super(DepartmentView, self).template_kwargs_view(**kwargs)
use_buefy = self.get_use_buefy()
department = kwargs['instance'] department = kwargs['instance']
department_employees = sorted(department.employees, key=six.text_type) department_employees = sorted(department.employees, key=str)
if use_buefy: employees = []
employees = [] for employee in department_employees:
for employee in department_employees: person = employee.person
person = employee.person employees.append({
employees.append({ 'uuid': employee.uuid,
'uuid': employee.uuid, 'first_name': person.first_name,
'first_name': person.first_name, 'last_name': person.last_name,
'last_name': person.last_name, '_action_url_view': self.request.route_url('employees.view', uuid=employee.uuid),
'_action_url_view': self.request.route_url('employees.view', uuid=employee.uuid), '_action_url_edit': self.request.route_url('employees.edit', uuid=employee.uuid),
'_action_url_edit': self.request.route_url('employees.edit', uuid=employee.uuid), })
}) kwargs['employees_data'] = employees
kwargs['employees_data'] = employees
else: # not buefy
if department.employees:
actions = [
grids.GridAction('view', icon='zoomin',
url=lambda r, i: self.request.route_url('employees.view', uuid=r.uuid))
]
kwargs['employees'] = grids.Grid(None, department_employees, ['display_name'], request=self.request,
model_class=model.Employee, main_actions=actions)
else:
kwargs['employees'] = None
return kwargs return kwargs
@ -218,33 +199,14 @@ class DepartmentView(MasterView):
.distinct()\ .distinct()\
.order_by(model.Department.name) .order_by(model.Department.name)
if self.get_use_buefy(): def normalize(dept):
return {
'uuid': dept.uuid,
'number': dept.number,
'name': dept.name,
}
def normalize(dept): return self.json_response([normalize(d) for d in data])
return {
'uuid': dept.uuid,
'number': dept.number,
'name': dept.name,
}
return self.json_response([normalize(d) for d in data])
# nb. the rest of this is legacy / not buefy
def configure(g):
g.configure(include=[
g.name,
], readonly=True)
def row_attrs(row, i):
return {'data-uuid': row.uuid}
grid = self.make_grid(data=data, sortable=False, filterable=False, pageable=False,
configure=configure, width=None, checkboxes=True,
row_attrs=row_attrs, main_actions=[], more_actions=[])
self.request.response.content_type = str('text/html')
self.request.response.text = grid.render_grid()
return self.request.response
@classmethod @classmethod
def defaults(cls, config): def defaults(cls, config):

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,9 +24,6 @@
Employee Views Employee Views
""" """
from __future__ import unicode_literals, absolute_import
import six
import sqlalchemy as sa import sqlalchemy as sa
from rattail.db import model from rattail.db import model
@ -84,7 +81,6 @@ class EmployeeView(MasterView):
def configure_grid(self, g): def configure_grid(self, g):
super(EmployeeView, self).configure_grid(g) super(EmployeeView, self).configure_grid(g)
route_prefix = self.get_route_prefix() route_prefix = self.get_route_prefix()
use_buefy = self.get_use_buefy()
# phone # phone
g.set_joiner('phone', lambda q: q.outerjoin(model.EmployeePhoneNumber, sa.and_( g.set_joiner('phone', lambda q: q.outerjoin(model.EmployeePhoneNumber, sa.and_(
@ -127,10 +123,7 @@ class EmployeeView(MasterView):
g.set_enum('status', self.enum.EMPLOYEE_STATUS) g.set_enum('status', self.enum.EMPLOYEE_STATUS)
g.filters['status'].default_active = True g.filters['status'].default_active = True
g.filters['status'].default_verb = 'equal' g.filters['status'].default_verb = 'equal'
if use_buefy: g.filters['status'].default_value = str(self.enum.EMPLOYEE_STATUS_CURRENT)
g.filters['status'].default_value = six.text_type(self.enum.EMPLOYEE_STATUS_CURRENT)
else:
g.filters['status'].default_value = self.enum.EMPLOYEE_STATUS_CURRENT
else: else:
g.remove('status') g.remove('status')
del g.filters['status'] del g.filters['status']
@ -202,7 +195,7 @@ class EmployeeView(MasterView):
f.set_label('stores', "Stores") # TODO: should not be necessary f.set_label('stores', "Stores") # TODO: should not be necessary
if self.creating or self.editing: if self.creating or self.editing:
stores = self.get_possible_stores().all() stores = self.get_possible_stores().all()
store_values = [(s.uuid, six.text_type(s)) for s in stores] store_values = [(s.uuid, str(s)) for s in stores]
f.set_node('stores', colander.SchemaNode(colander.Set())) f.set_node('stores', colander.SchemaNode(colander.Set()))
f.set_widget('stores', dfwidget.SelectWidget(multiple=True, f.set_widget('stores', dfwidget.SelectWidget(multiple=True,
size=len(stores), size=len(stores),
@ -214,7 +207,7 @@ class EmployeeView(MasterView):
f.set_label('departments', "Departments") # TODO: should not be necessary f.set_label('departments', "Departments") # TODO: should not be necessary
if self.creating or self.editing: if self.creating or self.editing:
departments = self.get_possible_departments().all() departments = self.get_possible_departments().all()
dept_values = [(d.uuid, six.text_type(d)) for d in departments] dept_values = [(d.uuid, str(d)) for d in departments]
f.set_node('departments', colander.SchemaNode(colander.Set())) f.set_node('departments', colander.SchemaNode(colander.Set()))
f.set_widget('departments', dfwidget.SelectWidget(multiple=True, f.set_widget('departments', dfwidget.SelectWidget(multiple=True,
size=len(departments), size=len(departments),
@ -284,7 +277,7 @@ class EmployeeView(MasterView):
person = employee.person if employee else None person = employee.person if employee else None
if not person: if not person:
return "" return ""
text = six.text_type(person) text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid) url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -293,8 +286,8 @@ class EmployeeView(MasterView):
if not stores: if not stores:
return "" return ""
items = [] items = []
for store in sorted(stores, key=six.text_type): for store in sorted(stores, key=str):
items.append(HTML.tag('li', c=six.text_type(store))) items.append(HTML.tag('li', c=str(store)))
return HTML.tag('ul', c=items) return HTML.tag('ul', c=items)
def render_departments(self, employee, field): def render_departments(self, employee, field):
@ -302,8 +295,8 @@ class EmployeeView(MasterView):
if not departments: if not departments:
return "" return ""
items = [] items = []
for department in sorted(departments, key=six.text_type): for department in sorted(departments, key=str):
items.append(HTML.tag('li', c=six.text_type(department))) items.append(HTML.tag('li', c=str(department)))
return HTML.tag('ul', c=items) return HTML.tag('ul', c=items)
def touch_instance(self, employee): def touch_instance(self, employee):

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,9 +24,6 @@
Feature views Feature views
""" """
from __future__ import unicode_literals, absolute_import
import six
import colander import colander
import markdown import markdown
@ -49,20 +46,16 @@ class GenerateFeatureView(View):
return handler return handler
def __call__(self): def __call__(self):
use_buefy = self.get_use_buefy()
schema = self.handler.make_schema() schema = self.handler.make_schema()
app_form = forms.Form(schema=schema, request=self.request, app_form = forms.Form(schema=schema, request=self.request)
use_buefy=use_buefy) for key, value in self.handler.get_defaults().items():
for key, value in six.iteritems(self.handler.get_defaults()):
app_form.set_default(key, value) app_form.set_default(key, value)
feature_forms = {} feature_forms = {}
for feature in self.handler.iter_features(): for feature in self.handler.iter_features():
schema = feature.make_schema() schema = feature.make_schema()
form = forms.Form(schema=schema, request=self.request, form = forms.Form(schema=schema, request=self.request)
use_buefy=use_buefy) for key, value in feature.get_defaults().items():
for key, value in six.iteritems(feature.get_defaults()):
form.set_default(key, value) form.set_default(key, value)
feature_forms[feature.feature_key] = form feature_forms[feature.feature_key] = form
@ -86,7 +79,6 @@ class GenerateFeatureView(View):
context = { context = {
'index_title': "Generate Feature", 'index_title': "Generate Feature",
'handler': self.handler, 'handler': self.handler,
'use_buefy': use_buefy,
'app_form': app_form, 'app_form': app_form,
'feature_type': feature_type, 'feature_type': feature_type,
'feature_forms': feature_forms, 'feature_forms': feature_forms,

View file

@ -24,8 +24,6 @@
View for running arbitrary import/export jobs View for running arbitrary import/export jobs
""" """
from __future__ import unicode_literals, absolute_import
import getpass import getpass
import socket import socket
import sys import sys
@ -34,7 +32,6 @@ import subprocess
import time import time
import json import json
import six
import sqlalchemy as sa import sqlalchemy as sa
from rattail.exceptions import ConfigurationError from rattail.exceptions import ConfigurationError
@ -222,7 +219,7 @@ class ImportingView(MasterView):
try: try:
return self.do_runjob(handler_info, form) return self.do_runjob(handler_info, form)
except Exception as error: except Exception as error:
self.request.session.flash(six.text_type(error), 'error') self.request.session.flash(str(error), 'error')
return self.redirect(self.request.current_route_url()) return self.redirect(self.request.current_route_url())
return self.render_to_response('runjob', { return self.render_to_response('runjob', {
@ -274,7 +271,6 @@ class ImportingView(MasterView):
handler = handler_info['_handler'] handler = handler_info['_handler']
defaults = { defaults = {
'request': self.request, 'request': self.request,
'use_buefy': self.get_use_buefy(),
'model_instance': handler, 'model_instance': handler,
'cancel_url': self.request.route_url('{}.view'.format(route_prefix), 'cancel_url': self.request.route_url('{}.view'.format(route_prefix),
key=handler.get_key()), key=handler.get_key()),
@ -411,8 +407,7 @@ And here is the output:
data = json.dumps({ data = json.dumps({
'everything_complete': True, 'everything_complete': True,
}) })
if six.PY3: data = data.encode('utf_8')
data = data.encode('utf_8')
cxn.send(data) cxn.send(data)
cxn.send(suffix) cxn.send(suffix)
cxn.close() cxn.close()

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,8 +24,6 @@
Label Profile Views Label Profile Views
""" """
from __future__ import unicode_literals, absolute_import
from rattail.db import model from rattail.db import model
import colander import colander
@ -93,7 +91,6 @@ class LabelProfileView(MasterView):
pass pass
def make_printer_settings_form(self, profile, printer): def make_printer_settings_form(self, profile, printer):
use_buefy = self.get_use_buefy()
schema = colander.Schema() schema = colander.Schema()
for name, label in printer.required_settings.items(): for name, label in printer.required_settings.items():
@ -104,7 +101,6 @@ class LabelProfileView(MasterView):
schema.add(node) schema.add(node)
form = forms.Form(schema=schema, request=self.request, form = forms.Form(schema=schema, request=self.request,
use_buefy=use_buefy,
model_instance=profile, model_instance=profile,
# TODO: ugh, this is necessary to avoid some logic # TODO: ugh, this is necessary to avoid some logic
# which assumes a ColanderAlchemy schema i think? # which assumes a ColanderAlchemy schema i think?

View file

@ -24,15 +24,12 @@
Views for Luigi Views for Luigi
""" """
from __future__ import unicode_literals, absolute_import
import json import json
import logging import logging
import os import os
import re import re
import shlex import shlex
import six
import sqlalchemy as sa import sqlalchemy as sa
from rattail.util import simple_error from rattail.util import simple_error
@ -81,7 +78,6 @@ class LuigiTaskView(MasterView):
luigi_url = self.rattail_config.get('rattail.luigi', 'url') luigi_url = self.rattail_config.get('rattail.luigi', 'url')
history_url = '{}/history'.format(luigi_url.rstrip('/')) if luigi_url else None history_url = '{}/history'.format(luigi_url.rstrip('/')) if luigi_url else None
return self.render_to_response('index', { return self.render_to_response('index', {
'use_buefy': self.get_use_buefy(),
'index_url': None, 'index_url': None,
'luigi_url': luigi_url, 'luigi_url': luigi_url,
'luigi_history_url': history_url, 'luigi_history_url': history_url,
@ -169,7 +165,7 @@ class LuigiTaskView(MasterView):
tasks = [] tasks = []
for task in tasks: for task in tasks:
if task['last_date']: if task['last_date']:
task['last_date'] = six.text_type(task['last_date']) task['last_date'] = str(task['last_date'])
return tasks return tasks
def get_backfill_tasks(self): def get_backfill_tasks(self):
@ -179,9 +175,9 @@ class LuigiTaskView(MasterView):
tasks = [] tasks = []
for task in tasks: for task in tasks:
if task['last_date']: if task['last_date']:
task['last_date'] = six.text_type(task['last_date']) task['last_date'] = str(task['last_date'])
if task['target_date']: if task['target_date']:
task['target_date'] = six.text_type(task['target_date']) task['target_date'] = str(task['target_date'])
return tasks return tasks
def configure_gather_settings(self, data): def configure_gather_settings(self, data):
@ -224,7 +220,7 @@ class LuigiTaskView(MasterView):
{'name': 'rattail.luigi.backfill.task.{}.notes'.format(key), {'name': 'rattail.luigi.backfill.task.{}.notes'.format(key),
'value': task['notes']}, 'value': task['notes']},
{'name': 'rattail.luigi.backfill.task.{}.target_date'.format(key), {'name': 'rattail.luigi.backfill.task.{}.target_date'.format(key),
'value': six.text_type(task['target_date'])}, 'value': str(task['target_date'])},
]) ])
if keys: if keys:
settings.append({'name': 'rattail.luigi.backfill.tasks', settings.append({'name': 'rattail.luigi.backfill.tasks',

View file

@ -24,8 +24,6 @@
Model Master View Model Master View
""" """
from __future__ import unicode_literals, absolute_import
import os import os
import csv import csv
import datetime import datetime
@ -252,7 +250,7 @@ class MasterView(View):
def set_labels(self, obj): def set_labels(self, obj):
labels = self.collect_labels() labels = self.collect_labels()
for key, label in six.iteritems(labels): for key, label in labels.items():
obj.set_label(key, label) obj.set_label(key, label)
def collect_labels(self): def collect_labels(self):
@ -283,7 +281,7 @@ class MasterView(View):
def set_row_labels(self, obj): def set_row_labels(self, obj):
labels = self.collect_row_labels() labels = self.collect_row_labels()
for key, label in six.iteritems(labels): for key, label in labels.items():
obj.set_label(key, label) obj.set_label(key, label)
def collect_row_labels(self): def collect_row_labels(self):
@ -333,7 +331,6 @@ class MasterView(View):
""" """
self.listing = True self.listing = True
grid = self.make_grid() grid = self.make_grid()
use_buefy = self.get_use_buefy()
# If user just refreshed the page with a reset instruction, issue a # If user just refreshed the page with a reset instruction, issue a
# redirect in order to clear out the query string. # redirect in order to clear out the query string.
@ -346,14 +343,9 @@ class MasterView(View):
# return grid only, if partial page was requested # return grid only, if partial page was requested
if self.request.params.get('partial'): if self.request.params.get('partial'):
if use_buefy: # render grid data only, as JSON
# render grid data only, as JSON return render_to_response('json', grid.get_buefy_data(),
return render_to_response('json', grid.get_buefy_data(), request=self.request)
request=self.request)
else: # just do traditional thing, render grid HTML
self.request.response.content_type = str('text/html')
self.request.response.text = grid.render_grid()
return self.request.response
context = { context = {
'grid': grid, 'grid': grid,
@ -552,17 +544,16 @@ class MasterView(View):
if self.has_rows and 'main_actions' not in defaults: if self.has_rows and 'main_actions' not in defaults:
actions = [] actions = []
use_buefy = self.get_use_buefy()
# view action # view action
if self.rows_viewable: if self.rows_viewable:
icon = 'eye' if use_buefy else 'zoomin' actions.append(self.make_action('view', icon='eye',
actions.append(self.make_action('view', icon=icon, url=self.row_view_action_url)) url=self.row_view_action_url))
# edit action # edit action
if self.rows_editable and self.has_perm('edit_row'): if self.rows_editable and self.has_perm('edit_row'):
icon = 'edit' if use_buefy else 'pencil' actions.append(self.make_action('edit', icon='edit',
actions.append(self.make_action('edit', icon=icon, url=self.row_edit_action_url)) url=self.row_edit_action_url))
# delete action # delete action
if self.rows_deletable and self.has_perm('delete_row'): if self.rows_deletable and self.has_perm('delete_row'):
@ -626,7 +617,6 @@ class MasterView(View):
Return a dictionary of kwargs to be passed to the factory when Return a dictionary of kwargs to be passed to the factory when
constructing a new version grid. constructing a new version grid.
""" """
use_buefy = self.get_use_buefy()
instance = kwargs.get('instance') or self.get_instance() instance = kwargs.get('instance') or self.get_instance()
route = '{}.version'.format(self.get_route_prefix()) route = '{}.version'.format(self.get_route_prefix())
defaults = { defaults = {
@ -638,7 +628,7 @@ class MasterView(View):
if 'main_actions' not in kwargs: if 'main_actions' not in kwargs:
url = lambda txn, i: self.request.route_url(route, uuid=instance.uuid, txnid=txn.id) url = lambda txn, i: self.request.route_url(route, uuid=instance.uuid, txnid=txn.id)
defaults['main_actions'] = [ defaults['main_actions'] = [
self.make_action('view', icon='eye' if use_buefy else 'zoomin', url=url), self.make_action('view', icon='eye', url=url),
] ]
defaults.update(kwargs) defaults.update(kwargs)
return defaults return defaults
@ -735,11 +725,10 @@ class MasterView(View):
delete=False, schema=None, importer_host_title=None): delete=False, schema=None, importer_host_title=None):
handler = handler_factory(self.rattail_config) handler = handler_factory(self.rattail_config)
use_buefy = self.get_use_buefy()
if not schema: if not schema:
schema = forms.SimpleFileImport().bind(request=self.request) schema = forms.SimpleFileImport().bind(request=self.request)
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy) form = forms.Form(schema=schema, request=self.request)
form.save_label = "Upload" form.save_label = "Upload"
form.cancel_url = self.get_index_url() form.cancel_url = self.get_index_url()
if form.validate(newstyle=True): if form.validate(newstyle=True):
@ -771,7 +760,7 @@ class MasterView(View):
value = getattr(obj, field) value = getattr(obj, field)
if value is None: if value is None:
return "" return ""
value = six.text_type(value) value = str(value)
if len(value) > 100: if len(value) > 100:
value = value[:100] + '...' value = value[:100] + '...'
return value return value
@ -841,7 +830,7 @@ class MasterView(View):
product = getattr(obj, field) product = getattr(obj, field)
if not product: if not product:
return "" return ""
text = six.text_type(product) text = str(product)
url = self.request.route_url('products.view', uuid=product.uuid) url = self.request.route_url('products.view', uuid=product.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -849,7 +838,7 @@ class MasterView(View):
pending = getattr(obj, field) pending = getattr(obj, field)
if not pending: if not pending:
return return
text = six.text_type(pending) text = str(pending)
url = self.request.route_url('pending_products.view', uuid=pending.uuid) url = self.request.route_url('pending_products.view', uuid=pending.uuid)
return tags.link_to(text, url, return tags.link_to(text, url,
class_='has-background-warning') class_='has-background-warning')
@ -862,7 +851,7 @@ class MasterView(View):
if short: if short:
text = "({}) {}".format(short, vendor.name) text = "({}) {}".format(short, vendor.name)
else: else:
text = six.text_type(vendor) text = str(vendor)
url = self.request.route_url('vendors.view', uuid=vendor.uuid) url = self.request.route_url('vendors.view', uuid=vendor.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -918,7 +907,7 @@ class MasterView(View):
person = getattr(obj, field) person = getattr(obj, field)
if not person: if not person:
return "" return ""
text = six.text_type(person) text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid) url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -926,7 +915,7 @@ class MasterView(View):
person = getattr(obj, field) person = getattr(obj, field)
if not person: if not person:
return "" return ""
text = six.text_type(person) text = str(person)
url = self.request.route_url('people.view_profile', uuid=person.uuid) url = self.request.route_url('people.view_profile', uuid=person.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -934,7 +923,7 @@ class MasterView(View):
user = getattr(obj, field) user = getattr(obj, field)
if not user: if not user:
return "" return ""
text = six.text_type(user) text = str(user)
url = self.request.route_url('users.view', uuid=user.uuid) url = self.request.route_url('users.view', uuid=user.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -954,7 +943,7 @@ class MasterView(View):
customer = getattr(obj, field) customer = getattr(obj, field)
if not customer: if not customer:
return "" return ""
text = six.text_type(customer) text = str(customer)
url = self.request.route_url('customers.view', uuid=customer.uuid) url = self.request.route_url('customers.view', uuid=customer.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -984,7 +973,7 @@ class MasterView(View):
value = obj.status_code value = obj.status_code
if value is None: if value is None:
return "" return ""
status_code_text = enum.get(value, six.text_type(value)) status_code_text = enum.get(value, str(value))
if obj.status_text: if obj.status_text:
return HTML.tag('span', title=obj.status_text, c=status_code_text) return HTML.tag('span', title=obj.status_text, c=status_code_text)
return status_code_text return status_code_text
@ -1072,7 +1061,6 @@ class MasterView(View):
View for viewing details of an existing model record. View for viewing details of an existing model record.
""" """
self.viewing = True self.viewing = True
use_buefy = self.get_use_buefy()
if instance is None: if instance is None:
instance = self.get_instance() instance = self.get_instance()
form = self.make_form(instance) form = self.make_form(instance)
@ -1090,14 +1078,9 @@ class MasterView(View):
# return grid only, if partial page was requested # return grid only, if partial page was requested
if self.request.params.get('partial'): if self.request.params.get('partial'):
if use_buefy: # render grid data only, as JSON
# render grid data only, as JSON return render_to_response('json', grid.get_buefy_data(),
return render_to_response('json', grid.get_buefy_data(), request=self.request)
request=self.request)
else: # just do traditional thing, render grid HTML
self.request.response.content_type = str('text/html')
self.request.response.text = grid.render_grid()
return self.request.response
context = { context = {
'instance': instance, 'instance': instance,
@ -1112,12 +1095,8 @@ class MasterView(View):
context['dform'] = form.make_deform_form() context['dform'] = form.make_deform_form()
if self.has_rows: if self.has_rows:
if use_buefy: context['rows_grid'] = grid
context['rows_grid'] = grid context['rows_grid_tools'] = HTML(self.make_row_grid_tools(instance) or '').strip()
context['rows_grid_tools'] = HTML(self.make_row_grid_tools(instance) or '').strip()
else:
context['rows_grid'] = grid.render_complete(allow_save_defaults=False,
tools=self.make_row_grid_tools(instance))
return self.render_to_response('view', context) return self.render_to_response('view', context)
@ -1224,18 +1203,12 @@ class MasterView(View):
instance = self.get_instance() instance = self.get_instance()
instance_title = self.get_instance_title(instance) instance_title = self.get_instance_title(instance)
grid = self.make_version_grid(instance=instance) grid = self.make_version_grid(instance=instance)
use_buefy = self.get_use_buefy()
# return grid only, if partial page was requested # return grid only, if partial page was requested
if self.request.params.get('partial'): if self.request.params.get('partial'):
if use_buefy: # render grid data only, as JSON
# render grid data only, as JSON return render_to_response('json', grid.get_buefy_data(),
return render_to_response('json', grid.get_buefy_data(), request=self.request)
request=self.request)
else: # just do traditional thing, render grid HTML
self.request.response.content_type = str('text/html')
self.request.response.text = grid.render_grid()
return self.request.response
return self.render_to_response('versions', { return self.render_to_response('versions', {
'instance': instance, 'instance': instance,
@ -1567,15 +1540,10 @@ class MasterView(View):
response.content_length = os.path.getsize(path) response.content_length = os.path.getsize(path)
content_type = self.download_content_type(path, filename) content_type = self.download_content_type(path, filename)
if content_type: if content_type:
if six.PY3: response.content_type = content_type
response.content_type = content_type
else:
response.content_type = six.binary_type(content_type)
# content-disposition # content-disposition
filename = os.path.basename(path) filename = os.path.basename(path)
if six.PY2:
filename = filename.encode('ascii', 'replace')
response.content_disposition = str('attachment; filename="{}"'.format(filename)) response.content_disposition = str('attachment; filename="{}"'.format(filename))
return response return response
@ -1986,8 +1954,7 @@ class MasterView(View):
# strip suffix, interpret data as JSON # strip suffix, interpret data as JSON
data = data[:-len(suffix)] data = data[:-len(suffix)]
if six.PY3: data = data.decode('utf_8')
data = data.decode('utf_8')
data = json.loads(data) data = json.loads(data)
if data.get('everything_complete'): if data.get('everything_complete'):
@ -2056,7 +2023,7 @@ class MasterView(View):
object_to_keep = self.Session.query(self.get_model_class()).get(uuids[1]) object_to_keep = self.Session.query(self.get_model_class()).get(uuids[1])
if object_to_remove and object_to_keep and self.request.POST.get('commit-merge') == 'yes': if object_to_remove and object_to_keep and self.request.POST.get('commit-merge') == 'yes':
msg = six.text_type(object_to_remove) msg = str(object_to_remove)
try: try:
self.validate_merge(object_to_remove, object_to_keep) self.validate_merge(object_to_remove, object_to_keep)
except Exception as error: except Exception as error:
@ -2166,7 +2133,7 @@ class MasterView(View):
""" """
if hasattr(cls, 'model_key'): if hasattr(cls, 'model_key'):
keys = cls.model_key keys = cls.model_key
if isinstance(keys, six.string_types): if isinstance(keys, str):
keys = [keys] keys = [keys]
else: else:
keys = get_primary_keys(cls.get_model_class()) keys = get_primary_keys(cls.get_model_class())
@ -2399,7 +2366,6 @@ class MasterView(View):
""" """
context = { context = {
'master': self, 'master': self,
'use_buefy': self.get_use_buefy(),
'model_title': self.get_model_title(), 'model_title': self.get_model_title(),
'model_title_plural': self.get_model_title_plural(), 'model_title_plural': self.get_model_title_plural(),
'route_prefix': self.get_route_prefix(), 'route_prefix': self.get_route_prefix(),
@ -2699,7 +2665,7 @@ class MasterView(View):
# nb. unfortunately HTML.tag() calls its first arg 'tag' and # nb. unfortunately HTML.tag() calls its first arg 'tag' and
# so we can't pass a kwarg with that name...so instead we # so we can't pass a kwarg with that name...so instead we
# patch that into place manually # patch that into place manually
button = six.text_type(button) button = str(button)
button = button.replace('<b-button ', button = button.replace('<b-button ',
'<b-button tag="a"') '<b-button tag="a"')
button = HTML.literal(button) button = HTML.literal(button)
@ -2733,7 +2699,7 @@ class MasterView(View):
btn_kw['icon_left'] = 'external-link-alt' btn_kw['icon_left'] = 'external-link-alt'
btn_kw['target'] = '_blank' btn_kw['target'] = '_blank'
button = HTML.tag('b-button', **btn_kw) button = HTML.tag('b-button', **btn_kw)
button = six.text_type(button) button = str(button)
button = button.replace('<b-button ', button = button.replace('<b-button ',
'<b-button tag="a"') '<b-button tag="a"')
button = HTML.literal(button) button = HTML.literal(button)
@ -2840,9 +2806,7 @@ class MasterView(View):
return actions return actions
def make_grid_action_view(self): def make_grid_action_view(self):
use_buefy = self.get_use_buefy() return self.make_action('view', icon='eye', url=self.default_view_url())
icon = 'eye' if use_buefy else 'zoomin'
return self.make_action('view', icon=icon, url=self.default_view_url())
def default_view_url(self): def default_view_url(self):
if self.use_index_links: if self.use_index_links:
@ -2869,18 +2833,15 @@ class MasterView(View):
return actions return actions
def make_grid_action_edit(self): def make_grid_action_edit(self):
use_buefy = self.get_use_buefy() return self.make_action('edit', icon='edit', url=self.default_edit_url)
icon = 'edit' if use_buefy else 'pencil'
return self.make_action('edit', icon=icon, url=self.default_edit_url)
def make_grid_action_clone(self): def make_grid_action_clone(self):
return self.make_action('clone', icon='object-ungroup', return self.make_action('clone', icon='object-ungroup',
url=self.default_clone_url) url=self.default_clone_url)
def make_grid_action_delete(self): def make_grid_action_delete(self):
use_buefy = self.get_use_buefy()
kwargs = {} kwargs = {}
if use_buefy and self.delete_confirm == 'simple': if self.delete_confirm == 'simple':
kwargs['click_handler'] = 'deleteObject' kwargs['click_handler'] = 'deleteObject'
return self.make_action('delete', icon='trash', url=self.default_delete_url, **kwargs) return self.make_action('delete', icon='trash', url=self.default_delete_url, **kwargs)
@ -2917,7 +2878,7 @@ class MasterView(View):
mapper = orm.object_mapper(row) mapper = orm.object_mapper(row)
except orm.exc.UnmappedInstanceError: except orm.exc.UnmappedInstanceError:
try: try:
if isinstance(self.model_key, six.string_types): if isinstance(self.model_key, str):
return {self.model_key: row[self.model_key]} return {self.model_key: row[self.model_key]}
return dict([(key, row[key]) return dict([(key, row[key])
for key in self.model_key]) for key in self.model_key])
@ -3134,12 +3095,8 @@ class MasterView(View):
""" """
if fmt == 'csv': if fmt == 'csv':
if six.PY2: csv_file = open(path, 'wt', encoding='utf_8')
csv_file = open(path, 'wb') writer = csv.DictWriter(csv_file, fields)
writer = UnicodeDictWriter(csv_file, fields, encoding='utf_8')
else: # PY3
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
writer.writeheader() writer.writeheader()
def write(obj, i): def write(obj, i):
@ -3229,7 +3186,7 @@ class MasterView(View):
if value is None: if value is None:
value = '' value = ''
else: else:
value = six.text_type(value) value = str(value)
csvrow[field] = value csvrow[field] = value
@ -3297,13 +3254,8 @@ class MasterView(View):
results = results.with_session(session).all() results = results.with_session(session).all()
fields = self.get_csv_fields() fields = self.get_csv_fields()
if six.PY2: csv_file = open(path, 'wt', encoding='utf_8')
csv_file = open(path, 'wb') writer = csv.DictWriter(csv_file, fields)
writer = UnicodeDictWriter(csv_file, fields, encoding='utf_8')
else: # PY3
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
writer.writeheader() writer.writeheader()
def write(obj, i): def write(obj, i):
@ -3663,12 +3615,8 @@ class MasterView(View):
if fmt == 'csv': if fmt == 'csv':
if six.PY2: csv_file = open(path, 'wt', encoding='utf_8')
csv_file = open(path, 'wb') writer = csv.DictWriter(csv_file, fields)
writer = UnicodeDictWriter(csv_file, fields, encoding='utf_8')
else: # PY3
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
writer.writeheader() writer.writeheader()
def write(obj, i): def write(obj, i):
@ -3737,7 +3685,7 @@ class MasterView(View):
if value is None: if value is None:
value = '' value = ''
else: else:
value = six.text_type(value) value = str(value)
csvrow[field] = value csvrow[field] = value
@ -3814,7 +3762,7 @@ class MasterView(View):
value = getattr(row, field, None) value = getattr(row, field, None)
if isinstance(value, GPC): if isinstance(value, GPC):
value = six.text_type(value) value = str(value)
elif isinstance(value, datetime.datetime): elif isinstance(value, datetime.datetime):
# datetime values we provide to Excel must *not* have time zone info, # datetime values we provide to Excel must *not* have time zone info,
@ -3844,14 +3792,9 @@ class MasterView(View):
writer.writerow(self.get_row_csv_row(row, fields)) writer.writerow(self.get_row_csv_row(row, fields))
response = self.request.response response = self.request.response
filename = self.get_row_results_csv_filename(obj) filename = self.get_row_results_csv_filename(obj)
if six.PY3: response.text = data.getvalue()
response.text = data.getvalue() response.content_type = 'text/csv'
response.content_type = 'text/csv' response.content_disposition = 'attachment; filename={}'.format(filename)
response.content_disposition = 'attachment; filename={}'.format(filename)
else:
response.body = data.getvalue()
response.content_type = b'text/csv'
response.content_disposition = b'attachment; filename={}'.format(filename)
data.close() data.close()
response.content_length = len(response.body) response.content_length = len(response.body)
return response return response
@ -3898,7 +3841,7 @@ class MasterView(View):
if isinstance(value, datetime.datetime): if isinstance(value, datetime.datetime):
# TODO: this assumes value is *always* naive UTC # TODO: this assumes value is *always* naive UTC
value = localtime(self.rattail_config, value, from_utc=True) value = localtime(self.rattail_config, value, from_utc=True)
csvrow[field] = '' if value is None else six.text_type(value) csvrow[field] = '' if value is None else str(value)
return csvrow return csvrow
def get_row_csv_row(self, row, fields): def get_row_csv_row(self, row, fields):
@ -3911,7 +3854,7 @@ class MasterView(View):
if isinstance(value, datetime.datetime): if isinstance(value, datetime.datetime):
# TODO: this assumes value is *always* naive UTC # TODO: this assumes value is *always* naive UTC
value = localtime(self.rattail_config, value, from_utc=True) value = localtime(self.rattail_config, value, from_utc=True)
csvrow[field] = '' if value is None else six.text_type(value) csvrow[field] = '' if value is None else str(value)
return csvrow return csvrow
############################## ##############################
@ -3966,7 +3909,7 @@ class MasterView(View):
""" """
Return a "pretty" title for the instance, to be used in the page title etc. Return a "pretty" title for the instance, to be used in the page title etc.
""" """
return six.text_type(instance) return str(instance)
@classmethod @classmethod
def get_form_factory(cls): def get_form_factory(cls):
@ -4078,7 +4021,6 @@ class MasterView(View):
'readonly': self.viewing, 'readonly': self.viewing,
'model_class': getattr(self, 'model_class', None), 'model_class': getattr(self, 'model_class', None),
'action_url': self.request.current_route_url(_query=None), 'action_url': self.request.current_route_url(_query=None),
'use_buefy': self.get_use_buefy(),
'assume_local_times': self.has_local_times, 'assume_local_times': self.has_local_times,
'route_prefix': route_prefix, 'route_prefix': route_prefix,
'can_edit_help': (self.has_perm('edit_help') 'can_edit_help': (self.has_perm('edit_help')
@ -4547,7 +4489,6 @@ class MasterView(View):
'readonly': self.viewing, 'readonly': self.viewing,
'model_class': getattr(self, 'model_row_class', None), 'model_class': getattr(self, 'model_row_class', None),
'action_url': self.request.current_route_url(_query=None), 'action_url': self.request.current_route_url(_query=None),
'use_buefy': self.get_use_buefy(),
} }
if self.creating: if self.creating:
kwargs.setdefault('cancel_url', self.request.get_referrer()) kwargs.setdefault('cancel_url', self.request.get_referrer())
@ -4644,7 +4585,7 @@ class MasterView(View):
# collect any uploaded files # collect any uploaded files
uploads = {} uploads = {}
for key, value in six.iteritems(data): for key, value in data.items():
if isinstance(value, cgi_FieldStorage): if isinstance(value, cgi_FieldStorage):
tempdir = tempfile.mkdtemp() tempdir = tempfile.mkdtemp()
filename = os.path.basename(value.filename) filename = os.path.basename(value.filename)
@ -4829,13 +4770,13 @@ class MasterView(View):
value = data.get(name) value = data.get(name)
if simple.get('type') is bool: if simple.get('type') is bool:
value = six.text_type(bool(value)).lower() value = str(bool(value)).lower()
elif simple.get('type') is int: elif simple.get('type') is int:
value = six.text_type(int(value or '0')) value = str(int(value or '0'))
elif value is None: elif value is None:
value = '' value = ''
else: else:
value = six.text_type(value) value = str(value)
# only want to save this setting if we received a # only want to save this setting if we received a
# value, or if empty values are okay to save # value, or if empty values are okay to save

View file

@ -24,8 +24,6 @@
Base class for Config Views Base class for Config Views
""" """
from __future__ import unicode_literals, absolute_import
import json import json
import sqlalchemy as sa import sqlalchemy as sa
@ -62,7 +60,6 @@ class MenuConfigView(View):
context = { context = {
'config_title': "Menus", 'config_title': "Menus",
'use_buefy': True,
'index_title': "App Details", 'index_title': "App Details",
'index_url': self.request.route_url('appinfo'), 'index_url': self.request.route_url('appinfo'),
} }

View file

@ -24,10 +24,6 @@
Message Views Message Views
""" """
from __future__ import unicode_literals, absolute_import
import six
from rattail.db import model from rattail.db import model
from rattail.time import localtime from rattail.time import localtime
@ -139,7 +135,7 @@ class MessageView(MasterView):
sender = message.sender sender = message.sender
if sender is self.request.user: if sender is self.request.user:
return 'you' return 'you'
return six.text_type(sender) return str(sender)
def render_subject_bold(self, message, field): def render_subject_bold(self, message, field):
if not message.subject: if not message.subject:
@ -164,8 +160,6 @@ class MessageView(MasterView):
if not recipients: if not recipients:
return "" return ""
use_buefy = self.get_use_buefy()
# remove current user from displayed list, even if they're a recipient # remove current user from displayed list, even if they're a recipient
recips = [r for r in recipients recips = [r for r in recipients
if r.recipient is not self.request.user] if r.recipient is not self.request.user]
@ -182,23 +176,17 @@ class MessageView(MasterView):
# client-side JS allowing the user to view all if they want # client-side JS allowing the user to view all if they want
max_display = 5 max_display = 5
if len(recips) > max_display: if len(recips) > max_display:
if use_buefy: basic = HTML.tag('span', c="{}, ".format(', '.join(recips[:max_display-1])))
basic = HTML.tag('span', c="{}, ".format(', '.join(recips[:max_display-1]))) more = tags.link_to("({} more)".format(len(recips[max_display-1:])), '#', **{
more = tags.link_to("({} more)".format(len(recips[max_display-1:])), '#', **{ 'v-show': '!showingAllRecipients',
'v-show': '!showingAllRecipients', '@click.prevent': 'showMoreRecipients()',
'@click.prevent': 'showMoreRecipients()', })
}) everyone = HTML.tag('span', c=', '.join(recips[max_display-1:]), **{
everyone = HTML.tag('span', c=', '.join(recips[max_display-1:]), **{ 'v-show': 'showingAllRecipients',
'v-show': 'showingAllRecipients', '@click': 'hideMoreRecipients()',
'@click': 'hideMoreRecipients()', 'class_': 'everyone',
'class_': 'everyone', })
}) return HTML.tag('div', c=[basic, more, everyone])
return HTML.tag('div', c=[basic, more, everyone])
else:
basic = HTML.literal("{}, ".format(', '.join(recips[:max_display-1])))
more = tags.link_to("({} more)".format(len(recips[max_display-1:])), '#', class_='more')
everyone = HTML.tag('span', class_='everyone', c=', '.join(recips[max_display-1:]))
return basic + more + everyone
# show the full list if there are few enough recipients for that # show the full list if there are few enough recipients for that
return ', '.join(recips) return ', '.join(recips)
@ -214,15 +202,9 @@ class MessageView(MasterView):
def configure_form(self, f): def configure_form(self, f):
super(MessageView, self).configure_form(f) super(MessageView, self).configure_form(f)
use_buefy = self.get_use_buefy()
f.submit_label = "Send Message" f.submit_label = "Send Message"
if not use_buefy:
# we have custom logic to disable submit button
f.auto_disable = False
f.auto_disable_save = False
# TODO: A fair amount of this still seems hacky... # TODO: A fair amount of this still seems hacky...
f.set_renderer('sender', self.render_sender) f.set_renderer('sender', self.render_sender)
@ -235,13 +217,12 @@ class MessageView(MasterView):
f.set_label('recipients', "To") f.set_label('recipients', "To")
# subject # subject
if use_buefy: f.set_renderer('subject', self.render_subject_bold)
f.set_renderer('subject', self.render_subject_bold) if self.creating:
if self.creating: f.set_widget('subject', dfwidget.TextInputWidget(
f.set_widget('subject', dfwidget.TextInputWidget( placeholder="please enter a subject",
placeholder="please enter a subject", autocomplete='off'))
autocomplete='off')) f.set_required('subject')
f.set_required('subject')
# body # body
f.set_widget('body', dfwidget.TextAreaWidget(cols=50, rows=15)) f.set_widget('body', dfwidget.TextAreaWidget(cols=50, rows=15))
@ -253,10 +234,7 @@ class MessageView(MasterView):
f.insert_after('recipients', 'set_recipients') f.insert_after('recipients', 'set_recipients')
f.remove('recipients') f.remove('recipients')
f.set_node('set_recipients', colander.SchemaNode(colander.Set())) f.set_node('set_recipients', colander.SchemaNode(colander.Set()))
if use_buefy: f.set_widget('set_recipients', RecipientsWidgetBuefy())
f.set_widget('set_recipients', RecipientsWidgetBuefy())
else:
f.set_widget('set_recipients', RecipientsWidget())
f.set_label('set_recipients', "To") f.set_label('set_recipients', "To")
if self.replying: if self.replying:
@ -278,17 +256,11 @@ class MessageView(MasterView):
value = [r[0] for r in value] value = [r[0] for r in value]
if old_message.sender is not self.request.user and old_message.sender.active: if old_message.sender is not self.request.user and old_message.sender.active:
value.insert(0, old_message.sender_uuid) value.insert(0, old_message.sender_uuid)
if use_buefy: f.set_default('set_recipients', value)
f.set_default('set_recipients', value)
else:
f.set_default('set_recipients', ','.join(value))
# Just a normal reply, to sender only. # Just a normal reply, to sender only.
elif self.filter_reply_recipient(old_message.sender): elif self.filter_reply_recipient(old_message.sender):
if use_buefy: f.set_default('set_recipients', [old_message.sender.uuid])
f.set_default('set_recipients', [old_message.sender.uuid])
else:
f.set_default('set_recipients', old_message.sender.uuid)
# TODO? # TODO?
# # Set focus to message body instead of recipients, when replying. # # Set focus to message body instead of recipients, when replying.
@ -347,11 +319,9 @@ class MessageView(MasterView):
return recipient return recipient
def template_kwargs_create(self, **kwargs): def template_kwargs_create(self, **kwargs):
use_buefy = self.get_use_buefy()
recips = self.get_available_recipients() recips = self.get_available_recipients()
if use_buefy: kwargs['recipient_display_map'] = recips
kwargs['recipient_display_map'] = recips
recips = list(recips.items()) recips = list(recips.items())
recips.sort(key=self.recipient_sortkey) recips.sort(key=self.recipient_sortkey)
kwargs['available_recipients'] = recips kwargs['available_recipients'] = recips
@ -359,9 +329,8 @@ class MessageView(MasterView):
if self.replying: if self.replying:
kwargs['original_message'] = self.get_instance() kwargs['original_message'] = self.get_instance()
if use_buefy: kwargs['index_url'] = None
kwargs['index_url'] = None kwargs['index_title'] = "New Message"
kwargs['index_title'] = "New Message"
return kwargs return kwargs
def recipient_sortkey(self, recip): def recipient_sortkey(self, recip):
@ -538,20 +507,6 @@ class SentView(MessageView):
default_active=True, default_verb='contains') default_active=True, default_verb='contains')
class RecipientsWidget(dfwidget.TextInputWidget):
def deserialize(self, field, pstruct):
if pstruct is colander.null:
return []
elif not isinstance(pstruct, six.string_types):
raise colander.Invalid(field.schema, "Pstruct is not a string")
if self.strip:
pstruct = pstruct.strip()
if not pstruct:
return []
return pstruct.split(',')
class RecipientsWidgetBuefy(dfwidget.Widget): class RecipientsWidgetBuefy(dfwidget.Widget):
""" """
Custom "message recipients" widget, for use with Buefy / Vue.js themes. Custom "message recipients" widget, for use with Buefy / Vue.js themes.
@ -561,7 +516,7 @@ class RecipientsWidgetBuefy(dfwidget.Widget):
def deserialize(self, field, pstruct): def deserialize(self, field, pstruct):
if pstruct is colander.null: if pstruct is colander.null:
return colander.null return colander.null
if not isinstance(pstruct, six.string_types): if not isinstance(pstruct, str):
raise colander.Invalid(field.schema, "Pstruct is not a string") raise colander.Invalid(field.schema, "Pstruct is not a string")
if not pstruct: if not pstruct:
return colander.null return colander.null

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,12 +24,9 @@
Person Views Person Views
""" """
from __future__ import unicode_literals, absolute_import
import datetime import datetime
import logging import logging
import six
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import orm from sqlalchemy import orm
@ -165,13 +162,10 @@ class PersonView(MasterView):
.filter(model.MergePeopleRequest.merged == None)\ .filter(model.MergePeopleRequest.merged == None)\
.first() .first()
if merge_request: if merge_request:
use_buefy = self.get_use_buefy() return HTML.tag('span',
if use_buefy: class_='has-text-danger has-text-weight-bold',
return HTML.tag('span', title="A merge has been requested for this person.",
class_='has-text-danger has-text-weight-bold', c="MR")
title="A merge has been requested for this person.",
c="MR")
return "MR"
def get_instance(self): def get_instance(self):
# TODO: I don't recall why this fallback check for a vendor contact # TODO: I don't recall why this fallback check for a vendor contact
@ -335,7 +329,7 @@ class PersonView(MasterView):
employee = person.employee employee = person.employee
if not employee: if not employee:
return "" return ""
text = six.text_type(employee) text = str(employee)
url = self.request.route_url('employees.view', uuid=employee.uuid) url = self.request.route_url('employees.view', uuid=employee.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -346,7 +340,7 @@ class PersonView(MasterView):
items = [] items = []
for customer in customers: for customer in customers:
customer = customer.customer customer = customer.customer
text = six.text_type(customer) text = str(customer)
if customer.number: if customer.number:
text = "(#{}) {}".format(customer.number, text) text = "(#{}) {}".format(customer.number, text)
elif customer.id: elif customer.id:
@ -361,7 +355,7 @@ class PersonView(MasterView):
return "" return ""
items = [] items = []
for member in members: for member in members:
text = six.text_type(member) text = str(member)
if member.number: if member.number:
text = "(#{}) {}".format(member.number, text) text = "(#{}) {}".format(member.number, text)
elif member.id: elif member.id:
@ -371,7 +365,6 @@ class PersonView(MasterView):
return HTML.tag('ul', c=items) return HTML.tag('ul', c=items)
def render_users(self, person, field): def render_users(self, person, field):
use_buefy = self.get_use_buefy()
users = person.users users = person.users
items = [] items = []
for user in users: for user in users:
@ -381,11 +374,8 @@ class PersonView(MasterView):
if items: if items:
return HTML.tag('ul', c=items) return HTML.tag('ul', c=items)
elif self.viewing and self.request.has_perm('users.create'): elif self.viewing and self.request.has_perm('users.create'):
if use_buefy: return HTML.tag('b-button', type='is-primary', c="Make User",
return HTML.tag('b-button', type='is-primary', c="Make User", **{'@click': 'clickMakeUser()'})
**{'@click': 'clickMakeUser()'})
else:
return HTML.tag('button', type='button', id='make-user', c="Make User")
else: else:
return "" return ""
@ -428,8 +418,7 @@ class PersonView(MasterView):
'dynamic_content_title': self.get_context_content_title(person), 'dynamic_content_title': self.get_context_content_title(person),
} }
use_buefy = self.get_use_buefy() template = 'view_profile_buefy'
template = 'view_profile_buefy' if use_buefy else 'view_profile'
return self.render_to_response(template, context) return self.render_to_response(template, context)
def get_customer_xref_buttons(self, person): def get_customer_xref_buttons(self, person):
@ -524,7 +513,7 @@ class PersonView(MasterView):
return context return context
def get_context_content_title(self, person): def get_context_content_title(self, person):
return six.text_type(person) return str(person)
def get_context_address(self, address): def get_context_address(self, address):
context = { context = {
@ -534,7 +523,7 @@ class PersonView(MasterView):
'city': address.city, 'city': address.city,
'state': address.state, 'state': address.state,
'zipcode': address.zipcode, 'zipcode': address.zipcode,
'display': six.text_type(address), 'display': str(address),
} }
model = self.model model = self.model
@ -587,12 +576,12 @@ class PersonView(MasterView):
'number': member.number, 'number': member.number,
'id': member.id, 'id': member.id,
'active': member.active, 'active': member.active,
'joined': six.text_type(member.joined) if member.joined else None, 'joined': str(member.joined) if member.joined else None,
'withdrew': six.text_type(member.withdrew) if member.withdrew else None, 'withdrew': str(member.withdrew) if member.withdrew else None,
'customer_uuid': member.customer_uuid, 'customer_uuid': member.customer_uuid,
'customer_name': member.customer.name if member.customer else None, 'customer_name': member.customer.name if member.customer else None,
'person_uuid': member.person_uuid, 'person_uuid': member.person_uuid,
'display': six.text_type(member), 'display': str(member),
'person_display_name': member.person.display_name if member.person else None, 'person_display_name': member.person.display_name if member.person else None,
'view_url': self.request.route_url('members.view', uuid=member.uuid), 'view_url': self.request.route_url('members.view', uuid=member.uuid),
'view_profile_url': profile_url, 'view_profile_url': profile_url,
@ -614,8 +603,8 @@ class PersonView(MasterView):
for history in employee.sorted_history(reverse=True): for history in employee.sorted_history(reverse=True):
data.append({ data.append({
'uuid': history.uuid, 'uuid': history.uuid,
'start_date': six.text_type(history.start_date), 'start_date': str(history.start_date),
'end_date': six.text_type(history.end_date or ''), 'end_date': str(history.end_date or ''),
}) })
return data return data
@ -911,7 +900,7 @@ class PersonView(MasterView):
'success': True, 'success': True,
'employee': self.get_context_employee(employee), 'employee': self.get_context_employee(employee),
'employee_view_url': self.request.route_url('employees.view', uuid=employee.uuid), 'employee_view_url': self.request.route_url('employees.view', uuid=employee.uuid),
'start_date': six.text_type(start_date), 'start_date': str(start_date),
'employee_history_data': self.get_context_employee_history(employee), 'employee_history_data': self.get_context_employee_history(employee),
'dynamic_content_title': self.get_context_content_title(person), 'dynamic_content_title': self.get_context_content_title(person),
} }
@ -942,7 +931,7 @@ class PersonView(MasterView):
'success': True, 'success': True,
'employee': self.get_context_employee(employee), 'employee': self.get_context_employee(employee),
'employee_view_url': self.request.route_url('employees.view', uuid=employee.uuid), 'employee_view_url': self.request.route_url('employees.view', uuid=employee.uuid),
'end_date': six.text_type(end_date), 'end_date': str(end_date),
'employee_history_data': self.get_context_employee_history(employee), 'employee_history_data': self.get_context_employee_history(employee),
'dynamic_content_title': self.get_context_content_title(person), 'dynamic_content_title': self.get_context_content_title(person),
} }
@ -975,8 +964,8 @@ class PersonView(MasterView):
return { return {
'success': True, 'success': True,
'employee': self.get_context_employee(employee), 'employee': self.get_context_employee(employee),
'start_date': six.text_type(current_history.start_date), 'start_date': str(current_history.start_date),
'end_date': six.text_type(current_history.end_date or ''), 'end_date': str(current_history.end_date or ''),
'employee_history_data': self.get_context_employee_history(employee), 'employee_history_data': self.get_context_employee_history(employee),
} }
@ -1438,7 +1427,7 @@ class MergePeopleRequestView(MasterView):
uuid = getattr(merge_request, field) uuid = getattr(merge_request, field)
person = self.Session.query(self.model.Person).get(uuid) person = self.Session.query(self.model.Person).get(uuid)
if person: if person:
return six.text_type(person) return str(person)
return "(person not found)" return "(person not found)"
def get_instance_title(self, merge_request): def get_instance_title(self, merge_request):
@ -1459,7 +1448,7 @@ class MergePeopleRequestView(MasterView):
uuid = getattr(merge_request, field) uuid = getattr(merge_request, field)
person = self.Session.query(self.model.Person).get(uuid) person = self.Session.query(self.model.Person).get(uuid)
if person: if person:
text = six.text_type(person) text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid) url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
return "(person not found)" return "(person not found)"

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,8 +24,6 @@
"Principal" master view "Principal" master view
""" """
from __future__ import unicode_literals, absolute_import
import copy import copy
from rattail.core import Object from rattail.core import Object
@ -85,12 +83,11 @@ class PrincipalMasterView(MasterView):
context = {'form': form, 'permissions': sorted_perms, 'principals': principals} context = {'form': form, 'permissions': sorted_perms, 'principals': principals}
if self.get_use_buefy(): perms = self.get_buefy_perms_data(sorted_perms)
perms = self.get_buefy_perms_data(sorted_perms) context['buefy_perms'] = perms
context['buefy_perms'] = perms context['buefy_sorted_groups'] = list(perms)
context['buefy_sorted_groups'] = list(perms) context['selected_group'] = self.request.POST.get('permission_group', 'common')
context['selected_group'] = self.request.POST.get('permission_group', 'common') context['selected_permission'] = self.request.POST.get('permission', None)
context['selected_permission'] = self.request.POST.get('permission', None)
return self.render_to_response('find_by_perm', context) return self.render_to_response('find_by_perm', context)

View file

@ -24,12 +24,9 @@
Product Views Product Views
""" """
from __future__ import unicode_literals, absolute_import
import re import re
import logging import logging
import six
import humanize import humanize
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import orm from sqlalchemy import orm
@ -212,7 +209,6 @@ class ProductView(MasterView):
super(ProductView, self).configure_grid(g) super(ProductView, self).configure_grid(g)
app = self.get_rattail_app() app = self.get_rattail_app()
model = self.model model = self.model
use_buefy = self.get_use_buefy()
def join_vendor(q): def join_vendor(q):
return q.outerjoin(self.ProductVendorCost, return q.outerjoin(self.ProductVendorCost,
@ -257,9 +253,6 @@ class ProductView(MasterView):
departments = self.get_departments() departments = self.get_departments()
department_choices = OrderedDict([('', "(any)")] department_choices = OrderedDict([('', "(any)")]
+ [(d.uuid, d.name) for d in departments]) + [(d.uuid, d.name) for d in departments])
if not use_buefy:
department_choices = [tags.Option(name, uuid)
for uuid, name in six.iteritems(department_choices)]
g.set_filter('department', model.Department.uuid, g.set_filter('department', model.Department.uuid,
value_enum=department_choices, value_enum=department_choices,
verbs=['equal', 'not_equal', 'is_null', 'is_not_null', 'is_any'], verbs=['equal', 'not_equal', 'is_null', 'is_not_null', 'is_any'],
@ -378,12 +371,9 @@ class ProductView(MasterView):
g.set_filter('report_code_name', model.ReportCode.name) g.set_filter('report_code_name', model.ReportCode.name)
if self.expose_label_printing and self.has_perm('print_labels'): if self.expose_label_printing and self.has_perm('print_labels'):
if use_buefy: g.more_actions.append(self.make_action(
g.more_actions.append(self.make_action( 'print_label', icon='print', url='#',
'print_label', icon='print', url='#', click_handler='quickLabelPrint(props.row)'))
click_handler='quickLabelPrint(props.row)'))
else:
g.more_actions.append(grids.GridAction('print_label', icon='print'))
g.set_renderer('regular_price', self.render_price) g.set_renderer('regular_price', self.render_price)
g.set_renderer('on_hand', self.render_on_hand) g.set_renderer('on_hand', self.render_on_hand)
@ -572,10 +562,7 @@ class ProductView(MasterView):
if not self.has_perm('versions'): if not self.has_perm('versions'):
return text return text
if self.get_use_buefy(): kwargs = {'@click.prevent': 'showPriceHistory_{}()'.format(typ)}
kwargs = {'@click.prevent': 'showPriceHistory_{}()'.format(typ)}
else:
kwargs = {'id': 'view-{}-price-history'.format(typ)}
history = tags.link_to("(view history)", '#', **kwargs) history = tags.link_to("(view history)", '#', **kwargs)
if not text: if not text:
return history return history
@ -815,7 +802,7 @@ class ProductView(MasterView):
if 'upc' in data: if 'upc' in data:
if isinstance(data['upc'], GPC): if isinstance(data['upc'], GPC):
data['upc'] = six.text_type(data['upc']) data['upc'] = str(data['upc'])
return data return data
@ -971,9 +958,9 @@ class ProductView(MasterView):
if self.request.POST.get('brand_uuid'): if self.request.POST.get('brand_uuid'):
brand = self.Session.query(model.Brand).get(self.request.POST['brand_uuid']) brand = self.Session.query(model.Brand).get(self.request.POST['brand_uuid'])
if brand: if brand:
brand_display = six.text_type(brand) brand_display = str(brand)
elif self.editing: elif self.editing:
brand_display = six.text_type(product.brand or '') brand_display = str(product.brand or '')
brands_url = self.request.route_url('brands.autocomplete') brands_url = self.request.route_url('brands.autocomplete')
f.set_widget('brand_uuid', forms.widgets.JQueryAutocompleteWidget( f.set_widget('brand_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=brand_display, service_url=brands_url)) field_display=brand_display, service_url=brands_url))
@ -1139,11 +1126,11 @@ class ProductView(MasterView):
history['price'] = float(price) history['price'] = float(price)
history['price_display'] = app.render_currency(price) history['price_display'] = app.render_currency(price)
changed = localtime(self.rattail_config, history['changed'], from_utc=True) changed = localtime(self.rattail_config, history['changed'], from_utc=True)
history['changed'] = six.text_type(changed) history['changed'] = str(changed)
history['changed_display_html'] = raw_datetime(self.rattail_config, changed) history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
user = history.pop('changed_by') user = history.pop('changed_by')
history['changed_by_uuid'] = user.uuid if user else None history['changed_by_uuid'] = user.uuid if user else None
history['changed_by_display'] = six.text_type(user or "??") history['changed_by_display'] = str(user or "??")
jsdata.append(history) jsdata.append(history)
return jsdata return jsdata
@ -1165,18 +1152,17 @@ class ProductView(MasterView):
else: else:
history['cost_display'] = None history['cost_display'] = None
changed = localtime(self.rattail_config, history['changed'], from_utc=True) changed = localtime(self.rattail_config, history['changed'], from_utc=True)
history['changed'] = six.text_type(changed) history['changed'] = str(changed)
history['changed_display_html'] = raw_datetime(self.rattail_config, changed) history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
user = history.pop('changed_by') user = history.pop('changed_by')
history['changed_by_uuid'] = user.uuid history['changed_by_uuid'] = user.uuid
history['changed_by_display'] = six.text_type(user) history['changed_by_display'] = str(user)
jsdata.append(history) jsdata.append(history)
return jsdata return jsdata
def template_kwargs_view(self, **kwargs): def template_kwargs_view(self, **kwargs):
kwargs = super(ProductView, self).template_kwargs_view(**kwargs) kwargs = super(ProductView, self).template_kwargs_view(**kwargs)
product = kwargs['instance'] product = kwargs['instance']
use_buefy = self.get_use_buefy()
kwargs['image_url'] = self.products_handler.get_image_url(product) kwargs['image_url'] = self.products_handler.get_image_url(product)
@ -1184,10 +1170,7 @@ class ProductView(MasterView):
if self.rattail_config.versioning_enabled() and self.has_perm('versions'): if self.rattail_config.versioning_enabled() and self.has_perm('versions'):
# regular price # regular price
if use_buefy: data = [] # defer fetching until user asks for it
data = [] # defer fetching until user asks for it
else:
data = self.get_regular_price_history(product)
grid = grids.Grid('products.regular_price_history', data, grid = grids.Grid('products.regular_price_history', data,
request=self.request, request=self.request,
columns=[ columns=[
@ -1201,10 +1184,7 @@ class ProductView(MasterView):
kwargs['regular_price_history_grid'] = grid kwargs['regular_price_history_grid'] = grid
# current price # current price
if use_buefy: data = [] # defer fetching until user asks for it
data = [] # defer fetching until user asks for it
else:
data = self.get_current_price_history(product)
grid = grids.Grid('products.current_price_history', data, grid = grids.Grid('products.current_price_history', data,
request=self.request, request=self.request,
columns=[ columns=[
@ -1222,10 +1202,7 @@ class ProductView(MasterView):
kwargs['current_price_history_grid'] = grid kwargs['current_price_history_grid'] = grid
# suggested price # suggested price
if use_buefy: data = [] # defer fetching until user asks for it
data = [] # defer fetching until user asks for it
else:
data = self.get_suggested_price_history(product)
grid = grids.Grid('products.suggested_price_history', data, grid = grids.Grid('products.suggested_price_history', data,
request=self.request, request=self.request,
columns=[ columns=[
@ -1239,10 +1216,7 @@ class ProductView(MasterView):
kwargs['suggested_price_history_grid'] = grid kwargs['suggested_price_history_grid'] = grid
# cost history # cost history
if use_buefy: data = [] # defer fetching until user asks for it
data = [] # defer fetching until user asks for it
else:
data = self.get_cost_history(product)
grid = grids.Grid('products.cost_history', data, grid = grids.Grid('products.cost_history', data,
request=self.request, request=self.request,
columns=[ columns=[
@ -1264,9 +1238,8 @@ class ProductView(MasterView):
kwargs['costs_label_code'] = "Order Code" kwargs['costs_label_code'] = "Order Code"
kwargs['costs_label_case_size'] = "Case Size" kwargs['costs_label_case_size'] = "Case Size"
if use_buefy: kwargs['vendor_sources'] = self.get_context_vendor_sources(product)
kwargs['vendor_sources'] = self.get_context_vendor_sources(product) kwargs['lookup_codes'] = self.get_context_lookup_codes(product)
kwargs['lookup_codes'] = self.get_context_lookup_codes(product)
kwargs['panel_fields'] = self.get_panel_fields(product) kwargs['panel_fields'] = self.get_panel_fields(product)
@ -1362,7 +1335,7 @@ class ProductView(MasterView):
source['case_size'] = app.render_quantity(cost.case_size) source['case_size'] = app.render_quantity(cost.case_size)
source['case_cost'] = app.render_currency(cost.case_cost) source['case_cost'] = app.render_currency(cost.case_cost)
text = six.text_type(cost.vendor) text = str(cost.vendor)
if link_vendor: if link_vendor:
url = self.request.route_url('vendors.view', uuid=cost.vendor.uuid) url = self.request.route_url('vendors.view', uuid=cost.vendor.uuid)
source['vendor'] = tags.link_to(text, url) source['vendor'] = tags.link_to(text, url)
@ -1768,8 +1741,6 @@ class ProductView(MasterView):
# TODO: how to properly detect image type? # TODO: how to properly detect image type?
# content_type = 'image/png' # content_type = 'image/png'
content_type = 'image/jpeg' content_type = 'image/jpeg'
if not six.PY3:
content_type = six.binary_type(content_type)
self.request.response.content_type = content_type self.request.response.content_type = content_type
self.request.response.body = product.image.bytes self.request.response.body = product.image.bytes
return self.request.response return self.request.response
@ -1802,7 +1773,7 @@ class ProductView(MasterView):
printer.print_labels([({'product': product}, quantity)]) printer.print_labels([({'product': product}, quantity)])
except Exception as error: except Exception as error:
log.warning("error occurred while printing labels", exc_info=True) log.warning("error occurred while printing labels", exc_info=True)
return {'error': six.text_type(error)} return {'error': str(error)}
return {'ok': True} return {'ok': True}
def search(self): def search(self):
@ -1923,7 +1894,7 @@ class ProductView(MasterView):
if product and (not product.deleted or self.request.has_perm('products.view_deleted')): if product and (not product.deleted or self.request.has_perm('products.view_deleted')):
data = { data = {
'uuid': product.uuid, 'uuid': product.uuid,
'upc': six.text_type(product.upc), 'upc': str(product.upc),
'upc_pretty': product.upc.pretty(), 'upc_pretty': product.upc.pretty(),
'full_description': product.full_description, 'full_description': product.full_description,
'image_url': pod.get_image_url(self.rattail_config, product.upc), 'image_url': pod.get_image_url(self.rattail_config, product.upc),
@ -2282,7 +2253,7 @@ class PendingProductView(MasterView):
g.set_enum('status_code', self.enum.PENDING_PRODUCT_STATUS) g.set_enum('status_code', self.enum.PENDING_PRODUCT_STATUS)
g.filters['status_code'].default_active = True g.filters['status_code'].default_active = True
g.filters['status_code'].default_verb = 'not_equal' g.filters['status_code'].default_verb = 'not_equal'
g.filters['status_code'].default_value = six.text_type(self.enum.PENDING_PRODUCT_STATUS_RESOLVED) g.filters['status_code'].default_value = str(self.enum.PENDING_PRODUCT_STATUS_RESOLVED)
g.set_sort_defaults('created', 'desc') g.set_sort_defaults('created', 'desc')
@ -2317,9 +2288,9 @@ class PendingProductView(MasterView):
if self.request.POST.get('brand_uuid'): if self.request.POST.get('brand_uuid'):
brand = self.Session.query(model.Brand).get(self.request.POST['brand_uuid']) brand = self.Session.query(model.Brand).get(self.request.POST['brand_uuid'])
if brand: if brand:
brand_display = six.text_type(brand) brand_display = str(brand)
elif self.editing: elif self.editing:
brand_display = six.text_type(pending.brand or '') brand_display = str(pending.brand or '')
brands_url = self.request.route_url('brands.autocomplete') brands_url = self.request.route_url('brands.autocomplete')
f.set_widget('brand_uuid', forms.widgets.JQueryAutocompleteWidget( f.set_widget('brand_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=brand_display, service_url=brands_url)) field_display=brand_display, service_url=brands_url))
@ -2344,7 +2315,7 @@ class PendingProductView(MasterView):
if self.request.POST.get('vendor_uuid'): if self.request.POST.get('vendor_uuid'):
vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor_uuid']) vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor_uuid'])
if vendor: if vendor:
vendor_display = six.text_type(vendor) vendor_display = str(vendor)
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget( f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, field_display=vendor_display,
service_url=self.request.route_url('vendors.autocomplete'))) service_url=self.request.route_url('vendors.autocomplete')))

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,8 +24,6 @@
Project views Project views
""" """
from __future__ import unicode_literals, absolute_import
import os import os
import zipfile import zipfile
# from collections import OrderedDict # from collections import OrderedDict
@ -160,7 +158,6 @@ class GenerateProjectView(View):
return RattailProjectHandler(self.rattail_config) return RattailProjectHandler(self.rattail_config)
def __call__(self): def __call__(self):
use_buefy = self.get_use_buefy()
# choices = OrderedDict([ # choices = OrderedDict([
# ('has_db', {'prompt': "Does project need its own Rattail DB?", # ('has_db', {'prompt': "Does project need its own Rattail DB?",
@ -183,8 +180,7 @@ class GenerateProjectView(View):
schema = GenerateTailboneIntegrationProject schema = GenerateTailboneIntegrationProject
else: else:
schema = GenerateProject schema = GenerateProject
form = forms.Form(schema=schema(), request=self.request, form = forms.Form(schema=schema(), request=self.request)
use_buefy=use_buefy)
if form.validate(newstyle=True): if form.validate(newstyle=True):
zipped = self.generate_project(project_type, form) zipped = self.generate_project(project_type, form)
return self.file_response(zipped) return self.file_response(zipped)
@ -195,7 +191,6 @@ class GenerateProjectView(View):
'index_title': "Generate Project", 'index_title': "Generate Project",
'handler': self.handler, 'handler': self.handler,
# 'choices': choices, # 'choices': choices,
'use_buefy': use_buefy,
} }
def generate_project(self, project_type, form): def generate_project(self, project_type, form):

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar # Copyright © 2010-2023 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,10 +24,6 @@
Base class for purchasing batch views Base class for purchasing batch views
""" """
from __future__ import unicode_literals, absolute_import
import six
from rattail.db import model, api from rattail.db import model, api
import colander import colander
@ -230,7 +226,6 @@ class PurchasingBatchView(BatchMasterView):
batch = f.model_instance batch = f.model_instance
app = self.get_rattail_app() app = self.get_rattail_app()
today = app.localtime().date() today = app.localtime().date()
use_buefy = self.get_use_buefy()
# mode # mode
f.set_enum('mode', self.enum.PURCHASE_BATCH_MODE) f.set_enum('mode', self.enum.PURCHASE_BATCH_MODE)
@ -278,7 +273,7 @@ class PurchasingBatchView(BatchMasterView):
if self.request.POST.get('vendor_uuid'): if self.request.POST.get('vendor_uuid'):
vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor_uuid']) vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor_uuid'])
if vendor: if vendor:
vendor_display = six.text_type(vendor) vendor_display = str(vendor)
vendors_url = self.request.route_url('vendors.autocomplete') vendors_url = self.request.route_url('vendors.autocomplete')
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget( f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url)) field_display=vendor_display, service_url=vendors_url))
@ -311,14 +306,14 @@ class PurchasingBatchView(BatchMasterView):
if self.request.POST.get('buyer_uuid'): if self.request.POST.get('buyer_uuid'):
buyer = self.Session.query(model.Employee).get(self.request.POST['buyer_uuid']) buyer = self.Session.query(model.Employee).get(self.request.POST['buyer_uuid'])
if buyer: if buyer:
buyer_display = six.text_type(buyer) buyer_display = str(buyer)
elif self.creating: elif self.creating:
buyer = self.request.user.employee buyer = self.request.user.employee
if buyer: if buyer:
buyer_display = six.text_type(buyer) buyer_display = str(buyer)
f.set_default('buyer_uuid', buyer.uuid) f.set_default('buyer_uuid', buyer.uuid)
elif self.editing: elif self.editing:
buyer_display = six.text_type(batch.buyer or '') buyer_display = str(batch.buyer or '')
buyers_url = self.request.route_url('employees.autocomplete') buyers_url = self.request.route_url('employees.autocomplete')
f.set_widget('buyer_uuid', forms.widgets.JQueryAutocompleteWidget( f.set_widget('buyer_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=buyer_display, service_url=buyers_url)) field_display=buyer_display, service_url=buyers_url))
@ -346,11 +341,7 @@ class PurchasingBatchView(BatchMasterView):
if len(parsers) == 1: if len(parsers) == 1:
f.set_default('invoice_parser_key', parsers[0].key) f.set_default('invoice_parser_key', parsers[0].key)
if use_buefy: f.set_widget('invoice_parser_key', dfwidget.SelectWidget(values=parser_values))
f.set_widget('invoice_parser_key', dfwidget.SelectWidget(values=parser_values))
else:
parser_values.insert(0, ('', "(please choose)"))
f.set_widget('invoice_parser_key', forms.widgets.JQuerySelectWidget(values=parser_values))
else: else:
f.remove_field('invoice_parser_key') f.remove_field('invoice_parser_key')
@ -422,7 +413,7 @@ class PurchasingBatchView(BatchMasterView):
purchase = batch.purchase purchase = batch.purchase
if not purchase: if not purchase:
return "" return ""
text = six.text_type(purchase) text = str(purchase)
url = self.request.route_url('purchases.view', uuid=purchase.uuid) url = self.request.route_url('purchases.view', uuid=purchase.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -435,7 +426,7 @@ class PurchasingBatchView(BatchMasterView):
def render_vendor_contact(self, batch, field): def render_vendor_contact(self, batch, field):
if batch.vendor.contact: if batch.vendor.contact:
return six.text_type(batch.vendor.contact) return str(batch.vendor.contact)
def render_vendor_phone(self, batch, field): def render_vendor_phone(self, batch, field):
return self.get_vendor_phone_number(batch) return self.get_vendor_phone_number(batch)
@ -455,7 +446,7 @@ class PurchasingBatchView(BatchMasterView):
employee = batch.buyer employee = batch.buyer
if not employee: if not employee:
return "" return ""
text = six.text_type(employee) text = str(employee)
if self.request.has_perm('employees.view'): if self.request.has_perm('employees.view'):
url = self.request.route_url('employees.view', uuid=employee.uuid) url = self.request.route_url('employees.view', uuid=employee.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
@ -484,7 +475,7 @@ class PurchasingBatchView(BatchMasterView):
def get_buyer_values(self): def get_buyer_values(self):
buyers = self.get_buyers() buyers = self.get_buyers()
return [(b.uuid, six.text_type(b)) return [(b.uuid, str(b))
for b in buyers] for b in buyers]
def get_department_options(self): def get_department_options(self):
@ -802,13 +793,12 @@ class PurchasingBatchView(BatchMasterView):
return app.render_cases_units(cases, units) return app.render_cases_units(cases, units)
def make_row_credits_grid(self, row): def make_row_credits_grid(self, row):
use_buefy = self.get_use_buefy()
route_prefix = self.get_route_prefix() route_prefix = self.get_route_prefix()
factory = self.get_grid_factory() factory = self.get_grid_factory()
g = factory( g = factory(
key='{}.row_credits'.format(route_prefix), key='{}.row_credits'.format(route_prefix),
data=[] if use_buefy else row.credits, data=[],
columns=[ columns=[
'credit_type', 'credit_type',
'shorted', 'shorted',
@ -837,17 +827,9 @@ class PurchasingBatchView(BatchMasterView):
return g return g
def render_row_credits(self, row, field): def render_row_credits(self, row, field):
use_buefy = self.get_use_buefy()
if not use_buefy and not row.credits:
return
g = self.make_row_credits_grid(row) g = self.make_row_credits_grid(row)
return HTML.literal(
if use_buefy: g.render_buefy_table_element(data_prop='rowData.credits'))
return HTML.literal(
g.render_buefy_table_element(data_prop='rowData.credits'))
else:
return HTML.literal(g.render_grid())
# def item_lookup(self, value, field=None): # def item_lookup(self, value, field=None):
# """ # """

Some files were not shown because too many files have changed in this diff Show more