From 95fd73ee577d090d297df88c379d6a4e0d5e09a3 Mon Sep 17 00:00:00 2001 From: Jhonatan Lopes Date: Thu, 25 Jan 2024 16:12:38 -0300 Subject: [PATCH 1/2] Convert snippets menu into groups (#11760) * Migrate ModelAdmin to SnippetViewSet * Remove contrib modeladmin model * Migrate tags to snippetviewset * Default ordering on menus * Donate banner wagtail menu * Events menu * Mozfest menu * Add icons * Blog menu * PNI menu * Add flask icon * Research Hub group * RCC groups * Move tito to mozfest * Donate group * Petitions menu * Profiles menu * CTA and Signup groups * Archived group * Add migrations for meta renaming * Fix bug with donate banner settings chooser * Change donate banner icon --- .../networkapi/donate/wagtail_hooks.py | 61 +++ .../networkapi/donate_banner/models.py | 31 +- network-api/networkapi/events/models.py | 2 - network-api/networkapi/highlights/admin.py | 31 -- network-api/networkapi/highlights/models.py | 2 - ..._newslettersignupwithbackground_options.py | 16 + network-api/networkapi/mozfest/models.py | 5 +- .../networkapi/mozfest/wagtail_hooks.py | 57 +++ network-api/networkapi/news/admin.py | 28 -- network-api/networkapi/news/models.py | 2 - network-api/networkapi/settings.py | 1 - .../networkapi/templates/icons/flask.svg | 4 + .../networkapi/templates/icons/heart.svg | 4 + .../networkapi/templates/icons/mozfest.svg | 13 + .../networkapi/templates/icons/newspaper.svg | 4 + .../networkapi/templates/icons/pni.svg | 12 + .../networkapi/templates/icons/ticket.svg | 4 + .../networkapi/templates/icons/tito.svg | 19 + .../views/snippet_chooser.py | 6 +- network-api/networkapi/wagtailpages/admin.py | 8 +- .../networkapi/wagtailpages/donation_modal.py | 2 - .../migrations/0120_alter_petition_options.py | 16 + .../wagtailpages/pagemodels/base.py | 2 - .../pagemodels/blog/blog_topic.py | 2 - .../pagemodels/buyersguide/call_to_action.py | 2 - .../pagemodels/buyersguide/products.py | 3 - .../pagemodels/buyersguide/taxonomies.py | 2 - .../wagtailpages/pagemodels/campaigns.py | 8 +- .../pagemodels/libraries/rcc/taxonomies.py | 5 - .../libraries/research_hub/taxonomies.py | 3 - .../wagtailpages/pagemodels/profiles.py | 2 - .../wagtailpages/pagemodels/pulse.py | 2 - .../networkapi/wagtailpages/wagtail_hooks.py | 378 +++++++++++++++++- 33 files changed, 593 insertions(+), 144 deletions(-) create mode 100644 network-api/networkapi/donate/wagtail_hooks.py delete mode 100644 network-api/networkapi/highlights/admin.py create mode 100644 network-api/networkapi/mozfest/migrations/0045_alter_newslettersignupwithbackground_options.py create mode 100644 network-api/networkapi/mozfest/wagtail_hooks.py delete mode 100644 network-api/networkapi/news/admin.py create mode 100644 network-api/networkapi/templates/icons/flask.svg create mode 100644 network-api/networkapi/templates/icons/heart.svg create mode 100644 network-api/networkapi/templates/icons/mozfest.svg create mode 100644 network-api/networkapi/templates/icons/newspaper.svg create mode 100644 network-api/networkapi/templates/icons/pni.svg create mode 100644 network-api/networkapi/templates/icons/ticket.svg create mode 100644 network-api/networkapi/templates/icons/tito.svg create mode 100644 network-api/networkapi/wagtailpages/migrations/0120_alter_petition_options.py diff --git a/network-api/networkapi/donate/wagtail_hooks.py b/network-api/networkapi/donate/wagtail_hooks.py new file mode 100644 index 00000000000..6ab0ebca6c0 --- /dev/null +++ b/network-api/networkapi/donate/wagtail_hooks.py @@ -0,0 +1,61 @@ +from wagtail import hooks +from wagtail.admin.ui.tables import UpdatedAtColumn +from wagtail.snippets.models import register_snippet +from wagtail.snippets.views.snippets import SnippetViewSet, SnippetViewSetGroup + +from networkapi.donate_banner.models import DonateBanner +from networkapi.wagtailcustomization.views.snippet_chooser import ( + DefaultLocaleSnippetChooserViewSet, +) +from networkapi.wagtailpages.donation_modal import DonationModal + + +# Customise DonateBanner Snippet admin listing to show extra columns. +class DonateBannerViewSet(SnippetViewSet): + model = DonateBanner + icon = "form" # change as required + menu_order = 100 + description = "Donation Banner" + menu_label = "Donation Banners" + list_display = ["name", "cta_link", "is_active", UpdatedAtColumn()] + + +# Customise chooser to only show the default language banners as options. +# We do not want editors to select the translations as +# localisation will be handled on the template instead. +@hooks.register("register_admin_viewset") +def register_donate_banner_chooser_viewset(): + return DefaultLocaleSnippetChooserViewSet( + "wagtailsnippetchoosers_custom_donatebanner", + model=DonateBanner, + url_prefix="donate_banner/chooser", + ) + + +class DonationModalSnippetViewSet(SnippetViewSet): + model = DonationModal + icon = "newspaper" + menu_order = 200 + menu_label = "Newsletter Signups" + menu_name = "Newsletter Signups" + list_display = ( + "name", + "donate_text", + "donate_url", + "dismiss_text", + ) + search_fields = ("name", "header", "body", "donate_text", "donate_url", "dismiss_text") + + +class DonateViewSetGroup(SnippetViewSetGroup): + items = ( + DonateBannerViewSet, + DonationModalSnippetViewSet, + ) + menu_icon = "heart" + menu_label = "Donate" + menu_name = "Donate" + menu_order = 1000 + + +register_snippet(DonateViewSetGroup) diff --git a/network-api/networkapi/donate_banner/models.py b/network-api/networkapi/donate_banner/models.py index d6a5c4abf48..b7d50b48315 100644 --- a/network-api/networkapi/donate_banner/models.py +++ b/network-api/networkapi/donate_banner/models.py @@ -1,18 +1,11 @@ from django.contrib import admin from django.core.validators import RegexValidator from django.db import models -from wagtail import hooks from wagtail.admin.panels import FieldPanel, HelpPanel -from wagtail.admin.ui.tables import UpdatedAtColumn from wagtail.contrib.settings.models import BaseSiteSetting, register_setting from wagtail.models import PreviewableMixin, TranslatableMixin -from wagtail.snippets.models import register_snippet -from wagtail.snippets.views.snippets import SnippetViewSet from wagtail_localize.fields import SynchronizedField, TranslatableField -from networkapi.wagtailcustomization.views.snippet_chooser import ( - DefaultLocaleSnippetChooserViewSet, -) from networkapi.wagtailpages.constants import url_or_query_regex @@ -96,29 +89,7 @@ def is_active(self): return "No" -# Customise DonateBanner Snippet admin listing to show extra columns. -class DonateBannerViewSet(SnippetViewSet): - model = DonateBanner - description = "Donate Banner" - list_display = ["name", "cta_link", "is_active", UpdatedAtColumn()] - - -register_snippet(DonateBanner, viewset=DonateBannerViewSet) - - -# Customise chooser to only show the default language banners as options. -# We do not want editors to select the translations as -# localisation will be handled on the template instead. -@hooks.register("register_admin_viewset") -def register_donate_banner_chooser_viewset(): - return DefaultLocaleSnippetChooserViewSet( - "wagtailsnippetchoosers_custom_donatebanner", - model=DonateBanner, - url_prefix="donate_banner/chooser", - ) - - -@register_setting(icon="pick") +@register_setting(icon="heart") class SiteDonateBanner(BaseSiteSetting): select_related = ["active_donate_banner"] diff --git a/network-api/networkapi/events/models.py b/network-api/networkapi/events/models.py index 32d1d2ac8ab..fd9f3d67371 100644 --- a/network-api/networkapi/events/models.py +++ b/network-api/networkapi/events/models.py @@ -1,8 +1,6 @@ from django.db import models -from wagtail.snippets.models import register_snippet -@register_snippet class TitoEvent(models.Model): """ Details of an event managed in Tito. diff --git a/network-api/networkapi/highlights/admin.py b/network-api/networkapi/highlights/admin.py deleted file mode 100644 index 4398929e620..00000000000 --- a/network-api/networkapi/highlights/admin.py +++ /dev/null @@ -1,31 +0,0 @@ -from adminsortable.admin import SortableAdmin -from django.contrib import admin -from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register - -from networkapi.highlights.forms import HighlightAdminForm -from networkapi.highlights.models import Highlight - - -@admin.register(Highlight) -class HighlightAdmin(SortableAdmin): - form = HighlightAdminForm - - sortable_change_list_template = ("shared/adminsortable_change_list_custom.html",) - - -# Wagtail admin -class WagtailHighlightAdmin(ModelAdmin): - model = Highlight - menu_icon = "date" # change as required - menu_order = 200 # will put in 3rd place (000 being 1st, 100 2nd) - add_to_settings_menu = False # or True to add your model to the Settings sub-menu - exclude_from_explorer = False # or True to exclude pages of this type from Wagtail's explorer view - list_display = ( - "title", - "description", - "link_url", - ) - search_fields = ("title", "description") - - -modeladmin_register(WagtailHighlightAdmin) diff --git a/network-api/networkapi/highlights/models.py b/network-api/networkapi/highlights/models.py index 42ce81807c1..59346f7c224 100644 --- a/network-api/networkapi/highlights/models.py +++ b/network-api/networkapi/highlights/models.py @@ -5,7 +5,6 @@ from wagtail.admin.panels import FieldPanel from wagtail.fields import RichTextField from wagtail.models import TranslatableMixin -from wagtail.snippets.models import register_snippet from wagtail_localize.fields import TranslatableField from networkapi.utility.images import get_image_upload_path @@ -33,7 +32,6 @@ def published(self): ) -@register_snippet class Highlight(TranslatableMixin, SortableMixin): """ An data type to highlight things like pulse diff --git a/network-api/networkapi/mozfest/migrations/0045_alter_newslettersignupwithbackground_options.py b/network-api/networkapi/mozfest/migrations/0045_alter_newslettersignupwithbackground_options.py new file mode 100644 index 00000000000..c53e3c2d13b --- /dev/null +++ b/network-api/networkapi/mozfest/migrations/0045_alter_newslettersignupwithbackground_options.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2.9 on 2024-01-23 17:52 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("mozfest", "0044_configure_cards_per_row_on_listing_block"), + ] + + operations = [ + migrations.AlterModelOptions( + name="newslettersignupwithbackground", + options={"ordering": ["name"], "verbose_name": "Mozfest Newsletter Signup"}, + ), + ] diff --git a/network-api/networkapi/mozfest/models.py b/network-api/networkapi/mozfest/models.py index 4b4d68377d2..3972b616cd7 100644 --- a/network-api/networkapi/mozfest/models.py +++ b/network-api/networkapi/mozfest/models.py @@ -4,7 +4,6 @@ from wagtail.admin.panels import FieldPanel, MultiFieldPanel from wagtail.fields import RichTextField, StreamField from wagtail.models import Locale, Page, TranslatableMixin -from wagtail.snippets.models import register_snippet from wagtail_localize.fields import SynchronizedField, TranslatableField from networkapi.mozfest import blocks as mozfest_blocks @@ -24,7 +23,6 @@ ) -@register_snippet class Ticket(TranslatableMixin): name = models.CharField( max_length=100, @@ -62,7 +60,6 @@ class Meta(TranslatableMixin.Meta): verbose_name = "Ticket" -@register_snippet class NewsletterSignupWithBackground(TranslatableMixin, campaign_models.CTA): background_image = models.ForeignKey( "wagtailimages.Image", @@ -80,7 +77,7 @@ class NewsletterSignupWithBackground(TranslatableMixin, campaign_models.CTA): class Meta(TranslatableMixin.Meta): ordering = ["name"] - verbose_name = "Newsletter Signup With Background" + verbose_name = "Mozfest Newsletter Signup" class MozfestPrimaryPage(FoundationMetadataPageMixin, FoundationBannerInheritanceMixin, Page): diff --git a/network-api/networkapi/mozfest/wagtail_hooks.py b/network-api/networkapi/mozfest/wagtail_hooks.py new file mode 100644 index 00000000000..6b98b134820 --- /dev/null +++ b/network-api/networkapi/mozfest/wagtail_hooks.py @@ -0,0 +1,57 @@ +from wagtail.snippets.models import register_snippet +from wagtail.snippets.views.snippets import SnippetViewSet, SnippetViewSetGroup + +from networkapi.events.models import TitoEvent +from networkapi.mozfest.models import NewsletterSignupWithBackground, Ticket + + +class TitoEventSnippetViewSet(SnippetViewSet): + model = TitoEvent + icon = "tito" + menu_order = 000 + menu_label = "Tito" + menu_name = "Tito" + list_display = ( + "title", + "event_id", + ) + search_fields = ("title", "event_id", "newsletter_question_id") + + +class TicketSnippetViewSet(SnippetViewSet): + model = Ticket + icon = "ticket" + menu_order = 100 + menu_label = "Tickets" + menu_name = "Tickets" + list_display = ( + "name", + "cost", + "event", + "sticker_text", + ) + search_fields = ("name", "description", "cost", "button_text", "releases", "event", "sticker_text") + + +class NewsletterSignupWithBackgroundSnippetViewSet(SnippetViewSet): + model = NewsletterSignupWithBackground + icon = "newspaper" + menu_order = 200 + menu_label = "Newsletter Signups" + menu_name = "Newsletter Signups" + list_display = ( + "name", + "newsletter", + ) + search_fields = ("name", "header", "description", "newsletter") + + +class MozfestViewSetGroup(SnippetViewSetGroup): + items = (TitoEventSnippetViewSet, TicketSnippetViewSet, NewsletterSignupWithBackgroundSnippetViewSet) + menu_icon = "mozfest" + menu_label = "Mozfest" + menu_name = "Mozfest" + menu_order = 1300 + + +register_snippet(MozfestViewSetGroup) diff --git a/network-api/networkapi/news/admin.py b/network-api/networkapi/news/admin.py deleted file mode 100644 index 03682c00371..00000000000 --- a/network-api/networkapi/news/admin.py +++ /dev/null @@ -1,28 +0,0 @@ -from django.contrib import admin -from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register - -from networkapi.news.forms import NewsAdminForm -from networkapi.news.models import News - - -@admin.register(News) -class NewsAdmin(admin.ModelAdmin): - form = NewsAdminForm - - -class WagtailNewsAdmin(ModelAdmin): - model = News - menu_icon = "doc-full-inverse" # change as required - menu_order = 200 # will put in 3rd place (000 being 1st, 100 2nd) - add_to_settings_menu = False # or True to add your model to the Settings sub-menu - exclude_from_explorer = False # or True to exclude pages of this type from Wagtail's explorer view - list_display = ( - "headline", - "thumbnail", - "date", - "link", - ) - search_fields = ("headline",) - - -modeladmin_register(WagtailNewsAdmin) diff --git a/network-api/networkapi/news/models.py b/network-api/networkapi/news/models.py index f184244463c..20221e39cda 100644 --- a/network-api/networkapi/news/models.py +++ b/network-api/networkapi/news/models.py @@ -2,7 +2,6 @@ from django.db.models import Q from django.utils import timezone from wagtail.models import TranslatableMixin -from wagtail.snippets.models import register_snippet from networkapi.utility.images import get_image_upload_path @@ -30,7 +29,6 @@ def published(self): ) -@register_snippet class News(TranslatableMixin, models.Model): """ Medium blog posts, articles and other media diff --git a/network-api/networkapi/settings.py b/network-api/networkapi/settings.py index 0a253d6d143..f2942ad121c 100644 --- a/network-api/networkapi/settings.py +++ b/network-api/networkapi/settings.py @@ -221,7 +221,6 @@ "wagtail.contrib.routable_page", "wagtail.contrib.styleguide" if DEBUG else None, "wagtail.contrib.table_block", - "wagtail.contrib.modeladmin", "wagtail.contrib.frontend_cache", "wagtail.contrib.settings", "wagtail_color_panel", diff --git a/network-api/networkapi/templates/icons/flask.svg b/network-api/networkapi/templates/icons/flask.svg new file mode 100644 index 00000000000..56bbff48ff4 --- /dev/null +++ b/network-api/networkapi/templates/icons/flask.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/network-api/networkapi/templates/icons/heart.svg b/network-api/networkapi/templates/icons/heart.svg new file mode 100644 index 00000000000..10bfdc15147 --- /dev/null +++ b/network-api/networkapi/templates/icons/heart.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/network-api/networkapi/templates/icons/mozfest.svg b/network-api/networkapi/templates/icons/mozfest.svg new file mode 100644 index 00000000000..02b8168bc34 --- /dev/null +++ b/network-api/networkapi/templates/icons/mozfest.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/network-api/networkapi/templates/icons/newspaper.svg b/network-api/networkapi/templates/icons/newspaper.svg new file mode 100644 index 00000000000..28023c8e7e7 --- /dev/null +++ b/network-api/networkapi/templates/icons/newspaper.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/network-api/networkapi/templates/icons/pni.svg b/network-api/networkapi/templates/icons/pni.svg new file mode 100644 index 00000000000..253de0cdc6b --- /dev/null +++ b/network-api/networkapi/templates/icons/pni.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/network-api/networkapi/templates/icons/ticket.svg b/network-api/networkapi/templates/icons/ticket.svg new file mode 100644 index 00000000000..f8eb383b2a2 --- /dev/null +++ b/network-api/networkapi/templates/icons/ticket.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/network-api/networkapi/templates/icons/tito.svg b/network-api/networkapi/templates/icons/tito.svg new file mode 100644 index 00000000000..3038788f4e1 --- /dev/null +++ b/network-api/networkapi/templates/icons/tito.svg @@ -0,0 +1,19 @@ + + + + Page 1 + Created with Sketch. + + + diff --git a/network-api/networkapi/wagtailcustomization/views/snippet_chooser.py b/network-api/networkapi/wagtailcustomization/views/snippet_chooser.py index b85d3274f46..d1cbde9a73c 100644 --- a/network-api/networkapi/wagtailcustomization/views/snippet_chooser.py +++ b/network-api/networkapi/wagtailcustomization/views/snippet_chooser.py @@ -49,7 +49,11 @@ def get_filter_form_class(self): class DefaultLocaleSnippetChooseResultsView(ChooseResultsViewMixin, CreationFormMixin, BaseSnippetChooseView): - pass + def get_object_list(self): + if not issubclass(self.model_class, TranslatableMixin): + return super().get_object_list() + + return super().get_object_list().filter(locale__id=Locale.get_default().id) class DefaultLocaleSnippetChooserViewSet(ChooserViewSet): diff --git a/network-api/networkapi/wagtailpages/admin.py b/network-api/networkapi/wagtailpages/admin.py index e70b62dc292..0d26f1d8af4 100644 --- a/network-api/networkapi/wagtailpages/admin.py +++ b/network-api/networkapi/wagtailpages/admin.py @@ -1,10 +1,12 @@ from taggit.models import Tag -from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register +from wagtail.snippets.models import register_snippet +from wagtail.snippets.views.snippets import SnippetViewSet # Wagtail admin -class WagtailTagAdmin(ModelAdmin): +class WagtailTagSnippetViewSet(SnippetViewSet): model = Tag + icon = "tag" menu_label = "Tags" menu_order = 200 # will put in 3rd place (000 being 1st, 100 2nd) add_to_settings_menu = True @@ -13,4 +15,4 @@ class WagtailTagAdmin(ModelAdmin): search_fields = ("name",) -modeladmin_register(WagtailTagAdmin) +register_snippet(WagtailTagSnippetViewSet) diff --git a/network-api/networkapi/wagtailpages/donation_modal.py b/network-api/networkapi/wagtailpages/donation_modal.py index af3ecc1f679..3f3061bbbb8 100644 --- a/network-api/networkapi/wagtailpages/donation_modal.py +++ b/network-api/networkapi/wagtailpages/donation_modal.py @@ -3,13 +3,11 @@ from modelcluster.fields import ParentalKey from wagtail.admin.panels import FieldPanel from wagtail.models import TranslatableMixin -from wagtail.snippets.models import register_snippet from wagtail_localize.fields import SynchronizedField, TranslatableField from networkapi.wagtailpages.constants import url_or_query_regex -@register_snippet class DonationModal(TranslatableMixin, models.Model): name = models.CharField( default="", diff --git a/network-api/networkapi/wagtailpages/migrations/0120_alter_petition_options.py b/network-api/networkapi/wagtailpages/migrations/0120_alter_petition_options.py new file mode 100644 index 00000000000..6bbdcc704ba --- /dev/null +++ b/network-api/networkapi/wagtailpages/migrations/0120_alter_petition_options.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2.9 on 2024-01-23 17:52 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("wagtailpages", "0119_alter_banneredcampaigntag_tag_alter_blogpagetag_tag"), + ] + + operations = [ + migrations.AlterModelOptions( + name="petition", + options={"ordering": ["-id"], "verbose_name": "Petition"}, + ), + ] diff --git a/network-api/networkapi/wagtailpages/pagemodels/base.py b/network-api/networkapi/wagtailpages/pagemodels/base.py index 12e55aa1c47..301e43bcc1f 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/base.py +++ b/network-api/networkapi/wagtailpages/pagemodels/base.py @@ -6,7 +6,6 @@ from wagtail.images import get_image_model_string from wagtail.models import Orderable as WagtailOrderable from wagtail.models import Page, TranslatableMixin -from wagtail.snippets.models import register_snippet from wagtail_localize.fields import SynchronizedField, TranslatableField # TODO: https://github.com/mozilla/foundation.mozilla.org/issues/2362 @@ -596,7 +595,6 @@ class ParticipateHighlights2(ParticipateHighlightsBase): ) -@register_snippet class FocusArea(TranslatableMixin, models.Model): interest_icon = models.ForeignKey( "wagtailimages.Image", diff --git a/network-api/networkapi/wagtailpages/pagemodels/blog/blog_topic.py b/network-api/networkapi/wagtailpages/pagemodels/blog/blog_topic.py index a434a07b9d2..1a53c513098 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/blog/blog_topic.py +++ b/network-api/networkapi/wagtailpages/pagemodels/blog/blog_topic.py @@ -3,7 +3,6 @@ from wagtail.admin.panels import FieldPanel from wagtail.fields import RichTextField from wagtail.models import TranslatableMixin -from wagtail.snippets.models import register_snippet from networkapi.wagtailpages.pagemodels.customblocks.base_rich_text_options import ( base_rich_text_options, @@ -11,7 +10,6 @@ from networkapi.wagtailpages.utils import get_default_locale -@register_snippet class BlogPageTopic(TranslatableMixin, models.Model): name = models.CharField(max_length=50) diff --git a/network-api/networkapi/wagtailpages/pagemodels/buyersguide/call_to_action.py b/network-api/networkapi/wagtailpages/pagemodels/buyersguide/call_to_action.py index 07dcfeb71d5..45d6c1a1a15 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/buyersguide/call_to_action.py +++ b/network-api/networkapi/wagtailpages/pagemodels/buyersguide/call_to_action.py @@ -6,7 +6,6 @@ from wagtail.fields import RichTextField from wagtail.models import Page, TranslatableMixin from wagtail.search import index -from wagtail.snippets.models import register_snippet from wagtail_localize.fields import SynchronizedField, TranslatableField from networkapi.wagtailpages.constants import url_or_query_regex @@ -15,7 +14,6 @@ ) -@register_snippet class BuyersGuideCallToAction(index.Indexed, TranslatableMixin, models.Model): """ Reusable call to action for the buyers guide, diff --git a/network-api/networkapi/wagtailpages/pagemodels/buyersguide/products.py b/network-api/networkapi/wagtailpages/pagemodels/buyersguide/products.py index 61576ed7893..420dc459d3c 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/buyersguide/products.py +++ b/network-api/networkapi/wagtailpages/pagemodels/buyersguide/products.py @@ -28,7 +28,6 @@ from wagtail.fields import RichTextField from wagtail.models import Orderable, Page, PageManager, PageQuerySet, TranslatableMixin from wagtail.search import index -from wagtail.snippets.models import register_snippet from wagtail_localize.fields import SynchronizedField, TranslatableField from networkapi.utility import orderables @@ -74,7 +73,6 @@ def with_usage_annotation(self): ) -@register_snippet class BuyersGuideProductCategory( index.Indexed, TranslatableMixin, @@ -512,7 +510,6 @@ class Meta(TranslatableMixin.Meta, Orderable.Meta): verbose_name = "Privacy Link" -@register_snippet class Update(TranslatableMixin, index.Indexed, models.Model): source = models.URLField( max_length=2048, diff --git a/network-api/networkapi/wagtailpages/pagemodels/buyersguide/taxonomies.py b/network-api/networkapi/wagtailpages/pagemodels/buyersguide/taxonomies.py index e103b575a3b..1290a3d2d34 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/buyersguide/taxonomies.py +++ b/network-api/networkapi/wagtailpages/pagemodels/buyersguide/taxonomies.py @@ -1,11 +1,9 @@ from django.db import models from wagtail import models as wagtail_models from wagtail.admin import panels as admin_panels -from wagtail.snippets import models as snippet_models from wagtail_localize import fields as localize_fields -@snippet_models.register_snippet class BuyersGuideContentCategory(wagtail_models.TranslatableMixin, models.Model): title = models.CharField(max_length=100, null=False, blank=False) slug = models.SlugField( diff --git a/network-api/networkapi/wagtailpages/pagemodels/campaigns.py b/network-api/networkapi/wagtailpages/pagemodels/campaigns.py index 2bf6cecf664..5449494574d 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/campaigns.py +++ b/network-api/networkapi/wagtailpages/pagemodels/campaigns.py @@ -7,7 +7,6 @@ from wagtail.admin.panels import FieldPanel, InlinePanel from wagtail.fields import RichTextField from wagtail.models import Page, TranslatableMixin -from wagtail.snippets.models import register_snippet from wagtail_localize.fields import SynchronizedField, TranslatableField from ..utils import get_content_related_by_tag, get_page_tree_information @@ -51,14 +50,12 @@ class Meta: abstract = True -@register_snippet class CTA(CTABase): class Meta: ordering = ["-id"] verbose_name_plural = "CTA" -@register_snippet class Callpower(TranslatableMixin, CTA): campaign_id = models.CharField( max_length=20, @@ -116,7 +113,6 @@ class Meta(TranslatableMixin.Meta): verbose_name = "Callpower" -@register_snippet class Signup(TranslatableMixin, CTA): campaign_id = models.CharField( max_length=20, @@ -140,7 +136,6 @@ class Meta(TranslatableMixin.Meta): verbose_name = "Signup" -@register_snippet class BlogSignup(TranslatableMixin, CTABase): description = RichTextField( help_text="Signup's body (richtext)", features=["bold", "italic"], max_length=300, blank=True @@ -180,7 +175,6 @@ class Meta: verbose_name_plural = "Default pages" -@register_snippet class Petition(TranslatableMixin, CTA): campaign_id = models.CharField( max_length=20, @@ -274,7 +268,7 @@ class Petition(TranslatableMixin, CTA): class Meta(TranslatableMixin.Meta): ordering = ["-id"] - verbose_name = "petition snippet" + verbose_name = "Petition" class CampaignPage(MiniSiteNameSpace): diff --git a/network-api/networkapi/wagtailpages/pagemodels/libraries/rcc/taxonomies.py b/network-api/networkapi/wagtailpages/pagemodels/libraries/rcc/taxonomies.py index dee0f5c2d67..a5675ca8fba 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/libraries/rcc/taxonomies.py +++ b/network-api/networkapi/wagtailpages/pagemodels/libraries/rcc/taxonomies.py @@ -1,18 +1,13 @@ -from wagtail.snippets import models as snippet_models - from networkapi.wagtailpages.pagemodels.taxonomy import BaseTaxonomy -@snippet_models.register_snippet class RCCContentType(BaseTaxonomy): pass -@snippet_models.register_snippet class RCCCurricularArea(BaseTaxonomy): pass -@snippet_models.register_snippet class RCCTopic(BaseTaxonomy): pass diff --git a/network-api/networkapi/wagtailpages/pagemodels/libraries/research_hub/taxonomies.py b/network-api/networkapi/wagtailpages/pagemodels/libraries/research_hub/taxonomies.py index 90d78179376..8bcdf26fa08 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/libraries/research_hub/taxonomies.py +++ b/network-api/networkapi/wagtailpages/pagemodels/libraries/research_hub/taxonomies.py @@ -1,16 +1,13 @@ from django.db import models from wagtail.admin import panels as wagtail_panels -from wagtail.snippets import models as snippet_models from networkapi.wagtailpages.pagemodels.taxonomy import BaseTaxonomy -@snippet_models.register_snippet class ResearchRegion(BaseTaxonomy): pass -@snippet_models.register_snippet class ResearchTopic(BaseTaxonomy): description = models.TextField(null=False, blank=True) diff --git a/network-api/networkapi/wagtailpages/pagemodels/profiles.py b/network-api/networkapi/wagtailpages/pagemodels/profiles.py index 00203023626..1adf543b1ea 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/profiles.py +++ b/network-api/networkapi/wagtailpages/pagemodels/profiles.py @@ -5,11 +5,9 @@ from wagtail.admin.panels import FieldPanel from wagtail.models import TranslatableMixin from wagtail.search import index -from wagtail.snippets.models import register_snippet from wagtail_localize.fields import SynchronizedField, TranslatableField -@register_snippet class Profile(index.Indexed, TranslatableMixin, models.Model): name = models.CharField(max_length=70, blank=False) diff --git a/network-api/networkapi/wagtailpages/pagemodels/pulse.py b/network-api/networkapi/wagtailpages/pagemodels/pulse.py index e9218b6fc81..106db927f7c 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/pulse.py +++ b/network-api/networkapi/wagtailpages/pagemodels/pulse.py @@ -2,10 +2,8 @@ from modelcluster.fields import ParentalKey from modelcluster.models import ClusterableModel from wagtail.admin.panels import FieldPanel, InlinePanel -from wagtail.snippets.models import register_snippet -@register_snippet class PulseFilter(ClusterableModel): name = models.CharField( help_text="Identify this filter for other editors.", diff --git a/network-api/networkapi/wagtailpages/wagtail_hooks.py b/network-api/networkapi/wagtailpages/wagtail_hooks.py index ab14c8724e0..1ed86d8992a 100644 --- a/network-api/networkapi/wagtailpages/wagtail_hooks.py +++ b/network-api/networkapi/wagtailpages/wagtail_hooks.py @@ -19,13 +19,19 @@ from wagtail.admin.rich_text.editors.draftail import features as draftail_features from wagtail.coreutils import find_available_slug from wagtail.rich_text import LinkHandler +from wagtail.snippets.models import register_snippet +from wagtail.snippets.views.snippets import SnippetViewSet, SnippetViewSetGroup from wagtail_localize.models import ( LocaleSynchronization, sync_trees_on_locale_sync_save, ) +from networkapi.highlights.models import Highlight +from networkapi.news.models import News +from networkapi.wagtailpages import models as wagtailpages_models from networkapi.wagtailpages.pagemodels.buyersguide.homepage import BuyersGuidePage from networkapi.wagtailpages.pagemodels.buyersguide.products import ProductPage +from networkapi.wagtailpages.pagemodels.campaigns import Callpower from networkapi.wagtailpages.utils import get_locale_from_request post_save.disconnect(sync_trees_on_locale_sync_save, sender=LocaleSynchronization) @@ -169,7 +175,16 @@ def global_admin_css(): @hooks.register("register_icons") def register_icons(icons): - return icons + ["icons/arrows-up-down.svg"] + return icons + [ + "icons/arrows-up-down.svg", + "icons/tito.svg", + "icons/ticket.svg", + "icons/newspaper.svg", + "icons/mozfest.svg", + "icons/pni.svg", + "icons/flask.svg", + "icons/heart.svg", + ] class HowToWagtailMenuItem(MenuItem): @@ -184,13 +199,360 @@ def register_howto_menu_item(): reverse("how-do-i-wagtail"), name="howdoIwagtail", classname="icon icon-help", - order=900, + order=1000, ) -@hooks.register("construct_main_menu") -@hooks.register("construct_settings_menu") -def construct_settings_menu(request, menu_items): - menu_items.sort(key=lambda x: x.name) - for order, item in enumerate(menu_items): - item.order = order +class BlogPageTopicSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.BlogPageTopic + icon = "tag" + menu_order = 000 + menu_label = "Topics" + menu_name = "Topics" + list_display = ("name",) + search_fields = ("name", "title", "intro", "share_description") + + +class BlogSignupSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.BlogSignup + icon = "newspaper" + menu_order = 100 + menu_label = "Newsletter Signups" + menu_name = "Newsletter Signups" + list_display = ( + "name", + "newsletter", + ) + search_fields = ("name", "header", "description", "newsletter") + + +class BlogViewSetGroup(SnippetViewSetGroup): + items = (BlogPageTopicSnippetViewSet, BlogSignupSnippetViewSet) + menu_icon = "bold" + menu_label = "Blog" + menu_name = "Blog" + menu_order = 1400 + + +register_snippet(BlogViewSetGroup) + + +class BuyersGuideProductCategorySnippetViewSet(SnippetViewSet): + model = wagtailpages_models.BuyersGuideProductCategory + icon = "list-ul" + menu_order = 000 + menu_label = "Product Categories" + menu_name = "Product Categories" + list_display = ("name", "parent", "featured", "hidden", "slug", "sort_order", "is_being_used") + search_fields = ( + "name", + "description", + "parent", + ) + + +class BuyersGuideContentCategorySnippetViewSet(SnippetViewSet): + model = wagtailpages_models.BuyersGuideContentCategory + icon = "tag" + menu_order = 100 + menu_label = "Content Categories" + menu_name = "Content Categories" + list_display = ( + "title", + "slug", + ) + search_fields = ( + "title", + "slug", + ) + + +class UpdateSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.Update + icon = "history" + menu_order = 200 + menu_label = "Product Updates" + menu_name = "Product Updates" + list_display = ( + "title", + "author", + "featured", + "created_date", + ) + search_fields = ( + "title", + "source", + "author", + "snippet", + "created_date", + ) + + +class BuyersGuideCTASnippetViewSet(SnippetViewSet): + model = wagtailpages_models.BuyersGuideCallToAction + icon = "link-external" + menu_order = 300 + menu_label = "CTAs" + menu_name = "CTAs" + list_display = ( + "title", + "link_label", + "link_target_url", + ) + search_fields = ("title", "content", "link_label", "link_target_url", "link_target_page") + + +class BuyersGuideViewSetGroup(SnippetViewSetGroup): + items = ( + BuyersGuideProductCategorySnippetViewSet, + BuyersGuideContentCategorySnippetViewSet, + UpdateSnippetViewSet, + BuyersGuideCTASnippetViewSet, + ) + menu_icon = "pni" + menu_label = "*PNI" + menu_name = "*PNI" + menu_order = 1500 + + +register_snippet(BuyersGuideViewSetGroup) + + +class ResearchTopicsSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.ResearchTopic + icon = "tag" + menu_order = 000 + menu_label = "Topics" + menu_name = "Topics" + list_display = ("name", "slug") + search_fields = ( + "name", + "slug", + "description", + ) + + +class ResearchRegionsSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.ResearchRegion + icon = "globe" + menu_order = 100 + menu_label = "Regions" + menu_name = "Regions" + list_display = ("name", "slug") + search_fields = ("name", "slug") + + +class ResearchSetGroup(SnippetViewSetGroup): + items = (ResearchTopicsSnippetViewSet, ResearchRegionsSnippetViewSet) + menu_icon = "flask" + menu_label = "Research Hub" + menu_name = "Research Hub" + menu_order = 1500 + + +register_snippet(ResearchSetGroup) + + +class RCCContentTypeSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.RCCContentType + icon = "clipboard-list" + menu_order = 000 + menu_label = "Content Types" + menu_name = "Content Types" + list_display = ("name", "slug") + search_fields = ("name", "slug") + + +class RCCCurricularAreaSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.RCCCurricularArea + icon = "doc-full" + menu_order = 100 + menu_label = "Curricular Areas" + menu_name = "Curricular Areas" + list_display = ("name", "slug") + search_fields = ("name", "slug") + + +class RCCTopicsSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.RCCTopic + icon = "tag" + menu_order = 200 + menu_label = "Topics" + menu_name = "Topics" + list_display = ("name", "slug") + search_fields = ( + "name", + "slug", + ) + + +class RCCSetGroup(SnippetViewSetGroup): + items = (RCCContentTypeSnippetViewSet, RCCCurricularAreaSnippetViewSet, RCCTopicsSnippetViewSet) + menu_icon = "desktop" + menu_label = "RCC" + menu_name = "RCC" + menu_order = 1600 + + +register_snippet(RCCSetGroup) + + +class PetitionsSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.Petition + icon = "comment" + menu_order = 1700 + menu_label = "Petitions" + menu_name = "Petitions" + add_to_admin_menu = True + list_display = ("name", "newsletter", "campaign_id") + search_fields = ( + "name", + "header", + "description", + "newsletter", + "campaign_id", + "share_link", + "share_link_text", + "thank_you", + ) + + +register_snippet(PetitionsSnippetViewSet) + + +class ProfilesSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.Profile + icon = "user" + menu_order = 1800 + menu_label = "Profiles" + menu_name = "Profiles" + add_to_admin_menu = True + list_display = ("name", "tagline", "slug") + search_fields = ( + "name", + "tagline", + "introduction", + "slug", + ) + + +register_snippet(ProfilesSnippetViewSet) + + +class CTASnippetViewSet(SnippetViewSet): + model = wagtailpages_models.CTA + icon = "link-external" + menu_order = 1900 + menu_label = "CTAs" + menu_name = "CTAs" + add_to_admin_menu = True + list_display = ("name", "header", "newsletter") + search_fields = ( + "name", + "header", + "description", + "newsletter", + ) + + +register_snippet(CTASnippetViewSet) + + +class SignupSnippetViewSet(SnippetViewSet): + model = wagtailpages_models.Signup + icon = "newspaper" + menu_order = 2000 + menu_label = "Signups" + menu_name = "Signups" + add_to_admin_menu = True + list_display = ("name", "header", "newsletter", "campaign_id") + search_fields = ( + "name", + "header", + "description", + "newsletter", + "campaign_id", + ) + + +register_snippet(SignupSnippetViewSet) + + +class AreasOfFocusViewSet(SnippetViewSet): + model = wagtailpages_models.FocusArea + icon = "view" + menu_order = 000 + menu_label = "Areas of Focus" + menu_name = "Areas of Focus" + list_display = ("name", "interest_icon", "page") + search_fields = ("name", "description", "interest_icon", "page") + + +class CallpowersViewSet(SnippetViewSet): + model = Callpower + icon = "chain-broken" + menu_order = 100 + menu_label = "Callpowers" + menu_name = "Callpowers" + list_display = ("name", "header", "newsletter", "campaign_id", "call_button_label") + search_fields = ( + "name", + "header", + "description", + "newsletter", + "campaign_id", + "call_button_label" "success_heading", + "success_text", + "share_facebook", + "share_email", + ) + + +class HighlightSnippetViewSet(SnippetViewSet): + model = Highlight + icon = "date" + menu_order = 200 + list_display = ( + "title", + "description", + "link_url", + ) + search_fields = ("title", "description") + + +class NewsSnippetViewSet(SnippetViewSet): + model = News + icon = "doc-full-inverse" + menu_order = 300 + list_display = ( + "headline", + "thumbnail", + "date", + "link", + ) + search_fields = ("headline",) + + +class PulseFiltersViewSet(SnippetViewSet): + model = wagtailpages_models.PulseFilter + icon = "cross" + menu_order = 400 + menu_label = "Pulse Filters" + menu_name = "Pulse Filters" + list_display = ("name", "filter_key", "filter_key_label") + search_fields = ( + "name", + "filter_key", + "filter_key_label", + ) + + +class ArchiveSetGroup(SnippetViewSetGroup): + items = (AreasOfFocusViewSet, CallpowersViewSet, HighlightSnippetViewSet, NewsSnippetViewSet, PulseFiltersViewSet) + menu_icon = "folder-open-1" + menu_label = "Archived" + menu_name = "Archived" + menu_order = 2100 + + +register_snippet(ArchiveSetGroup) From 2d61300074c111637250d7a28a797fcac3497217 Mon Sep 17 00:00:00 2001 From: Mavis Ou Date: Thu, 25 Jan 2024 15:27:27 -0800 Subject: [PATCH 2/2] Allow newsletter signup module to have two optional name fields & update newsletter module on Bannered Campaign Page (#11761) * removed a styling class that's not needed * improvement of the existing code * repurposed the existing input-email.jsx to a general input-text.jsx * Allow newsletter module to show two optional fields (first name and last name) & replaced the newsletter module on Bannered Campaign Page to use to new implementation approach. * allow options to show country field and language field by default --- .../wagtailpages/bannered_campaign_page.html | 7 +- .../templates/wagtailpages/tags/cta.html | 2 - .../atoms/{input-email.jsx => input-text.jsx} | 12 +- .../organisms/default-layout-signup.jsx | 166 +++++++++++++----- .../organisms/form-specific-style.js | 8 + .../organisms/with-submission-logic.jsx | 4 +- 6 files changed, 142 insertions(+), 57 deletions(-) rename source/js/components/newsletter-signup/atoms/{input-email.jsx => input-text.jsx} (92%) diff --git a/network-api/networkapi/wagtailpages/templates/wagtailpages/bannered_campaign_page.html b/network-api/networkapi/wagtailpages/templates/wagtailpages/bannered_campaign_page.html index eec975add0b..ee046230cdc 100644 --- a/network-api/networkapi/wagtailpages/templates/wagtailpages/bannered_campaign_page.html +++ b/network-api/networkapi/wagtailpages/templates/wagtailpages/bannered_campaign_page.html @@ -63,7 +63,12 @@ {% if page.signup %} {% with localized_signup=page.signup.localized %}
{ let inputField = ( ({ formData: { @@ -90,21 +87,46 @@ class DefaultSignupForm extends Component { } } + handleInputFocus() { + ReactGA.event({ + category: `signup`, + action: `form focus`, + label: `Signup form input focused`, + }); + } + + handleFirstNameChange(event) { + this.updateFormFieldValue(event.target.name, event.target.value); + } + + handleLastNameChange(event) { + this.updateFormFieldValue(event.target.name, event.target.value); + } + + handleEmailFocusAndInput() { + this.handleInputFocus(); + + this.setState({ showCountryField: true, showLanguageField: true }); + } + handleEmailChange(event) { - this.updateFormFieldValue("email", event.target.value); + this.updateFormFieldValue(event.target.name, event.target.value); this.toggleSubmitButton(event.target.value === ""); } handleCountryChange(event) { - this.updateFormFieldValue("country", event.target.value); + this.updateFormFieldValue(event.target.name, event.target.value); } handleLanguageChange(event) { - this.updateFormFieldValue("language", event.target.value); + this.updateFormFieldValue(event.target.name, event.target.value); } handlePrivacyChange(event) { - this.updateFormFieldValue("privacy", event.target.checked.toString()); + this.updateFormFieldValue( + event.target.name, + event.target.checked.toString() + ); } renderHeader() { @@ -131,18 +153,59 @@ class DefaultSignupForm extends Component { ); } + renderFirstNameField() { + const name = "firstName"; + + return ( + this.handleInputFocus()} + onChange={(event) => this.handleFirstNameChange(event)} + required={false} + outerMarginClasses={FIELD_MARGIN_CLASSES} + errorMessage={this.props.errors[name]} + fieldStyle={this.style.fieldStyle} + /> + ); + } + + renderLastNameField() { + const name = "lastName"; + + return ( + this.handleInputFocus()} + onChange={(event) => this.handleLastNameChange(event)} + required={false} + outerMarginClasses={FIELD_MARGIN_CLASSES} + errorMessage={this.props.errors[name]} + fieldStyle={this.style.fieldStyle} + /> + ); + } + renderEmailField() { const name = "email"; return ( - this.showAllFields()} - onInput={() => this.showAllFields()} + onFocus={() => this.handleEmailFocusAndInput()} + onInput={() => this.handleEmailFocusAndInput()} onChange={(event) => this.handleEmailChange(event)} required={true} outerMarginClasses={FIELD_MARGIN_CLASSES} @@ -152,33 +215,37 @@ class DefaultSignupForm extends Component { ); } - renderAdditionalFields() { - const nameCountry = "country"; - const nameLanguage = "language"; + renderCountryField() { + const name = "country"; return ( - <> - this.handleLanguageChange(event)} - required={false} - outerMarginClasses={FIELD_MARGIN_CLASSES} - fieldStyle={this.style.fieldStyle} - /> - + this.handleLanguageChange(event)} + required={false} + outerMarginClasses={FIELD_MARGIN_CLASSES} + fieldStyle={this.style.fieldStyle} + /> ); } @@ -187,7 +254,7 @@ class DefaultSignupForm extends Component { return (
+ {this.props.askName === "True" && this.renderFirstNameField()} + {this.props.askName === "True" && this.renderLastNameField()} {this.renderEmailField()} - {this.state.showAllFields && this.renderAdditionalFields()} + {this.state.showCountryField && this.renderCountryField()} + {this.state.showLanguageField && this.renderLanguageField()}
{this.renderPrivacyCheckbox()}
diff --git a/source/js/components/newsletter-signup/organisms/form-specific-style.js b/source/js/components/newsletter-signup/organisms/form-specific-style.js index 6518833c940..a32bd48165a 100644 --- a/source/js/components/newsletter-signup/organisms/form-specific-style.js +++ b/source/js/components/newsletter-signup/organisms/form-specific-style.js @@ -27,6 +27,14 @@ */ export const FORM_STYLE = { + "bannered-campaign-body": { + buttonPosition: "bottom", + buttonStyle: "primary", + buttonWidthClasses: "tw-w-full", + fieldStyle: "filled", + headingLevel: 3, + headingClass: "tw-h5-heading", + }, "blog-body": { fieldStyle: "outlined", headingLevel: 2, diff --git a/source/js/components/newsletter-signup/organisms/with-submission-logic.jsx b/source/js/components/newsletter-signup/organisms/with-submission-logic.jsx index 2914aa46d74..068ac250ee5 100644 --- a/source/js/components/newsletter-signup/organisms/with-submission-logic.jsx +++ b/source/js/components/newsletter-signup/organisms/with-submission-logic.jsx @@ -167,6 +167,8 @@ function withSubmissionLogic(WrappedComponent) { }); let payload = { + givenNames: formData.firstName, + surname: formData.lastName, email: formData.email, country: formData.country, lang: formData.language, @@ -269,7 +271,7 @@ function withSubmissionLogic(WrappedComponent) { apiUrl: PropTypes.string.isRequired, ctaHeader: PropTypes.string.isRequired, ctaDescription: PropTypes.string.isRequired, - formPosition: PropTypes.string.isRequired, + formPosition: PropTypes.string, whenLoaded: PropTypes.func, };