fix(photos): fix SQL type mismatch, pagination panic, missing icons, and add day/month/year grouping

- Fix photos endpoint 500: remove ::uuid cast on user_id WHERE clause (VARCHAR column)
- Fix pagination underflow panic when total_pages is 0
- Add missing 'images' and 'play' icons to SVG icon registry
- Add day/month/year grouping toggle with localStorage persistence
- Improve grid spacing and group header styling per mode
- Add i18n translations for grouping labels (all 9 locales)
This commit is contained in:
Jared Wolff
2026-03-05 14:46:30 -05:00
parent 53e4f5afe6
commit 6a84a5c44e
22 changed files with 220 additions and 64 deletions
+5 -1
View File
@@ -642,7 +642,11 @@ impl FileHandler {
}
}
Err(e) => {
tracing::warn!("Failed to read file for EXIF extraction {}: {}", file_id, e);
tracing::warn!(
"Failed to read file for EXIF extraction {}: {}",
file_id,
e
);
}
}
}
@@ -36,7 +36,10 @@ pub async fn list_photos(
let file_read = &state.repositories.file_read_repository;
match file_read.list_media_files(user_id, params.before, limit).await {
match file_read
.list_media_files(user_id, params.before, limit)
.await
{
Ok((files, sort_dates)) => {
info!("Photos: returned {} media files for user", files.len());
@@ -54,10 +57,9 @@ pub async fn list_photos(
// Set cursor header for next page
let mut response = Json(&dtos).into_response();
if let Some(&last_sd) = sort_dates.last() {
response.headers_mut().insert(
"X-Next-Cursor",
last_sd.to_string().parse().unwrap(),
);
response
.headers_mut()
.insert("X-Next-Cursor", last_sd.to_string().parse().unwrap());
}
response
@@ -183,11 +183,7 @@ async fn handle_webdav_methods(
/// If `path` doesn't already start with the user's home folder name, prepend
/// the home folder path so downstream services can find the resource in the DB.
/// Returns `None` when the path already includes the prefix or resolution fails.
async fn resolve_webdav_path(
state: &Arc<AppState>,
user_id: &str,
path: &str,
) -> Option<String> {
async fn resolve_webdav_path(state: &Arc<AppState>, user_id: &str, path: &str) -> Option<String> {
let folder_service = &state.applications.folder_service;
let home_folders = folder_service
.list_folders_for_owner(None, user_id)
@@ -213,10 +209,7 @@ async fn handle_webdav_dispatch(
// prefix when the path doesn't already include it.
// Extract user_id before any async call to keep the future Send.
let path = if !path.is_empty() && method.as_str() != "OPTIONS" {
let user_id = req
.extensions()
.get::<CurrentUser>()
.map(|u| u.id.clone());
let user_id = req.extensions().get::<CurrentUser>().map(|u| u.id.clone());
if let Some(uid) = user_id {
resolve_webdav_path(&state, &uid, &path)
.await