feat: move "basic" grid pagination logic to wuttaweb
so far only "simple" pagination is supported by wuttaweb, so basically the main feature flag, page size, current page. in this scenario *all* data is written to client-side JSON and Buefy handles the actual pagination. backend pagination coming soon for wuttaweb but for now tailbone still handles all that.
This commit is contained in:
		
							parent
							
								
									2a0b6da2f9
								
							
						
					
					
						commit
						9da2a148c6
					
				
					 5 changed files with 195 additions and 47 deletions
				
			
		|  | @ -31,6 +31,7 @@ import logging | |||
| import sqlalchemy as sa | ||||
| from sqlalchemy import orm | ||||
| 
 | ||||
| from wuttjamaican.util import UNSPECIFIED | ||||
| from rattail.db.types import GPCType | ||||
| from rattail.util import prettify, pretty_boolean | ||||
| 
 | ||||
|  | @ -209,9 +210,6 @@ class Grid(WuttaGrid): | |||
|             sorters={}, | ||||
|             default_sortkey=None, | ||||
|             default_sortdir='asc', | ||||
|             pageable=False, | ||||
|             default_pagesize=None, | ||||
|             default_page=1, | ||||
|             checkboxes=False, | ||||
|             checked=None, | ||||
|             check_handler=None, | ||||
|  | @ -233,7 +231,26 @@ class Grid(WuttaGrid): | |||
|                           DeprecationWarning, stacklevel=2) | ||||
|             kwargs.setdefault('vue_tagname', kwargs.pop('component')) | ||||
| 
 | ||||
|         # TODO: pretty sure this should go away? | ||||
|         if kwargs.get('pageable'): | ||||
|             warnings.warn("component param is deprecated for Grid(); " | ||||
|                           "please use vue_tagname param instead", | ||||
|                           DeprecationWarning, stacklevel=2) | ||||
|             kwargs.setdefault('paginated', kwargs.pop('pageable')) | ||||
| 
 | ||||
|         if kwargs.get('default_pagesize'): | ||||
|             warnings.warn("default_pagesize param is deprecated for Grid(); " | ||||
|                           "please use pagesize param instead", | ||||
|                           DeprecationWarning, stacklevel=2) | ||||
|             kwargs.setdefault('pagesize', kwargs.pop('default_pagesize')) | ||||
| 
 | ||||
|         if kwargs.get('default_page'): | ||||
|             warnings.warn("default_page param is deprecated for Grid(); " | ||||
|                           "please use page param instead", | ||||
|                           DeprecationWarning, stacklevel=2) | ||||
|             kwargs.setdefault('page', kwargs.pop('default_page')) | ||||
| 
 | ||||
|         # TODO: this should not be needed once all templates correctly | ||||
|         # reference grid.vue_component etc. | ||||
|         kwargs.setdefault('vue_tagname', 'tailbone-grid') | ||||
| 
 | ||||
|         kwargs['key'] = key | ||||
|  | @ -272,10 +289,6 @@ class Grid(WuttaGrid): | |||
|         self.default_sortkey = default_sortkey | ||||
|         self.default_sortdir = default_sortdir | ||||
| 
 | ||||
|         self.pageable = pageable | ||||
|         self.default_pagesize = default_pagesize | ||||
|         self.default_page = default_page | ||||
| 
 | ||||
|         self.checkboxes = checkboxes | ||||
|         self.checked = checked | ||||
|         if self.checked is None: | ||||
|  | @ -333,6 +346,16 @@ class Grid(WuttaGrid): | |||
|                       DeprecationWarning, stacklevel=2) | ||||
|         return self.vue_component | ||||
| 
 | ||||
|     def get_pageable(self): | ||||
|         """ """ | ||||
|         return self.paginated | ||||
| 
 | ||||
|     def set_pageable(self, value): | ||||
|         """ """ | ||||
|         self.paginated = value | ||||
| 
 | ||||
|     pageable = property(get_pageable, set_pageable) | ||||
| 
 | ||||
