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 0971187a..2c1b6b24 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 ce5a3853..ffaa5df9 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 bb9ae540..6c3cb87b 100644 --- a/app/src/ui/elements/media/DropzoneInner.tsx +++ b/app/src/ui/elements/media/DropzoneInner.tsx @@ -67,7 +67,7 @@ export const DropzoneInner = ({ )} >
- +