Skip to content

Commit

Permalink
[Main Nav] Featured columns [TP1-53](#12134)
Browse files Browse the repository at this point in the history
* Add NavFeaturedItem block

* Add NavFeaturedColumn block

* Add featured column to dropdown

* Adjust factories to featured column

* Adjust tests to new factories and add tests for featured column

* Fix migration
  • Loading branch information
jhonatan-lopes committed Apr 3, 2024
1 parent 9a04f2e commit e141850
Show file tree
Hide file tree
Showing 4 changed files with 345 additions and 43 deletions.
125 changes: 111 additions & 14 deletions network-api/networkapi/nav/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.core.exceptions import ValidationError
from django.forms.utils import ErrorList
from wagtail import blocks
from wagtail.images.blocks import ImageChooserBlock
from wagtail.telepath import register

from networkapi.wagtailpages.pagemodels.customblocks.common.base_link_block import (
Expand Down Expand Up @@ -48,6 +49,33 @@ class Meta:
register(BaseLinkBlockAdapter(), NavItem)


class NavFeaturedItem(BaseLinkBlock):
icon = ImageChooserBlock()

def __init__(self, local_blocks=None, **kwargs):
# Use __init__ method to change the order of the blocks when constructing
# them through inheritance
super().__init__(local_blocks, **kwargs)
self.child_blocks = self.base_blocks.copy()
child_blocks = OrderedDict(
{
"label": self.child_blocks.pop("label"),
"icon": self.child_blocks.pop("icon"),
}
)
child_blocks.update({k: v for k, v in self.child_blocks.items()})
self.child_blocks = child_blocks

class Meta:
value_class = NavItemValue
label = "Featured Navigation Link"
icon = "link"
template = "nav/blocks/featured_item_block.html"


register(BaseLinkBlockAdapter(), NavFeaturedItem)


class NavButton(BaseLinkBlock):
class Meta:
value_class = NavItemValue
Expand Down Expand Up @@ -93,6 +121,18 @@ class Meta:
value_class = NavColumnValue


class NavFeaturedColumn(blocks.StructBlock):
title = blocks.CharBlock(max_length=100)
# Empty default so that it starts collapsed:
nav_items = blocks.ListBlock(NavFeaturedItem, min_num=1, max_num=4, label="Items", default=[])

class Meta:
label = "Featured Navigation Column"
icon = "list-ul"
template = "nav/blocks/featured_column_block.html"
value_class = NavColumnValue


class NavOverview(blocks.StructBlock):
title = blocks.CharBlock(max_length=100)
description = blocks.RichTextBlock(features=["bold", "italic"], max_length=200)
Expand Down Expand Up @@ -126,6 +166,17 @@ def button(self) -> NavButton | None:
return button[0]
return None

@property
def has_featured_column(self) -> bool:
return bool(self.get("featured_column"))

@property
def featured_column(self) -> NavFeaturedColumn | None:
featured_column = self.get("featured_column")
if featured_column:
return featured_column[0]
return None


class NavDropdown(blocks.StructBlock):
title = blocks.CharBlock(max_length=100, help_text="How the dropdown menu will be labelled in the nav bar")
Expand All @@ -144,6 +195,14 @@ class NavDropdown(blocks.StructBlock):
label="Columns",
help_text="Add up to 4 columns of navigation links",
)
featured_column = blocks.ListBlock(
NavFeaturedColumn(label="Featured Column"),
min_num=0,
max_num=1,
label="Featured Column",
help_text="A column made of items and icons. If added, it will take the place of the last column",
default=[],
)
button = blocks.ListBlock(
NavButton,
required=False,
Expand All @@ -158,24 +217,62 @@ def clean(self, value):
result = super().clean(value)
errors = {}

if result["overview"] and len(result["columns"]) > 3:
errors["overview"] = ErrorList(
[
blocks.ListBlockValidationError(
block_errors={},
non_block_errors=ErrorList(
[ValidationError("Overview cannot be used with more than 3 nav columns.")]
),
)
]
)
has_overview = bool(result["overview"])
has_featured_column = bool(result["featured_column"])

allowed_number_of_columns = 4
if has_overview:
allowed_number_of_columns -= 1
if has_featured_column:
allowed_number_of_columns -= 1

current_number_of_columns = len(result["columns"])

if current_number_of_columns > allowed_number_of_columns:
if has_overview and not has_featured_column:
err_msg_overview = 'A maximum of 3 columns can be added together with an "overview".'
err_msg_columns = 'A maximum of 3 columns can be added together with an "overview".'
err_msg_featured_column = ""
elif has_featured_column and not has_overview:
err_msg_overview = ""
err_msg_columns = 'A maximum of 3 columns can be added together with a "featured column".'
err_msg_featured_column = "Featured column cannot be used with more than 3 nav columns."
elif has_overview and has_featured_column:
err_msg_overview = (
'A maximum of 2 columns can be added together with an "overview" and a "featured column".'
)
err_msg_columns = (
'A maximum of 2 columns can be added together with an "overview" and a "featured column".'
)
err_msg_featured_column = (
'A maximum of 2 columns can be added together with an "overview" and a "featured column".'
)

if err_msg_overview:
errors["overview"] = ErrorList(
[
blocks.ListBlockValidationError(
block_errors={},
non_block_errors=ErrorList([ValidationError(err_msg_overview)]),
)
]
)

if err_msg_featured_column:
errors["featured_column"] = ErrorList(
[
blocks.ListBlockValidationError(
block_errors={},
non_block_errors=ErrorList([ValidationError(err_msg_featured_column)]),
)
]
)

errors["columns"] = ErrorList(
[
blocks.ListBlockValidationError(
block_errors={},
non_block_errors=ErrorList(
[ValidationError('A maximum of 3 columns can be added together with an "overview".')]
),
non_block_errors=ErrorList([ValidationError(err_msg_columns)]),
)
]
)
Expand Down
95 changes: 89 additions & 6 deletions network-api/networkapi/nav/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,31 @@ class Params:
relative_url = ""


class NavFeaturedItemFactory(ExtendedStructBlockFactory):
class Meta:
model = nav_blocks.NavFeaturedItem

class Params:
page_link = factory.Trait(
link_to="page",
page=factory.Iterator(wagtail_models.Page.objects.filter(locale_id="1")),
)
external_url_link = factory.Trait(link_to="external_url", external_url=factory.Faker("url"))
relative_url_link = factory.Trait(link_to="relative_url", relative_url=f'/{factory.Faker("uri_path")}')

label = factory.Faker("sentence", nb_words=3)
icon = factory.SubFactory(wagtail_factories.ImageChooserBlockFactory)

# Setup default link as external URL (it won't pass validation without a link type defined though
# so it's still necessary to use the factory with traits)
link_to = "external_url"
# Set all link types to None by default. Only define the needed link type in the factory
# trait to avoid conflicts
page = None
external_url = ""
relative_url = ""


class NavButtonFactory(ExtendedStructBlockFactory):
"""Factory for NavButtonBlock.
Expand Down Expand Up @@ -108,6 +133,22 @@ class Params:
button = wagtail_factories.ListBlockFactory(NavButtonFactory, **{"0__external_url_link": True})


class NavFeaturedColumnFactory(ExtendedStructBlockFactory):
class Meta:
model = nav_blocks.NavFeaturedColumn

title = factory.Faker("sentence", nb_words=3)
nav_items = wagtail_factories.ListBlockFactory(
NavFeaturedItemFactory,
**{
"0__external_url_link": True,
"1__external_url_link": True,
"2__external_url_link": True,
"3__external_url_link": True,
},
)


class NavOverviewFactory(wagtail_factories.StructBlockFactory):
class Meta:
model = nav_blocks.NavOverview
Expand All @@ -121,32 +162,74 @@ class Meta:
model = nav_blocks.NavDropdown

class Params:
no_overview = factory.Trait(overview=[])
all_columns = factory.Trait(
with_overview = factory.Trait(
overview=wagtail_factories.ListBlockFactory(
NavOverviewFactory,
**{
"0__title": factory.Faker("sentence", nb_words=3),
},
),
columns=wagtail_factories.ListBlockFactory(
NavColumnFactory,
**{
"0__title": factory.Faker("sentence", nb_words=3),
"1__title": factory.Faker("sentence", nb_words=3),
"2__title": factory.Faker("sentence", nb_words=3),
},
),
featured_column=[],
)
with_featured_column = factory.Trait(
overview=[],
columns=wagtail_factories.ListBlockFactory(
NavColumnFactory,
**{
"0__title": factory.Faker("sentence", nb_words=3),
"1__title": factory.Faker("sentence", nb_words=3),
"2__title": factory.Faker("sentence", nb_words=3),
"3__title": factory.Faker("sentence", nb_words=3),
},
),
featured_column=wagtail_factories.ListBlockFactory(
NavFeaturedColumnFactory,
**{
"0__title": factory.Faker("sentence", nb_words=3),
},
),
)
with_overview_and_featured_column = factory.Trait(
overview=wagtail_factories.ListBlockFactory(
NavOverviewFactory,
**{
"0__title": factory.Faker("sentence", nb_words=3),
},
),
columns=wagtail_factories.ListBlockFactory(
NavColumnFactory,
**{
"0__title": factory.Faker("sentence", nb_words=3),
"1__title": factory.Faker("sentence", nb_words=3),
},
),
featured_column=wagtail_factories.ListBlockFactory(
NavFeaturedColumnFactory,
**{
"0__title": factory.Faker("sentence", nb_words=3),
},
),
)
no_button = factory.Trait(button=[])

overview = wagtail_factories.ListBlockFactory(
NavOverviewFactory, **{"0__title": factory.Faker("sentence", nb_words=3)}
)
overview = wagtail_factories.ListBlockFactory(NavOverviewFactory)
columns = wagtail_factories.ListBlockFactory(
NavColumnFactory,
**{
"0__title": factory.Faker("sentence", nb_words=3),
"1__title": factory.Faker("sentence", nb_words=3),
"2__title": factory.Faker("sentence", nb_words=3),
"3__title": factory.Faker("sentence", nb_words=3),
},
)
featured_column = wagtail_factories.ListBlockFactory(NavFeaturedColumnFactory)
button = wagtail_factories.ListBlockFactory(NavButtonFactory, **{"0__external_url_link": True})


Expand Down
28 changes: 27 additions & 1 deletion network-api/networkapi/nav/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.10 on 2024-03-28 18:22
# Generated by Django 4.2.11 on 2024-04-01 16:39

import uuid

Expand Down Expand Up @@ -116,6 +116,32 @@ class Migration(migrations.Migration):
min_num=1,
),
),
(
"featured_column",
wagtail.blocks.ListBlock(
wagtail.blocks.StructBlock(
[
("title", wagtail.blocks.CharBlock(max_length=100)),
(
"nav_items",
wagtail.blocks.ListBlock(
networkapi.nav.blocks.NavFeaturedItem,
default=[],
label="Items",
max_num=4,
min_num=1,
),
),
],
label="Featured Column",
),
default=[],
help_text="A column made of items and icons. If added, it will take the place of the last column",
label="Featured Column",
max_num=1,
min_num=0,
),
),
(
"button",
wagtail.blocks.ListBlock(
Expand Down
Loading

0 comments on commit e141850

Please sign in to comment.