|     def hide_column(self, key): | ||||
|         """ | ||||
|         This *removes* a column from the grid, altogether. | ||||
|  | @ -756,18 +779,61 @@ class Grid(WuttaGrid): | |||
|             keyfunc = lambda v: v[key] | ||||
|         return lambda q, d: sorted(q, key=keyfunc, reverse=d == 'desc') | ||||
| 
 | ||||
|     def get_default_pagesize(self): | ||||
|     def get_pagesize_options(self, default=None): | ||||
|         """ """ | ||||
|         # let upstream check config | ||||
|         options = super().get_pagesize_options(default=UNSPECIFIED) | ||||
|         if options is not UNSPECIFIED: | ||||
|             return options | ||||
| 
 | ||||
|         # fallback to legacy config | ||||
|         options = self.config.get_list('tailbone.grid.pagesize_options') | ||||
|         if options: | ||||
|             warnings.warn("tailbone.grid.pagesize_options setting is deprecated; " | ||||
|                           "please set wuttaweb.grids.default_pagesize_options instead", | ||||
|                           DeprecationWarning) | ||||
|             options = [int(size) for size in options | ||||
|                        if size.isdigit()] | ||||
|             if options: | ||||
|                 return options | ||||
| 
 | ||||
|         if default: | ||||
|             return default | ||||
| 
 | ||||
|         # use upstream default | ||||
|         return super().get_pagesize_options() | ||||
| 
 | ||||
|     def get_pagesize(self, default=None): | ||||
|         """ """ | ||||
|         # let upstream check config | ||||
|         pagesize = super().get_pagesize(default=UNSPECIFIED) | ||||
|         if pagesize is not UNSPECIFIED: | ||||
|             return pagesize | ||||
| 
 | ||||
|         # fallback to legacy config | ||||
|         pagesize = self.config.get_int('tailbone.grid.default_pagesize') | ||||
|         if pagesize: | ||||
|             warnings.warn("tailbone.grid.default_pagesize setting is deprecated; " | ||||
|                           "please use wuttaweb.grids.default_pagesize instead", | ||||
|                           DeprecationWarning) | ||||
|             return pagesize | ||||
| 
 | ||||
|         if default: | ||||
|             return default | ||||
| 
 | ||||
|         # use upstream default | ||||
|         return super().get_pagesize() | ||||
| 
 | ||||
|     def get_default_pagesize(self): # pragma: no cover | ||||
|         """ """ | ||||
|         warnings.warn("Grid.get_default_pagesize() method is deprecated; " | ||||
|                       "please use Grid.get_pagesize() of Grid.page instead", | ||||
|                       DeprecationWarning, stacklevel=2) | ||||
| 
 | ||||
|         if self.default_pagesize: | ||||
|             return self.default_pagesize | ||||
| 
 | ||||
|         pagesize = self.request.rattail_config.getint('tailbone', | ||||
|                                                       'grid.default_pagesize', | ||||
|                                                       default=0) | ||||
|         if pagesize: | ||||
|             return pagesize | ||||
| 
 | ||||
|         options = self.get_pagesize_options() | ||||
|         return options[0] | ||||
|         return self.get_pagesize() | ||||
| 
 | ||||
|     def load_settings(self, store=True): | ||||
|         """ | ||||
|  | @ -789,9 +855,9 @@ class Grid(WuttaGrid): | |||
|                 settings['sorters.1.dir'] = self.default_sortdir | ||||
|             else: | ||||
|                 settings['sorters.length'] = 0 | ||||
|         if self.pageable: | ||||
|             settings['pagesize'] = self.get_default_pagesize() | ||||
|             settings['page'] = self.default_page | ||||
|         if self.paginated: | ||||
|             settings['pagesize'] = self.pagesize | ||||
|             settings['page'] = self.page | ||||
|         if self.filterable: | ||||
|             for filtr in self.iter_filters(): | ||||
|                 settings['filter.{}.active'.format(filtr.key)] = filtr.default_active | ||||
|  | @ -867,7 +933,7 @@ class Grid(WuttaGrid): | |||
|                     'field': settings[f'sorters.{i}.key'], | ||||
|                     'order': settings[f'sorters.{i}.dir'], | ||||
|                 }) | ||||
|         if self.pageable: | ||||
|         if self.paginated: | ||||
|             self.pagesize = settings['pagesize'] | ||||
|             self.page = settings['page'] | ||||
| 
 | ||||
