Custom integrations often need to add new files to a Site A website in CloudCannon that includes all the files, content, configuration, and settings needed to edit, build, and host a complete website. A person who belongs to the same Organization as you. Team members are other CloudCannon users who have been invited to your Organization to collaborate on Sites, edit content, or manage settings. Each team member has their own CloudCannon account with individual permissions assigned through Permission Groups. CloudCannon's visual editing interface provides a user-friendly way of updating your website files on an interactive preview of your webpage. You can navigate around your website preview using links/buttons, as you would on the live version, and edit your content inline on the page, or with the data panel or sidebar. What you see in the Visual Editor is what your website visitors will see on your live webpages.Site
Team Member
Visual Editor
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.
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 CloudCannon Configuration Files store the preferences and settings for your Site, allowing you to customize its functionality and appearance. CloudCannon supports cloudcannon.config.json, cloudcannon.config.yaml, or cloudcannon.config.yml file types, and allows you to split your configuration across multiple files.paths options tell CloudCannon where to store the upload and how to name it. They line up with the paths in your Configuration FileConfiguration Files
doodle[count].png keeps each filename unique.
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.