diff --git a/CHANGELOG.md b/CHANGELOG.md index 18526c3..4a8ea89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to wuttaweb 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.20.5 (2025-01-23) + +### Fix + +- improve styling for grid tools section +- add basic checkbox support for grids +- add WuttaRequestMixin for ThisPage component +- avoid literal `None` when rendering form field value +- let header title be even wider + ## v0.20.4 (2025-01-15) ### Fix diff --git a/pyproject.toml b/pyproject.toml index 8858f8a..6c63e8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "WuttaWeb" -version = "0.20.4" +version = "0.20.5" description = "Web App for Wutta Framework" readme = "README.md" authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}] @@ -44,7 +44,7 @@ dependencies = [ "pyramid_tm", "waitress", "WebHelpers2", - "WuttJamaican[db]>=0.20.1", + "WuttJamaican[db]>=0.20.2", "zope.sqlalchemy>=1.5", ] diff --git a/src/wuttaweb/forms/base.py b/src/wuttaweb/forms/base.py index edd1e2d..504e012 100644 --- a/src/wuttaweb/forms/base.py +++ b/src/wuttaweb/forms/base.py @@ -1033,12 +1033,13 @@ class Form: # render static text if field not in deform/schema # TODO: need to abstract this somehow if self.model_instance: - html = str(self.model_instance[fieldname]) + value = self.model_instance[fieldname] + html = str(value) if value is not None else '' else: html = '' # mark all that as safe - html = HTML.literal(html) + html = HTML.literal(html or ' ') # render field label label = self.get_label(fieldname) diff --git a/src/wuttaweb/grids/base.py b/src/wuttaweb/grids/base.py index 33269f2..e93627f 100644 --- a/src/wuttaweb/grids/base.py +++ b/src/wuttaweb/grids/base.py @@ -118,6 +118,11 @@ class Grid: See also :meth:`set_renderer()` and :meth:`set_default_renderers()`. + .. attribute:: checkable + + Boolean indicating whether the grid should expose per-row + checkboxes. + .. attribute:: row_class This represents the CSS ``class`` attribute for a row within @@ -362,6 +367,7 @@ class Grid: data=None, labels={}, renderers={}, + checkable=False, row_class=None, actions=[], linked_columns=[], @@ -388,6 +394,7 @@ class Grid: self.key = key self.data = data self.labels = labels or {} + self.checkable = checkable self.row_class = row_class self.actions = actions or [] self.linked_columns = linked_columns or [] diff --git a/src/wuttaweb/templates/base.mako b/src/wuttaweb/templates/base.mako index 486b496..d84a0e2 100644 --- a/src/wuttaweb/templates/base.mako +++ b/src/wuttaweb/templates/base.mako @@ -155,7 +155,7 @@ } #content-title h1 { - max-width: 85%; + max-width: 95%; overflow: hidden; padding-left: 0.5rem; text-overflow: ellipsis; @@ -186,6 +186,11 @@ width: 100%; } + .wutta-grid-tools-wrapper { + display: flex; + gap: 0.5rem; + } + ############################## ## forms ############################## diff --git a/src/wuttaweb/templates/grids/vue_template.mako b/src/wuttaweb/templates/grids/vue_template.mako index ba548cb..fa7b8f7 100644 --- a/src/wuttaweb/templates/grids/vue_template.mako +++ b/src/wuttaweb/templates/grids/vue_template.mako @@ -116,6 +116,13 @@ hoverable icon-pack="fas" + ## checkboxes + % if grid.checkable: + checkable + checkbox-position="right" + :checked-rows.sync="checkedRows" + % endif + ## sorting % if grid.sortable: ## nb. buefy/oruga only support *one* default sorter @@ -267,6 +274,11 @@ shareLink: null, % endif + ## checkboxes + % if grid.checkable: + checkedRows: [], + % endif + ## filtering % if grid.filterable: filters: ${json.dumps(grid.get_vue_filters())|n}, diff --git a/src/wuttaweb/templates/page.mako b/src/wuttaweb/templates/page.mako index c23ce90..cd5b1da 100644 --- a/src/wuttaweb/templates/page.mako +++ b/src/wuttaweb/templates/page.mako @@ -26,6 +26,7 @@ const ThisPage = { template: '#this-page-template', + mixins: [WuttaRequestMixin], props: { ## configureFieldsHelp: Boolean, }, diff --git a/src/wuttaweb/views/master.py b/src/wuttaweb/views/master.py index 61d4d14..5903fe4 100644 --- a/src/wuttaweb/views/master.py +++ b/src/wuttaweb/views/master.py @@ -189,6 +189,12 @@ class MasterView(View): This is optional; see also :meth:`get_grid_columns()`. + .. attribute:: checkable + + Boolean indicating whether the grid should expose per-row + checkboxes. This is passed along to set + :attr:`~wuttaweb.grids.base.Grid.checkable` on the grid. + .. method:: grid_row_class(obj, data, i) This method is *not* defined on the ``MasterView`` base class; @@ -395,6 +401,7 @@ class MasterView(View): # features listable = True has_grid = True + checkable = False filterable = True filter_defaults = None sortable = True @@ -1992,6 +1999,7 @@ class MasterView(View): kwargs['tools'] = tools + kwargs.setdefault('checkable', self.checkable) if hasattr(self, 'grid_row_class'): kwargs.setdefault('row_class', self.grid_row_class) kwargs.setdefault('filterable', self.filterable) diff --git a/tests/grids/test_base.py b/tests/grids/test_base.py index d5f3766..1002ac9 100644 --- a/tests/grids/test_base.py +++ b/tests/grids/test_base.py @@ -1433,7 +1433,7 @@ class TestGrid(WebTestCase): # null obj = MagicMock(dt=None) result = grid.render_date(obj, 'dt', None) - self.assertIsNone(result) + self.assertEqual(result, '') # typical dt = datetime.date(2025, 1, 13) @@ -1446,7 +1446,7 @@ class TestGrid(WebTestCase): obj = MagicMock(dt=None) result = grid.render_datetime(obj, 'dt', None) - self.assertIsNone(result) + self.assertEqual(result, '') dt = datetime.datetime(2024, 12, 12, 13, 44, tzinfo=datetime.timezone.utc) obj = MagicMock(dt=dt)