From 388a93bdee0d81e07a004a100b8ca255911b30f2 Mon Sep 17 00:00:00 2001 From: nadijagraca Date: Fri, 27 Oct 2023 13:09:45 +0200 Subject: [PATCH] addressing pr comments part 3 --- vizro-core/examples/default/app.py | 5 -- vizro-core/src/vizro/_constants.py | 1 - vizro-core/src/vizro/models/__init__.py | 2 +- .../src/vizro/models/_navigation/accordion.py | 2 +- .../src/vizro/models/_navigation/nav_bar.py | 25 ++++------ .../src/vizro/models/_navigation/nav_item.py | 50 +++++++++++++------ .../vizro/models/_navigation/navigation.py | 6 +++ vizro-core/src/vizro/models/types.py | 2 + 8 files changed, 54 insertions(+), 39 deletions(-) diff --git a/vizro-core/examples/default/app.py b/vizro-core/examples/default/app.py index 3b1fd6ed2..cf285ed00 100644 --- a/vizro-core/examples/default/app.py +++ b/vizro-core/examples/default/app.py @@ -525,10 +525,6 @@ def create_home_page(): create_country_analysis(), ], navigation=vm.Navigation( - pages={ - "Analysis": ["Homepage", "Variable Analysis"], - "Summary": ["Relationship Analysis", "Continent Summary", "Country Analysis"], - }, selector=vm.NavBar( items=[ vm.NavItem( @@ -541,7 +537,6 @@ def create_home_page(): ), vm.NavItem( pages=["Country Analysis"], - text="Country Analysis is the set text for this icon", ), ] ), diff --git a/vizro-core/src/vizro/_constants.py b/vizro-core/src/vizro/_constants.py index 3cf0ec352..5e05700d9 100644 --- a/vizro-core/src/vizro/_constants.py +++ b/vizro-core/src/vizro/_constants.py @@ -8,4 +8,3 @@ FILTER_ACTION_PREFIX = "filter_action" PARAMETER_ACTION_PREFIX = "parameter_action" ACCORDION_DEFAULT_TITLE = "SELECT PAGE" -MIN_NO_OF_PAGES = 2 diff --git a/vizro-core/src/vizro/models/__init__.py b/vizro-core/src/vizro/models/__init__.py index 33887a143..d5ced4be0 100644 --- a/vizro-core/src/vizro/models/__init__.py +++ b/vizro-core/src/vizro/models/__init__.py @@ -29,9 +29,9 @@ "Dropdown", "Filter", "Graph", - "NavItem", "Layout", "NavBar", + "NavItem", "Navigation", "Page", "Parameter", diff --git a/vizro-core/src/vizro/models/_navigation/accordion.py b/vizro-core/src/vizro/models/_navigation/accordion.py index 5500af582..1690cbc1b 100644 --- a/vizro-core/src/vizro/models/_navigation/accordion.py +++ b/vizro-core/src/vizro/models/_navigation/accordion.py @@ -7,7 +7,7 @@ from dash import html from pydantic import Field, validator -from vizro._constants import ACCORDION_DEFAULT_TITLE, MIN_NO_OF_PAGES +from vizro._constants import ACCORDION_DEFAULT_TITLE from vizro.models import VizroBaseModel from vizro.models._models_utils import _log_call from vizro.models._navigation._navigation_utils import _validate_pages diff --git a/vizro-core/src/vizro/models/_navigation/nav_bar.py b/vizro-core/src/vizro/models/_navigation/nav_bar.py index 1ced3960b..879bc3861 100644 --- a/vizro-core/src/vizro/models/_navigation/nav_bar.py +++ b/vizro-core/src/vizro/models/_navigation/nav_bar.py @@ -4,8 +4,8 @@ from typing import List, Optional from dash import html +from pydantic import validator -from vizro.managers import model_manager from vizro.models import VizroBaseModel from vizro.models._models_utils import _log_call from vizro.models._navigation.nav_item import NavItem @@ -18,26 +18,21 @@ class NavBar(VizroBaseModel): Args: pages (Optional[NavPagesType]): See [`NavPagesType`][vizro.models.types.NavPagesType]. Defaults to `None`. - items (List[NavItem]): List of NavItem models. Defaults to `[]`. + items (List[NavItem]): See [`NavItem`][vizro.models.NavItem]. Defaults to `[]`. """ pages: Optional[NavPagesType] = None items: List[NavItem] = [] - @_log_call - def pre_build(self): - from vizro.models._navigation import Navigation - - _, navigation = next(model_manager._items_with_type(Navigation)) - - if self.pages is None: - self.pages = navigation.pages + @validator("items", always=True) + def validate_items(cls, items, values): + if not items: + if isinstance(values.get("pages"), list): + return [NavItem(pages=[page]) for page in values.get("pages")] + if isinstance(values.get("pages"), dict): + return [NavItem(pages=value) for page, value in values.get("pages").items()] - if not self.items: - if isinstance(self.pages, list): - self.items = [NavItem(pages=[page]) for page in self.pages] - if isinstance(self.pages, dict): - self.items = [NavItem(pages=value) for page, value in self.pages.items()] + return items @_log_call def build(self, active_page_id): diff --git a/vizro-core/src/vizro/models/_navigation/nav_item.py b/vizro-core/src/vizro/models/_navigation/nav_item.py index fc80eca6d..d81bdfe0c 100644 --- a/vizro-core/src/vizro/models/_navigation/nav_item.py +++ b/vizro-core/src/vizro/models/_navigation/nav_item.py @@ -19,17 +19,20 @@ class NavItem(VizroBaseModel): """Icon to be used in Navigation Panel of Dashboard. Args: - tooltip (Optional[str]): Text to be displayed in the tooltip on icon hover. - icon (Optional[str]): URI (relative or absolute) of the embeddable content. pages (NavPagesType): See [NavPagesType][vizro.models.types.NavPagesType]. + selector (Optional[Accordion]): See [`Accordion`][vizro.models.Accordion]. Defaults to `None`. + icon (Optional[str]): URI (relative or absolute) of the embeddable content. + max_text_length (int): Character limit for `text` argument. Defaults to 9. + text (str): Text to be display below the icon. Defaults to `""`. + tooltip (Optional[str]): Text to be displayed in the tooltip on icon hover. """ - tooltip: Optional[str] icon: str = "home" pages: NavPagesType selector: Optional[Accordion] = None - text: Optional[str] = "" max_text_length: int = 9 + text: str = "" + tooltip: Optional[str] = None # Re-used validators _validate_pages = validator("pages", allow_reuse=True, always=True)(_validate_pages) @@ -47,28 +50,46 @@ def pre_build(self): self.tooltip = self.text self.text = self.text[:self.max_text_length] + @validator("text", always=True) + def set_text(cls, text, values): + if text and len(text) > values.get("max_text_length"): + return text[: values.get("max_text_length")] + return text + + @validator("tooltip", always=True, pre=True) + def set_tooltip(cls, tooltip, values): + if tooltip is None: + if values.get("text") and len(values.get("text")) > values.get("max_text_length"): + return values.get("text") + return tooltip + @_log_call def build(self, active_page_id): + icon_first_page = ( + list(itertools.chain(*self.pages.values()))[0] if isinstance(self.pages, dict) else self.pages[0] + ) + icon_div = ( + html.Span(self.icon, className="material-symbols-outlined") + if self.icon + else html.Div(className="hidden") + ) + text_div = html.Div(children=[self.text], className="icon-text") if self.text else html.Div(className="hidden") + return dbc.Button( id=self.id, children=[ html.Div( children=[ - html.Span(self.icon, className="material-symbols-outlined"), - html.Div( - children=[self.text], - className="icon-text", - ) - if self.text - else html.Div(className="hidden"), + icon_div, + text_div, ], className="nav-icon-text", ), self._create_icon_tooltip(), ], className="icon-button", - href=dash.page_registry[self._get_first_page()]["relative_path"], - active=self._get_first_page() == active_page_id, + href=dash.page_registry[icon_first_page]["relative_path"], + active=icon_first_page == active_page_id, ) def _create_icon_tooltip(self): @@ -80,6 +101,3 @@ def _create_icon_tooltip(self): className="custom-tooltip", ) return tooltip - - def _get_first_page(self): - return list(itertools.chain(*self.pages.values()))[0] if isinstance(self.pages, dict) else self.pages[0] diff --git a/vizro-core/src/vizro/models/_navigation/navigation.py b/vizro-core/src/vizro/models/_navigation/navigation.py index 17cf2bc1a..082bf2116 100644 --- a/vizro-core/src/vizro/models/_navigation/navigation.py +++ b/vizro-core/src/vizro/models/_navigation/navigation.py @@ -33,6 +33,12 @@ class Navigation(VizroBaseModel): def set_selector(cls, selector, values): if selector is None: return Accordion(pages=values.get("pages")) + + if isinstance(selector, NavBar): + if selector.pages is None and selector.items is None: + selector.pages = values.get("pages") + selector.items = [] + return selector return selector @_log_call diff --git a/vizro-core/src/vizro/models/types.py b/vizro-core/src/vizro/models/types.py index 21b30d04f..f9b6f785d 100644 --- a/vizro-core/src/vizro/models/types.py +++ b/vizro-core/src/vizro/models/types.py @@ -319,3 +319,5 @@ class OptionsDictType(TypedDict): Union["Accordion", "NavBar"], Field(discriminator="type", description="Component that makes up part of the navigation panel"), ] +"""Discriminated union. Permissible value types for selector attribute: +[`Accordion`][vizro.models.Accordion], [`NavBar`][vizro.models.NavBar]."""