directory downloads (zipped)

This commit is contained in:
2025-08-29 21:20:44 +02:00
parent 76713db985
commit 3498a2926c
11 changed files with 368 additions and 47 deletions

248
backend/Cargo.lock generated
View File

@@ -17,6 +17,17 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aes"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.1.3" version = "1.1.3"
@@ -53,6 +64,15 @@ version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "argon2" name = "argon2"
version = "0.5.3" version = "0.5.3"
@@ -248,12 +268,23 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "bzip2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bea8dcd42434048e4f7a304411d9273a411f647446c1234a65ce0554923f4cff"
dependencies = [
"libbz2-rs-sys",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.29" version = "1.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
dependencies = [ dependencies = [
"jobserver",
"libc",
"shlex", "shlex",
] ]
@@ -278,6 +309,16 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]] [[package]]
name = "concurrent-queue" name = "concurrent-queue"
version = "2.5.0" version = "2.5.0"
@@ -293,6 +334,12 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "constant_time_eq"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
[[package]] [[package]]
name = "cookie" name = "cookie"
version = "0.18.1" version = "0.18.1"
@@ -344,6 +391,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "crossbeam-queue" name = "crossbeam-queue"
version = "0.3.12" version = "0.3.12"
@@ -410,6 +466,12 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
[[package]]
name = "deflate64"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
[[package]] [[package]]
name = "der" name = "der"
version = "0.7.10" version = "0.7.10"
@@ -430,6 +492,17 @@ dependencies = [
"powerfmt", "powerfmt",
] ]
[[package]]
name = "derive_arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "2.0.1" version = "2.0.1"
@@ -548,6 +621,17 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "flate2"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
dependencies = [
"crc32fast",
"libz-rs-sys",
"miniz_oxide",
]
[[package]] [[package]]
name = "flume" name = "flume"
version = "0.11.1" version = "0.11.1"
@@ -1036,6 +1120,15 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "inout"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "io-uring" name = "io-uring"
version = "0.7.8" version = "0.7.8"
@@ -1069,6 +1162,16 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jobserver"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
"getrandom 0.3.3",
"libc",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.77" version = "0.3.77"
@@ -1088,12 +1191,38 @@ dependencies = [
"spin", "spin",
] ]
[[package]]
name = "libbz2-rs-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.174" version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "liblzma"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10bf66f4598dc77ff96677c8e763655494f00ff9c1cf79e2eb5bb07bc31f807d"
dependencies = [
"liblzma-sys",
]
[[package]]
name = "liblzma-sys"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01b9596486f6d60c3bbe644c0e1be1aa6ccc472ad630fe8927b456973d7cb736"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]] [[package]]
name = "libm" name = "libm"
version = "0.2.15" version = "0.2.15"
@@ -1110,6 +1239,15 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "libz-rs-sys"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221"
dependencies = [
"zlib-rs",
]
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.9.4" version = "0.9.4"
@@ -1427,6 +1565,16 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "pbkdf2"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest",
"hmac",
]
[[package]] [[package]]
name = "pem-rfc7468" name = "pem-rfc7468"
version = "0.7.0" version = "0.7.0"
@@ -1496,6 +1644,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppmd-rust"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.21" version = "0.2.21"
@@ -1878,6 +2032,12 @@ dependencies = [
"rand_core", "rand_core",
] ]
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.10" version = "0.4.10"
@@ -2653,6 +2813,7 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
"url", "url",
"uuid", "uuid",
"zip",
] ]
[[package]] [[package]]
@@ -3081,6 +3242,20 @@ name = "zeroize"
version = "1.8.1" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "zerotrie" name = "zerotrie"
@@ -3114,3 +3289,76 @@ dependencies = [
"quote", "quote",
"syn", "syn",
] ]
[[package]]
name = "zip"
version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835eb39822904d39cb19465de1159e05d371973f0c6df3a365ad50565ddc8b9"
dependencies = [
"aes",
"arbitrary",
"bzip2",
"constant_time_eq",
"crc32fast",
"deflate64",
"flate2",
"getrandom 0.3.3",
"hmac",
"indexmap",
"liblzma",
"memchr",
"pbkdf2",
"ppmd-rust",
"sha1",
"time",
"zeroize",
"zopfli",
"zstd",
]
[[package]]
name = "zlib-rs"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a"
[[package]]
name = "zopfli"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
dependencies = [
"bumpalo",
"crc32fast",
"log",
"simd-adler32",
]
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.15+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
dependencies = [
"cc",
"pkg-config",
]

View File

@@ -45,3 +45,4 @@ tracing = "0.1.41"
tracing-subscriber = "0.3.19" tracing-subscriber = "0.3.19"
url = "2.5.4" url = "2.5.4"
uuid = { version = "1.17.0", features = ["serde"] } uuid = { version = "1.17.0", features = ["serde"] }
zip = "4.5.0"

View File

