3
0
Fork 0

fix: add value choice/enum support for grid filters

also add `set_enum()` method for grids, which updates column renderer
as well as filter choices
This commit is contained in:
Lance Edgar 2025-02-21 13:27:52 -06:00
parent 8357fd594f
commit 37ae69de00
5 changed files with 291 additions and 1 deletions

View file

@ -2,6 +2,8 @@
import datetime
import decimal
from collections import OrderedDict
from enum import Enum
from unittest import TestCase
from unittest.mock import patch, MagicMock
@ -261,6 +263,36 @@ class TestGrid(WebTestCase):
self.assertIn('created', grid.renderers)
self.assertIsNot(grid.renderers['created'], myrender)
def test_set_enum(self):
model = self.app.model
class MockEnum(Enum):
FOO = 'foo'
BAR = 'bar'
# no enums by default
grid = self.make_grid(columns=['foo', 'bar'])
self.assertEqual(grid.enums, {})
# enum is set, but not filter choices
grid = self.make_grid(columns=['foo', 'bar'],
filterable=False,
enums={'foo': MockEnum})
self.assertIs(grid.enums['foo'], MockEnum)
self.assertEqual(grid.filters, {})
# both enum and filter choices are set
grid = self.make_grid(model_class=model.Setting,
filterable=True,
enums={'name': MockEnum})
self.assertIs(grid.enums['name'], MockEnum)
self.assertIn('name', grid.filters)
self.assertIn('value', grid.filters)
self.assertEqual(grid.filters['name'].choices, OrderedDict([
('FOO', 'foo'),
('BAR', 'bar'),
]))
def test_linked_columns(self):
grid = self.make_grid(columns=['foo', 'bar'])
self.assertEqual(grid.linked_columns, [])
@ -1432,6 +1464,20 @@ class TestGrid(WebTestCase):
value = decimal.Decimal('-42.42')
self.assertEqual(grid.render_currency(obj, 'foo', value), '($42.42)')
def test_render_enum(self):
enum = self.app.enum
grid = self.make_grid(columns=['foo', 'bar'])
obj = {'status': None}
# null
value = grid.render_enum(obj, 'status', None, enum=enum.UpgradeStatus)
self.assertIsNone(value)
# normal
obj['status'] = enum.UpgradeStatus.SUCCESS
value = grid.render_enum(obj, 'status', 'SUCCESS', enum=enum.UpgradeStatus)
self.assertEqual(value, 'success')
def test_render_percent(self):
grid = self.make_grid(columns=['foo', 'bar'])
obj = MagicMock()
@ -1572,6 +1618,27 @@ class TestGrid(WebTestCase):
grid.load_settings()
filters = grid.get_vue_filters()
self.assertEqual(len(filters), 2)
name, value = filters
self.assertEqual(name['choices'], [])
self.assertEqual(name['choice_labels'], {})
self.assertEqual(value['choices'], [])
self.assertEqual(value['choice_labels'], {})
class MockEnum(Enum):
FOO = 'foo'
BAR = 'bar'
# with filter choices
grid = self.make_grid(key='settings', model_class=model.Setting,
filterable=True, enums={'name': MockEnum})
grid.load_settings()
filters = grid.get_vue_filters()
self.assertEqual(len(filters), 2)
name, value = filters
self.assertEqual(name['choices'], ['FOO', 'BAR'])
self.assertEqual(name['choice_labels'], {'FOO': 'foo', 'BAR': 'bar'})
self.assertEqual(value['choices'], [])
self.assertEqual(value['choice_labels'], {})
def test_object_to_dict(self):
grid = self.make_grid()

View file

@ -1,6 +1,8 @@
# -*- coding: utf-8; -*-
import datetime
from collections import OrderedDict
from enum import Enum
from unittest import TestCase
from unittest.mock import patch
@ -136,6 +138,67 @@ class TestGridFilter(WebTestCase):
self.assertIsInstance(verbs, list)
self.assertIn('is_any', verbs)
def test_set_choices(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter)
self.assertEqual(filtr.choices, {})
self.assertEqual(filtr.data_type, 'string')
class MockEnum(Enum):
FOO = 'foo'
BAR = 'bar'
filtr.set_choices(MockEnum)
self.assertEqual(filtr.choices, OrderedDict([
('FOO', 'foo'),
('BAR', 'bar'),
]))
self.assertEqual(filtr.data_type, 'choice')
filtr.set_choices(None)
self.assertEqual(filtr.choices, {})
self.assertEqual(filtr.data_type, 'string')
def test_normalize_choices(self):
model = self.app.model
filtr = self.make_filter(model.Setting.name, factory=mod.AlchemyFilter)
class MockEnum(Enum):
FOO = 'foo'
BAR = 'bar'
choices = filtr.normalize_choices(MockEnum)
self.assertEqual(choices, OrderedDict([
('FOO', 'foo'),
('BAR', 'bar'),
]))
choices = filtr.normalize_choices(OrderedDict([
('first', '1'),
('second', '2'),
]))
self.assertEqual(choices, OrderedDict([
('first', '1'),
('second', '2'),
]))
choices = filtr.normalize_choices({
'bbb': 'b',
'aaa': 'a',
})
self.assertEqual(choices, OrderedDict([
('aaa', 'a'),
('bbb', 'b'),
]))
choices = filtr.normalize_choices(['one', 'two', 'three'])
self.assertEqual(choices, OrderedDict([
('one', 'one'),
('two', 'two'),
('three', 'three'),
]))
def test_apply_filter(self):
model = self.app.model
filtr = self.make_filter(model.Setting.value, factory=mod.StringAlchemyFilter)