Fix job details popover sticking after cancel/delete (#6930)

## Summary
- close the job details popover when its job disappears or timers fire
after list changes, and clear hover timers on unmount
- emit an explicit details-leave on cancel/delete clicks so the popover
closes even if hover-out never fires

Fixes https://github.com/Comfy-Org/ComfyUI_frontend/issues/6907

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6930-Fix-job-details-popover-sticking-after-cancel-delete-2b66d73d365081dc990ae87d01455bad)
by [Unito](https://www.unito.io)
This commit is contained in:
Benjamin Lu
2025-12-08 15:00:12 -08:00
committed by GitHub
parent 248929c655
commit 97c7b33713
2 changed files with 39 additions and 5 deletions

View File

@@ -36,12 +36,12 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { onBeforeUnmount, ref, watch } from 'vue'
import QueueJobItem from '@/components/queue/job/QueueJobItem.vue'
import type { JobGroup, JobListItem } from '@/composables/queue/useJobList'
defineProps<{ displayedJobGroups: JobGroup[] }>()
const props = defineProps<{ displayedJobGroups: JobGroup[] }>()
const emit = defineEmits<{
(e: 'cancelItem', item: JobListItem): void
@@ -89,4 +89,26 @@ const onDetailsLeave = (jobId: string) => {
hideTimer.value = null
}, 150)
}
const resetActiveDetails = () => {
clearHideTimer()
clearShowTimer()
activeDetailsId.value = null
}
watch(
() => props.displayedJobGroups,
(groups) => {
const activeId = activeDetailsId.value
if (!activeId) return
const hasActiveJob = groups.some((group) =>
group.items.some((item) => item.id === activeId)
)
if (!hasActiveJob) resetActiveDetails()
}
)
onBeforeUnmount(resetActiveDetails)
</script>

View File

@@ -135,7 +135,7 @@
size="sm"
class="size-6 transform gap-1 rounded bg-destructive-background text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:bg-destructive-background-hover hover:opacity-95"
:aria-label="t('g.delete')"
@click.stop="emit('delete')"
@click.stop="onDeleteClick"
>
<i class="icon-[lucide--trash-2] size-4" />
</IconButton>
@@ -150,7 +150,7 @@
size="sm"
class="size-6 transform gap-1 rounded bg-destructive-background text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:bg-destructive-background-hover hover:opacity-95"
:aria-label="t('g.cancel')"
@click.stop="emit('cancel')"
@click.stop="onCancelClick"
>
<i class="icon-[lucide--x] size-4" />
</IconButton>
@@ -190,7 +190,7 @@
size="sm"
class="size-6 transform gap-1 rounded bg-destructive-background text-text-primary transition duration-150 ease-in-out hover:-translate-y-px hover:bg-destructive-background-hover hover:opacity-95"
:aria-label="t('g.cancel')"
@click.stop="emit('cancel')"
@click.stop="onCancelClick"
>
<i class="icon-[lucide--x] size-4" />
</IconButton>
@@ -355,6 +355,18 @@ const computedShowClear = computed(() => {
return props.state !== 'completed'
})
const emitDetailsLeave = () => emit('details-leave', props.jobId)
const onCancelClick = () => {
emitDetailsLeave()
emit('cancel')
}
const onDeleteClick = () => {
emitDetailsLeave()
emit('delete')
}
const onContextMenu = (event: MouseEvent) => {
const shouldShowMenu = props.showMenu !== undefined ? props.showMenu : true
if (shouldShowMenu) emit('menu', event)