Skip to content

Commit

Permalink
Updating Meta Tags (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnnMarieW authored Dec 21, 2023
1 parent 9818e08 commit 4aa482e
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 1 deletion.
47 changes: 47 additions & 0 deletions vizro-core/changelog.d/20231221_052426_amward_update_meta_tags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!--
A new scriv changelog fragment.
Uncomment the section that is right (remove the HTML comment wrapper).
-->

<!--
### Highlights ✨
- A bullet item for the Highlights ✨ category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Removed
- A bullet item for the Removed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->

### Added

- Enable adding description and image to the meta tags. ([#185](https://github.com/mckinsey/vizro/pull/185))

<!--
### Changed
- A bullet item for the Changed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Deprecated
- A bullet item for the Deprecated category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Fixed
- A bullet item for the Fixed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Security
- A bullet item for the Security category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
9 changes: 9 additions & 0 deletions vizro-core/examples/assets/images/app.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions vizro-core/examples/assets/images/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions vizro-core/examples/default/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def create_variable_analysis():
"""Function returns a page with gapminder data to do variable analysis."""
page_variable = vm.Page(
title="Variable Analysis",
description="Analyzing population, GDP per capita and life expectancy on country and continent level",
layout=vm.Layout(
grid=[
# fmt: off
Expand Down Expand Up @@ -194,6 +195,7 @@ def create_relation_analysis():
"""Function returns a page to perform relation analysis."""
page_relation_analysis = vm.Page(
title="Relationship Analysis",
description="Investigating the interconnection between population, GDP per capita and life expectancy",
layout=vm.Layout(
grid=[[0, 0, 0, 0, 1]] + [[2, 2, 3, 3, 3]] * 4 + [[4, 4, 4, 4, 4]] * 5,
row_min_height="100px",
Expand Down Expand Up @@ -323,6 +325,7 @@ def create_continent_summary():
"""Function returns a page with markdown including images."""
page_summary = vm.Page(
title="Continent Summary",
description="Summarizing the main findings for each continent",
layout=vm.Layout(grid=[[i] for i in range(5)], row_min_height="190px", row_gap="25px"),
components=[
vm.Card(
Expand Down Expand Up @@ -415,6 +418,7 @@ def create_benchmark_analysis():

page_country = vm.Page(
title="Benchmark Analysis",
description="Discovering how the metrics differ for each country and export data for further investigation",
layout=vm.Layout(grid=[[0, 1]] * 5 + [[2, -1]], col_gap="32px", row_gap="60px"),
components=[
vm.Table(
Expand Down Expand Up @@ -496,6 +500,7 @@ def create_home_page():
"""Function returns the homepage."""
page_home = vm.Page(
title="Homepage",
description="Vizro demo app for studying gapminder data",
layout=vm.Layout(grid=[[0, 1], [2, 3]], row_gap="16px", col_gap="24px"),
components=[
vm.Card(
Expand Down
8 changes: 7 additions & 1 deletion vizro-core/schemas/0.1.8.dev0.json
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@
},
"Page": {
"title": "Page",
"description": "A page in [`Dashboard`][vizro.models.Dashboard] with its own URL path and place in the `Navigation`.\n\nArgs:\n components (List[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component\n has to be provided.\n title (str): Title to be displayed.\n layout (Layout): Layout to place components in. Defaults to `None`.\n controls (List[ControlType]): See [ControlType][vizro.models.types.ControlType]. Defaults to `[]`.\n path (str): Path to navigate to page. Defaults to `\"\"`.\n\nRaises:\n ValueError: If number of page and grid components is not the same",
"description": "A page in [`Dashboard`][vizro.models.Dashboard] with its own URL path and place in the `Navigation`.\n\nArgs:\n components (List[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component\n has to be provided.\n title (str): Title to be displayed.\n description (str): Description for meta tags.\n layout (Layout): Layout to place components in. Defaults to `None`.\n controls (List[ControlType]): See [ControlType][vizro.models.types.ControlType]. Defaults to `[]`.\n path (str): Path to navigate to page. Defaults to `\"\"`.\n\nRaises:\n ValueError: If number of page and grid components is not the same",
"type": "object",
"properties": {
"id": {
Expand Down Expand Up @@ -888,6 +888,12 @@
"description": "Title to be displayed.",
"type": "string"
},
"description": {
"title": "Description",
"description": "Description for meta tags.",
"default": "",
"type": "string"
},
"layout": {
"$ref": "#/definitions/Layout"
},
Expand Down
13 changes: 13 additions & 0 deletions vizro-core/src/vizro/models/_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import logging
from functools import partial
from pathlib import Path
from typing import TYPE_CHECKING, List, Literal, TypedDict

import dash
Expand Down Expand Up @@ -88,13 +89,17 @@ def set_navigation_pages(cls, navigation, values):

@_log_call
def pre_build(self):
meta_image = self._infer_image("app") or self._infer_image("logo")

# Setting order here ensures that the pages in dash.page_registry preserves the order of the List[Page].
# For now the homepage (path /) corresponds to self.pages[0].
# Note redirect_from=["/"] doesn't work and so the / route must be defined separately.
for order, page in enumerate(self.pages):
dash.register_page(
module=page.id,
name=page.title,
description=page.description,
image=meta_image,
title=f"{self.title}: {page.title}" if self.title else page.title,
path=page.path if order else "/",
order=order,
Expand Down Expand Up @@ -193,3 +198,11 @@ def _make_page_404_layout():
],
className="page_error_container",
)

def _infer_image(self, filename: str):
valid_extensions = [".apng", ".avif", ".gif", ".jpeg", ".jpg", ".png", ".svg", ".webp"]
assets_folder = Path(dash.get_app().config.assets_folder)
if assets_folder.is_dir():
for path in Path(assets_folder).rglob(f"{filename}.*"):
if path.suffix in valid_extensions:
return str(path.relative_to(assets_folder))
2 changes: 2 additions & 0 deletions vizro-core/src/vizro/models/_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Page(VizroBaseModel):
components (List[ComponentType]): See [ComponentType][vizro.models.types.ComponentType]. At least one component
has to be provided.
title (str): Title to be displayed.
description (str): Description for meta tags.
layout (Layout): Layout to place components in. Defaults to `None`.
controls (List[ControlType]): See [ControlType][vizro.models.types.ControlType]. Defaults to `[]`.
path (str): Path to navigate to page. Defaults to `""`.
Expand All @@ -42,6 +43,7 @@ class Page(VizroBaseModel):

components: List[ComponentType]
title: str = Field(..., description="Title to be displayed.")
description: str = Field("", description="Description for meta tags.")
layout: Layout = None # type: ignore[assignment]
controls: List[ControlType] = []
path: str = Field("", description="Path to navigate to page.")
Expand Down
65 changes: 65 additions & 0 deletions vizro-core/tests/unit/vizro/models/test_dashboard.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
from pathlib import Path

import dash
import dash_bootstrap_components as dbc
Expand All @@ -14,6 +15,7 @@

import vizro
import vizro.models as vm
from vizro import Vizro
from vizro.actions._action_loop._action_loop import ActionLoop
from vizro.models._dashboard import _all_hidden

Expand Down Expand Up @@ -77,6 +79,8 @@ def test_page_registry(self, vizro_app, page_1, page_2, mocker):
mock_register_page.assert_any_call(
module=page_1.id,
name="Page 1",
description="",
image=None,
title="Page 1",
path="/",
order=0,
Expand All @@ -85,6 +89,8 @@ def test_page_registry(self, vizro_app, page_1, page_2, mocker):
mock_register_page.assert_any_call(
module=page_2.id,
name="Page 2",
description="",
image=None,
title="Page 2",
path="/page-2",
order=1,
Expand All @@ -103,12 +109,71 @@ def test_page_registry_with_title(self, vizro_app, page_1, mocker):
mock_register_page.assert_any_call(
module=page_1.id,
name="Page 1",
description="",
image=None,
title="My dashboard: Page 1",
path="/",
order=0,
layout=mocker.ANY, # partial call is tricky to mock out so we ignore it.
)

def test_page_registry_with_description(self, vizro_app, mocker):
mock_register_page = mocker.patch("dash.register_page", autospec=True)
vm.Dashboard(
pages=[vm.Page(title="Page 1", components=[vm.Button()], description="My description")]
).pre_build()

mock_register_page.assert_any_call(
module="Page 1",
name="Page 1",
description="My description",
image=None,
title="Page 1",
path="/",
order=0,
layout=mocker.ANY, # partial call is tricky to mock out so we ignore it.
)

@pytest.mark.parametrize(
"image_path", ["app.png", "app.svg", "images/app.png", "images/app.svg", "logo.png", "logo.svg"]
)
def test_page_registry_with_image(self, page_1, mocker, tmp_path, image_path):
if Path(image_path).parent != Path("."):
Path(tmp_path / image_path).parent.mkdir()
Path(tmp_path / image_path).touch()
Vizro(assets_folder=tmp_path)
mock_register_page = mocker.patch("dash.register_page", autospec=True)
vm.Dashboard(pages=[page_1]).pre_build()

mock_register_page.assert_any_call(
module=page_1.id,
name="Page 1",
description="",
image=image_path,
title="Page 1",
path="/",
order=0,
layout=mocker.ANY, # partial call is tricky to mock out so we ignore it.
)

def test_page_registry_with_images(self, page_1, mocker, tmp_path):
Path(tmp_path / "app.svg").touch()
Path(tmp_path / "logo.svg").touch()
Vizro(assets_folder=tmp_path)
mock_register_page = mocker.patch("dash.register_page", autospec=True)
vm.Dashboard(pages=[page_1]).pre_build()

mock_register_page.assert_any_call(
module=page_1.id,
name="Page 1",
description="",
image="app.svg",
title="Page 1",
path="/",
order=0,
layout=mocker.ANY, # partial call is tricky to mock out so we ignore it.
)

def test_make_page_404_layout(self, vizro_app):
# vizro_app fixture is needed to avoid mocking out get_relative_path.
expected = html.Div(
Expand Down

0 comments on commit 4aa482e

Please sign in to comment.