feat: delta/instant upload + frontend UI/UX polish
Bundles the backend+frontend delta-upload (content-dedup) feature with a batch of frontend fixes from this session. Upload / dedup: - Client-hashed delta & instant upload (deltaUpload, hashWasm vendor shim) - Backend dedup batch endpoint (dedup_service, dedup_handler, routes) - session store owned-hash helpers; unit tests + upload-strategy bench Frontend UI/UX: - Colour file-type icons in grid/list (per-type tinted tiles + glyph hue) - Robust thumbnail fallback; PDFs now show their type icon (backend generates no PDF thumbnails) instead of a blank tile - Fix PDF preview: load via a same-origin blob: iframe — the API URL is blocked by the global X-Frame-Options: DENY in the browser's framed PDF viewer, matching the existing CSP `frame-src blob:` design - Groups: localized virtual-group description (no DB schema-note leak), add nav.groups to the 15 missing locales, fix primary-button contrast - Repoint --color-text-light → --color-on-accent (was faint grey on accent) - Nudge the admin role badge off the user-menu header divider Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1075,6 +1075,33 @@ impl DedupService {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Batch variant of [`Self::user_owns_blob_reference`]: given candidate
|
||||
/// hashes, return the subset the user already references — in ONE query
|
||||
/// (backed by `idx_files_blob_hash`). Lets a client hash a whole upload set
|
||||
/// and learn which files it can skip with a single round trip instead of
|
||||
/// one probe per file.
|
||||
///
|
||||
/// User-scoped, exactly like the single check: only the caller's own blobs
|
||||
/// are returned, so it cannot probe whether *other* users hold a blob.
|
||||
pub async fn user_owned_blob_references(
|
||||
&self,
|
||||
hashes: &[String],
|
||||
user_id: &str,
|
||||
) -> Vec<String> {
|
||||
if hashes.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
sqlx::query_scalar::<_, String>(
|
||||
"SELECT DISTINCT blob_hash FROM storage.files \
|
||||
WHERE blob_hash = ANY($1) AND user_id = $2::uuid",
|
||||
)
|
||||
.bind(hashes)
|
||||
.bind(user_id)
|
||||
.fetch_all(self.pool.as_ref())
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Get metadata for a blob (manifest-aware with legacy fallback).
|
||||
pub async fn get_blob_metadata(&self, hash: &str) -> Option<BlobMetadataDto> {
|
||||
// Check manifest first
|
||||
|
||||
Reference in New Issue
Block a user