|  | @ -971,7 +1037,7 @@ class Grid(WuttaGrid): | |||
|                     merge(f'sorters.{i}.key') | ||||
|                     merge(f'sorters.{i}.dir') | ||||
| 
 | ||||
|         if self.pageable: | ||||
|         if self.paginated: | ||||
|             merge('pagesize', int) | ||||
|             merge('page', int) | ||||
| 
 | ||||
|  | @ -1154,7 +1220,7 @@ class Grid(WuttaGrid): | |||
| 
 | ||||
|         :param settings: Dictionary of initial settings, which is to be updated. | ||||
|         """ | ||||
|         if not self.pageable: | ||||
|         if not self.paginated: | ||||
|             return | ||||
| 
 | ||||
|         pagesize = self.request.GET.get('pagesize') | ||||
|  | @ -1231,7 +1297,7 @@ class Grid(WuttaGrid): | |||
|                 persist(f'sorters.{i}.key') | ||||
|                 persist(f'sorters.{i}.dir') | ||||
| 
 | ||||
|         if self.pageable: | ||||
|         if self.paginated: | ||||
|             persist('pagesize') | ||||
|             persist('page') | ||||
| 
 | ||||
|  | @ -1355,7 +1421,7 @@ class Grid(WuttaGrid): | |||
|             data = self.filter_data(data) | ||||
|         if self.sortable: | ||||
|             data = self.sort_data(data) | ||||
|         if self.pageable: | ||||
|         if self.paginated: | ||||
|             self.pager = self.paginate_data(data) | ||||
|             data = self.pager | ||||
|         return data | ||||
|  | @ -1580,18 +1646,6 @@ class Grid(WuttaGrid): | |||
|         return tags.checkbox('checkbox-{}-{}'.format(self.key, self.get_row_key(item)), | ||||
|                              checked=self.checked(item)) | ||||
| 
 | ||||
|     def get_pagesize_options(self): | ||||
| 
 | ||||
|         # use values from config, if defined | ||||
|         options = self.request.rattail_config.getlist('tailbone', 'grid.pagesize_options') | ||||
|         if options: | ||||
|             options = [int(size) for size in options | ||||
|                        if size.isdigit()] | ||||
|             if options: | ||||
|                 return options | ||||
| 
 | ||||
|         return [5, 10, 20, 50, 100, 200] | ||||
| 
 | ||||
|     def has_static_data(self): | ||||
|         """ | ||||
|         Should return ``True`` if the grid data can be considered "static" | ||||
|  | @ -1734,7 +1788,7 @@ class Grid(WuttaGrid): | |||
|             results['checked_rows_code'] = '[{}]'.format( | ||||
|                 ', '.join(['{}[{}]'.format(var, i) for i in checked])) | ||||
| 
 | ||||
|         if self.pageable and self.pager is not None: | ||||
|         if self.paginated and self.pager is not None: | ||||
|             results['total_items'] = self.pager.item_count | ||||
|             results['per_page'] = self.pager.items_per_page | ||||
|             results['page'] = self.pager.page | ||||
|  |  | |||
|  | @ -107,12 +107,14 @@ | |||
|        @cellclick="cellClick" | ||||
|        % endif | ||||
| 
 | ||||
|        % if grid.paginated: | ||||
|        :paginated="paginated" | ||||
|        :per-page="perPage" | ||||
|        :current-page="currentPage" | ||||
|        backend-pagination | ||||
|        :total="total" | ||||
|        @page-change="onPageChange" | ||||
|        % endif | ||||
| 
 | ||||
|        ## TODO: should let grid (or master view) decide how to set these? | ||||
|        icon-pack="fas" | ||||
|  | @ -203,7 +205,7 @@ | |||
|               <div></div> | ||||
|           % endif | ||||
| 
 | ||||
