feat(web): richer active-job rows on The Floor (source/format/tracks, stage, elapsed, error)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { POST, GET } from "./route";
|
||||
import { prisma } from "@/lib/db";
|
||||
|
||||
function postReq(body: unknown) {
|
||||
return new Request("http://localhost/api/requests", {
|
||||
@@ -55,4 +56,58 @@ describe("requests API", () => {
|
||||
expect(body.requests[0].artist).toBe("B");
|
||||
expect(body.requests[0].job.state).toBe("requested");
|
||||
});
|
||||
|
||||
it("expands job detail with candidate summary and chosen candidate", async () => {
|
||||
const created = await prisma.request.create({
|
||||
data: {
|
||||
artist: "Chosen Artist",
|
||||
album: "Chosen Album",
|
||||
job: { create: { state: "downloading", currentStage: "download", attempts: 2, error: "boom" } },
|
||||
},
|
||||
include: { job: true },
|
||||
});
|
||||
await prisma.candidate.create({
|
||||
data: {
|
||||
jobId: created.job!.id,
|
||||
source: "qobuz",
|
||||
format: "flac",
|
||||
qualityClass: 1,
|
||||
trackCount: 12,
|
||||
confidence: 0.9,
|
||||
sourceRef: "ref-1",
|
||||
chosen: true,
|
||||
},
|
||||
});
|
||||
await prisma.candidate.create({
|
||||
data: {
|
||||
jobId: created.job!.id,
|
||||
source: "slskd",
|
||||
format: "mp3",
|
||||
qualityClass: 2,
|
||||
trackCount: 12,
|
||||
confidence: 0.5,
|
||||
sourceRef: "ref-2",
|
||||
chosen: false,
|
||||
},
|
||||
});
|
||||
|
||||
const res = await GET();
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
const found = body.requests.find((r: { id: string }) => r.id === created.id);
|
||||
expect(found.job.candidateCount).toBe(2);
|
||||
expect(found.job.chosen).toEqual({ source: "qobuz", format: "flac", trackCount: 12 });
|
||||
expect(found.job.error).toBe("boom");
|
||||
expect(found.job.attempts).toBe(2);
|
||||
});
|
||||
|
||||
it("reports no chosen candidate and zero count when a job has none", async () => {
|
||||
const res = await POST(postReq({ artist: "NoCand", album: "Album" }));
|
||||
const created = await res.json();
|
||||
const listRes = await GET();
|
||||
const body = await listRes.json();
|
||||
const found = body.requests.find((r: { id: string }) => r.id === created.id);
|
||||
expect(found.job.candidateCount).toBe(0);
|
||||
expect(found.job.chosen).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,7 +36,10 @@ export async function POST(request: Request) {
|
||||
|
||||
export async function GET() {
|
||||
const [requests, releases] = await Promise.all([
|
||||
prisma.request.findMany({ orderBy: { createdAt: "desc" }, include: { job: true } }),
|
||||
prisma.request.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
include: { job: { include: { candidates: { select: { source: true, format: true, trackCount: true, chosen: true } } } } },
|
||||
}),
|
||||
prisma.monitoredRelease.findMany({ select: { artistName: true, album: true, rgMbid: true } }),
|
||||
]);
|
||||
const rgByKey = new Map(releases.map((mr) => [`${mr.artistName} ${mr.album}`, mr.rgMbid]));
|
||||
@@ -49,7 +52,22 @@ export async function GET() {
|
||||
status: r.status,
|
||||
createdAt: r.createdAt,
|
||||
rgMbid: rgByKey.get(`${r.artist} ${r.album}`) ?? null,
|
||||
job: r.job ? { state: r.job.state, currentStage: r.job.currentStage } : null,
|
||||
job: r.job
|
||||
? (() => {
|
||||
const cands = r.job.candidates;
|
||||
const chosen = cands.find((c) => c.chosen) ?? null;
|
||||
return {
|
||||
state: r.job.state,
|
||||
currentStage: r.job.currentStage,
|
||||
attempts: r.job.attempts,
|
||||
error: r.job.error,
|
||||
claimedAt: r.job.claimedAt,
|
||||
updatedAt: r.job.updatedAt,
|
||||
candidateCount: cands.length,
|
||||
chosen: chosen ? { source: chosen.source, format: chosen.format, trackCount: chosen.trackCount } : null,
|
||||
};
|
||||
})()
|
||||
: null,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user