mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-05 07:30:11 +00:00
nit
This commit is contained in:
@@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useCurrentNodeName } from '@/composables/queue/useCurrentNodeName'
|
||||
import { useQueueProgress } from '@/composables/queue/useQueueProgress'
|
||||
import { isCloud } from '@/platform/distribution/types'
|
||||
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
|
||||
import { useExecutionStore } from '@/stores/executionStore'
|
||||
import { useQueueStore } from '@/stores/queueStore'
|
||||
import type { TaskItemImpl } from '@/stores/queueStore'
|
||||
@@ -19,14 +18,6 @@ import {
|
||||
import { buildJobDisplay } from '@/utils/queueDisplay'
|
||||
import { jobStateFromTask } from '@/utils/queueUtil'
|
||||
|
||||
/** Tabs for job list filtering */
|
||||
/** Tabs for job list filtering */
|
||||
const jobTabs = ['All', 'Completed', 'Failed']
|
||||
type JobTab = (typeof jobTabs)[number]
|
||||
|
||||
const jobSortModes = ['mostRecent', 'totalGenerationTime']
|
||||
type JobSortMode = (typeof jobSortModes)[number]
|
||||
|
||||
/**
|
||||
* UI item in the job list. Mirrors data previously prepared inline.
|
||||
*/
|
||||
@@ -89,13 +80,12 @@ type TaskWithState = {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the reactive job list, filters, and grouped view for the queue overlay.
|
||||
* Builds the reactive job list and grouped view for the queue overlay.
|
||||
*/
|
||||
export function useJobList() {
|
||||
const { t, locale } = useI18n()
|
||||
const queueStore = useQueueStore()
|
||||
const executionStore = useExecutionStore()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const seenPendingIds = ref<Set<string>>(new Set())
|
||||
const recentlyAddedPendingIds = ref<Set<string>>(new Set())
|
||||
@@ -184,11 +174,7 @@ export function useJobList() {
|
||||
const isJobInitializing = (promptId: string | number | undefined) =>
|
||||
executionStore.isPromptInitializing(promptId)
|
||||
|
||||
const selectedJobTab = ref<JobTab>('All')
|
||||
const selectedWorkflowFilter = ref<'all' | 'current'>('all')
|
||||
const selectedSortMode = ref<JobSortMode>('mostRecent')
|
||||
|
||||
const allTasksSorted = computed<TaskItemImpl[]>(() => {
|
||||
const orderedTasks = computed<TaskItemImpl[]>(() => {
|
||||
const all = [
|
||||
...queueStore.pendingTasks,
|
||||
...queueStore.runningTasks,
|
||||
@@ -198,50 +184,14 @@ export function useJobList() {
|
||||
})
|
||||
|
||||
const tasksWithJobState = computed<TaskWithState[]>(() =>
|
||||
allTasksSorted.value.map((task) => ({
|
||||
orderedTasks.value.map((task) => ({
|
||||
task,
|
||||
state: jobStateFromTask(task, isJobInitializing(task?.promptId))
|
||||
}))
|
||||
)
|
||||
|
||||
const hasFailedJobs = computed(() =>
|
||||
tasksWithJobState.value.some(({ state }) => state === 'failed')
|
||||
)
|
||||
|
||||
watch(
|
||||
() => hasFailedJobs.value,
|
||||
(hasFailed) => {
|
||||
if (!hasFailed && selectedJobTab.value === 'Failed') {
|
||||
selectedJobTab.value = 'All'
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const filteredTaskEntries = computed<TaskWithState[]>(() => {
|
||||
let entries = tasksWithJobState.value
|
||||
if (selectedJobTab.value === 'Completed') {
|
||||
entries = entries.filter(({ state }) => state === 'completed')
|
||||
} else if (selectedJobTab.value === 'Failed') {
|
||||
entries = entries.filter(({ state }) => state === 'failed')
|
||||
}
|
||||
|
||||
if (selectedWorkflowFilter.value === 'current') {
|
||||
const activeId = workflowStore.activeWorkflow?.activeState?.id
|
||||
if (!activeId) return []
|
||||
entries = entries.filter(({ task }) => {
|
||||
const wid = task.workflow?.id
|
||||
return !!wid && wid === activeId
|
||||
})
|
||||
}
|
||||
return entries
|
||||
})
|
||||
|
||||
const filteredTasks = computed<TaskItemImpl[]>(() =>
|
||||
filteredTaskEntries.value.map(({ task }) => task)
|
||||
)
|
||||
|
||||
const jobItems = computed<JobListItem[]>(() => {
|
||||
return filteredTaskEntries.value.map(({ task, state }) => {
|
||||
return tasksWithJobState.value.map(({ task, state }) => {
|
||||
const isActive =
|
||||
String(task.promptId ?? '') ===
|
||||
String(executionStore.activePromptId ?? '')
|
||||
@@ -295,7 +245,7 @@ export function useJobList() {
|
||||
const groups: JobGroup[] = []
|
||||
const index = new Map<string, number>()
|
||||
const localeValue = locale.value
|
||||
for (const { task, state } of filteredTaskEntries.value) {
|
||||
for (const { task, state } of tasksWithJobState.value) {
|
||||
let ts: number | undefined
|
||||
if (state === 'completed' || state === 'failed') {
|
||||
ts = task.executionEndTimestamp
|
||||
@@ -321,29 +271,11 @@ export function useJobList() {
|
||||
if (ji) groups[groupIdx].items.push(ji)
|
||||
}
|
||||
|
||||
if (selectedSortMode.value === 'totalGenerationTime') {
|
||||
const valueOrDefault = (value: JobListItem['executionTimeMs']) =>
|
||||
typeof value === 'number' && !Number.isNaN(value) ? value : -1
|
||||
const sortByExecutionTimeDesc = (a: JobListItem, b: JobListItem) =>
|
||||
valueOrDefault(b.executionTimeMs) - valueOrDefault(a.executionTimeMs)
|
||||
|
||||
groups.forEach((group) => {
|
||||
group.items.sort(sortByExecutionTimeDesc)
|
||||
})
|
||||
}
|
||||
|
||||
return groups
|
||||
})
|
||||
|
||||
return {
|
||||
// filters/state
|
||||
selectedJobTab,
|
||||
selectedWorkflowFilter,
|
||||
selectedSortMode,
|
||||
hasFailedJobs,
|
||||
// data sources
|
||||
allTasksSorted,
|
||||
filteredTasks,
|
||||
orderedTasks,
|
||||
jobItems,
|
||||
groupedJobItems,
|
||||
currentNodeName
|
||||
|
||||
@@ -158,23 +158,6 @@ vi.mock('@/stores/executionStore', () => ({
|
||||
}
|
||||
}))
|
||||
|
||||
let workflowStoreMock: {
|
||||
activeWorkflow: null | { activeState?: { id?: string } }
|
||||
}
|
||||
const ensureWorkflowStore = () => {
|
||||
if (!workflowStoreMock) {
|
||||
workflowStoreMock = reactive({
|
||||
activeWorkflow: null as null | { activeState?: { id?: string } }
|
||||
})
|
||||
}
|
||||
return workflowStoreMock
|
||||
}
|
||||
vi.mock('@/platform/workflow/management/stores/workflowStore', () => ({
|
||||
useWorkflowStore: () => {
|
||||
return ensureWorkflowStore()
|
||||
}
|
||||
}))
|
||||
|
||||
const createTask = (
|
||||
overrides: Partial<TestTask> & { mockState?: JobState } = {}
|
||||
): TestTask => ({
|
||||
@@ -210,9 +193,6 @@ const resetStores = () => {
|
||||
executionStore.activePromptId = null
|
||||
executionStore.executingNode = null
|
||||
|
||||
const workflowStore = ensureWorkflowStore()
|
||||
workflowStore.activeWorkflow = null
|
||||
|
||||
ensureProgressRefs()
|
||||
totalPercent.value = 0
|
||||
currentNodePercent.value = 0
|
||||
@@ -332,7 +312,7 @@ describe('useJobList', () => {
|
||||
expect(vi.getTimerCount()).toBe(0)
|
||||
})
|
||||
|
||||
it('sorts all tasks by queue index descending', async () => {
|
||||
it('sorts tasks by queue index descending', async () => {
|
||||
queueStoreMock.pendingTasks = [
|
||||
createTask({ promptId: 'p', queueIndex: 1, mockState: 'pending' })
|
||||
]
|
||||
@@ -343,75 +323,16 @@ describe('useJobList', () => {
|
||||
createTask({ promptId: 'h', queueIndex: 3, mockState: 'completed' })
|
||||
]
|
||||
|
||||
const { allTasksSorted } = initComposable()
|
||||
const { orderedTasks } = initComposable()
|
||||
await flush()
|
||||
|
||||
expect(allTasksSorted.value.map((task) => task.promptId)).toEqual([
|
||||
expect(orderedTasks.value.map((task) => task.promptId)).toEqual([
|
||||
'r',
|
||||
'h',
|
||||
'p'
|
||||
])
|
||||
})
|
||||
|
||||
it('filters by job tab and resets failed tab when failures disappear', async () => {
|
||||
queueStoreMock.historyTasks = [
|
||||
createTask({ promptId: 'c', queueIndex: 3, mockState: 'completed' }),
|
||||
createTask({ promptId: 'f', queueIndex: 2, mockState: 'failed' }),
|
||||
createTask({ promptId: 'p', queueIndex: 1, mockState: 'pending' })
|
||||
]
|
||||
|
||||
const instance = initComposable()
|
||||
await flush()
|
||||
|
||||
instance.selectedJobTab.value = 'Completed'
|
||||
await flush()
|
||||
expect(instance.filteredTasks.value.map((t) => t.promptId)).toEqual(['c'])
|
||||
|
||||
instance.selectedJobTab.value = 'Failed'
|
||||
await flush()
|
||||
expect(instance.filteredTasks.value.map((t) => t.promptId)).toEqual(['f'])
|
||||
expect(instance.hasFailedJobs.value).toBe(true)
|
||||
|
||||
queueStoreMock.historyTasks = [
|
||||
createTask({ promptId: 'c', queueIndex: 3, mockState: 'completed' })
|
||||
]
|
||||
await flush()
|
||||
|
||||
expect(instance.hasFailedJobs.value).toBe(false)
|
||||
expect(instance.selectedJobTab.value).toBe('All')
|
||||
})
|
||||
|
||||
it('filters by active workflow when requested', async () => {
|
||||
queueStoreMock.pendingTasks = [
|
||||
createTask({
|
||||
promptId: 'wf-1',
|
||||
queueIndex: 2,
|
||||
mockState: 'pending',
|
||||
workflow: { id: 'workflow-1' }
|
||||
}),
|
||||
createTask({
|
||||
promptId: 'wf-2',
|
||||
queueIndex: 1,
|
||||
mockState: 'pending',
|
||||
workflow: { id: 'workflow-2' }
|
||||
})
|
||||
]
|
||||
|
||||
const instance = initComposable()
|
||||
await flush()
|
||||
|
||||
instance.selectedWorkflowFilter.value = 'current'
|
||||
await flush()
|
||||
expect(instance.filteredTasks.value).toEqual([])
|
||||
|
||||
workflowStoreMock.activeWorkflow = { activeState: { id: 'workflow-1' } }
|
||||
await flush()
|
||||
|
||||
expect(instance.filteredTasks.value.map((t) => t.promptId)).toEqual([
|
||||
'wf-1'
|
||||
])
|
||||
})
|
||||
|
||||
it('hydrates job items with active progress and compute hours', async () => {
|
||||
queueStoreMock.runningTasks = [
|
||||
createTask({
|
||||
@@ -468,7 +389,7 @@ describe('useJobList', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('groups job items by date label and sorts by total generation time when requested', async () => {
|
||||
it('groups job items by date label using queue order', async () => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date('2024-01-10T12:00:00Z'))
|
||||
queueStoreMock.historyTasks = [
|
||||
@@ -501,7 +422,6 @@ describe('useJobList', () => {
|
||||
]
|
||||
|
||||
const instance = initComposable()
|
||||
instance.selectedSortMode.value = 'totalGenerationTime'
|
||||
await flush()
|
||||
|
||||
const groups = instance.groupedJobItems.value
|
||||
@@ -513,8 +433,8 @@ describe('useJobList', () => {
|
||||
|
||||
const todayGroup = groups[0]
|
||||
expect(todayGroup.items.map((item) => item.id)).toEqual([
|
||||
'today-large',
|
||||
'today-small'
|
||||
'today-small',
|
||||
'today-large'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user