|           % if getattr(grid, 'pageable', False): | ||||
|           % if grid.paginated: | ||||
|               <div v-if="firstItem" | ||||
|                    style="display: flex; gap: 0.5rem; align-items: center;"> | ||||
|                 <span> | ||||
|  | @ -255,12 +257,14 @@ | |||
|       checkedRows: ${grid_data['checked_rows_code']|n}, | ||||
|       % endif | ||||
| 
 | ||||
|       paginated: ${json.dumps(getattr(grid, 'pageable', False))|n}, | ||||
|       % if grid.paginated: | ||||
|       paginated: ${json.dumps(grid.paginated)|n}, | ||||
|       total: ${len(grid_data['data']) if static_data else (grid_data['total_items'] if grid_data is not Undefined else 0)}, | ||||
|       perPage: ${json.dumps(grid.pagesize if getattr(grid, 'pageable', False) else None)|n}, | ||||
|       currentPage: ${json.dumps(grid.page if getattr(grid, 'pageable', False) else None)|n}, | ||||
|       firstItem: ${json.dumps(grid_data['first_item'] if getattr(grid, 'pageable', False) else None)|n}, | ||||
|       lastItem: ${json.dumps(grid_data['last_item'] if getattr(grid, 'pageable', False) else None)|n}, | ||||
|       perPage: ${json.dumps(grid.pagesize if grid.paginated else None)|n}, | ||||
|       currentPage: ${json.dumps(grid.page if grid.paginated else None)|n}, | ||||
|       firstItem: ${json.dumps(grid_data['first_item'] if grid.paginated else None)|n}, | ||||
|       lastItem: ${json.dumps(grid_data['last_item'] if grid.paginated else None)|n}, | ||||
|       % endif | ||||
| 
 | ||||
|       % if getattr(grid, 'sortable', False): | ||||
| 
 | ||||
|  | @ -439,7 +443,7 @@ | |||
|                       params['sort'+i+'dir'] = this.backendSorters[i-1].order | ||||
|                   } | ||||
|               % endif | ||||
|               % if getattr(grid, 'pageable', False): | ||||
|               % if grid.paginated: | ||||
|                   params.pagesize = this.perPage | ||||
|                   params.page = this.currentPage | ||||
|               % endif | ||||
|  |  | |||
|  | @ -439,7 +439,7 @@ class MasterView(View): | |||
|             'filterable': self.filterable, | ||||
|             'use_byte_string_filters': self.use_byte_string_filters, | ||||
|             'sortable': self.sortable, | ||||
|             'pageable': self.pageable, | ||||
|             'paginated': self.pageable, | ||||
|             'extra_row_class': self.grid_extra_class, | ||||
|             'url': lambda obj: self.get_action_url('view', obj), | ||||
|             'checkboxes': checkboxes, | ||||
|  | @ -589,7 +589,7 @@ class MasterView(View): | |||
|         } | ||||
| 
 | ||||
|         if self.rows_default_pagesize: | ||||
|             defaults['default_pagesize'] = self.rows_default_pagesize | ||||
|             defaults['pagesize'] = self.rows_default_pagesize | ||||
| 
 | ||||
|         if self.has_rows and 'actions' not in defaults: | ||||
|             actions = [] | ||||
|  |  | |||
|  | @ -45,6 +45,10 @@ class PersonView(wutta.PersonView): | |||
|     model_class = Person | ||||
|     Session = Session | ||||
| 
 | ||||
|     # TODO: /grids/complete.mako is too aggressive for the | ||||
|     # limited support we have in wuttaweb thus far | ||||
|     paginated = False | ||||
| 
 | ||||
|     labels = { | ||||
|         'display_name': "Full Name", | ||||
|     } | ||||
|  |  | |||
|  | @ -19,6 +19,32 @@ class TestGrid(WebTestCase): | |||
|         grid = self.make_grid('foo') | ||||
|         self.assertIsInstance(grid, mod.Grid) | ||||
| 
 | ||||
|     def test_deprecated_params(self): | ||||
| 
 | ||||
|         # component | ||||
|         grid = self.make_grid() | ||||
|         self.assertEqual(grid.vue_tagname, 'tailbone-grid') | ||||
|         grid = self.make_grid(component='blarg') | ||||
|         self.assertEqual(grid.vue_tagname, 'blarg') | ||||
| 
 | ||||
|         # pageable | ||||
|         grid = self.make_grid() | ||||
|         self.assertFalse(grid.paginated) | ||||
|         grid = self.make_grid(pageable=True) | ||||
|         self.assertTrue(grid.paginated) | ||||
| 
 | ||||
|         # default_pagesize | ||||
|         grid = self.make_grid() | ||||
|         self.assertEqual(grid.pagesize, 20) | ||||
|         grid = self.make_grid(default_pagesize=15) | ||||
|         self.assertEqual(grid.pagesize, 15) | ||||
| 
 | ||||
|         # default_page | ||||
|         grid = self.make_grid() | ||||
|         self.assertEqual(grid.page, 1) | ||||
|         grid = self.make_grid(default_page=42) | ||||
|         self.assertEqual(grid.page, 42) | ||||
| 
 | ||||
|     def test_vue_tagname(self): | ||||
| 
 | ||||
|         # default | ||||
|  | @ -133,6 +159,66 @@ class TestGrid(WebTestCase): | |||
|         grid.set_action_urls(setting, setting, 0) | ||||
|         self.assertEqual(setting['_action_url_view'], '/blarg') | ||||
| 
 | ||||
|     def test_pageable(self): | ||||
|         grid = self.make_grid() | ||||
|         self.assertFalse(grid.paginated) | ||||
|         grid.pageable = True | ||||
|         self.assertTrue(grid.paginated) | ||||
|         grid.paginated = False | ||||
|         self.assertFalse(grid.pageable) | ||||
| 
 | ||||
|     def test_get_pagesize_options(self): | ||||
|         grid = self.make_grid() | ||||
| 
 | ||||
|         # default | ||||
|         options = grid.get_pagesize_options() | ||||
|         self.assertEqual(options, [5, 10, 20, 50, 100, 200]) | ||||
| 
 | ||||
|         # override default | ||||
|         options = grid.get_pagesize_options(default=[42]) | ||||
|         self.assertEqual(options, [42]) | ||||
| 
 | ||||
|         # from legacy config | ||||
|         self.config.setdefault('tailbone.grid.pagesize_options', '1 2 3') | ||||
|         grid = self.make_grid() | ||||
|         options = grid.get_pagesize_options() | ||||
|         self.assertEqual(options, [1, 2, 3]) | ||||
| 
 | ||||
|         # from new config | ||||
|         self.config.setdefault('wuttaweb.grids.default_pagesize_options', '4, 5, 6') | ||||
|         grid = self.make_grid() | ||||
|         options = grid.get_pagesize_options() | ||||
|         self.assertEqual(options, [4, 5, 6]) | ||||
| 
 | ||||
|     def test_get_pagesize(self): | ||||
|         grid = self.make_grid() | ||||
| 
 | ||||
|         # default | ||||
|         size = grid.get_pagesize() | ||||
|         self.assertEqual(size, 20) | ||||
| 
 | ||||
|         # override default | ||||
|         size = grid.get_pagesize(default=42) | ||||
|         self.assertEqual(size, 42) | ||||
| 
 | ||||
|         # override default options | ||||
|         self.config.setdefault('wuttaweb.grids.default_pagesize_options', '10 15 30') | ||||
|         grid = self.make_grid() | ||||
|         size = grid.get_pagesize() | ||||
|         self.assertEqual(size, 10) | ||||
| 
 | ||||
|         # from legacy config | ||||
|         self.config.setdefault('tailbone.grid.default_pagesize', '12') | ||||
|         grid = self.make_grid() | ||||
|         size = grid.get_pagesize() | ||||
|         self.assertEqual(size, 12) | ||||
| 
 | ||||
|         # from new config | ||||
|         self.config.setdefault('wuttaweb.grids.default_pagesize', '15') | ||||
|         grid = self.make_grid() | ||||
|         size = grid.get_pagesize() | ||||
|         self.assertEqual(size, 15) | ||||
| 
 | ||||
|     def test_render_vue_tag(self): | ||||
|         model = self.app.model | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar