From 14f983828bb7cfa93919af2ebfb4764413fc90fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABlann=20Barciet?= Date: Thu, 22 Oct 2020 20:17:02 +0200 Subject: [PATCH 1/3] add upload openAPI file button --- frontend/src/views/Apps.jsx | 61 +++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx index 1245d15f..d5f0cddc 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, useRef } from 'react'; import { useInterval } from 'react-powerhooks'; @@ -134,6 +134,8 @@ const Apps = (props) => { const [cursearch, setCursearch] = React.useState("") const [sharingConfiguration, setSharingConfiguration] = React.useState("you") + const upload = useRef(null); + const { start, stop } = useInterval({ duration: 5000, startImmediate: false, @@ -1198,6 +1200,25 @@ const Apps = (props) => { setLoadAppsModalOpen(false) } + const uploadFile = (e) => { + const file = e.target.files[0]; + const reader = new FileReader(); + + reader.addEventListener('load', (e) => { + const content = e.target.result; + setOpenApiData(content); + }); + + reader.readAsText(file); + }; + + useEffect(() => { + if(openApiData.length > 0) { + setOpenApiError(''); + validateOpenApi(openApiData); + } + }, [openApiData]); + const deleteModal = deleteModalOpen ? {
https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/json/uber.json */} - Or paste the YAML or JSON specification - 0} color="primary" onClick={() => { - setOpenApiError("") - validateOpenApi(openApiData) - }}>Validate OpenAPI - }} - onChange={e => setOpenApiData(e.target.value)} - helperText={Must point to a version 2 or 3 specification.} - placeholder="OpenAPI text" - fullWidth - /> +

Or upload a YAML or JSON specification

+ + {errorText} From 57d4fa77191d0432ac55dc0e47133f47320dce18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABlann=20Barciet?= Date: Thu, 22 Oct 2020 22:34:39 +0200 Subject: [PATCH 2/3] add dropzone of OpenAPI files --- frontend/src/components/Dropzone.js | 84 +++++++++++++++++++++++++++++ frontend/src/views/Apps.jsx | 61 ++++++++++++--------- 2 files changed, 120 insertions(+), 25 deletions(-) create mode 100644 frontend/src/components/Dropzone.js 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 d5f0cddc..fe2fd6ad 100644 --- a/frontend/src/views/Apps.jsx +++ b/frontend/src/views/Apps.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } 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,7 +135,8 @@ const Apps = (props) => { const [cursearch, setCursearch] = React.useState("") const [sharingConfiguration, setSharingConfiguration] = React.useState("you") - const upload = useRef(null); + const [isDropzone, setIsDropzone] = React.useState(false); + const upload = React.useRef(null); const { start, stop } = useInterval({ duration: 5000, @@ -179,7 +181,6 @@ const Apps = (props) => { color: "#ffffff", width: "100%", display: "flex", - margin: 20, } const paperAppStyle = { @@ -792,8 +793,37 @@ 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); + }); + + 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}>
@@ -905,7 +935,7 @@ const Apps = (props) => {
-
+ : null @@ -1176,7 +1206,7 @@ const Apps = (props) => { }) .then((responseJson) => { if (responseJson.success) { - setAppValidation(responseJson.id) + setAppValidation(responseJson.id); } else { if (responseJson.reason !== undefined) { setOpenApiError(responseJson.reason) @@ -1200,25 +1230,6 @@ const Apps = (props) => { setLoadAppsModalOpen(false) } - const uploadFile = (e) => { - const file = e.target.files[0]; - const reader = new FileReader(); - - reader.addEventListener('load', (e) => { - const content = e.target.result; - setOpenApiData(content); - }); - - reader.readAsText(file); - }; - - useEffect(() => { - if(openApiData.length > 0) { - setOpenApiError(''); - validateOpenApi(openApiData); - } - }, [openApiData]); - const deleteModal = deleteModalOpen ? Date: Fri, 23 Oct 2020 02:14:52 +0200 Subject: [PATCH 3/3] #182: Added error popup if bad OpenAPI --- frontend/src/views/Apps.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx index fe2fd6ad..b30f47c5 100644 --- a/frontend/src/views/Apps.jsx +++ b/frontend/src/views/Apps.jsx @@ -803,7 +803,8 @@ const Apps = (props) => { const content = e.target.result; setOpenApiData(content); setIsDropzone(isDropzone); - }); + setOpenApiModal(true) + }) reader.readAsText(files[0]); }; @@ -1359,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 ?