feat: inherit from wutta base class for Grid

This commit is contained in:
Lance Edgar 2024-08-16 14:34:50 -05:00
parent f7641218cb
commit 2a0b6da2f9
23 changed files with 317 additions and 274 deletions

View file

@ -38,7 +38,7 @@ from pyramid.renderers import render
from webhelpers2.html import HTML, tags
from paginate_sqlalchemy import SqlalchemyOrmPage
from wuttaweb.grids import GridAction as WuttaGridAction
from wuttaweb.grids import Grid as WuttaGrid, GridAction as WuttaGridAction
from . import filters as gridfilters
from tailbone.db import Session
from tailbone.util import raw_datetime
@ -61,7 +61,7 @@ class FieldList(list):
self.insert(i + 1, newfield)
class Grid:
class Grid(WuttaGrid):
"""
Core grid class. In sore need of documentation.
@ -186,32 +186,59 @@ class Grid:
grid.row_uuid_getter = fake_uuid
"""
def __init__(self, key, data, columns=None, width='auto', request=None,
model_class=None, model_title=None, model_title_plural=None,
enums={}, labels={}, assume_local_times=False, renderers={}, invisible=[],
raw_renderers={},
extra_row_class=None, linked_columns=[], url='#',
joiners={}, filterable=False, filters={}, use_byte_string_filters=False,
searchable={},
sortable=False, sorters={}, default_sortkey=None, default_sortdir='asc',
pageable=False, default_pagesize=None, default_page=1,
checkboxes=False, checked=None, check_handler=None, check_all_handler=None,
checkable=None, row_uuid_getter=None,
clicking_row_checks_box=False, click_handlers=None,
main_actions=[], more_actions=[], delete_speedbump=False,
ajax_data_url=None,
vue_tagname=None,
expose_direct_link=False,
**kwargs):
def __init__(
self,
request,
key=None,
data=None,
width='auto',
model_title=None,
model_title_plural=None,
enums={},
assume_local_times=False,
invisible=[],
raw_renderers={},
extra_row_class=None,
url='#',
joiners={},
filterable=False,
filters={},
use_byte_string_filters=False,
searchable={},
sortable=False,
sorters={},
default_sortkey=None,
default_sortdir='asc',
pageable=False,
default_pagesize=None,
default_page=1,
checkboxes=False,
checked=None,
check_handler=None,
check_all_handler=None,
checkable=None,
row_uuid_getter=None,
clicking_row_checks_box=False,
click_handlers=None,
main_actions=[],
more_actions=[],
delete_speedbump=False,
ajax_data_url=None,
expose_direct_link=False,
**kwargs,
):
if kwargs.get('component'):
warnings.warn("component param is deprecated for Grid(); "
"please use vue_tagname param instead",
DeprecationWarning, stacklevel=2)
kwargs.setdefault('vue_tagname', kwargs.pop('component'))
self.key = key
self.data = data
self.columns = FieldList(columns) if columns is not None else None
self.width = width
self.request = request
self.model_class = model_class
if self.model_class and self.columns is None:
self.columns = self.make_columns()
# TODO: pretty sure this should go away?
kwargs.setdefault('vue_tagname', 'tailbone-grid')
kwargs['key'] = key
kwargs['data'] = data
super().__init__(request, **kwargs)
self.model_title = model_title
if not self.model_title and self.model_class and hasattr(self.model_class, 'get_model_title'):
@ -224,15 +251,13 @@ class Grid:
if not self.model_title_plural:
self.model_title_plural = '{}s'.format(self.model_title)
self.width = width
self.enums = enums or {}
self.labels = labels or {}
self.assume_local_times = assume_local_times
self.renderers = self.make_default_renderers(renderers or {})
self.renderers = self.make_default_renderers(self.renderers)
self.raw_renderers = raw_renderers or {}
self.invisible = invisible or []
self.extra_row_class = extra_row_class
self.linked_columns = linked_columns or []
self.url = url
self.joiners = joiners or {}
@ -263,8 +288,6 @@ class Grid:
self.click_handlers = click_handlers or {}
self.main_actions = main_actions or []
self.more_actions = more_actions or []
self.delete_speedbump = delete_speedbump
if ajax_data_url:
@ -274,29 +297,22 @@ class Grid:
else:
self.ajax_data_url = ''
# vue_tagname
self.vue_tagname = vue_tagname
if not self.vue_tagname and kwargs.get('component'):
warnings.warn("component kwarg is deprecated for Grid(); "
"please use vue_tagname param instead",
self.main_actions = main_actions or []
if self.main_actions:
warnings.warn("main_actions param is deprecated for Grdi(); "
"please use actions param instead",
DeprecationWarning, stacklevel=2)
self.vue_tagname = kwargs['component']
if not self.vue_tagname:
self.vue_tagname = 'tailbone-grid'
self.actions.extend(self.main_actions)
self.more_actions = more_actions or []
if self.more_actions:
warnings.warn("more_actions param is deprecated for Grdi(); "
"please use actions param instead",
DeprecationWarning, stacklevel=2)
self.actions.extend(self.more_actions)
self.expose_direct_link = expose_direct_link
self._whgrid_kwargs = kwargs
@property
def vue_component(self):
"""
String name for the Vue component, e.g. ``'TailboneGrid'``.
This is a generated value based on :attr:`vue_tagname`.
"""
words = self.vue_tagname.split('-')
return ''.join([word.capitalize() for word in words])
@property
def component(self):
"""
@ -317,34 +333,6 @@ class Grid:
DeprecationWarning, stacklevel=2)
return self.vue_component
@property
def actions(self):
""" """
actions = []
if self.main_actions:
actions.extend(self.main_actions)
if self.more_actions:
actions.extend(self.more_actions)
return actions
def make_columns(self):
"""
Return a default list of columns, based on :attr:`model_class`.
"""
if not self.model_class:
raise ValueError("Must define model_class to use make_columns()")
mapper = orm.class_mapper(self.model_class)
return [prop.key for prop in mapper.iterate_properties]
def remove(self, *keys):
"""
This *removes* some column(s) from the grid, altogether.
"""
for key in keys:
if key in self.columns:
self.columns.remove(key)
def hide_column(self, key):
"""
This *removes* a column from the grid, altogether.
@ -377,9 +365,6 @@ class Grid:
if key in self.invisible:
self.invisible.remove(key)
def append(self, field):
self.columns.append(field)
def insert_before(self, field, newfield):
self.columns.insert_before(field, newfield)
@ -430,24 +415,22 @@ class Grid:
self.filters.pop(key, None)
def set_label(self, key, label, column_only=False):
self.labels[key] = label
"""
Set/override the label for a column.
This overrides
:meth:`~wuttaweb:wuttaweb.grids.base.Grid.set_label()` to add
the following params:
:param column_only: Boolean indicating whether the label
should be applied *only* to the column header (if
``True``), vs. applying also to the filter (if ``False``).
"""
super().set_label(key, label)
if not column_only and key in self.filters:
self.filters[key].label = label
def get_label(self, key):
"""
Returns the label text for given field key.
"""
return self.labels.get(key, prettify(key))
def set_link(self, key, link=True):
if link:
if key not in self.linked_columns:
self.linked_columns.append(key)
else: # unlink
if self.linked_columns and key in self.linked_columns:
self.linked_columns.remove(key)
def set_click_handler(self, key, handler):
if handler:
self.click_handlers[key] = handler
@ -457,9 +440,6 @@ class Grid:
def has_click_handler(self, key):
return key in self.click_handlers
def set_renderer(self, key, renderer):
self.renderers[key] = renderer
def set_raw_renderer(self, key, renderer):
"""
Set or remove the "raw" renderer for the given field.
@ -1450,22 +1430,13 @@ class Grid:
return render(template, context)
def get_view_click_handler(self):
""" """
# locate the 'view' action
# TODO: this should be easier, and/or moved elsewhere?
view = None
for action in self.main_actions:
for action in self.actions:
if action.key == 'view':
view = action
break
if not view:
for action in self.more_actions:
if action.key == 'view':
view = action
break
if view:
return view.click_handler
return action.click_handler
def set_filters_sequence(self, filters, only=False):
"""
@ -1561,26 +1532,21 @@ class Grid:
kwargs['form'] = form
return render(template, kwargs)
def render_actions(self, row, i):
"""
Returns the rendered contents of the 'actions' column for a given row.
"""
main_actions = [self.render_action(a, row, i)
for a in self.main_actions]
main_actions = [a for a in main_actions if a]
more_actions = [self.render_action(a, row, i)
for a in self.more_actions]
more_actions = [a for a in more_actions if a]
if more_actions:
icon = HTML.tag('span', class_='ui-icon ui-icon-carat-1-e')
link = tags.link_to("More" + icon, '#', class_='more')
main_actions.append(HTML.literal('  ') + link + HTML.tag('div', class_='more', c=more_actions))
return HTML.literal('').join(main_actions)
def render_actions(self, row, i): # pragma: no cover
""" """
warnings.warn("grid.render_actions() is deprecated!",
DeprecationWarning, stacklevel=2)
actions = [self.render_action(a, row, i)
for a in self.actions]
actions = [a for a in actions if a]
return HTML.literal('').join(actions)
def render_action(self, action, row, i): # pragma: no cover
""" """
warnings.warn("grid.render_action() is deprecated!",
DeprecationWarning, stacklevel=2)
def render_action(self, action, row, i):
"""
Renders an action menu item (link) for the given row.
"""
url = action.get_url(row, i)
if url:
kwargs = {'class_': action.key, 'target': action.target}
@ -1786,21 +1752,10 @@ class Grid:
Pre-generate all action URLs for the given data row. Meant for use
with client-side table, since we can't generate URLs from JS.
"""
for action in (self.main_actions + self.more_actions):
for action in self.actions:
url = action.get_url(rowobj, i)
row['_action_url_{}'.format(action.key)] = url
def is_linked(self, name):
"""
Should return ``True`` if the given column name is configured to be
"linked" (i.e. table cell should contain a link to "view object"),
otherwise ``False``.
"""
if self.linked_columns:
if name in self.linked_columns:
return True
return False
class GridAction(WuttaGridAction):
"""