From 95268f134301c922d0402ab4f65651cbff397472 Mon Sep 17 00:00:00 2001 From: prosfus Date: Sat, 4 Jan 2025 13:14:40 +0100 Subject: [PATCH] feat: be able to download multiple minio files --- package.json | 1 + .../minio/components/BucketContent/index.tsx | 114 ++++++++++++++++-- 2 files changed, 104 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index bb8b7dc..b169ba6 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "clsx": "^2.1.1", "file-type": "^19.6.0", "framer-motion": "^11.3.31", + "jszip": "^3.10.1", "lucide-react": "^0.411.0", "next-themes": "^0.3.0", "react": "^18.3.1", diff --git a/src/pages/ui/minio/components/BucketContent/index.tsx b/src/pages/ui/minio/components/BucketContent/index.tsx index 8183f8b..7fb4067 100644 --- a/src/pages/ui/minio/components/BucketContent/index.tsx +++ b/src/pages/ui/minio/components/BucketContent/index.tsx @@ -3,7 +3,14 @@ import { _Object, CommonPrefix } from "@aws-sdk/client-s3"; import { useEffect, useState } from "react"; import { Link } from "react-router-dom"; import GenericTable from "@/components/Table"; // Importar GenericTable -import { AlertCircle, Eye, Folder, Trash } from "lucide-react"; +import { + AlertCircle, + Eye, + Folder, + Trash, + Download, + DownloadIcon, +} from "lucide-react"; import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert"; import OscarColors from "@/styles"; import { motion, AnimatePresence } from "framer-motion"; @@ -11,6 +18,12 @@ import useSelectedBucket from "../../hooks/useSelectedBucket"; import { Button } from "@/components/ui/button"; import DeleteDialog from "@/components/DeleteDialog"; import FilePreviewModal from "./FilePreview"; +import JSZip from "jszip"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/ui/tooltip"; export type BucketItem = | { @@ -29,7 +42,8 @@ export type BucketItem = export default function BucketContent() { const { name: bucketName, path } = useSelectedBucket(); - const { getBucketItems, buckets, uploadFile, deleteFile } = useMinio(); + const { getBucketItems, buckets, uploadFile, deleteFile, getFileUrl } = + useMinio(); const [items, setItems] = useState([]); @@ -87,6 +101,48 @@ export default function BucketContent() { const [itemsToDelete, setItemsToDelete] = useState([]); + const handleDownloadFile = async (item: BucketItem) => { + if (item.Type === "file") { + try { + const url = await getFileUrl(item.BucketName, item.Key.Key!); + if (url) { + const a = document.createElement("a"); + a.href = url; + a.download = item.Name; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + } + } catch (error) { + console.error("Error al descargar el archivo:", error); + } + } + }; + + const handleBulkDownload = async (items: BucketItem[]) => { + const zip = new JSZip(); + + for (const item of items) { + if (item.Type === "file") { + const url = await getFileUrl(item.BucketName, item.Key.Key!); + if (url) { + const response = await fetch(url); + const blob = await response.blob(); + zip.file(item.Name, blob); + } + } + } + + zip.generateAsync({ type: "blob" }).then((content) => { + const a = document.createElement("a"); + a.href = URL.createObjectURL(content); + a.download = `${bucketName}_files.zip`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }); + }; + return ( <> {previewFile && ( @@ -202,15 +258,24 @@ export default function BucketContent() { return ( <> {item.Type === "file" && ( - + <> + + + )} + + + {items.some((item) => item.Type === "folder") && ( + Cannot download folders + )} + + ); + }, + }, + ]} />