diff --git a/src/components/common/LoadingOverlay.vue b/src/components/common/LoadingOverlay.vue
new file mode 100644
index 000000000..ccc34908e
--- /dev/null
+++ b/src/components/common/LoadingOverlay.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+ {{ loadingMessage }}
+
+
+
+
+
+
+
diff --git a/src/components/load3d/Load3DScene.vue b/src/components/load3d/Load3DScene.vue
index cf497dea5..de2afbdb2 100644
--- a/src/components/load3d/Load3DScene.vue
+++ b/src/components/load3d/Load3DScene.vue
@@ -31,7 +31,7 @@
-
-
diff --git a/src/components/sidebar/tabs/AssetsSidebarListView.vue b/src/components/sidebar/tabs/AssetsSidebarListView.vue
index b39d982a5..1e2bbe2d9 100644
--- a/src/components/sidebar/tabs/AssetsSidebarListView.vue
+++ b/src/components/sidebar/tabs/AssetsSidebarListView.vue
@@ -63,39 +63,47 @@
@approach-end="emit('approach-end')"
>
-
-
-
-
-
+
@@ -105,6 +113,7 @@
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
+import LoadingOverlay from '@/components/common/LoadingOverlay.vue'
import VirtualGrid from '@/components/common/VirtualGrid.vue'
import Button from '@/components/ui/button/Button.vue'
import { useJobActions } from '@/composables/queue/useJobActions'
@@ -114,6 +123,7 @@ import AssetsListItem from '@/platform/assets/components/AssetsListItem.vue'
import { getOutputAssetMetadata } from '@/platform/assets/schemas/assetMetadataSchema'
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
import { iconForMediaType } from '@/platform/assets/utils/mediaIconUtil'
+import { useAssetsStore } from '@/stores/assetsStore'
import { isActiveJobState } from '@/utils/queueUtil'
import {
formatDuration,
@@ -134,6 +144,8 @@ const {
assetType?: 'input' | 'output'
}>()
+const assetsStore = useAssetsStore()
+
const emit = defineEmits<{
(e: 'select-asset', asset: AssetItem): void
(e: 'context-menu', event: MouseEvent, asset: AssetItem): void
diff --git a/src/components/sidebar/tabs/AssetsSidebarTab.vue b/src/components/sidebar/tabs/AssetsSidebarTab.vue
index 58b686516..e91238a6b 100644
--- a/src/components/sidebar/tabs/AssetsSidebarTab.vue
+++ b/src/components/sidebar/tabs/AssetsSidebarTab.vue
@@ -331,7 +331,7 @@ const {
const {
downloadMultipleAssets,
- deleteMultipleAssets,
+ deleteAssets,
addMultipleToWorkflow,
openMultipleWorkflows,
exportMultipleWorkflows
@@ -495,8 +495,9 @@ const handleBulkDownload = (assets: AssetItem[]) => {
}
const handleBulkDelete = async (assets: AssetItem[]) => {
- await deleteMultipleAssets(assets)
- clearSelection()
+ if (await deleteAssets(assets)) {
+ clearSelection()
+ }
}
const handleClearQueue = async () => {
@@ -524,6 +525,17 @@ const handleBulkExportWorkflow = async (assets: AssetItem[]) => {
clearSelection()
}
+const handleDownloadSelected = () => {
+ downloadMultipleAssets(selectedAssets.value)
+ clearSelection()
+}
+
+const handleDeleteSelected = async () => {
+ if (await deleteAssets(selectedAssets.value)) {
+ clearSelection()
+ }
+}
+
const handleZoomClick = (asset: AssetItem) => {
const mediaType = getMediaTypeFromFilename(asset.name)
@@ -672,16 +684,6 @@ const copyJobId = async () => {
}
}
-const handleDownloadSelected = () => {
- downloadMultipleAssets(selectedAssets.value)
- clearSelection()
-}
-
-const handleDeleteSelected = async () => {
- await deleteMultipleAssets(selectedAssets.value)
- clearSelection()
-}
-
const handleApproachEnd = useDebounceFn(async () => {
if (
activeTab.value === 'output' &&
diff --git a/src/composables/queue/useJobMenu.test.ts b/src/composables/queue/useJobMenu.test.ts
index e07889022..eea3d9232 100644
--- a/src/composables/queue/useJobMenu.test.ts
+++ b/src/composables/queue/useJobMenu.test.ts
@@ -40,7 +40,7 @@ vi.mock('@/platform/assets/composables/media/assetMappers', () => ({
}))
const mediaAssetActionsMock = {
- confirmDelete: vi.fn()
+ deleteAssets: vi.fn()
}
vi.mock('@/platform/assets/composables/useMediaAssetActions', () => ({
useMediaAssetActions: () => mediaAssetActionsMock
@@ -198,7 +198,7 @@ describe('useJobMenu', () => {
}))
queueStoreMock.update.mockResolvedValue(undefined)
queueStoreMock.delete.mockResolvedValue(undefined)
- mediaAssetActionsMock.confirmDelete.mockResolvedValue(false)
+ mediaAssetActionsMock.deleteAssets.mockResolvedValue(false)
mapTaskOutputToAssetItemMock.mockImplementation((task, output) => ({
task,
output
@@ -666,7 +666,7 @@ describe('useJobMenu', () => {
})
it('deletes preview asset when confirmed', async () => {
- mediaAssetActionsMock.confirmDelete.mockResolvedValue(true)
+ mediaAssetActionsMock.deleteAssets.mockResolvedValue(true)
const { jobMenuEntries } = mountJobMenu()
const preview = { filename: 'foo', subfolder: 'bar', type: 'output' }
const taskRef = { previewOutput: preview }
@@ -681,7 +681,7 @@ describe('useJobMenu', () => {
})
it('does not refresh queue when delete cancelled', async () => {
- mediaAssetActionsMock.confirmDelete.mockResolvedValue(false)
+ mediaAssetActionsMock.deleteAssets.mockResolvedValue(false)
const { jobMenuEntries } = mountJobMenu()
setCurrentItem(
createJobItem({
diff --git a/src/composables/queue/useJobMenu.ts b/src/composables/queue/useJobMenu.ts
index b50a24846..bdf7033f6 100644
--- a/src/composables/queue/useJobMenu.ts
+++ b/src/composables/queue/useJobMenu.ts
@@ -210,8 +210,8 @@ export function useJobMenu(
if (!task || !preview) return
const asset = mapTaskOutputToAssetItem(task, preview)
- const success = await mediaAssetActions.confirmDelete(asset)
- if (success) {
+ const confirmed = await mediaAssetActions.deleteAssets(asset)
+ if (confirmed) {
await queueStore.update()
}
}
diff --git a/src/platform/assets/components/MediaAssetCard.vue b/src/platform/assets/components/MediaAssetCard.vue
index 8da39c67b..f6179f303 100644
--- a/src/platform/assets/components/MediaAssetCard.vue
+++ b/src/platform/assets/components/MediaAssetCard.vue
@@ -48,6 +48,10 @@
@image-loaded="handleImageLoaded"
/>
+
+
+
+
()
+const assetsStore = useAssetsStore()
+
+// Get deletion state from store
+const isDeleting = computed(() =>
+ asset ? assetsStore.isAssetDeleting(asset.id) : false
+)
+
const emit = defineEmits<{
click: []
zoom: [asset: AssetItem]
@@ -252,7 +265,7 @@ const metaInfo = computed(() => {
})
const showActionsOverlay = computed(() => {
- if (loading || !asset) return false
+ if (loading || !asset || isDeleting.value) return false
return isHovered.value || selected || isVideoPlaying.value
})
diff --git a/src/platform/assets/components/MediaAssetContextMenu.vue b/src/platform/assets/components/MediaAssetContextMenu.vue
index 57c99cf52..35b97fab7 100644
--- a/src/platform/assets/components/MediaAssetContextMenu.vue
+++ b/src/platform/assets/components/MediaAssetContextMenu.vue
@@ -247,8 +247,8 @@ const contextMenuItems = computed