@@ -1,6 +1,7 @@
mod requests; mod requests;
use bytes::Bytes;
use futures_util::Stream;
pub use requests::*; pub use requests::*;
use tokio_util::io::ReaderStream;
use std::path::Path; use std::path::Path;
@@ -263,20 +264,25 @@ impl From<AbsoluteFilePath> for FilePath {
} }
} }
#[derive(Debug)] pub type FileStreamInner =
pub struct FileStream(ReaderStream<tokio::fs::File>); Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send + Sync + Unpin + 'static>;
pub struct FileStream(FileStreamInner);
impl FileStream { impl FileStream {
pub fn new(stream: ReaderStream<tokio::fs::File>) -> Self { pub fn new<S>(stream: S) -> Self
Self(stream) where
S: Stream<Item = Result<Bytes, std::io::Error>> + Send + Sync + Unpin + 'static,
{
Self(Box::new(stream))
} }
pub fn stream(&self) -> &ReaderStream<tokio::fs::File> { pub fn stream(&self) -> &FileStreamInner {
&self.0 &self.0
} }
} }
impl From<FileStream> for ReaderStream<tokio::fs::File> { impl From<FileStream> for FileStreamInner {
fn from(value: FileStream) -> Self { fn from(value: FileStream) -> Self {
value.0 value.0
} }

View File

@@ -50,7 +50,6 @@ impl From<&ShareCatRequest> for VerifySharePasswordRequest {
} }
} }
#[derive(Debug)]
pub struct ShareCatResponse { pub struct ShareCatResponse {
share: Share, share: Share,
warren: Warren, warren: Warren,

View File

@@ -74,9 +74,9 @@ where
return Ok(Self(None)); return Ok(Self(None));
}; };
SharePassword::new(cookie.value()) Ok(SharePassword::new(cookie.value())
.map(|v| Self(Some(v))) .map(|v| Self(Some(v)))
.map_err(|_| ApiError::BadRequest("Invalid password".to_string())) .unwrap_or(Self(None)))
} }
// Debug build // Debug build
else { else {

View File

@@ -16,6 +16,7 @@ mod warren_rm;
use axum::{ use axum::{
Router, Router,
body::Body,
extract::DefaultBodyLimit, extract::DefaultBodyLimit,
routing::{get, post}, routing::{get, post},
}; };
@@ -41,7 +42,7 @@ use warren_mv::warren_mv;
use crate::{ use crate::{
domain::warren::{ domain::warren::{
models::file::{File, FileMimeType, FileType}, models::file::{File, FileMimeType, FileStream, FileStreamInner, FileType},
ports::{AuthService, WarrenService}, ports::{AuthService, WarrenService},
}, },
inbound::http::AppState, inbound::http::AppState,
@@ -67,6 +68,13 @@ impl From<&File> for WarrenFileElement {
} }
} }
impl From<FileStream> for Body {
fn from(value: FileStream) -> Self {
let inner: FileStreamInner = value.into();
Body::from_stream(inner)
}
}
pub fn routes<WS: WarrenService, AS: AuthService>() -> Router<AppState<WS, AS>> { pub fn routes<WS: WarrenService, AS: AuthService>() -> Router<AppState<WS, AS>> {
Router::new() Router::new()
.route("/", get(list_warrens)) .route("/", get(list_warrens))

View File

@@ -4,14 +4,13 @@ use axum::{
}; };
use serde::Deserialize; use serde::Deserialize;
use thiserror::Error; use thiserror::Error;
use tokio_util::io::ReaderStream;
use uuid::Uuid; use uuid::Uuid;
use crate::{ use crate::{
domain::warren::{ domain::warren::{
models::{ models::{
auth_session::AuthRequest, auth_session::AuthRequest,
file::{AbsoluteFilePathError, CatRequest, FilePath, FilePathError, FileStream}, file::{AbsoluteFilePathError, CatRequest, FilePath, FilePathError},
warren::WarrenCatRequest, warren::WarrenCatRequest,
}, },
ports::{AuthService, WarrenService}, ports::{AuthService, WarrenService},
@@ -59,12 +58,6 @@ impl WarrenCatHttpRequestBody {
} }
} }
impl From<FileStream> for Body {
fn from(value: FileStream) -> Self {
Body::from_stream::<ReaderStream<tokio::fs::File>>(value.into())
}
}
pub async fn fetch_file<WS: WarrenService, AS: AuthService>( pub async fn fetch_file<WS: WarrenService, AS: AuthService>(
State(state): State<AppState<WS, AS>>, State(state): State<AppState<WS, AS>>,
SessionIdHeader(session): SessionIdHeader, SessionIdHeader(session): SessionIdHeader,

View File

@@ -1,11 +1,15 @@
use std::{os::unix::fs::MetadataExt, path::PathBuf}; use std::{
io::{Cursor, Write},
os::unix::fs::MetadataExt,
path::{Path, PathBuf},
};
use anyhow::{Context, anyhow, bail}; use anyhow::{Context, anyhow, bail};
use futures_util::TryStreamExt; use futures_util::TryStreamExt;
use rustix::fs::{Statx, statx}; use rustix::fs::{Statx, statx};
use tokio::{ use tokio::{
fs, fs::{self},
io::{self, AsyncWriteExt as _}, io::{self, AsyncReadExt as _, AsyncWriteExt as _},
}; };
use tokio_util::io::ReaderStream; use tokio_util::io::ReaderStream;
@@ -214,7 +218,48 @@ impl FileSystem {
.open(&path) .open(&path)
.await?; .await?;
let file_size = file.metadata().await?.size(); let metadata = file.metadata().await?;
if metadata.is_dir() {
drop(file);
let options = zip::write::SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Zstd)
.unix_permissions(0o755);
let mut file_buf = Vec::new();
let zip_buf = Vec::new();
let cursor = Cursor::new(zip_buf);
let mut zip = zip::ZipWriter::new(cursor);
for entry_path_buf in walk_dir(&path).await? {
let entry_path = entry_path_buf.as_path();
let entry_str = entry_path
.strip_prefix(&path)?
.to_str()
.context("Failed to get directory entry name")?;
if entry_path.is_dir() {
zip.add_directory(entry_str, options)?;
continue;
}
zip.start_file(entry_str, options)?;
let mut entry_file = tokio::fs::File::open(entry_path).await?;
entry_file.read_to_end(&mut file_buf).await?;
zip.write_all(&file_buf)?;
file_buf.clear();
}
let mut cursor = zip.finish()?;
cursor.set_position(0);
let stream = FileStream::new(ReaderStream::new(cursor));
return Ok(stream);
}
let file_size = metadata.size();
if file_size > self.max_file_fetch_bytes { if file_size > self.max_file_fetch_bytes {
bail!("File size exceeds configured limit"); bail!("File size exceeds configured limit");
@@ -410,3 +455,27 @@ where
) )
} }
} }
async fn walk_dir<P>(dir: P) -> Result<Vec<PathBuf>, tokio::io::Error>
where
P: AsRef<Path>,
{
let mut dirs = vec![dir.as_ref().to_owned()];
let mut files = vec![];
while !dirs.is_empty() {
let mut dir_iter = tokio::fs::read_dir(dirs.remove(0)).await?;
while let Some(entry) = dir_iter.next_entry().await? {
let entry_path_buf = entry.path();
if entry_path_buf.is_dir() {
dirs.push(entry_path_buf);
} else {
files.push(entry_path_buf);
}
}
}
Ok(files)
}

View File

@@ -143,10 +143,7 @@ function onDownload() {
<Icon name="lucide:copy" /> <Icon name="lucide:copy" />
Copy Copy
</ContextMenuItem> </ContextMenuItem>
<ContextMenuItem <ContextMenuItem @select="onDownload">
:disabled="entry.fileType !== 'file'"
@select="onDownload"
>
<Icon name="lucide:download" /> <Icon name="lucide:download" />
Download Download
</ContextMenuItem> </ContextMenuItem>

View File

@@ -125,10 +125,15 @@ function onDowloadClicked() {
return; return;
} }
downloadFile( const downloadName =
share.file.name, share.file.fileType === 'directory'
getApiUrl(`warrens/files/cat_share?shareId=${share.data.id}&path=/`) ? `${share.file.name}.zip`
: share.file.name;
const downloadApiUrl = getApiUrl(
`warrens/files/cat_share?shareId=${share.data.id}&path=/`
); );
downloadFile(downloadName, downloadApiUrl);
} }
function onEntryDownload(entry: DirectoryEntry) { function onEntryDownload(entry: DirectoryEntry) {
@@ -136,12 +141,13 @@ function onEntryDownload(entry: DirectoryEntry) {
return; return;
} }
downloadFile( const downloadName =
entry.name, entry.fileType === 'directory' ? `${entry.name}.zip` : entry.name;
getApiUrl( const downloadApiUrl = getApiUrl(
`warrens/files/cat_share?shareId=${share.data.id}&path=${joinPaths(warrenStore.current.path, entry.name)}` `warrens/files/cat_share?shareId=${share.data.id}&path=${joinPaths(warrenStore.current.path, entry.name)}`
)
); );
downloadFile(downloadName, downloadApiUrl);
} }
</script> </script>

View File

@@ -111,19 +111,13 @@ function onEntryDownload(entry: DirectoryEntry) {
return; return;
} }
if (entry.fileType !== 'file') { const downloadName =
toast.warning('Download', { entry.fileType === 'directory' ? `${entry.name}.zip` : entry.name;
description: 'Directory downloads are not supported yet', const downloadApiUrl = getApiUrl(
}); `warrens/files/cat?warrenId=${warrenStore.current.warrenId}&path=${joinPaths(warrenStore.current.path, entry.name)}`
return;
}
downloadFile(
entry.name,
getApiUrl(
`warrens/files/cat?warrenId=${warrenStore.current.warrenId}&path=${joinPaths(warrenStore.current.path, entry.name)}`
)
); );
downloadFile(downloadName, downloadApiUrl);
} }
function onBack() { function onBack() {