mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-06 16:10:09 +00:00
Handle bulk deletes
This commit is contained in:
@@ -116,10 +116,12 @@
|
||||
:open-context-menu-id="openContextMenuId"
|
||||
:selected-assets="getSelectedAssets(displayAssets)"
|
||||
:has-selection="hasSelection"
|
||||
:is-deleting="deletingAssetIds.has(item.id)"
|
||||
@click="handleAssetSelect(item)"
|
||||
@zoom="handleZoomClick(item)"
|
||||
@output-count-click="enterFolderView(item)"
|
||||
@asset-deleted="refreshAssets"
|
||||
@asset-deleting="handleAssetDeleting(item.id, $event)"
|
||||
@context-menu-opened="openContextMenuId = item.id"
|
||||
@bulk-download="handleBulkDownload"
|
||||
@bulk-delete="handleBulkDelete"
|
||||
@@ -239,6 +241,9 @@ const isQueuePanelV2Enabled = computed(() =>
|
||||
// Track which asset's context menu is open (for single-instance context menu management)
|
||||
const openContextMenuId = ref<string | null>(null)
|
||||
|
||||
// Track which assets are currently being deleted (for showing loading state)
|
||||
const deletingAssetIds = ref(new Set<string>())
|
||||
|
||||
// Determine if delete button should be shown
|
||||
// Hide delete button when in input tab and not in cloud (OSS mode - files are from local folders)
|
||||
const shouldShowDeleteButton = computed(() => {
|
||||
@@ -531,9 +536,21 @@ const handleDownloadSelected = () => {
|
||||
clearSelection()
|
||||
}
|
||||
|
||||
const setAssetsDeletingState = (assetIds: string[], isDeleting: boolean) => {
|
||||
assetIds.forEach((id) =>
|
||||
isDeleting
|
||||
? deletingAssetIds.value.add(id)
|
||||
: deletingAssetIds.value.delete(id)
|
||||
)
|
||||
}
|
||||
|
||||
const handleDeleteSelected = async () => {
|
||||
const selectedAssets = getSelectedAssets(displayAssets.value)
|
||||
await deleteMultipleAssets(selectedAssets)
|
||||
const assetIds = selectedAssets.map((a) => a.id)
|
||||
|
||||
await deleteMultipleAssets(selectedAssets, (isDeleting) =>
|
||||
setAssetsDeletingState(assetIds, isDeleting)
|
||||
)
|
||||
clearSelection()
|
||||
}
|
||||
|
||||
@@ -542,8 +559,16 @@ const handleBulkDownload = (assets: AssetItem[]) => {
|
||||
clearSelection()
|
||||
}
|
||||
|
||||
const handleAssetDeleting = (assetId: string, isDeleting: boolean) => {
|
||||
setAssetsDeletingState([assetId], isDeleting)
|
||||
}
|
||||
|
||||
const handleBulkDelete = async (assets: AssetItem[]) => {
|
||||
await deleteMultipleAssets(assets)
|
||||
const assetIds = assets.map((a) => a.id)
|
||||
|
||||
await deleteMultipleAssets(assets, (isDeleting) =>
|
||||
setAssetsDeletingState(assetIds, isDeleting)
|
||||
)
|
||||
clearSelection()
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
:is-bulk-mode="hasSelection && (selectedAssets?.length ?? 0) > 1"
|
||||
@zoom="handleZoomClick"
|
||||
@asset-deleted="emit('asset-deleted')"
|
||||
@asset-deleting="isDeleting = $event"
|
||||
@asset-deleting="emit('asset-deleting', $event)"
|
||||
@bulk-download="emit('bulk-download', $event)"
|
||||
@bulk-delete="emit('bulk-delete', $event)"
|
||||
/>
|
||||
@@ -193,7 +193,8 @@ const {
|
||||
showDeleteButton,
|
||||
openContextMenuId,
|
||||
selectedAssets,
|
||||
hasSelection
|
||||
hasSelection,
|
||||
isDeleting
|
||||
} = defineProps<{
|
||||
asset?: AssetItem
|
||||
loading?: boolean
|
||||
@@ -204,6 +205,7 @@ const {
|
||||
openContextMenuId?: string | null
|
||||
selectedAssets?: AssetItem[]
|
||||
hasSelection?: boolean
|
||||
isDeleting?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -211,6 +213,7 @@ const emit = defineEmits<{
|
||||
zoom: [asset: AssetItem]
|
||||
'output-count-click': []
|
||||
'asset-deleted': []
|
||||
'asset-deleting': [isDeleting: boolean]
|
||||
'context-menu-opened': []
|
||||
'bulk-download': [assets: AssetItem[]]
|
||||
'bulk-delete': [assets: AssetItem[]]
|
||||
@@ -221,7 +224,6 @@ const contextMenu = ref<InstanceType<typeof MediaAssetContextMenu>>()
|
||||
|
||||
const isVideoPlaying = ref(false)
|
||||
const showVideoControls = ref(false)
|
||||
const isDeleting = ref(false)
|
||||
|
||||
// Store actual image dimensions
|
||||
const imageDimensions = ref<{ width: number; height: number } | undefined>()
|
||||
@@ -296,7 +298,7 @@ const metaInfo = computed(() => {
|
||||
})
|
||||
|
||||
const showActionsOverlay = computed(() => {
|
||||
if (loading || !asset || isDeleting.value) return false
|
||||
if (loading || !asset || isDeleting) return false
|
||||
return isHovered.value || selected || isVideoPlaying.value
|
||||
})
|
||||
|
||||
|
||||
@@ -376,8 +376,12 @@ export function useMediaAssetActions() {
|
||||
/**
|
||||
* Delete multiple assets with confirmation dialog
|
||||
* @param assets Array of assets to delete
|
||||
* @param onDeleting Optional callback called with true when deletion starts (after confirmation) and false when complete
|
||||
*/
|
||||
const deleteMultipleAssets = async (assets: AssetItem[]) => {
|
||||
const deleteMultipleAssets = async (
|
||||
assets: AssetItem[],
|
||||
onDeleting?: (deleting: boolean) => void
|
||||
) => {
|
||||
if (!assets || assets.length === 0) return
|
||||
|
||||
const assetsStore = useAssetsStore()
|
||||
@@ -394,6 +398,7 @@ export function useMediaAssetActions() {
|
||||
type: 'delete',
|
||||
itemList: assets.map((asset) => asset.name),
|
||||
onConfirm: async () => {
|
||||
onDeleting?.(true)
|
||||
try {
|
||||
// Delete all assets using Promise.allSettled to track individual results
|
||||
const results = await Promise.allSettled(
|
||||
@@ -470,6 +475,8 @@ export function useMediaAssetActions() {
|
||||
detail: t('mediaAsset.selection.failedToDeleteAssets'),
|
||||
life: 3000
|
||||
})
|
||||
} finally {
|
||||
onDeleting?.(false)
|
||||
}
|
||||
|
||||
resolve()
|
||||
|
||||
Reference in New Issue
Block a user