diff --git a/packages/api/package.json b/packages/api/package.json index fd66f5cca..c50faa68e 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -18,6 +18,7 @@ "exceljs": "^4.0.1", "express": "^4.17.1", "express-basic-auth": "^1.2.0", + "express-fileupload": "^1.2.0", "find-free-port": "^2.0.0", "fs-extra": "^8.1.0", "http": "^0.0.0", diff --git a/packages/api/src/controllers/uploads.js b/packages/api/src/controllers/uploads.js new file mode 100644 index 000000000..d593bf104 --- /dev/null +++ b/packages/api/src/controllers/uploads.js @@ -0,0 +1,26 @@ +const path = require('path'); +const { uploadsdir } = require('../utility/directories'); +const uuidv1 = require('uuid/v1'); + +module.exports = { + upload_meta: { + method: 'post', + raw: true, + }, + upload(req, res) { + const { data } = req.files || {}; + if (!data) { + res.json(null); + return; + } + const uploadName = uuidv1(); + const filePath = path.join(uploadsdir(), uploadName); + console.log(`Uploading file ${data.name}, size=${data.size}`); + data.mv(filePath, () => { + res.json({ + originalName: data.name, + uploadName, + }); + }); + }, +}; diff --git a/packages/api/src/main.js b/packages/api/src/main.js index de0ece6bf..bafaf0c59 100644 --- a/packages/api/src/main.js +++ b/packages/api/src/main.js @@ -1,6 +1,7 @@ const express = require('express'); const basicAuth = require('express-basic-auth'); const bodyParser = require('body-parser'); +const fileUpload = require('express-fileupload'); const http = require('http'); const cors = require('cors'); const io = require('socket.io'); @@ -21,6 +22,7 @@ const jsldata = require('./controllers/jsldata'); const config = require('./controllers/config'); const files = require('./controllers/files'); const archive = require('./controllers/archive'); +const uploads = require('./controllers/uploads'); const { rundir } = require('./utility/directories'); @@ -47,6 +49,13 @@ function start(argument = null) { app.use(cors()); app.use(bodyParser.json({ limit: '50mb' })); + app.use( + '/uploads', + fileUpload({ + limits: { fileSize: 4 * 1024 * 1024 }, + }) + ); + useController(app, '/connections', connections); useController(app, '/server-connections', serverConnections); useController(app, '/database-connections', databaseConnections); @@ -57,6 +66,7 @@ function start(argument = null) { useController(app, '/config', config); useController(app, '/files', files); useController(app, '/archive', archive); + useController(app, '/uploads', uploads); if (process.env.PAGES_DIRECTORY) { app.use('/pages', express.static(process.env.PAGES_DIRECTORY)); diff --git a/packages/web/package.json b/packages/web/package.json index 891979e11..7802975bc 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -19,6 +19,7 @@ "react": "^16.12.0", "react-ace": "^8.0.0", "react-dom": "^16.12.0", + "react-dropzone": "^11.2.3", "react-json-view": "^1.19.1", "react-modal": "^3.11.1", "react-scripts": "3.3.0", diff --git a/packages/web/src/Screen.js b/packages/web/src/Screen.js index 86149a3f3..a2ce0db8f 100644 --- a/packages/web/src/Screen.js +++ b/packages/web/src/Screen.js @@ -3,6 +3,7 @@ import React from 'react'; import theme from './theme'; import styled from 'styled-components'; +import { useDropzone } from 'react-dropzone'; import TabsPanel from './TabsPanel'; import TabContent from './TabContent'; import WidgetIconPanel from './widgets/WidgetIconPanel'; @@ -12,6 +13,7 @@ import ToolBar from './widgets/Toolbar'; import StatusBar from './widgets/StatusBar'; import { useSplitterDrag, HorizontalSplitHandle } from './widgets/Splitter'; import { ModalLayer } from './modals/showModal'; +import resolveApi from './utility/resolveApi'; const BodyDiv = styled.div` position: fixed; @@ -96,6 +98,15 @@ const ScreenHorizontalSplitHandle = styled(HorizontalSplitHandle)` bottom: ${theme.statusBar.height}px; `; +const DragAndDropTarget = styled.div` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: red; +`; + export default function Screen() { const currentWidget = useCurrentWidget(); const leftPanelWidth = useLeftPanelWidth(); @@ -105,8 +116,46 @@ export default function Screen() { : theme.widgetMenu.iconSize; const toolbarPortalRef = React.useRef(); const onSplitDown = useSplitterDrag('clientX', (diff) => setLeftPanelWidth((v) => v + diff)); + + const onDrop = React.useCallback((files) => { + // Do something with the files + console.log('FILES', files); + files.forEach(async (file) => { + if (parseInt(file.size, 10) >= 4 * 1024 * 1024) { + // to big file + return; + } + + const formData = new FormData(); + formData.append('data', file); + + const fetchOptions = { + method: 'POST', + body: formData, + }; + + const apiBase = resolveApi(); + const resp = await fetch(`${apiBase}/uploads/upload`, fetchOptions); + const event = await resp.json(); + + return event; + + // const reader = new FileReader(); + + // reader.onabort = () => console.log('file reading was aborted'); + // reader.onerror = () => console.log('file reading has failed'); + // reader.onload = () => { + // // Do whatever you want with the file contents + // const binaryStr = reader.result; + // console.log(binaryStr); + // }; + // reader.readAsArrayBuffer(file); + }); + }, []); + const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop }); + return ( - <> +