Let finished caption jobs be dismissed from the Queue panel.
This commit is contained in:
@@ -1,15 +1,40 @@
|
||||
import { records, saveRecord } from '../../utils/studio2/store';
|
||||
import { listStudioJobs } from '../../utils/studioQueue';
|
||||
export default defineEventHandler(event => {
|
||||
const { owner } = assertLibraryOwner(event), queue=listStudioJobs(owner);
|
||||
let cleared=0;
|
||||
for (const r of records(owner)) {
|
||||
try { assertFolderAccess(event,r.request.folderId); } catch { continue; }
|
||||
const status=queue.find(q=>q.id===r.queueId)?.status;
|
||||
if (['complete','failed','cancelled'].includes(r.state) || ['cancelled','error'].includes(status || '')) {
|
||||
r.dismissed=true; saveRecord(r); cleared++;
|
||||
import { records, saveRecord } from '../../utils/studio2/store'
|
||||
import { dismissFinishedStudioJobs, dismissStudioJob, listStudioJobs } from '../../utils/studioQueue'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { owner } = assertLibraryOwner(event)
|
||||
const body = await readBody<{ id?: string }>(event).catch(() => ({} as { id?: string }))
|
||||
const queue = listStudioJobs(owner)
|
||||
let cleared = 0
|
||||
|
||||
if (body?.id) {
|
||||
const row = queue.find(job => job.id === body.id)
|
||||
if (!row) throw createError({ statusCode: 404, statusMessage: 'Queued job not found' })
|
||||
try { assertFolderAccess(event, row.payload.folderId) } catch {
|
||||
throw createError({ statusCode: 403, statusMessage: 'Folder locked' })
|
||||
}
|
||||
await dismissStudioJob(owner, body.id)
|
||||
return { cleared: 1 }
|
||||
}
|
||||
}
|
||||
// Retain internal manifests for cleanup retries; remove these records from the visible jobs list.
|
||||
return {cleared};
|
||||
});
|
||||
|
||||
for (const r of records(owner)) {
|
||||
try { assertFolderAccess(event, r.request.folderId) } catch { continue }
|
||||
const status = queue.find(q => q.id === r.queueId)?.status
|
||||
if (['complete', 'failed', 'cancelled'].includes(r.state) || ['cancelled', 'error'].includes(status || '')) {
|
||||
r.dismissed = true
|
||||
saveRecord(r)
|
||||
cleared++
|
||||
}
|
||||
}
|
||||
|
||||
// Caption (and other finished studio-queue) cards — hide from Queue, keep resultText on the row
|
||||
const finishedIds = queue
|
||||
.filter(job => !job.dismissed && ['complete', 'error', 'cancelled'].includes(job.status))
|
||||
.filter(job => {
|
||||
try { assertFolderAccess(event, job.payload.folderId); return true } catch { return false }
|
||||
})
|
||||
.map(job => job.id)
|
||||
cleared += await dismissFinishedStudioJobs(owner, finishedIds)
|
||||
|
||||
return { cleared }
|
||||
})
|
||||
|
||||
@@ -5,12 +5,14 @@ export default defineEventHandler((event) => {
|
||||
const { owner } = assertLibraryOwner(event)
|
||||
const full = String(getQuery(event).full || '') === '1'
|
||||
const active = listStudioJobs(owner)
|
||||
.filter(job => !job.dismissed)
|
||||
.filter(job => (
|
||||
job.status === 'waiting'
|
||||
|| job.status === 'running'
|
||||
|| job.status === 'held'
|
||||
|| (job.status === 'error' && Date.now() - job.updatedAt < 60 * 60 * 1000)
|
||||
|| (job.kind === 'caption' && job.status === 'complete' && Date.now() - job.updatedAt < 60 * 60 * 1000)
|
||||
|| (job.kind === 'caption' && job.status === 'cancelled' && Date.now() - job.updatedAt < 60 * 60 * 1000)
|
||||
))
|
||||
const claimed = new Set(active.map(job => job.shotQueueId).filter(Boolean) as string[])
|
||||
const queues = listShotQueues(owner)
|
||||
|
||||
@@ -107,6 +107,8 @@ export interface StudioJob {
|
||||
lastError?: string
|
||||
waitReason?: string
|
||||
resultText?: string
|
||||
/** Hidden from Queue UI; keeps resultText on the stored row. */
|
||||
dismissed?: boolean
|
||||
}
|
||||
|
||||
type StudioQueueStore = {
|
||||
@@ -535,6 +537,40 @@ function canCancelStudioStatus(status: StudioJobStatus) {
|
||||
return status === 'waiting' || status === 'held' || status === 'running' || status === 'error'
|
||||
}
|
||||
|
||||
function isFinishedStudioStatus(status: StudioJobStatus) {
|
||||
return status === 'complete' || status === 'error' || status === 'cancelled'
|
||||
}
|
||||
|
||||
/** Hide a finished studio-queue row from the Queue panel (keeps resultText). */
|
||||
export async function dismissStudioJob(owner: string, id: string) {
|
||||
return mutate(owner, (jobs) => {
|
||||
const job = jobs.find(item => item.id === id)
|
||||
if (!job) throw createError({ statusCode: 404, statusMessage: 'Queued job not found' })
|
||||
if (!isFinishedStudioStatus(job.status)) {
|
||||
throw createError({ statusCode: 409, statusMessage: 'Only finished jobs can be dismissed' })
|
||||
}
|
||||
job.dismissed = true
|
||||
job.updatedAt = Date.now()
|
||||
return structuredClone(job)
|
||||
})
|
||||
}
|
||||
|
||||
/** Dismiss finished studio-queue rows (caption complete cards, errors, etc.). */
|
||||
export async function dismissFinishedStudioJobs(owner: string, ids?: string[]) {
|
||||
return mutate(owner, (jobs) => {
|
||||
let cleared = 0
|
||||
for (const job of jobs) {
|
||||
if (ids?.length && !ids.includes(job.id)) continue
|
||||
if (job.dismissed) continue
|
||||
if (!isFinishedStudioStatus(job.status)) continue
|
||||
job.dismissed = true
|
||||
job.updatedAt = Date.now()
|
||||
cleared += 1
|
||||
}
|
||||
return cleared
|
||||
})
|
||||
}
|
||||
|
||||
export async function cancelStudioJob(owner: string, id: string) {
|
||||
const before = readJobs(owner).find(item => item.id === id)
|
||||
if (!before) throw createError({ statusCode: 404, statusMessage: 'Queued job not found' })
|
||||
|
||||
Reference in New Issue
Block a user