feat: inherit most logic from wuttaweb, for GridAction

This commit is contained in:
Lance Edgar 2024-08-16 11:56:12 -05:00
parent 09612b1921
commit 1b78bd617c
9 changed files with 65 additions and 61 deletions

View file

@ -38,6 +38,7 @@ from pyramid.renderers import render
from webhelpers2.html import HTML, tags from webhelpers2.html import HTML, tags
from paginate_sqlalchemy import SqlalchemyOrmPage from paginate_sqlalchemy import SqlalchemyOrmPage
from wuttaweb.grids import GridAction as WuttaGridAction
from . import filters as gridfilters from . import filters as gridfilters
from tailbone.db import Session from tailbone.db import Session
from tailbone.util import raw_datetime from tailbone.util import raw_datetime
@ -1801,18 +1802,20 @@ class Grid:
return False return False
class GridAction(object): class GridAction(WuttaGridAction):
""" """
Represents an action available to a grid. This is used to construct the Represents a "row action" hyperlink within a grid context.
'actions' column when rendering the grid.
:param key: Key for the action (e.g. ``'edit'``), unique within This is a subclass of
the grid. :class:`wuttaweb:wuttaweb.grids.base.GridAction`.
:param label: Label to be displayed for the action. If not set, .. warning::
will be a capitalized version of ``key``.
:param icon: Icon name for the action. This class remains for now, to retain compatibility with
existing code. But at some point the WuttaWeb class will
supersede this one entirely.
:param target: HTML "target" attribute for the ``<a>`` tag.
:param click_handler: Optional JS click handler for the action. :param click_handler: Optional JS click handler for the action.
This value will be rendered as-is within the final grid This value will be rendered as-is within the final grid
@ -1824,41 +1827,23 @@ class GridAction(object):
* ``$emit('do-something', props.row)`` * ``$emit('do-something', props.row)``
""" """
def __init__(self, key, label=None, url='#', icon=None, target=None, def __init__(
link_class=None, click_handler=None): self,
self.key = key request,
self.label = label or prettify(key) key,
self.icon = icon target=None,
self.url = url click_handler=None,
**kwargs,
):
# TODO: previously url default was '#' - but i don't think we
# need that anymore? guess we'll see..
#kwargs.setdefault('url', '#')
super().__init__(request, key, **kwargs)
self.target = target self.target = target
self.link_class = link_class
self.click_handler = click_handler self.click_handler = click_handler
def get_url(self, row, i):
"""
Returns an action URL for the given row.
"""
if callable(self.url):
return self.url(row, i)
return self.url
def render_icon(self):
"""
Render the HTML snippet for the action link icon.
"""
return HTML.tag('i', class_='fas fa-{}'.format(self.icon))
def render_label(self):
"""
Render the label "text" within the actions column of a grid
row. Most actions have a static label that never varies, but
you can override this to add e.g. HTML content. Note that the
return value will be treated / rendered as HTML whether or not
it contains any, so perhaps be careful that it is trusted
content.
"""
return self.label
class URLMaker(object): class URLMaker(object):
""" """

View file

@ -53,11 +53,11 @@
</${b}-table-column> </${b}-table-column>
% endfor % endfor
% if grid.main_actions or grid.more_actions: % if grid.actions:
<${b}-table-column field="actions" <${b}-table-column field="actions"
label="Actions" label="Actions"
v-slot="props"> v-slot="props">
% for action in grid.main_actions: % for action in grid.actions:
<a :href="props.row._action_url_${action.key}" <a :href="props.row._action_url_${action.key}"
% if action.link_class: % if action.link_class:
class="${action.link_class}" class="${action.link_class}"
@ -68,12 +68,7 @@
@click.prevent="${action.click_handler}" @click.prevent="${action.click_handler}"
% endif % endif
> >
% if request.use_oruga: ${action.render_icon_and_label()}
<o-icon icon="${action.icon}" />
% else:
<i class="fas fa-${action.icon}"></i>
% endif
${action.label}
</a> </a>
&nbsp; &nbsp;
% endfor % endfor

View file

@ -163,13 +163,7 @@
target="${action.target}" target="${action.target}"
% endif % endif
> >
% if request.use_oruga: ${action.render_icon_and_label()}
<o-icon icon="${action.icon}" />
<span>${action.render_label()|n}</span>
% else:
${action.render_icon()|n}
${action.render_label()|n}
% endif
</a> </a>
&nbsp; &nbsp;
% endfor % endfor

View file

