From 00f6e28207215b186fc842da1d1acca0bbb98daf Mon Sep 17 00:00:00 2001
From: Atharva Ombase <94031822+atharvaombase@users.noreply.github.com>
Date: Wed, 16 Apr 2025 15:19:55 +0530
Subject: [PATCH] Feat:Added file icons and fixed download errors
---
Frontend/src/components/FileList.jsx | 229 +++++++++++++++++++++------
1 file changed, 183 insertions(+), 46 deletions(-)
diff --git a/Frontend/src/components/FileList.jsx b/Frontend/src/components/FileList.jsx
index 22e4d1a..e7647a7 100644
--- a/Frontend/src/components/FileList.jsx
+++ b/Frontend/src/components/FileList.jsx
@@ -1,25 +1,83 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
+import { useDispatch } from "react-redux";
+import { setCurrentPath } from "../store/pathSlice";
+import {
+ FileText,
+ FileVideo,
+ FileImage,
+ FileAudio,
+ FileArchive,
+ FileSpreadsheet,
+ FileType2,
+ FileCode2,
+ Presentation,
+ Folder,
+ Download,
+ Trash2,
+ ArrowLeft,
+} from "lucide-react";
const FileTable = ({ initialPath }) => {
- const [currentPath, setCurrentPath] = useState(initialPath || "/");
+ const [currentPath, setCurrentPathState] = useState(initialPath || "/");
const [files, setFiles] = useState([]);
+ const dispatch = useDispatch();
- // Helpers to parse entry
const getType = (entry) =>
entry.trim().startsWith("📁") ? "Folder" : "File";
+
const getName = (entry) => entry.trim().replace(/^📁\s*|^📄\s*/, "");
+
const isFile = (entry) => getType(entry) === "File";
- // Fetch and show only top-level entries (indentation = 0)
+ const getIcon = (name, type) => {
+ if (type === "Folder")
+ return ;
+ const ext = name.split(".").pop().toLowerCase();
+ switch (ext) {
+ case "txt":
+ return ;
+ case "mp4":
+ case "mkv":
+ return ;
+ case "jpg":
+ case "jpeg":
+ case "png":
+ case "gif":
+ return ;
+ case "mp3":
+ case "wav":
+ return ;
+ case "zip":
+ case "rar":
+ case "tar":
+ case "gz":
+ return ;
+ case "csv":
+ case "xls":
+ case "xlsx":
+ return ;
+ case "ppt":
+ case "pptx":
+ return ;
+ case "js":
+ case "html":
+ case "css":
+ case "java":
+ case "py":
+ case "cpp":
+ return ;
+ default:
+ return ;
+ }
+ };
+
const fetchFiles = async () => {
try {
const response = await fetch(
`http://192.168.29.61:8080/api/hdfs/listFiles?hdfsPath=${currentPath}`
);
const data = await response.json();
-
- // Filter entries: only those without leading spaces
const filtered = data.filter(
(entry) => entry.match(/^ */)[0].length === 0
);
@@ -30,53 +88,130 @@ const FileTable = ({ initialPath }) => {
}
};
+ const deleteFileOrFolder = async (name, type, event) => {
+ event.stopPropagation(); // Prevent row onClick from firing.
+ try {
+ const hdfsPath =
+ currentPath === "/" ? `/${name}` : `${currentPath}/${name}`;
+ const encodedPath = encodeURIComponent(hdfsPath);
+ let deleteEndpoint = "";
+
+ if (type === "File") {
+ deleteEndpoint = `http://192.168.29.61:8080/api/hdfs/deleteFile?hdfsPath=${encodedPath}`;
+ } else {
+ deleteEndpoint = `http://192.168.29.61:8080/api/hdfs/deleteFolder?hdfsPath=${encodedPath}`;
+ }
+
+ const response = await fetch(deleteEndpoint, { method: "DELETE" });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ console.error("Deletion failed:", errorText);
+ }
+
+ fetchFiles();
+ } catch (error) {
+ console.error("Failed to delete file/folder:", error);
+ }
+ };
+
useEffect(() => {
+ dispatch(setCurrentPath(currentPath));
fetchFiles();
}, [currentPath]);
- // Navigate into a folder
const handleOpenFolder = (folderName) => {
const newPath =
currentPath === "/" ? `/${folderName}` : `${currentPath}/${folderName}`;
- setCurrentPath(newPath);
+ setCurrentPathState(newPath);
};
- // Go up one level
const goBack = () => {
if (currentPath === "/") return;
const parts = currentPath.split("/").filter(Boolean);
parts.pop();
- setCurrentPath(parts.length === 0 ? "/" : `/${parts.join("/")}`);
+ setCurrentPathState(parts.length === 0 ? "/" : `/${parts.join("/")}`);
+ };
+
+ const handleFileDownload = async (hdfsPath, name, event) => {
+ event.stopPropagation(); // Prevent row click (if any) for files.
+ try {
+ const formData = new URLSearchParams();
+ formData.append("hdfsPath", hdfsPath);
+ formData.append("username", "kalas");
+
+ const response = await fetch(
+ "http://192.168.29.61:8080/api/hdfs/downloadFile",
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ body: formData.toString(),
+ }
+ );
+
+ if (!response.ok) throw new Error("Download failed");
+
+ // Extract filename from header OR fallback to name from path
+ const contentDisposition = response.headers.get("Content-Disposition");
+ let fileName = "downloaded_file";
+
+ if (contentDisposition && contentDisposition.includes("filename=")) {
+ const match = contentDisposition.match(
+ /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
+ );
+ if (match && match[1]) {
+ fileName = match[1].replace(/['"]/g, "");
+ }
+ } else {
+ // fallback: extract name from path
+ const parts = hdfsPath.split("/");
+ const fallback = parts[parts.length - 1];
+ if (fallback) fileName = fallback;
+ }
+
+ // Create blob and trigger download
+ const blob = await response.blob();
+ const url = window.URL.createObjectURL(blob);
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = fileName;
+ document.body.appendChild(link);
+ link.click();
+ link.remove();
+ window.URL.revokeObjectURL(url);
+ } catch (error) {
+ console.error("Download failed:", error);
+ alert("Something went wrong while downloading the file.");
+ }
};
return (
-
-
-
Path: {currentPath}
+
+
+
Path: {currentPath}
{currentPath !== "/" && (
-
-
+
- |
- File Name
- |
-
- Type
- |
-
- Action
- |
+ Name |
+ Actions |
{files.length === 0 ? (
- |
+ |
No files found.
|
@@ -84,38 +219,40 @@ const FileTable = ({ initialPath }) => {
files.map((entry, idx) => {
const name = getName(entry);
const type = getType(entry);
- const encodedPath = encodeURIComponent(`${currentPath}/${name}`);
- const downloadUrl = `http://192.168.29.61:8080/api/hdfs/downloadFile?hdfsPath=${encodedPath}&localPath=E:/testdownload/${name}&kalas=${
- currentPath.split("/")[1] || "user"
- }`;
+ const hdfsPath =
+ currentPath === "/" ? `/${name}` : `${currentPath}/${name}`;
return (
handleOpenFolder(name) : undefined
+ }
+ className={`even:bg-blue-50 odd:bg-white border-b border-blue-100 transition hover:bg-blue-100 ${
+ type === "Folder" ? "cursor-pointer" : ""
+ }`}
>
- |
+ |
+ {getIcon(name, type)}
{name}
|
- {type} |
-
- {isFile(entry) ? (
-
- Download
-
- ) : (
+ |
+ {isFile(entry) && (
handleOpenFolder(name)}
- className="font-medium text-blue-600 hover:underline"
+ onClick={(e) => handleFileDownload(hdfsPath, name, e)}
+ className="text-blue-600 hover:underline inline-flex items-center"
>
- Open
+
+ Download
)}
+ deleteFileOrFolder(name, type, e)}
+ className="text-red-600 hover:underline inline-flex items-center"
+ >
+
+ Delete
+
|
);