Fix Buefy "row grids" when viewing parent; add basic file upload support

This commit is contained in:
Lance Edgar 2019-05-23 16:29:29 -05:00
parent 5998941741
commit d7c8b80da5
8 changed files with 125 additions and 38 deletions

View file

@ -3,5 +3,3 @@ let TailboneForm = {
template: '#tailbone-form-template', template: '#tailbone-form-template',
methods: {} methods: {}
} }
let TailboneFormData = {}

View file

@ -5,6 +5,9 @@ const OnceButton = {
'<b-button', '<b-button',
':type="type"', ':type="type"',
':native-type="nativeType"', ':native-type="nativeType"',
':tag="tag"',
':href="href"',
':title="title"',
':disabled="disabled"', ':disabled="disabled"',
'@click="clicked"', '@click="clicked"',
'>', '>',
@ -15,7 +18,10 @@ const OnceButton = {
props: { props: {
type: String, type: String,
nativeType: String, nativeType: String,
tag: String,
href: String,
text: String, text: String,
title: String,
working: String, working: String,
workingText: String, workingText: String,
disabled: Boolean disabled: Boolean

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2018 Lance Edgar # Copyright © 2010-2019 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -34,6 +34,8 @@ import rattail
from rattail.db import model from rattail.db import model
from rattail.db.auth import cache_permissions from rattail.db.auth import cache_permissions
import colander
import deform
from pyramid import threadlocal from pyramid import threadlocal
from webhelpers2.html import tags from webhelpers2.html import tags
@ -97,6 +99,8 @@ def before_render(event):
renderer_globals['six'] = six renderer_globals['six'] = six
renderer_globals['json'] = json renderer_globals['json'] = json
renderer_globals['datetime'] = datetime renderer_globals['datetime'] = datetime
renderer_globals['colander'] = colander
renderer_globals['deform'] = deform
# theme - we only want do this for classic web app, *not* API # theme - we only want do this for classic web app, *not* API
# TODO: so, clearly we need a better way to distinguish the two # TODO: so, clearly we need a better way to distinguish the two

View file

@ -63,10 +63,10 @@
% if master.batch_refreshable(batch) and request.has_perm('{}.refresh'.format(permission_prefix)): % if master.batch_refreshable(batch) and request.has_perm('{}.refresh'.format(permission_prefix)):
% if use_buefy: % if use_buefy:
## TODO: this should surely use a POST request? ## TODO: this should surely use a POST request?
<a class="button" <once-button tag="a"
href="${url('{}.refresh'.format(route_prefix), uuid=batch.uuid)}"> href="${url('{}.refresh'.format(route_prefix), uuid=batch.uuid)}"
Refresh Data text="Refresh Data">
</a> </once-button>
% else: % else:
<button type="button" class="button" id="refresh-data">Refresh Data</button> <button type="button" class="button" id="refresh-data">Refresh Data</button>
% endif % endif
@ -74,17 +74,16 @@
</%def> </%def>
<%def name="execute_submit_button()"> <%def name="execute_submit_button()">
<button type="submit" <once-button type="is-primary"
class="button is-primary" native-type="submit"
% if not execute_enabled: % if not execute_enabled:
disabled="disabled" disabled
% endif % endif
% if why_not_execute: % if why_not_execute:
title="${why_not_execute}" title="${why_not_execute}"
% endif % endif
> text="${execute_title}">
${execute_title} </once-button>
</button>
</%def> </%def>
<%def name="execute_button()"> <%def name="execute_button()">
@ -145,30 +144,21 @@
% endif % endif
</%def> </%def>
<div style="display: flex; justify-content: space-between;"> <%def name="render_form()">
## TODO: should use self.render_form_buttons()
<div class="form-wrapper"> ## ${form.render(form_id='batch-form', buttons=capture(self.render_form_buttons))|n}
${form.render(form_id='batch-form', buttons=capture(buttons))|n} ${form.render(form_id='batch-form', buttons=capture(buttons))|n}
</div><!-- form-wrapper --> </%def>
<div style="display: flex; align-items: flex-start;">
<div class="object-helpers"> ${self.render_form_complete()}
${self.object_helpers()}
</div>
<ul id="context-menu">
${self.context_menu_items()}
</ul>
</div>
</div>
% if use_buefy: % if use_buefy:
<br /><br /> <br /><br />
## TODO: stop using |n filter ## TODO: stop using |n filter
${rows_grid.render_buefy(allow_save_defaults=False, tools=rows_grid_tools)|n} ${rows_grid.render_buefy(allow_save_defaults=False, tools=rows_grid_tools)|n}
${self.make_tailbone_form_app()}
${self.make_tailbone_grid_app()}
% else: % else:
## no buefy, so do the traditional thing ## no buefy, so do the traditional thing
${rows_grid|n} ${rows_grid|n}

View file

@ -0,0 +1,43 @@
<!-- -*- mode: html; -*- -->
<tal:block tal:define="oid oid|field.oid;
css_class css_class|field.widget.css_class;
style style|field.widget.style;
field_name field_name|field.name;
use_buefy use_buefy|0;">
<div tal:condition="not use_buefy" tal:omit-tag="">
${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;"
tal:omit-tag="">
${field.start_mapping()}
<b-upload name="upload"
v-model="${vmodel}">
<a class="button is-primary">
<b-icon pack="fas" icon="upload"></b-icon>
<span>Click to upload</span>
</a>
</b-upload>
<span class="file-name" v-if="${vmodel}">
{{ ${vmodel}.name }}
</span>
${field.end_mapping()}
</div>
</tal:block>

View file

@ -18,7 +18,7 @@
${self.render_form()} ${self.render_form()}
</div> </div>
<div style="display: flex;"> <div style="display: flex; align-items: flex-start;">
<div class="object-helpers"> <div class="object-helpers">
${self.object_helpers()} ${self.object_helpers()}
</div> </div>

View file

@ -20,6 +20,10 @@
<b-field horizontal <b-field horizontal
label="${form.get_label(field.name)}" label="${form.get_label(field.name)}"
## TODO: is this class="file" really needed?
% if isinstance(field.schema.typ, deform.FileData):
class="file"
% 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}'
@ -58,6 +62,28 @@
</div> </div>
</script> </script>
<script type="text/javascript">
let TailboneFormData = {
## TODO: ugh, this seems pretty hacky. need to declare some data models
## for various field components to bind to...
% if not form.readonly:
% for field in form.fields:
% if field in dform:
<% field = dform[field] %>
% if isinstance(field.schema.typ, colander.Date):
field_model_${field.name}: null,
% elif isinstance(field.schema.typ, deform.FileData):
field_model_${field.name}: null,
% endif
% endif
% endfor
% endif
}
</script>
<div id="tailbone-form-app"> <div id="tailbone-form-app">
<tailbone-form></tailbone-form> <tailbone-form></tailbone-form>

View file

@ -7,7 +7,7 @@
${parent.extra_javascript()} ${parent.extra_javascript()}
% if master.has_rows: % if master.has_rows:
% if use_buefy: % if use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.gridfilters.js') + '?ver={}'.format(tailbone.__version__))} ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.grid.js') + '?ver={}'.format(tailbone.__version__))}
% else: % else:
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
@ -69,6 +69,25 @@
${rows_grid_tools} ${rows_grid_tools}
</%def> </%def>
<%def name="modify_tailbone_grid()">
## NOTE: if you override this, must use <script> tags
</%def>
<%def name="make_tailbone_grid_app()">
${self.modify_tailbone_grid()}
<script type="text/javascript">
TailboneGrid.data = function() { return TailboneGridData }
Vue.component('tailbone-grid', TailboneGrid)
new Vue({
el: '#tailbone-grid-app'
});
</script>
</%def>
${self.render_form_complete()} ${self.render_form_complete()}
@ -77,12 +96,13 @@ ${self.render_form_complete()}
<br /><br /> <br /><br />
## TODO: stop using |n filter ## TODO: stop using |n filter
${rows_grid.render_buefy(allow_save_defaults=False, tools=capture(self.render_row_grid_tools))|n} ${rows_grid.render_buefy(allow_save_defaults=False, tools=capture(self.render_row_grid_tools))|n}
${self.make_tailbone_grid_app()}
% else: % else:
## no buefy, so do the traditional thing ## no buefy, so do the traditional thing
${rows_grid|n} ${rows_grid|n}
% endif % endif
% endif % endif
% if form.use_buefy: % if use_buefy:
${self.make_tailbone_form_app()} ${self.make_tailbone_form_app()}
% endif % endif