add support for previewing pages
This commit is contained in:
@@ -10,13 +10,14 @@ from wagtail.admin.panels import FieldPanel
|
||||
from wagtail.fields import RichTextField
|
||||
from wagtail.models import Page
|
||||
from wagtail.search import index
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
from dnscms.fields import CommonStreamField
|
||||
from dnscms.wordpress.models import WPImportedPageMixin
|
||||
|
||||
|
||||
@register_singular_query_field("associationIndex")
|
||||
class AssociationIndex(Page):
|
||||
class AssociationIndex(HeadlessMixin, Page):
|
||||
max_count = 1
|
||||
subpage_types = ["associations.AssociationPage"]
|
||||
|
||||
@@ -37,7 +38,7 @@ class AssociationIndex(Page):
|
||||
search_fields = Page.search_fields
|
||||
|
||||
|
||||
class AssociationPage(WPImportedPageMixin, Page):
|
||||
class AssociationPage(HeadlessMixin, WPImportedPageMixin, Page):
|
||||
subpage_types = []
|
||||
parent_page_types = ["associations.AssociationIndex"]
|
||||
show_in_menus = False
|
||||
|
||||
@@ -11,6 +11,7 @@ from wagtail.fields import RichTextField, StreamField
|
||||
from wagtail.models import Page
|
||||
from wagtail.search import index
|
||||
from wagtail.snippets.models import register_snippet
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
from contacts.blocks import ContactSectionBlock
|
||||
from dnscms.blocks import BASE_BLOCKS
|
||||
@@ -22,7 +23,7 @@ PHONE_REGEX_VALIDATOR = RegexValidator(
|
||||
|
||||
|
||||
@register_singular_query_field("contactIndex")
|
||||
class ContactIndex(Page):
|
||||
class ContactIndex(HeadlessMixin, Page):
|
||||
max_count = 1
|
||||
subpage_types = []
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ INSTALLED_APPS = [
|
||||
# end cms apps
|
||||
"grapple",
|
||||
"graphene_django",
|
||||
"wagtail_headless_preview",
|
||||
"wagtail.contrib.forms",
|
||||
"wagtail.contrib.redirects",
|
||||
"wagtail.contrib.settings",
|
||||
@@ -185,11 +186,22 @@ WAGTAILSEARCH_BACKENDS = {
|
||||
}
|
||||
|
||||
# Base URL to use when referring to full URLs within the Wagtail admin backend -
|
||||
# e.g. in notification emails. Don't include '/admin' or a trailing slash
|
||||
WAGTAILADMIN_BASE_URL = "http://example.com"
|
||||
# e.g. in notification emails. Don't include '/admin' or a trailing slash.
|
||||
# Also used by wagtail-grapple to make image URLs absolute.
|
||||
WAGTAIL_BASE_URL = os.environ.get("WAGTAIL_BASE_URL", "http://127.0.0.1:8000").rstrip("/")
|
||||
WAGTAILADMIN_BASE_URL = WAGTAIL_BASE_URL
|
||||
BASE_URL = WAGTAIL_BASE_URL
|
||||
|
||||
# Required by wagtail-grapple to make image URLs absolute
|
||||
BASE_URL = "http://example.com"
|
||||
# Public URL of the Next.js frontend. Used to direct preview iframes and to
|
||||
# redirect "View Live" clicks on the CMS host over to the headless frontend.
|
||||
FRONTEND_BASE_URL = os.environ.get("FRONTEND_BASE_URL", "http://localhost:3000").rstrip("/")
|
||||
|
||||
WAGTAIL_HEADLESS_PREVIEW = {
|
||||
"CLIENT_URLS": {"default": f"{FRONTEND_BASE_URL}/api/preview"},
|
||||
"SERVE_BASE_URL": FRONTEND_BASE_URL,
|
||||
"ENFORCE_TRAILING_SLASH": False,
|
||||
"REDIRECT_ON_PREVIEW": False,
|
||||
}
|
||||
|
||||
# https://docs.wagtail.org/en/latest/releases/6.4.html#data-upload-max-number-fields-update
|
||||
DATA_UPLOAD_MAX_NUMBER_FIELDS = 10_000
|
||||
|
||||
@@ -11,13 +11,6 @@ ALLOWED_HOSTS = ["*"]
|
||||
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
|
||||
# Base URL to use when referring to full URLs within the Wagtail admin backend -
|
||||
# e.g. in notification emails. Don't include '/admin' or a trailing slash
|
||||
WAGTAILADMIN_BASE_URL = "http://127.0.0.1:8000"
|
||||
|
||||
# Required by wagtail-grapple to make image URLs absolute
|
||||
BASE_URL = "http://127.0.0.1:8000"
|
||||
|
||||
try:
|
||||
from .local import *
|
||||
except ImportError:
|
||||
|
||||
@@ -30,6 +30,7 @@ from wagtail.fields import RichTextField
|
||||
from wagtail.models import Orderable, Page, PageManager, PageQuerySet
|
||||
from wagtail.search import index
|
||||
from wagtail.snippets.models import register_snippet
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
from associations.widgets import AssociationChooserWidget
|
||||
from dnscms.fields import CommonStreamField
|
||||
@@ -39,7 +40,7 @@ from venues.models import VenuePage
|
||||
|
||||
|
||||
@register_singular_query_field("eventIndex")
|
||||
class EventIndex(Page):
|
||||
class EventIndex(HeadlessMixin, Page):
|
||||
max_count = 1
|
||||
subpage_types = ["events.EventPage"]
|
||||
|
||||
@@ -220,7 +221,7 @@ class EventPageQuerySet(PageQuerySet):
|
||||
EventPageManager = PageManager.from_queryset(EventPageQuerySet)
|
||||
|
||||
|
||||
class EventPage(WPImportedPageMixin, Page):
|
||||
class EventPage(HeadlessMixin, WPImportedPageMixin, Page):
|
||||
subpage_types = []
|
||||
parent_page_types = ["events.EventIndex"]
|
||||
show_in_menus = False
|
||||
@@ -358,7 +359,7 @@ class EventPage(WPImportedPageMixin, Page):
|
||||
GraphQLImage("featured_image"),
|
||||
GraphQLRichText("lead"),
|
||||
GraphQLStreamfield("body"),
|
||||
GraphQLString("pig"),
|
||||
GraphQLString("pig", required=True),
|
||||
GraphQLString("ticket_url"),
|
||||
GraphQLString("facebook_url"),
|
||||
GraphQLBoolean("free"),
|
||||
|
||||
@@ -4,13 +4,14 @@ from wagtail.admin.panels import FieldPanel
|
||||
from wagtail.fields import RichTextField, StreamField
|
||||
from wagtail.models import Page
|
||||
from wagtail.search import index
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
from dnscms.blocks import PageSectionBlock
|
||||
from dnscms.fields import BASE_BLOCKS
|
||||
from dnscms.options import ALL_PIGS
|
||||
|
||||
|
||||
class GenericPage(Page):
|
||||
class GenericPage(HeadlessMixin, Page):
|
||||
subpage_types = ["generic.GenericPage"]
|
||||
show_in_menus = True
|
||||
|
||||
|
||||
@@ -10,9 +10,10 @@ from wagtail.admin.panels import (
|
||||
PageChooserPanel,
|
||||
)
|
||||
from wagtail.models import Orderable, Page
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
|
||||
class HomePage(Page):
|
||||
class HomePage(HeadlessMixin, Page):
|
||||
max_count = 1
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
|
||||
@@ -5,13 +5,14 @@ from wagtail.admin.panels import FieldPanel
|
||||
from wagtail.fields import RichTextField
|
||||
from wagtail.models import Page
|
||||
from wagtail.search import index
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
from dnscms.fields import CommonStreamField
|
||||
from dnscms.wordpress.models import WPImportedPageMixin
|
||||
|
||||
|
||||
@register_singular_query_field("newsIndex")
|
||||
class NewsIndex(Page):
|
||||
class NewsIndex(HeadlessMixin, Page):
|
||||
max_count = 1
|
||||
subpage_types = ["news.NewsPage"]
|
||||
|
||||
@@ -28,7 +29,7 @@ class NewsIndex(Page):
|
||||
search_fields = []
|
||||
|
||||
|
||||
class NewsPage(WPImportedPageMixin, Page):
|
||||
class NewsPage(HeadlessMixin, WPImportedPageMixin, Page):
|
||||
subpage_types = []
|
||||
parent_page_types = ["news.NewsIndex"]
|
||||
show_in_menus = False
|
||||
|
||||
@@ -7,6 +7,7 @@ requires-python = ">=3.14, <3.15"
|
||||
dependencies = [
|
||||
"wagtail>=7.4,<8",
|
||||
"wagtail-grapple>=0.31.0,<0.32",
|
||||
"wagtail-headless-preview>=0.8,<0.9",
|
||||
"django>=6.0.5,<7",
|
||||
"django-extensions>=4.1,<5",
|
||||
"psycopg2-binary>=2.9.12,<3",
|
||||
|
||||
@@ -8,6 +8,7 @@ from wagtail.fields import RichTextField, StreamField
|
||||
from wagtail.images.blocks import ImageChooserBlock
|
||||
from wagtail.models import Page
|
||||
from wagtail.search import index
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
from dnscms.blocks import BASE_BLOCKS
|
||||
|
||||
@@ -34,7 +35,7 @@ class SponsorBlock(blocks.StructBlock):
|
||||
|
||||
|
||||
@register_singular_query_field("sponsorsPage")
|
||||
class SponsorsPage(Page):
|
||||
class SponsorsPage(HeadlessMixin, Page):
|
||||
max_count = 1
|
||||
subpage_types = []
|
||||
|
||||
|
||||
@@ -10,13 +10,14 @@ from wagtail.admin.panels import FieldPanel
|
||||
from wagtail.fields import RichTextField, StreamField
|
||||
from wagtail.models import Page
|
||||
from wagtail.search import index
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
from dnscms.blocks import BASE_BLOCKS, PageSectionBlock
|
||||
from dnscms.options import ALL_PIGS
|
||||
|
||||
|
||||
@register_singular_query_field("studioPage")
|
||||
class StudioPage(Page):
|
||||
class StudioPage(HeadlessMixin, Page):
|
||||
max_count = 1
|
||||
subpage_types = []
|
||||
show_in_menus = True
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Round-trip tests for wagtail-headless-preview token resolution via grapple."""
|
||||
|
||||
from generic.models import GenericPage
|
||||
from tests.conftest import GenericPageFactory
|
||||
|
||||
|
||||
def test_generic_page_preview_token_resolves_draft(home_page, graphql_post):
|
||||
"""A minted preview token returns the unsaved draft via grapple's page(token: …)."""
|
||||
# Publish a baseline so there's a live revision to diverge from.
|
||||
page = GenericPageFactory(parent=home_page, title="Original title", slug="generic-preview")
|
||||
|
||||
# Mutate in-memory to simulate unsaved editor state, then mint a token.
|
||||
# create_page_preview() snapshots the current to_json() into a PagePreview row.
|
||||
page.title = "Edited title (draft)"
|
||||
preview = page.create_page_preview()
|
||||
|
||||
response, body = graphql_post(
|
||||
"""
|
||||
query previewPage($token: String!) {
|
||||
page: page(token: $token) {
|
||||
__typename
|
||||
... on GenericPage {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
""",
|
||||
variables={"token": preview.token},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "errors" not in body, body
|
||||
assert body["data"]["page"]["__typename"] == "GenericPage"
|
||||
assert body["data"]["page"]["title"] == "Edited title (draft)"
|
||||
|
||||
# Live revision is unchanged — token short-circuits the published query.
|
||||
assert GenericPage.objects.get(pk=page.pk).title == "Original title"
|
||||
Generated
+2
@@ -255,6 +255,7 @@ dependencies = [
|
||||
{ name = "psycopg2-binary" },
|
||||
{ name = "wagtail" },
|
||||
{ name = "wagtail-grapple" },
|
||||
{ name = "wagtail-headless-preview" },
|
||||
{ name = "whitenoise" },
|
||||
]
|
||||
|
||||
@@ -275,6 +276,7 @@ requires-dist = [
|
||||
{ name = "psycopg2-binary", specifier = ">=2.9.12,<3" },
|
||||
{ name = "wagtail", specifier = ">=7.4,<8" },
|
||||
{ name = "wagtail-grapple", specifier = ">=0.31.0,<0.32" },
|
||||
{ name = "wagtail-headless-preview", specifier = ">=0.8,<0.9" },
|
||||
{ name = "whitenoise", specifier = ">=6.12.0,<7" },
|
||||
]
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel
|
||||
from wagtail.fields import RichTextField, StreamField
|
||||
from wagtail.models import Page
|
||||
from wagtail.search import index
|
||||
from wagtail_headless_preview.models import HeadlessMixin
|
||||
|
||||
from dnscms.blocks import ImageSliderBlock
|
||||
from dnscms.fields import CommonStreamField
|
||||
@@ -18,7 +19,7 @@ from dnscms.wordpress.models import WPImportedPageMixin
|
||||
|
||||
|
||||
@register_singular_query_field("venueIndex")
|
||||
class VenueIndex(Page):
|
||||
class VenueIndex(HeadlessMixin, Page):
|
||||
# there can only be one venue index page
|
||||
max_count = 1
|
||||
subpage_types = ["venues.VenuePage"]
|
||||
@@ -35,7 +36,7 @@ class VenueIndex(Page):
|
||||
|
||||
|
||||
@register_singular_query_field("venueRentalIndex")
|
||||
class VenueRentalIndex(Page):
|
||||
class VenueRentalIndex(HeadlessMixin, Page):
|
||||
# there can only be one venue index page
|
||||
max_count = 1
|
||||
subpage_types = []
|
||||
@@ -51,7 +52,7 @@ class VenueRentalIndex(Page):
|
||||
graphql_fields = [GraphQLRichText("lead"), GraphQLStreamfield("body")]
|
||||
|
||||
|
||||
class VenuePage(WPImportedPageMixin, Page):
|
||||
class VenuePage(HeadlessMixin, WPImportedPageMixin, Page):
|
||||
# no children
|
||||
subpage_types = []
|
||||
parent_page_types = ["venues.VenueIndex"]
|
||||
|
||||
Reference in New Issue
Block a user