Compare commits

...

1 Commits

Author SHA1 Message Date
Benjamin Lu
85dd78e58f fix: gate qpov2 failed cards on active jobs 2026-02-07 21:13:33 -08:00
4 changed files with 69 additions and 13 deletions

View File

@@ -2,12 +2,12 @@
<div class="flex h-full flex-col">
<!-- Active Jobs Grid -->
<div
v-if="isQueuePanelV2Enabled && activeJobItems.length"
v-if="isQueuePanelV2Enabled && sidebarJobItems.length"
class="grid max-h-[50%] scrollbar-custom overflow-y-auto"
:style="gridStyle"
>
<ActiveMediaAssetCard
v-for="job in activeJobItems"
v-for="job in sidebarJobItems"
:key="job.id"
:job="job"
/>
@@ -16,7 +16,7 @@
<!-- Assets Header -->
<div
v-if="assets.length"
:class="cn('px-2 2xl:px-4', activeJobItems.length && 'mt-2')"
:class="cn('px-2 2xl:px-4', sidebarJobItems.length && 'mt-2')"
>
<div
class="flex items-center py-2 text-sm font-normal leading-normal text-muted-foreground font-inter"
@@ -63,7 +63,7 @@ import ActiveMediaAssetCard from '@/platform/assets/components/ActiveMediaAssetC
import { useJobList } from '@/composables/queue/useJobList'
import MediaAssetCard from '@/platform/assets/components/MediaAssetCard.vue'
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
import { isActiveJobState } from '@/utils/queueUtil'
import { isActiveJobState, isAssetsSidebarJobState } from '@/utils/queueUtil'
import { cn } from '@/utils/tailwindUtil'
import { useSettingStore } from '@/platform/settings/settingStore'
@@ -99,10 +99,17 @@ const isQueuePanelV2Enabled = computed(() =>
type AssetGridItem = { key: string; asset: AssetItem }
const activeJobItems = computed(() =>
jobItems.value.filter((item) => isActiveJobState(item.state))
const hasActiveJobItems = computed(() =>
jobItems.value.some((item) => isActiveJobState(item.state))
)
const sidebarJobItems = computed(() => {
if (!hasActiveJobItems.value) {
return []
}
return jobItems.value.filter((item) => isAssetsSidebarJobState(item.state))
})
const assetItems = computed<AssetGridItem[]>(() =>
assets.map((asset) => ({
key: `asset-${asset.id}`,

View File

@@ -1,11 +1,11 @@
<template>
<div class="flex h-full flex-col">
<div
v-if="isQueuePanelV2Enabled && activeJobItems.length"
v-if="isQueuePanelV2Enabled && sidebarJobItems.length"
class="flex max-h-[50%] scrollbar-custom flex-col gap-2 overflow-y-auto px-2"
>
<AssetsListItem
v-for="job in activeJobItems"
v-for="job in sidebarJobItems"
:key="job.id"
:class="
cn(
@@ -41,7 +41,7 @@
<div
v-if="assets.length"
:class="cn('px-2', activeJobItems.length && 'mt-2')"
:class="cn('px-2', sidebarJobItems.length && 'mt-2')"
>
<div
class="flex items-center p-2 text-sm font-normal leading-normal text-muted-foreground font-inter"
@@ -124,7 +124,7 @@ import { getOutputAssetMetadata } from '@/platform/assets/schemas/assetMetadataS
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 { isActiveJobState, isAssetsSidebarJobState } from '@/utils/queueUtil'
import {
formatDuration,
formatSize,
@@ -165,12 +165,19 @@ const hoveredAssetId = ref<string | null>(null)
type AssetListItem = { key: string; asset: AssetItem }
const activeJobItems = computed(() =>
jobItems.value.filter((item) => isActiveJobState(item.state))
const hasActiveJobItems = computed(() =>
jobItems.value.some((item) => isActiveJobState(item.state))
)
const sidebarJobItems = computed(() => {
if (!hasActiveJobItems.value) {
return []
}
return jobItems.value.filter((item) => isAssetsSidebarJobState(item.state))
})
const hoveredJob = computed(() =>
hoveredJobId.value
? (activeJobItems.value.find((job) => job.id === hoveredJobId.value) ??
? (sidebarJobItems.value.find((job) => job.id === hoveredJobId.value) ??
null)
: null
)

View File

@@ -0,0 +1,35 @@
import { describe, expect, it } from 'vitest'
import type { JobState } from '@/types/queue'
import { isActiveJobState, isAssetsSidebarJobState } from './queueUtil'
describe('queueUtil', () => {
it('marks only in-progress states as active', () => {
const states: Record<JobState, boolean> = {
pending: true,
initialization: true,
running: true,
completed: false,
failed: false
}
for (const state of Object.keys(states) as JobState[]) {
expect(isActiveJobState(state)).toBe(states[state])
}
})
it('includes failed states in assets sidebar jobs and excludes completed', () => {
const states: Record<JobState, boolean> = {
pending: true,
initialization: true,
running: true,
completed: false,
failed: true
}
for (const state of Object.keys(states) as JobState[]) {
expect(isAssetsSidebarJobState(state)).toBe(states[state])
}
})
})

View File

@@ -10,6 +10,13 @@ export function isActiveJobState(state: JobState): boolean {
)
}
/**
* Checks if a job state should be shown in the assets sidebar QPOV2 job area.
*/
export function isAssetsSidebarJobState(state: JobState): boolean {
return state !== 'completed'
}
/**
* Map a task to a UI job state, including initialization override.
*