From 32cba38899fcfb10b963b73f911433b3b8c832f7 Mon Sep 17 00:00:00 2001
From: 4nalog <88684372+4nalog@users.noreply.github.com>
Date: Sat, 25 Feb 2023 01:09:37 +0530
Subject: [PATCH] feat: add draggable file upload component (#690)
* feat: add draggable file upload component
Signed-off-by: 4nalog <4nalog@protonmail.com>
* chore: add support for listening to file changes
Signed-off-by: 4nalog <4nalog@protonmail.com>
* refactor: extensible file upload input
Signed-off-by: 4nalog <4nalog@protonmail.com>
* refactor: rename component
Signed-off-by: 4nalog <4nalog@protonmail.com>
* chore: fix file upload props
Signed-off-by: 4nalog <4nalog@protonmail.com>
* chore: add comments for file upload component options
Signed-off-by: 4nalog <4nalog@protonmail.com>
---------
Signed-off-by: 4nalog <4nalog@protonmail.com>
---
packages/console/package.json | 4 +-
.../components/common/FileUpload/FileItem.tsx | 50 +++++++++++
.../common/FileUpload/FileUpload.tsx | 85 +++++++++++++++++++
yarn.lock | 47 ++++++++++
4 files changed, 185 insertions(+), 1 deletion(-)
create mode 100644 packages/console/src/components/common/FileUpload/FileItem.tsx
create mode 100644 packages/console/src/components/common/FileUpload/FileUpload.tsx
diff --git a/packages/console/package.json b/packages/console/package.json
index 741447e1c..95e572196 100644
--- a/packages/console/package.json
+++ b/packages/console/package.json
@@ -1,6 +1,6 @@
{
"name": "@flyteorg/console",
- "version": "0.0.10",
+ "version": "0.0.11",
"description": "Flyteconsole main app module",
"main": "./dist/index.js",
"module": "./lib/index.js",
@@ -93,6 +93,7 @@
"prop-types": "15.6.0",
"query-string": "^6.5.0",
"react-chartjs-2": "^4.3.1",
+ "react-dropzone": "^14.2.3",
"react-flow-renderer": "10.3.8",
"react-ga4": "^1.4.1",
"react-intersection-observer": "^8.25.1",
@@ -120,6 +121,7 @@
"@types/pure-render-decorator": "^0.2.27",
"@types/react": "^16.9.34",
"@types/react-dom": "^16.9.7",
+ "@types/react-dropzone": "^5.1.0",
"@types/react-virtualized": "^9.21.4",
"@types/serve-static": "^1.7.31",
"@types/shallowequal": "^0.2.3"
diff --git a/packages/console/src/components/common/FileUpload/FileItem.tsx b/packages/console/src/components/common/FileUpload/FileItem.tsx
new file mode 100644
index 000000000..f9b14ce9a
--- /dev/null
+++ b/packages/console/src/components/common/FileUpload/FileItem.tsx
@@ -0,0 +1,50 @@
+import { makeStyles, Theme } from '@material-ui/core';
+import { Clear, Done } from '@material-ui/icons';
+import React from 'react';
+
+const useStyles = makeStyles((theme: Theme) => ({
+ container: {
+ background: theme.palette.grey[100],
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ gap: '8px',
+ alignItems: 'center',
+ width: '100%',
+ padding: theme.spacing(1, 0.5),
+ fontSize: 12,
+ },
+ icon: {
+ color: theme.palette.success.main,
+ },
+ fileName: {
+ flex: 1,
+ textAlign: 'left',
+ },
+}));
+
+interface Props {
+ file: File;
+ remove: () => void;
+}
+
+function FileItem({ file, remove }: Props) {
+ const styles = useStyles();
+
+ return (
+
+
+
{file.name}
+
{
+ e.preventDefault();
+ e.stopPropagation();
+
+ remove();
+ }}
+ />
+
+ );
+}
+
+export default FileItem;
diff --git a/packages/console/src/components/common/FileUpload/FileUpload.tsx b/packages/console/src/components/common/FileUpload/FileUpload.tsx
new file mode 100644
index 000000000..7ab6269e5
--- /dev/null
+++ b/packages/console/src/components/common/FileUpload/FileUpload.tsx
@@ -0,0 +1,85 @@
+import { makeStyles, Theme } from '@material-ui/core';
+import React from 'react';
+import { DropzoneProps, useDropzone } from 'react-dropzone';
+import FileItem from './FileItem';
+
+const useStyles = makeStyles((theme: Theme) => ({
+ container: {
+ margin: 'auto',
+ maxWidth: '536px',
+ color: theme.palette.grey[400],
+ cursor: 'pointer',
+ },
+ uploadContainer: {
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ gap: theme.spacing(0.5),
+ padding: theme.spacing(4, 3),
+ border: `0.5px dashed ${theme.palette.divider}`,
+ borderRadius: '4px',
+ },
+ filesContainer: {
+ width: '100%',
+ },
+ highlight: {
+ color: theme.palette.primary.main,
+ },
+}));
+
+/**
+ * For a list of available options, see https://react-dropzone.js.org/
+ */
+export interface FileUploadProps extends DropzoneProps {
+ files: File[];
+ setFiles: React.Dispatch>;
+ helpText?: React.ReactNode;
+}
+
+export function FileUpload({
+ files,
+ setFiles,
+ helpText,
+ ...options
+}: FileUploadProps) {
+ const styles = useStyles();
+ const { getRootProps, getInputProps } = useDropzone({
+ ...options,
+ onDrop: (acceptedFiles, fileRejections, event) => {
+ setFiles(acceptedFiles);
+ options?.onDrop?.(acceptedFiles, fileRejections, event);
+ },
+ });
+
+ const removeFile = (fileIdx: number) => {
+ setFiles(files => files.filter((_, idx) => idx !== fileIdx));
+ };
+
+ const ctaText = files.length ? 'Replace file' : 'Upload a file';
+
+ return (
+
+
+
+ {files.map((file, idx) => (
+ removeFile(idx)}
+ key={file.name}
+ />
+ ))}
+
+
+ {ctaText} or drag and drop
+ here
+
+ {helpText}
+
+
+
+ );
+}
+
+export default FileUpload;
diff --git a/yarn.lock b/yarn.lock
index 270d73183..d407696a7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2138,6 +2138,7 @@ __metadata:
"@types/pure-render-decorator": ^0.2.27
"@types/react": ^16.9.34
"@types/react-dom": ^16.9.7
+ "@types/react-dropzone": ^5.1.0
"@types/react-virtualized": ^9.21.4
"@types/serve-static": ^1.7.31
"@types/shallowequal": ^0.2.3
@@ -2168,6 +2169,7 @@ __metadata:
prop-types: 15.6.0
query-string: ^6.5.0
react-chartjs-2: ^4.3.1
+ react-dropzone: ^14.2.3
react-flow-renderer: 10.3.8
react-ga4: ^1.4.1
react-intersection-observer: ^8.25.1
@@ -5520,6 +5522,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/react-dropzone@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "@types/react-dropzone@npm:5.1.0"
+ dependencies:
+ react-dropzone: "*"
+ checksum: 2b68fcf0153fb00e17088907490b823b6d81a29a02e615f820e347df2546f9318c5f025eeb33d575c648d01a14e55a19e528c32907608b5a7f727ff0e96b3923
+ languageName: node
+ linkType: hard
+
"@types/react-test-renderer@npm:>=16.9.0":
version: 18.0.0
resolution: "@types/react-test-renderer@npm:18.0.0"
@@ -7015,6 +7026,13 @@ __metadata:
languageName: node
linkType: hard
+"attr-accept@npm:^2.2.2":
+ version: 2.2.2
+ resolution: "attr-accept@npm:2.2.2"
+ checksum: 496f7249354ab53e522510c1dc8f67a1887382187adde4dc205507d2f014836a247073b05e9d9ea51e2e9c7f71b0d2aa21730af80efa9af2d68303e5f0565c4d
+ languageName: node
+ linkType: hard
+
"autoprefixer@npm:^9.8.6":
version: 9.8.8
resolution: "autoprefixer@npm:9.8.8"
@@ -11370,6 +11388,15 @@ __metadata:
languageName: node
linkType: hard
+"file-selector@npm:^0.6.0":
+ version: 0.6.0
+ resolution: "file-selector@npm:0.6.0"
+ dependencies:
+ tslib: ^2.4.0
+ checksum: 7d051b6e5d793f3c6e2ab287ba5e7c2c6a0971bccc9d56e044c8047ba483e18f60fc0b5771c951dc707c0d15f4f36ccb4f1f1aaf385d21ec8f7700dadf8325ba
+ languageName: node
+ linkType: hard
+
"file-system-cache@npm:^1.0.5":
version: 1.1.0
resolution: "file-system-cache@npm:1.1.0"
@@ -18516,6 +18543,19 @@ __metadata:
languageName: node
linkType: hard
+"react-dropzone@npm:*, react-dropzone@npm:^14.2.3":
+ version: 14.2.3
+ resolution: "react-dropzone@npm:14.2.3"
+ dependencies:
+ attr-accept: ^2.2.2
+ file-selector: ^0.6.0
+ prop-types: ^15.8.1
+ peerDependencies:
+ react: ">= 16.8 || 18.0.0"
+ checksum: 174b744d5ca898cf3d84ec1aeb6cef5211c446697e45dc8ece8287a03d291f8d07253206d5a1247ef156fd385d65e7de666d4d5c2986020b8543b8f2434e8b40
+ languageName: node
+ linkType: hard
+
"react-element-to-jsx-string@npm:^14.3.4":
version: 14.3.4
resolution: "react-element-to-jsx-string@npm:14.3.4"
@@ -21273,6 +21313,13 @@ __metadata:
languageName: node
linkType: hard
+"tslib@npm:^2.4.0":
+ version: 2.5.0
+ resolution: "tslib@npm:2.5.0"
+ checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1
+ languageName: node
+ linkType: hard
+
"tsutils@npm:^3.21.0":
version: 3.21.0
resolution: "tsutils@npm:3.21.0"