From a924abf4c18a3845dd6bcb0514802f513efbd247 Mon Sep 17 00:00:00 2001 From: Travis Vachon Date: Wed, 20 Dec 2023 07:22:07 -0800 Subject: [PATCH] feat: support multi file upload and directory wrapping (#615) Make backwards compatible API changes to support multi-file upload and directory wrapping. Also support directory selection, wrapping the wonky builtin API with something a little cleaner. Revive the multi file upload and uploads lists examples! --- examples/react/components/src/Uploader.tsx | 53 +++++--- .../react/multi-file-upload/.eslintrc.cjs | 20 +++ examples/react/multi-file-upload/.gitignore | 24 ++++ examples/react/multi-file-upload/README.md | 8 ++ examples/react/multi-file-upload/index.html | 13 ++ examples/react/multi-file-upload/package.json | 32 +++++ .../react/multi-file-upload/postcss.config.js | 6 + examples/react/multi-file-upload/src/App.tsx | 43 +++++++ .../react/multi-file-upload/src/index.css | 26 ++++ examples/react/multi-file-upload/src/main.jsx | 10 ++ .../multi-file-upload/tailwind.config.js | 13 ++ .../react/multi-file-upload/vite.config.js | 11 ++ examples/react/uploads-list/.eslintrc.cjs | 20 +++ examples/react/uploads-list/.gitignore | 24 ++++ examples/react/uploads-list/README.md | 8 ++ examples/react/uploads-list/index.html | 13 ++ examples/react/uploads-list/package.json | 33 +++++ examples/react/uploads-list/postcss.config.js | 6 + examples/react/uploads-list/src/App.tsx | 76 +++++++++++ examples/react/uploads-list/src/index.css | 26 ++++ examples/react/uploads-list/src/main.jsx | 10 ++ .../react/uploads-list/tailwind.config.js | 13 ++ examples/react/uploads-list/vite.config.js | 11 ++ .../playwright/src/multi-file-upload.spec.ts | 4 +- .../test/playwright/src/uploads-list.spec.ts | 4 +- packages/react/src/Uploader.tsx | 113 +++++++++++++--- packages/react/test/Uploader.spec.tsx | 87 ++++++++++++- pnpm-lock.yaml | 121 ++++++++++++++++++ 28 files changed, 779 insertions(+), 49 deletions(-) create mode 100644 examples/react/multi-file-upload/.eslintrc.cjs create mode 100644 examples/react/multi-file-upload/.gitignore create mode 100644 examples/react/multi-file-upload/README.md create mode 100644 examples/react/multi-file-upload/index.html create mode 100644 examples/react/multi-file-upload/package.json create mode 100644 examples/react/multi-file-upload/postcss.config.js create mode 100644 examples/react/multi-file-upload/src/App.tsx create mode 100644 examples/react/multi-file-upload/src/index.css create mode 100644 examples/react/multi-file-upload/src/main.jsx create mode 100644 examples/react/multi-file-upload/tailwind.config.js create mode 100644 examples/react/multi-file-upload/vite.config.js create mode 100644 examples/react/uploads-list/.eslintrc.cjs create mode 100644 examples/react/uploads-list/.gitignore create mode 100644 examples/react/uploads-list/README.md create mode 100644 examples/react/uploads-list/index.html create mode 100644 examples/react/uploads-list/package.json create mode 100644 examples/react/uploads-list/postcss.config.js create mode 100644 examples/react/uploads-list/src/App.tsx create mode 100644 examples/react/uploads-list/src/index.css create mode 100644 examples/react/uploads-list/src/main.jsx create mode 100644 examples/react/uploads-list/tailwind.config.js create mode 100644 examples/react/uploads-list/vite.config.js diff --git a/examples/react/components/src/Uploader.tsx b/examples/react/components/src/Uploader.tsx index ea228cc2..8ae8f1fd 100644 --- a/examples/react/components/src/Uploader.tsx +++ b/examples/react/components/src/Uploader.tsx @@ -9,14 +9,16 @@ function humanFileSize (bytes: number): string { interface UploadingProps { file?: File + files?: File[] storedDAGShards: CARMetadata[] uploadProgress: UploadProgress } -function Uploading ({ file, storedDAGShards, uploadProgress }: UploadingProps): ReactNode { +function Uploading ({ file, files, storedDAGShards, uploadProgress }: UploadingProps): ReactNode { + const fileName = ((files != null) && files.length > 1) ? 'your files' : file?.name return (
-

Uploading {file?.name}

+

Uploading {fileName}

{storedDAGShards?.map(({ cid, size }) => (

@@ -40,20 +42,22 @@ function Errored ({ error }: { error?: Error }): ReactNode { interface DoneProps { file?: File + files?: File[] dataCID?: AnyLink storedDAGShards: CARMetadata[] } -const Done = ({ file, dataCID, storedDAGShards }: DoneProps): ReactNode => { +const Done = ({ file, files, dataCID, storedDAGShards }: DoneProps): ReactNode => { const cidString: string = dataCID?.toString() ?? '' + const fileName = ((files != null) && files.length > 1) ? 'your files' : file?.name return (

-

Done!

-

{cidString}

-

View {file?.name} on IPFS Gateway.

-

Chunks ({storedDAGShards.length}):

+

Done!

+

{cidString}

+

View {fileName} on IPFS Gateway.

+

Chunks ({storedDAGShards.length}):

{storedDAGShards.map(({ cid, size }) => ( -

+

{cid.toString()} ({size} bytes)

))} @@ -62,16 +66,16 @@ const Done = ({ file, dataCID, storedDAGShards }: DoneProps): ReactNode => { } function UploaderConsole (): ReactNode { - const [{ status, file, error, dataCID, storedDAGShards, uploadProgress }] = + const [{ status, file, files, error, dataCID, storedDAGShards, uploadProgress }] = useUploader() switch (status) { case UploadStatus.Uploading: { - return + return } case UploadStatus.Succeeded: { return ( - + ) } case UploadStatus.Failed: { @@ -84,19 +88,21 @@ function UploaderConsole (): ReactNode { } function UploaderContents (): ReactNode { - const [{ status, file }] = useUploader() + const [{ status, file, files }] = useUploader() const hasFile = file !== undefined if (status === UploadStatus.Idle) { return hasFile ? ( <> -
-
- {file.name} - - {humanFileSize(file.size)} - -
+
+ {files?.map((f, i) => ( +
+ {f.name} + + {humanFileSize(f.size)} + +
+ ))}