merge upstream
All checks were successful
mnemo-build-and-publish / gractwo-mnemo-build (push) Successful in 42s

This commit is contained in:
2026-04-09 16:38:35 +00:00
2 changed files with 49 additions and 8 deletions

View File

@@ -33,10 +33,17 @@ impl LogEntry {
))?; ))?;
Ok(log) Ok(log)
} }
pub fn get_all(conn: &Connection) -> Result<Vec<LogEntry>, DatabaseError> { pub fn total_count(conn: &Connection) -> Result<i64, DatabaseError> {
Ok(conn.query_row("SELECT COUNT(*) FROM logs", (), |r| r.get(0))?)
}
pub fn get_chronological_offset(
conn: &Connection,
offset: i64,
limit: i64,
) -> Result<Vec<LogEntry>, DatabaseError> {
Ok(conn Ok(conn
.prepare("SELECT id, actor, target, actiontype, payload FROM logs ORDER BY id DESC")? .prepare("SELECT id, actor, target, actiontype, payload FROM logs ORDER BY id DESC LIMIT ?1 OFFSET ?2")?
.query_map((), |r| { .query_map((limit, offset), |r| {
let payload: String = r.get(4)?; let payload: String = r.get(4)?;
Ok(LogEntry { Ok(LogEntry {
id: r.get(0)?, id: r.get(0)?,

View File

@@ -1,8 +1,9 @@
use axum::{ use axum::{
extract::Request, extract::{Query, Request},
response::{IntoResponse, Redirect, Response}, response::{IntoResponse, Redirect, Response},
}; };
use maud::{PreEscaped, html}; use maud::{PreEscaped, html};
use serde::Deserialize;
use crate::{ use crate::{
database::{self}, database::{self},
@@ -12,14 +13,29 @@ use crate::{
web::{components::nav::nav, icons, pages::base}, web::{components::nav::nav, icons, pages::base},
}; };
pub async fn page(req: Request) -> Result<Response, CompositeError> { #[derive(Deserialize)]
pub struct PageQuery {
page: Option<i64>,
}
pub async fn page(
Query(query): Query<PageQuery>,
req: Request,
) -> Result<Response, CompositeError> {
let u = match User::authenticate(req.headers())? { let u = match User::authenticate(req.headers())? {
Some(u) => u, Some(u) => u,
None => return Ok(Redirect::to(&format!("/login?r={}", req.uri().path())).into_response()), None => return Ok(Redirect::to(&format!("/login?r={}", req.uri().path())).into_response()),
}; };
let mut conn = database::conn()?; let mut conn = database::conn()?;
let tx = conn.transaction()?; let tx = conn.transaction()?;
let logs = LogEntry::get_all(&tx)?;
let page = query.page.unwrap_or(1).max(1);
let per_page = 20;
let offset = (page - 1) * per_page;
let logs = LogEntry::get_chronological_offset(&tx, offset, per_page)?;
let total_logs = LogEntry::total_count(&tx)?;
let total_pages = (total_logs as f64 / per_page as f64).ceil() as i64;
Ok(base( Ok(base(
"Logs | Mnemosyne", "Logs | Mnemosyne",
@@ -59,8 +75,26 @@ pub async fn page(req: Request) -> Result<Response, CompositeError> {
div class="p-2 font-light" style=(s) {(log.actor.handle)} div class="p-2 font-light" style=(s) {(log.actor.handle)}
div class="p-2 font-light" style=(s) {(log.data.get_humanreadable_payload())} div class="p-2 font-light" style=(s) {(log.data.get_humanreadable_payload())}
} }
@if true { }
div class="p-2 col-span-3 text-center font-light text-neutral-400" {"You've reached the end of all logs."} div class="flex justify-between items-center my-4 text-neutral-400" {
@if page > 1 {
a href=(format!("/logs?page={}", (page - 1).max(1))) class="px-4 py-2 border border-neutral-200/25 hover:border-neutral-200/45 bg-neutral-200/5 hover:bg-neutral-200/15 rounded" {
"Previous"
}
} @else {
div {}
}
span {
"Page " (page) " of " (total_pages)
}
@if page < total_pages {
a href=(format!("/logs?page={}", page + 1)) class="px-4 py-2 border border-neutral-200/25 hover:border-neutral-200/45 bg-neutral-200/5 hover:bg-neutral-200/15 rounded" {
"Next"
}
} @else {
div {}
} }
} }
} }