Recent searches

in

Upload a file

Open the submit flow, lock the data file, and upload the doodle as an image with uploadFile.

Custom integrations often need to add new files to a Site and write changes back to existing files. Additionally, because more than one Team Member can edit a Site in the Visual Editor at once, you may need to claim a lock on a file before writing, so two people don't overwrite each other's work. The Visual Editor API allows you to do all of these.

In the Doodle Gallery, this happens when a Team Member clicks the Add to the gallery button: the submit() function uploads the drawing as an image, then adds that image to the gallery data file. It's defined inside the same Doodler component, so it can read the API Object from the apiRef we set up earlier. We'll build the upload here and finish the data write in the next step.

First, we open the write transaction: get a reference to the data file we'll be changing, then claim a lock on it. claimLock() returns readOnly: true if someone else already holds the lock, so we retry a few times and give up rather than interrupt their work.

A file editing lock is cooperative, not absolute.

A Team Member editing in the Visual Editor can take the lock from your integration at any time: when they open a file that is already being edited, CloudCannon shows them a banner with a Switch to editing button. Clicking it gives them the lock, moves your integration to read-only, and keeps any unsaved changes.

Because a held lock is not a guarantee of exclusive access, call claimLock() again and check readOnly before resuming writes to confirm your integration still holds the lock. For how this looks to a Team Member in the Visual Editor, please read our documentation on Editing sessions and collaboration.

TypeScript
Copied to clipboard
async function submit() {
  const cloudcannonApi = apiRef.current; 
  if (cloudcannonApi === undefined) {
    throw new Error("Can't access the CloudCannon API! Refresh and try again.");
  }

  const file = cloudcannonApi.file('/src/data/doodles.json'); 

  let readOnly = true;
  for (let fileLockAttempts = 0; readOnly; fileLockAttempts++) { 
    readOnly = (await file.claimLock())?.readOnly ?? true;
    if (readOnly) {
      if (fileLockAttempts > 3) {
        throw new Error('Someone else is editing this file. Try again in a second!');
      }
      await new Promise((resolve) => window.setTimeout(resolve, 1000));
    }
  }

  const canvas = canvasRef.current;
  if (!canvas) {
    throw new Error('Lost reference to the canvas.');
  }

  const blob: Blob | null = await new Promise((resolve) => canvas.toBlob(resolve)); 
  if (!blob) {
    throw new Error("couldn't turn this drawing into an image file");
  }

  const uploadedPath = await cloudcannonApi.uploadFile( 
    new File([blob], 'doodle.png'),
    {
      type: 'image',
      options: {
        paths: {
          uploads: 'public/doodles',
          uploads_filename: 'doodle[count].png',
          static: 'public',
        },
      },
    },
  );

  // ...continued in the next step
}

Read the API Object from the apiRef we set on load, and bail out early if it isn't available — everything below depends on it.

Get a reference to the data file we'll add the doodle to with cloudcannonApi.file().

Claim a lock before writing. We retry while readOnly is true, then give up after a few attempts so two Team Members can't overwrite each other.

Turn the drawing on the canvas into a PNG image file.

Upload the image with uploadFile(). It returns the path to the uploaded file, which we'll save as the doodle's image source.

The paths options tell CloudCannon where to store the upload and how to name it. They line up with the paths in your Configuration File, and doodle[count].png keeps each filename unique.

Copied to clipboard
paths:
  static: public
  uploads: public/doodles
{
  "paths": {
    "static": "public",
    "uploads": "public/doodles"
  }
}

In the next step of this guide, we'll wrap these calls in a try/catch/finally that releases the file lock and keeps Team Members looking at the Visual Editor informed as your submit() function runs, then finish the function by writing the new doodle into the gallery data file.

Build custom Visual Editor integrations (5/7)
Upload a file
Open in a new tab