@ -3220,14 +3220,18 @@ class MasterView(View):
def make_action(self, key, url=None, factory=None, **kwargs): def make_action(self, key, url=None, factory=None, **kwargs):
""" """
Make a new :class:`GridAction` instance for the current grid. Make and return a new :class:`~tailbone.grids.core.GridAction`
instance.
This can be called to make actions for any grid, not just the
one from :meth:`index()`.
""" """
if url is None: if url is None:
route = '{}.{}'.format(self.get_route_prefix(), key) route = '{}.{}'.format(self.get_route_prefix(), key)
url = lambda r, i: self.request.route_url(route, **self.get_action_route_kwargs(r)) url = lambda r, i: self.request.route_url(route, **self.get_action_route_kwargs(r))
if not factory: if not factory:
factory = grids.GridAction factory = grids.GridAction
return factory(key, url=url, **kwargs) return factory(self.request, key, url=url, **kwargs)
def get_action_route_kwargs(self, obj): def get_action_route_kwargs(self, obj):
""" """

View file

@ -552,7 +552,7 @@ class PersonView(MasterView):
if self.request.has_perm('trainwreck.transactions.view'): if self.request.has_perm('trainwreck.transactions.view'):
url = lambda row, i: self.request.route_url('trainwreck.transactions.view', url = lambda row, i: self.request.route_url('trainwreck.transactions.view',
uuid=row.uuid) uuid=row.uuid)
g.main_actions.append(grids.GridAction('view', icon='eye', url=url)) g.main_actions.append(self.make_action('view', icon='eye', url=url))
g.load_settings() g.load_settings()
g.set_enum('system', self.enum.TRAINWRECK_SYSTEM) g.set_enum('system', self.enum.TRAINWRECK_SYSTEM)

View file

@ -40,7 +40,7 @@ from webhelpers2.html import tags, HTML
from wuttaweb.util import get_form_data from wuttaweb.util import get_form_data
from tailbone import forms, grids from tailbone import forms
from tailbone.views.purchasing import PurchasingBatchView from tailbone.views.purchasing import PurchasingBatchView
@ -1031,7 +1031,7 @@ class ReceivingBatchView(PurchasingBatchView):
if batch.is_truck_dump_parent(): if batch.is_truck_dump_parent():
permission_prefix = self.get_permission_prefix() permission_prefix = self.get_permission_prefix()
if self.request.has_perm('{}.edit_row'.format(permission_prefix)): if self.request.has_perm('{}.edit_row'.format(permission_prefix)):
transform = grids.GridAction('transform', transform = self.make_action('transform',
icon='shuffle', icon='shuffle',
label="Transform to Unit", label="Transform to Unit",
url=self.transform_unit_url) url=self.transform_unit_url)

View file

@ -363,7 +363,7 @@ class RoleView(PrincipalMasterView):
if role.users: if role.users:
users = sorted(role.users, key=lambda u: u.username) users = sorted(role.users, key=lambda u: u.username)
actions = [ actions = [
grids.GridAction('view', icon='zoomin', self.make_action('view', icon='zoomin',
url=lambda r, i: self.request.route_url('users.view', uuid=r.uuid)) url=lambda r, i: self.request.route_url('users.view', uuid=r.uuid))
] ]
kwargs['users'] = grids.Grid(None, users, ['username', 'active'], kwargs['users'] = grids.Grid(None, users, ['username', 'active'],

View file

@ -137,3 +137,20 @@ class TestGrid(WebTestCase):
# calling again returns same data # calling again returns same data
data2 = grid.get_vue_data() data2 = grid.get_vue_data()
self.assertIs(data2, data) self.assertIs(data2, data)
class TestGridAction(WebTestCase):
def test_constructor(self):
# null by default
action = mod.GridAction(self.request, 'view')
self.assertIsNone(action.target)
self.assertIsNone(action.click_handler)
# but can set them
action = mod.GridAction(self.request, 'view',
target='_blank',
click_handler='doSomething(props.row)')
self.assertEqual(action.target, '_blank')
self.assertEqual(action.click_handler, 'doSomething(props.row)')

View file

@ -3,6 +3,7 @@
from unittest.mock import patch from unittest.mock import patch
from tailbone.views import master as mod from tailbone.views import master as mod
from wuttaweb.grids import GridAction
from tests.util import WebTestCase from tests.util import WebTestCase
@ -24,3 +25,11 @@ class TestMasterView(WebTestCase):
# sanity / coverage check # sanity / coverage check
kw = view.make_form_kwargs(model_instance=setting) kw = view.make_form_kwargs(model_instance=setting)
self.assertIsNotNone(kw['action_url']) self.assertIsNotNone(kw['action_url'])
def test_make_action(self):
model = self.app.model
with patch.multiple(mod.MasterView, create=True,
model_class=model.Setting):
view = self.make_view()
action = view.make_action('view')
self.assertIsInstance(action, GridAction)