diff --git a/.github/ISSUE_TEMPLATE/1-bug.yml b/.github/ISSUE_TEMPLATE/1-bug.yml new file mode 100644 index 0000000000..23b00ca079 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-bug.yml @@ -0,0 +1,47 @@ +name: 🐛 Bug report +labels: Bug, Triage +description: Describe a bug with a project +body: + - type: checkboxes + id: initial-checklist + attributes: + label: Initial checklist + options: + - label: I understand this is a bug report and questions should be posted in the [Community Forum](https://community.transloadit.com/) + required: true + - label: I searched [issues](https://github.com/transloadit/uppy/issues?q=is%3Aissue) and couldn’t find anything (or linked relevant results below) + required: true + - type: input + id: runnable-example + attributes: + label: Link to runnable example + description: | + Link to repository or sandbox with runnable example of the issue. + Alternatively, use the next section *Steps to reproduce*. + + Starters: + + - [Uppy Dashboard](https://codesandbox.io/s/uppy-dashboard-xpxuhd?file=/src/index.js) + validations: + required: false + - type: textarea + id: steps-to-reproduce + attributes: + label: Steps to reproduce + description: How did this happen? Please provide a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: What should happen? + validations: + required: true + - type: textarea + id: actual-behavior + attributes: + label: Actual behavior + description: What happens instead? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/2-feature.yml b/.github/ISSUE_TEMPLATE/2-feature.yml new file mode 100644 index 0000000000..63e577292f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-feature.yml @@ -0,0 +1,34 @@ +name: 🚀 Feature request +labels: Feature, Triage +description: Suggest an idea +body: + - type: checkboxes + id: initial-checklist + attributes: + label: Initial checklist + options: + - label: I understand this is a feature request and questions should be posted in the [Community Forum](https://community.transloadit.com/) + required: true + - label: I searched [issues](https://github.com/transloadit/uppy/issues?q=is%3Aissue) and couldn’t find anything (or linked relevant results below) + required: true + - type: textarea + id: problem + attributes: + label: Problem + description: Please describe the problem you are trying to solve here. + validations: + required: true + - type: textarea + id: solution + attributes: + label: Solution + description: What should happen? Please describe the desired behavior. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives + description: What are the alternative solutions? Can this be solved in a different way? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index be83e490e2..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: Bug report -about: Let us know about an unexpected error, a crash, or an incorrect behavior. -labels: Bug, Triage ---- diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..a0b8456619 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: 🙋 Ask a question + url: https://community.transloadit.com + about: Ask questions and discuss with other community members diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 49ae7f50e2..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: Feature request -about: Suggest a new feature or other enhancement. -labels: Feature, Triage ---- diff --git a/.github/ISSUE_TEMPLATE/integration_help.md b/.github/ISSUE_TEMPLATE/integration_help.md deleted file mode 100644 index 22cbdf54f5..0000000000 --- a/.github/ISSUE_TEMPLATE/integration_help.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Integration help -title: Please use the community forum (or paid support) instead -about: Do you need assistance with building the Uppy client in your bundler, or running Companion on your own preferred server platform? -labels: Not Accepted, Triage ---- - -Transloadit is providing Uppy free of charge. If you want, you can self-host all its components and never pay us a dime. You can access docs and tests, and your Bug Reports and Feature Requests are always welcome on GitHub. - -We offer also a different category of support that we like to call Integration Help: help to make things work for your environment, that have already been reported as working for the larger community. - -As much as we at Transloadit would like to provide detailed Integration Help to every non-paying user, Uppy has reached a point where this is no longer sustainable for our small crew. If we end up investing our time in a million different apps that use Uppy, as long as no money is flowing back, we won’t be able to ramp up our team to meet the demand. This would spread the team ever thinner and eventually grind development to a halt. - -That is not where we want to be. So, to offer enthusiasts, businesses, and enterprises help in a sustainable way, we’re providing community-based Integration Help for free at . If you are unable to solve your problem with help of the Uppy community, we offer paid Integration Help via . diff --git a/BACKLOG.md b/BACKLOG.md index fca6f63e6e..b5f00deee3 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -9,10 +9,13 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature, - [x] Switch to ES Modules (ESM) - [x] @uppy/image-editor: Remove silly hack to work around non-ESM. -- [ ] Some not too breaking breaking changes. Go through TODOs -- [ ] Companion breaking changes, like S3 keys +- [ ] Some not too breaking breaking changes. Go through TODOs (@arturi, @aduh95, @Murderlon) +- [ ] Companion breaking changes, like S3 keys (@mifi) - [x] New remote-sources preset - [ ] Deprecate Robodog + - [ ] Remove from 3.x branch (@aduh95) + - [ ] Update docs that refer to Robodog (@arturi) + - [ ] Update Transloadit.com examples and docs to use @uppy/transloadit + @uppy/remote-sources plugins instead of @uppy/robodog (@arturi) ## `4.0.0` @@ -27,7 +30,6 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature, - [ ] Make sure Uppy works well in VR - [ ] normalize file names when uploading from iOS? Can we do it with meta data? date? `image-${index}`? #678 -- [ ] robodog: Simplify Robodog — yes to easy few lines of code Transloadit experience, but currently it’s hard to choose between modes, decide what you need. - [ ] Can Uppy upload a lot of files at once? Seems to fail now: https://github.com/transloadit/uppy/issues/3313 (@aduh95, @Murderlon) - [ ] Consider how we can make Uppy smaller. Replace some packages with smaller alternatives. Talk about Socket.io again (@aduh95) - [ ] Better events — more data, consistency, naming (@Murderlon) @@ -57,14 +59,13 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature, - [ ] Giphy image search (on top of Unsplash plugin) () - [ ] Image search (via Google or Bing or DuckDuckGo): use duckduckgo-images-api or Google Search API (@arturi) - [ ] Vimeo #2872 -- [ ] box: add to https://uppy.io/examples/dashboard/ (@mifi) ### Miscellaneous - [ ] goldenretriever: make it work with aws multipart https://community.transloadit.com/t/resumable-aws-s3-multipart-integration/14888 (@goto-bus-stop) - [ ] provider: add sorting (by date) #254 - [ ] qa: add one integration test (or add to existing test) that uses more exotic (tus) options such as `useFastRemoteRetry` or `removeFingerprintOnSuccess` https://github.com/transloadit/uppy/issues/1327 (@arturi, @ifedapoolarewaju) -- [ ] react: Add a React Hook to manage an Uppy instance https://github.com/transloadit/uppy/pull/1247#issuecomment-458063951 (@goto-bus-stop) +- [x] react: Add a React Hook to manage an Uppy instance https://github.com/transloadit/uppy/pull/1247#issuecomment-458063951 (@goto-bus-stop) - [ ] rn: Uppy React Native works with Expo, now let's make it work without - [ ] rn: Uppy React Native works with Url Plugin, now let's make it work with Instagram - [ ] security: consider iframe / more security for Transloadit/Uppy integration widget and Uppy itself. Page can’t get files from Google Drive if its an iframe diff --git a/CHANGELOG.md b/CHANGELOG.md index f4a16071ed..9fa2d43b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,58 @@ Released: 2022-05-30 - @uppy/companion: remove support for EOL versions of Node.js (Antoine du Hamel / #3784) - @uppy/react: refactor to ESM (Antoine du Hamel / #3780) - @uppy/transloadit: remove IE 10 hack (Antoine du Hamel / #3777) +## 2.13.1 + +Released: 2022-07-27 + +| Package | Version | Package | Version | +| -------------------- | ------- | -------------------- | ------- | +| @uppy/companion | 3.7.1 | @uppy/remote-sources | 0.1.1 | +| @uppy/compressor | 0.3.1 | @uppy/transloadit | 2.3.5 | +| @uppy/core | 2.3.2 | @uppy/robodog | 2.9.1 | +| @uppy/dashboard | 2.4.1 | uppy | 2.13.1 | +| @uppy/image-editor | 1.4.1 | | | + +- @uppy/compressor: fix upload causing meta name to reset (Justin / #3890) +- @uppy/transloadit: cancel assemblies when all its files have been removed (Antoine du Hamel / #3893) +- e2e: Add retries for flaky e2e test (Merlijn Vos / #3915) +- @uppy/dashboard,@uppy/image-editor,@uppy/remote-sources: Fix `uppy.close()` crashes when remote-sources or image-editor is installed (Merlijn Vos / #3914) +- @uppy/core: Add missing type for retry-all event (Luc Boissaye / #3901) +- @uppy/companion: Companion app type (Mikael Finstad / #3899) +- e2e: upgrade to Cypress 10 (Antoine du Hamel / #3896) +- meta: Fix website build (Murderlon) +- meta: Create new issue templates (Merlijn Vos / #3879) + + +## 2.13.0 + +Released: 2022-07-18 + +| Package | Version | Package | Version | +| ------------------ | ------- | ------------------ | ------- | +| @uppy/dashboard | 2.4.0 | @uppy/robodog | 2.9.0 | +| @uppy/image-editor | 1.4.0 | uppy | 2.13.0 | +| @uppy/transloadit | 2.3.4 | | | + +- @uppy/transloadit: fix outdated file ids and incorrect usage of files (Merlijn Vos / #3886) +- @uppy/image-editor: remove beta notice (Merlijn Vos / #3877) +- meta: Fix broken links in _posts/2019-08-1.3.md (YukeshShr / #3884) +- meta: Fix broken link in _posts/2017-03-0.15.md (YukeshShr / #3883) +- @uppy/image-editor: Add image editor cancel event (James R T / #3875) + + +## 2.12.3 + +Released: 2022-07-11 + +| Package | Version | Package | Version | +| ----------------- | ------- | ----------------- | ------- | +| @uppy/transloadit | 2.3.3 | uppy | 2.12.3 | +| @uppy/robodog | 2.8.3 | | | + +- @uppy/transloadit: fix TypeError when file is cancelled asynchronously (Antoine du Hamel / #3872) +- @uppy/robodog,@uppy/transloadit: use modern syntax to simplify code (Antoine du Hamel / #3873) +- meta: fix `release-beta` automation (Antoine du Hamel) ## 2.12.2 diff --git a/README.md b/README.md index a7bba89499..cd0c454038 100644 --- a/README.md +++ b/README.md @@ -254,9 +254,9 @@ Use Uppy in your project? [Let us know](https://github.com/transloadit/uppy/issu :---: |:---: |:---: |:---: |:---: |:---: | [sadovnychyi](https://github.com/sadovnychyi) |[samuelayo](https://github.com/samuelayo) |[richardwillars](https://github.com/richardwillars) |[ajkachnic](https://github.com/ajkachnic) |[dependabot\[bot\]](https://github.com/apps/dependabot) |[github-actions\[bot\]](https://github.com/apps/github-actions) | -[zcallan](https://github.com/zcallan) |[tim-kos](https://github.com/tim-kos) |[janko](https://github.com/janko) |[wilkoklak](https://github.com/wilkoklak) |[YukeshShr](https://github.com/YukeshShr) |[oliverpool](https://github.com/oliverpool) | +[zcallan](https://github.com/zcallan) |[tim-kos](https://github.com/tim-kos) |[YukeshShr](https://github.com/YukeshShr) |[janko](https://github.com/janko) |[wilkoklak](https://github.com/wilkoklak) |[oliverpool](https://github.com/oliverpool) | :---: |:---: |:---: |:---: |:---: |:---: | -[zcallan](https://github.com/zcallan) |[tim-kos](https://github.com/tim-kos) |[janko](https://github.com/janko) |[wilkoklak](https://github.com/wilkoklak) |[YukeshShr](https://github.com/YukeshShr) |[oliverpool](https://github.com/oliverpool) | +[zcallan](https://github.com/zcallan) |[tim-kos](https://github.com/tim-kos) |[YukeshShr](https://github.com/YukeshShr) |[janko](https://github.com/janko) |[wilkoklak](https://github.com/wilkoklak) |[oliverpool](https://github.com/oliverpool) | [Botz](https://github.com/Botz) |[mcallistertyler](https://github.com/mcallistertyler) |[mokutsu-coursera](https://github.com/mokutsu-coursera) |[DJWassink](https://github.com/DJWassink) |[taoqf](https://github.com/taoqf) |[mrbatista](https://github.com/mrbatista) | :---: |:---: |:---: |:---: |:---: |:---: | @@ -378,85 +378,89 @@ Use Uppy in your project? [Let us know](https://github.com/transloadit/uppy/issu :---: |:---: |:---: |:---: |:---: |:---: | [jorgeepc](https://github.com/jorgeepc) |[jszobody](https://github.com/jszobody) |[jcalonso](https://github.com/jcalonso) |[jmontoyaa](https://github.com/jmontoyaa) |[tykarol](https://github.com/tykarol) |[firesharkstudios](https://github.com/firesharkstudios) | -[kaspermeinema](https://github.com/kaspermeinema) |[firesharkstudios](https://github.com/firesharkstudios) |[kevin-west-10x](https://github.com/kevin-west-10x) |[elkebab](https://github.com/elkebab) |[kyleparisi](https://github.com/kyleparisi) |[leaanthony](https://github.com/leaanthony) | +[justinjurenka](https://github.com/justinjurenka) |[tykarol](https://github.com/tykarol) |[kaspermeinema](https://github.com/kaspermeinema) |[firesharkstudios](https://github.com/firesharkstudios) |[kevin-west-10x](https://github.com/kevin-west-10x) |[elkebab](https://github.com/elkebab) | :---: |:---: |:---: |:---: |:---: |:---: | -[kaspermeinema](https://github.com/kaspermeinema) |[firesharkstudios](https://github.com/firesharkstudios) |[kevin-west-10x](https://github.com/kevin-west-10x) |[elkebab](https://github.com/elkebab) |[kyleparisi](https://github.com/kyleparisi) |[leaanthony](https://github.com/leaanthony) | +[justinjurenka](https://github.com/justinjurenka) |[tykarol](https://github.com/tykarol) |[kaspermeinema](https://github.com/kaspermeinema) |[firesharkstudios](https://github.com/firesharkstudios) |[kevin-west-10x](https://github.com/kevin-west-10x) |[elkebab](https://github.com/elkebab) | -[larowlan](https://github.com/larowlan) |[dviry](https://github.com/dviry) |[galli-leo](https://github.com/galli-leo) |[leods92](https://github.com/leods92) |[louim](https://github.com/louim) |[lucaperret](https://github.com/lucaperret) | +[kyleparisi](https://github.com/kyleparisi) |[leaanthony](https://github.com/leaanthony) |[larowlan](https://github.com/larowlan) |[dviry](https://github.com/dviry) |[galli-leo](https://github.com/galli-leo) |[leods92](https://github.com/leods92) | :---: |:---: |:---: |:---: |:---: |:---: | -[larowlan](https://github.com/larowlan) |[dviry](https://github.com/dviry) |[galli-leo](https://github.com/galli-leo) |[leods92](https://github.com/leods92) |[louim](https://github.com/louim) |[lucaperret](https://github.com/lucaperret) | +[kyleparisi](https://github.com/kyleparisi) |[leaanthony](https://github.com/leaanthony) |[larowlan](https://github.com/larowlan) |[dviry](https://github.com/dviry) |[galli-leo](https://github.com/galli-leo) |[leods92](https://github.com/leods92) | -[lucax88x](https://github.com/lucax88x) |[onhate](https://github.com/onhate) |[mperrando](https://github.com/mperrando) |[marcosthejew](https://github.com/marcosthejew) |[marcusforsberg](https://github.com/marcusforsberg) |[Acconut](https://github.com/Acconut) | +[louim](https://github.com/louim) |[ombr](https://github.com/ombr) |[lucaperret](https://github.com/lucaperret) |[lucax88x](https://github.com/lucax88x) |[onhate](https://github.com/onhate) |[mperrando](https://github.com/mperrando) | :---: |:---: |:---: |:---: |:---: |:---: | -[lucax88x](https://github.com/lucax88x) |[onhate](https://github.com/onhate) |[mperrando](https://github.com/mperrando) |[marcosthejew](https://github.com/marcosthejew) |[marcusforsberg](https://github.com/marcusforsberg) |[Acconut](https://github.com/Acconut) | +[louim](https://github.com/louim) |[ombr](https://github.com/ombr) |[lucaperret](https://github.com/lucaperret) |[lucax88x](https://github.com/lucax88x) |[onhate](https://github.com/onhate) |[mperrando](https://github.com/mperrando) | -[martin-brennan](https://github.com/martin-brennan) |[masaok](https://github.com/masaok) |[mattfik](https://github.com/mattfik) |[matthewhartstonge](https://github.com/matthewhartstonge) |[mauricioribeiro](https://github.com/mauricioribeiro) |[hrsh](https://github.com/hrsh) | +[marcosthejew](https://github.com/marcosthejew) |[marcusforsberg](https://github.com/marcusforsberg) |[Acconut](https://github.com/Acconut) |[martin-brennan](https://github.com/martin-brennan) |[masaok](https://github.com/masaok) |[mattfik](https://github.com/mattfik) | :---: |:---: |:---: |:---: |:---: |:---: | -[martin-brennan](https://github.com/martin-brennan) |[masaok](https://github.com/masaok) |[mattfik](https://github.com/mattfik) |[matthewhartstonge](https://github.com/matthewhartstonge) |[mauricioribeiro](https://github.com/mauricioribeiro) |[hrsh](https://github.com/hrsh) | +[marcosthejew](https://github.com/marcosthejew) |[marcusforsberg](https://github.com/marcusforsberg) |[Acconut](https://github.com/Acconut) |[martin-brennan](https://github.com/martin-brennan) |[masaok](https://github.com/masaok) |[mattfik](https://github.com/mattfik) | -[mhulet](https://github.com/mhulet) |[mkopinsky](https://github.com/mkopinsky) |[achmiral](https://github.com/achmiral) |[boudra](https://github.com/boudra) |[mnafees](https://github.com/mnafees) |[shahimclt](https://github.com/shahimclt) | +[matthewhartstonge](https://github.com/matthewhartstonge) |[mauricioribeiro](https://github.com/mauricioribeiro) |[hrsh](https://github.com/hrsh) |[mhulet](https://github.com/mhulet) |[mkopinsky](https://github.com/mkopinsky) |[achmiral](https://github.com/achmiral) | :---: |:---: |:---: |:---: |:---: |:---: | -[mhulet](https://github.com/mhulet) |[mkopinsky](https://github.com/mkopinsky) |[achmiral](https://github.com/achmiral) |[boudra](https://github.com/boudra) |[mnafees](https://github.com/mnafees) |[shahimclt](https://github.com/shahimclt) | +[matthewhartstonge](https://github.com/matthewhartstonge) |[mauricioribeiro](https://github.com/mauricioribeiro) |[hrsh](https://github.com/hrsh) |[mhulet](https://github.com/mhulet) |[mkopinsky](https://github.com/mkopinsky) |[achmiral](https://github.com/achmiral) | -[navruzm](https://github.com/navruzm) |[marton-laszlo-attila](https://github.com/marton-laszlo-attila) |[pleasespammelater](https://github.com/pleasespammelater) |[naveed-ahmad](https://github.com/naveed-ahmad) |[nicojones](https://github.com/nicojones) |[coreprocess](https://github.com/coreprocess) | +[boudra](https://github.com/boudra) |[mnafees](https://github.com/mnafees) |[shahimclt](https://github.com/shahimclt) |[navruzm](https://github.com/navruzm) |[marton-laszlo-attila](https://github.com/marton-laszlo-attila) |[pleasespammelater](https://github.com/pleasespammelater) | :---: |:---: |:---: |:---: |:---: |:---: | -[navruzm](https://github.com/navruzm) |[marton-laszlo-attila](https://github.com/marton-laszlo-attila) |[pleasespammelater](https://github.com/pleasespammelater) |[naveed-ahmad](https://github.com/naveed-ahmad) |[nicojones](https://github.com/nicojones) |[coreprocess](https://github.com/coreprocess) | +[boudra](https://github.com/boudra) |[mnafees](https://github.com/mnafees) |[shahimclt](https://github.com/shahimclt) |[navruzm](https://github.com/navruzm) |[marton-laszlo-attila](https://github.com/marton-laszlo-attila) |[pleasespammelater](https://github.com/pleasespammelater) | -[nil1511](https://github.com/nil1511) |[leftdevel](https://github.com/leftdevel) |[cryptic022](https://github.com/cryptic022) |[patricklindsay](https://github.com/patricklindsay) |[plneto](https://github.com/plneto) |[pedrofs](https://github.com/pedrofs) | +[naveed-ahmad](https://github.com/naveed-ahmad) |[nicojones](https://github.com/nicojones) |[coreprocess](https://github.com/coreprocess) |[nil1511](https://github.com/nil1511) |[leftdevel](https://github.com/leftdevel) |[cryptic022](https://github.com/cryptic022) | :---: |:---: |:---: |:---: |:---: |:---: | -[nil1511](https://github.com/nil1511) |[leftdevel](https://github.com/leftdevel) |[cryptic022](https://github.com/cryptic022) |[patricklindsay](https://github.com/patricklindsay) |[plneto](https://github.com/plneto) |[pedrofs](https://github.com/pedrofs) | +[naveed-ahmad](https://github.com/naveed-ahmad) |[nicojones](https://github.com/nicojones) |[coreprocess](https://github.com/coreprocess) |[nil1511](https://github.com/nil1511) |[leftdevel](https://github.com/leftdevel) |[cryptic022](https://github.com/cryptic022) | -[pmusaraj](https://github.com/pmusaraj) |[phillipalexander](https://github.com/phillipalexander) |[ppadmavilasom](https://github.com/ppadmavilasom) |[Pzoco](https://github.com/Pzoco) |[eman8519](https://github.com/eman8519) |[luarmr](https://github.com/luarmr) | +[patricklindsay](https://github.com/patricklindsay) |[plneto](https://github.com/plneto) |[pedrofs](https://github.com/pedrofs) |[pmusaraj](https://github.com/pmusaraj) |[phillipalexander](https://github.com/phillipalexander) |[ppadmavilasom](https://github.com/ppadmavilasom) | :---: |:---: |:---: |:---: |:---: |:---: | -[pmusaraj](https://github.com/pmusaraj) |[phillipalexander](https://github.com/phillipalexander) |[ppadmavilasom](https://github.com/ppadmavilasom) |[Pzoco](https://github.com/Pzoco) |[eman8519](https://github.com/eman8519) |[luarmr](https://github.com/luarmr) | +[patricklindsay](https://github.com/patricklindsay) |[plneto](https://github.com/plneto) |[pedrofs](https://github.com/pedrofs) |[pmusaraj](https://github.com/pmusaraj) |[phillipalexander](https://github.com/phillipalexander) |[ppadmavilasom](https://github.com/ppadmavilasom) | -[refo](https://github.com/refo) |[SxDx](https://github.com/SxDx) |[robwilson1](https://github.com/robwilson1) |[romain-preston](https://github.com/romain-preston) |[scherroman](https://github.com/scherroman) |[rossng](https://github.com/rossng) | +[Pzoco](https://github.com/Pzoco) |[eman8519](https://github.com/eman8519) |[luarmr](https://github.com/luarmr) |[refo](https://github.com/refo) |[SxDx](https://github.com/SxDx) |[robwilson1](https://github.com/robwilson1) | :---: |:---: |:---: |:---: |:---: |:---: | -[refo](https://github.com/refo) |[SxDx](https://github.com/SxDx) |[robwilson1](https://github.com/robwilson1) |[romain-preston](https://github.com/romain-preston) |[scherroman](https://github.com/scherroman) |[rossng](https://github.com/rossng) | +[Pzoco](https://github.com/Pzoco) |[eman8519](https://github.com/eman8519) |[luarmr](https://github.com/luarmr) |[refo](https://github.com/refo) |[SxDx](https://github.com/SxDx) |[robwilson1](https://github.com/robwilson1) | -[rart](https://github.com/rart) |[fortunto2](https://github.com/fortunto2) |[samuelcolburn](https://github.com/samuelcolburn) |[sebasegovia01](https://github.com/sebasegovia01) |[sergei-zelinsky](https://github.com/sergei-zelinsky) |[szh](https://github.com/szh) | +[romain-preston](https://github.com/romain-preston) |[scherroman](https://github.com/scherroman) |[rossng](https://github.com/rossng) |[rart](https://github.com/rart) |[fortunto2](https://github.com/fortunto2) |[samuelcolburn](https://github.com/samuelcolburn) | :---: |:---: |:---: |:---: |:---: |:---: | -[rart](https://github.com/rart) |[fortunto2](https://github.com/fortunto2) |[samuelcolburn](https://github.com/samuelcolburn) |[sebasegovia01](https://github.com/sebasegovia01) |[sergei-zelinsky](https://github.com/sergei-zelinsky) |[szh](https://github.com/szh) | +[romain-preston](https://github.com/romain-preston) |[scherroman](https://github.com/scherroman) |[rossng](https://github.com/rossng) |[rart](https://github.com/rart) |[fortunto2](https://github.com/fortunto2) |[samuelcolburn](https://github.com/samuelcolburn) | -[SpazzMarticus](https://github.com/SpazzMarticus) |[waptik](https://github.com/waptik) |[amaitu](https://github.com/amaitu) |[steverob](https://github.com/steverob) |[sjauld](https://github.com/sjauld) |[taj](https://github.com/taj) | +[sebasegovia01](https://github.com/sebasegovia01) |[sergei-zelinsky](https://github.com/sergei-zelinsky) |[szh](https://github.com/szh) |[SpazzMarticus](https://github.com/SpazzMarticus) |[waptik](https://github.com/waptik) |[amaitu](https://github.com/amaitu) | :---: |:---: |:---: |:---: |:---: |:---: | -[SpazzMarticus](https://github.com/SpazzMarticus) |[waptik](https://github.com/waptik) |[amaitu](https://github.com/amaitu) |[steverob](https://github.com/steverob) |[sjauld](https://github.com/sjauld) |[taj](https://github.com/taj) | +[sebasegovia01](https://github.com/sebasegovia01) |[sergei-zelinsky](https://github.com/sergei-zelinsky) |[szh](https://github.com/szh) |[SpazzMarticus](https://github.com/SpazzMarticus) |[waptik](https://github.com/waptik) |[amaitu](https://github.com/amaitu) | -[Tashows](https://github.com/Tashows) |[twarlop](https://github.com/twarlop) |[tmaier](https://github.com/tmaier) |[WIStudent](https://github.com/WIStudent) |[tomsaleeba](https://github.com/tomsaleeba) |[tomekp](https://github.com/tomekp) | +[steverob](https://github.com/steverob) |[sjauld](https://github.com/sjauld) |[taj](https://github.com/taj) |[Tashows](https://github.com/Tashows) |[twarlop](https://github.com/twarlop) |[tmaier](https://github.com/tmaier) | :---: |:---: |:---: |:---: |:---: |:---: | -[Tashows](https://github.com/Tashows) |[twarlop](https://github.com/twarlop) |[tmaier](https://github.com/tmaier) |[WIStudent](https://github.com/WIStudent) |[tomsaleeba](https://github.com/tomsaleeba) |[tomekp](https://github.com/tomekp) | +[steverob](https://github.com/steverob) |[sjauld](https://github.com/sjauld) |[taj](https://github.com/taj) |[Tashows](https://github.com/Tashows) |[twarlop](https://github.com/twarlop) |[tmaier](https://github.com/tmaier) | -[tvaliasek](https://github.com/tvaliasek) |[vially](https://github.com/vially) |[valentinoli](https://github.com/valentinoli) |[nagyv](https://github.com/nagyv) |[dwnste](https://github.com/dwnste) |[weston-sankey-mark43](https://github.com/weston-sankey-mark43) | +[WIStudent](https://github.com/WIStudent) |[tomsaleeba](https://github.com/tomsaleeba) |[tomekp](https://github.com/tomekp) |[tvaliasek](https://github.com/tvaliasek) |[vially](https://github.com/vially) |[valentinoli](https://github.com/valentinoli) | :---: |:---: |:---: |:---: |:---: |:---: | -[tvaliasek](https://github.com/tvaliasek) |[vially](https://github.com/vially) |[valentinoli](https://github.com/valentinoli) |[nagyv](https://github.com/nagyv) |[dwnste](https://github.com/dwnste) |[weston-sankey-mark43](https://github.com/weston-sankey-mark43) | +[WIStudent](https://github.com/WIStudent) |[tomsaleeba](https://github.com/tomsaleeba) |[tomekp](https://github.com/tomekp) |[tvaliasek](https://github.com/tvaliasek) |[vially](https://github.com/vially) |[valentinoli](https://github.com/valentinoli) | -[willycamargo](https://github.com/willycamargo) |[xhocquet](https://github.com/xhocquet) |[YehudaKremer](https://github.com/YehudaKremer) |[zachconner](https://github.com/zachconner) |[zacharylawson](https://github.com/zacharylawson) |[zackbloom](https://github.com/zackbloom) | +[nagyv](https://github.com/nagyv) |[dwnste](https://github.com/dwnste) |[weston-sankey-mark43](https://github.com/weston-sankey-mark43) |[willycamargo](https://github.com/willycamargo) |[xhocquet](https://github.com/xhocquet) |[YehudaKremer](https://github.com/YehudaKremer) | :---: |:---: |:---: |:---: |:---: |:---: | -[willycamargo](https://github.com/willycamargo) |[xhocquet](https://github.com/xhocquet) |[YehudaKremer](https://github.com/YehudaKremer) |[zachconner](https://github.com/zachconner) |[zacharylawson](https://github.com/zacharylawson) |[zackbloom](https://github.com/zackbloom) | +[nagyv](https://github.com/nagyv) |[dwnste](https://github.com/dwnste) |[weston-sankey-mark43](https://github.com/weston-sankey-mark43) |[willycamargo](https://github.com/willycamargo) |[xhocquet](https://github.com/xhocquet) |[YehudaKremer](https://github.com/YehudaKremer) | -[sartoshi-foot-dao](https://github.com/sartoshi-foot-dao) |[agreene-coursera](https://github.com/agreene-coursera) |[alfatv](https://github.com/alfatv) |[arggh](https://github.com/arggh) |[avalla](https://github.com/avalla) |[bdirito](https://github.com/bdirito) | +[zachconner](https://github.com/zachconner) |[zacharylawson](https://github.com/zacharylawson) |[zackbloom](https://github.com/zackbloom) |[sartoshi-foot-dao](https://github.com/sartoshi-foot-dao) |[agreene-coursera](https://github.com/agreene-coursera) |[alfatv](https://github.com/alfatv) | :---: |:---: |:---: |:---: |:---: |:---: | -[sartoshi-foot-dao](https://github.com/sartoshi-foot-dao) |[agreene-coursera](https://github.com/agreene-coursera) |[alfatv](https://github.com/alfatv) |[arggh](https://github.com/arggh) |[avalla](https://github.com/avalla) |[bdirito](https://github.com/bdirito) | +[zachconner](https://github.com/zachconner) |[zacharylawson](https://github.com/zacharylawson) |[zackbloom](https://github.com/zackbloom) |[sartoshi-foot-dao](https://github.com/sartoshi-foot-dao) |[agreene-coursera](https://github.com/agreene-coursera) |[alfatv](https://github.com/alfatv) | -[c0b41](https://github.com/c0b41) |[canvasbh](https://github.com/canvasbh) |[christianwengert](https://github.com/christianwengert) |[craigcbrunner](https://github.com/craigcbrunner) |[darthf1](https://github.com/darthf1) |[dkisic](https://github.com/dkisic) | +[arggh](https://github.com/arggh) |[avalla](https://github.com/avalla) |[bdirito](https://github.com/bdirito) |[c0b41](https://github.com/c0b41) |[canvasbh](https://github.com/canvasbh) |[christianwengert](https://github.com/christianwengert) | :---: |:---: |:---: |:---: |:---: |:---: | -[c0b41](https://github.com/c0b41) |[canvasbh](https://github.com/canvasbh) |[christianwengert](https://github.com/christianwengert) |[craigcbrunner](https://github.com/craigcbrunner) |[darthf1](https://github.com/darthf1) |[dkisic](https://github.com/dkisic) | +[arggh](https://github.com/arggh) |[avalla](https://github.com/avalla) |[bdirito](https://github.com/bdirito) |[c0b41](https://github.com/c0b41) |[canvasbh](https://github.com/canvasbh) |[christianwengert](https://github.com/christianwengert) | -[fingul](https://github.com/fingul) |[franckl](https://github.com/franckl) |[gaelicwinter](https://github.com/gaelicwinter) |[green-mike](https://github.com/green-mike) |[heocoi](https://github.com/heocoi) |[hxgf](https://github.com/hxgf) | +[craigcbrunner](https://github.com/craigcbrunner) |[darthf1](https://github.com/darthf1) |[dkisic](https://github.com/dkisic) |[fingul](https://github.com/fingul) |[franckl](https://github.com/franckl) |[gaelicwinter](https://github.com/gaelicwinter) | :---: |:---: |:---: |:---: |:---: |:---: | -[fingul](https://github.com/fingul) |[franckl](https://github.com/franckl) |[gaelicwinter](https://github.com/gaelicwinter) |[green-mike](https://github.com/green-mike) |[heocoi](https://github.com/heocoi) |[hxgf](https://github.com/hxgf) | +[craigcbrunner](https://github.com/craigcbrunner) |[darthf1](https://github.com/darthf1) |[dkisic](https://github.com/dkisic) |[fingul](https://github.com/fingul) |[franckl](https://github.com/franckl) |[gaelicwinter](https://github.com/gaelicwinter) | -[johnmanjiro13](https://github.com/johnmanjiro13) |[kode-ninja](https://github.com/kode-ninja) |[jx-zyf](https://github.com/jx-zyf) |[magumbo](https://github.com/magumbo) |[ninesalt](https://github.com/ninesalt) |[phil714](https://github.com/phil714) | +[green-mike](https://github.com/green-mike) |[heocoi](https://github.com/heocoi) |[hxgf](https://github.com/hxgf) |[johnmanjiro13](https://github.com/johnmanjiro13) |[kode-ninja](https://github.com/kode-ninja) |[jx-zyf](https://github.com/jx-zyf) | :---: |:---: |:---: |:---: |:---: |:---: | -[johnmanjiro13](https://github.com/johnmanjiro13) |[kode-ninja](https://github.com/kode-ninja) |[jx-zyf](https://github.com/jx-zyf) |[magumbo](https://github.com/magumbo) |[ninesalt](https://github.com/ninesalt) |[phil714](https://github.com/phil714) | +[green-mike](https://github.com/green-mike) |[heocoi](https://github.com/heocoi) |[hxgf](https://github.com/hxgf) |[johnmanjiro13](https://github.com/johnmanjiro13) |[kode-ninja](https://github.com/kode-ninja) |[jx-zyf](https://github.com/jx-zyf) | -[luntta](https://github.com/luntta) |[rhymes](https://github.com/rhymes) |[rlebosse](https://github.com/rlebosse) |[rtaieb](https://github.com/rtaieb) |[slawexxx44](https://github.com/slawexxx44) |[thanhthot](https://github.com/thanhthot) | +[magumbo](https://github.com/magumbo) |[ninesalt](https://github.com/ninesalt) |[phil714](https://github.com/phil714) |[luntta](https://github.com/luntta) |[rhymes](https://github.com/rhymes) |[rlebosse](https://github.com/rlebosse) | :---: |:---: |:---: |:---: |:---: |:---: | -[luntta](https://github.com/luntta) |[rhymes](https://github.com/rhymes) |[rlebosse](https://github.com/rlebosse) |[rtaieb](https://github.com/rtaieb) |[slawexxx44](https://github.com/slawexxx44) |[thanhthot](https://github.com/thanhthot) | +[magumbo](https://github.com/magumbo) |[ninesalt](https://github.com/ninesalt) |[phil714](https://github.com/phil714) |[luntta](https://github.com/luntta) |[rhymes](https://github.com/rhymes) |[rlebosse](https://github.com/rlebosse) | -[tinny77](https://github.com/tinny77) |[tusharjkhunt](https://github.com/tusharjkhunt) |[vedran555](https://github.com/vedran555) |[yoann-hellopret](https://github.com/yoann-hellopret) |[olitomas](https://github.com/olitomas) |[JimmyLv](https://github.com/JimmyLv) | +[rtaieb](https://github.com/rtaieb) |[slawexxx44](https://github.com/slawexxx44) |[thanhthot](https://github.com/thanhthot) |[tinny77](https://github.com/tinny77) |[tusharjkhunt](https://github.com/tusharjkhunt) |[vedran555](https://github.com/vedran555) | :---: |:---: |:---: |:---: |:---: |:---: | -[tinny77](https://github.com/tinny77) |[tusharjkhunt](https://github.com/tusharjkhunt) |[vedran555](https://github.com/vedran555) |[yoann-hellopret](https://github.com/yoann-hellopret) |[olitomas](https://github.com/olitomas) |[JimmyLv](https://github.com/JimmyLv) | +[rtaieb](https://github.com/rtaieb) |[slawexxx44](https://github.com/slawexxx44) |[thanhthot](https://github.com/thanhthot) |[tinny77](https://github.com/tinny77) |[tusharjkhunt](https://github.com/tusharjkhunt) |[vedran555](https://github.com/vedran555) | + +[yoann-hellopret](https://github.com/yoann-hellopret) |[olitomas](https://github.com/olitomas) |[JimmyLv](https://github.com/JimmyLv) | +:---: |:---: |:---: | +[yoann-hellopret](https://github.com/yoann-hellopret) |[olitomas](https://github.com/olitomas) |[JimmyLv](https://github.com/JimmyLv) | diff --git a/e2e/clients/dashboard-ui/app.js b/e2e/clients/dashboard-ui/app.js index 93ac419d69..6e63ab9a14 100644 --- a/e2e/clients/dashboard-ui/app.js +++ b/e2e/clients/dashboard-ui/app.js @@ -1,13 +1,36 @@ import Uppy from '@uppy/core' import Dashboard from '@uppy/dashboard' +import RemoteSources from '@uppy/remote-sources' +import Webcam from '@uppy/webcam' +import ScreenCapture from '@uppy/screen-capture' +import GoldenRetriever from '@uppy/golden-retriever' import ImageEditor from '@uppy/image-editor' +import DropTarget from '@uppy/drop-target' +import Audio from '@uppy/audio' +import Compressor from '@uppy/compressor' import '@uppy/core/dist/style.css' import '@uppy/dashboard/dist/style.css' +const COMPANION_URL = 'http://companion.uppy.io' + const uppy = new Uppy() .use(Dashboard, { target: '#app', inline: true }) + .use(RemoteSources, { companionUrl: COMPANION_URL }) + .use(Webcam, { + target: Dashboard, + showVideoSourceDropdown: true, + showRecordingLength: true, + }) + .use(Audio, { + target: Dashboard, + showRecordingLength: true, + }) + .use(ScreenCapture, { target: Dashboard }) .use(ImageEditor, { target: Dashboard }) + .use(DropTarget, { target: document.body }) + .use(Compressor) + .use(GoldenRetriever, { serviceWorker: true }) // Keep this here to access uppy in tests window.uppy = uppy diff --git a/e2e/cypress.config.mjs b/e2e/cypress.config.mjs new file mode 100644 index 0000000000..7f5e81f736 --- /dev/null +++ b/e2e/cypress.config.mjs @@ -0,0 +1,16 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { defineConfig } from 'cypress' + +export default defineConfig({ + defaultCommandTimeout: 16000, + + e2e: { + baseUrl: 'http://localhost:1234', + specPattern: 'cypress/integration/*.spec.ts', + + // eslint-disable-next-line no-unused-vars + setupNodeEvents (on, config) { + // implement node event listeners here + }, + }, +}) diff --git a/e2e/cypress.json b/e2e/cypress.json deleted file mode 100644 index 0151aa17ec..0000000000 --- a/e2e/cypress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "projectId": "mcijsj", - "baseUrl": "http://localhost:1234", - "defaultCommandTimeout": 16000 -} diff --git a/e2e/cypress/integration/dashboard-compressor.spec.ts b/e2e/cypress/integration/dashboard-compressor.spec.ts index 0cc63fb228..93b22858ca 100644 --- a/e2e/cypress/integration/dashboard-compressor.spec.ts +++ b/e2e/cypress/integration/dashboard-compressor.spec.ts @@ -22,13 +22,13 @@ function uglierBytes (text) { describe('dashboard-compressor', () => { beforeEach(() => { cy.visit('/dashboard-compressor') - cy.get('.uppy-Dashboard-input').as('file-input') + cy.get('.uppy-Dashboard-input:first').as('file-input') }) it('should compress images', () => { const sizeBeforeCompression = [] - cy.get('@file-input').attachFile(['images/cat.jpg', 'images/traffic.jpg']) + cy.get('@file-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) cy.get('.uppy-Dashboard-Item-statusSize').each((element) => { const text = element.text() diff --git a/e2e/cypress/integration/dashboard-transloadit.spec.ts b/e2e/cypress/integration/dashboard-transloadit.spec.ts index f9087c3b8f..0d4dc32107 100644 --- a/e2e/cypress/integration/dashboard-transloadit.spec.ts +++ b/e2e/cypress/integration/dashboard-transloadit.spec.ts @@ -1,13 +1,14 @@ describe('Dashboard with Transloadit', () => { beforeEach(() => { cy.visit('/dashboard-transloadit') - cy.get('.uppy-Dashboard-input').as('file-input') + cy.get('.uppy-Dashboard-input:first').as('file-input') + cy.intercept('/assemblies').as('createAssemblies') cy.intercept('/assemblies/*').as('assemblies') cy.intercept('/resumable/*').as('resumable') }) it('should upload cat image successfully', () => { - cy.get('@file-input').attachFile('images/cat.jpg') + cy.get('@file-input').selectFile('cypress/fixtures/images/cat.jpg', { force:true }) cy.get('.uppy-StatusBar-actionBtn--upload').click() cy.wait('@assemblies') @@ -17,7 +18,7 @@ describe('Dashboard with Transloadit', () => { }) it('should close assembly polling when cancelled', () => { - cy.get('@file-input').attachFile(['images/cat.jpg', 'images/traffic.jpg']) + cy.get('@file-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) cy.get('.uppy-StatusBar-actionBtn--upload').click() cy.intercept({ @@ -42,4 +43,73 @@ describe('Dashboard with Transloadit', () => { expect(Object.values(uppy.getPlugin('Transloadit').activeAssemblies).some((a: any) => a.pollInterval)).to.equal(false) }) }) + + it('should not create assembly when all individual files have been cancelled', () => { + cy.get('@file-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) + cy.get('.uppy-StatusBar-actionBtn--upload').click() + + cy.window().then(({ uppy }) => { + expect(Object.values(uppy.getPlugin('Transloadit').activeAssemblies).length).to.equal(0) + + const { files } = uppy.getState() + uppy.removeFiles(Object.keys(files)) + + cy.wait('@createAssemblies').then(() => { + expect(Object.values(uppy.getPlugin('Transloadit').activeAssemblies).some((a: any) => a.pollInterval)).to.equal(false) + }) + }) + }) + + // Not working, the upstream changes have not landed yet. + it.skip('should create assembly if there is still one file to upload', () => { + cy.get('@file-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) + cy.get('.uppy-StatusBar-actionBtn--upload').click() + + cy.window().then(({ uppy }) => { + expect(Object.values(uppy.getPlugin('Transloadit').activeAssemblies).length).to.equal(0) + + const { files } = uppy.getState() + const [fileID] = Object.keys(files) + uppy.removeFile(fileID) + + cy.wait('@createAssemblies').then(() => { + cy.wait('@resumable') + cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') + }) + }) + }) + + // Not working, the upstream changes have not landed yet. + it.skip('should complete upload if one gets cancelled mid-flight', () => { + cy.get('@file-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) + cy.get('.uppy-StatusBar-actionBtn--upload').click() + + cy.wait('@createAssemblies') + cy.wait('@resumable') + + cy.window().then(({ uppy }) => { + const { files } = uppy.getState() + const [fileID] = Object.keys(files) + uppy.removeFile(fileID) + + cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') + }) + }) + + it('should not emit error if upload is cancelled right away', () => { + cy.get('@file-input').selectFile('cypress/fixtures/images/cat.jpg', { force:true }) + cy.get('.uppy-StatusBar-actionBtn--upload').click() + + const handler = cy.spy() + + cy.window().then(({ uppy }) => { + const { files } = uppy.getState() + uppy.on('upload-error', handler) + + const [fileID] = Object.keys(files) + uppy.removeFile(fileID) + uppy.removeFile(fileID) + cy.wait('@createAssemblies').then(() => expect(handler).not.to.be.called) + }) + }) }) diff --git a/e2e/cypress/integration/dashboard-tus.spec.ts b/e2e/cypress/integration/dashboard-tus.spec.ts index 9657f2b11f..4d44137146 100644 --- a/e2e/cypress/integration/dashboard-tus.spec.ts +++ b/e2e/cypress/integration/dashboard-tus.spec.ts @@ -10,14 +10,14 @@ type Tus = BaseTus & { describe('Dashboard with Tus', () => { beforeEach(() => { cy.visit('/dashboard-tus') - cy.get('.uppy-Dashboard-input').as('file-input') + cy.get('.uppy-Dashboard-input:first').as('file-input') cy.intercept('/files/*').as('tus') cy.intercept('http://localhost:3020/url/*').as('url') cy.intercept('http://localhost:3020/search/unsplash/*').as('unsplash') }) it('should upload cat image successfully', () => { - cy.get('@file-input').attachFile('images/cat.jpg') + cy.get('@file-input').selectFile('cypress/fixtures/images/cat.jpg', { force:true }) cy.get('.uppy-StatusBar-actionBtn--upload').click() cy.wait('@tus') @@ -25,24 +25,32 @@ describe('Dashboard with Tus', () => { cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') }) - it('should start exponential backoff when receiving HTTP 429', () => { - cy.get('@file-input').attachFile(['images/baboon.png']) - cy.get('.uppy-StatusBar-actionBtn--upload').click() + it( + 'should start exponential backoff when receiving HTTP 429', + { + retries: { + runMode: 3, // retry flaky test + }, + }, + () => { + cy.get('@file-input').selectFile('cypress/fixtures/images/baboon.png', { force:true }) + cy.get('.uppy-StatusBar-actionBtn--upload').click() - cy.intercept( - { method: 'PATCH', pathname: '/files/*', times: 2 }, - { statusCode: 429, body: {} }, - ).as('patch') + cy.intercept( + { method: 'PATCH', pathname: '/files/*', times: 2 }, + { statusCode: 429, body: {} }, + ).as('patch') - cy.wait('@patch') - cy.wait('@patch') + cy.wait('@patch') + cy.wait('@patch') - cy.window().then(({ uppy }) => { - expect(uppy.getPlugin('Tus').requests.isPaused).to.equal(true) - cy.wait('@tus') - cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') - }) - }) + cy.window().then(({ uppy }) => { + expect(uppy.getPlugin('Tus').requests.isPaused).to.equal(true) + cy.wait('@tus') + cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete') + }) + }, + ) it('should upload remote image with URL plugin', () => { cy.get('[data-cy="Url"]').click() diff --git a/e2e/cypress/integration/dashboard-ui.spec.ts b/e2e/cypress/integration/dashboard-ui.spec.ts index 4baead87fe..f68ec8b156 100644 --- a/e2e/cypress/integration/dashboard-ui.spec.ts +++ b/e2e/cypress/integration/dashboard-ui.spec.ts @@ -1,11 +1,19 @@ describe('dashboard-ui', () => { beforeEach(() => { cy.visit('/dashboard-ui') - cy.get('.uppy-Dashboard-input').as('file-input') + cy.get('.uppy-Dashboard-input:first').as('file-input') + }) + + it('should not throw when calling uppy.close()', () => { + cy.get('@file-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) + + cy.window().then(({ uppy }) => { + expect(uppy.close()).to.not.throw + }) }) it('should render thumbnails', () => { - cy.get('@file-input').attachFile(['images/cat.jpg', 'images/traffic.jpg']) + cy.get('@file-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) cy.get('.uppy-Dashboard-Item-previewImg') .should('have.length', 2) .each((element) => expect(element).attr('src').to.include('blob:')) diff --git a/e2e/cypress/integration/dashboard-vue.spec.ts b/e2e/cypress/integration/dashboard-vue.spec.ts index c2d9a3516b..d36860d3b3 100644 --- a/e2e/cypress/integration/dashboard-vue.spec.ts +++ b/e2e/cypress/integration/dashboard-vue.spec.ts @@ -6,7 +6,7 @@ describe('dashboard-vue', () => { // Only Vue 3 works in Parcel if you use SFC's but Vue 3 is broken in Uppy: // https://github.com/transloadit/uppy/issues/2877 xit('should render in Vue 3 and show thumbnails', () => { - cy.get('@file-input').attachFile(['images/cat.jpg', 'images/traffic.jpg']) + cy.get('@file-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) cy.get('.uppy-Dashboard-Item-previewImg') .should('have.length', 2) .each((element) => expect(element).attr('src').to.include('blob:')) diff --git a/e2e/cypress/integration/react.spec.ts b/e2e/cypress/integration/react.spec.ts index ef5989d628..b3120e7b57 100644 --- a/e2e/cypress/integration/react.spec.ts +++ b/e2e/cypress/integration/react.spec.ts @@ -1,13 +1,13 @@ describe('@uppy/react', () => { beforeEach(() => { cy.visit('/react') - cy.get('#dashboard .uppy-Dashboard-input').as('dashboard-input') - cy.get('#modal .uppy-Dashboard-input').as('modal-input') + cy.get('#dashboard .uppy-Dashboard-input:first').as('dashboard-input') + cy.get('#modal .uppy-Dashboard-input:first').as('modal-input') cy.get('#drag-drop .uppy-DragDrop-input').as('dragdrop-input') }) it('should render Dashboard in React and show thumbnails', () => { - cy.get('@dashboard-input').attachFile(['images/cat.jpg', 'images/traffic.jpg']) + cy.get('@dashboard-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) cy.get('#dashboard .uppy-Dashboard-Item-previewImg') .should('have.length', 2) .each((element) => expect(element).attr('src').to.include('blob:')) @@ -15,7 +15,7 @@ describe('@uppy/react', () => { it('should render Modal in React and show thumbnails', () => { cy.get('#open').click() - cy.get('@modal-input').attachFile(['images/cat.jpg', 'images/traffic.jpg']) + cy.get('@modal-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) cy.get('#modal .uppy-Dashboard-Item-previewImg') .should('have.length', 2) .each((element) => expect(element).attr('src').to.include('blob:')) @@ -25,7 +25,7 @@ describe('@uppy/react', () => { const spy = cy.spy() cy.window().then(({ uppy }) => uppy.on('thumbnail:generated', spy)) - cy.get('@dragdrop-input').attachFile(['images/cat.jpg', 'images/traffic.jpg']) + cy.get('@dragdrop-input').selectFile(['cypress/fixtures/images/cat.jpg', 'cypress/fixtures/images/traffic.jpg'], { force:true }) // not sure how I can accurately wait for the thumbnail // eslint-disable-next-line cypress/no-unnecessary-waiting cy.wait(1000).then(() => expect(spy).to.be.called) diff --git a/e2e/cypress/plugins/index.js b/e2e/cypress/plugins/index.js deleted file mode 100644 index 59b2bab6e4..0000000000 --- a/e2e/cypress/plugins/index.js +++ /dev/null @@ -1,22 +0,0 @@ -/// -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -/** - * @type {Cypress.PluginConfig} - */ -// eslint-disable-next-line no-unused-vars -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config -} diff --git a/e2e/cypress/support/commands.ts b/e2e/cypress/support/commands.ts index fafe15d889..2bf214d22f 100644 --- a/e2e/cypress/support/commands.ts +++ b/e2e/cypress/support/commands.ts @@ -25,9 +25,6 @@ // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) // -/* eslint-disable-next-line import/no-extraneous-dependencies */ -import 'cypress-file-upload' - import { createFakeFile } from './createFakeFile' Cypress.Commands.add('createFakeFile', createFakeFile) diff --git a/e2e/cypress/support/e2e.ts b/e2e/cypress/support/e2e.ts new file mode 100644 index 0000000000..ed5730de11 --- /dev/null +++ b/e2e/cypress/support/e2e.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/e2e.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/e2e/package.json b/e2e/package.json index 2dbd445094..3642f81205 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -6,7 +6,7 @@ "scripts": { "client:start": "parcel clients/index.html", "cypress:open": "cypress open", - "cypress:headless": "cypress run --record", + "cypress:headless": "cypress run", "generate-test": "yarn node generate-test.mjs" }, "dependencies": { @@ -45,8 +45,7 @@ "@uppy/zoom": "workspace:^" }, "devDependencies": { - "cypress": "^9.0.0", - "cypress-file-upload": "^5.0.8", + "cypress": "^10.0.0", "deep-freeze": "^0.0.1", "parcel": "^2.0.1", "prompts": "^2.4.2", diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json index e6f27d1702..fb294941d3 100644 --- a/e2e/tsconfig.json +++ b/e2e/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "es2020", "lib": ["es2020", "dom"], - "types": ["cypress", "cypress-file-upload"] + "types": ["cypress"] }, "include": ["cypress/**/*.ts"] } diff --git a/packages/@uppy/companion/CHANGELOG.md b/packages/@uppy/companion/CHANGELOG.md index 1cf55a307c..b6b5a28a94 100644 --- a/packages/@uppy/companion/CHANGELOG.md +++ b/packages/@uppy/companion/CHANGELOG.md @@ -21,6 +21,12 @@ Included in: Uppy v3.0.0-beta - @uppy/companion: remove `searchProviders` wrapper & move `s3` options (Merlijn Vos / #3781) - @uppy/companion: remove support for EOL versions of Node.js (Antoine du Hamel / #3784) +## 3.7.1 + +Released: 2022-07-27 +Included in: Uppy v2.13.1 + +- @uppy/companion: Companion app type (Mikael Finstad / #3899) ## 3.7.0 diff --git a/packages/@uppy/compressor/CHANGELOG.md b/packages/@uppy/compressor/CHANGELOG.md index 71b2c6e58a..83c784e6c8 100644 --- a/packages/@uppy/compressor/CHANGELOG.md +++ b/packages/@uppy/compressor/CHANGELOG.md @@ -1,5 +1,12 @@ # @uppy/compressor +## 0.3.1 + +Released: 2022-07-27 +Included in: Uppy v2.13.1 + +- @uppy/compressor: fix upload causing meta name to reset (Justin / #3890) + ## 0.3.0 Released: 2022-05-30 diff --git a/packages/@uppy/compressor/src/index.js b/packages/@uppy/compressor/src/index.js index 185036944a..66ec022bd2 100644 --- a/packages/@uppy/compressor/src/index.js +++ b/packages/@uppy/compressor/src/index.js @@ -60,7 +60,7 @@ export default class Compressor extends BasePlugin { size, data: compressedBlob, }) - this.uppy.setFileMeta(file.id, { name, type }) + this.uppy.setFileMeta(file.id, { type }) compressedFiles.push(file) } catch (err) { this.uppy.log(`[Image Compressor] Failed to compress ${file.id}:`, 'warning') diff --git a/packages/@uppy/core/CHANGELOG.md b/packages/@uppy/core/CHANGELOG.md index 132fa83117..fb72249861 100644 --- a/packages/@uppy/core/CHANGELOG.md +++ b/packages/@uppy/core/CHANGELOG.md @@ -6,6 +6,12 @@ Released: 2022-06-09 Included in: Uppy v3.0.0-beta.1 - @uppy/core,@uppy/dashboard: fix types for some events (Antoine du Hamel / #3812) +## 2.3.2 + +Released: 2022-07-27 +Included in: Uppy v2.13.1 + +- @uppy/core: Add missing type for retry-all event (Luc Boissaye / #3901) ## 2.3.1 diff --git a/packages/@uppy/core/src/Uppy.js b/packages/@uppy/core/src/Uppy.js index af48cd779b..fce36139a6 100644 --- a/packages/@uppy/core/src/Uppy.js +++ b/packages/@uppy/core/src/Uppy.js @@ -677,6 +677,12 @@ class Uppy { return } + const { capabilities } = this.getState() + if (newFileIDs.length !== currentUploads[uploadID].fileIDs.length + && !capabilities.individualCancellation) { + throw new Error('individualCancellation is disabled') + } + updatedUploads[uploadID] = { ...currentUploads[uploadID], fileIDs: newFileIDs, diff --git a/packages/@uppy/core/src/Uppy.test.js b/packages/@uppy/core/src/Uppy.test.js index 01196a635b..5a058f0c20 100644 --- a/packages/@uppy/core/src/Uppy.test.js +++ b/packages/@uppy/core/src/Uppy.test.js @@ -1,6 +1,7 @@ /* eslint no-console: "off", no-restricted-syntax: "off" */ import { afterEach, beforeEach, describe, expect, it, jest, xit } from '@jest/globals' +import assert from 'node:assert' import fs from 'node:fs' import prettierBytes from '@transloadit/prettier-bytes' import Core from '../lib/index.js' @@ -263,6 +264,117 @@ describe('src/Core', () => { expect(Object.keys(core.getState().files).length).toEqual(0) }) + it('should allow remove all uploads when individualCancellation is disabled', () => { + const core = new Core() + + const { capabilities } = core.getState() + core.setState({ + capabilities: { + ...capabilities, + individualCancellation: false, + }, + }) + + core.addFile({ + source: 'jest', + name: 'foo1.jpg', + type: 'image/jpeg', + data: new File([sampleImage], { type: 'image/jpeg' }), + }) + + core.addFile({ + source: 'jest', + name: 'foo2.jpg', + type: 'image/jpeg', + data: new File([sampleImage], { type: 'image/jpeg' }), + }) + + const fileIDs = Object.keys(core.getState().files) + const id = core[Symbol.for('uppy test: createUpload')](fileIDs) + + expect(core.getState().currentUploads[id]).toBeDefined() + expect(Object.keys(core.getState().files).length).toEqual(2) + + core.removeFiles(fileIDs) + + expect(core.getState().currentUploads[id]).toBeUndefined() + expect(Object.keys(core.getState().files).length).toEqual(0) + }) + + it('should disallow remove one upload when individualCancellation is disabled', () => { + const core = new Core() + + const { capabilities } = core.getState() + core.setState({ + capabilities: { + ...capabilities, + individualCancellation: false, + }, + }) + + core.addFile({ + source: 'jest', + name: 'foo1.jpg', + type: 'image/jpeg', + data: new File([sampleImage], { type: 'image/jpeg' }), + }) + + core.addFile({ + source: 'jest', + name: 'foo2.jpg', + type: 'image/jpeg', + data: new File([sampleImage], { type: 'image/jpeg' }), + }) + + const fileIDs = Object.keys(core.getState().files) + const id = core[Symbol.for('uppy test: createUpload')](fileIDs) + + expect(core.getState().currentUploads[id]).toBeDefined() + expect(Object.keys(core.getState().files).length).toEqual(2) + + assert.throws(() => core.removeFile(fileIDs[0]), /individualCancellation is disabled/) + + expect(core.getState().currentUploads[id]).toBeDefined() + expect(Object.keys(core.getState().files).length).toEqual(2) + }) + + it('should allow remove one upload when individualCancellation is enabled', () => { + const core = new Core() + + const { capabilities } = core.getState() + core.setState({ + capabilities: { + ...capabilities, + individualCancellation: true, + }, + }) + + core.addFile({ + source: 'jest', + name: 'foo1.jpg', + type: 'image/jpeg', + data: new File([sampleImage], { type: 'image/jpeg' }), + }) + + core.addFile({ + source: 'jest', + name: 'foo2.jpg', + type: 'image/jpeg', + data: new File([sampleImage], { type: 'image/jpeg' }), + }) + + const fileIDs = Object.keys(core.getState().files) + const id = core[Symbol.for('uppy test: createUpload')](fileIDs) + + expect(core.getState().currentUploads[id]).toBeDefined() + expect(Object.keys(core.getState().files).length).toEqual(2) + + core.removeFile(fileIDs[0]) + + expect(core.getState().currentUploads[id]).toBeDefined() + expect(Object.keys(core.getState().files).length).toEqual(1) + }) + it('should close, reset and uninstall when the close method is called', () => { // use DeepFrozenStore in some tests to make sure we are not mutating things const core = new Core({ diff --git a/packages/@uppy/core/types/index.d.ts b/packages/@uppy/core/types/index.d.ts index 70f6f382e2..60c2b26953 100644 --- a/packages/@uppy/core/types/index.d.ts +++ b/packages/@uppy/core/types/index.d.ts @@ -216,6 +216,8 @@ export type UploadCompleteCallback = (result: UploadResult) => voi export type ErrorCallback = (error: Error) => void; export type UploadErrorCallback = (file: UppyFile | undefined, error: Error, response?: ErrorResponse) => void; export type UploadRetryCallback = (fileID: string) => void; +export type RetryAllCallback = (fileIDs: string[]) => void; + // TODO: reverse the order in the next major version export type RestrictionFailedCallback = (file: UppyFile | undefined, error: Error) => void; @@ -232,6 +234,7 @@ export interface UppyEventMap> { 'error': ErrorCallback 'upload-error': UploadErrorCallback 'upload-retry': UploadRetryCallback + 'retry-all': RetryAllCallback 'info-visible': GenericEventCallback 'info-hidden': GenericEventCallback 'cancel-all': GenericEventCallback diff --git a/packages/@uppy/dashboard/CHANGELOG.md b/packages/@uppy/dashboard/CHANGELOG.md index f097060ff7..a21d0df679 100644 --- a/packages/@uppy/dashboard/CHANGELOG.md +++ b/packages/@uppy/dashboard/CHANGELOG.md @@ -6,6 +6,12 @@ Released: 2022-06-09 Included in: Uppy v3.0.0-beta.1 - @uppy/core,@uppy/dashboard: fix types for some events (Antoine du Hamel / #3812) +## 2.4.1 + +Released: 2022-07-27 +Included in: Uppy v2.13.1 + +- @uppy/dashboard,@uppy/image-editor,@uppy/remote-sources: Fix `uppy.close()` crashes when remote-sources or image-editor is installed (Merlijn Vos / #3914) ## 2.3.0 diff --git a/packages/@uppy/dashboard/src/components/FileCard/index.jsx b/packages/@uppy/dashboard/src/components/FileCard/index.jsx index 481b71a8c8..d1a8d4e4a1 100644 --- a/packages/@uppy/dashboard/src/components/FileCard/index.jsx +++ b/packages/@uppy/dashboard/src/components/FileCard/index.jsx @@ -59,6 +59,8 @@ class FileCard extends Component { } handleCancel = () => { + const file = this.props.files[this.props.fileCardFor] + this.props.uppy.emit('file-editor:cancel', file) this.props.toggleFileCard(false) } diff --git a/packages/@uppy/image-editor/CHANGELOG.md b/packages/@uppy/image-editor/CHANGELOG.md index 2fe6f8b26d..75eab5fc58 100644 --- a/packages/@uppy/image-editor/CHANGELOG.md +++ b/packages/@uppy/image-editor/CHANGELOG.md @@ -1,5 +1,20 @@ # @uppy/image-editor +## 1.4.1 + +Released: 2022-07-27 +Included in: Uppy v2.13.1 + +- @uppy/dashboard,@uppy/image-editor,@uppy/remote-sources: Fix `uppy.close()` crashes when remote-sources or image-editor is installed (Merlijn Vos / #3914) + +## 1.4.0 + +Released: 2022-07-18 +Included in: Uppy v2.13.0 + +- @uppy/image-editor: remove beta notice (Merlijn Vos / #3877) +- @uppy/image-editor: Add image editor cancel event (James R T / #3875) + ## 1.3.0 Released: 2022-05-30 diff --git a/packages/@uppy/image-editor/src/ImageEditor.jsx b/packages/@uppy/image-editor/src/ImageEditor.jsx index 8549079a57..ff97f94dee 100644 --- a/packages/@uppy/image-editor/src/ImageEditor.jsx +++ b/packages/@uppy/image-editor/src/ImageEditor.jsx @@ -121,6 +121,12 @@ export default class ImageEditor extends UIPlugin { } uninstall () { + const { currentImage } = this.getPluginState() + + if (currentImage) { + const file = this.uppy.getFile(currentImage.id) + this.uppy.emit('file-editor:cancel', file) + } this.unmount() } diff --git a/packages/@uppy/image-editor/types/index.d.ts b/packages/@uppy/image-editor/types/index.d.ts index add9409836..c8eace6bd0 100644 --- a/packages/@uppy/image-editor/types/index.d.ts +++ b/packages/@uppy/image-editor/types/index.d.ts @@ -34,10 +34,12 @@ export default ImageEditor export type FileEditorStartCallback = (file: UppyFile) => void; export type FileEditorCompleteCallback = (updatedFile: UppyFile) => void; +export type FileEditorCancelCallback = (file: UppyFile) => void; declare module '@uppy/core' { export interface UppyEventMap { 'file-editor:start' : FileEditorStartCallback 'file-editor:complete': FileEditorCompleteCallback + 'file-editor:cancel': FileEditorCancelCallback } } diff --git a/packages/@uppy/image-editor/types/index.test-d.ts b/packages/@uppy/image-editor/types/index.test-d.ts index 790a466746..de8641a686 100644 --- a/packages/@uppy/image-editor/types/index.test-d.ts +++ b/packages/@uppy/image-editor/types/index.test-d.ts @@ -16,4 +16,8 @@ import ImageEditor from '..' // eslint-disable-next-line @typescript-eslint/no-unused-vars const fileName = file.name }) + uppy.on('file-editor:cancel', (file) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const fileName = file.name + }) } diff --git a/packages/@uppy/remote-sources/CHANGELOG.md b/packages/@uppy/remote-sources/CHANGELOG.md index d53b56a41c..723ae9b405 100644 --- a/packages/@uppy/remote-sources/CHANGELOG.md +++ b/packages/@uppy/remote-sources/CHANGELOG.md @@ -1,5 +1,12 @@ # @uppy/remote-sources +## 0.1.1 + +Released: 2022-07-27 +Included in: Uppy v2.13.1 + +- @uppy/dashboard,@uppy/image-editor,@uppy/remote-sources: Fix `uppy.close()` crashes when remote-sources or image-editor is installed (Merlijn Vos / #3914) + ## 0.1.0 Released: 2022-06-07 diff --git a/packages/@uppy/remote-sources/src/index.js b/packages/@uppy/remote-sources/src/index.js index a332c89eba..1ccd4bf007 100644 --- a/packages/@uppy/remote-sources/src/index.js +++ b/packages/@uppy/remote-sources/src/index.js @@ -70,7 +70,9 @@ export default class RemoteSources extends BasePlugin { throw new Error(`Invalid plugin: "${pluginId}" is not one of: ${formatter.format(pluginNames)}.`) } this.uppy.use(plugin, optsForRemoteSourcePlugin) - this.#installedPlugins.add(plugin) + // `plugin` is a class, but we want to track the instance object + // so we have to do `getPlugin` here. + this.#installedPlugins.add(this.uppy.getPlugin(pluginId)) }) } diff --git a/packages/@uppy/robodog/CHANGELOG.md b/packages/@uppy/robodog/CHANGELOG.md index 20d1097957..5b019b461e 100644 --- a/packages/@uppy/robodog/CHANGELOG.md +++ b/packages/@uppy/robodog/CHANGELOG.md @@ -1,5 +1,12 @@ # @uppy/robodog +## 2.8.3 + +Released: 2022-07-11 +Included in: Uppy v2.12.3 + +- @uppy/robodog,@uppy/transloadit: use modern syntax to simplify code (Antoine du Hamel / #3873) + ## 2.8.0 Released: 2022-06-07 diff --git a/packages/@uppy/robodog/src/TransloaditFormResult.js b/packages/@uppy/robodog/src/TransloaditFormResult.js index da95e39fe4..662f95b67e 100644 --- a/packages/@uppy/robodog/src/TransloaditFormResult.js +++ b/packages/@uppy/robodog/src/TransloaditFormResult.js @@ -17,17 +17,12 @@ class TransloaditFormResult extends BasePlugin { } getAssemblyStatuses (fileIDs) { - const assemblyIds = [] - fileIDs.forEach((fileID) => { - const file = this.uppy.getFile(fileID) - const assembly = file.transloadit && file.transloadit.assembly - if (assembly && assemblyIds.indexOf(assembly) === -1) { - assemblyIds.push(assembly) - } - }) + const assemblyIds = new Set( + fileIDs.map(fileID => this.uppy.getFile(fileID)?.transloadit?.assembly).filter(Boolean), + ) const tl = this.uppy.getPlugin(this.opts.transloaditPluginId || 'Transloadit') - return assemblyIds.map((id) => tl.getAssembly(id)) + return Array.from(assemblyIds, (id) => tl.getAssembly(id)) } handleUpload (fileIDs) { diff --git a/packages/@uppy/transloadit/CHANGELOG.md b/packages/@uppy/transloadit/CHANGELOG.md index d27e384a38..aebf18aa87 100644 --- a/packages/@uppy/transloadit/CHANGELOG.md +++ b/packages/@uppy/transloadit/CHANGELOG.md @@ -6,6 +6,27 @@ Released: 2022-05-30 Included in: Uppy v3.0.0-beta - @uppy/transloadit: remove IE 10 hack (Antoine du Hamel / #3777) +## 2.3.5 + +Released: 2022-07-27 +Included in: Uppy v2.13.1 + +- @uppy/transloadit: cancel assemblies when all its files have been removed (Antoine du Hamel / #3893) + +## 2.3.4 + +Released: 2022-07-18 +Included in: Uppy v2.13.0 + +- @uppy/transloadit: fix outdated file ids and incorrect usage of files (Merlijn Vos / #3886) + +## 2.3.3 + +Released: 2022-07-11 +Included in: Uppy v2.12.3 + +- @uppy/transloadit: fix TypeError when file is cancelled asynchronously (Antoine du Hamel / #3872) +- @uppy/robodog,@uppy/transloadit: use modern syntax to simplify code (Antoine du Hamel / #3873) ## 2.3.2 diff --git a/packages/@uppy/transloadit/src/AssemblyOptions.js b/packages/@uppy/transloadit/src/AssemblyOptions.js index cae1bd3422..5b09908edf 100644 --- a/packages/@uppy/transloadit/src/AssemblyOptions.js +++ b/packages/@uppy/transloadit/src/AssemblyOptions.js @@ -30,7 +30,7 @@ function validateParams (params) { */ function dedupe (list) { const dedupeMap = Object.create(null) - for (const { fileIDs, options } of list) { + for (const { fileIDs, options } of list.filter(Boolean)) { const id = JSON.stringify(options) if (id in dedupeMap) { dedupeMap[id].fileIDArrays.push(fileIDs) @@ -62,9 +62,16 @@ class AssemblyOptions { * Get Assembly options for a file. */ async #getAssemblyOptions (file) { - const options = this.opts + if (file == null) return undefined + const options = this.opts const assemblyOptions = await options.getAssemblyOptions(file, options) + + // We check if the file is present here again, because it could had been + // removed during the await, e.g. if the user hit cancel while we were + // waiting for the options. + if (file == null) return undefined + if (Array.isArray(assemblyOptions.fields)) { assemblyOptions.fields = Object.fromEntries( assemblyOptions.fields.map((fieldName) => [fieldName, file.meta[fieldName]]), diff --git a/packages/@uppy/transloadit/src/Client.js b/packages/@uppy/transloadit/src/Client.js index 81c1407220..0d7bbe8d58 100644 --- a/packages/@uppy/transloadit/src/Client.js +++ b/packages/@uppy/transloadit/src/Client.js @@ -20,6 +20,11 @@ export default class Client { this.#fetchWithNetworkError = this.opts.rateLimitedQueue.wrapPromiseFunction(fetchWithNetworkError) } + /** + * @param {RequestInfo | URL} input + * @param {RequestInit} init + * @returns {Promise} + */ #fetchJSON (...args) { return this.#fetchWithNetworkError(...args).then(response => { if (response.status === 429) { @@ -126,6 +131,25 @@ export default class Client { .catch((err) => this.#reportError(err, { assembly, file, url, type: 'API_ERROR' })) } + /** + * Update the number of expected files in an already created assembly. + * + * @param {object} assembly + * @param {number} num_expected_upload_files + */ + updateNumberOfFilesInAssembly (assembly, num_expected_upload_files) { + const url = new URL(assembly.assembly_ssl_url) + url.pathname = '/update_assemblies' + const body = JSON.stringify({ + assembly_updates: [{ + assembly_id: assembly.assembly_id, + num_expected_upload_files, + }], + }) + return this.#fetchJSON(url, { method: 'post', headers: this.#headers, body }) + .catch((err) => this.#reportError(err, { url, type: 'API_ERROR' })) + } + /** * Cancel a running Assembly. * diff --git a/packages/@uppy/transloadit/src/index.js b/packages/@uppy/transloadit/src/index.js index 45e6719909..22a664493b 100644 --- a/packages/@uppy/transloadit/src/index.js +++ b/packages/@uppy/transloadit/src/index.js @@ -190,7 +190,18 @@ export default class Transloadit extends BasePlugin { fields: options.fields, expectedFiles: fileIDs.length, signature: options.signature, - }).then((newAssembly) => { + }).then(async (newAssembly) => { + const files = this.uppy.getFiles().filter(({ id }) => fileIDs.includes(id)) + if (files.length !== fileIDs.length) { + if (files.length === 0) { + // All files have been removed, cancelling. + await this.client.cancelAssembly(newAssembly) + return null + } + // At least one file has been removed. + await this.client.updateNumberOfFilesInAssembly(newAssembly, files.length) + } + const assembly = new Assembly(newAssembly, this.#rateLimitedQueue) const { status } = assembly const assemblyID = status.assembly_id @@ -212,26 +223,33 @@ export default class Transloadit extends BasePlugin { }, }) - const { files } = this.uppy.getState() const updatedFiles = {} - fileIDs.forEach((id) => { - updatedFiles[id] = this.#attachAssemblyMetadata(this.uppy.getFile(id), status) + files.forEach((file) => { + updatedFiles[file.id] = this.#attachAssemblyMetadata(file, status) }) + this.uppy.setState({ files: { - ...files, + ...this.uppy.getState().files, ...updatedFiles, }, }) + const fileRemovedHandler = (fileRemoved, reason) => { if (reason === 'cancel-all') { assembly.close() + this.client.cancelAssembly(newAssembly).catch(() => { /* ignore potential errors */ }) this.uppy.off(fileRemovedHandler) } else if (fileRemoved.id in updatedFiles) { delete updatedFiles[fileRemoved.id] - if (Object.keys(updatedFiles).length === 0) { + const nbOfRemainingFiles = Object.keys(updatedFiles).length + if (nbOfRemainingFiles === 0) { assembly.close() + this.client.cancelAssembly(newAssembly).catch(() => { /* ignore potential errors */ }) this.uppy.off(fileRemovedHandler) + } else { + this.client.updateNumberOfFilesInAssembly(newAssembly, nbOfRemainingFiles) + .catch(() => { /* ignore potential errors */ }) } } } @@ -253,7 +271,7 @@ export default class Transloadit extends BasePlugin { }) } - #createAssemblyWatcher (assemblyID, fileIDs, uploadID) { + #createAssemblyWatcher (assemblyID, uploadID) { // AssemblyWatcher tracks completion states of all Assemblies in this upload. const watcher = new AssemblyWatcher(this.uppy, assemblyID) @@ -300,7 +318,7 @@ export default class Transloadit extends BasePlugin { */ #onFileUploadURLAvailable = (rawFile) => { const file = this.uppy.getFile(rawFile.id) - if (!file || !file.transloadit || !file.transloadit.assembly) { + if (!file?.transloadit?.assembly) { return } @@ -497,10 +515,7 @@ export default class Transloadit extends BasePlugin { // Set up the assembly watchers again for all the ongoing uploads. Object.keys(uploadsAssemblies).forEach((uploadID) => { const assemblyIDs = uploadsAssemblies[uploadID] - const fileIDsInUpload = assemblyIDs.flatMap((assemblyID) => { - return this.getAssemblyFiles(assemblyID).map((file) => file.id) - }) - this.#createAssemblyWatcher(assemblyIDs, fileIDsInUpload, uploadID) + this.#createAssemblyWatcher(assemblyIDs, uploadID) }) const allAssemblyIDs = Object.keys(assemblies) @@ -586,16 +601,16 @@ export default class Transloadit extends BasePlugin { } #prepareUpload = (fileIDs, uploadID) => { - // Only use files without errors - const filteredFileIDs = fileIDs.filter((file) => !file.error) - - const files = filteredFileIDs.map(fileID => { - const file = this.uppy.getFile(fileID) - this.uppy.emit('preprocess-progress', file, { - mode: 'indeterminate', - message: this.i18n('creatingAssembly'), - }) - return file + const files = fileIDs.map(id => this.uppy.getFile(id)) + const filesWithoutErrors = files.filter((file) => { + if (!file.error) { + this.uppy.emit('preprocess-progress', file, { + mode: 'indeterminate', + message: this.i18n('creatingAssembly'), + }) + return true + } + return false }) // eslint-disable-next-line no-shadow @@ -630,19 +645,20 @@ export default class Transloadit extends BasePlugin { }, }) - const assemblyOptions = new AssemblyOptions(files, this.opts) + const assemblyOptions = new AssemblyOptions(filesWithoutErrors, this.opts) return assemblyOptions.build() .then((assemblies) => Promise.all(assemblies.map(createAssembly))) - .then((createdAssemblies) => { + .then((maybeCreatedAssemblies) => { + const createdAssemblies = maybeCreatedAssemblies.filter(Boolean) const assemblyIDs = createdAssemblies.map(assembly => assembly.status.assembly_id) - this.#createAssemblyWatcher(assemblyIDs, filteredFileIDs, uploadID) + this.#createAssemblyWatcher(assemblyIDs, uploadID) return Promise.all(createdAssemblies.map(assembly => this.#connectAssembly(assembly))) }) // If something went wrong before any Assemblies could be created, // clear all processing state. .catch((err) => { - files.forEach((file) => { + filesWithoutErrors.forEach((file) => { this.uppy.emit('preprocess-complete', file) this.uppy.emit('upload-error', file, err) }) @@ -829,7 +845,7 @@ export default class Transloadit extends BasePlugin { getAssemblyFiles (assemblyID) { return this.uppy.getFiles().filter((file) => { - return file && file.transloadit && file.transloadit.assembly === assemblyID + return file?.transloadit?.assembly === assemblyID }) } } diff --git a/website/src/_posts/2017-03-0.15.md b/website/src/_posts/2017-03-0.15.md index 89f4763a78..c8735452d4 100644 --- a/website/src/_posts/2017-03-0.15.md +++ b/website/src/_posts/2017-03-0.15.md @@ -11,7 +11,7 @@ Spring is in the air and Uppy is feeling particularly full of life. In this post ## Yo-yoify for NPM-installed Uppy -In [`0.14`](http://localhost:4000/blog/2017/02/0.14/), we added `yo-yoify` transform to give Uppy some extra speed and eliminate `Function.caller` issues. As it turned out, we [forgot](https://github.com/transloadit/uppy/issues/158) about our Babel-transpiled `lib` version of Uppy that gets published to NPM 🙀. We then spent some time creating a standalone version of `yo-yoify` that would be able to parse `yo-yo` template strings before Babel-transpilation, only to discover that there already is a [`babel-plugin-yo-yoify`](https://www.npmjs.com/package/babel-plugin-yo-yoify) that not only does precisely that, but also frees us from jumping through a lot of unnecessary hoops. It did [have](https://github.com/goto-bus-stop/babel-plugin-yo-yoify/issues/9) [a few](https://github.com/goto-bus-stop/babel-plugin-yo-yoify/pull/8) [issues](https://github.com/goto-bus-stop/babel-plugin-yo-yoify/issues/11) at first, but luckily our friend [RenĂ©e](https://github.com/goto-bus-stop) was available to colaborate with us on this. RenĂ©e has also agreed to join Uppy for a while to help us with other pressing issues. So, silver linings — bugs can sometimes lead to new friends and wonderful beginnings. We are very excited about what this all means for Uppy in the months to come. +In [`0.14`](https://uppy.io/blog/2017/02/0.14/), we added `yo-yoify` transform to give Uppy some extra speed and eliminate `Function.caller` issues. As it turned out, we [forgot](https://github.com/transloadit/uppy/issues/158) about our Babel-transpiled `lib` version of Uppy that gets published to NPM 🙀. We then spent some time creating a standalone version of `yo-yoify` that would be able to parse `yo-yo` template strings before Babel-transpilation, only to discover that there already is a [`babel-plugin-yo-yoify`](https://www.npmjs.com/package/babel-plugin-yo-yoify) that not only does precisely that, but also frees us from jumping through a lot of unnecessary hoops. It did [have](https://github.com/goto-bus-stop/babel-plugin-yo-yoify/issues/9) [a few](https://github.com/goto-bus-stop/babel-plugin-yo-yoify/pull/8) [issues](https://github.com/goto-bus-stop/babel-plugin-yo-yoify/issues/11) at first, but luckily our friend [RenĂ©e](https://github.com/goto-bus-stop) was available to colaborate with us on this. RenĂ©e has also agreed to join Uppy for a while to help us with other pressing issues. So, silver linings — bugs can sometimes lead to new friends and wonderful beginnings. We are very excited about what this all means for Uppy in the months to come. Uppy from NPM is now good to go and the issue has been completely resolved. You can update at: . And yeah, if you use `yo-yo`, give [`babel-plugin-yo-yoify`](https://www.npmjs.com/package/babel-plugin-yo-yoify) a try. diff --git a/website/src/_posts/2019-08-1.3.md b/website/src/_posts/2019-08-1.3.md index 532084d541..5d68af313c 100644 --- a/website/src/_posts/2019-08-1.3.md +++ b/website/src/_posts/2019-08-1.3.md @@ -94,7 +94,7 @@ See [#1440](https://github.com/transloadit/uppy/pull/1440), [#1565](https://gith Thanks to our amazing contributors, Uppy now speaks: Arabic, Chinese, Dutch, English, Finnish, French, German, Hungarian, Italian, Japanese, Persian, Portuguese, Russian, Serbian, Spanish an Turkish! -New translations are rolling in every month, but there are plenty more languages out there that Uppy would love to learn. Please consider [contributing your language](http://localhost:4000/docs/locales/#Contributing-a-new-language) as well! +New translations are rolling in every month, but there are plenty more languages out there that Uppy would love to learn. Please consider [contributing your language](http://uppy.io/docs/locales/#Contributing-a-new-language) as well! We’ve also added docs for locales — how to use from NPM and CDN, auto-generated list of languages that are supported already and an invitation to add more [#1553](https://github.com/transloadit/uppy/pull/1553). @@ -119,7 +119,7 @@ Robodog is an Uppy-based library that helps you talk to the Transloadit API. Sin ## Website and docs * Added Community projects — a page with Uppy plugins and integrations developed by the community [#1620](https://github.com/transloadit/uppy/pull/1620). [Add yours](https://github.com/transloadit/uppy/blob/master/website/src/docs/community-projects.md)! -* Custom plugin [example](http://localhost:4000/docs/writing-plugins/#Example-of-a-custom-plugin) — now you have a reference to look at when writing your own plugin for Uppy [#1623](https://github.com/transloadit/uppy/pull/1623). +* Custom plugin [example](http://uppy.io/docs/writing-plugins/#Example-of-a-custom-plugin) — now you have a reference to look at when writing your own plugin for Uppy [#1623](https://github.com/transloadit/uppy/pull/1623). * Added signature authentication to Transloadit example [#1705](https://github.com/transloadit/uppy/pull/1705). * Documented Companion’s Auth and Token mechanism [#1540](https://github.com/transloadit/uppy/pull/1540). * Updated AWS S3 Multipart documentation wrt CORS settings [#1539](https://github.com/transloadit/uppy/pull/1539). diff --git a/website/src/docs/image-editor.md b/website/src/docs/image-editor.md index 31ba34f265..8decd5e5e0 100644 --- a/website/src/docs/image-editor.md +++ b/website/src/docs/image-editor.md @@ -12,8 +12,6 @@ tagline: "allows users to crop, rotate, zoom and flip images that are added to U Designed to be used with the Dashboard UI (can in theory work without it). -⚠ In beta. - ![Screenshor of the Image Editor plugin UI in Dashboard](https://user-images.githubusercontent.com/1199054/87208710-654db400-c307-11ea-9471-6e3c6582d2a5.png) ```js @@ -121,6 +119,16 @@ uppy.on('file-editor:complete', (updatedFile) => { }) ``` +### file-editor:cancel + +Emitted when `uninstall` is called or when the current image editing changes are discarded. + +```js +uppy.on('file-editor:cancel', (file) => { + console.log(file) +}) +``` + ### `locale: {}` ```js diff --git a/yarn.lock b/yarn.lock index 02b3e78484..b4b5f81ab8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16437,18 +16437,9 @@ __metadata: languageName: node linkType: hard -"cypress-file-upload@npm:^5.0.8": - version: 5.0.8 - resolution: "cypress-file-upload@npm:5.0.8" - peerDependencies: - cypress: ">3.0.0" - checksum: 9c70ca7e0bb137d0ec0b8d38987219ce15b26ac3a40e3ed4e78e6ad4690392eab905586848eec6ad8edd42ee480e68ccc63007b2ebd0a02f4b3eca116ff017e3 - languageName: node - linkType: hard - -"cypress@npm:^9.0.0": - version: 9.7.0 - resolution: "cypress@npm:9.7.0" +"cypress@npm:^10.0.0": + version: 10.3.1 + resolution: "cypress@npm:10.3.1" dependencies: "@cypress/request": ^2.88.10 "@cypress/xvfb": ^1.2.4 @@ -16494,7 +16485,7 @@ __metadata: yauzl: ^2.10.0 bin: cypress: bin/cypress - checksum: 45df7c85bc7ec2e187153ff2b98bf5106d2313d70e2367a5742b5269a9e82d3fdd730d5bbc32ac8da72aeb120a52f9384c2ba4e2fc86b532f68440f22d700fc9 + checksum: 7c76157195ec9409b9665aa9f7698ffd221c74c17f5026769fa20f90a60869cc8274282fa5b9b65e495429839f7a0ba05d69cf12a8af7a318ebcd704f96156c2 languageName: node linkType: hard @@ -17557,8 +17548,7 @@ __metadata: "@uppy/webcam": "workspace:^" "@uppy/xhr-upload": "workspace:^" "@uppy/zoom": "workspace:^" - cypress: ^9.0.0 - cypress-file-upload: ^5.0.8 + cypress: ^10.0.0 deep-freeze: ^0.0.1 parcel: ^2.0.1 prompts: ^2.4.2