Repository: wagtail/wagtail

Issue:
Live preview panel shows stale preview data after reloading the create view
### Issue Summary

The live preview panel shows stale preview data after a reload of the page create view.

https://user-images.githubusercontent.com/6379424/185642633-c3c9e9b4-f55d-456a-9c90-9959649ae58b.mov

### Steps to Reproduce

1. Open a page create view.
2. Open the live preview panel.
3. Fill the form until the live preview is updated.
4. Reload the page create view.
5. Open the live preview panel.
6. Instead of showing "Preview not available", the live preview panel shows the preview using the "last 'good' data". This stale preview will be replaced once you start filling the form (until it's valid and the preview is refreshed).

Any other relevant information. For example, why do you consider this a bug and what did you expect to happen instead?

I think the preview panel should not show the stale data on a reload if the loaded form data is invalid. Instead, it should show the "Preview not available" screen.

Live preview panel shows stale preview data after reloading the create view
### Issue Summary

The live preview panel shows stale preview data after a reload of the page create view.

https://user-images.githubusercontent.com/6379424/185642633-c3c9e9b4-f55d-456a-9c90-9959649ae58b.mov

### Steps to Reproduce

1. Open a page create view.
2. Open the live preview panel.
3. Fill the form until the live preview is updated.
4. Reload the page create view.
5. Open the live preview panel.
6. Instead of showing "Preview not available", the live preview panel shows the preview using the "last 'good' data". This stale preview will be replaced once you start filling the form (until it's valid and the preview is refreshed).

Any other relevant information. For example, why do you consider this a bug and what did you expect to happen instead?

I think the preview panel should not show the stale data on a reload if the loaded form data is invalid. Instead, it should show the "Preview not available" screen.



Discussion:

Resolving patch:
diff --git a/wagtail/admin/views/generic/preview.py b/wagtail/admin/views/generic/preview.py
--- a/wagtail/admin/views/generic/preview.py
+++ b/wagtail/admin/views/generic/preview.py
@@ -16,7 +16,7 @@
 
 class PreviewOnEdit(View):
     model = None
-    http_method_names = ("post", "get")
+    http_method_names = ("post", "get", "delete")
     preview_expiration_timeout = 60 * 60 * 24  # seconds
     session_key_prefix = "wagtail-preview-"
 
@@ -111,6 +111,10 @@ def get(self, request, *args, **kwargs):
 
         return self.object.make_preview_request(request, preview_mode, extra_attrs)
 
+    def delete(self, request, *args, **kwargs):
+        request.session.pop(self.session_key, None)
+        return JsonResponse({"success": True})
+
 
 class PreviewOnCreate(PreviewOnEdit):
     @property


Test patch:
diff --git a/wagtail/admin/tests/pages/test_preview.py b/wagtail/admin/tests/pages/test_preview.py
--- a/wagtail/admin/tests/pages/test_preview.py
+++ b/wagtail/admin/tests/pages/test_preview.py
@@ -316,6 +316,79 @@ def test_preview_on_edit_expiry(self):
             response = self.client.get(preview_url)
             self.assertEqual(response.status_code, 200)
 
+    def test_preview_on_create_clear_preview_data(self):
+        preview_session_key = "wagtail-preview-tests-eventpage-{}".format(
+            self.home_page.id
+        )
+
+        # Set a fake preview session data for the page
+        self.client.session[preview_session_key] = "test data"
+
+        preview_url = reverse(
+            "wagtailadmin_pages:preview_on_add",
+            args=("tests", "eventpage", self.home_page.id),
+        )
+        response = self.client.delete(preview_url)
+        self.assertEqual(response.status_code, 200)
+        self.assertJSONEqual(
+            response.content.decode(),
+            {"success": True},
+        )
+
+        # The data should no longer exist in the session
+        self.assertNotIn(preview_session_key, self.client.session)
+
+        response = self.client.get(preview_url)
+
+        # The preview should be unavailable
+        self.assertEqual(response.status_code, 200)
+        self.assertTemplateUsed(response, "wagtailadmin/generic/preview_error.html")
+        self.assertContains(
+            response,
+            "<title>Wagtail - Preview not available</title>",
+            html=True,
+        )
+        self.assertContains(
+            response,
+            '<h1 class="preview-error__title">Preview not available</h1>',
+            html=True,
+        )
+
+    def test_preview_on_edit_clear_preview_data(self):
+        preview_session_key = "wagtail-preview-{}".format(self.event_page.id)
+
+        # Set a fake preview session data for the page
+        self.client.session[preview_session_key] = "test data"
+
+        preview_url = reverse(
+            "wagtailadmin_pages:preview_on_edit", args=(self.event_page.id,)
+        )
+        response = self.client.delete(preview_url)
+        self.assertEqual(response.status_code, 200)
+        self.assertJSONEqual(
+            response.content.decode(),
+            {"success": True},
+        )
+
+        # The data should no longer exist in the session
+        self.assertNotIn(preview_session_key, self.client.session)
+
+        response = self.client.get(preview_url)
+
+        # The preview should be unavailable
+        self.assertEqual(response.status_code, 200)
+        self.assertTemplateUsed(response, "wagtailadmin/generic/preview_error.html")
+        self.assertContains(
+            response,
+            "<title>Wagtail - Preview not available</title>",
+            html=True,
+        )
+        self.assertContains(
+            response,
+            '<h1 class="preview-error__title">Preview not available</h1>',
+            html=True,
+        )
+
     def test_preview_modes(self):
         preview_url = reverse(
             "wagtailadmin_pages:preview_on_add",
diff --git a/wagtail/snippets/tests/test_preview.py b/wagtail/snippets/tests/test_preview.py
--- a/wagtail/snippets/tests/test_preview.py
+++ b/wagtail/snippets/tests/test_preview.py
@@ -199,6 +199,66 @@ def test_preview_on_edit_expiry(self):
                 self.client.session,
             )
 
+    def test_preview_on_create_clear_preview_data(self):
+        # Set a fake preview session data for the page
+        self.client.session[self.session_key_prefix] = "test data"
+
+        response = self.client.delete(self.preview_on_add_url)
+        self.assertEqual(response.status_code, 200)
+        self.assertJSONEqual(
+            response.content.decode(),
+            {"success": True},
+        )
+
+        # The data should no longer exist in the session
+        self.assertNotIn(self.session_key_prefix, self.client.session)
+
+        response = self.client.get(self.preview_on_add_url)
+
+        # The preview should be unavailable
+        self.assertEqual(response.status_code, 200)
+        self.assertTemplateUsed(response, "wagtailadmin/generic/preview_error.html")
+        self.assertContains(
+            response,
+            "<title>Wagtail - Preview not available</title>",
+            html=True,
+        )
+        self.assertContains(
+            response,
+            '<h1 class="preview-error__title">Preview not available</h1>',
+            html=True,
+        )
+
+    def test_preview_on_edit_clear_preview_data(self):
+        # Set a fake preview session data for the page
+        self.client.session[self.edit_session_key] = "test data"
+
+        response = self.client.delete(self.preview_on_edit_url)
+        self.assertEqual(response.status_code, 200)
+        self.assertJSONEqual(
+            response.content.decode(),
+            {"success": True},
+        )
+
+        # The data should no longer exist in the session
+        self.assertNotIn(self.edit_session_key, self.client.session)
+
+        response = self.client.get(self.preview_on_edit_url)
+
+        # The preview should be unavailable
+        self.assertEqual(response.status_code, 200)
+        self.assertTemplateUsed(response, "wagtailadmin/generic/preview_error.html")
+        self.assertContains(
+            response,
+            "<title>Wagtail - Preview not available</title>",
+            html=True,
+        )
+        self.assertContains(
+            response,
+            '<h1 class="preview-error__title">Preview not available</h1>',
+            html=True,
+        )
+
     def test_preview_revision(self):
         snippet = MultiPreviewModesModel.objects.create(text="Multiple modes")
         revision = snippet.save_revision(log_action=True)