diff --git a/packages/bbui/src/Form/Core/Dropzone.svelte b/packages/bbui/src/Form/Core/Dropzone.svelte index 36515acbc5..80f51f5dae 100644 --- a/packages/bbui/src/Form/Core/Dropzone.svelte +++ b/packages/bbui/src/Form/Core/Dropzone.svelte @@ -17,6 +17,7 @@ export let disabled = false export let fileSizeLimit = BYTES_IN_MB * 20 export let processFiles = null + export let deleteAttachments = null export let handleFileTooLarge = null export let handleTooManyFiles = null export let gallery = true @@ -95,6 +96,7 @@ value.filter((x, idx) => idx !== selectedImageIdx) ) selectedImageIdx = 0 + await deleteAttachments(value.map(item => item.key)) } function navigateLeft() { diff --git a/packages/client/src/components/app/forms/AttachmentField.svelte b/packages/client/src/components/app/forms/AttachmentField.svelte index 5023e77ae5..8a98f92d83 100644 --- a/packages/client/src/components/app/forms/AttachmentField.svelte +++ b/packages/client/src/components/app/forms/AttachmentField.svelte @@ -47,6 +47,17 @@ } } + const deleteAttachments = async fileList => { + try { + return await API.deleteAttachments({ + keys: fileList, + tableId: formContext?.dataSource?.tableId, + }) + } catch (error) { + return [] + } + } + const handleChange = e => { fieldApi.setValue(e.detail) if (onChange) { @@ -72,6 +83,7 @@ error={fieldState.error} on:change={handleChange} {processFiles} + {deleteAttachments} {handleFileTooLarge} {handleTooManyFiles} {maximum} diff --git a/packages/frontend-core/src/api/attachments.js b/packages/frontend-core/src/api/attachments.js index e3b1b74e5b..1a24785a89 100644 --- a/packages/frontend-core/src/api/attachments.js +++ b/packages/frontend-core/src/api/attachments.js @@ -61,5 +61,19 @@ export const buildAttachmentEndpoints = API => { }) return { publicUrl } }, + + /** + * Deletes attachments from the bucket. + * @param keys the attachments to delete + * @param tableId the associated table ID + */ + deleteAttachments: async ({ keys, tableId }) => { + return await API.post({ + url: `/api/attachments/${tableId}/delete`, + body: { + keys, + }, + }) + }, } } diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 7aeea98adc..c4d51293b5 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -12,7 +12,7 @@ const { } = require("../../../utilities/fileSystem") const env = require("../../../environment") const { clientLibraryPath } = require("../../../utilities") -const { upload } = require("../../../utilities/fileSystem") +const { upload, deleteFiles } = require("../../../utilities/fileSystem") const { attachmentsRelativeURL } = require("../../../utilities") const { DocumentType } = require("../../../db/utils") const { getAppDB, getAppId } = require("@budibase/backend-core/context") @@ -97,6 +97,10 @@ export const uploadFile = async function (ctx: any) { ctx.body = await Promise.all(uploads) } +export const deleteObjects = async function (ctx: any) { + ctx.body = await deleteFiles(ObjectStoreBuckets.APPS, ctx.request.body.keys) +} + export const serveApp = async function (ctx: any) { const db = getAppDB({ skip_setup: true }) const appInfo = await db.get(DocumentType.APP_METADATA) diff --git a/packages/server/src/api/routes/static.ts b/packages/server/src/api/routes/static.ts index 61cf2b1245..7cf3f5e145 100644 --- a/packages/server/src/api/routes/static.ts +++ b/packages/server/src/api/routes/static.ts @@ -45,6 +45,12 @@ router authorized(PermissionTypes.TABLE, PermissionLevels.WRITE), controller.uploadFile ) + .post( + "/api/attachments/:tableId/delete", + paramResource("tableId"), + authorized(PermissionTypes.TABLE, PermissionLevels.WRITE), + controller.deleteObjects + ) .get("/:appId/:path*", controller.serveApp) .get("/app/:appUrl/:path*", controller.serveApp) .post( diff --git a/packages/server/src/utilities/fileSystem/index.js b/packages/server/src/utilities/fileSystem/index.js index f4aebd11a8..1223ea55f0 100644 --- a/packages/server/src/utilities/fileSystem/index.js +++ b/packages/server/src/utilities/fileSystem/index.js @@ -15,6 +15,7 @@ const { streamUpload, deleteFolder, downloadTarball, + deleteFiles, } = require("./utilities") const { updateClientLibrary } = require("./clientLibrary") const env = require("../../environment") @@ -327,5 +328,6 @@ exports.cleanup = appIds => { exports.upload = upload exports.retrieve = retrieve exports.retrieveToTmp = retrieveToTmp +exports.deleteFiles = deleteFiles exports.TOP_LEVEL_PATH = TOP_LEVEL_PATH exports.NODE_MODULES_PATH = NODE_MODULES_PATH