Use async api for upload

This commit is contained in:
Arnaud 2024-09-13 20:49:40 +02:00
parent 2330d34546
commit 88b2d8486a
No known key found for this signature in database
GPG Key ID: 69D6CE281FCAE663
6 changed files with 131 additions and 143 deletions

124
package-lock.json generated
View File

@ -41,7 +41,7 @@
"node": ">=18"
},
"peerDependencies": {
"@codex-storage/sdk-js": "0.0.1",
"@codex-storage/sdk-js": "0.0.2",
"@tanstack/react-query": "^5.51.24",
"react": "^18.3.1",
"react-dom": "^18.3.1"
@ -1940,9 +1940,9 @@
}
},
"node_modules/@codex-storage/sdk-js": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@codex-storage/sdk-js/-/sdk-js-0.0.1.tgz",
"integrity": "sha512-Zhc7sBXjNKSEjRkqfSy9NG9r5gCulKiGpDZ8t19INVPJpn0VWhjqMSQLDYcCWdxkeBz/EJPS3+ktJ5kCieeeAQ==",
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@codex-storage/sdk-js/-/sdk-js-0.0.2.tgz",
"integrity": "sha512-LCzEPZFOqjPz+cC03eyzp7YlfBLe6ixuG0Q3wt4RXw4Ib+iH3lqrTE1a2c4g71OVQicooXoyYZWkJpZabdmaNQ==",
"peer": true,
"dependencies": {
"valibot": "^0.36.0"
@ -4353,21 +4353,6 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
},
"node_modules/body-parser/node_modules/qs": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dev": true,
"dependencies": {
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"dev": true,
@ -5455,9 +5440,9 @@
}
},
"node_modules/express": {
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz",
"integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==",
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
"integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
"dev": true,
"dependencies": {
"accepts": "~1.3.8",
@ -5472,7 +5457,7 @@
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.3",
@ -5481,11 +5466,11 @@
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7",
"qs": "6.11.0",
"qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.19.0",
"serve-static": "1.16.0",
"serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@ -5595,12 +5580,13 @@
}
},
"node_modules/finalhandler": {
"version": "1.2.0",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
@ -5613,16 +5599,27 @@
},
"node_modules/finalhandler/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/finalhandler/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"dev": true,
"engines": {
"node": ">= 0.8"
}
},
"node_modules/finalhandler/node_modules/ms": {
"version": "2.0.0",
"dev": true,
"license": "MIT"
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
},
"node_modules/find-cache-dir": {
"version": "3.3.2",
@ -7380,8 +7377,9 @@
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
@ -7700,12 +7698,12 @@
}
},
"node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dev": true,
"dependencies": {
"side-channel": "^1.0.4"
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@ -8239,63 +8237,27 @@
"dev": true
},
"node_modules/serve-static": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz",
"integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==",
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dev": true,
"dependencies": {
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.18.0"
"send": "0.19.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/serve-static/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/serve-static/node_modules/debug/node_modules/ms": {
"node_modules/serve-static/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
},
"node_modules/serve-static/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
"node_modules/serve-static/node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"dev": true,
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
"node": ">= 0.8"
}
},
"node_modules/set-function-length": {

View File

@ -35,7 +35,7 @@
"lucide-react": "^0.428.0"
},
"peerDependencies": {
"@codex-storage/sdk-js": "0.0.1",
"@codex-storage/sdk-js": "0.0.2",
"@tanstack/react-query": "^5.51.24",
"react": "^18.3.1",
"react-dom": "^18.3.1"

View File

@ -60,7 +60,7 @@ type Props = {
* If not provider is passed, the cid returned will be empty.
* Default value: provider returning random cid.
*/
provider?: () => Promise<CodexData["upload"]>;
codexData: CodexData;
/**
* If true, the upload will run in a separate web worker.
@ -81,21 +81,6 @@ type Props = {
style?: CustomStyleCSS;
};
const defaultProvider = () =>
Promise.resolve(
(_: File, onProgress: (loaded: number, total: number) => void) => {
onProgress(100, 100);
return Promise.resolve({
abort: () => {},
result: Promise.resolve({
error: false,
data: Date.now().toString(),
}),
} satisfies UploadResponse);
}
);
export function Upload({
onMouseEnter,
onMouseLeave,
@ -105,7 +90,7 @@ export function Upload({
editable = true,
onDeleteItem,
onSuccess,
provider = defaultProvider,
codexData,
// useWorker = !!window.Worker,
}: Props) {
const { deleteFile, files, uploadFiles, warning } = useUploadStategy(
@ -188,7 +173,7 @@ export function Upload({
onClose={() => onClose(id)}
id={id}
onSuccess={onSuccess}
provider={provider}
codexData={codexData}
// useWorker={useWorker}
/>
))}

View File

@ -23,7 +23,7 @@ type UploadFileProps = {
onClose: (id: string) => void;
id: string;
onSuccess: ((cid: string, file: File) => void) | undefined;
provider: () => Promise<CodexData["upload"]>;
codexData: CodexData;
// useWorker: boolean;
};
@ -121,7 +121,7 @@ export function UploadFile({
onClose,
id,
onSuccess,
provider,
codexData,
// useWorker,
}: UploadFileProps) {
const abort = useRef<(() => void) | null>(null);
@ -138,8 +138,8 @@ export function UploadFile({
const { mutateAsync } = useMutation({
mutationKey: ["upload"],
mutationFn: (file: File) => {
return provider()
.then((upload) => upload(file, onProgress))
return codexData
.upload(file, onProgress)
.then((res) => {
abort.current = res.abort;
return res.result;
@ -152,7 +152,6 @@ export function UploadFile({
},
onError: (error) => {
worker.current?.terminate();
// TODO report to Sentry
dispatch({ type: "error", error: error.message });
},
onSuccess: (cid: string) => {
@ -242,7 +241,7 @@ export function UploadFile({
// } else {
// mutateAsync(file);
// }
}, [file, mutateAsync, onInternalSuccess, provider]);
}, [file, mutateAsync, onInternalSuccess, codexData]);
const onCancel = () => {
if (worker.current) {

View File

@ -1,9 +1,10 @@
import type { Meta } from "@storybook/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { UploadResponse } from "@codex-storage/sdk-js";
import { Codex, CodexData, UploadResponse } from "@codex-storage/sdk-js";
import { Upload } from "../src/components/Upload/Upload";
import { fn } from "@storybook/test";
import "./Upload.stories.css";
import { CodexDataSdk, CodexDataSlowSdk } from "./sdk";
const meta = {
title: "Advanced/Upload",
@ -42,50 +43,18 @@ type Props = {
const Template = (p: Props) => {
return (
<QueryClientProvider client={queryClient}>
{<Upload useWorker={false} multiple {...p} />}
{<Upload multiple {...p} codexData={CodexDataSdk} />}
</QueryClientProvider>
);
};
export const Multiple = Template.bind({});
const slowProvider = () =>
Promise.resolve(
(_: File, onProgress: (loaded: number, total: number) => void) => {
return new Promise<UploadResponse>((resolve) => {
let timeout: number;
resolve({
abort: () => {
window.clearInterval(timeout);
},
result: new Promise((resolve) => {
let count = 0;
timeout = window.setInterval(() => {
count++;
onProgress(500 * count, 1500);
if (count === 3) {
window.clearInterval(timeout);
resolve({
error: false,
data: Date.now().toString(),
});
}
}, 1500);
}),
});
});
}
);
const SlowTemplate = (p: Props) => {
return (
<div className="demo">
<QueryClientProvider client={queryClient}>
{<Upload useWorker={false} multiple provider={slowProvider} {...p} />}
{<Upload multiple codexData={CodexDataSlowSdk} {...p} />}
</QueryClientProvider>
</div>
);
@ -99,10 +68,9 @@ const SingleTemplate = (p: Props) => {
<QueryClientProvider client={queryClient}>
{
<Upload
useWorker={false}
multiple={false}
editable={false}
provider={slowProvider}
codexData={CodexDataSlowSdk}
{...p}
/>
}

74
stories/sdk.ts Normal file
View File

@ -0,0 +1,74 @@
import { Codex } from "@codex-storage/sdk-js";
import { CodexData, UploadResponse } from "@codex-storage/sdk-js";
class CodexDataMock extends CodexData {
override upload(
_: File,
onProgress?: (loaded: number, total: number) => void
): Promise<UploadResponse> {
return new Promise<UploadResponse>((resolve) => {
let timeout: number;
resolve({
abort: () => {
window.clearInterval(timeout);
},
result: new Promise((resolve) => {
let count = 0;
timeout = window.setInterval(() => {
count++;
onProgress?.(500 * count, 1500);
if (count === 3) {
window.clearInterval(timeout);
resolve({
error: false,
data: Date.now().toString(),
});
}
}, 1500);
}),
});
});
}
}
export const CodexDataSdk = new CodexDataMock("");
class CodexDataSlowMock extends CodexData {
override upload(
_: File,
onProgress?: (loaded: number, total: number) => void
): Promise<UploadResponse> {
return new Promise<UploadResponse>((resolve) => {
let timeout: number;
resolve({
abort: () => {
window.clearInterval(timeout);
},
result: new Promise((resolve) => {
let count = 0;
timeout = window.setInterval(() => {
count++;
onProgress?.(500 * count, 1500);
if (count === 3) {
window.clearInterval(timeout);
resolve({
error: false,
data: Date.now().toString(),
});
}
}, 1500);
}),
});
});
}
}
export const CodexDataSlowSdk = new CodexDataSlowMock("");