diff --git a/wagtail/admin/templates/wagtailadmin/generic/streamfield_block_preview.html b/wagtail/admin/templates/wagtailadmin/generic/streamfield_block_preview.html index d1c3d14d1b..d31a32f472 100644 --- a/wagtail/admin/templates/wagtailadmin/generic/streamfield_block_preview.html +++ b/wagtail/admin/templates/wagtailadmin/generic/streamfield_block_preview.html @@ -18,7 +18,11 @@
{% block content %} - {% include_block bound_block %} + {% if block_def.is_previewable %} + {% include_block bound_block %} + {% else %} + {% translate 'Preview not available' %} + {% endif %} {% endblock %}
diff --git a/wagtail/admin/tests/test_block_preview.py b/wagtail/admin/tests/test_block_preview.py index c7422c0a4f..18ec713dbd 100644 --- a/wagtail/admin/tests/test_block_preview.py +++ b/wagtail/admin/tests/test_block_preview.py @@ -82,7 +82,7 @@ class TestStreamFieldBlockPreviewView(WagtailTestUtils, TestCase): ) self.user.save() - block = blocks.CharBlock() + block = blocks.CharBlock(preview_value="Hello, world!") response = self.get(block) self.assertEqual(response.status_code, 200) @@ -93,7 +93,7 @@ class TestStreamFieldBlockPreviewView(WagtailTestUtils, TestCase): soup = self.get_soup(response.content) main = soup.select_one("main") self.assertIsNotNone(main) - self.assertEqual(main.text.strip(), "None") + self.assertEqual(main.text.strip(), "Preview not available") def test_preview_value_falls_back_to_default(self): block = blocks.IntegerBlock(default=42) diff --git a/wagtail/blocks/base.py b/wagtail/blocks/base.py index 8a1072939a..d79c6233fa 100644 --- a/wagtail/blocks/base.py +++ b/wagtail/blocks/base.py @@ -293,6 +293,25 @@ class Block(metaclass=BaseBlock): return self.normalize(self.meta.preview_value) return self.get_default() + @cached_property + def is_previewable(self): + # To prevent showing a broken preview if the block preview has not been + # configured, consider the block to be previewable if either: + # - a preview template, preview value, or default value is defined + # - a preview method is overridden + # which are the intended ways to configure block previews. + # + # If a block is made previewable by other means, the `is_previewable` + # property should be overridden to return `True`. + return ( + hasattr(self.meta, "preview_template") + or hasattr(self.meta, "preview_value") + or getattr(self.meta, "default", None) is not None + or self.__class__.get_preview_context is not Block.get_preview_context + or self.__class__.get_preview_template is not Block.get_preview_template + or self.__class__.get_preview_value is not Block.get_preview_value + ) + def get_description(self): return getattr(self.meta, "description", "") diff --git a/wagtail/blocks/field_block.py b/wagtail/blocks/field_block.py index cbe4a7d4dd..93ae3d272b 100644 --- a/wagtail/blocks/field_block.py +++ b/wagtail/blocks/field_block.py @@ -117,6 +117,7 @@ class FieldBlockAdapter(Adapter): "required": block.required, "icon": block.meta.icon, "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": " ".join(classname), "showAddCommentButton": getattr( block.field.widget, "show_add_comment_button", True diff --git a/wagtail/blocks/list_block.py b/wagtail/blocks/list_block.py index c78537a3c1..f446eb4f15 100644 --- a/wagtail/blocks/list_block.py +++ b/wagtail/blocks/list_block.py @@ -452,6 +452,7 @@ class ListBlockAdapter(Adapter): "description": block.get_description(), "icon": block.meta.icon, "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": block.meta.form_classname, "collapsed": block.meta.collapsed, "strings": { diff --git a/wagtail/blocks/static_block.py b/wagtail/blocks/static_block.py index 3224c8b9e6..8c26ef3150 100644 --- a/wagtail/blocks/static_block.py +++ b/wagtail/blocks/static_block.py @@ -60,6 +60,7 @@ class StaticBlockAdapter(Adapter): "label": block.label, "description": block.get_description(), "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, }, ] diff --git a/wagtail/blocks/stream_block.py b/wagtail/blocks/stream_block.py index 5b894ce468..42de7c9ad1 100644 --- a/wagtail/blocks/stream_block.py +++ b/wagtail/blocks/stream_block.py @@ -830,6 +830,7 @@ class StreamBlockAdapter(Adapter): "required": block.required, "icon": block.meta.icon, "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": block.meta.form_classname, "maxNum": block.meta.max_num, "minNum": block.meta.min_num, diff --git a/wagtail/blocks/struct_block.py b/wagtail/blocks/struct_block.py index fcca424f9e..05a717cb8c 100644 --- a/wagtail/blocks/struct_block.py +++ b/wagtail/blocks/struct_block.py @@ -408,6 +408,7 @@ class StructBlockAdapter(Adapter): "required": block.required, "icon": block.meta.icon, "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": block.meta.form_classname, } diff --git a/wagtail/contrib/table_block/tests.py b/wagtail/contrib/table_block/tests.py index 04476d0a7f..853d845851 100644 --- a/wagtail/contrib/table_block/tests.py +++ b/wagtail/contrib/table_block/tests.py @@ -573,6 +573,7 @@ class TestTableBlockForm(WagtailTestUtils, SimpleTestCase): "required": True, "icon": "table", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--char_field w-field--table_input", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, diff --git a/wagtail/contrib/typed_table_block/blocks.py b/wagtail/contrib/typed_table_block/blocks.py index dc6fd5023e..ef4304aaca 100644 --- a/wagtail/contrib/typed_table_block/blocks.py +++ b/wagtail/contrib/typed_table_block/blocks.py @@ -336,6 +336,7 @@ class TypedTableBlockAdapter(Adapter): "required": block.required, "icon": block.meta.icon, "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "strings": { "CAPTION": _("Caption"), "CAPTION_HELP_TEXT": _( diff --git a/wagtail/contrib/typed_table_block/tests.py b/wagtail/contrib/typed_table_block/tests.py index b7a41b0234..38bada6c77 100644 --- a/wagtail/contrib/typed_table_block/tests.py +++ b/wagtail/contrib/typed_table_block/tests.py @@ -239,6 +239,7 @@ class TestTableBlock(TestCase): "required": False, "icon": "table", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "strings": { "CAPTION": "Caption", "CAPTION_HELP_TEXT": ( diff --git a/wagtail/snippets/tests/test_snippets.py b/wagtail/snippets/tests/test_snippets.py index e8b397f209..438764133c 100644 --- a/wagtail/snippets/tests/test_snippets.py +++ b/wagtail/snippets/tests/test_snippets.py @@ -5544,6 +5544,7 @@ class TestSnippetChooserBlock(TestCase): "required": True, "icon": "snippet", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "helpText": "pick an advert, any advert", "classname": "w-field w-field--model_choice_field w-field--admin_snippet_chooser", "showAddCommentButton": True, @@ -5856,6 +5857,7 @@ class TestSnippetChooserBlockWithCustomPrimaryKey(TestCase): "required": True, "icon": "snippet", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "helpText": "pick an advert, any advert", "classname": "w-field w-field--model_choice_field w-field--admin_snippet_chooser", "showAddCommentButton": True, diff --git a/wagtail/tests/test_blocks.py b/wagtail/tests/test_blocks.py index 3ca6c045ab..b5cfe53777 100644 --- a/wagtail/tests/test_blocks.py +++ b/wagtail/tests/test_blocks.py @@ -62,6 +62,32 @@ class TestBlock(SimpleTestCase): block = blocks.Block() self.assertIs(blocks.Block.definition_registry[block.definition_prefix], block) + def test_block_is_previewable(self): + class CustomContextBlock(blocks.Block): + def get_preview_context(self, value, parent_context=None): + return {"value": value, "foo": "bar"} + + class CustomTemplateBlock(blocks.Block): + def get_preview_template(self, value=None, context=None): + return "foo.html" + + class CustomValueBlock(blocks.Block): + def get_preview_value(self): + return "foo" + + cases = [ + (blocks.Block(), False), + (blocks.Block(preview_template="foo.html"), True), + (blocks.Block(preview_value="foo"), True), + (blocks.Block(default="bar"), True), + (CustomContextBlock(), True), + (CustomTemplateBlock(), True), + (CustomValueBlock(), True), + ] + for block, is_previewable in cases: + with self.subTest(block=block): + self.assertEqual(block.is_previewable, is_previewable) + class TestFieldBlock(WagtailTestUtils, SimpleTestCase): def test_charfield_render(self): @@ -100,6 +126,7 @@ class TestFieldBlock(WagtailTestUtils, SimpleTestCase): "required": True, "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--char_field w-field--text_input", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, @@ -208,6 +235,7 @@ class TestFieldBlock(WagtailTestUtils, SimpleTestCase): "required": True, "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--choice_field w-field--select", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, @@ -619,6 +647,7 @@ class TestRichTextBlock(TestCase): "label": "Test richtextblock", "description": "", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "required": True, "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, @@ -643,6 +672,7 @@ class TestRichTextBlock(TestCase): "required": True, "icon": "pilcrow", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--char_field w-field--draftail_rich_text_area", "showAddCommentButton": False, # Draftail manages its own comments "strings": {"ADD_COMMENT": "Add Comment"}, @@ -667,6 +697,7 @@ class TestRichTextBlock(TestCase): "required": True, "icon": "pilcrow", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--char_field w-field--draftail_rich_text_area", "showAddCommentButton": False, # Draftail manages its own comments "strings": {"ADD_COMMENT": "Add Comment"}, @@ -784,6 +815,7 @@ class TestChoiceBlock(WagtailTestUtils, SimpleTestCase): "required": True, "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--choice_field w-field--select", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, @@ -1187,6 +1219,7 @@ class TestMultipleChoiceBlock(WagtailTestUtils, SimpleTestCase): "required": True, "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--multiple_choice_field w-field--select_multiple", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, @@ -1625,6 +1658,7 @@ class TestRawHTMLBlock(unittest.TestCase): "required": True, "icon": "code", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--char_field w-field--textarea", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, @@ -1969,6 +2003,7 @@ class TestStructBlock(SimpleTestCase): "required": False, "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "struct-block", }, ) @@ -2000,6 +2035,7 @@ class TestStructBlock(SimpleTestCase): "required": False, "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "struct-block", "formTemplate": "
Hello
", }, @@ -2026,6 +2062,7 @@ class TestStructBlock(SimpleTestCase): "required": False, "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "struct-block", "formTemplate": "
Hello
", }, @@ -2061,6 +2098,7 @@ class TestStructBlock(SimpleTestCase): "required": False, "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "struct-block", "helpIcon": ( 'Latest posts - This block doesn't need to be configured, it will be displayed automatically", "icon": "placeholder", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "label": "Posts static block", "description": "", }, @@ -5133,6 +5185,7 @@ class TestDateBlock(TestCase): "required": True, "icon": "date", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--date_field w-field--admin_date_input", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, @@ -5168,6 +5221,7 @@ class TestTimeBlock(TestCase): "required": True, "icon": "time", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--time_field w-field--admin_time_input", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"}, @@ -5203,6 +5257,7 @@ class TestDateTimeBlock(TestCase): "required": True, "icon": "date", "blockDefId": block.definition_prefix, + "isPreviewable": block.is_previewable, "classname": "w-field w-field--date_time_field w-field--admin_date_time_input", "showAddCommentButton": True, "strings": {"ADD_COMMENT": "Add Comment"},