fix(ui): fix list view column spacing, rubber-band selection, and clippy warnings

Add column-gap to list header/items, prevent rubber-band selection from
swallowing clicks on list headers and file items, preserve rubber-band
selection after mouseup, and extract type aliases to resolve clippy
type_complexity warnings.
This commit is contained in:
Jared Wolff
2026-03-05 21:07:19 -05:00
parent d8eecbd9ca
commit 4617c1c1df
7 changed files with 53 additions and 37 deletions
@@ -7,6 +7,20 @@
//! File paths are resolved by JOINing with `storage.folders.path` (the
//! materialized path column), so no recursive CTEs or N+1 queries are needed.
/// Row shape returned by media-file queries (avoids `clippy::type_complexity`).
type MediaFileRow = (
String, // id
String, // name
Option<String>, // folder_id
Option<String>, // folder path
i64, // size
String, // mime_type
i64, // created_at
i64, // updated_at
Option<String>, // user_id
i64, // sort_date
);
use bytes::Bytes;
use futures::{Stream, TryStreamExt};
use moka::sync::Cache;
@@ -156,18 +170,7 @@ impl FileBlobReadRepository {
before: Option<i64>,
limit: i64,
) -> Result<(Vec<File>, Vec<i64>), DomainError> {
let rows: Vec<(
String, // id
String, // name
Option<String>, // folder_id
Option<String>, // folder path
i64, // size
String, // mime_type
i64, // created_at
i64, // updated_at
Option<String>, // user_id
i64, // sort_date
)> = sqlx::query_as(
let rows: Vec<MediaFileRow> = sqlx::query_as(
r#"
SELECT fi.id::text, fi.name, fi.folder_id::text, fo.path,
fi.size, fi.mime_type,
@@ -10,6 +10,19 @@ use tracing::error;
use crate::common::errors::DomainError;
use crate::infrastructure::services::exif_service::ExifMetadata;
/// Row shape returned by metadata queries (avoids `clippy::type_complexity`).
type MetadataRow = (
String,
Option<DateTime<Utc>>,
Option<f64>,
Option<f64>,
Option<String>,
Option<String>,
Option<i16>,
Option<i32>,
Option<i32>,
);
/// Metadata as stored/retrieved from the database.
#[derive(Debug, Clone, Serialize)]
pub struct StoredMetadata {
@@ -73,17 +86,7 @@ impl FileMetadataRepository {
/// Get metadata for a single file.
pub async fn get(&self, file_id: &str) -> Result<Option<StoredMetadata>, DomainError> {
let row: Option<(
String,
Option<DateTime<Utc>>,
Option<f64>,
Option<f64>,
Option<String>,
Option<String>,
Option<i16>,
Option<i32>,
Option<i32>,
)> = sqlx::query_as(
let row: Option<MetadataRow> = sqlx::query_as(
r#"
SELECT file_id::text, captured_at, latitude, longitude,
camera_make, camera_model, orientation, width, height
@@ -135,17 +138,7 @@ impl FileMetadataRepository {
return Ok(HashMap::new());
}
let rows: Vec<(
String,
Option<DateTime<Utc>>,
Option<f64>,
Option<f64>,
Option<String>,
Option<String>,
Option<i16>,
Option<i32>,
Option<i32>,
)> = sqlx::query_as(
let rows: Vec<MetadataRow> = sqlx::query_as(
r#"
SELECT file_id::text, captured_at, latitude, longitude,
camera_make, camera_model, orientation, width, height
+5 -1
View File
@@ -39,7 +39,11 @@ pub async fn handle_preview(
) -> impl IntoResponse {
// Parse the Nextcloud file ID — the NC app may append an instance suffix
// (e.g. "00000326ocnca"), so strip non-digit characters first.
let numeric_part: String = params.file_id.chars().take_while(|c| c.is_ascii_digit()).collect();
let numeric_part: String = params
.file_id
.chars()
.take_while(|c| c.is_ascii_digit())
.collect();
let nc_file_id: i64 = match numeric_part.parse() {
Ok(id) => id,
Err(_) => {