ed9f9b13c1
Deploy / deploy (push) Successful in 6m8s
Shot.clientCode already drove slates, overlay burn-ins and delivered file names, but the client portal — the one place the client actually reads — was still showing our internal codes. Task titles were the larger leak. They follow the house convention "UNG_106_010_020_cmp_TT_v004", so the internal code sat embedded in the string the client reads and copies, in three places on the shot list and again in the player header. Swapping only the heading would have left it on display directly underneath. lib/shot-code.ts resolves both: clientShotCode picks the alias when set, and clientTaskTitle swaps the code out of a title by substring, leaving a hand-edited title that does not carry the code untouched rather than guessing at it. Applied at the API boundary rather than at each render site, so the shot list, search, playlist labels, alt text, player header and every copy-to-clipboard button inherit it and nothing downstream has to remember which code it is holding. The internal code is no longer sent to the browser on these routes at all. Slack notifications deliberately keep the internal code: those go to our artists, who need the code that matches the comp and the SAN path. The two existing "clientCode || shotCode" expressions in preview.ts and deliveries.ts now use the same helper so slates, deliveries and the portal cannot drift apart. Shots with no clientCode are unchanged throughout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
46 lines
1.8 KiB
TypeScript
46 lines
1.8 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { clientShotCode, clientTaskTitle } from "./shot-code";
|
|
|
|
describe("clientShotCode", () => {
|
|
it("prefers the client's alias", () => {
|
|
expect(clientShotCode({ shotCode: "UNG_106_010_020", clientCode: "EP6_VFX_012" })).toBe("EP6_VFX_012");
|
|
});
|
|
|
|
it("falls back to our code when there is no alias", () => {
|
|
expect(clientShotCode({ shotCode: "UNG_106_010_020", clientCode: null })).toBe("UNG_106_010_020");
|
|
expect(clientShotCode({ shotCode: "UNG_106_010_020" })).toBe("UNG_106_010_020");
|
|
});
|
|
|
|
it("ignores a whitespace-only alias", () => {
|
|
expect(clientShotCode({ shotCode: "UNG_106_010_020", clientCode: " " })).toBe("UNG_106_010_020");
|
|
});
|
|
});
|
|
|
|
describe("clientTaskTitle", () => {
|
|
const shot = { shotCode: "UNG_106_010_020", clientCode: "EP6_VFX_012" };
|
|
|
|
it("swaps the internal code out of a house-convention title", () => {
|
|
expect(clientTaskTitle("UNG_106_010_020_cmp_TT_v004", shot)).toBe("EP6_VFX_012_cmp_TT_v004");
|
|
});
|
|
|
|
it("leaves the title alone when there is no alias", () => {
|
|
const t = "UNG_106_010_020_cmp_TT_v004";
|
|
expect(clientTaskTitle(t, { shotCode: "UNG_106_010_020", clientCode: null })).toBe(t);
|
|
});
|
|
|
|
it("leaves a title that does not carry the code untouched", () => {
|
|
// Hand-edited titles are not guessed at — better an unhelpful title than a
|
|
// mangled one.
|
|
expect(clientTaskTitle("Roto pass", shot)).toBe("Roto pass");
|
|
});
|
|
|
|
it("swaps every occurrence", () => {
|
|
expect(clientTaskTitle("UNG_106_010_020 / UNG_106_010_020_cmp", shot)).toBe("EP6_VFX_012 / EP6_VFX_012_cmp");
|
|
});
|
|
|
|
it("is a no-op when the alias equals the code", () => {
|
|
const same = { shotCode: "UNG_106_010_020", clientCode: "UNG_106_010_020" };
|
|
expect(clientTaskTitle("UNG_106_010_020_cmp", same)).toBe("UNG_106_010_020_cmp");
|
|
});
|
|
});
|