Compare commits
25 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9355f9982d | |||
| ceb0c3226e | |||
| 2500805c54 | |||
| 8a3c147858 | |||
| 5ae236f228 | |||
| b62e41966c | |||
| c230536e49 | |||
| 3cc37bea30 | |||
| 207125bdb3 | |||
| 5a78b0740d | |||
| 8e7169fb4a | |||
| 6f14bb0e88 | |||
| fcc90d25ac | |||
| e150453801 | |||
| e2582ffec5 | |||
| a6508154cb | |||
| 7348eec671 | |||
| 4221fa50dd | |||
| e0ebd43e7a | |||
| c7ee9de9eb | |||
| 950db697a0 | |||
| 358b3b75a5 | |||
| 7e559a01b3 | |||
| 23bdde245a | |||
| 2c269b640b |
13 changed files with 96 additions and 25 deletions
57
CHANGELOG.md
57
CHANGELOG.md
|
|
@ -5,6 +5,63 @@ All notable changes to Tailbone will be documented in this file.
|
|||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## v0.23.0 (2025-10-19)
|
||||
|
||||
### Feat
|
||||
|
||||
- require latest rattail; drop passlib dependency
|
||||
|
||||
### Fix
|
||||
|
||||
- depend on latest rattail
|
||||
|
||||
## v0.22.11 (2025-09-20)
|
||||
|
||||
### Fix
|
||||
|
||||
- avoid error when row object missing field
|
||||
|
||||
## v0.22.10 (2025-09-20)
|
||||
|
||||
### Fix
|
||||
|
||||
- avoid error if 'default' theme not included
|
||||
- fix config extension entry point
|
||||
|
||||
## v0.22.9 (2025-09-20)
|
||||
|
||||
### Fix
|
||||
|
||||
- small bugfixes per upstream changes
|
||||
|
||||
## v0.22.8 (2025-05-20)
|
||||
|
||||
### Fix
|
||||
|
||||
- add startup hack for tempmon DB model
|
||||
|
||||
## v0.22.7 (2025-02-19)
|
||||
|
||||
### Fix
|
||||
|
||||
- stop using old config for logo image url on login page
|
||||
- fix warning msg for deprecated Grid param
|
||||
|
||||
## v0.22.6 (2025-02-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- register vue3 form component for products -> make batch
|
||||
|
||||
## v0.22.5 (2024-12-16)
|
||||
|
||||
### Fix
|
||||
|
||||
- whoops this is latest rattail
|
||||
- require newer rattail lib
|
||||
- require newer wuttaweb
|
||||
- let caller request safe HTML literal for rendered grid table
|
||||
|
||||
## v0.22.4 (2024-11-22)
|
||||
|
||||
### Fix
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ templates_path = ['_templates']
|
|||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
intersphinx_mapping = {
|
||||
'rattail': ('https://rattailproject.org/docs/rattail/', None),
|
||||
'rattail': ('https://docs.wuttaproject.org/rattail/', None),
|
||||
'webhelpers2': ('https://webhelpers2.readthedocs.io/en/latest/', None),
|
||||
'wuttaweb': ('https://rattailproject.org/docs/wuttaweb/', None),
|
||||
'wuttjamaican': ('https://rattailproject.org/docs/wuttjamaican/', None),
|
||||
'wuttaweb': ('https://docs.wuttaproject.org/wuttaweb/', None),
|
||||
'wuttjamaican': ('https://docs.wuttaproject.org/wuttjamaican/', None),
|
||||
}
|
||||
|
||||
# allow todo entries to show up
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "Tailbone"
|
||||
version = "0.22.4"
|
||||
version = "0.23.0"
|
||||
description = "Backoffice Web Application for Rattail"
|
||||
readme = "README.md"
|
||||
authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]
|
||||
|
|
@ -43,7 +43,6 @@ dependencies = [
|
|||
"openpyxl",
|
||||
"paginate",
|
||||
"paginate_sqlalchemy",
|
||||
"passlib",
|
||||
"Pillow",
|
||||
"pyramid>=2",
|
||||
"pyramid_beaker",
|
||||
|
|
@ -53,13 +52,13 @@ dependencies = [
|
|||
"pyramid_mako",
|
||||
"pyramid_retry",
|
||||
"pyramid_tm",
|
||||
"rattail[db,bouncer]>=0.18.5",
|
||||
"rattail[db,bouncer]>=0.21.0",
|
||||
"sa-filters",
|
||||
"simplejson",
|
||||
"transaction",
|
||||
"waitress",
|
||||
"WebHelpers2",
|
||||
"WuttaWeb>=0.14.0",
|
||||
"WuttaWeb>=0.27.0",
|
||||
"zope.sqlalchemy>=1.5",
|
||||
]
|
||||
|
||||
|
|
@ -78,7 +77,7 @@ webapi = "tailbone.webapi:main"
|
|||
beaker = "tailbone.cleanup:BeakerCleaner"
|
||||
|
||||
|
||||
[project.entry-points."rattail.config.extensions"]
|
||||
[project.entry-points."wutta.config.extensions"]
|
||||
tailbone = "tailbone.config:ConfigExtension"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,17 @@ def make_rattail_config(settings):
|
|||
# nb. this is for compaibility with wuttaweb
|
||||
settings['wutta_config'] = rattail_config
|
||||
|
||||
# must import all sqlalchemy models before things get rolling,
|
||||
# otherwise can have errors about continuum TransactionMeta class
|
||||
# not yet mapped, when relevant pages are first requested...
|
||||
# cf. https://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/database/sqlalchemy.html#importing-all-sqlalchemy-models
|
||||
# hat tip to https://stackoverflow.com/a/59241485
|
||||
if getattr(rattail_config, 'tempmon_engine', None):
|
||||
from rattail_tempmon.db import model as tempmon_model, Session as TempmonSession
|
||||
tempmon_session = TempmonSession()
|
||||
tempmon_session.query(tempmon_model.Appliance).first()
|
||||
tempmon_session.close()
|
||||
|
||||
# configure database sessions
|
||||
if hasattr(rattail_config, 'appdb_engine'):
|
||||
tailbone.db.Session.configure(bind=rattail_config.appdb_engine)
|
||||
|
|
@ -197,6 +208,7 @@ def make_pyramid_config(settings, configure_csrf=True):
|
|||
'wuttaweb.auth.add_permission')
|
||||
|
||||
# and some similar magic for certain master views
|
||||
config.add_directive('add_wutta_master_view', 'wuttaweb.conf.add_master_view')
|
||||
config.add_directive('add_tailbone_index_page', 'tailbone.app.add_index_page')
|
||||
config.add_directive('add_tailbone_config_page', 'tailbone.app.add_config_page')
|
||||
config.add_directive('add_tailbone_model_view', 'tailbone.app.add_model_view')
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ class Grid(WuttaGrid):
|
|||
|
||||
if 'pageable' in kwargs:
|
||||
warnings.warn("pageable param is deprecated for Grid(); "
|
||||
"please use vue_tagname param instead",
|
||||
"please use paginated param instead",
|
||||
DeprecationWarning, stacklevel=2)
|
||||
kwargs.setdefault('paginated', kwargs.pop('pageable'))
|
||||
|
||||
|
|
@ -578,7 +578,7 @@ class Grid(WuttaGrid):
|
|||
|
||||
try:
|
||||
return obj[column_name]
|
||||
except TypeError:
|
||||
except (TypeError, KeyError):
|
||||
pass
|
||||
|
||||
def render_currency(self, obj, column_name):
|
||||
|
|
@ -1223,6 +1223,7 @@ class Grid(WuttaGrid):
|
|||
|
||||
def render_table_element(self, template='/grids/b-table.mako',
|
||||
data_prop='gridData', empty_labels=False,
|
||||
literal=False,
|
||||
**kwargs):
|
||||
"""
|
||||
This is intended for ad-hoc "small" grids with static data. Renders
|
||||
|
|
@ -1239,7 +1240,10 @@ class Grid(WuttaGrid):
|
|||
if context['paginated']:
|
||||
context.setdefault('per_page', 20)
|
||||
context['view_click_handler'] = self.get_view_click_handler()
|
||||
return render(template, context)
|
||||
result = render(template, context)
|
||||
if literal:
|
||||
result = HTML.literal(result)
|
||||
return result
|
||||
|
||||
def get_view_click_handler(self):
|
||||
""" """
|
||||
|
|
|
|||
|
|
@ -55,19 +55,20 @@
|
|||
</%def>
|
||||
|
||||
<%def name="render_form_template()">
|
||||
<script type="text/x-template" id="${form.component}-template">
|
||||
<script type="text/x-template" id="${form.vue_tagname}-template">
|
||||
${self.render_form_innards()}
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
<%def name="modify_vue_vars()">
|
||||
${parent.modify_vue_vars()}
|
||||
<% request.register_component(form.vue_tagname, form.vue_component) %>
|
||||
<script>
|
||||
|
||||
## TODO: ugh, an awful lot of duplicated code here (from /forms/deform.mako)
|
||||
|
||||
let ${form.vue_component} = {
|
||||
template: '#${form.component}-template',
|
||||
template: '#${form.vue_tagname}-template',
|
||||
methods: {
|
||||
|
||||
## TODO: deprecate / remove the latter option here
|
||||
|
|
|
|||
|
|
@ -300,8 +300,8 @@ def get_available_themes(rattail_config, include=None):
|
|||
available.sort()
|
||||
|
||||
# make default theme the first option
|
||||
i = available.index('default')
|
||||
if i >= 0:
|
||||
if 'default' in available:
|
||||
i = available.index('default')
|
||||
available.pop(i)
|
||||
available.insert(0, 'default')
|
||||
|
||||
|
|
|
|||
|
|
@ -94,10 +94,6 @@ class AuthenticationView(View):
|
|||
else:
|
||||
self.request.session.flash("Invalid username or password", 'error')
|
||||
|
||||
image_url = self.rattail_config.get(
|
||||
'tailbone', 'main_image_url',
|
||||
default=self.request.static_url('tailbone:static/img/home_logo.png'))
|
||||
|
||||
# nb. hacky..but necessary, to add the refs, for autofocus
|
||||
# (also add key handler, so ENTER acts like TAB)
|
||||
dform = form.make_deform_form()
|
||||
|
|
@ -110,7 +106,6 @@ class AuthenticationView(View):
|
|||
return {
|
||||
'form': form,
|
||||
'referrer': referrer,
|
||||
'image_url': image_url,
|
||||
'index_title': app.get_node_title(),
|
||||
'help_url': global_help_url(self.rattail_config),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ class MasterView(View):
|
|||
return self.redirect(self.request.current_route_url(**kw))
|
||||
|
||||
# Stash some grid stats, for possible use when generating URLs.
|
||||
if grid.paginated and hasattr(grid, 'pager'):
|
||||
if grid.paginated and grid.pager is not None:
|
||||
self.first_visible_grid_index = grid.pager.first_item
|
||||
|
||||
# return grid data only, if partial page was requested
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ class TestGrid(WebTestCase):
|
|||
|
||||
# settings are loaded, applied, saved
|
||||
self.assertEqual(grid.sort_defaults, [])
|
||||
self.assertFalse(hasattr(grid, 'active_sorters'))
|
||||
self.assertIsNone(grid.active_sorters)
|
||||
self.request.GET = {'sort1key': 'name', 'sort1dir': 'desc'}
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'desc'}])
|
||||
|
|
@ -365,7 +365,7 @@ class TestGrid(WebTestCase):
|
|||
# with sort defaults
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True,
|
||||
sort_on_backend=True, sort_defaults='name')
|
||||
self.assertFalse(hasattr(grid, 'active_sorters'))
|
||||
self.assertIsNone(grid.active_sorters)
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'asc'}])
|
||||
|
||||
|
|
@ -376,7 +376,7 @@ class TestGrid(WebTestCase):
|
|||
mod.SortInfo('name', 'asc'),
|
||||
mod.SortInfo('value', 'desc'),
|
||||
]
|
||||
self.assertFalse(hasattr(grid, 'active_sorters'))
|
||||
self.assertIsNone(grid.active_sorters)
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'asc'}])
|
||||
|
||||
|
|
@ -390,7 +390,7 @@ class TestGrid(WebTestCase):
|
|||
grid = self.make_grid(key='settings', model_class=model.Setting,
|
||||
sortable=True, sort_on_backend=True,
|
||||
paginated=True, paginate_on_backend=True)
|
||||
self.assertFalse(hasattr(grid, 'active_sorters'))
|
||||
self.assertIsNone(grid.active_sorters)
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'desc'}])
|
||||
|
||||
|
|
|
|||
|
|
@ -13,5 +13,6 @@ class TestPersonView(WebTestCase):
|
|||
self.pyramid_config.include('tailbone.views.people')
|
||||
|
||||
def test_includeme_wutta(self):
|
||||
self.pyramid_config.add_directive('add_wutta_master_view', 'wuttaweb.conf.add_master_view')
|
||||
self.config.setdefault('tailbone.use_wutta_views', 'true')
|
||||
self.pyramid_config.include('tailbone.views.people')
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ from tests.util import WebTestCase
|
|||
class TestSettingView(WebTestCase):
|
||||
|
||||
def test_includeme(self):
|
||||
self.pyramid_config.add_directive('add_wutta_master_view', 'wuttaweb.conf.add_master_view')
|
||||
self.pyramid_config.include('tailbone.views.settings')
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class TestPersonView(WebTestCase):
|
|||
return mod.PersonView(self.request)
|
||||
|
||||
def test_includeme(self):
|
||||
self.pyramid_config.add_directive('add_wutta_master_view', 'wuttaweb.conf.add_master_view')
|
||||
self.pyramid_config.include('tailbone.views.wutta.people')
|
||||
|
||||
def test_get_query(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue