bada122f42
Deploy / deploy (push) Successful in 7m4s
Initialise Workspace built UNG_101..UNG_117 from a hardcoded range and
imported one hardcoded AEP, and fourteen findComp calls named UNG's comps
literally. None of it worked for a second show.
Comp names now follow a convention derived from the show id —
{showId}_VFX_OVERLAY, {showId}_EXPORT_TEMPLATE, _SHOW LUT — which
reproduces UNG's existing names exactly, so nothing changes for the show
it was written for. A project whose template departs from the pattern can
override any of the three.
Paths cannot be derived: UNG's show id is UNG while its folder is
UNGO_VFX. Those live on Project.pipelineConfig and are edited under
Project → Settings → Pipeline. They are resolved server-side and handed
to the panel with the project list, and read by buildPreviewManifest for
the headless build, so the panel and the farm cannot disagree about which
template — or which show LUT — a shot was built with. That mattered more
than the folder names: a preview rendered through another show's LUT is
quietly the wrong colour rather than obviously broken.
Episode folders come from the project's episode list, falling back to the
folders under its footage root for a show whose episodes are not entered
yet.
Panel 2.5.0. Adds migration 20260814010000_project_pipeline_config.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
2.6 KiB
TypeScript
73 lines
2.6 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { db } from "@/lib/db";
|
|
import { resolveProjectTemplates } from "@/lib/render-pipeline/project-templates";
|
|
|
|
// ── Auth ─────────────────────────────────────────────────────────────────────
|
|
|
|
function isAuthorized(req: NextRequest): boolean {
|
|
const apiKey = process.env.API_SECRET_KEY;
|
|
if (!apiKey) return false;
|
|
const authHeader = req.headers.get("authorization") ?? "";
|
|
if (authHeader.startsWith("Bearer ")) return authHeader.slice(7) === apiKey;
|
|
return (req.headers.get("x-api-key") ?? "") === apiKey;
|
|
}
|
|
|
|
// ── GET /api/ext/projects ─────────────────────────────────────────────────────
|
|
//
|
|
// Returns all projects with their showIds. Useful for pipeline tools that need
|
|
// to enumerate available projects and resolve a showId → projectCode mapping.
|
|
//
|
|
// Query params (all optional):
|
|
// status Filter by project status: ACTIVE (default) | ARCHIVED | ALL
|
|
//
|
|
// Example:
|
|
// GET /api/ext/projects
|
|
// GET /api/ext/projects?status=ALL
|
|
|
|
export async function GET(req: NextRequest) {
|
|
if (!isAuthorized(req)) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
const { searchParams } = new URL(req.url);
|
|
const statusParam = searchParams.get("status")?.toUpperCase() ?? "ACTIVE";
|
|
|
|
const whereStatus =
|
|
statusParam === "ALL"
|
|
? undefined
|
|
: statusParam === "ARCHIVED"
|
|
? { status: "ARCHIVED" as const }
|
|
: { status: "ACTIVE" as const };
|
|
|
|
const projects = await db.project.findMany({
|
|
where: whereStatus,
|
|
orderBy: [{ showId: "asc" }, { code: "asc" }],
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
code: true,
|
|
showId: true,
|
|
projectType: true,
|
|
status: true,
|
|
startDate: true,
|
|
dueDate: true,
|
|
pipelineConfig: true,
|
|
_count: {
|
|
select: { shots: true },
|
|
},
|
|
},
|
|
});
|
|
|
|
// Templates are resolved here rather than in the panel so that the panel and
|
|
// the headless preview build cannot disagree about which template, or which
|
|
// show LUT, a shot was built with.
|
|
const withTemplates = await Promise.all(
|
|
projects.map(async ({ pipelineConfig, ...project }) => ({
|
|
...project,
|
|
templates: await resolveProjectTemplates({ ...project, pipelineConfig }),
|
|
}))
|
|
);
|
|
|
|
return NextResponse.json({ projects: withTemplates, total: withTemplates.length });
|
|
}
|