@page now supports an explicit order

This commit is contained in:
Jakob Pinterits
2024-09-16 20:02:01 +02:00
parent 29f221116b
commit 9f15231065
3 changed files with 50 additions and 7 deletions

View File

@@ -141,9 +141,10 @@ class App:
name: str | None = None,
description: str | None = None,
icon: ImageLike | None = None,
pages: Iterable[rio.ComponentPage]
pages: Iterable[rio.ComponentPage | rio.Redirect]
| os.PathLike
| Literal["auto"] = "auto",
| str
| None = None,
on_app_start: rio.EventHandler[App] = None,
on_app_close: rio.EventHandler[App] = None,
on_session_start: rio.EventHandler[rio.Session] = None,
@@ -193,7 +194,7 @@ class App:
Per default, rio scans your project's "pages" directory for
components decorated with `@rio.page` and turns them into pages. To
override the location of this directory, you can pass in a file
override the location of this directory, you can provide a custom
path.
`on_app_start`: A function that will be called when the app is first
@@ -321,12 +322,12 @@ class App:
def _load_pages(self) -> None:
pages: Iterable[rio.ComponentPage | rio.Redirect]
if self._raw_pages == "auto":
if self._raw_pages is None:
pages = routing.auto_detect_pages(
self._module_path / "pages",
package=f"{self._module_path.stem}.pages",
)
elif isinstance(self._raw_pages, os.PathLike):
elif isinstance(self._raw_pages, (os.PathLike, str)):
pages = routing.auto_detect_pages(Path(self._raw_pages))
else:
pages = self._raw_pages # type: ignore (wtf?)

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import logging
import math
import typing as t
import warnings
from collections.abc import Callable, Iterable, Sequence
@@ -129,6 +130,10 @@ class ComponentPage:
guard: Callable[[rio.GuardEvent], None | rio.URL | str] | None = None
meta_tags: dict[str, str] = field(default_factory=dict)
# This is used to allow users to order pages when using the `rio.page`
# decorator. It's not public, but simply a convenient place to store this.
_page_order_: int | None = field(default=None, init=False)
if not t.TYPE_CHECKING:
page_url: str | None = None
@@ -330,8 +335,11 @@ def page(
icon: str = DEFAULT_ICON,
guard: (Callable[[GuardEvent], None | rio.URL | str] | None) = None,
meta_tags: dict[str, str] | None = None,
order: int | None = None,
):
""" """
"""
TODO
"""
def decorator(build: C) -> C:
nonlocal name, url_segment
@@ -358,10 +366,44 @@ def page(
return decorator
def _page_sort_key(page: rio.ComponentPage) -> tuple:
"""
Returns a key that can be used to sort pages.
"""
return (
# Any explicit ordering takes precedence
math.inf if page._page_order_ is None else page._page_order_,
# Put the home page first
not page.url_segment == "",
# Then sort by name
page.name,
)
def auto_detect_pages(
directory: Path,
*,
package: str | None = None,
) -> list[rio.ComponentPage]:
# Find all pages using the iterator method
pages = list(
_auto_detect_pages_iter(
directory,
package=package,
)
)
# Sort them
pages.sort(key=_page_sort_key)
# Done
return pages
def _auto_detect_pages_iter(
directory: Path,
*,
package: str | None = None,
) -> Iterable[rio.ComponentPage]:
try:
contents = list(directory.iterdir())

View File

@@ -22,7 +22,7 @@ def guard(event: rio.GuardEvent) -> str | None:
## Parameters
`event`: The event that triggered the guard containing the `session` and `active_pages`.
`event`: The event that triggered the guard containing the `session` and `active_pages`.
"""
# If the user is already logged in, there is no reason to show the login page.