mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-26 17:54:14 +00:00
Fix gallery changing image every time a task finishes (#2125)
This commit is contained in:
@@ -108,6 +108,8 @@ class ConfirmDialog {
|
||||
}
|
||||
|
||||
export class ComfyPage {
|
||||
private _history: TaskHistory | null = null
|
||||
|
||||
public readonly url: string
|
||||
// All canvas position operations are based on default view of canvas.
|
||||
public readonly canvas: Locator
|
||||
@@ -242,7 +244,8 @@ export class ComfyPage {
|
||||
}
|
||||
|
||||
setupHistory(): TaskHistory {
|
||||
return new TaskHistory(this)
|
||||
this._history ??= new TaskHistory(this)
|
||||
return this._history
|
||||
}
|
||||
|
||||
async setup({ clearStorage = true }: { clearStorage?: boolean } = {}) {
|
||||
|
||||
@@ -242,4 +242,21 @@ export class QueueSidebarTab extends SidebarTab {
|
||||
localStorage.setItem('queue', JSON.stringify([width, 100 - width]))
|
||||
}, width)
|
||||
}
|
||||
|
||||
getTaskPreviewButton(taskIndex: number) {
|
||||
return this.tasks.nth(taskIndex).getByRole('button')
|
||||
}
|
||||
|
||||
async openTaskPreview(taskIndex: number) {
|
||||
const previewButton = this.getTaskPreviewButton(taskIndex)
|
||||
await previewButton.hover()
|
||||
await previewButton.click()
|
||||
return this.getGalleryImage(taskIndex).waitFor({ state: 'visible' })
|
||||
}
|
||||
|
||||
getGalleryImage(galleryItemIndex: number) {
|
||||
// Aria labels of Galleria items are 1-based indices
|
||||
const galleryLabel = `${galleryItemIndex + 1}`
|
||||
return this.page.getByLabel(galleryLabel).locator('.galleria-image')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { expect, mergeTests } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture as test } from './fixtures/ComfyPage'
|
||||
import { comfyPageFixture } from './fixtures/ComfyPage'
|
||||
import { webSocketFixture } from './fixtures/ws'
|
||||
|
||||
const test = mergeTests(comfyPageFixture, webSocketFixture)
|
||||
|
||||
test.describe('Menu', () => {
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
@@ -873,4 +876,70 @@ test.describe('Queue sidebar', () => {
|
||||
expect(await comfyPage.menu.queueTab.visibleTasks.count()).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Gallery', () => {
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
await comfyPage
|
||||
.setupHistory()
|
||||
.withTask(['example.webp'])
|
||||
.repeat(1)
|
||||
.setupRoutes()
|
||||
await comfyPage.menu.queueTab.open()
|
||||
await comfyPage.menu.queueTab.waitForTasks()
|
||||
})
|
||||
|
||||
test('displays gallery image after opening task preview', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.menu.queueTab.openTaskPreview(0)
|
||||
expect(comfyPage.menu.queueTab.getGalleryImage(0)).toBeVisible()
|
||||
})
|
||||
|
||||
test('should maintain active gallery item when new tasks are added', async ({
|
||||
comfyPage,
|
||||
ws
|
||||
}) => {
|
||||
const initialIndex = 0
|
||||
await comfyPage.menu.queueTab.openTaskPreview(initialIndex)
|
||||
|
||||
// Add a new task while the gallery is still open
|
||||
comfyPage.setupHistory().withTask(['example.webp'])
|
||||
await ws.trigger({
|
||||
type: 'status',
|
||||
data: {
|
||||
status: { exec_info: { queue_remaining: 0 } }
|
||||
}
|
||||
})
|
||||
await comfyPage.menu.queueTab.waitForTasks()
|
||||
|
||||
// The index of all tasks increments when a new task is prepended
|
||||
const expectIndex = initialIndex + 1
|
||||
expect(comfyPage.menu.queueTab.getGalleryImage(expectIndex)).toBeVisible()
|
||||
})
|
||||
|
||||
test.describe('Gallery navigation', () => {
|
||||
const paths: {
|
||||
description: string
|
||||
path: ('Right' | 'Left')[]
|
||||
expectIndex: number
|
||||
}[] = [
|
||||
{ description: 'Right', path: ['Right'], expectIndex: 1 },
|
||||
{ description: 'Left', path: ['Right', 'Left'], expectIndex: 0 },
|
||||
{ description: 'Right wrap', path: ['Right', 'Right'], expectIndex: 0 },
|
||||
{ description: 'Left wrap', path: ['Left'], expectIndex: 1 }
|
||||
]
|
||||
|
||||
paths.forEach(({ description, path, expectIndex }) => {
|
||||
test(`can navigate gallery ${description}`, async ({ comfyPage }) => {
|
||||
await comfyPage.menu.queueTab.openTaskPreview(0)
|
||||
for (const direction of path)
|
||||
await comfyPage.page.keyboard.press(`Arrow${direction}`)
|
||||
|
||||
expect(
|
||||
comfyPage.menu.queueTab.getGalleryImage(expectIndex)
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -99,7 +99,7 @@ import type { MenuItem } from 'primevue/menuitem'
|
||||
import ProgressSpinner from 'primevue/progressspinner'
|
||||
import { useConfirm } from 'primevue/useconfirm'
|
||||
import { useToast } from 'primevue/usetoast'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
|
||||
@@ -108,7 +108,11 @@ import { api } from '@/scripts/api'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useLitegraphService } from '@/services/litegraphService'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
import { TaskItemImpl, useQueueStore } from '@/stores/queueStore'
|
||||
import {
|
||||
ResultItemImpl,
|
||||
TaskItemImpl,
|
||||
useQueueStore
|
||||
} from '@/stores/queueStore'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { ComfyNode } from '@/types/comfyWorkflow'
|
||||
|
||||
@@ -127,6 +131,7 @@ const { t } = useI18n()
|
||||
// Expanded view: show all outputs in a flat list.
|
||||
const isExpanded = ref(false)
|
||||
const galleryActiveIndex = ref(-1)
|
||||
const allGalleryItems = shallowRef<ResultItemImpl[]>([])
|
||||
// Folder view: only show outputs from a single selected task.
|
||||
const folderTask = ref<TaskItemImpl | null>(null)
|
||||
const isInFolderView = computed(() => folderTask.value !== null)
|
||||
@@ -141,12 +146,12 @@ const allTasks = computed(() =>
|
||||
? queueStore.flatTasks
|
||||
: queueStore.tasks
|
||||
)
|
||||
const allGalleryItems = computed(() =>
|
||||
allTasks.value.flatMap((task: TaskItemImpl) => {
|
||||
const updateGalleryItems = () => {
|
||||
allGalleryItems.value = allTasks.value.flatMap((task: TaskItemImpl) => {
|
||||
const previewOutput = task.previewOutput
|
||||
return previewOutput ? [previewOutput] : []
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const toggleExpanded = () => {
|
||||
isExpanded.value = !isExpanded.value
|
||||
@@ -232,6 +237,7 @@ const handleContextMenu = ({
|
||||
}
|
||||
|
||||
const handlePreview = (task: TaskItemImpl) => {
|
||||
updateGalleryItems()
|
||||
galleryActiveIndex.value = allGalleryItems.value.findIndex(
|
||||
(item) => item.url === task.previewOutput?.url
|
||||
)
|
||||
@@ -249,6 +255,19 @@ const toggleImageFit = () => {
|
||||
settingStore.set(IMAGE_FIT, imageFit.value === 'cover' ? 'contain' : 'cover')
|
||||
}
|
||||
|
||||
watch(allTasks, () => {
|
||||
const isGalleryOpen = galleryActiveIndex.value !== -1
|
||||
if (!isGalleryOpen) return
|
||||
|
||||
const prevLength = allGalleryItems.value.length
|
||||
updateGalleryItems()
|
||||
const lengthChange = allGalleryItems.value.length - prevLength
|
||||
if (!lengthChange) return
|
||||
|
||||
const newIndex = galleryActiveIndex.value + lengthChange
|
||||
galleryActiveIndex.value = Math.max(0, newIndex)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
api.addEventListener('status', onStatus)
|
||||
queueStore.update()
|
||||
|
||||
Reference in New Issue
Block a user