logs page filtering UI
This commit is contained in:
29
src/logs.rs
29
src/logs.rs
@@ -1,6 +1,6 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{PgConnection, Row};
|
use sqlx::{PgConnection, Row};
|
||||||
use strum::{EnumDiscriminants, IntoStaticStr, VariantNames};
|
use strum::{EnumDiscriminants, EnumIter, IntoStaticStr, VariantNames};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{database::DatabaseError, users::User, web::icons};
|
use crate::{database::DatabaseError, users::User, web::icons};
|
||||||
@@ -38,10 +38,25 @@ impl LogEntry {
|
|||||||
Ok(log)
|
Ok(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn total_count(conn: &mut PgConnection) -> Result<i64, DatabaseError> {
|
pub async fn count(
|
||||||
Ok(sqlx::query_scalar("SELECT COUNT(*) FROM logs")
|
conn: &mut PgConnection,
|
||||||
.fetch_one(&mut *conn)
|
action_type: Option<LogActionDiscriminant>,
|
||||||
.await?)
|
) -> Result<i64, DatabaseError> {
|
||||||
|
let count = match action_type {
|
||||||
|
Some(at) => {
|
||||||
|
let atstr: &'static str = at.into();
|
||||||
|
sqlx::query_scalar("SELECT COUNT(*) FROM logs WHERE actiontype = $1")
|
||||||
|
.bind(atstr)
|
||||||
|
.fetch_one(&mut *conn)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
sqlx::query_scalar("SELECT COUNT(*) FROM logs")
|
||||||
|
.fetch_one(&mut *conn)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_chronological_offset(
|
pub async fn get_chronological_offset(
|
||||||
@@ -81,7 +96,7 @@ impl LogEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, IntoStaticStr, Serialize, Deserialize, VariantNames, EnumDiscriminants)]
|
#[derive(Debug, IntoStaticStr, Serialize, Deserialize, VariantNames, EnumDiscriminants)]
|
||||||
#[strum_discriminants(derive(IntoStaticStr, Serialize, Deserialize))]
|
#[strum_discriminants(derive(EnumIter, IntoStaticStr, Serialize, Deserialize))]
|
||||||
#[strum_discriminants(name(LogActionDiscriminant))]
|
#[strum_discriminants(name(LogActionDiscriminant))]
|
||||||
pub enum LogAction {
|
pub enum LogAction {
|
||||||
Initialize,
|
Initialize,
|
||||||
@@ -209,7 +224,7 @@ impl LogActionDiscriminant {
|
|||||||
LAD::Initialize => "Mnemosyne Initialization",
|
LAD::Initialize => "Mnemosyne Initialization",
|
||||||
LAD::RegenInfradmin => "Infradmin Regeneration",
|
LAD::RegenInfradmin => "Infradmin Regeneration",
|
||||||
LAD::CreateUser => "User Creation",
|
LAD::CreateUser => "User Creation",
|
||||||
LAD::ManuallyChangeUsersPassword => "Another User's Password Change",
|
LAD::ManuallyChangeUsersPassword => "Password Override",
|
||||||
LAD::CreateTag => "Tag Creation",
|
LAD::CreateTag => "Tag Creation",
|
||||||
LAD::RenameTag => "Tag Rename",
|
LAD::RenameTag => "Tag Rename",
|
||||||
LAD::DeleteTag => "Tag Deletion",
|
LAD::DeleteTag => "Tag Deletion",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use axum::{
|
|||||||
};
|
};
|
||||||
use maud::{PreEscaped, html};
|
use maud::{PreEscaped, html};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
MnemoState,
|
MnemoState,
|
||||||
@@ -35,7 +36,7 @@ pub async fn page(
|
|||||||
let offset = (page - 1) * per_page;
|
let offset = (page - 1) * per_page;
|
||||||
|
|
||||||
let logs = LogEntry::get_chronological_offset(&mut *tx, query.action, offset, per_page).await?;
|
let logs = LogEntry::get_chronological_offset(&mut *tx, query.action, offset, per_page).await?;
|
||||||
let total_logs = LogEntry::total_count(&mut *tx).await?;
|
let total_logs = LogEntry::count(&mut *tx, query.action).await?;
|
||||||
let total_pages = (total_logs as f64 / per_page as f64).ceil() as i64;
|
let total_pages = (total_logs as f64 / per_page as f64).ceil() as i64;
|
||||||
|
|
||||||
Ok(base(
|
Ok(base(
|
||||||
@@ -52,7 +53,22 @@ pub async fn page(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// abcdefghijklmnopqrstuvwxyz
|
// abcdefghijklmnopqrstuvwxyz
|
||||||
div class="w-full border border-neutral-200/25 rounded grid grid-cols-[auto_auto_1fr]" {
|
div class="mb-4 flex flex-wrap gap-2 items-center justify-between" {
|
||||||
|
div class="text-sm text-neutral-400" {
|
||||||
|
"Showing " (total_logs) " logs"
|
||||||
|
}
|
||||||
|
select
|
||||||
|
class="bg-neutral-900 border border-neutral-200/25 rounded px-2 py-1 text-sm text-neutral-200"
|
||||||
|
onchange="window.location.search = this.value ? '?action=' + this.value : ''"
|
||||||
|
{
|
||||||
|
option value="" { "All Actions" }
|
||||||
|
@for action in LogActionDiscriminant::iter() {
|
||||||
|
@let act_str: &'static str = action.into();
|
||||||
|
option value=(act_str) selected[query.action == Some(action)] { (action.human_readable()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div class="w-full overflow-x-auto border border-neutral-200/25 rounded grid grid-cols-[auto_auto_1fr]" {
|
||||||
@for (txt, ico) in [("Timestamp", icons::CLOCK), ("Actor", icons::USER), ("Action", icons::PEN)] {
|
@for (txt, ico) in [("Timestamp", icons::CLOCK), ("Actor", icons::USER), ("Action", icons::PEN)] {
|
||||||
div class="p-2 flex gap-1 font-semibold border-b border-neutral-200/25" {
|
div class="p-2 flex gap-1 font-semibold border-b border-neutral-200/25" {
|
||||||
span class="text-neutral-500 scale-[.8]" {(PreEscaped(ico))}
|
span class="text-neutral-500 scale-[.8]" {(PreEscaped(ico))}
|
||||||
@@ -75,9 +91,10 @@ pub async fn page(
|
|||||||
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())}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div class="flex justify-between items-center my-4 text-neutral-400" {
|
@let action_q = query.action.map(|a| { let s: &'static str = a.into(); format!("&action={s}") }).unwrap_or_default();
|
||||||
|
div class="flex flex-wrap gap-2 justify-between items-center my-4 text-neutral-400" {
|
||||||
@if page > 1 {
|
@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" {
|
a href=(format!("/logs?page={}{}", (page - 1).max(1), action_q)) 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"
|
"Previous"
|
||||||
}
|
}
|
||||||
} @else {
|
} @else {
|
||||||
@@ -89,7 +106,7 @@ pub async fn page(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@if page < 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" {
|
a href=(format!("/logs?page={}{}", page + 1, action_q)) 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"
|
"Next"
|
||||||
}
|
}
|
||||||
} @else {
|
} @else {
|
||||||
|
|||||||
Reference in New Issue
Block a user