From 5e71fc89478ea64a9388ae0e08c497488641b7c3 Mon Sep 17 00:00:00 2001 From: dswbx Date: Mon, 29 Sep 2025 16:47:44 +0200 Subject: [PATCH] feat: implement media cleanup on entity deletion and enhance Dropzone logging Added functionality to clean up media files associated with entities upon deletion, ensuring proper resource management. Enhanced logging in the Dropzone component to provide better feedback on file type validation and user interactions, improving overall user experience. --- app/src/media/AppMedia.ts | 25 +++++++++++++++++++++ app/src/ui/elements/media/Dropzone.tsx | 8 ++++++- app/src/ui/elements/media/DropzoneInner.tsx | 2 +- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/src/media/AppMedia.ts b/app/src/media/AppMedia.ts index 0971187..2c1b6b2 100644 --- a/app/src/media/AppMedia.ts +++ b/app/src/media/AppMedia.ts @@ -8,6 +8,7 @@ import { MediaController } from "./api/MediaController"; import { buildMediaSchema, registry, type TAppMediaConfig } from "./media-schema"; import { mediaFields } from "./media-entities"; import * as MediaPermissions from "media/media-permissions"; +import * as DatabaseEvents from "data/events"; export type MediaFields = typeof AppMedia.mediaFields; export type MediaFieldSchema = FieldSchema; @@ -139,6 +140,30 @@ export class AppMedia extends Module> { }, { mode: "sync", id: "delete-data-media" }, ); + + emgr.onEvent( + DatabaseEvents.MutatorDeleteAfter, + async (e) => { + const { entity, data } = e.params; + const fields = entity.fields.filter((f) => f.type === "media"); + if (fields.length > 0) { + const references = fields.map((f) => `${entity.name}.${f.name}`); + $console.log("App:storage:file cleaning up", { + reference: { $in: references }, + entity_id: String(data.id), + }); + const { data: deleted } = await em.mutator(media).deleteWhere({ + reference: { $in: references }, + entity_id: String(data.id), + }); + for (const file of deleted) { + await this.storage.deleteFile(file.path); + } + $console.log("App:storage:file cleaned up files:", deleted.length); + } + }, + { mode: "async", id: "delete-data-media-after" }, + ); } override getOverwritePaths() { diff --git a/app/src/ui/elements/media/Dropzone.tsx b/app/src/ui/elements/media/Dropzone.tsx index ce5a385..ffaa5df 100644 --- a/app/src/ui/elements/media/Dropzone.tsx +++ b/app/src/ui/elements/media/Dropzone.tsx @@ -173,9 +173,14 @@ export function Dropzone({ return specs.every((spec) => { if (spec.kind !== "file") { + console.log("not a file", spec.kind); return false; } - return !(allowedMimeTypes && !allowedMimeTypes.includes(spec.type)); + if (allowedMimeTypes && allowedMimeTypes.length > 0) { + console.log("not allowed mimetype", spec.type); + return allowedMimeTypes.includes(spec.type); + } + return true; }); } @@ -432,6 +437,7 @@ export function Dropzone({ type: "file", multiple: !maxItems || maxItems > 1, onChange: handleFileInputChange, + accept: allowedMimeTypes?.join(","), }, showPlaceholder, actions: { diff --git a/app/src/ui/elements/media/DropzoneInner.tsx b/app/src/ui/elements/media/DropzoneInner.tsx index bb9ae54..6c3cb87 100644 --- a/app/src/ui/elements/media/DropzoneInner.tsx +++ b/app/src/ui/elements/media/DropzoneInner.tsx @@ -67,7 +67,7 @@ export const DropzoneInner = ({ )} >
- +