From 08ea608f94a2b187cfb3359deac985356d6696ec Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Sun, 28 Jun 2026 12:36:13 +0100 Subject: [PATCH] feat(media): delete videos from the media library Add an admin flow to permanently delete a media asset and clean up everything it leaves behind. - Delete dialog with a destructive, irreversible confirmation; deletion is blocked while the video is still attached and shows the in-use lessons so the admin can detach first. - Usage list resolves lesson/course context for each attachment, links to the lesson editor via an anchor (right-click "open in new tab"), and exposes a refresh button to re-check usage after detaching elsewhere. - Storage cleanup runs as a background maintenance job: the producer captures the asset's object keys/prefixes up front and an idempotent worker sweeps HLS segments, thumbnails, audio, transcript, and the raw upload from object storage. Also harden usage accounting so stale attachments cannot trap an asset: - asset_usages has no FK to its polymorphic target, so prune a lesson's usage rows whenever the lesson is hard-deleted (single + bulk paths). - Usage resolution drops orphaned lesson usages (lesson gone or course soft-deleted) so they neither appear in the list nor block deletion. Document the icon-only button convention (variant="secondary") in AGENTS.md. --- AGENTS.md | 1 + .../media/api/media-manager.svelte.ts | 25 +++ .../media/components/asset-card.svelte | 12 +- .../components/asset-usage-dialog.svelte | 68 +++---- .../media/components/asset-usage-list.svelte | 54 ++++++ .../components/delete-asset-dialog.svelte | 117 ++++++++++++ .../lib/features/media/components/index.ts | 2 + .../src/lib/features/media/pages/media.svelte | 62 ++++++- .../media/utils/media-manager-utils.ts | 8 + .../src/lib/utils/translations/da.json | 28 ++- .../src/lib/utils/translations/de.json | 28 ++- .../src/lib/utils/translations/en.json | 23 ++- .../src/lib/utils/translations/es.json | 28 ++- .../src/lib/utils/translations/fr.json | 28 ++- .../src/lib/utils/translations/hi.json | 28 ++- .../src/lib/utils/translations/pl.json | 28 ++- .../src/lib/utils/translations/pt.json | 28 ++- .../src/lib/utils/translations/ru.json | 28 ++- .../src/lib/utils/translations/vi.json | 28 ++- apps/jobs/src/workers/maintenance.ts | 13 ++ packages/core/src/services/assets/assets.ts | 110 +++++++++-- packages/core/src/services/course/content.ts | 5 + packages/core/src/services/lesson/lesson.ts | 17 +- packages/db/package.json | 1 + packages/db/src/queries/assets/assets.ts | 27 +++ packages/db/src/queries/lesson/lesson.ts | 35 +++- packages/db/src/scripts/rewrite-media-host.ts | 172 ++++++++++++++++++ packages/jobs/src/enqueue/index.ts | 1 + packages/jobs/src/enqueue/maintenance.ts | 19 ++ packages/jobs/src/payloads/maintenance.ts | 19 ++ packages/jobs/src/queues/names.ts | 3 +- 31 files changed, 966 insertions(+), 80 deletions(-) create mode 100644 apps/dashboard/src/lib/features/media/components/asset-usage-list.svelte create mode 100644 apps/dashboard/src/lib/features/media/components/delete-asset-dialog.svelte create mode 100644 packages/db/src/scripts/rewrite-media-host.ts create mode 100644 packages/jobs/src/enqueue/maintenance.ts diff --git a/AGENTS.md b/AGENTS.md index 9c773751..148cbac3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -325,6 +325,7 @@ Use `.server.ts` files for server-side code to isolate API keys. - For dashboard forms, prefer `@cio/ui/custom/*-field` wrappers (for example `InputField`, `TextareaField`, `CheckboxField`) so label/error/spacing behavior stays consistent. - Use base primitives (`@cio/ui/base/input`, `@cio/ui/base/textarea`, `@cio/ui/base/checkbox`, `@cio/ui/base/label`) only when creating/updating reusable UI components or when no custom field wrapper exists. - In app-level form UIs, do not introduce native form controls (``, `