Skip to content
Merged
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
2 changes: 0 additions & 2 deletions app/sep/apps/backup_mongo/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
The Jinja UI router is threaded explicitly.
"""

from app.core.pagination.deps import pagination_dep
from app.sep.apps.backup_mongo.api_routes import router as backup_mongo_custom_router
from app.sep.apps.backup_mongo.deps import (
build_backup_mongo_api_task_response,
Expand Down Expand Up @@ -65,7 +64,6 @@
response_model=BackupTaskResponse,
response_builder=build_backup_mongo_api_task_response,
get_task=get_backups_task,
pagination=pagination_dep,
list_filter=ListFilterConfig(
status=True,
roots_only=True,
Expand Down
2 changes: 0 additions & 2 deletions app/sep/apps/backup_pg/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
``jinja_router``; the registry does not.
"""

from app.core.pagination.deps import make_pagination_dep
from app.inventory.models import ServiceTypeEnum
from app.sep.apps.backup_pg.deps import (
build_backup_pg_api_detail_response,
Expand Down Expand Up @@ -77,7 +76,6 @@
task_spec_builder=build_backup_pg_spec,
capabilities=AppCapabilities(update=True, delete=True),
service_type=ServiceTypeEnum.POSTGRESQL,
pagination=make_pagination_dep(),
list_filter=ListFilterConfig(status=True),
response_builder=build_backup_pg_api_task_response,
detail_response_builder=build_backup_pg_api_detail_response,
Expand Down
39 changes: 33 additions & 6 deletions app/sep/apps/framework/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from fastapi.routing import APIRoute
from pydantic import BaseModel, Field, model_validator, PrivateAttr, SkipValidation

from app.core.pagination import PaginationDependency
from app.core.pagination import make_pagination_dep, PaginationDependency
from app.inventory.models import ServiceTypeEnum
from app.sep.apps.framework.api import (
capabilities_endpoint,
Expand Down Expand Up @@ -81,6 +81,7 @@
from app.tasks.models import Task, TaskHistoryStatusEnum, TaskWrite

__all__ = [
"NO_PAGINATION",
"UNGUARDED",
"AppCapabilities",
"Cascade",
Expand Down Expand Up @@ -113,6 +114,25 @@ def __repr__(self) -> str:
UNGUARDED = _Unguarded()


class _NoPagination:
"""Mark a derived list route as explicitly opting out of pagination.

A named singleton (mirroring :data:`UNGUARDED`) so an author's opt-out reads
as a greppable, importable :data:`NO_PAGINATION` rather than ``None`` — which
stays a purely internal route-shape switch in
:mod:`~app.sep.apps.framework.api`.
"""

__slots__ = ()

def __repr__(self) -> str:
"""Return the marker name so tracebacks and reprs read ``NO_PAGINATION``."""
return "NO_PAGINATION"


NO_PAGINATION = _NoPagination()


class AppCapabilities(BaseModel):
"""Toggle which verbs a ``TaskExecutionApp`` derives.

Expand Down Expand Up @@ -288,8 +308,12 @@ class TaskExecutionApp(BaseApp):
``task_name``).
:param capabilities: The verb toggles gating route derivation. Defaults to
all-default :class:`AppCapabilities`.
:param pagination: A ``make_pagination_dep(...)`` callable; when set the list
route paginates. Defaults to ``None``.
:param pagination: The derived list route's pagination knob. Defaults to
``make_pagination_dep()`` (page size 50, ceiling 200), so a list route
paginates unless overridden — a new app is bounded by default. Pass a
custom ``make_pagination_dep(max_limit=...)`` callable to change the
ceiling, or the :data:`NO_PAGINATION` sentinel to opt out and serve a plain
``list[model]``.
:param create_form_encoded: Whether the derived create route accepts a
form-urlencoded body (``Form()``) instead of the default JSON body
(``Body()``). A create-route option, so it is rejected unless
Expand Down Expand Up @@ -395,7 +419,7 @@ class TaskExecutionApp(BaseApp):
script_source: SkipValidation[ScriptSource | None] = None
get_task: Callable[..., Awaitable[Task]] | None = None
capabilities: AppCapabilities = AppCapabilities()
pagination: PaginationDependency | None = None
pagination: PaginationDependency | _NoPagination = make_pagination_dep()
create_form_encoded: bool = False
cascade: SkipValidation[Cascade | None] = None
extra_routes: tuple[APIRouter, ...] = ()
Expand Down Expand Up @@ -992,11 +1016,14 @@ def build_router(self) -> APIRouter:

:return: The composed plugin ``APIRouter``.
"""
pagination_dep = (
None if isinstance(self.pagination, _NoPagination) else self.pagination
)
if self.script_source is not None:
router = derive_script_routes(
self.script_source,
name=self.name,
pagination_dep=self.pagination,
pagination_dep=pagination_dep,
)
if self.capabilities_provider is not None:
capabilities_endpoint(router, self.capabilities_provider)
Expand All @@ -1023,7 +1050,7 @@ def build_router(self) -> APIRouter:
create_response_builder=self._build_create_response_builder(),
connectivity_check=self.connectivity_check,
detail_path_param=self.detail_path_param,
pagination_dep=self.pagination,
pagination_dep=pagination_dep,
list_status_filter=self.list_filter.status,
list_service_type=(
self.service_type if self.list_filter.service_type else None
Expand Down
1 change: 1 addition & 0 deletions changelog.d/SEP-1564.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TaskExecutionApp derived list routes now paginate by default (page size 50, max 200); apps opt out with the NO_PAGINATION sentinel. The archives, checksums, and snippets list routes change from a plain list to a PaginatedResponse envelope.
167 changes: 149 additions & 18 deletions frontend/packages/api/specs/sep.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading