Skip to content

Commit

Permalink
[Main Nav] Nav menu [TP1-51](#12120)
Browse files Browse the repository at this point in the history
* Add `NavMenu` model

* Add factory for `NavMenu`

* Add initial migration for `NavMenu`

* Add tests for `NavMenu`

* Register nav on wagtail side bar

* Update migration file
  • Loading branch information
jhonatan-lopes authored Apr 1, 2024
1 parent 84ed530 commit 81ce62a
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 0 deletions.
18 changes: 18 additions & 0 deletions network-api/networkapi/nav/factories.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import factory
import wagtail_factories
from factory.django import DjangoModelFactory
from wagtail import models as wagtail_models
from wagtail.rich_text import RichText

from networkapi.nav import blocks as nav_blocks
from networkapi.nav import models as nav_models
from networkapi.wagtailcustomization.factories.blocks import ExtendedStructBlockFactory


Expand Down Expand Up @@ -146,3 +148,19 @@ class Params:
},
)
button = wagtail_factories.ListBlockFactory(NavButtonFactory, **{"0__external_url_link": True})


class NavMenuFactory(DjangoModelFactory):
class Meta:
model = nav_models.NavMenu

title = factory.Faker("sentence", nb_words=3)
dropdowns = wagtail_factories.StreamFieldFactory(
{"dropdown": factory.SubFactory(NavDropdownFactory)},
**{
"0": "dropdown",
"1": "dropdown",
"2": "dropdown",
"3": "dropdown",
},
)
182 changes: 182 additions & 0 deletions network-api/networkapi/nav/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Generated by Django 4.2.10 on 2024-03-28 18:22

import uuid

import django.db.models.deletion
import wagtail.blocks
import wagtail.fields
import wagtail.models
from django.db import migrations, models

import networkapi.nav.blocks


class Migration(migrations.Migration):

initial = True

dependencies = [
("wagtailcore", "0089_log_entry_data_json_null_to_object"),
]

operations = [
migrations.CreateModel(
name="NavMenu",
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("translation_key", models.UUIDField(default=uuid.uuid4, editable=False)),
("live", models.BooleanField(default=True, editable=False, verbose_name="live")),
(
"has_unpublished_changes",
models.BooleanField(default=False, editable=False, verbose_name="has unpublished changes"),
),
(
"first_published_at",
models.DateTimeField(blank=True, db_index=True, null=True, verbose_name="first published at"),
),
(
"last_published_at",
models.DateTimeField(editable=False, null=True, verbose_name="last published at"),
),
("go_live_at", models.DateTimeField(blank=True, null=True, verbose_name="go live date/time")),
("expire_at", models.DateTimeField(blank=True, null=True, verbose_name="expiry date/time")),
("expired", models.BooleanField(default=False, editable=False, verbose_name="expired")),
("title", models.CharField(help_text="For internal identification only", max_length=100)),
(
"dropdowns",
wagtail.fields.StreamField(
[
(
"dropdown",
wagtail.blocks.StructBlock(
[
(
"title",
wagtail.blocks.CharBlock(
help_text="How the dropdown menu will be labelled in the nav bar",
max_length=100,
),
),
(
"overview",
wagtail.blocks.ListBlock(
wagtail.blocks.StructBlock(
[
("title", wagtail.blocks.CharBlock(max_length=100)),
(
"description",
wagtail.blocks.RichTextBlock(
features=["bold", "italic"], max_length=200
),
),
],
label="Overview",
),
default=[],
help_text="If added, the overview will take the place of the first column",
label="Overview",
max_num=1,
min_num=0,
),
),
(
"columns",
wagtail.blocks.ListBlock(
wagtail.blocks.StructBlock(
[
("title", wagtail.blocks.CharBlock(max_length=100)),
(
"nav_items",
wagtail.blocks.ListBlock(
networkapi.nav.blocks.NavItem,
default=[],
label="Items",
max_num=4,
min_num=1,
),
),
(
"button",
wagtail.blocks.ListBlock(
networkapi.nav.blocks.NavButton,
default=[],
help_text="Adds a CTA button to the bottom of the nav column.",
label="Column Button",
max_num=1,
min_num=0,
required=False,
),
),
],
label="Column",
),
help_text="Add up to 4 columns of navigation links",
label="Columns",
max_num=4,
min_num=1,
),
),
(
"button",
wagtail.blocks.ListBlock(
networkapi.nav.blocks.NavButton,
default=[],
help_text="Use it to add a CTA to link to the contents of the dropdown menu",
label="Dropdown Button",
max_num=1,
min_num=0,
required=False,
),
),
],
label="Dropdown",
),
)
],
help_text="Add up to 5 dropdown menus",
use_json_field=True,
),
),
(
"latest_revision",
models.ForeignKey(
blank=True,
editable=False,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to="wagtailcore.revision",
verbose_name="latest revision",
),
),
(
"live_revision",
models.ForeignKey(
blank=True,
editable=False,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to="wagtailcore.revision",
verbose_name="live revision",
),
),
(
"locale",
models.ForeignKey(
editable=False,
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to="wagtailcore.locale",
),
),
],
options={
"verbose_name": "Navigation Menu",
"verbose_name_plural": "Navigation Menus",
"abstract": False,
"unique_together": {("translation_key", "locale")},
},
bases=(wagtail.models.PreviewableMixin, models.Model),
),
]
Empty file.
38 changes: 38 additions & 0 deletions network-api/networkapi/nav/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from django.db import models
from wagtail import models as wagtail_models
from wagtail.admin import panels
from wagtail.fields import StreamField

