diff --git a/frontend/src/components/Dropzone.js b/frontend/src/components/Dropzone.js
new file mode 100644
index 00000000..621e74b5
--- /dev/null
+++ b/frontend/src/components/Dropzone.js
@@ -0,0 +1,84 @@
+import React, { useRef, useState } from 'react';
+import { useEffect } from 'react';
+import BackupIcon from '@material-ui/icons/Backup';
+
+const dragOverStyle = {
+ backgroundColor: 'rgba(0,0,0,0.8)',
+ border: '5px dashed white',
+ borderRadius: '8px',
+ width: '100%',
+ height: '100%',
+ position: 'absolute',
+ overflow: 'hidden',
+ zIndex: 100,
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center'
+};
+
+const Dropzone = ({ children, style, onDrop }) => {
+ const dropzoneRef = useRef(null);
+ const [dragging, setDragging] = useState(false);
+
+ let dragCounter = 0;
+
+ const handleDragOver = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ };
+
+ const handleDragEnter = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ dragCounter++;
+ if (e.dataTransfer.items && e.dataTransfer.items.length > 0)
+ setDragging(true);
+ };
+
+ const handleDragLeave = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ dragCounter--;
+ if (dragCounter === 0) setDragging(false);
+ };
+
+ const handleDrop = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ setDragging(false);
+ if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
+ onDrop(e);
+ e.dataTransfer.clearData();
+ dragCounter = 0;
+ }
+ };
+
+ useEffect(() => {
+ if (!dropzoneRef.current) return;
+
+ dropzoneRef.current.addEventListener('dragover', handleDragOver);
+ dropzoneRef.current.addEventListener('dragenter', handleDragEnter);
+ dropzoneRef.current.addEventListener('dragleave', handleDragLeave);
+ dropzoneRef.current.addEventListener('drop', handleDrop);
+
+ return () => {
+ dropzoneRef.current.removeEventListener('dragover', handleDragOver);
+ dropzoneRef.current.removeEventListener('dragenter', handleDragEnter);
+ dropzoneRef.current.removeEventListener('dragleave', handleDragLeave);
+ dropzoneRef.current.removeEventListener('drop', handleDrop);
+ };
+ }, [dropzoneRef]);
+
+ return (
+
+ {dragging && (
+
+
+
+ )}
+ {children}
+
+ );
+};
+
+export default Dropzone;
diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx
index ccc56c87..7d159d04 100644
--- a/frontend/src/views/Apps.jsx
+++ b/frontend/src/views/Apps.jsx
@@ -1,4 +1,4 @@
-import React, { useEffect} from 'react';
+import React, { useEffect } from 'react';
import { useInterval } from 'react-powerhooks';
@@ -37,6 +37,7 @@ import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import CircularProgress from '@material-ui/core/CircularProgress';
+import Dropzone from '../components/Dropzone';
const surfaceColor = "#27292D"
const inputColor = "#383B40"
@@ -134,6 +135,9 @@ const Apps = (props) => {
const [cursearch, setCursearch] = React.useState("")
const [sharingConfiguration, setSharingConfiguration] = React.useState("you")
+ const [isDropzone, setIsDropzone] = React.useState(false);
+ const upload = React.useRef(null);
+
const { start, stop } = useInterval({
duration: 5000,
startImmediate: false,
@@ -177,7 +181,6 @@ const Apps = (props) => {
color: "#ffffff",
width: "100%",
display: "flex",
- margin: 20,
}
const paperAppStyle = {
@@ -790,8 +793,38 @@ const Apps = (props) => {
//}
}
+ const uploadFile = (e) => {
+ const isDropzone = e.dataTransfer?.files.length > 0;
+ const files = isDropzone ? e.dataTransfer.files : e.target.files;
+
+ const reader = new FileReader();
+
+ reader.addEventListener('load', (e) => {
+ const content = e.target.result;
+ setOpenApiData(content);
+ setIsDropzone(isDropzone);
+ setOpenApiModal(true)
+ })
+
+ reader.readAsText(files[0]);
+ };
+
+ useEffect(() => {
+ if (openApiData.length > 0) {
+ setOpenApiError('');
+ validateOpenApi(openApiData);
+ }
+ }, [openApiData]);
+
+ useEffect(() => {
+ if (appValidation && isDropzone) {
+ redirectOpenApi();
+ setIsDropzone(false);
+ }
+ }, [appValidation, isDropzone]);
+
const appView = isLoggedIn ?
- 1366 ? 1366 : 1200, margin: "auto",}}>
+
1366 ? 1366 : 1200, margin: "auto", padding: 20 }} onDrop={uploadFile}>
@@ -903,7 +936,7 @@ const Apps = (props) => {
-
+
:
null
@@ -1174,7 +1207,7 @@ const Apps = (props) => {
})
.then((responseJson) => {
if (responseJson.success) {
- setAppValidation(responseJson.id)
+ setAppValidation(responseJson.id);
} else {
if (responseJson.reason !== undefined) {
setOpenApiError(responseJson.reason)
@@ -1327,7 +1360,7 @@ const Apps = (props) => {
: null
- const errorText = openApiError.length > 0 ? Error: {openApiError}
: null
+ const errorText = openApiError.length > 0 ? Error: {openApiError}
: null
const modalView = openApiModal ?