Add pagination

This commit is contained in:
Joakim Hellsén 2024-05-23 04:25:04 +02:00
commit 6b52e455bc
No known key found for this signature in database
GPG key ID: D196AE66FEBE1DC9
6 changed files with 82 additions and 26 deletions

View file

@ -7,7 +7,7 @@ from typing import Annotated
import humanize
from fastapi import Depends
from reader import EntryCounts, FeedCounts, Reader, make_reader
from reader import Reader, make_reader
from app.settings import DB_PATH
@ -20,21 +20,22 @@ def get_reader() -> Reader:
def get_stats() -> str:
"""Return the stats."""
db_size: int = DB_PATH.stat().st_size
# Get the feed counts.
feed_counts: FeedCounts = get_reader().get_feed_counts()
total_feed_counts: int | None = feed_counts.total
if total_feed_counts is None:
total_feed_counts = 0
# Get the entry counts.
entry_counts: EntryCounts = get_reader().get_entry_counts()
total_entry_counts: int | None = entry_counts.total
if total_entry_counts is None:
total_entry_counts = 0
return f"{total_feed_counts} feeds ({total_entry_counts} entries) ~{humanize.naturalsize(db_size, binary=True)}"
# db_size: int = DB_PATH.stat().st_size
#
# # Get the feed counts.
# feed_counts: FeedCounts = get_reader().get_feed_counts()
# total_feed_counts: int | None = feed_counts.total
# if total_feed_counts is None:
# total_feed_counts = 0
#
# # Get the entry counts.
# entry_counts: EntryCounts = get_reader().get_entry_counts()
# total_entry_counts: int | None = entry_counts.total
# if total_entry_counts is None:
# total_entry_counts = 0
#
# 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)]

View file

@ -19,7 +19,6 @@ if TYPE_CHECKING:
from fastapi.datastructures import Address
from reader import Feed
from reader.types import Entry, EntrySearchResult
logger: logging.Logger = logging.getLogger(__name__)
@ -37,22 +36,44 @@ async def favicon(request: Request):
@static_router.get(path="/", summary="Index page.", tags=["HTML"])
async def index(request: Request, reader: CommonReader, stats: CommonStats):
"""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})
@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: Iterable[Feed] = reader.get_feeds()
return templates.TemplateResponse(request=request, name="feeds.html", context={"feeds": feeds, "stats": stats})
if next_url:
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"])
async def feed(request: Request, feed_url: str, reader: CommonReader, stats: CommonStats):
"""Feed page."""
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(
request=request,
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"])
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."""
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
reader.update_search()
entries: Iterable[EntrySearchResult] = reader.search_entries(q)
return templates.TemplateResponse(
request=request,
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,
},
)

View file

@ -15,7 +15,7 @@ python-dotenv = "^1.0.1"
python-multipart = "^0.0.9"
reader = "^3.12"
orjson = "^3.10.3"
typer = {extras = ["all"], version = "^0.12.3"}
typer = { extras = ["all"], version = "^0.12.3" }
[tool.poetry.group.dev.dependencies]
ruff = "^0.4.4"
@ -42,6 +42,7 @@ lint.ignore = [
"D104", # Checks for undocumented public package definitions.
"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.
"ERA001", # Checks for commented-out Python code.
]
[tool.ruff.lint.pydocstyle]

View file

@ -3,6 +3,7 @@
<h2>{{ feed.url }}</h2>
<p>{{ feed.description }}</p>
<h3>Entries</h3>
{% if entries|length == 0 %}<p>No entries found.</p>{% endif %}
<ul>
{% for entry in entries %}
<li>

View file

@ -9,4 +9,6 @@
</li>
{% endfor %}
</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 %}

View file

@ -12,4 +12,10 @@
{% else %}
<p>No entries found.</p>
{% 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 %}