from networkapi.nav import blocks as nav_blocks


class NavMenu(
wagtail_models.PreviewableMixin,
wagtail_models.DraftStateMixin,
wagtail_models.RevisionMixin,
wagtail_models.TranslatableMixin,
models.Model,
):
title = models.CharField(max_length=100, help_text="For internal identification only")

dropdowns = StreamField(
[
("dropdown", nav_blocks.NavDropdown(label="Dropdown")),
],
use_json_field=True,
min_num=1,
max_num=5,
help_text="Add up to 5 dropdown menus",
)

panels = [
panels.FieldPanel("title"),
panels.FieldPanel("dropdowns"),
]

class Meta(wagtail_models.TranslatableMixin.Meta):
verbose_name = "Navigation Menu"
verbose_name_plural = "Navigation Menus"

def __str__(self) -> str:
return self.title
29 changes: 29 additions & 0 deletions network-api/networkapi/nav/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from django.test import TestCase
from wagtail.blocks import StreamBlockValidationError

from networkapi.nav import factories as nav_factories
from networkapi.nav import models as nav_models


class NavMenuTests(TestCase):
def test_default_factory(self):
"""Test that the default factory creates a NavMenu with 4 dropdowns."""
menu = nav_factories.NavMenuFactory()
self.assertIsInstance(menu, nav_models.NavMenu)
self.assertEqual(len(menu.dropdowns), 4)

def test_cannot_create_nav_menu_without_dropdowns(self):
with self.assertRaises(StreamBlockValidationError):
menu = nav_factories.NavMenuFactory(dropdowns={})
menu.dropdowns.stream_block.clean([])

def test_cannot_create_nav_menu_with_more_than_five_dropdowns(self):
with self.assertRaises(StreamBlockValidationError):
menu = nav_factories.NavMenuFactory(
dropdowns__0="dropdown",
dropdowns__1="dropdown",
dropdowns__2="dropdown",
dropdowns__3="dropdown",
dropdowns__4="dropdown",
)
menu.dropdowns.stream_block.clean([])
25 changes: 25 additions & 0 deletions network-api/networkapi/nav/wagtail_hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from wagtail.snippets.models import register_snippet
from wagtail.snippets.views.snippets import SnippetViewSet, SnippetViewSetGroup

from networkapi.nav.models import NavMenu


class NavMenuViewSet(SnippetViewSet):
model = NavMenu
icon = "list-ul"
menu_order = 100
menu_label = "Navigation Menus"
list_display = ("title",)
search_fields = ("title",)
ordering = ("title",)


class NavDropdownViewSetGroup(SnippetViewSetGroup):
items = (NavMenuViewSet,)
menu_label = "Main Navigation"
menu_name = "Main Navigation"
add_to_admin_menu = True
menu_order = 1600


register_snippet(NavDropdownViewSetGroup)

0 comments on commit 81ce62a

Please sign in to comment.