Implement folder sorting

This commit is contained in:
Jackzie 2025-04-20 08:48:33 -05:00
parent 6eb900b814
commit d1cf5d3038
5 changed files with 49 additions and 7 deletions

View file

@ -1,7 +1,9 @@
use std::cmp::Ordering;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use anyhow::Error;
use anyhow::{anyhow, Error};
use log::trace;
use rocket::response::stream::ReaderStream;
use rocket::serde::Serialize;
use tokio::io::BufStream;
@ -17,6 +19,21 @@ pub struct Library {
repo: RepoContainer,
}
/// The direction of sort and the field to sort by
#[derive(PartialEq, Debug)]
pub struct ListOptions {
pub sort_field: Option<String>,
pub sort_descending: Option<bool>
}
impl Default for ListOptions {
fn default() -> Self {
ListOptions {
sort_field: Some("name".to_string()),
sort_descending: Some(false),
}
}
}
impl Library {
pub fn new(library_model: LibraryModel, repo: RepoContainer) -> Library {
Library {
@ -49,9 +66,28 @@ impl Library {
repo.backend.read_file(&self.model.id.to_string(), rel_path)
}
pub async fn list_files(&self, rel_path: &PathBuf) -> Result<Vec<FileEntry>, anyhow::Error> {
pub async fn list_files(&self, rel_path: &PathBuf, options: ListOptions) -> Result<Vec<FileEntry>, anyhow::Error> {
let repo = self.repo.read().await;
repo.backend.list_files(&self.model.id.to_string(), rel_path)
let mut list = repo.backend.list_files(&self.model.id.to_string(), rel_path)?;
let field = options.sort_field.unwrap_or("name".to_string());
let descending = options.sort_descending.unwrap_or(false);
match field.as_str() {
"name" => list.sort_by(|a, b| {
if a._type == FileType::File && b._type != FileType::File { Ordering::Greater }
else if a._type != FileType::File && b._type == FileType::File { Ordering::Less }
else { a.path.cmp(&b.path) }
}),
"size" => list.sort_by(|a, b| {
if a._type == FileType::File && b._type != FileType::File { Ordering::Greater }
else if a._type != FileType::File && b._type == FileType::File { Ordering::Less }
else { a.size.cmp(&b.size) }
}),
_ => return Err(anyhow!("Unsupported field"))
}
if descending {
list.reverse();
}
Ok(list)
}
pub async fn delete_file(&self, rel_path: &PathBuf) -> Result<(), anyhow::Error> {

View file

@ -17,6 +17,7 @@ use crate::managers::libraries::LibraryManager;
use crate::managers::repos::RepoManager;
use crate::models::library::{LibraryModel, LibraryWithRepoModel};
use crate::models::user;
use crate::objs::library::ListOptions;
use crate::storage::{FileEntry, FileType};
use crate::util::{JsonErrorResponse, ResponseError};
#[get("/<library_id>")]
@ -30,7 +31,7 @@ pub(crate) async fn get_file(pool: &State<DB>, library_id: &str) -> Result<Optio
pub(crate) async fn list_files(libraries: &State<Arc<Mutex<LibraryManager>>>, library_id: &str, path: &str) -> Result<Json<Vec<FileEntry>>, ResponseError> {
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
library.list_files(&PathBuf::from(path)).await
library.list_files(&PathBuf::from(path), ListOptions::default()).await
.map(|files| Json(files))
.map_err(|e| ResponseError::InternalServerError(JsonErrorResponse {
code: "STORAGE_ERROR".to_string(),

View file

@ -17,6 +17,7 @@ use tokio::sync::Mutex;
use crate::consts::FILE_CONSTANTS;
use crate::guards::{AuthUser};
use crate::managers::libraries::LibraryManager;
use crate::objs::library::ListOptions;
use crate::routes::ui::auth;
use crate::util::{JsonErrorResponse, ResponseError};
@ -55,7 +56,11 @@ pub async fn list_library_files(
};
let libs = libraries.lock().await;
let library = libs.get(library_id).await?;
let files = library.list_files(&PathBuf::from(&path)).await
let list_options = ListOptions {
sort_field: Some(options.sort_key.clone()),
sort_descending: Some(options.sort_dir == "desc"),
};
let files = library.list_files(&PathBuf::from(&path), list_options).await
.map_err(|e| ResponseError::InternalServerError(JsonErrorResponse {
code: "STORAGE_ERROR".to_string(),
message: e.to_string(),

View file

@ -19,7 +19,7 @@ pub enum StorageBackendMap {
S3(S3Storage)
}
#[derive(Debug, Serialize, Deserialize, FromFormField)]
#[derive(Debug, Serialize, Deserialize, FromFormField, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum FileType {
File,

View file

@ -24,7 +24,7 @@
<div class="field">
<label class="label">Username / Email</label>
<div class="control has-icons-left">
<input required name="username" class="input {{#if errors.username}}is-danger{{/if}}" type="text" placeholder="Username or Email">
<input autofocus required name="username" class="input {{#if errors.username}}is-danger{{/if}}" type="text" placeholder="Username or Email">
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>