initial commit
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I4a6b498153eccd5407510dd541b7f4816a6a6964
This commit is contained in:
commit
6a73d11c4b
124 changed files with 34856 additions and 0 deletions
183
crates/pinakes-ui/src/components/statistics.rs
Normal file
183
crates/pinakes-ui/src/components/statistics.rs
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
use dioxus::prelude::*;
|
||||
|
||||
use super::utils::format_size;
|
||||
use crate::client::LibraryStatisticsResponse;
|
||||
|
||||
#[component]
|
||||
pub fn Statistics(
|
||||
stats: Option<LibraryStatisticsResponse>,
|
||||
#[props(default)] error: Option<String>,
|
||||
on_refresh: EventHandler<()>,
|
||||
) -> Element {
|
||||
rsx! {
|
||||
div { class: "card mb-16",
|
||||
div { class: "card-header",
|
||||
h3 { class: "card-title", "Library Statistics" }
|
||||
button {
|
||||
class: "btn btn-sm btn-secondary",
|
||||
onclick: move |_| on_refresh.call(()),
|
||||
"\u{21bb} Refresh"
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref err) = error {
|
||||
div { class: "alert alert-error mb-8",
|
||||
span { "{err}" }
|
||||
button {
|
||||
class: "btn btn-sm btn-secondary ml-8",
|
||||
onclick: move |_| on_refresh.call(()),
|
||||
"Retry"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match stats.as_ref() {
|
||||
Some(s) => {
|
||||
let total_size = format_size(s.total_size_bytes);
|
||||
let avg_size = format_size(s.avg_file_size_bytes);
|
||||
rsx! {
|
||||
// Overview
|
||||
div { class: "stats-grid",
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "{s.total_media}" }
|
||||
div { class: "stat-label", "Total Media" }
|
||||
}
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "{total_size}" }
|
||||
div { class: "stat-label", "Total Size" }
|
||||
}
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "{avg_size}" }
|
||||
div { class: "stat-label", "Avg File Size" }
|
||||
}
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "{s.total_tags}" }
|
||||
div { class: "stat-label", "Tags" }
|
||||
}
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "{s.total_collections}" }
|
||||
div { class: "stat-label", "Collections" }
|
||||
}
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "{s.total_duplicates}" }
|
||||
div { class: "stat-label", "Duplicate Hashes" }
|
||||
}
|
||||
}
|
||||
|
||||
// Media by Type
|
||||
if !s.media_by_type.is_empty() {
|
||||
div { class: "card mt-16",
|
||||
h4 { class: "card-title", "Media by Type" }
|
||||
table { class: "table",
|
||||
thead {
|
||||
tr {
|
||||
th { "Type" }
|
||||
th { "Count" }
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
for item in s.media_by_type.iter() {
|
||||
tr {
|
||||
td { "{item.name}" }
|
||||
td { "{item.count}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Storage by Type
|
||||
if !s.storage_by_type.is_empty() {
|
||||
div { class: "card mt-16",
|
||||
h4 { class: "card-title", "Storage by Type" }
|
||||
table { class: "table",
|
||||
thead {
|
||||
tr {
|
||||
th { "Type" }
|
||||
th { "Size" }
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
for item in s.storage_by_type.iter() {
|
||||
tr {
|
||||
td { "{item.name}" }
|
||||
td { "{format_size(item.count)}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Top Tags
|
||||
if !s.top_tags.is_empty() {
|
||||
div { class: "card mt-16",
|
||||
h4 { class: "card-title", "Top Tags" }
|
||||
table { class: "table",
|
||||
thead {
|
||||
tr {
|
||||
th { "Tag" }
|
||||
th { "Count" }
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
for item in s.top_tags.iter() {
|
||||
tr {
|
||||
td { "{item.name}" }
|
||||
td { "{item.count}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Top Collections
|
||||
if !s.top_collections.is_empty() {
|
||||
div { class: "card mt-16",
|
||||
h4 { class: "card-title", "Top Collections" }
|
||||
table { class: "table",
|
||||
thead {
|
||||
tr {
|
||||
th { "Collection" }
|
||||
th { "Members" }
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
for item in s.top_collections.iter() {
|
||||
tr {
|
||||
td { "{item.name}" }
|
||||
td { "{item.count}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Date Range
|
||||
div { class: "card mt-16",
|
||||
h4 { class: "card-title", "Date Range" }
|
||||
div { class: "stats-grid",
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "{s.oldest_item.as_deref().unwrap_or(\"N/A\")}" }
|
||||
div { class: "stat-label", "Oldest Item" }
|
||||
}
|
||||
div { class: "stat-card",
|
||||
div { class: "stat-value", "{s.newest_item.as_deref().unwrap_or(\"N/A\")}" }
|
||||
div { class: "stat-label", "Newest Item" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
None => rsx! {
|
||||
div { class: "empty-state",
|
||||
p { "Loading statistics..." }
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue