rpldy / react-uploady Goto Github PK
View Code? Open in Web Editor NEWModern file uploading - components & hooks for React
Home Page: https://react-uploady.org/
License: MIT License
Modern file uploading - components & hooks for React
Home Page: https://react-uploady.org/
License: MIT License
need to expose method from context to call uploader.upload
reported by #40
both xhr sender and mock sender
Describe the bug
When Uplody is created with autoUpload = false and concurrent = true, upload of Items is triggered several Times.
To Reproduce
See this Sandbox: https://codesandbox.io/s/vibrant-cdn-b25h6?fontsize=14&hidenavigation=1&theme=dark&file=/src/App.js
In production i Noticed this behavior in the Network-tab.
Expected behavior
Each file only triggered once.
Versions
@rpldy/uplody 0.8.3
@rpldy/uploder 0.8.3
@rpldy/sender 0.8.0
Which browser this bug reproduces in.
Tested in Chrome
Code
See sandbox above. I wrapped the "send"-method for logging purposes.
Describe the bug
The accept
parameter is ignored when dragging and dropping files. For example, when set to accept="image/*"
, non-image file types cannot get uploaded from the UploadButton
but they are uploaded when dragging and dropping.
To Reproduce
Steps to reproduce the behavior:
UploadButton
in the provided codesandbox and the native file browser will appear. For me, using Chrome 85 on Mac Mojave, all non-image file types appear greyed out and cannot be selected.UploadDropZone
(I used a .mov type)Expected behavior
Only file types that are listed in the accept
parameter can be uploaded. In this case, a non-image would not trigger a network request, and there would be some kind of error response from Uploady.
Versions
"@rpldy/upload-button": "0.7.0",
"@rpldy/upload-drop-zone": "0.7.0",
"@rpldy/uploady": "0.7.0"
Trying to use your great package with SSR.
But I got error on server
ReferenceError: window is not defined
at Object.<anonymous> (/*/node_modules/@rpldy/uploader/lib/utils.js:16:40)
My config
"@rpldy/upload-drop-zone": "^0.5.0",
"@rpldy/uploady": "^0.5.0",
<Uploady
multiple
grouped
maxGroupSize={2}
method="POST"
destination={{url: generateApiUrl(API_ROUTES_POST.FILES, {method: "POST"}) }}
>
<UploadDropZone
onDragOverClassName="drag-over"
grouped={grouped}
maxGroupSize={groupSize}
>
<span>Drag&Drop File(s) Here</span>
</UploadDropZone>
</Uploady>
Hi,
Some services like S3 stop reading form data once the 'file' value has been reached.
When looking at the uploady POST request, it starts with the 'file' value, and so the other values like 'key' that are needed for S3, are ignored.
Is there any way in which the order of values for the POST can be changed so that 'file' comes last?
Describe the bug
When autoUpload is false and abort is called the item will not be removed .
Expected behavior
Abort deletes the file from the list OR a remove method is provided.
Versions
"@rpldy/uploady": "^0.8.3",
"@rpldy/upload-drop-zone": "^0.8.3",
"@rpldy/uploader": "^0.8.3",
"@rpldy/sender": "^0.8.0",
"@rpldy/shared": "^0.8.0",
Code
const FileItems = () => {
const abort = useItemAbort();
const [files, setFiles] = useState([]);
useBatchAddListener((batch: Batch) => {
setFiles(prevState => [...prevState, ...batch.items]);
});
useItemAbortListener((batch: BatchItem) => {
debugger;
});
useBatchAbortListener(batch => {
debugger;
});
useAllAbortListener(() => {
debugger;
});
return files.map(file => <FileItem file={file} onClick={() => abort(file.id)} />)
}
const App = () => {
return <Uploady autoUpload={false} >
<FileItems />
</Uploady
}
I noticed while trying to implement this package that the tus-uploady readme states:
# packages/ui/tus-uploady/README.md L63
It also supports the Upload-Metadata header and will turn the destination params prop into the metadata key/value.
Headers aren't passed through with the prop destination={{url: "https://my-server", headers: {"x-custom": "123"}}}
even though the Readme states all UploadOptions props can be passed to TusUploady
.
I would suggest either allowing custom headers or updating the Readme to make the params
object more clear in the props table.
I'd also suggest making it clear that you don't have to pre-encode the Upload-Metadata values in Base64 as is required in the TUS Docs concerning the Upload-Metadata format. The destination params: {key: 'value'}
is automatically converted to Upload-Metadata: key dmFsdWU=
.
I'm creating an object for the uploadyContext API and trying to simulate events inside the context listener hooks, but neither seems to be working.
autoUpload = false
in the component wrapper and calling uploadyContext.upload(batchId) => failautoUpload = true
in the wrapper and calling uplodyContet.abort(itemId) => failimport {
useBatchStartListener,
useBatchFinishListener,
useItemStartListener,
useItemFinishListener,
useItemProgressListener,
useBatchAbortListener,
useBatchCancelledListener,
useItemAbortListener,
useItemCancelListener,
useBatchAddListener,
useItemErrorListener
, UploadyContext } from '@rpldy/uploady';
import { Batch, BatchItem } from '@rpldy/shared';
// .... Inside my React component ... //
const uploadyContext = React.useContext(UploadyContext);
useBatchAddListener((batch: Batch) => {
console.warn(`batch ${batch.id} was just added with ${batch.items.length} items`);
uploadyContext.upload(batch.items[0].batchId); // Calling with the batchId or should be by itemId ?
});
useItemStartListener((item: BatchItem) => {
// Cancel the upload if given file already exceeds the maximum files allowed or the size of any
console.warn(`item ${item.id} started uploading`);
uploadyContext.abort(item.id);
});
useItemProgressListener((item: BatchItem) => {
console.warn(
`item ${item.id} File ${item.file.name} is ${item.completed}% done and ${item.loaded} bytes uploaded`
);
// Despite calling`abort` at the itemStartEvent above, the web socket continues with the upload
});
test static pages that use the bundles
use updateable protection only in dev
Describe the bug
When using Uploady in a SSR app, it throws this error on the server side. "ReferenceError: File is not defined"
To Reproduce
npm i @rpldy/uploady
pages/test.js
and use the code provided belowExpected behavior
Does not throw an error.
Versions
I'm still using version 9.5.2 though of NextJS, their latest release is 10.0.3 and latest on the 9.5.* branch is 9.5.5. Have not had the chance to update yet.
"@rpldy/uploady": "^0.8.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"next": "9.5.2",
Code
This is what I put in the test.js
file:
import Uploady from '@rpldy/uploady'
export default function TestPage() {
return (
<Uploady destination={{ url: '/path/to/upload' }}>
Hello
</Uploady>
)
}
Stack Trace I get:
ReferenceError: File is not defined
at isNativeFile (<working dir>/node_modules/@rpldy/simple-state/lib/cjs/utils.js:20:25)
at isProxiable (<working dir>/node_modules/@rpldy/simple-state/lib/cjs/utils.js:24:68)
at deepProxy (<working dir>/node_modules/@rpldy/simple-state/lib/cjs/createState.js:40:30)
at _default (<working dir>/node_modules/@rpldy/simple-state/lib/cjs/createState.js:112:46)
at createUploaderQueue (<working dir>/node_modules/@rpldy/uploader/lib/cjs/queue/uploaderQueue.js:41:50)
at _default (<working dir>/node_modules/@rpldy/uploader/lib/cjs/processor.js:18:37)
at _default (<working dir>/node_modules/@rpldy/uploader/lib/cjs/uploader.js:166:45)
at <working dir>/node_modules/@rpldy/shared-ui/lib/cjs/useUploader.js:33:37
at Object.useMemo (<working dir>/node_modules/react-dom/cjs/react-dom-server.node.development.js:1239:19)
at useMemo (<working dir>/node_modules/react/cjs/react.development.js:1521:21)
And just tagging the prior comments on this issue for anyone that might be googling: #76
Here is the reproduce link: https://codesandbox.io/s/rough-lake-5v98z
After choosing a file in the file dialog, the upload process will not start.
As far as I can tell it only happens after abort. If you let the upload process to complete it works fine.
It might be a wrong implementation on my side but I don't think I'm doing anything weird or unusual.
Thanks.
Can i hide upload Button when Previews count is = 5?
return (
<Uploady
debug
destination={destination}
concurrent={concurrent}
multiple={multiple}
{...rest}
>
<div className={styles.uploadedImagesWrp}>
<UploadPreview />
{
previews && previews.length < 5
? <UploadButton className={styles.uploader}/>
: null
}
</div>
</Uploady>
)
Where can i get previews?
Using asUploadButton
like in the example causing the following warning in the console:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of `ForwardRef(AsUploadButton)`.
in Unknown (created by ForwardRef(AsUploadButton))
Versions
Uploady 0.5.0
React 16.13.1
Code
import React, { useState } from 'react'
import ChunkedUploady, {
useBatchStartListener,
useBatchFinishListener
} from '@rpldy/chunked-uploady'
import { asUploadButton } from '@rpldy/upload-button'
import { Button } from 'antd'
import { UploadOutlined } from '@antd-design/icons'
const UploadButton = asUploadButton(props => {
const [visible, setVisible] = useState(true)
useBatchStartListener(() => {
setVisible(false)
})
useBatchFinishListener(() => {
setVisible(true)
})
return visible ? (
<Button shape="circle" {...props}>
<UploadOutlined />
</Button>
) : null
})
const Upload = (props) => {
return (
<ChunkedUploady
destination={{
url: props.url
}}
multiple={props.multiple}
withCredentials={true}
params={props.params}
accept={props.accept}
>
<UploadButton />
</ChunkedUploady>
)
}
export default Upload
Describe the bug
I'm not sure if I am doing this right or if this is a bug, but I have been trying to modify the default inputFieldName
prop from "file" to a custom name, say "myCustomField" so that on submission/upload the field name of the file in formData will be "myCustomField". However, even after modifying the inputFieldName
prop on the Uploady
component, the field retains the "file" input field name. (P.S I am using a custom component as upload button, even though I think this shouldn't matter)
To Reproduce
const CustomUploader = ({useMock, fieldName}) => {
const [isUploading, setIsUploading] = useState(false);
const [uploadStatus, setUploadStatus] = useState("");
const onUploading = (value) => setIsUploading(value);
const handleUploadStatus = (value) => setUploadStatus(value);
const extraProps={onUploading, handleUploadStatus};
return (
<Uploady
destination={{ url: "http://localhost:5000/v1/mock-path" }}
autoUpload={false}
enhancer={useMock ? mockEnhancer : null}
inputFieldName={fieldName}
>
<div className="Uploader">
<Custombutton { ...{extraProps} }/>
<UploadProgress animated={isUploading} status={uploadStatus}/>
</div>
</Uploady>
)
}
const mockEnhancer = (uploader) => {
const mockSender = createMockSender({ delay: 5000 });
uploader.update({ send: mockSender.send });
return uploader;
};
---------------------------------------------------------
Used in another component as:
<CustomUploader fieldName="myCustomField" />
Below is a sample formData request on upload
XHRPOSThttp://localhost:5000/v1/mock-path
Content-Disposition: form-data; name="file"; filename="Text.txt"
Content-Type: text/plain
Some Text File
Expected behavior
Expected the request to be as shown below
XHRPOSThttp://localhost:5000/v1/mock-path
Content-Disposition: form-data; name="myCustomField"; filename="Text.txt"
Content-Type: text/plain
Some Text File
Versions
Specify the versions of the @rpldy packages you're using.
"@rpldy/mock-sender": "^0.8.2",
"@rpldy/upload-button": "^0.8.2",
"@rpldy/uploady": "^0.8.2",
Which browser this bug reproduces in.
Firefox 81
Code
Please provide code sample or better yet, a link to a reproducing repository or best yet, codesandbox (fiddle, etc) where issue can be reproduced easily
I abort and retry items in batch of 7 items, and got this error
batchHelpers.js:13 Uncaught (in promise) TypeError: Cannot read property 'batch' of undefined
at getBatchFromState (batchHelpers.js:13)
at triggerUploaderBatchEvent (batchHelpers.js:106)
at cleanUpFinishedBatch (batchHelpers.js:98)
at processFinishedRequest.js:65
at processBatchItems.js:94
And all my not uploaded items is disappeared!
Steps to reproduce:
This is the way i'm using chunked-uploady
:
import React, { useState, useCallback } from 'react'
import ChunkedUploady, {
useBatchStartListener,
useBatchProgressListener,
useBatchFinishListener,
useBatchAbortListener,
useAbortBatch,
} from '@rpldy/chunked-uploady'
import { asUploadButton } from '@rpldy/upload-button'
import { UploadIcon, StopIcon } from 'components/icons'
import { message, Button, Tooltip, Progress } from 'antd'
const UploadButton = asUploadButton(
React.forwardRef((props, ref) => {
const [visible, setVisible] = useState(true)
useBatchStartListener(() => {
setVisible(false)
})
useBatchAbortListener(() => {
setVisible(true)
})
useBatchFinishListener(() => {
setVisible(true)
})
return (
{visible ? (
<Button shape="circle" {...props} ref={ref}>
<UploadIcon />
</Button>
) : null}
)
})
)
const UploadProgress = () => {
const [visible, setVisible] = useState(false)
const [currentBatch, setCurrentBatch] = useState('')
const abortBatch = useAbortBatch()
const onAbort = useCallback(() => {
abortBatch(currentBatch)
}, [abortBatch, currentBatch])
useBatchStartListener(batch => {
setCurrentBatch(batch.id)
setVisible(true)
})
const progress = useBatchProgressListener()
useBatchAbortListener(() => {
message.error('File upload aborted')
setVisible(false)
})
useBatchFinishListener(() => {
setVisible(false)
})
return visible ? (
<div>
<Tooltip title="Abort upload">
<Button shape="circle" icon={<StopIcon />} onClick={onAbort} />
</Tooltip>
<Progress type="circle" percent={parseInt(progress?.completed)} />
</div>
) : null
}
const Upload = () => {
return (
<ChunkedUploady destination={{ url: 'api/upload' }}>
<UploadButton />
<UploadProgress />
</ChunkedUploady>
)
}
export default Upload
As you can see in order to abort the upload i'm forced to maintain a state with the current batch id.
What I really would like is to use the abortAll
hook since I really want to cancel everything in this case. But it seems like abortAll
doesn't trigger the useBatchAbortListener
nor does it have his own abort event...
I Wonder if i'm missing something here or this is a missing feature.
Describe the bug
When uploading a file using tus-uploady, the Location is provided by the tus server.
However, on UPLOADER_EVENTS.ITEM_FINISH I seem to be getting the response of the last PATCH:
data: ""
headers:
cache-control: "no-store"
content-length: "0"
content-type: "text/html; charset=utf-8"
tus-res umable: "1.0.0"
upload-offset: "469"
instead of the response of the last POST with the Location information
To Reproduce
Upload a file using the library, and search for the Location header in uploadResponse
Expected behavior
Location header is available
Versions
Specify the versions of the @rpldy packages you're using: 0.6.0
Which browser this bug reproduces in: Chrome 85
Code
const tusEnhancer = getTusEnhancer({
parallel: 1,
});
const random = "asdfqwfwefiqwfpjoqwef"
const uploader = createUploader({
enhancer: tusEnhancer,
autoUpload: true,
grouped: false,
destination: {url: "https:///upload/",
filesParamName: random,
headers: {Authorization: getAuthorization()}
},
params: {
project: "p",
access: "a",
},
sendDataOnCreate: true,
});
uploader.add (file);
I am using chunked upload feature but getting error Invariant Violation: Uploady - valid UploadyContext not found. Make sure you render inside .
I have resolved above error with to import chunkedUploady through "@rpldy/uploady".
I have gone through the code and found that uploady is returning from chunkeduploady, so why i am getting this error.
Now chunkedSize and chunked are not supported by chunkeduploady.
Here is my code...
import ChunkedUploady from "@rpldy/uploady";
import { useContext } from 'react';
import { UploadyContext } from '@rpldy/uploady';
const UploadContent = () => {
return (
< ChunkedUploady
chunkSize={2142880}
chunked={true} >
< UploadButton1 />
< /ChunkedUploady>);
}
export default UploadContent;
const UploadButton1 = () => {
const uploady = useContext(UploadyContext);
let url = null;
const onClick = async () => {
try {
if (!url) {
await apiGetSignedUploadUrl(idType)
.then((out) => {
const { success, data } = out;
if (success) {
url = data.uploadUrl;
}
})
}
uploady.showFileUpload({
destination: {
url,
method: 'PUT',
headers: {
"Content-Type": '',
},
},
sendWithFormData: false,
});
} catch (error) {
console.error(error, error.response);
throw error;
}
}
return <>
<Button type='button'
onClick={onClick}
style={{
border: isError ? '1px solid red' : '1px solid rgba(166, 125, 255, 0.5)',
color: isError ? 'red' : '#a67dff'
}}
>
{getUrl ? successCaption : 'Upload'}</Button>
<div>
<span style={{ color: isError ? 'red' : '#a67dff' }}>{isError ? errMsg : ''}</span>
</div>
</>
}
Thanks in advance!!
in e2e - dont initiate click on file input
file data is passed through cypress command
When calling context.upload(file), it randomly seems to not trigger the upload process. autoUpload is set to true.
Trying to force a uploadyContext.processPending() doesn't do anything either.
UPLOADER_EVENTS.BATCH_ADD is successfully called with the correct file though.
Uploadhandler's useRequestPreSend is not called.
Following code is used:
<Uploady> <UploadHandler /> <UploadButton className="btn btn-primary"> Upload Files </UploadButton> </Uploady>
Any ideas where I could look?
tus-sender
Please share your use-case and company (if relevant).
It will be great to know how Uploady is used in the wild ๐ง
I try to made retry UI by your example https://react-uploady-storybook.netlify.app/?path=/story/retry-hooks--with-retry-and-preview.
But i got this error after start function retry = useRetry();
I cannot retry item when current batch is not finished.
If i create 3 batch by 1 item in it, retry works perfectly.
index.js:88 Uncaught (in promise) Error: Uploader queue conflict - item batch-1.item-2 already exists (recycled: true)
at add (index.js:88)
at Proxy.forEach (<anonymous>)
at Object.uploadBatch (index.js:104)
at Object.process (processor.js:23)
at _callee$ (uploader.js:77)
at tryCatch (runtime.js:65)
at Generator.invoke [as _invoke] (runtime.js:303)
at Generator.prototype.<computed> [as next] (runtime.js:117)
at asyncGeneratorStep (uploader.js:22)
at _next (uploader.js:24)
export const PreviewImage = memo((props: any) => {
const { id, url, name, props:{ className = "", ...rest } = {} } = props;
const [progress, setProgress] = useState(0);
const [itemState, setItemState] = useState(0);
const abortItem = useAbortItem();
const retry = useRetry();
const onAbortClick = useCallback(() => abortItem(id), [abortItem, id]);
const onRetryItem = useCallback(() => retry(id), [retry, id]);
useItemProgressListener(item => {
console.log("useItemProgressListener");
if (item.completed > progress) {
setProgress(item.completed);
setItemState(() =>
item.completed === 100 ? STATES.DONE : STATES.PROGRESS
);
}
}, id);
useItemAbortListener(() => {
console.log("useItemAbortListener");
setItemState(STATES.ABORTED);
}, id);
useItemErrorListener(() => {
console.log("useItemErrorListener");
setItemState(STATES.ERROR);
}, id);
useRetryListener(({ items }) => {
console.log("##### RETRY EVENT - retrying items: ", items);
});
return (
<div className={cn(styles.previewImage, className, {[styles.hidden]: itemState === STATES.DONE })} {...rest}>
{
itemState !== STATES.DONE
? <div className={styles.backdrop}>
{
itemState === STATES.PROGRESS
? (
<>
<Circle
className={styles.progressbar}
strokeWidth={10}
trailWidth={10}
percent={progress}
/>
<Icon name="cross" onClick={onAbortClick} className={styles.abort}/>
</>
)
: null
}
{
itemState === STATES.ABORTED || itemState === STATES.ERROR
? <Icon name="arrow-circle" onClick={onRetryItem} className={styles.retry}/>
: null
}
</div>
: null
}
<img src={url} alt={name}/>
</div>
)
});
What is the recommended way to reset the uploader. I.e. a user has uploaded a bunch of items, and they want to clear the finished batch(es) and start afresh. I guess I could trigger a complete remount of the component somehow.
Keep getting this error, i have 'babel/next' in my babelrc file.
ReferenceError: regeneratorRuntime is not defined at /Users/m5/projects/meet_apps/pwa/node_modules/@rpldy/uploader/lib/queue/batchHelpers.js:104:46 at Object.<anonymous> (/Users/m5/projects/meet_apps/pwa/node_modules/@rpldy/uploader/lib/queue/batchHelpers.js:136:2) at Module._compile (internal/modules/cjs/loader.js:1138:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10) at Module.load (internal/modules/cjs/loader.js:986:32) at Function.Module._load (internal/modules/cjs/loader.js:879:14) at Module.require (internal/modules/cjs/loader.js:1026:19) at require (internal/modules/cjs/helpers.js:72:18) at Object.<anonymous> (/Users/m5/projects/meet_apps/pwa/node_modules/@rpldy/uploader/lib/queue/processFinishedRequest.js:12:21) at Module._compile (internal/modules/cjs/loader.js:1138:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10) at Module.load (internal/modules/cjs/loader.js:986:32) at Function.Module._load (internal/modules/cjs/loader.js:879:14) at Module.require (internal/modules/cjs/loader.js:1026:19) at require (internal/modules/cjs/helpers.js:72:18) at Object.<anonymous> (/Users/m5/projects/meet_apps/pwa/node_modules/@rpldy/uploader/lib/queue/processBatchItems.js:12:54)
not sure what other information to provide as i can't get past the example with custom button in my Nextjs app
check if it doesnt cause build issues
because immer isnt actually used in build it should be possibe to move to deps so its not counted by bundlephobia
Describe the bug
When I try to upload a 0-byte file, I get the following error:
Uncaught (in promise) ChunkedSendError: start byte 0 is invalid. File size: 0
To Reproduce
Steps to reproduce the behavior:
Versions
Specify the versions of the @rpldy packages you're using.
"@rpldy/tus-uploady": "^0.7.0",
"@rpldy/uploader": "^0.7.0",
"@rpldy/uploady": "^0.7.0",
Google chrome: Version 85.0.4183.121 (Offizieller Build) (32-Bit)
Hi.. This library is really great.. I like this concept..
But, when I tries to implement it in my next.js app (just copy and paste from your example):
<Uploady
debug
destination={{ url }}
>
<UploadButton>Upload Files</UploadButton>
</Uploady>
I got this error:
TypeError: proxy[key] is null
Any idea about this error?
Hi again!
I'm having trouble parsing how to use autoUpload={false}
in conjunction with form values.
I have a requirement to use the TUS protocol for uploading videos. The form has fields which populate the Upload-Metadata (params) values and they need to be set before the upload begins. (implementing that part isn't a problem, see screenshot for context)
I've crawled through the docs and packages to find the best path forward using uploady (without scrapping third-party packages and doing it all manually, of which i'd like to avoid) but I need a push in the right direction -- plus this could potentially be a good storybook example, telling uploady to "start uploading now" and clearing up how to do that, because I wont be the only one who will be looking for it.
Error [ERR_INVALID_PACKAGE_CONFIG]: Invalid package config /Users/lucamarchal/code/ProvePay/node_modules/@rpldy/uploady/package.json. "exports" cannot contain some keys starting with '.' and some not. The exports object must either be an object of package subpath keys or an object of main entry condition name keys only.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.