60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
|
|
/** Shared utility functions and constants for WorkItemDetailPanel sub-components. */
|
||
|
|
|
||
|
|
import type { AgentStatusValue } from "../api/agents";
|
||
|
|
|
||
|
|
export const STAGE_LABELS: Record<string, string> = {
|
||
|
|
backlog: "Backlog",
|
||
|
|
current: "Current",
|
||
|
|
qa: "QA",
|
||
|
|
merge: "To Merge",
|
||
|
|
done: "Done",
|
||
|
|
archived: "Archived",
|
||
|
|
};
|
||
|
|
|
||
|
|
export const STATUS_COLORS: Record<AgentStatusValue, string> = {
|
||
|
|
running: "#3fb950",
|
||
|
|
pending: "#e3b341",
|
||
|
|
completed: "#aaa",
|
||
|
|
failed: "#f85149",
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Strip YAML front matter and the first H1 heading from story content before
|
||
|
|
* rendering. The panel header already shows the story ID/title, so rendering
|
||
|
|
* them again inside the markdown body creates duplicate information.
|
||
|
|
*/
|
||
|
|
export function stripDisplayContent(content: string): string {
|
||
|
|
let text = content;
|
||
|
|
// Strip YAML front matter (--- ... ---)
|
||
|
|
if (text.startsWith("---")) {
|
||
|
|
const eol = text.indexOf("\n");
|
||
|
|
if (eol !== -1) {
|
||
|
|
const closeIdx = text.indexOf("\n---", eol);
|
||
|
|
if (closeIdx !== -1) {
|
||
|
|
text = text.slice(closeIdx + 4);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Trim leading blank lines left by the front matter
|
||
|
|
text = text.trimStart();
|
||
|
|
// Strip the first H1 heading — it duplicates the panel header title
|
||
|
|
if (text.startsWith("# ")) {
|
||
|
|
const eol = text.indexOf("\n");
|
||
|
|
text = eol !== -1 ? text.slice(eol + 1).trimStart() : "";
|
||
|
|
}
|
||
|
|
return text;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Format the story ID/title line shown in the panel header.
|
||
|
|
* Produces e.g. "Story 454: My Story Name" or "Bug 12: Crash on startup".
|
||
|
|
* Falls back to name or storyId when the pattern doesn't match.
|
||
|
|
*/
|
||
|
|
export function formatStoryTitle(storyId: string, name: string | null): string {
|
||
|
|
const match = storyId.match(/^(\d+)_([a-z]+)_/);
|
||
|
|
if (!match || !name) return name ?? storyId;
|
||
|
|
const [, number, type] = match;
|
||
|
|
const typeLabel = type.charAt(0).toUpperCase() + type.slice(1);
|
||
|
|
return `${typeLabel} ${number}: ${name}`;
|
||
|
|
}
|