Przeglądaj źródła

Introduce BooleanColumn for showing boolean values as tick/cross icons

Sage Abdullah 1 rok temu
rodzic
commit
c56ec67a39

+ 18 - 0
docs/reference/contrib/modeladmin/migrating_to_snippets.md

@@ -53,6 +53,24 @@ There are a few attributes of `ModelAdmin` that need to be renamed/adjusted for
 | `form_fields_exclude`  | {attr}`~wagtail.admin.viewsets.model.ModelViewSet.exclude_form_fields`           | Same value, but different attribute name to better align with `ModelViewSet`. |
 | - | {attr}`~SnippetViewSet.template_prefix` | New attribute. Set to the name of a template directory to override the `"wagtailsnippets/snippets/"` default. If set to `"modeladmin/"`, the template directory structure will be equal to what ModelAdmin uses. Make sure any custom templates are placed in the correct directory according to this prefix. See [](wagtailsnippets_templates) for more details. |
 
+### Boolean properties in `list_display`
+
+In ModelAdmin, boolean fields in `list_display` are rendered as tick/cross icons. To achieve the same behavior in SnippetViewSet, you need to use a `wagtail.admin.ui.tables.BooleanColumn` instance in `SnippetViewSet.list_display`:
+
+```python
+from wagtail.admin.ui.tables import BooleanColumn
+
+
+class MySnippetViewSet(SnippetViewSet):
+    list_display = ("title", BooleanColumn("is_active"))
+```
+
+The `BooleanColumn` class works with both model fields and custom properties that return booleans.
+
+```{versionadded} 5.1.1
+The `BooleanColumn` class was added.
+```
+
 ## Convert `ModelAdminGroup` class to `SnippetViewSetGroup`
 
 The {class}`~SnippetViewSetGroup` class is the snippets-equivalent to the `ModelAdminGroup` class. To migrate a `ModelAdminGroup` class to a `SnippetViewSetGroup` class, follow these instructions.

+ 10 - 0
wagtail/admin/templates/wagtailadmin/tables/boolean_cell.html

@@ -0,0 +1,10 @@
+{% load wagtailadmin_tags %}
+<td {% if column.classname %}class="{{ column.classname }}"{% endif %}>
+    {% if value is None %}
+        {% icon title=value|stringformat:'s' name="help" classname="default" %}
+    {% elif value %}
+        {% icon title=value|stringformat:'s' name="success" classname="default w-text-positive-100" %}
+    {% else %}
+        {% icon title=value|stringformat:'s' name="error" classname="default w-text-critical-100" %}
+    {% endif %}
+</td>

+ 6 - 0
wagtail/admin/ui/tables/__init__.py

@@ -243,6 +243,12 @@ class StatusTagColumn(Column):
         return context
 
 
+class BooleanColumn(Column):
+    """Represents a True/False/None value as a tick/cross/question icon"""
+
+    cell_template_name = "wagtailadmin/tables/boolean_cell.html"
+
+
 class LiveStatusTagColumn(StatusTagColumn):
     """Represents a live/draft status tag"""
 

+ 46 - 2
wagtail/snippets/tests/test_viewset.py

@@ -667,6 +667,7 @@ class TestListViewWithCustomColumns(BaseSnippetViewSetTests):
         self.assertContains(response, "Custom FOO column")
         self.assertContains(response, "Updated")
         self.assertContains(response, "Modulo two")
+        self.assertContains(response, "Tristate")
 
         self.assertContains(response, "Foo UK")
 
@@ -678,14 +679,57 @@ class TestListViewWithCustomColumns(BaseSnippetViewSetTests):
 
         html = response.content.decode()
 
-        # The bulk actions column plus 5 columns defined in FullFeaturedSnippetViewSet
-        self.assertTagInHTML("<th>", html, count=6, allow_extra_attrs=True)
+        # The bulk actions column plus 6 columns defined in FullFeaturedSnippetViewSet
+        self.assertTagInHTML("<th>", html, count=7, allow_extra_attrs=True)
 
     def test_falsy_value(self):
         # https://github.com/wagtail/wagtail/issues/10765
         response = self.get()
         self.assertContains(response, "<td>0</td>", html=True, count=1)
 
+    def test_boolean_column(self):
+        self.model.objects.create(text="Another one")
+        response = self.get()
+        self.assertContains(
+            response,
+            """
+            <td>
+                <svg class="icon icon-success default w-text-positive-100" aria-hidden="true">
+                    <use href="#icon-success"></use>
+                </svg>
+                <span class="visuallyhidden">True</span>
+            </td>
+            """,
+            html=True,
+            count=1,
+        )
+        self.assertContains(
+            response,
+            """
+            <td>
+                <svg class="icon icon-error default w-text-critical-100" aria-hidden="true">
+                    <use href="#icon-error"></use>
+                </svg>
+                <span class="visuallyhidden">False</span>
+            </td>
+            """,
+            html=True,
+            count=1,
+        )
+        self.assertContains(
+            response,
+            """
+            <td>
+                <svg class="icon icon-help default" aria-hidden="true">
+                    <use href="#icon-help"></use>
+                </svg>
+                <span class="visuallyhidden">None</span>
+            </td>
+            """,
+            html=True,
+            count=1,
+        )
+
 
 class TestListExport(BaseSnippetViewSetTests):
     model = FullFeaturedSnippet

+ 3 - 0
wagtail/test/testapp/models.py

@@ -1132,6 +1132,9 @@ class FullFeaturedSnippet(
     def modulo_two(self):
         return self.pk % 2
 
+    def tristate(self):
+        return (None, True, False)[self.pk % 3]
+
     def get_preview_template(self, request, mode_name):
         return "tests/previewable_model.html"
 

+ 2 - 1
wagtail/test/testapp/wagtail_hooks.py

@@ -17,7 +17,7 @@ from wagtail.admin.rich_text.converters.html_to_contentstate import BlockElement
 from wagtail.admin.search import SearchArea
 from wagtail.admin.site_summary import SummaryItem
 from wagtail.admin.ui.components import Component
-from wagtail.admin.ui.tables import UpdatedAtColumn
+from wagtail.admin.ui.tables import BooleanColumn, UpdatedAtColumn
 from wagtail.admin.views.account import BaseSettingsPanel
 from wagtail.admin.widgets import Button
 from wagtail.snippets.models import register_snippet
@@ -263,6 +263,7 @@ class FullFeaturedSnippetViewSet(SnippetViewSet):
         "get_foo_country_code",
         UpdatedAtColumn(),
         "modulo_two",
+        BooleanColumn("tristate"),
     ]
     list_export = [
         "text",