Feat:Added username from localhost for fetching
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { setCurrentPath } from "../store/pathSlice";
|
import { setCurrentPath } from "../store/pathSlice";
|
||||||
@@ -18,6 +18,10 @@ import {
|
|||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
|
const username = localStorage.getItem("username");
|
||||||
|
// const authToken = localStorage.getItem("token");
|
||||||
|
const API_URL = import.meta.env.VITE_API_URL || "http://localhost:8080";
|
||||||
|
// const token = localStorage.getItem("token");
|
||||||
const FileTable = ({ initialPath }) => {
|
const FileTable = ({ initialPath }) => {
|
||||||
const [currentPath, setCurrentPathState] = useState(initialPath || "/");
|
const [currentPath, setCurrentPathState] = useState(initialPath || "/");
|
||||||
const [files, setFiles] = useState([]);
|
const [files, setFiles] = useState([]);
|
||||||
@@ -33,6 +37,7 @@ const FileTable = ({ initialPath }) => {
|
|||||||
const getIcon = (name, type) => {
|
const getIcon = (name, type) => {
|
||||||
if (type === "Folder")
|
if (type === "Folder")
|
||||||
return <Folder className="text-yellow-500 w-5 h-5 mr-2" />;
|
return <Folder className="text-yellow-500 w-5 h-5 mr-2" />;
|
||||||
|
|
||||||
const ext = name.split(".").pop().toLowerCase();
|
const ext = name.split(".").pop().toLowerCase();
|
||||||
switch (ext) {
|
switch (ext) {
|
||||||
case "txt":
|
case "txt":
|
||||||
@@ -74,44 +79,41 @@ const FileTable = ({ initialPath }) => {
|
|||||||
|
|
||||||
const fetchFiles = async () => {
|
const fetchFiles = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const res = await fetch(
|
||||||
`http://192.168.29.61:8080/api/hdfs/listFiles?hdfsPath=${currentPath}`
|
`${API_URL}/api/hdfs/listFiles?hdfsPath=${encodeURIComponent(
|
||||||
|
currentPath
|
||||||
|
)}`
|
||||||
);
|
);
|
||||||
const data = await response.json();
|
const data = await res.json();
|
||||||
|
// filter out indented children, only top-level entries
|
||||||
const filtered = data.filter(
|
const filtered = data.filter(
|
||||||
(entry) => entry.match(/^ */)[0].length === 0
|
(entry) => entry.match(/^ */)[0].length === 0
|
||||||
);
|
);
|
||||||
setFiles(filtered);
|
setFiles(filtered);
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Failed to fetch files:", error);
|
console.error("Failed to fetch files:", err);
|
||||||
setFiles([]);
|
setFiles([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteFileOrFolder = async (name, type, event) => {
|
const deleteFileOrFolder = async (name, type, e) => {
|
||||||
event.stopPropagation(); // Prevent row onClick from firing.
|
e.stopPropagation();
|
||||||
try {
|
try {
|
||||||
const hdfsPath =
|
const hdfsPath =
|
||||||
currentPath === "/" ? `/${name}` : `${currentPath}/${name}`;
|
currentPath === "/" ? `/${name}` : `${currentPath}/${name}`;
|
||||||
const encodedPath = encodeURIComponent(hdfsPath);
|
const encoded = encodeURIComponent(hdfsPath);
|
||||||
let deleteEndpoint = "";
|
const endpoint =
|
||||||
|
type === "File"
|
||||||
|
? `${API_URL}/api/hdfs/deleteFile?hdfsPath=${encoded}`
|
||||||
|
: `${API_URL}/api/hdfs/deleteFolder?hdfsPath=${encoded}`;
|
||||||
|
|
||||||
if (type === "File") {
|
const resp = await fetch(endpoint, { method: "DELETE" });
|
||||||
deleteEndpoint = `http://192.168.29.61:8080/api/hdfs/deleteFile?hdfsPath=${encodedPath}`;
|
if (!resp.ok) {
|
||||||
} else {
|
console.error("Deletion failed:", await resp.text());
|
||||||
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();
|
fetchFiles();
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error("Failed to delete file/folder:", error);
|
console.error("Failed to delete:", err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -134,53 +136,45 @@ const FileTable = ({ initialPath }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleFileDownload = async (hdfsPath, name, event) => {
|
const handleFileDownload = async (hdfsPath, name, event) => {
|
||||||
event.stopPropagation(); // Prevent row click (if any) for files.
|
event.stopPropagation(); // Prevent row click (if any)
|
||||||
try {
|
try {
|
||||||
const formData = new URLSearchParams();
|
const authToken = localStorage.getItem("token"); // Get JWT token from localStorage
|
||||||
formData.append("hdfsPath", hdfsPath);
|
|
||||||
formData.append("username", "kalas");
|
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
"http://192.168.29.61:8080/api/hdfs/downloadFile",
|
`${API_URL}/api/hdfs/downloadFile?hdfsEncPath=${hdfsPath}&localPath=${name}&username=${username}`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
Authorization: `Bearer ${authToken}`,
|
||||||
},
|
},
|
||||||
body: formData.toString(),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) throw new Error("Download failed");
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
throw new Error(`Download failed: ${errorText}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Extract filename from header OR fallback to name from path
|
// Extract filename from response headers or fallback to 'name'
|
||||||
const contentDisposition = response.headers.get("Content-Disposition");
|
const contentDisposition = response.headers.get("Content-Disposition");
|
||||||
let fileName = "downloaded_file";
|
let downloadedFileName = name;
|
||||||
|
|
||||||
if (contentDisposition && contentDisposition.includes("filename=")) {
|
if (contentDisposition && contentDisposition.includes("filename=")) {
|
||||||
const match = contentDisposition.match(
|
const match = contentDisposition.match(
|
||||||
/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
|
/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
|
||||||
);
|
);
|
||||||
if (match && match[1]) {
|
if (match) downloadedFileName = 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 blob = await response.blob();
|
||||||
const url = window.URL.createObjectURL(blob);
|
const blobUrl = window.URL.createObjectURL(blob);
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.href = url;
|
link.href = blobUrl;
|
||||||
link.download = fileName;
|
link.download = downloadedFileName;
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
link.remove();
|
link.remove();
|
||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(blobUrl);
|
||||||
|
fetchFiles();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Download failed:", error);
|
console.error("Download failed:", error);
|
||||||
alert("Something went wrong while downloading the file.");
|
alert("Something went wrong while downloading the file.");
|
||||||
@@ -201,6 +195,7 @@ const FileTable = ({ initialPath }) => {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table className="w-full text-sm text-left text-black">
|
<table className="w-full text-sm text-left text-black">
|
||||||
<thead className="text-xs uppercase bg-blue-50 text-blue-800 border-b border-blue-200">
|
<thead className="text-xs uppercase bg-blue-50 text-blue-800 border-b border-blue-200">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -208,6 +203,7 @@ const FileTable = ({ initialPath }) => {
|
|||||||
<th className="px-6 py-3">Actions</th>
|
<th className="px-6 py-3">Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{files.length === 0 ? (
|
{files.length === 0 ? (
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user