Compare commits
No commits in common. "7fcc24ce0ddc574055214f02ef4ab5d2f3ac2369" and "55a97211c1c9f361362ab15151a42674ed959b4d" have entirely different histories.
7fcc24ce0d
...
55a97211c1
12 changed files with 78 additions and 270 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
|
@ -5,19 +5,6 @@ All notable changes to wuttaweb will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## v0.28.2 (2026-02-25)
|
|
||||||
|
|
||||||
### Fix
|
|
||||||
|
|
||||||
- only show string filter input if data type matches
|
|
||||||
- move `coerce_value()` method to base `GridFilter` class
|
|
||||||
- preserve original data type when un-setting filter choices
|
|
||||||
- raise better error if field widget serialization fails
|
|
||||||
- tweak how grid filter params are built, for better link share
|
|
||||||
- allow passing filter factory to `Grid.set_filter()`
|
|
||||||
- track column-only labels separately for grid
|
|
||||||
- make view responsible for App Info field/values
|
|
||||||
|
|
||||||
## v0.28.1 (2026-02-17)
|
## v0.28.1 (2026-02-17)
|
||||||
|
|
||||||
### Fix
|
### Fix
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "WuttaWeb"
|
name = "WuttaWeb"
|
||||||
version = "0.28.2"
|
version = "0.28.1"
|
||||||
description = "Web App for Wutta Framework"
|
description = "Web App for Wutta Framework"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
|
authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
|
||||||
|
|
|
||||||
|
|
@ -1138,18 +1138,7 @@ class Form: # pylint: disable=too-many-instance-attributes,too-many-public-meth
|
||||||
field = dform[fieldname]
|
field = dform[fieldname]
|
||||||
if readonly:
|
if readonly:
|
||||||
kwargs["readonly"] = True
|
kwargs["readonly"] = True
|
||||||
|
|
||||||
try:
|
|
||||||
html = field.serialize(**kwargs)
|
html = field.serialize(**kwargs)
|
||||||
except Exception as exc:
|
|
||||||
log.warning(
|
|
||||||
"widget serialization failed for field: %s",
|
|
||||||
fieldname,
|
|
||||||
exc_info=True,
|
|
||||||
)
|
|
||||||
raise RuntimeError(
|
|
||||||
f"widget serialization failed for field: {fieldname}"
|
|
||||||
) from exc
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# render static text if field not in deform/schema
|
# render static text if field not in deform/schema
|
||||||
|
|
|
||||||
|
|
@ -119,17 +119,9 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
|
||||||
|
|
||||||
.. attribute:: labels
|
.. attribute:: labels
|
||||||
|
|
||||||
Dict of column and/or filter label overrides.
|
Dict of column label overrides.
|
||||||
|
|
||||||
See also :attr:`column_labels`, :meth:`set_label()`,
|
See also :meth:`get_label()` and :meth:`set_label()`.
|
||||||
:meth:`get_column_label()` and :meth:`get_filter_label()`.
|
|
||||||
|
|
||||||
.. attribute:: column_labels
|
|
||||||
|
|
||||||
Dict of label overrides for column only.
|
|
||||||
|
|
||||||
See also :attr:`labels`, :meth:`set_label()` and
|
|
||||||
:meth:`get_column_label()`.
|
|
||||||
|
|
||||||
.. attribute:: centered
|
.. attribute:: centered
|
||||||
|
|
||||||
|
|
@ -442,7 +434,6 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
|
||||||
self.key = key
|
self.key = key
|
||||||
self.data = data
|
self.data = data
|
||||||
self.labels = labels or {}
|
self.labels = labels or {}
|
||||||
self.column_labels = {}
|
|
||||||
self.checkable = checkable
|
self.checkable = checkable
|
||||||
self.row_class = row_class
|
self.row_class = row_class
|
||||||
self.actions = actions or []
|
self.actions = actions or []
|
||||||
|
|
@ -637,61 +628,35 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
|
||||||
|
|
||||||
def set_label(self, key, label, column_only=False):
|
def set_label(self, key, label, column_only=False):
|
||||||
"""
|
"""
|
||||||
Set/override the label for a column and/or filter.
|
Set/override the label for a column.
|
||||||
|
|
||||||
:param key: Key for the column/filter.
|
:param key: Name of column.
|
||||||
|
|
||||||
:param label: New label for the column and/or filter.
|
:param label: New label for the column header.
|
||||||
|
|
||||||
:param column_only: Boolean indicating whether the label
|
:param column_only: Boolean indicating whether the label
|
||||||
should be applied *only* to the column header (if
|
should be applied *only* to the column header (if
|
||||||
``True``), vs. applying also to the filter (if ``False``).
|
``True``), vs. applying also to the filter (if ``False``).
|
||||||
|
|
||||||
See also :meth:`get_column_label()` and
|
See also :meth:`get_label()`. Label overrides are tracked via
|
||||||
:meth:`get_filter_label()`. Label overrides are tracked via
|
:attr:`labels`.
|
||||||
:attr:`labels` and :attr:`column_labels`.
|
|
||||||
"""
|
"""
|
||||||
if column_only:
|
|
||||||
self.column_labels[key] = label
|
|
||||||
else:
|
|
||||||
self.labels[key] = label
|
self.labels[key] = label
|
||||||
if key in self.filters:
|
|
||||||
|
if not column_only and key in self.filters:
|
||||||
self.filters[key].label = label
|
self.filters[key].label = label
|
||||||
|
|
||||||
def get_label(self, key): # pylint: disable=missing-function-docstring
|
def get_label(self, key):
|
||||||
warnings.warn(
|
|
||||||
"Grid.get_label() is deprecated; please use "
|
|
||||||
"get_filter_label() or get_column_label() instead",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self.get_filter_label(key)
|
|
||||||
|
|
||||||
def get_filter_label(self, key):
|
|
||||||
"""
|
|
||||||
Returns the label text for a given filter.
|
|
||||||
|
|
||||||
If no override is defined, the label is derived from ``key``.
|
|
||||||
|
|
||||||
See also :meth:`set_label()` and :meth:`get_column_label()`.
|
|
||||||
"""
|
|
||||||
if key in self.labels:
|
|
||||||
return self.labels[key]
|
|
||||||
|
|
||||||
return self.app.make_title(key)
|
|
||||||
|
|
||||||
def get_column_label(self, key):
|
|
||||||
"""
|
"""
|
||||||
Returns the label text for a given column.
|
Returns the label text for a given column.
|
||||||
|
|
||||||
If no override is defined, the label is derived from ``key``.
|
If no override is defined, the label is derived from ``key``.
|
||||||
|
|
||||||
See also :meth:`set_label()` and :meth:`get_filter_label()`.
|
See also :meth:`set_label()`.
|
||||||
"""
|
"""
|
||||||
if key in self.column_labels:
|
if key in self.labels:
|
||||||
return self.column_labels[key]
|
return self.labels[key]
|
||||||
|
return self.app.make_title(key)
|
||||||
return self.get_filter_label(key)
|
|
||||||
|
|
||||||
def set_centered(self, key, centered=True):
|
def set_centered(self, key, centered=True):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1404,11 +1369,10 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
|
||||||
Code usually does not need to call this directly. See also
|
Code usually does not need to call this directly. See also
|
||||||
:meth:`set_filter()`, which calls this method automatically.
|
:meth:`set_filter()`, which calls this method automatically.
|
||||||
|
|
||||||
:param columninfo: Can be either a model property
|
:param columninfo: Can be either a model property (see below),
|
||||||
(e.g. ``model.User.username``), or a column name
|
or a column name.
|
||||||
(e.g. ``"username"``).
|
|
||||||
|
|
||||||
:returns: :class:`~wuttaweb.grids.filters.GridFilter`
|
:returns: A :class:`~wuttaweb.grids.filters.GridFilter`
|
||||||
instance.
|
instance.
|
||||||
"""
|
"""
|
||||||
key = kwargs.pop("key", None)
|
key = kwargs.pop("key", None)
|
||||||
|
|
@ -1446,18 +1410,12 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
|
||||||
|
|
||||||
:param key: Name of column.
|
:param key: Name of column.
|
||||||
|
|
||||||
:param filterinfo: Can be either a filter factory, or else a
|
:param filterinfo: Can be either a
|
||||||
model property (e.g. ``model.User.username``) or column
|
:class:`~wuttweb.grids.filters.GridFilter` instance, or
|
||||||
name (e.g. ``"username"``). If not specified then the
|
else a model property (see below).
|
||||||
``key`` will be used instead.
|
|
||||||
|
|
||||||
:param \\**kwargs: Additional kwargs to pass along to the
|
If ``filterinfo`` is a ``GridFilter`` instance, it will be
|
||||||
filter factory.
|
used as-is for the backend filter.
|
||||||
|
|
||||||
If ``filterinfo`` is a factory, it will be called with the
|
|
||||||
current request, key and kwargs like so::
|
|
||||||
|
|
||||||
filtr = factory(self.request, key, **kwargs)
|
|
||||||
|
|
||||||
Otherwise :meth:`make_filter()` will be called to obtain the
|
Otherwise :meth:`make_filter()` will be called to obtain the
|
||||||
backend filter. The ``filterinfo`` will be passed along to
|
backend filter. The ``filterinfo`` will be passed along to
|
||||||
|
|
@ -1469,12 +1427,11 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
|
||||||
filtr = None
|
filtr = None
|
||||||
|
|
||||||
if filterinfo and callable(filterinfo):
|
if filterinfo and callable(filterinfo):
|
||||||
kwargs.setdefault("label", self.get_filter_label(key))
|
# filtr = filterinfo
|
||||||
filtr = filterinfo(self.request, key, **kwargs)
|
raise NotImplementedError
|
||||||
|
|
||||||
else:
|
|
||||||
kwargs["key"] = key
|
kwargs["key"] = key
|
||||||
kwargs.setdefault("label", self.get_filter_label(key))
|
kwargs.setdefault("label", self.get_label(key))
|
||||||
filtr = self.make_filter(filterinfo or key, **kwargs)
|
filtr = self.make_filter(filterinfo or key, **kwargs)
|
||||||
|
|
||||||
self.filters[key] = filtr
|
self.filters[key] = filtr
|
||||||
|
|
@ -2357,7 +2314,7 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
|
||||||
columns.append(
|
columns.append(
|
||||||
{
|
{
|
||||||
"field": name,
|
"field": name,
|
||||||
"label": self.get_column_label(name),
|
"label": self.get_label(name),
|
||||||
"hidden": self.is_hidden(name),
|
"hidden": self.is_hidden(name),
|
||||||
"sortable": self.is_sortable(name),
|
"sortable": self.is_sortable(name),
|
||||||
"searchable": self.is_searchable(name),
|
"searchable": self.is_searchable(name),
|
||||||
|
|
|
||||||
|
|
@ -189,10 +189,6 @@ class GridFilter: # pylint: disable=too-many-instance-attributes
|
||||||
self.app = self.config.get_app()
|
self.app = self.config.get_app()
|
||||||
self.label = label or self.app.make_title(self.key)
|
self.label = label or self.app.make_title(self.key)
|
||||||
|
|
||||||
# remember original data type in case we need to revert,
|
|
||||||
# e.g. after changing it to 'choices' and back again
|
|
||||||
self.original_data_type = self.data_type
|
|
||||||
|
|
||||||
# active
|
# active
|
||||||
self.default_active = default_active
|
self.default_active = default_active
|
||||||
self.active = self.default_active
|
self.active = self.default_active
|
||||||
|
|
@ -205,7 +201,7 @@ class GridFilter: # pylint: disable=too-many-instance-attributes
|
||||||
self.verb = None # active verb is set later
|
self.verb = None # active verb is set later
|
||||||
|
|
||||||
# choices
|
# choices
|
||||||
self.set_choices(choices)
|
self.set_choices(choices or {})
|
||||||
|
|
||||||
# nullable
|
# nullable
|
||||||
self.nullable = nullable
|
self.nullable = nullable
|
||||||
|
|
@ -308,8 +304,7 @@ class GridFilter: # pylint: disable=too-many-instance-attributes
|
||||||
self.data_type = "choice"
|
self.data_type = "choice"
|
||||||
else:
|
else:
|
||||||
self.choices = {}
|
self.choices = {}
|
||||||
if self.data_type == "choice":
|
self.data_type = "string"
|
||||||
self.data_type = self.original_data_type
|
|
||||||
|
|
||||||
def normalize_choices(self, choices):
|
def normalize_choices(self, choices):
|
||||||
"""
|
"""
|
||||||
|
|
@ -350,26 +345,6 @@ class GridFilter: # pylint: disable=too-many-instance-attributes
|
||||||
|
|
||||||
return normalized
|
return normalized
|
||||||
|
|
||||||
def coerce_value(self, value):
|
|
||||||
"""
|
|
||||||
Coerce the given value to the correct type/format for use with
|
|
||||||
the filter. This is where e.g. a boolean or date filter
|
|
||||||
should convert input string to ``bool`` or ``date`` value.
|
|
||||||
|
|
||||||
This is (usually) called from a filter method, when applying
|
|
||||||
the filter. See also :meth:`apply_filter()`.
|
|
||||||
|
|
||||||
Default logic on the base class returns value as-is; subclass
|
|
||||||
may override as needed.
|
|
||||||
|
|
||||||
:param value: Input string provided by the user via the filter
|
|
||||||
form submission.
|
|
||||||
|
|
||||||
:returns: Value of the appropriate type, depending on the
|
|
||||||
filter subclass.
|
|
||||||
"""
|
|
||||||
return value
|
|
||||||
|
|
||||||
def apply_filter(self, data, verb=None, value=UNSPECIFIED):
|
def apply_filter(self, data, verb=None, value=UNSPECIFIED):
|
||||||
"""
|
"""
|
||||||
Filter the given data set according to a verb/value pair.
|
Filter the given data set according to a verb/value pair.
|
||||||
|
|
@ -440,6 +415,15 @@ class AlchemyFilter(GridFilter):
|
||||||
if len(columns) == 1:
|
if len(columns) == 1:
|
||||||
self.nullable = columns[0].nullable
|
self.nullable = columns[0].nullable
|
||||||
|
|
||||||
|
def coerce_value(self, value):
|
||||||
|
"""
|
||||||
|
Coerce the given value to the correct type/format for use with
|
||||||
|
the filter.
|
||||||
|
|
||||||
|
Default logic returns value as-is; subclass may override.
|
||||||
|
"""
|
||||||
|
return value
|
||||||
|
|
||||||
def filter_equal(self, query, value):
|
def filter_equal(self, query, value):
|
||||||
"""
|
"""
|
||||||
Filter data with an equal (``=``) condition.
|
Filter data with an equal (``=``) condition.
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,30 @@
|
||||||
<p class="panel-heading">Application</p>
|
<p class="panel-heading">Application</p>
|
||||||
<div class="panel-block">
|
<div class="panel-block">
|
||||||
<div style="width: 100%;">
|
<div style="width: 100%;">
|
||||||
% for key, info in (appinfo or {}).items():
|
<b-field horizontal label="Distribution">
|
||||||
<b-field horizontal label="${info['label']}">
|
<span>${app.get_distribution() or f'?? - set config for `{app.appname}.app_dist`'}</span>
|
||||||
<span>${info["value"]}</span>
|
</b-field>
|
||||||
|
<b-field horizontal label="Version">
|
||||||
|
<span>${app.get_version() or f'?? - set config for `{app.appname}.app_dist`'}</span>
|
||||||
|
</b-field>
|
||||||
|
<b-field horizontal label="App Title">
|
||||||
|
<span>${app.get_title()}</span>
|
||||||
|
</b-field>
|
||||||
|
<b-field horizontal label="Node Title">
|
||||||
|
<span>${app.get_node_title()}</span>
|
||||||
|
</b-field>
|
||||||
|
<b-field horizontal label="DB Backend">
|
||||||
|
<span>${config.appdb_engine.dialect.name}</span>
|
||||||
|
</b-field>
|
||||||
|
<b-field horizontal label="Time Zone">
|
||||||
|
<span>${app.get_timezone_name()}</span>
|
||||||
|
</b-field>
|
||||||
|
<b-field horizontal label="Production Mode">
|
||||||
|
<span>${"Yes" if config.production() else "No"}</span>
|
||||||
|
</b-field>
|
||||||
|
<b-field horizontal label="Email Enabled">
|
||||||
|
<span>${"Yes" if app.get_email_handler().sending_is_enabled() else "No"}</span>
|
||||||
</b-field>
|
</b-field>
|
||||||
% endfor
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
||||||
|
|
@ -653,21 +653,9 @@
|
||||||
params[filter.key+'.verb'] = filter.verb
|
params[filter.key+'.verb'] = filter.verb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Object.keys(params).length) {
|
||||||
## nb. we used to add filter=true only if some
|
|
||||||
## filter(s) is currently active, but that can cause
|
|
||||||
## problems when sharing a link for a grid which
|
|
||||||
## *currently* has no active filters, but which does
|
|
||||||
## have *default* filters. so for now we always
|
|
||||||
## declare filters to be "in effect" even if there
|
|
||||||
## are none active. hopefully that does not break
|
|
||||||
## anything else but this note is here just in case.
|
|
||||||
|
|
||||||
## if (Object.keys(params).length) {
|
|
||||||
## params.filter = 'true'
|
|
||||||
## }
|
|
||||||
params.filter = 'true'
|
params.filter = 'true'
|
||||||
|
}
|
||||||
return params
|
return params
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -623,7 +623,7 @@
|
||||||
</option>
|
</option>
|
||||||
</b-select>
|
</b-select>
|
||||||
|
|
||||||
<wutta-filter-value v-if="filter.data_type == 'string'"
|
<wutta-filter-value v-else
|
||||||
v-model="filter.value"
|
v-model="filter.value"
|
||||||
ref="filterValue"
|
ref="filterValue"
|
||||||
v-show="valuedVerb()"
|
v-show="valuedVerb()"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# wuttaweb -- Web App for Wutta Framework
|
# wuttaweb -- Web App for Wutta Framework
|
||||||
# Copyright © 2024-2026 Lance Edgar
|
# Copyright © 2024-2025 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Wutta Framework.
|
# This file is part of Wutta Framework.
|
||||||
#
|
#
|
||||||
|
|
@ -73,80 +73,6 @@ class AppInfoView(MasterView): # pylint: disable=abstract-method
|
||||||
# TODO: for tailbone backward compat with get_liburl() etc.
|
# TODO: for tailbone backward compat with get_liburl() etc.
|
||||||
weblib_config_prefix = None
|
weblib_config_prefix = None
|
||||||
|
|
||||||
def get_template_context(self, context): # pylint: disable=empty-docstring
|
|
||||||
""" """
|
|
||||||
if self.listing:
|
|
||||||
context["appinfo"] = self.get_appinfo_dict()
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_appinfo_dict(self): # pylint: disable=missing-function-docstring
|
|
||||||
return OrderedDict(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
"distribution",
|
|
||||||
{
|
|
||||||
"label": "Distribution",
|
|
||||||
"value": self.app.get_distribution()
|
|
||||||
or f"?? - set config for `{self.app.appname}.app_dist`",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"version",
|
|
||||||
{
|
|
||||||
"label": "Version",
|
|
||||||
"value": self.app.get_version()
|
|
||||||
or f"?? - set config for `{self.app.appname}.app_dist`",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"app_title",
|
|
||||||
{
|
|
||||||
"label": "App Title",
|
|
||||||
"value": self.app.get_title(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"node_title",
|
|
||||||
{
|
|
||||||
"label": "Node Title",
|
|
||||||
"value": self.app.get_node_title(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"db_backend",
|
|
||||||
{
|
|
||||||
"label": "DB Backend",
|
|
||||||
"value": self.config.appdb_engine.dialect.name,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"timezone",
|
|
||||||
{
|
|
||||||
"label": "Timezone",
|
|
||||||
"value": self.app.get_timezone_name(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"production",
|
|
||||||
{
|
|
||||||
"label": "Production Mode",
|
|
||||||
"value": "Yes" if self.config.production() else "No",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"email_enabled",
|
|
||||||
{
|
|
||||||
"label": "Email Enabled",
|
|
||||||
"value": (
|
|
||||||
"Yes"
|
|
||||||
if self.app.get_email_handler().sending_is_enabled()
|
|
||||||
else "No"
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_grid_data( # pylint: disable=empty-docstring
|
def get_grid_data( # pylint: disable=empty-docstring
|
||||||
self, columns=None, session=None
|
self, columns=None, session=None
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -587,14 +587,6 @@ class TestForm(WebTestCase):
|
||||||
html = form.render_vue_field("foo")
|
html = form.render_vue_field("foo")
|
||||||
self.assertIn("something is wrong", html)
|
self.assertIn("something is wrong", html)
|
||||||
|
|
||||||
class BadWidget(deform.widget.Widget):
|
|
||||||
def serialize(self, **kwargs):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
# widget serialization error
|
|
||||||
dform["foo"].widget = BadWidget()
|
|
||||||
self.assertRaises(RuntimeError, form.render_vue_field, "foo")
|
|
||||||
|
|
||||||
# add another field, but not to deform, so it should still
|
# add another field, but not to deform, so it should still
|
||||||
# display but with no widget
|
# display but with no widget
|
||||||
form.fields.append("zanzibar")
|
form.fields.append("zanzibar")
|
||||||
|
|
|
||||||
|
|
@ -198,48 +198,17 @@ class TestGrid(WebTestCase):
|
||||||
# can replace label
|
# can replace label
|
||||||
grid.set_label("name", "Different")
|
grid.set_label("name", "Different")
|
||||||
self.assertEqual(grid.labels["name"], "Different")
|
self.assertEqual(grid.labels["name"], "Different")
|
||||||
self.assertEqual(grid.get_filter_label("name"), "Different")
|
self.assertEqual(grid.get_label("name"), "Different")
|
||||||
self.assertEqual(grid.get_column_label("name"), "Different")
|
|
||||||
|
|
||||||
# can update only column, not filter
|
# can update only column, not filter
|
||||||
self.assertEqual(grid.labels, {"name": "Different"})
|
self.assertEqual(grid.labels, {"name": "Different"})
|
||||||
self.assertEqual(grid.column_labels, {})
|
|
||||||
self.assertIn("name", grid.filters)
|
self.assertIn("name", grid.filters)
|
||||||
self.assertEqual(grid.filters["name"].label, "Different")
|
self.assertEqual(grid.filters["name"].label, "Different")
|
||||||
grid.set_label("name", "COLUMN ONLY", column_only=True)
|
grid.set_label("name", "COLUMN ONLY", column_only=True)
|
||||||
self.assertEqual(grid.get_column_label("name"), "COLUMN ONLY")
|
self.assertEqual(grid.get_label("name"), "COLUMN ONLY")
|
||||||
self.assertEqual(grid.get_filter_label("name"), "Different")
|
self.assertEqual(grid.filters["name"].label, "Different")
|
||||||
|
|
||||||
def test_get_filter_label(self):
|
|
||||||
grid = self.make_grid(columns=["foo", "bar"])
|
|
||||||
self.assertEqual(grid.labels, {})
|
|
||||||
|
|
||||||
# default derived from key
|
|
||||||
self.assertEqual(grid.get_filter_label("foo"), "Foo")
|
|
||||||
|
|
||||||
# can override
|
|
||||||
grid.set_label("foo", "Different")
|
|
||||||
self.assertEqual(grid.get_filter_label("foo"), "Different")
|
|
||||||
|
|
||||||
def test_get_column_label(self):
|
|
||||||
grid = self.make_grid(columns=["foo", "bar"])
|
|
||||||
self.assertEqual(grid.labels, {})
|
|
||||||
|
|
||||||
# default derived from key
|
|
||||||
self.assertEqual(grid.get_column_label("foo"), "Foo")
|
|
||||||
|
|
||||||
# can override "globally"
|
|
||||||
grid.set_label("foo", "Different")
|
|
||||||
self.assertEqual(grid.get_column_label("foo"), "Different")
|
|
||||||
|
|
||||||
# can override for "just column"
|
|
||||||
grid.set_label("foo", "Col Lbl", column_only=True)
|
|
||||||
self.assertEqual(grid.get_column_label("foo"), "Col Lbl")
|
|
||||||
|
|
||||||
def test_get_label(self):
|
def test_get_label(self):
|
||||||
# nb. the get_label() method is deprecated; can remove this
|
|
||||||
# test eventually
|
|
||||||
|
|
||||||
grid = self.make_grid(columns=["foo", "bar"])
|
grid = self.make_grid(columns=["foo", "bar"])
|
||||||
self.assertEqual(grid.labels, {})
|
self.assertEqual(grid.labels, {})
|
||||||
|
|
||||||
|
|
@ -1310,13 +1279,10 @@ class TestGrid(WebTestCase):
|
||||||
grid.set_filter("name")
|
grid.set_filter("name")
|
||||||
self.assertIn("name", grid.filters)
|
self.assertIn("name", grid.filters)
|
||||||
|
|
||||||
# auto from filter factory
|
# explicit is not yet implemented
|
||||||
grid = self.make_grid(model_class=model.Setting)
|
grid = self.make_grid(model_class=model.Setting)
|
||||||
self.assertEqual(grid.filters, {})
|
self.assertEqual(grid.filters, {})
|
||||||
grid.set_filter(
|
self.assertRaises(NotImplementedError, grid.set_filter, "name", lambda q: q)
|
||||||
"name", StringAlchemyFilter, model_property=model.Setting.name
|
|
||||||
)
|
|
||||||
self.assertIn("name", grid.filters)
|
|
||||||
|
|
||||||
def test_remove_filter(self):
|
def test_remove_filter(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
|
|
||||||
|
|
@ -454,8 +454,8 @@ class TestBatchMasterView(WebTestCase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
grid.columns, ["sequence", "status_code", "modified"]
|
grid.columns, ["sequence", "status_code", "modified"]
|
||||||
)
|
)
|
||||||
self.assertIn("sequence", grid.column_labels)
|
self.assertIn("sequence", grid.labels)
|
||||||
self.assertEqual(grid.column_labels["sequence"], "Seq.")
|
self.assertEqual(grid.labels["sequence"], "Seq.")
|
||||||
self.assertEqual(grid.tools, {})
|
self.assertEqual(grid.tools, {})
|
||||||
|
|
||||||
# missing 'sequence' column
|
# missing 'sequence' column
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue