Update Khufu's file retrieval system
This commit is contained in:
parent
fe36970476
commit
79b381b302
10 changed files with 86 additions and 78 deletions
|
@ -8,10 +8,7 @@
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
"@fortawesome/react-fontawesome": "^0.1.14",
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"js-file-download": "^0.4.12",
|
||||||
"@testing-library/react": "^12.0.0",
|
|
||||||
"@testing-library/user-event": "^13.2.0",
|
|
||||||
"http-proxy-middleware": "^2.0.1",
|
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-axios": "^2.0.5",
|
"react-axios": "^2.0.5",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
|
|
@ -5,7 +5,8 @@ import "react-toastify/dist/ReactToastify.css";
|
||||||
//Local Imports
|
//Local Imports
|
||||||
import Stash from "./Stash";
|
import Stash from "./Stash";
|
||||||
//Constants
|
//Constants
|
||||||
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoiYmVjYWNjNjdhNmRjLTBlN2QtMDBlNi1jYmVhLWVhZGNlYmUxIiwiaWF0IjoxNjI3MTcxMDU1LCJleHAiOjE2Mjk3NjMwNTV9.zqiHrYnJlB7ozwjMnpgVUsBAt9vfLHLICFgWB0MguLA"
|
const token =
|
||||||
|
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoiYmVjYWNjNjdhNmRjLTBlN2QtMDBlNi1jYmVhLWVhZGNlYmUxIiwiaWF0IjoxNjI3MTcxMDU1LCJleHAiOjE2Mjk3NjMwNTV9.zqiHrYnJlB7ozwjMnpgVUsBAt9vfLHLICFgWB0MguLA";
|
||||||
localStorage.setItem("authToken", token);
|
localStorage.setItem("authToken", token);
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
|
@ -18,6 +19,7 @@ class App extends React.Component {
|
||||||
newestOnTop={false}
|
newestOnTop={false}
|
||||||
closeOnClick={true}
|
closeOnClick={true}
|
||||||
rtl={false}
|
rtl={false}
|
||||||
|
limit={3}
|
||||||
pauseOnFocusLoss
|
pauseOnFocusLoss
|
||||||
draggable
|
draggable
|
||||||
pauseOnHover={false}
|
pauseOnHover={false}
|
||||||
|
|
|
@ -11,26 +11,32 @@ import "./stash/scss/Stash.scss";
|
||||||
//Constants
|
//Constants
|
||||||
const filesUrl = `${serverAddress}/${serverUrls.GET.filesUrl}`;
|
const filesUrl = `${serverAddress}/${serverUrls.GET.filesUrl}`;
|
||||||
//Class
|
//Class
|
||||||
function getConfig() {
|
const getConfig = () => ({
|
||||||
var authToken = localStorage.getItem("authToken");
|
headers: {
|
||||||
console.log({ headers: { authorization: `Bearer ${authToken}` } });
|
authorization: `Bearer ${localStorage.getItem("authToken")}`,
|
||||||
return {
|
withCredentials: true,
|
||||||
headers: { authorization: `Bearer ${authToken}`, withCredentials: true },
|
},
|
||||||
};
|
});
|
||||||
}
|
|
||||||
function buildFilebox(file, index) {
|
const buildFilebox = (file, index) => ({
|
||||||
return {
|
file,
|
||||||
file,
|
selected: false,
|
||||||
selected: false,
|
filtered: true,
|
||||||
filtered: true,
|
position: index,
|
||||||
position: index,
|
});
|
||||||
};
|
const buildDownload = (name, total) => ({
|
||||||
}
|
name,
|
||||||
|
total,
|
||||||
|
completed: 0.01,
|
||||||
|
progress: 0.01,
|
||||||
|
});
|
||||||
|
|
||||||
class Stash extends React.Component {
|
class Stash extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
fileBoxes: {},
|
fileBoxes: {},
|
||||||
|
downloads: {},
|
||||||
contextMenu: null,
|
contextMenu: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -39,17 +45,13 @@ class Stash extends React.Component {
|
||||||
axios
|
axios
|
||||||
.get(filesUrl, getConfig())
|
.get(filesUrl, getConfig())
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 401) {
|
if (res.status === 401) return console.log("Would redirect to login");
|
||||||
console.log("Would redirect to login");
|
if (res.data === undefined || res.data.length === undefined)
|
||||||
return;
|
return toast.error("Error Loading Files");
|
||||||
}
|
|
||||||
if (res.data === undefined || res.data.length === undefined) {
|
|
||||||
toast.error("Error Loading Files");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var fileBoxes = {};
|
var fileBoxes = {};
|
||||||
res.data.forEach((file, index) => {
|
res.data.forEach((file, index) => {
|
||||||
fileBoxes[file.fileUuid] = buildFilebox(file, index);
|
fileBoxes[file._id] = buildFilebox(file, index);
|
||||||
});
|
});
|
||||||
this.setState({ fileBoxes });
|
this.setState({ fileBoxes });
|
||||||
})
|
})
|
||||||
|
@ -76,13 +78,29 @@ class Stash extends React.Component {
|
||||||
|
|
||||||
addFilebox(file) {
|
addFilebox(file) {
|
||||||
var fileBoxes = this.state.fileBoxes;
|
var fileBoxes = this.state.fileBoxes;
|
||||||
fileBoxes[file.fileUuid] = buildFilebox(
|
fileBoxes[file._id] = buildFilebox(file, Object.keys(fileBoxes).length);
|
||||||
file,
|
|
||||||
Object.keys(fileBoxes).length
|
|
||||||
);
|
|
||||||
this.setState({ fileBoxes });
|
this.setState({ fileBoxes });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startDownload(name, total) {
|
||||||
|
const downloads = this.state.downloads;
|
||||||
|
const key = `${Date.now()}-${name}`;
|
||||||
|
const download = buildDownload(name, total);
|
||||||
|
download.toast = toast.dark(name, {
|
||||||
|
progress: download.progress,
|
||||||
|
position: "bottom-right",
|
||||||
|
});
|
||||||
|
downloads[key] = download;
|
||||||
|
this.setState({ downloads });
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDownload(downloadId, completed, total) {
|
||||||
|
const downloads = this.state.downloads;
|
||||||
|
const progress = completed / total;
|
||||||
|
toast.update(downloads[downloadId].toast, { progress });
|
||||||
|
}
|
||||||
|
|
||||||
removeDriveContextMenu() {
|
removeDriveContextMenu() {
|
||||||
if (this.state.contextMenu !== null) this.setState({ contextMenu: null });
|
if (this.state.contextMenu !== null) this.setState({ contextMenu: null });
|
||||||
}
|
}
|
||||||
|
@ -118,9 +136,10 @@ class Stash extends React.Component {
|
||||||
fileBoxes={this.state.fileBoxes}
|
fileBoxes={this.state.fileBoxes}
|
||||||
fileBoxesChanged={this.fileBoxesChanged.bind(this)}
|
fileBoxesChanged={this.fileBoxesChanged.bind(this)}
|
||||||
getSelectedBoxes={this.getSelectedBoxes.bind(this)}
|
getSelectedBoxes={this.getSelectedBoxes.bind(this)}
|
||||||
|
startDownload={this.startDownload.bind(this)}
|
||||||
|
updateDownload={this.updateDownload.bind(this)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="stash">
|
<div className="stash">
|
||||||
<StashUpload
|
<StashUpload
|
||||||
addFilebox={this.addFilebox.bind(this)}
|
addFilebox={this.addFilebox.bind(this)}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
const { createProxyMiddleware } = require("http-proxy-middleware");
|
|
||||||
const { serverAddress } = require("./stash/api.json");
|
|
||||||
module.exports = (app) => {
|
|
||||||
app.use(
|
|
||||||
"/api",
|
|
||||||
createProxyMiddleware({
|
|
||||||
target: serverAddress,
|
|
||||||
changeOrigin: true,
|
|
||||||
logLevel: "silent",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -2,6 +2,7 @@ import React from "react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import FileDownload from "js-file-download";
|
||||||
import {
|
import {
|
||||||
faInfoCircle,
|
faInfoCircle,
|
||||||
faFileDownload,
|
faFileDownload,
|
||||||
|
@ -16,7 +17,6 @@ import { serverUrls, serverAddress } from "./api.json";
|
||||||
const downloadUrl = `${serverAddress}/${serverUrls.POST.downloadUrl}`;
|
const downloadUrl = `${serverAddress}/${serverUrls.POST.downloadUrl}`;
|
||||||
const deleteUrl = `${serverAddress}/${serverUrls.POST.deleteUrl}`;
|
const deleteUrl = `${serverAddress}/${serverUrls.POST.deleteUrl}`;
|
||||||
const publicUrl = `${serverAddress}/${serverUrls.POST.publicUrl}`;
|
const publicUrl = `${serverAddress}/${serverUrls.POST.publicUrl}`;
|
||||||
const rawUrl = `${serverAddress}/${serverUrls.GET.rawUrl}`;
|
|
||||||
|
|
||||||
function getConfig() {
|
function getConfig() {
|
||||||
var authToken = localStorage.getItem("authToken");
|
var authToken = localStorage.getItem("authToken");
|
||||||
|
@ -26,27 +26,19 @@ function getConfig() {
|
||||||
export default class StashContextMenu extends React.Component {
|
export default class StashContextMenu extends React.Component {
|
||||||
infoView() {
|
infoView() {
|
||||||
var selectedCount = this.props.getSelectedBoxes().length;
|
var selectedCount = this.props.getSelectedBoxes().length;
|
||||||
if (selectedCount === 1) return "View";
|
if (selectedCount > 0) return `${selectedCount} files selected`;
|
||||||
if (selectedCount > 1) return `${selectedCount} files selected`;
|
|
||||||
return "No Files Selected";
|
return "No Files Selected";
|
||||||
}
|
}
|
||||||
|
|
||||||
infoClick(e) {
|
|
||||||
const selectedBoxes = this.props.getSelectedBoxes();
|
|
||||||
if (selectedBoxes.length !== 1) return;
|
|
||||||
const file = selectedBoxes[0];
|
|
||||||
let win = window.open(`${rawUrl}?target=${file}`);
|
|
||||||
if (!win || win.closed || typeof win.closed == "undefined") {
|
|
||||||
window.location = `${rawUrl}?target=${file}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
downloadClick() {
|
downloadClick() {
|
||||||
const selectedBoxes = this.props.getSelectedBoxes();
|
const selectedBoxes = this.props.getSelectedBoxes();
|
||||||
//ZIPS ARE NOT SUPPORTED YET
|
//ZIPS ARE NOT SUPPORTED YET
|
||||||
if (selectedBoxes.length > 1)
|
if (selectedBoxes.length > 1)
|
||||||
return toast.error("Downloading multiple files is not yet supported!");
|
return toast.error("Downloading multiple files is not yet supported!");
|
||||||
else
|
return this.handleDownload(
|
||||||
return this.handleDownload(`${downloadUrl}?target=${selectedBoxes[0]}`);
|
`${downloadUrl}?target=${selectedBoxes[0]}`,
|
||||||
|
this.props.fileBoxes[selectedBoxes[0]].file
|
||||||
|
);
|
||||||
}
|
}
|
||||||
deleteClick() {
|
deleteClick() {
|
||||||
const selectedBoxes = this.props.getSelectedBoxes();
|
const selectedBoxes = this.props.getSelectedBoxes();
|
||||||
|
@ -69,19 +61,28 @@ export default class StashContextMenu extends React.Component {
|
||||||
toast.error("There was an issue making some files public!");
|
toast.error("There was an issue making some files public!");
|
||||||
let fileBoxes = this.props.fileBoxes;
|
let fileBoxes = this.props.fileBoxes;
|
||||||
selectedBoxes.forEach((selectedBoxId) => {
|
selectedBoxes.forEach((selectedBoxId) => {
|
||||||
if (!failedFiles.includes(selectedBoxId)) {
|
if (failedFiles.includes(selectedBoxId))
|
||||||
|
fileBoxes[selectedBoxId].selected = true;
|
||||||
|
else
|
||||||
fileBoxes[selectedBoxId].file.public = !fileBoxes[selectedBoxId].file
|
fileBoxes[selectedBoxId].file.public = !fileBoxes[selectedBoxId].file
|
||||||
.public;
|
.public;
|
||||||
} else {
|
|
||||||
fileBoxes[selectedBoxId].selected = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
this.props.fileBoxesChanged(fileBoxes);
|
this.props.fileBoxesChanged(fileBoxes);
|
||||||
}
|
}
|
||||||
handleDownload(url) {
|
handleDownload(url, file) {
|
||||||
let win = window.open(url);
|
const downloadName = `${file.date}-${file.name}`;
|
||||||
if (!win || win.closed || typeof win.closed == "undefined")
|
const config = getConfig();
|
||||||
window.location = url;
|
config.method = "GET";
|
||||||
|
config["Content-Type"] = "application/octet-stream";
|
||||||
|
config.responseType = "blob";
|
||||||
|
const downloadId = this.props.startDownload(file.name);
|
||||||
|
config.onDownloadProgress = (e) =>
|
||||||
|
this.props.updateDownload(downloadId, e.loaded, e.total);
|
||||||
|
axios.request(url, config).then((response) => {
|
||||||
|
if (response.status !== 200)
|
||||||
|
return toast.error("There was an error downloading that!");
|
||||||
|
FileDownload(response.data, downloadName);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Handles the response from the deleteClick()
|
* Handles the response from the deleteClick()
|
||||||
|
@ -95,11 +96,8 @@ export default class StashContextMenu extends React.Component {
|
||||||
if (res.status !== 200) toast.error("Error Deleting Some Files");
|
if (res.status !== 200) toast.error("Error Deleting Some Files");
|
||||||
let fileBoxes = this.props.fileBoxes;
|
let fileBoxes = this.props.fileBoxes;
|
||||||
selectedBoxes.forEach((selectedBoxId) => {
|
selectedBoxes.forEach((selectedBoxId) => {
|
||||||
if (!failedFiles.includes(selectedBoxId)) {
|
if (!failedFiles.includes(selectedBoxId)) delete fileBoxes[selectedBoxId];
|
||||||
delete fileBoxes[selectedBoxId];
|
else fileBoxes[selectedBoxId].selected = true;
|
||||||
} else {
|
|
||||||
fileBoxes[selectedBoxId].selected = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
this.props.fileBoxesChanged(fileBoxes);
|
this.props.fileBoxesChanged(fileBoxes);
|
||||||
}
|
}
|
||||||
|
@ -123,7 +121,7 @@ export default class StashContextMenu extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div className="drive-context-menu" style={this.styleCalc()}>
|
<div className="drive-context-menu" style={this.styleCalc()}>
|
||||||
<ul>
|
<ul>
|
||||||
<li onClick={this.infoClick.bind(this)}>
|
<li>
|
||||||
<FontAwesomeIcon icon={faInfoCircle} />
|
<FontAwesomeIcon icon={faInfoCircle} />
|
||||||
{this.infoView()}
|
{this.infoView()}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@import "global/colors", "global/fonts", "global/measurements",
|
@import "global/colors", "global/fonts", "global/measurements",
|
||||||
"global/animations";
|
"global/animations", "global/zindex";
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
4
src/stash/scss/global/_zindex.scss
Normal file
4
src/stash/scss/global/_zindex.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
$stashbarIndex: 200;
|
||||||
|
$contextMenuIndex: 300;
|
||||||
|
$fudIndex: 100;
|
||||||
|
$downloadsIndex: 100;
|
|
@ -6,7 +6,7 @@
|
||||||
background: lighten($sectionMenuOptions, 10%);
|
background: lighten($sectionMenuOptions, 10%);
|
||||||
box-shadow: 1px 3px 2px lighten ($sectionMenuOptions, 5%);
|
box-shadow: 1px 3px 2px lighten ($sectionMenuOptions, 5%);
|
||||||
color: $foreground;
|
color: $foreground;
|
||||||
z-index: 300;
|
z-index: $contextMenuIndex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: inherit;
|
max-width: inherit;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
|
|
@ -16,7 +16,7 @@ $actionButtonSize: 25px;
|
||||||
max-height: 250px;
|
max-height: 250px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
-webkit-transform: translate3d(0, 0, 0);
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
z-index: 100;
|
z-index: $fudIndex;
|
||||||
display: block;
|
display: block;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
.stashbar {
|
.stashbar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 200;
|
z-index: $stashbarIndex;
|
||||||
}
|
}
|
||||||
.stashbar-menu {
|
.stashbar-menu {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
Reference in a new issue