Add pagination
This commit is contained in:
parent
b57e1f59a2
commit
6b52e455bc
6 changed files with 82 additions and 26 deletions
|
|
@ -7,7 +7,7 @@ from typing import Annotated
|
||||||
|
|
||||||
import humanize
|
import humanize
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from reader import EntryCounts, FeedCounts, Reader, make_reader
|
from reader import Reader, make_reader
|
||||||
|
|
||||||
from app.settings import DB_PATH
|
from app.settings import DB_PATH
|
||||||
|
|
||||||
|
|
@ -20,21 +20,22 @@ def get_reader() -> Reader:
|
||||||
|
|
||||||
def get_stats() -> str:
|
def get_stats() -> str:
|
||||||
"""Return the stats."""
|
"""Return the stats."""
|
||||||
db_size: int = DB_PATH.stat().st_size
|
# db_size: int = DB_PATH.stat().st_size
|
||||||
|
#
|
||||||
# Get the feed counts.
|
# # Get the feed counts.
|
||||||
feed_counts: FeedCounts = get_reader().get_feed_counts()
|
# feed_counts: FeedCounts = get_reader().get_feed_counts()
|
||||||
total_feed_counts: int | None = feed_counts.total
|
# total_feed_counts: int | None = feed_counts.total
|
||||||
if total_feed_counts is None:
|
# if total_feed_counts is None:
|
||||||
total_feed_counts = 0
|
# total_feed_counts = 0
|
||||||
|
#
|
||||||
# Get the entry counts.
|
# # Get the entry counts.
|
||||||
entry_counts: EntryCounts = get_reader().get_entry_counts()
|
# entry_counts: EntryCounts = get_reader().get_entry_counts()
|
||||||
total_entry_counts: int | None = entry_counts.total
|
# total_entry_counts: int | None = entry_counts.total
|
||||||
if total_entry_counts is None:
|
# if total_entry_counts is None:
|
||||||
total_entry_counts = 0
|
# total_entry_counts = 0
|
||||||
|
#
|
||||||
return f"{total_feed_counts} feeds ({total_entry_counts} entries) ~{humanize.naturalsize(db_size, binary=True)}"
|
# return f"{total_feed_counts} feeds ({total_entry_counts} entries) ~{humanize.naturalsize(db_size, binary=True)}"
|
||||||
|
return f"0 feeds (0 entries) ~{humanize.naturalsize(0, binary=True)}"
|
||||||
|
|
||||||
|
|
||||||
CommonReader = Annotated[Reader, Depends(get_reader)]
|
CommonReader = Annotated[Reader, Depends(get_reader)]
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
from fastapi.datastructures import Address
|
from fastapi.datastructures import Address
|
||||||
from reader import Feed
|
from reader import Feed
|
||||||
from reader.types import Entry, EntrySearchResult
|
|
||||||
|
|
||||||
|
|
||||||
logger: logging.Logger = logging.getLogger(__name__)
|
logger: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
@ -37,22 +36,44 @@ async def favicon(request: Request):
|
||||||
@static_router.get(path="/", summary="Index page.", tags=["HTML"])
|
@static_router.get(path="/", summary="Index page.", tags=["HTML"])
|
||||||
async def index(request: Request, reader: CommonReader, stats: CommonStats):
|
async def index(request: Request, reader: CommonReader, stats: CommonStats):
|
||||||
"""Index page."""
|
"""Index page."""
|
||||||
feeds: Iterable[Feed] = reader.get_feeds()
|
feeds: Iterable[Feed] = reader.get_feeds(limit=15)
|
||||||
return templates.TemplateResponse(request=request, name="index.html", context={"feeds": feeds, "stats": stats})
|
return templates.TemplateResponse(request=request, name="index.html", context={"feeds": feeds, "stats": stats})
|
||||||
|
|
||||||
|
|
||||||
@static_router.get(path="/feeds", summary="Feeds page.", tags=["HTML"])
|
@static_router.get(path="/feeds", summary="Feeds page.", tags=["HTML"])
|
||||||
async def feeds(request: Request, reader: CommonReader, stats: CommonStats):
|
async def feeds(
|
||||||
|
request: Request,
|
||||||
|
reader: CommonReader,
|
||||||
|
stats: CommonStats,
|
||||||
|
next_url: str | None = None,
|
||||||
|
prev_url: str | None = None,
|
||||||
|
):
|
||||||
"""Feeds page."""
|
"""Feeds page."""
|
||||||
feeds: Iterable[Feed] = reader.get_feeds()
|
if next_url:
|
||||||
return templates.TemplateResponse(request=request, name="feeds.html", context={"feeds": feeds, "stats": stats})
|
feeds = list(reader.get_feeds(starting_after=next_url, limit=15))
|
||||||
|
elif prev_url:
|
||||||
|
feeds = list(reader.get_feeds(starting_after=prev_url, limit=15))
|
||||||
|
else:
|
||||||
|
feeds = list(reader.get_feeds(limit=15))
|
||||||
|
|
||||||
|
# This is the last feed on the page.
|
||||||
|
next_url = feeds[-1].url if feeds else None
|
||||||
|
|
||||||
|
# This is the first feed on the page.
|
||||||
|
prev_url = feeds[0].url if feeds else None
|
||||||
|
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
request=request,
|
||||||
|
name="feeds.html",
|
||||||
|
context={"feeds": feeds, "stats": stats, "next_url": next_url, "prev_url": prev_url},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@static_router.get(path="/feed/{feed_url:path}", summary="Feed page.", tags=["HTML"])
|
@static_router.get(path="/feed/{feed_url:path}", summary="Feed page.", tags=["HTML"])
|
||||||
async def feed(request: Request, feed_url: str, reader: CommonReader, stats: CommonStats):
|
async def feed(request: Request, feed_url: str, reader: CommonReader, stats: CommonStats):
|
||||||
"""Feed page."""
|
"""Feed page."""
|
||||||
feed: Feed = reader.get_feed(feed_url)
|
feed: Feed = reader.get_feed(feed_url)
|
||||||
entries: Iterable[Entry] = reader.get_entries(feed=feed.url)
|
entries = list(reader.get_entries(feed=feed.url))
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="feed.html",
|
name="feed.html",
|
||||||
|
|
@ -61,15 +82,39 @@ async def feed(request: Request, feed_url: str, reader: CommonReader, stats: Com
|
||||||
|
|
||||||
|
|
||||||
@static_router.get(path="/search", summary="Search page.", tags=["HTML"])
|
@static_router.get(path="/search", summary="Search page.", tags=["HTML"])
|
||||||
async def search(request: Request, q: str, reader: CommonReader, stats: CommonStats):
|
async def search( # noqa: PLR0913, PLR0917
|
||||||
|
request: Request,
|
||||||
|
q: str,
|
||||||
|
reader: CommonReader,
|
||||||
|
stats: CommonStats,
|
||||||
|
next_feed: str | None = None,
|
||||||
|
next_entry: str | None = None,
|
||||||
|
prev_feed: str | None = None,
|
||||||
|
prev_entry: str | None = None,
|
||||||
|
):
|
||||||
"""Search page."""
|
"""Search page."""
|
||||||
|
if next_feed and next_entry:
|
||||||
|
entries = list(reader.search_entries(q, starting_after=(next_feed, next_entry), limit=15))
|
||||||
|
elif prev_feed and prev_entry:
|
||||||
|
entries = list(reader.search_entries(q, starting_after=(prev_feed, prev_entry), limit=15))
|
||||||
|
else:
|
||||||
|
entries = list(reader.search_entries(q, limit=15))
|
||||||
|
|
||||||
# TODO(TheLovinator): We need to show the entries in the search results. # noqa: TD003
|
# TODO(TheLovinator): We need to show the entries in the search results. # noqa: TD003
|
||||||
reader.update_search()
|
reader.update_search()
|
||||||
entries: Iterable[EntrySearchResult] = reader.search_entries(q)
|
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="search.html",
|
name="search.html",
|
||||||
context={"query": q, "entries": entries, "stats": stats},
|
context={
|
||||||
|
"query": q,
|
||||||
|
"entries": entries,
|
||||||
|
"stats": stats,
|
||||||
|
"next_feed": next_feed,
|
||||||
|
"next_entry": next_entry,
|
||||||
|
"prev_feed": prev_feed,
|
||||||
|
"prev_entry": prev_entry,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ lint.ignore = [
|
||||||
"D104", # Checks for undocumented public package definitions.
|
"D104", # Checks for undocumented public package definitions.
|
||||||
"FIX002", # Checks for "TODO" comments.
|
"FIX002", # Checks for "TODO" comments.
|
||||||
"RUF029", # Checks for functions declared async that do not await or otherwise use features requiring the function to be declared async.
|
"RUF029", # Checks for functions declared async that do not await or otherwise use features requiring the function to be declared async.
|
||||||
|
"ERA001", # Checks for commented-out Python code.
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff.lint.pydocstyle]
|
[tool.ruff.lint.pydocstyle]
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
<h2>{{ feed.url }}</h2>
|
<h2>{{ feed.url }}</h2>
|
||||||
<p>{{ feed.description }}</p>
|
<p>{{ feed.description }}</p>
|
||||||
<h3>Entries</h3>
|
<h3>Entries</h3>
|
||||||
|
{% if entries|length == 0 %}<p>No entries found.</p>{% endif %}
|
||||||
<ul>
|
<ul>
|
||||||
{% for entry in entries %}
|
{% for entry in entries %}
|
||||||
<li>
|
<li>
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,6 @@
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
{% if next_url %}<a href='{{ url_for("feeds") }}?next_url={{ next_url }}'>Next</a>{% endif %}
|
||||||
|
{% if previous_url %}<a href='{{ url_for("feeds") }}?previous_url={{ previous_url }}'>Previous</a>{% endif %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,10 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>No entries found.</p>
|
<p>No entries found.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if next_feed and next_entry %}
|
||||||
|
<a href='{{ url_for("search") }}?query={{ query }}&next_feed={{ next_feed }}&next_entry={{ next_entry }}'>Next</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if prev_feed and prev_entry %}
|
||||||
|
<a href='{{ url_for("search") }}?query={{ query }}&prev_feed={{ prev_feed }}&prev_entry={{ prev_entry }}'>Previous</a>
|
||||||
|
{% endif %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue