3
0
Fork 0

feat: add multi-column sorting (frontend or backend) for grids

This commit is contained in:
Lance Edgar 2024-08-18 19:23:15 -05:00
parent 58f7a862a2
commit 8d6f4ad368
4 changed files with 388 additions and 93 deletions

View file

@ -71,10 +71,19 @@ class TestGrid(WebTestCase):
sort_defaults=[('name', 'desc')])
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'desc')])
# sort defaults as list w/ multiple
# multi-column defaults
grid = self.make_grid(model_class=model.Setting, sortable=True,
sort_multiple=True,
sort_defaults=[('name', 'desc'), ('value', 'asc')])
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'desc')])
self.assertTrue(grid.sort_multiple)
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'desc'),
mod.SortInfo('value', 'asc')])
# multi-column sort disabled for oruga
self.request.use_oruga = True
grid = self.make_grid(model_class=model.Setting, sortable=True,
sort_multiple=True)
self.assertFalse(grid.sort_multiple)
def test_vue_tagname(self):
grid = self.make_grid()
@ -236,7 +245,7 @@ class TestGrid(WebTestCase):
# can skip the saving step
self.request.GET = {'pagesize': '10', 'page': '3'}
grid.load_settings(store=False)
grid.load_settings(persist=False)
self.assertEqual(grid.page, 3)
self.assertEqual(self.request.session['grid.foo.page'], 2)
@ -261,7 +270,7 @@ class TestGrid(WebTestCase):
# can skip the saving step
self.request.GET = {'sort1key': 'name', 'sort1dir': 'asc'}
grid.load_settings(store=False)
grid.load_settings(persist=False)
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'asc'}])
self.assertEqual(self.request.session['grid.settings.sorters.length'], 1)
self.assertEqual(self.request.session['grid.settings.sorters.1.key'], 'name')
@ -575,21 +584,21 @@ class TestGrid(WebTestCase):
sorted_data = sorter(sample_data, 'asc')
self.assertEqual(len(sorted_data), 9)
# case folding is off by default
# case folding is on by default
grid = self.make_grid(model_class=model.Setting)
sorter = grid.make_sorter('value')
sorted_data = sorter(sample_data, 'desc')
self.assertEqual(dict(sorted_data[0]), {'name': 'foo2', 'value': 'two'})
sorted_data = sorter(sample_data, 'asc')
self.assertEqual(dict(sorted_data[0]), {'name': 'foo1', 'value': 'ONE'})
self.assertEqual(dict(sorted_data[0]), {'name': 'foo8', 'value': 'eight'})
# results are different with case folding
# results are different with case folding off
grid = self.make_grid(model_class=model.Setting)
sorter = grid.make_sorter('value', foldcase=True)
sorter = grid.make_sorter('value', foldcase=False)
sorted_data = sorter(sample_data, 'desc')
self.assertEqual(dict(sorted_data[0]), {'name': 'foo2', 'value': 'two'})
sorted_data = sorter(sample_data, 'asc')
self.assertEqual(dict(sorted_data[0]), {'name': 'foo8', 'value': 'eight'})
self.assertEqual(dict(sorted_data[0]), {'name': 'foo1', 'value': 'ONE'})
def test_set_sorter(self):
model = self.app.model
@ -632,13 +641,38 @@ class TestGrid(WebTestCase):
def test_set_sort_defaults(self):
model = self.app.model
# basics
grid = self.make_grid(model_class=model.Setting, sortable=True)
self.assertEqual(grid.sort_defaults, [])
grid.set_sort_defaults('name', 'asc')
# can set just sortkey
grid.set_sort_defaults('name')
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'asc')])
# can set sortkey, sortdir
grid.set_sort_defaults('name', 'desc')
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'desc')])
# can set sortkey, sortdir as tuple
grid.set_sort_defaults(('value', 'asc'))
self.assertEqual(grid.sort_defaults, [mod.SortInfo('value', 'asc')])
# can set as list
grid.sort_multiple = True
grid.set_sort_defaults([('value', 'asc'), ('name', 'desc')])
self.assertEqual(grid.sort_defaults, [mod.SortInfo('value', 'asc'),
mod.SortInfo('name', 'desc')])
# list is pruned if multi-sort disabled
grid.sort_multiple = False
grid.set_sort_defaults([('value', 'asc'), ('name', 'desc')])
self.assertEqual(grid.sort_defaults, [mod.SortInfo('value', 'asc')])
# error if any other single arg
self.assertRaises(ValueError, grid.set_sort_defaults, 42)
# error if more than 2 args
self.assertRaises(ValueError, grid.set_sort_defaults, 'name', 'asc', 'value', 'desc')
def test_is_sortable(self):
model = self.app.model
@ -701,9 +735,9 @@ class TestGrid(WebTestCase):
sample_data = [
{'name': 'foo1', 'value': 'ONE'},
{'name': 'foo2', 'value': 'two'},
{'name': 'foo3', 'value': 'three'},
{'name': 'foo4', 'value': 'four'},
{'name': 'foo5', 'value': 'five'},
{'name': 'foo3', 'value': 'ggg'},
{'name': 'foo4', 'value': 'ggg'},
{'name': 'foo5', 'value': 'ggg'},
{'name': 'foo6', 'value': 'six'},
{'name': 'foo7', 'value': 'seven'},
{'name': 'foo8', 'value': 'eight'},
@ -740,15 +774,26 @@ class TestGrid(WebTestCase):
self.assertEqual(sorted_data[0]['name'], 'foo1')
self.assertEqual(sorted_data[-1]['name'], 'foo9')
# error if mult-column sort attempted
self.assertRaises(NotImplementedError, grid.sort_data, sample_data, sorters=[
{'key': 'name', 'dir': 'desc'},
{'key': 'value', 'dir': 'asc'},
])
# multi-column sorting for list data
sorted_data = grid.sort_data(sample_data, sorters=[{'key': 'value', 'dir': 'asc'},
{'key': 'name', 'dir': 'asc'}])
self.assertEqual(dict(sorted_data[0]), {'name': 'foo8', 'value': 'eight'})
self.assertEqual(dict(sorted_data[1]), {'name': 'foo3', 'value': 'ggg'})
self.assertEqual(dict(sorted_data[3]), {'name': 'foo5', 'value': 'ggg'})
self.assertEqual(dict(sorted_data[-1]), {'name': 'foo2', 'value': 'two'})
# multi-column sorting for query
sorted_query = grid.sort_data(sample_query, sorters=[{'key': 'value', 'dir': 'asc'},
{'key': 'name', 'dir': 'asc'}])
self.assertEqual(dict(sorted_data[0]), {'name': 'foo8', 'value': 'eight'})
self.assertEqual(dict(sorted_data[1]), {'name': 'foo3', 'value': 'ggg'})
self.assertEqual(dict(sorted_data[3]), {'name': 'foo5', 'value': 'ggg'})
self.assertEqual(dict(sorted_data[-1]), {'name': 'foo2', 'value': 'two'})
# cannot sort data if sortfunc is missing for column
grid.remove_sorter('name')
sorted_data = grid.sort_data(sample_data)
sorted_data = grid.sort_data(sample_data, sorters=[{'key': 'value', 'dir': 'asc'},
{'key': 'name', 'dir': 'asc'}])
# nb. sorted data is in same order as original sample (not sorted)
self.assertEqual(sorted_data[0]['name'], 'foo1')
self.assertEqual(sorted_data[-1]['name'], 'foo9')
@ -823,6 +868,24 @@ class TestGrid(WebTestCase):
self.assertEqual(first['field'], 'foo')
self.assertEqual(first['label'], 'Foo')
def test_get_vue_active_sorters(self):
model = self.app.model
# empty
grid = self.make_grid(key='foo', sortable=True, sort_on_backend=True)
grid.load_settings()
sorters = grid.get_vue_active_sorters()
self.assertEqual(sorters, [])
# format is different
grid = self.make_grid(key='settings', model_class=model.Setting,
sortable=True, sort_on_backend=True,
sort_defaults='name')
grid.load_settings()
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'asc'}])
sorters = grid.get_vue_active_sorters()
self.assertEqual(sorters, [{'field': 'name', 'order': 'asc'}])
def test_get_vue_data(self):
# empty if no columns defined