Add basic Buefy support for App Settings page
also various buttons have been tweaked on some other "master view" pages
This commit is contained in:
parent
e1ff4578e9
commit
fcfc8b56bb
|
@ -67,7 +67,8 @@ class Grid(object):
|
||||||
Core grid class. In sore need of documentation.
|
Core grid class. In sore need of documentation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, key, data, columns=None, width='auto', request=None, mobile=False, model_class=None,
|
def __init__(self, key, data, columns=None, width='auto', request=None, mobile=False,
|
||||||
|
model_class=None, model_title=None, model_title_plural=None,
|
||||||
enums={}, labels={}, renderers={}, extra_row_class=None, linked_columns=[], url='#',
|
enums={}, labels={}, renderers={}, extra_row_class=None, linked_columns=[], url='#',
|
||||||
joiners={}, filterable=False, filters={}, use_byte_string_filters=False,
|
joiners={}, filterable=False, filters={}, use_byte_string_filters=False,
|
||||||
sortable=False, sorters={}, default_sortkey=None, default_sortdir='asc',
|
sortable=False, sorters={}, default_sortkey=None, default_sortdir='asc',
|
||||||
|
@ -84,6 +85,18 @@ class Grid(object):
|
||||||
self.model_class = model_class
|
self.model_class = model_class
|
||||||
if self.model_class and self.columns is None:
|
if self.model_class and self.columns is None:
|
||||||
self.columns = self.make_columns()
|
self.columns = self.make_columns()
|
||||||
|
|
||||||
|
self.model_title = model_title
|
||||||
|
if not self.model_title and self.model_class:
|
||||||
|
self.model_title = self.model_class.get_model_title()
|
||||||
|
|
||||||
|
self.model_title_plural = model_title_plural
|
||||||
|
if not self.model_title_plural:
|
||||||
|
if self.model_class:
|
||||||
|
self.model_title_plural = self.model_class.get_model_title_plural()
|
||||||
|
if not self.model_title_plural:
|
||||||
|
self.model_title_plural = '{}s'.format(self.model_title)
|
||||||
|
|
||||||
self.enums = enums or {}
|
self.enums = enums or {}
|
||||||
|
|
||||||
self.labels = labels or {}
|
self.labels = labels or {}
|
||||||
|
|
|
@ -7,11 +7,14 @@
|
||||||
|
|
||||||
<%def name="extra_javascript()">
|
<%def name="extra_javascript()">
|
||||||
${parent.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__))}
|
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.appsettings.js') + '?ver={}'.format(tailbone.__version__))}
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="extra_styles()">
|
<%def name="extra_styles()">
|
||||||
${parent.extra_styles()}
|
${parent.extra_styles()}
|
||||||
|
% if not use_buefy:
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
div.form {
|
div.form {
|
||||||
float: none;
|
float: none;
|
||||||
|
@ -27,6 +30,7 @@
|
||||||
width: 50em;
|
width: 50em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<div class="form">
|
<div class="form">
|
||||||
|
@ -46,10 +50,17 @@
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
|
% if use_buefy:
|
||||||
|
<div id="app-settings-app">
|
||||||
|
<app-settings :groups="groups" :showing-group="showingGroup"></app-settings>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
% else:
|
||||||
|
## not buefy
|
||||||
<div class="group-picker">
|
<div class="group-picker">
|
||||||
<div class="field-wrapper">
|
<div class="field-wrapper">
|
||||||
<label for="settings-group">Showing Group</label>
|
<label for="settings-group">Showing Group</label>
|
||||||
<div class="field">
|
<div class="field select">
|
||||||
${h.select('settings-group', current_group, group_options, **{'auto-enhance': 'true'})}
|
${h.select('settings-group', current_group, group_options, **{'auto-enhance': 'true'})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,11 +99,116 @@
|
||||||
</div><!-- panel-body -->
|
</div><!-- panel-body -->
|
||||||
</div><! -- panel -->
|
</div><! -- panel -->
|
||||||
% endfor
|
% endfor
|
||||||
|
% endif
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
${h.submit('save', getattr(form, 'submit_label', getattr(form, 'save_label', "Submit")))}
|
${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 ''))}
|
${h.link_to("Cancel", form.cancel_url, class_='cancel button{}'.format(' autodisable' if form.auto_disable_cancel else ''))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
% if use_buefy:
|
||||||
|
<script type="text/x-template" id="app-settings-template">
|
||||||
|
<div class="app-wrapper">
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label for="settings-group">Showing Group</label>
|
||||||
|
<b-select @input="showGroup"
|
||||||
|
name="settings-group"
|
||||||
|
v-model="showingGroup">
|
||||||
|
<option value="">(All)</option>
|
||||||
|
<option v-for="group in groups"
|
||||||
|
:key="group.label"
|
||||||
|
:value="group.label">
|
||||||
|
{{ group.label }}
|
||||||
|
</option>
|
||||||
|
</b-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-for="group in groups"
|
||||||
|
class="card"
|
||||||
|
v-show="!showingGroup || showingGroup == group.label"
|
||||||
|
style="margin-bottom: 1rem;">
|
||||||
|
<header class="card-header">
|
||||||
|
<p class="card-header-title">{{ group.label }}</p>
|
||||||
|
</header>
|
||||||
|
<div class="card-content">
|
||||||
|
<div v-for="setting in group.settings"
|
||||||
|
:class="'field-wrapper' + (setting.error ? ' with-error' : '')">
|
||||||
|
|
||||||
|
<div v-if="setting.error" class="field-error">
|
||||||
|
<span v-for="msg in setting.error_messages"
|
||||||
|
class="error-msg">
|
||||||
|
{{ msg }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-row">
|
||||||
|
<label :for="setting.field_name">{{ setting.label }}</label>
|
||||||
|
<div class="field">
|
||||||
|
|
||||||
|
<input v-if="setting.data_type == 'bool'"
|
||||||
|
type="checkbox"
|
||||||
|
:name="setting.field_name"
|
||||||
|
:id="setting.field_name"
|
||||||
|
v-model="setting.value"
|
||||||
|
value="true" />
|
||||||
|
|
||||||
|
<b-select v-else-if="setting.choices"
|
||||||
|
:name="setting.field_name"
|
||||||
|
:id="setting.field_name"
|
||||||
|
v-model="setting.value">
|
||||||
|
<option v-for="choice in setting.choices"
|
||||||
|
:value="choice">
|
||||||
|
{{ choice }}
|
||||||
|
</option>
|
||||||
|
</b-select>
|
||||||
|
|
||||||
|
<b-input v-else
|
||||||
|
:name="setting.field_name"
|
||||||
|
:id="setting.field_name"
|
||||||
|
v-model="setting.value" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span v-if="setting.helptext" class="instructions">
|
||||||
|
{{ setting.helptext }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</div><!-- field-wrapper -->
|
||||||
|
</div><!-- card-content -->
|
||||||
|
</div><!-- card -->
|
||||||
|
|
||||||
|
</div><!-- app-wrapper -->
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
Vue.component('app-settings', {
|
||||||
|
template: '#app-settings-template',
|
||||||
|
props: {
|
||||||
|
groups: Array,
|
||||||
|
showingGroup: String
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showGroup(group) {
|
||||||
|
console.log("SHOWING GROUP")
|
||||||
|
console.log(group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
el: '#app-settings-app',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
groups: ${json.dumps(buefy_data)|n},
|
||||||
|
showingGroup: ${json.dumps(current_group or '')|n}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
% endif
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
|
|
||||||
<%def name="object_helpers()">
|
<%def name="object_helpers()">
|
||||||
${parent.object_helpers()}
|
${parent.object_helpers()}
|
||||||
|
% if instance.people:
|
||||||
${view_profiles_helper(instance.people)}
|
${view_profiles_helper(instance.people)}
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
${parent.body()}
|
${parent.body()}
|
||||||
|
|
|
@ -5,16 +5,16 @@
|
||||||
${parent.grid_tools()}
|
${parent.grid_tools()}
|
||||||
|
|
||||||
% if request.has_perm('datasync.restart'):
|
% if request.has_perm('datasync.restart'):
|
||||||
${h.form(url('datasync.restart'), name='restart-datasync', class_='autodisable')}
|
${h.form(url('datasync.restart'), name='restart-datasync', class_='autodisable control')}
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
${h.submit('submit', "Restart DataSync", data_working_label="Restarting DataSync")}
|
${h.submit('submit', "Restart DataSync", data_working_label="Restarting DataSync", class_='button')}
|
||||||
${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'):
|
||||||
${h.form(url('filemon.restart'), name='restart-filemon', class_='autodisable')}
|
${h.form(url('filemon.restart'), name='restart-filemon', class_='autodisable control')}
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
${h.submit('submit', "Restart FileMon", data_working_label="Restarting FileMon")}
|
${h.submit('submit', "Restart FileMon", data_working_label="Restarting FileMon", class_='button')}
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
<input type="hidden" name="__start__" value="${name}:sequence"
|
<input type="hidden" name="__start__" value="${name}:sequence"
|
||||||
tal:condition="multiple" />
|
tal:condition="multiple" />
|
||||||
|
<div class="select">
|
||||||
<select tal:attributes="
|
<select tal:attributes="
|
||||||
name name;
|
name name;
|
||||||
id oid;
|
id oid;
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
value item[0]">${item[1]}</option>
|
value item[0]">${item[1]}</option>
|
||||||
</tal:loop>
|
</tal:loop>
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
<input type="hidden" name="__end__" value="${name}:sequence"
|
<input type="hidden" name="__end__" value="${name}:sequence"
|
||||||
tal:condition="multiple" />
|
tal:condition="multiple" />
|
||||||
<script tal:condition="not multiple" type="text/javascript">
|
<script tal:condition="not multiple" type="text/javascript">
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
|
|
||||||
<div class="grid-tools-wrapper">
|
<div class="grid-tools-wrapper">
|
||||||
% if tools:
|
% if tools:
|
||||||
<div class="grid-tools">
|
<div class="grid-tools field is-grouped">
|
||||||
## TODO: stop using |n filter
|
## TODO: stop using |n filter
|
||||||
${tools|n}
|
${tools|n}
|
||||||
</div>
|
</div>
|
||||||
|
@ -299,6 +299,14 @@
|
||||||
// apply current filters as normal, but add special directive
|
// apply current filters as normal, but add special directive
|
||||||
const params = ['save-current-filters-as-defaults=true']
|
const params = ['save-current-filters-as-defaults=true']
|
||||||
this.applyFilters(params)
|
this.applyFilters(params)
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteResults(event) {
|
||||||
|
|
||||||
|
// submit form if user confirms
|
||||||
|
if (confirm("You are about to delete " + this.total + " ${grid.model_title_plural}.\n\nAre you sure?")) {
|
||||||
|
event.target.form.submit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<a class="button" href="${form.cancel_url}">Whoops, nevermind...</a>
|
<a class="button" href="${form.cancel_url}">Whoops, nevermind...</a>
|
||||||
${h.submit('submit', "Yes, please DELETE this data forever!")}
|
${h.submit('submit', "Yes, please DELETE this data forever!", class_='button is-primary')}
|
||||||
</div>
|
</div>
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
|
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
|
% if not use_buefy and master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
|
||||||
|
|
||||||
$('form[name="bulk-delete"] button').click(function() {
|
$('form[name="bulk-delete"] button').click(function() {
|
||||||
var count = $('.grid-wrapper').gridwrapper('results_count', true);
|
var count = $('.grid-wrapper').gridwrapper('results_count', true);
|
||||||
|
@ -134,42 +134,53 @@
|
||||||
|
|
||||||
## 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)):
|
||||||
${h.form(url('{}.merge'.format(route_prefix)), name='merge-things')}
|
${h.form(url('{}.merge'.format(route_prefix)), name='merge-things', class_='control')}
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
${h.hidden('uuids')}
|
${h.hidden('uuids')}
|
||||||
<button type="submit">Merge 2 ${model_title_plural}</button>
|
<button type="submit" class="button">Merge 2 ${model_title_plural}</button>
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
## enable / disable selected objects
|
## enable / disable selected objects
|
||||||
% if master.supports_set_enabled_toggle and request.has_perm('{}.enable_disable_set'.format(permission_prefix)):
|
% if master.supports_set_enabled_toggle and request.has_perm('{}.enable_disable_set'.format(permission_prefix)):
|
||||||
${h.form(url('{}.enable_set'.format(route_prefix)), name='enable-set')}
|
${h.form(url('{}.enable_set'.format(route_prefix)), name='enable-set', class_='control')}
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
${h.hidden('uuids')}
|
${h.hidden('uuids')}
|
||||||
<button type="button">Enable Selected</button>
|
<button type="button" class="button">Enable Selected</button>
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
|
|
||||||
${h.form(url('{}.disable_set'.format(route_prefix)), name='disable-set')}
|
${h.form(url('{}.disable_set'.format(route_prefix)), name='disable-set', class_='control')}
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
${h.hidden('uuids')}
|
${h.hidden('uuids')}
|
||||||
<button type="button">Disable Selected</button>
|
<button type="button" class="button">Disable Selected</button>
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
## delete selected objects
|
## delete selected objects
|
||||||
% if master.set_deletable and request.has_perm('{}.delete_set'.format(permission_prefix)):
|
% if master.set_deletable and request.has_perm('{}.delete_set'.format(permission_prefix)):
|
||||||
${h.form(url('{}.delete_set'.format(route_prefix)), name='delete-set')}
|
${h.form(url('{}.delete_set'.format(route_prefix)), name='delete-set', class_='control')}
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
${h.hidden('uuids')}
|
${h.hidden('uuids')}
|
||||||
<button type="button">Delete Selected</button>
|
<button type="button" class="button">Delete Selected</button>
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
% 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)):
|
||||||
${h.form(url('{}.bulk_delete'.format(route_prefix)), name='bulk-delete')}
|
${h.form(url('{}.bulk_delete'.format(route_prefix)), name='bulk-delete', class_='control')}
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
|
% if use_buefy:
|
||||||
|
<b-button type="is-danger"
|
||||||
|
:disabled="! total"
|
||||||
|
:title="total ? null : 'There are no results to delete'"
|
||||||
|
@click="deleteResults"
|
||||||
|
icon-pack="fas"
|
||||||
|
icon-left="trash">
|
||||||
|
Delete Results
|
||||||
|
</b-button>
|
||||||
|
% else:
|
||||||
<button type="button">Delete Results</button>
|
<button type="button">Delete Results</button>
|
||||||
|
% endif
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
|
|
|
@ -43,12 +43,12 @@ ${parent.body()}
|
||||||
% if instance.enabled and not instance.executing:
|
% if instance.enabled and not instance.executing:
|
||||||
${h.form(url('{}.execute'.format(route_prefix), uuid=instance.uuid), class_='autodisable')}
|
${h.form(url('{}.execute'.format(route_prefix), uuid=instance.uuid), class_='autodisable')}
|
||||||
${h.csrf_token(request)}
|
${h.csrf_token(request)}
|
||||||
${h.submit('execute', "Execute this upgrade")}
|
${h.submit('execute', "Execute this upgrade", class_='button is-primary')}
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
% elif instance.enabled:
|
% elif instance.enabled:
|
||||||
<button type="button" 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>
|
||||||
% else:
|
% else:
|
||||||
<button type="button" disabled="disabled" title="This upgrade is not enabled">Execute this upgrade</button>
|
<button type="button" class="button is-primary" disabled="disabled" title="This upgrade is not enabled">Execute this upgrade</button>
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -73,6 +73,25 @@ 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.
|
||||||
|
"""
|
||||||
|
# first check theme-specific setting, if one has been defined
|
||||||
|
theme = self.request.registry.settings['tailbone.theme']
|
||||||
|
buefy = self.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 self.rattail_config.getbool('tailbone', 'grids.use_buefy', default=False)
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -33,7 +33,6 @@ import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
from deform import widget as dfwidget
|
|
||||||
from pyramid.httpexceptions import HTTPNotFound
|
from pyramid.httpexceptions import HTTPNotFound
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
|
@ -220,7 +219,7 @@ class CustomersView(MasterView):
|
||||||
f.set_enum('email_preference', self.enum.EMAIL_PREFERENCE)
|
f.set_enum('email_preference', self.enum.EMAIL_PREFERENCE)
|
||||||
preferences = list(self.enum.EMAIL_PREFERENCE.items())
|
preferences = list(self.enum.EMAIL_PREFERENCE.items())
|
||||||
preferences.insert(0, ('', "(no preference)"))
|
preferences.insert(0, ('', "(no preference)"))
|
||||||
f.set_widget('email_preference', dfwidget.SelectWidget(values=preferences))
|
f.widgets['email_preference'].values = preferences
|
||||||
|
|
||||||
# person
|
# person
|
||||||
if self.creating:
|
if self.creating:
|
||||||
|
|
|
@ -251,25 +251,6 @@ class MasterView(View):
|
||||||
labels.update(cls.row_labels)
|
labels.update(cls.row_labels)
|
||||||
return labels
|
return labels
|
||||||
|
|
||||||
def get_use_buefy(self):
|
|
||||||
"""
|
|
||||||
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 = self.request.registry.settings['tailbone.theme']
|
|
||||||
buefy = self.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 self.rattail_config.getbool('tailbone', 'grids.use_buefy', default=False)
|
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# Available Views
|
# Available Views
|
||||||
##############################
|
##############################
|
||||||
|
@ -368,6 +349,8 @@ class MasterView(View):
|
||||||
|
|
||||||
defaults = {
|
defaults = {
|
||||||
'model_class': getattr(self, 'model_class', None),
|
'model_class': getattr(self, 'model_class', None),
|
||||||
|
'model_title': self.get_model_title(),
|
||||||
|
'model_title_plural': self.get_model_title_plural(),
|
||||||
'width': 'full',
|
'width': 'full',
|
||||||
'filterable': self.filterable,
|
'filterable': self.filterable,
|
||||||
'use_byte_string_filters': self.use_byte_string_filters,
|
'use_byte_string_filters': self.use_byte_string_filters,
|
||||||
|
|
|
@ -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.
|
||||||
#
|
#
|
||||||
|
@ -33,6 +33,7 @@ import six
|
||||||
from rattail.db import model, api
|
from rattail.db import model, api
|
||||||
from rattail.settings import Setting
|
from rattail.settings import Setting
|
||||||
from rattail.util import import_module_path
|
from rattail.util import import_module_path
|
||||||
|
from rattail.config import parse_bool
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
from webhelpers2.html import tags
|
from webhelpers2.html import tags
|
||||||
|
@ -109,7 +110,7 @@ class AppSettingsView(View):
|
||||||
if form.validate(newstyle=True):
|
if form.validate(newstyle=True):
|
||||||
self.save_form(form)
|
self.save_form(form)
|
||||||
group = self.request.POST.get('settings-group')
|
group = self.request.POST.get('settings-group')
|
||||||
if group:
|
if group is not None:
|
||||||
self.request.session['appsettings.current_group'] = group
|
self.request.session['appsettings.current_group'] = group
|
||||||
self.request.session.flash("App Settings have been saved.")
|
self.request.session.flash("App Settings have been saved.")
|
||||||
return self.redirect(self.request.current_route_url())
|
return self.redirect(self.request.current_route_url())
|
||||||
|
@ -120,17 +121,56 @@ class AppSettingsView(View):
|
||||||
if not current_group:
|
if not current_group:
|
||||||
current_group = self.request.session.get('appsettings.current_group')
|
current_group = self.request.session.get('appsettings.current_group')
|
||||||
|
|
||||||
group_options = [tags.Option(group, group) for group in groups]
|
use_buefy = self.get_use_buefy()
|
||||||
group_options.insert(0, tags.Option("(All)", "(All)"))
|
context = {
|
||||||
return {
|
|
||||||
'index_title': "App Settings",
|
'index_title': "App Settings",
|
||||||
'form': form,
|
'form': form,
|
||||||
'dform': form.make_deform_form(),
|
'dform': form.make_deform_form(),
|
||||||
'groups': groups,
|
'groups': groups,
|
||||||
'group_options': group_options,
|
|
||||||
'current_group': current_group,
|
|
||||||
'settings': settings,
|
'settings': settings,
|
||||||
|
'use_buefy': use_buefy,
|
||||||
}
|
}
|
||||||
|
if use_buefy:
|
||||||
|
context['buefy_data'] = self.get_buefy_data(form, groups, settings)
|
||||||
|
# TODO: this seems hacky, and probably only needed if theme changes?
|
||||||
|
if current_group == '(All)':
|
||||||
|
current_group = ''
|
||||||
|
else:
|
||||||
|
group_options = [tags.Option(group, group) for group in groups]
|
||||||
|
group_options.insert(0, tags.Option("(All)", "(All)"))
|
||||||
|
context['group_options'] = group_options
|
||||||
|
context['current_group'] = current_group
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_buefy_data(self, form, groups, settings):
|
||||||
|
dform = form.make_deform_form()
|
||||||
|
grouped = dict([(label, [])
|
||||||
|
for label in groups])
|
||||||
|
|
||||||
|
for setting in settings:
|
||||||
|
field = dform[setting.node_name]
|
||||||
|
s = {
|
||||||
|
'field_name': field.name,
|
||||||
|
'label': form.get_label(field.name),
|
||||||
|
'data_type': setting.data_type.__name__,
|
||||||
|
'choices': setting.choices,
|
||||||
|
'helptext': form.render_helptext(field.name) if form.has_helptext(field.name) else None,
|
||||||
|
'error': field.error,
|
||||||
|
}
|
||||||
|
value = self.get_setting_value(setting)
|
||||||
|
if setting.data_type is bool:
|
||||||
|
value = parse_bool(value)
|
||||||
|
s['value'] = value
|
||||||
|
if field.error:
|
||||||
|
s['error_messages'] = field.error_messages()
|
||||||
|
grouped[setting.group].append(s)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for label in groups:
|
||||||
|
group = {'label': label, 'settings': grouped[label]}
|
||||||
|
data.append(group)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
def make_form(self, known_settings):
|
def make_form(self, known_settings):
|
||||||
schema = colander.MappingSchema()
|
schema = colander.MappingSchema()
|
||||||
|
|
Loading…
Reference in a new issue