Server: paginate servers on admin page
This commit is contained in:
parent
7fc61d0e26
commit
5940264ffd
|
@ -38,6 +38,7 @@ rsa-pem = "0.2.0"
|
|||
rust-embed = "5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_urlencoded = "0.7"
|
||||
sha2 = "0.9"
|
||||
sled = { version = "0.34.6", features = ["compression"] }
|
||||
structopt = "0.3"
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
|||
error::{Error, OptionExt},
|
||||
extensions::{CommentExt, ProfileExt, SubmissionExt},
|
||||
nav::NavState,
|
||||
pagination::{PageNum, SearchPage},
|
||||
views::{OwnedProfileView, OwnedSubmissionView},
|
||||
ActixLoader, State,
|
||||
};
|
||||
|
@ -20,6 +21,11 @@ use uuid::Uuid;
|
|||
|
||||
pub use hyaenidae_profiles::store::Report;
|
||||
|
||||
mod pagination;
|
||||
use pagination::{
|
||||
BlockedPager, FederatedPager, InboundPager, KnownPager, OutboundPager, ServerPager,
|
||||
};
|
||||
|
||||
pub(super) fn scope() -> Scope {
|
||||
web::scope("/admin")
|
||||
.service(web::resource("").route(web::get().to(admin_page)))
|
||||
|
@ -87,6 +93,7 @@ async fn discover_server(
|
|||
loader: ActixLoader,
|
||||
_: Admin,
|
||||
form: web::Form<DiscoverForm>,
|
||||
query: web::Query<HashMap<String, String>>,
|
||||
nav_state: NavState,
|
||||
client: web::Data<Client>,
|
||||
state: web::Data<State>,
|
||||
|
@ -117,7 +124,7 @@ async fn discover_server(
|
|||
};
|
||||
|
||||
if let Err(e) = (fallible)().await {
|
||||
let mut federation_view = FederationView::build(&state2).await?;
|
||||
let mut federation_view = FederationView::build(query.into_inner(), &state2).await?;
|
||||
federation_view
|
||||
.discover_error(e.to_string())
|
||||
.discover_value(url2);
|
||||
|
@ -384,13 +391,14 @@ async fn defederate(
|
|||
|
||||
pub struct FederationView {
|
||||
servers: HashMap<Uuid, Server>,
|
||||
blocked: Vec<Uuid>,
|
||||
federated: Vec<Uuid>,
|
||||
inbound_requests: Vec<Uuid>,
|
||||
outbound_requests: Vec<Uuid>,
|
||||
known: Vec<Uuid>,
|
||||
blocked: SearchPage,
|
||||
federated: SearchPage,
|
||||
inbound_requests: SearchPage,
|
||||
outbound_requests: SearchPage,
|
||||
known: SearchPage,
|
||||
discover_value: Option<String>,
|
||||
discover_error: Option<String>,
|
||||
query: HashMap<String, String>,
|
||||
}
|
||||
|
||||
pub(crate) struct BlockView<'a> {
|
||||
|
@ -514,13 +522,6 @@ impl FederationView {
|
|||
self
|
||||
}
|
||||
|
||||
pub(crate) fn blocked<'a>(&'a self) -> impl Iterator<Item = BlockView<'a>> + 'a {
|
||||
self.blocked
|
||||
.iter()
|
||||
.filter_map(move |id| self.servers.get(id))
|
||||
.map(|server| BlockView { server })
|
||||
}
|
||||
|
||||
pub(crate) fn discover_input(&self, loader: &ActixLoader) -> TextInput {
|
||||
let input = TextInput::new("url")
|
||||
.title(&fl!(loader, "admin-discover-input"))
|
||||
|
@ -538,107 +539,326 @@ impl FederationView {
|
|||
"/admin/discover"
|
||||
}
|
||||
|
||||
pub(crate) fn blocked<'a>(&'a self) -> impl Iterator<Item = BlockView<'a>> + 'a {
|
||||
self.blocked
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(move |id| self.servers.get(id))
|
||||
.map(|server| BlockView { server })
|
||||
}
|
||||
|
||||
pub(crate) fn has_blocked_nav(&self) -> bool {
|
||||
self.blocked.next.is_some() || self.blocked.prev.is_some()
|
||||
}
|
||||
|
||||
fn blocked_next(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(next) = self.blocked.next {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("blocked_page".to_owned(), next.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-next-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn blocked_previous(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(prev) = self.blocked.prev {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("blocked_page".to_owned(), prev.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-previous-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn blocked_buttons(&self, loader: &ActixLoader) -> Vec<Button> {
|
||||
self.blocked_previous(loader)
|
||||
.into_iter()
|
||||
.chain(self.blocked_next(loader))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn known<'a>(&'a self) -> impl Iterator<Item = KnownView<'a>> + 'a {
|
||||
self.known
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(move |id| self.servers.get(id))
|
||||
.map(|server| KnownView { server })
|
||||
}
|
||||
|
||||
pub(crate) fn has_known_nav(&self) -> bool {
|
||||
self.known.next.is_some() || self.known.prev.is_some()
|
||||
}
|
||||
|
||||
fn known_next(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(next) = self.known.next {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("known_page".to_owned(), next.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-next-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn known_previous(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(prev) = self.known.prev {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("known_page".to_owned(), prev.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-previous-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn known_buttons(&self, loader: &ActixLoader) -> Vec<Button> {
|
||||
self.known_previous(loader)
|
||||
.into_iter()
|
||||
.chain(self.known_next(loader))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn federated<'a>(&'a self) -> impl Iterator<Item = FederatedView<'a>> + 'a {
|
||||
self.federated
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(move |id| self.servers.get(id))
|
||||
.map(|server| FederatedView { server })
|
||||
}
|
||||
|
||||
pub(crate) fn has_federated_nav(&self) -> bool {
|
||||
self.federated.next.is_some() || self.federated.prev.is_some()
|
||||
}
|
||||
|
||||
fn federated_next(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(next) = self.federated.next {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("federated_page".to_owned(), next.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-next-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn federated_previous(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(prev) = self.federated.prev {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("federated_page".to_owned(), prev.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-previous-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn federated_buttons(&self, loader: &ActixLoader) -> Vec<Button> {
|
||||
self.federated_previous(loader)
|
||||
.into_iter()
|
||||
.chain(self.federated_next(loader))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn inbound<'a>(&'a self) -> impl Iterator<Item = InboundRequestView<'a>> + 'a {
|
||||
self.inbound_requests
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(move |id| self.servers.get(id))
|
||||
.map(|server| InboundRequestView { server })
|
||||
}
|
||||
|
||||
pub(crate) fn has_inbound_nav(&self) -> bool {
|
||||
self.inbound_requests.next.is_some() || self.inbound_requests.prev.is_some()
|
||||
}
|
||||
|
||||
fn inbound_next(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(next) = self.inbound_requests.next {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("inbound_page".to_owned(), next.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-next-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn inbound_previous(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(prev) = self.inbound_requests.prev {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("inbound_page".to_owned(), prev.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-previous-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn inbound_buttons(&self, loader: &ActixLoader) -> Vec<Button> {
|
||||
self.inbound_previous(loader)
|
||||
.into_iter()
|
||||
.chain(self.inbound_next(loader))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn outbound<'a>(&'a self) -> impl Iterator<Item = OutboundRequestView<'a>> + 'a {
|
||||
self.outbound_requests
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(move |id| self.servers.get(id))
|
||||
.map(|server| OutboundRequestView { server })
|
||||
}
|
||||
|
||||
async fn build(state: &State) -> Result<Self, Error> {
|
||||
let server_store = state.profiles.store.servers.clone();
|
||||
let server_blocks = state.profiles.store.view.server_blocks.clone();
|
||||
let server_requests = state.profiles.store.view.server_follow_requests.clone();
|
||||
let server_follows = state.profiles.store.view.server_follows.clone();
|
||||
pub(crate) fn has_outbound_nav(&self) -> bool {
|
||||
self.outbound_requests.next.is_some() || self.outbound_requests.prev.is_some()
|
||||
}
|
||||
|
||||
fn outbound_next(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(next) = self.outbound_requests.next {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("outbound_page".to_owned(), next.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-next-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn outbound_previous(&self, loader: &ActixLoader) -> Option<Button> {
|
||||
if let Some(prev) = self.outbound_requests.prev {
|
||||
let mut query = self.query.clone();
|
||||
query.insert("outbound_page".to_owned(), prev.to_string());
|
||||
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||
format!("/admin?{}", query)
|
||||
} else {
|
||||
"/admin".to_owned()
|
||||
};
|
||||
|
||||
Some(Button::secondary(&fl!(loader, "server-previous-page")).href(&href))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn outbound_buttons(&self, loader: &ActixLoader) -> Vec<Button> {
|
||||
self.outbound_previous(loader)
|
||||
.into_iter()
|
||||
.chain(self.outbound_next(loader))
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn build(query: HashMap<String, String>, state: &State) -> Result<Self, Error> {
|
||||
let profiles = state.profiles.clone();
|
||||
|
||||
let view = web::block(move || {
|
||||
let mut servers = HashMap::new();
|
||||
|
||||
let self_id = server_store.get_self()?.req()?;
|
||||
let self_id = profiles.store.servers.get_self()?.req()?;
|
||||
|
||||
let self_server = server_store.by_id(self_id)?.req()?;
|
||||
let self_server = profiles.store.servers.by_id(self_id)?.req()?;
|
||||
servers.insert(self_server.id(), self_server);
|
||||
|
||||
let federated = server_follows
|
||||
.forward_iter(self_id)
|
||||
.chain(server_follows.backward_iter(self_id))
|
||||
.filter_map(|server_id| {
|
||||
if !servers.contains_key(&server_id) {
|
||||
let server = server_store.by_id(server_id).ok()??;
|
||||
servers.insert(server.id(), server);
|
||||
Some(server_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let federated = SearchPage::from_pagination(
|
||||
FederatedPager(ServerPager {
|
||||
self_id,
|
||||
store: &profiles.store,
|
||||
servers: &mut servers,
|
||||
}),
|
||||
10,
|
||||
"".to_owned(),
|
||||
page_num(&query, "federated_page"),
|
||||
);
|
||||
|
||||
let inbound_requests = server_requests
|
||||
.forward_iter(self_id)
|
||||
.filter_map(|server_id| {
|
||||
if !servers.contains_key(&server_id) {
|
||||
let server = server_store.by_id(server_id).ok()??;
|
||||
servers.insert(server.id(), server);
|
||||
}
|
||||
Some(server_id)
|
||||
})
|
||||
.collect();
|
||||
let inbound_requests = SearchPage::from_pagination(
|
||||
InboundPager(ServerPager {
|
||||
self_id,
|
||||
store: &profiles.store,
|
||||
servers: &mut servers,
|
||||
}),
|
||||
10,
|
||||
"".to_owned(),
|
||||
page_num(&query, "inbound_page"),
|
||||
);
|
||||
|
||||
let outbound_requests = server_requests
|
||||
.backward_iter(self_id)
|
||||
.filter_map(|server_id| {
|
||||
if !servers.contains_key(&server_id) {
|
||||
let server = server_store.by_id(server_id).ok()??;
|
||||
servers.insert(server.id(), server);
|
||||
}
|
||||
Some(server_id)
|
||||
})
|
||||
.collect();
|
||||
let outbound_requests = SearchPage::from_pagination(
|
||||
OutboundPager(ServerPager {
|
||||
self_id,
|
||||
store: &profiles.store,
|
||||
servers: &mut servers,
|
||||
}),
|
||||
10,
|
||||
"".to_owned(),
|
||||
page_num(&query, "outbound_page"),
|
||||
);
|
||||
|
||||
let blocked = server_blocks
|
||||
.backward_iter(self_id)
|
||||
.filter_map(|server_id| {
|
||||
if !servers.contains_key(&server_id) {
|
||||
let server = server_store.by_id(server_id).ok()??;
|
||||
servers.insert(server.id(), server);
|
||||
}
|
||||
Some(server_id)
|
||||
})
|
||||
.collect();
|
||||
let blocked = SearchPage::from_pagination(
|
||||
BlockedPager(ServerPager {
|
||||
self_id,
|
||||
store: &profiles.store,
|
||||
servers: &mut servers,
|
||||
}),
|
||||
10,
|
||||
"".to_owned(),
|
||||
page_num(&query, "blocked_page"),
|
||||
);
|
||||
|
||||
let known = server_store
|
||||
.known()
|
||||
.filter_map(|server_id| {
|
||||
if !servers.contains_key(&server_id) {
|
||||
let server = server_store.by_id(server_id).ok()??;
|
||||
servers.insert(server.id(), server);
|
||||
Some(server_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let known = SearchPage::from_pagination(
|
||||
KnownPager(ServerPager {
|
||||
self_id,
|
||||
store: &profiles.store,
|
||||
servers: &mut servers,
|
||||
}),
|
||||
10,
|
||||
"".to_owned(),
|
||||
page_num(&query, "known_page"),
|
||||
);
|
||||
|
||||
Ok(FederationView {
|
||||
servers,
|
||||
|
@ -649,6 +869,7 @@ impl FederationView {
|
|||
known,
|
||||
discover_value: None,
|
||||
discover_error: None,
|
||||
query,
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
|
@ -657,6 +878,14 @@ impl FederationView {
|
|||
}
|
||||
}
|
||||
|
||||
fn page_num(query: &HashMap<String, String>, name: &str) -> Option<PageNum> {
|
||||
query.get(name).and_then(|page_str| {
|
||||
Some(PageNum {
|
||||
page: page_str.parse().ok()?,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize)]
|
||||
struct ConfigForm {
|
||||
title: String,
|
||||
|
@ -876,11 +1105,12 @@ fn to_admin() -> HttpResponse {
|
|||
|
||||
async fn admin_page(
|
||||
loader: ActixLoader,
|
||||
query: web::Query<HashMap<String, String>>,
|
||||
_: Admin,
|
||||
nav_state: NavState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let federation_view = FederationView::build(&state).await?;
|
||||
let federation_view = FederationView::build(query.into_inner(), &state).await?;
|
||||
let server_view = ServerView::build(&state).await?;
|
||||
let open_reports = ReportsView::new(state).await?;
|
||||
|
104
src/admin/pagination.rs
Normal file
104
src/admin/pagination.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
use crate::pagination::SearchPagination;
|
||||
use hyaenidae_profiles::store::Server;
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(super) struct ServerPager<'b> {
|
||||
pub(super) self_id: Uuid,
|
||||
pub(super) store: &'b hyaenidae_profiles::store::Store,
|
||||
pub(super) servers: &'b mut HashMap<Uuid, Server>,
|
||||
}
|
||||
|
||||
pub(super) struct FederatedPager<'a>(pub(super) ServerPager<'a>);
|
||||
pub(super) struct InboundPager<'a>(pub(super) ServerPager<'a>);
|
||||
pub(super) struct OutboundPager<'a>(pub(super) ServerPager<'a>);
|
||||
pub(super) struct BlockedPager<'a>(pub(super) ServerPager<'a>);
|
||||
pub(super) struct KnownPager<'a>(pub(super) ServerPager<'a>);
|
||||
|
||||
impl<'b> SearchPagination for FederatedPager<'b> {
|
||||
fn from_term<'a>(&'a mut self, _: &'a str) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||
Box::new(
|
||||
self.0
|
||||
.store
|
||||
.view
|
||||
.server_follows
|
||||
.forward_iter(self.0.self_id)
|
||||
.chain(
|
||||
self.0
|
||||
.store
|
||||
.view
|
||||
.server_follows
|
||||
.backward_iter(self.0.self_id),
|
||||
)
|
||||
.filter_map(move |server_id| self.0.filter_server(server_id))
|
||||
.rev(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> SearchPagination for InboundPager<'b> {
|
||||
fn from_term<'a>(&'a mut self, _: &'a str) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||
Box::new(
|
||||
self.0
|
||||
.store
|
||||
.view
|
||||
.server_follow_requests
|
||||
.forward_iter(self.0.self_id)
|
||||
.filter_map(move |server_id| self.0.filter_server(server_id))
|
||||
.rev(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> SearchPagination for OutboundPager<'b> {
|
||||
fn from_term<'a>(&'a mut self, _: &'a str) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||
Box::new(
|
||||
self.0
|
||||
.store
|
||||
.view
|
||||
.server_follow_requests
|
||||
.backward_iter(self.0.self_id)
|
||||
.filter_map(move |server_id| self.0.filter_server(server_id))
|
||||
.rev(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> SearchPagination for BlockedPager<'b> {
|
||||
fn from_term<'a>(&'a mut self, _: &'a str) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||
Box::new(
|
||||
self.0
|
||||
.store
|
||||
.view
|
||||
.server_blocks
|
||||
.backward_iter(self.0.self_id)
|
||||
.filter_map(move |server_id| self.0.filter_server(server_id))
|
||||
.rev(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> SearchPagination for KnownPager<'b> {
|
||||
fn from_term<'a>(&'a mut self, _: &'a str) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||
Box::new(
|
||||
self.0
|
||||
.store
|
||||
.servers
|
||||
.known()
|
||||
.filter_map(move |server_id| self.0.filter_server(server_id))
|
||||
.rev(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> ServerPager<'b> {
|
||||
fn filter_server(&mut self, server_id: Uuid) -> Option<Uuid> {
|
||||
if !self.servers.contains_key(&server_id) {
|
||||
let server = self.store.servers.by_id(server_id).ok()??;
|
||||
self.servers.insert(server.id(), server);
|
||||
Some(server_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -113,24 +113,25 @@ impl SearchPage {
|
|||
|
||||
match page {
|
||||
Some(PageNum { page }) => {
|
||||
let page = page.saturating_sub(1);
|
||||
items = pagination
|
||||
.from_term(&term)
|
||||
.skip(page * per_page)
|
||||
.take(per_page + 1)
|
||||
.collect();
|
||||
if page > 0 {
|
||||
prev = Some(page - 1);
|
||||
prev = Some(page);
|
||||
}
|
||||
if items.len() == per_page + 1 {
|
||||
items.pop();
|
||||
next = Some(page + 1);
|
||||
next = Some(page + 2);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
items = pagination.from_term(&term).take(per_page + 1).collect();
|
||||
if items.len() == per_page + 1 {
|
||||
items.pop();
|
||||
next = Some(1);
|
||||
next = Some(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
@use crate::admin::{FederationView, ReportsView, ServerView};
|
||||
@use crate::extensions::ProfileExt;
|
||||
@use crate::nav::NavState;
|
||||
@use crate::templates::button_js;
|
||||
@use crate::templates::layouts::home;
|
||||
@use crate::templates::admin::{reporter, server_box};
|
||||
@use hyaenidae_toolkit::{templates::button_group, Button};
|
||||
|
@ -12,7 +13,9 @@
|
|||
|
||||
@(loader: &ActixLoader, reports_view: &ReportsView, server_view: &ServerView, federation_view: &FederationView, nav_state: &NavState)
|
||||
|
||||
@:home(loader, &fl!(loader, "admin-settings-title"), &fl!(loader, "admin-settings-subtitle"), nav_state, {}, {
|
||||
@:home(loader, &fl!(loader, "admin-settings-title"), &fl!(loader, "admin-settings-subtitle"), nav_state, {
|
||||
@:button_js()
|
||||
}, {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="@server_view.update_path()">
|
||||
@:card_title({
|
||||
|
@ -123,6 +126,11 @@
|
|||
</div>
|
||||
})
|
||||
}
|
||||
@if federation_view.has_inbound_nav() {
|
||||
@:card_body({
|
||||
@:button_group(&federation_view.inbound_buttons(loader))
|
||||
})
|
||||
}
|
||||
})
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({
|
||||
|
@ -139,6 +147,11 @@
|
|||
</div>
|
||||
})
|
||||
}
|
||||
@if federation_view.has_outbound_nav() {
|
||||
@:card_body({
|
||||
@:button_group(&federation_view.outbound_buttons(loader))
|
||||
})
|
||||
}
|
||||
})
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({
|
||||
|
@ -155,6 +168,11 @@
|
|||
</div>
|
||||
})
|
||||
}
|
||||
@if federation_view.has_federated_nav() {
|
||||
@:card_body({
|
||||
@:button_group(&federation_view.federated_buttons(loader))
|
||||
})
|
||||
}
|
||||
})
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({
|
||||
|
@ -170,6 +188,11 @@
|
|||
</div>
|
||||
})
|
||||
}
|
||||
@if federation_view.has_blocked_nav() {
|
||||
@:card_body({
|
||||
@:button_group(&federation_view.blocked_buttons(loader))
|
||||
})
|
||||
}
|
||||
})
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({
|
||||
|
@ -186,5 +209,10 @@
|
|||
</div>
|
||||
})
|
||||
}
|
||||
@if federation_view.has_known_nav() {
|
||||
@:card_body({
|
||||
@:button_group(&federation_view.known_buttons(loader))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -326,6 +326,9 @@ admin-federation-defederate = Defederate
|
|||
admin-federation-block = Block
|
||||
admin-federation-unblock = Unblock
|
||||
|
||||
server-previous-page = Previous
|
||||
server-next-page = Next
|
||||
|
||||
update-comment-heading = Update Comment
|
||||
update-comment-button = Save
|
||||
|
||||
|
|
Loading…
Reference in a new issue