Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/6923.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow State Vars for page titles and descriptions in `@rx.page` and compiled metadata.
8 changes: 6 additions & 2 deletions reflex/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1020,8 +1020,12 @@ def _prepare_page(
from reflex_components_core.el.elements import span

component = span("404: Page not found")
title = title or constants.Page404.TITLE
description = description or constants.Page404.DESCRIPTION
title = title if title is not None else constants.Page404.TITLE
description = (
description
if description is not None
else constants.Page404.DESCRIPTION
)
image = image or constants.Page404.IMAGE
else:
if component is None:
Expand Down
6 changes: 3 additions & 3 deletions reflex/compiler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,10 +784,10 @@ def get_memo_module_path(segments: tuple[str, ...]) -> str:

def add_meta(
page: Component,
title: str,
title: str | Var,
image: str,
meta: Sequence[Mapping[str, Any] | Component],
description: str | None = None,
description: str | Var | None = None,
) -> Component:
"""Add metadata to a page.

Expand All @@ -806,7 +806,7 @@ def add_meta(
]

children: list[Any] = [Title.create(title)]
if description:
if description is not None:
children.append(Description.create(content=description))
children.append(Image.create(content=image))

Expand Down
13 changes: 7 additions & 6 deletions reflex/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
from typing import Any

from reflex_base.event import EventType
from reflex_base.vars import Var


def page(
route: str | None = None,
title: str | None = None,
title: str | Var | None = None,
image: str | None = None,
description: str | None = None,
description: str | Var | None = None,
meta: list[Any] | None = None,
script_tags: list[Any] | None = None,
on_load: EventType[()] | None = None,
Expand Down Expand Up @@ -49,11 +50,11 @@ def decorator(render_fn: Callable):
kwargs: dict[str, Any] = {}
if route:
kwargs["route"] = route
if title:
if title is not None:
kwargs["title"] = title
if image:
kwargs["image"] = image
if description:
if description is not None:
kwargs["description"] = description
if meta:
kwargs["meta"] = meta
Expand All @@ -75,9 +76,9 @@ class PageNamespace:
def __new__(
cls,
route: str | None = None,
title: str | None = None,
title: str | Var | None = None,
image: str | None = None,
description: str | None = None,
description: str | Var | None = None,
meta: list[Any] | None = None,
script_tags: list[Any] | None = None,
on_load: EventType[()] | None = None,
Expand Down
21 changes: 20 additions & 1 deletion tests/units/compiler/test_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from reflex_base.utils.imports import ImportVar, ParsedImportDict
from reflex_base.vars.base import Var
from reflex_base.vars.sequence import LiteralStringVar
from reflex_components_core.base import document
from reflex_components_core.base import Description, document
from reflex_components_core.base.document import Links, Scripts
from reflex_components_core.el.elements.metadata import Head, Link, Meta
from reflex_components_core.el.elements.other import Html
Expand Down Expand Up @@ -617,6 +617,25 @@ def test_create_document_root():
assert isinstance(root.children[0].children[5], Links)


def test_add_meta_accepts_dynamic_description():
"""Dynamic page descriptions should be represented as component Vars."""

class PageState(rx.State):
description: str = "Dynamic description"

page = rx.box()
utils.add_meta(
page,
title="title",
image="",
meta=(),
description=PageState.description,
)

assert isinstance(page.children[1], Description)
assert page.children[1].content is PageState.description


def test_create_document_root_with_scripts():
# Test with components.
comps = [
Expand Down
18 changes: 18 additions & 0 deletions tests/units/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,24 @@ def test_add_page_default_route(
assert app._pages.keys() == {"index", "about"}


def test_prepare_404_page_preserves_dynamic_metadata():
"""404 fallback defaults should not evaluate explicitly supplied Vars."""

class PageState(rx.State):
title: str = "Dynamic title"
description: str = "Dynamic description"

app = App()
prepared = app._prepare_page(
route=constants.Page404.SLUG,
title=PageState.title,
description=PageState.description,
)

assert prepared.page.title is PageState.title
assert prepared.page.description is PageState.description


def test_add_page_set_route(app: App, index_page: ComponentCallable):
"""Test adding a page to an app.

Expand Down
23 changes: 22 additions & 1 deletion tests/units/test_page.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from reflex_base.registry import RegistrationContext

from reflex import text
from reflex import State, text
from reflex.page import page


Expand All @@ -22,6 +22,27 @@ def foo_():
assert page_data == {}


def test_page_decorator_accepts_state_metadata(
clean_registration_context: RegistrationContext,
):
"""State Vars should be preserved as page metadata without bool evaluation."""

class PageState(State):
title: str = "Dynamic title"
description: str = "Dynamic description"

def foo_():
return text("foo")

assert clean_registration_context.decorated_pages == []
page(title=PageState.title, description=PageState.description)(foo_)

assert len(clean_registration_context.decorated_pages) == 1
_, page_data = clean_registration_context.decorated_pages[0]
assert page_data["title"] is PageState.title
assert page_data["description"] is PageState.description


def test_page_decorator_with_kwargs(
clean_registration_context: RegistrationContext,
):
Expand Down
Loading