React Dashboard component doesn't update as expected with custom plugin

Hello, Transloadit community!

I am using Uppy for the first time and trying to integrate it with a React app. I have followed the documentation and things seem to work as expected, but everything falls apart when I try to plug my custom upload plugin.

I need a custom plugin because my use case is slightly different than what Uppy offers out of the box. I want to make a request to the backend for a signed S3 URL and the do the actual upload to that URL for each file. (I can’t use the @uppy/aws-s3 plugin because the requests need to go through my backend)

I have implemented the plugin as follows. Written in TypeScript.

The implementation details are redacted and replaced with dummy awaits because I am not sure if its okay to share them.

import { Uppy, BasePlugin, DefaultPluginOptions, UppyFile } from "@uppy/core";
import { Dashboard } from "@uppy/react";

import "@uppy/core/dist/style.min.css";
import "@uppy/dashboard/dist/style.min.css";
import "@uppy/progress-bar/dist/style.min.css";
import "@uppy/status-bar/dist/style.min.css";

function delay(n: number) {
  return new Promise((resolve) => setTimeout(resolve, n));
}

class MyPlugin extends BasePlugin {
  constructor(uppy: Uppy, opts: DefaultPluginOptions) {
    super(uppy, opts);

    this.id = "MyPlugin";
    this.type = "my-plugin";

    this.uploadHandler = this.uploadHandler.bind(this);
  }

  async simulatedUpload(file: UppyFile) {
    // Generate signed url
    console.log("Uploading", file.id);
    await delay(1000);

    // Upload the file to signed url
    for (let index = 1; index <= 10; index++) {
      await delay(500);

      console.log(
        "Progress",
        file.id,
        file.progress.bytesTotal * (index * 0.1),
        "/",
        file.progress.bytesTotal
      );
     // Emit fake progress events
      this.uppy.emit("upload-progress", file, {
        uploader: this,
        bytesUploaded: file.progress.bytesTotal * (index * 0.1),
        bytesTotal: file.progress.bytesTotal,
      });
    }

    console.log("Completed", file.id);
    this.uppy.emit("upload-success", file, {});
  }

  async uploadHandler(fileIds: string[]) {
    const uploadRequests = [];

    for (const id of fileIds) {
      const file = this.uppy.getFile(id);
      uploadRequests.push(this.simulatedUpload(file));
    }

    await Promise.allSettled(uploadRequests);
  }

  install() {
    this.uppy.addUploader(this.uploadHandler);
  }

  uninstall() {
    this.uppy.removeUploader(this.uploadHandler);
  }
}

const uppy = new Uppy().use(MyPlugin);

function App() {
  return <Dashboard uppy={uppy} plugins={["ProgressBar", "StatusBar"]} />;
}

export default App;

The plugin works without any errors and the files get uploaded to S3. The main issue is that the UI behaves differently than if I use a built-in plugin, that is, it doesn’t show any progress or the upload completed state with the done button. (Images below)

For more context, I am using Vite + React + Typescript. I have also tried looking at the source of existing plugins like xhr-upload and tus but to no avail.

Upload completed when using custom plugin

https://i.imgur.com/im8wS6z.png

In the above image the files are actually done uploading, but it doesn’t show the checkmark or done status.

Upload progress and completion when using @uppy/tus plugin

https://i.imgur.com/GzuRJop.png

As you can notice the image with custom plugin doesn’t show progress or completion indication. So my question is, How do I set up my custom plugin such that it also updates the Dashboard UI according to the current upload state?

If someone can point out the mistakes in my code or point me towards working custom plugin examples it would be great.

Any help is appreciated, Thanks!

1 Like

After doing some digging in the Uppy source I was able to figure out a solution.

The Dashboard component needs upload-start event with a list of files that are about to be uploaded from the custom plugin.

this.uppy.emit("upload-start", files);