| 1 | /** |
| 2 | * The postmortem editor's sections, and its preview's reading of plain |
| 3 | * text, the same way the status page reads it (apps/status render.ts |
| 4 | * `prose`). No Workers or React imports, so it is tested under Node. |
| 5 | */ |
| 6 | import type { PostmortemFields } from "@g1t/contracts/status"; |
| 7 | |
| 8 | export const POSTMORTEM_SECTIONS: { key: keyof PostmortemFields; title: string; hint: string; rows: number }[] = [ |
| 9 | { key: "summary", title: "Summary", hint: "Two or three sentences: what happened, to whom, for how long. Required to publish.", rows: 4 }, |
| 10 | { key: "impact", title: "Impact", hint: "Who noticed, and what they could not do.", rows: 3 }, |
| 11 | { key: "timeline", title: "Timeline", hint: "Filled in from the incident's timeline. Times are UTC.", rows: 8 }, |
| 12 | { key: "root_cause", title: "Root cause", hint: "Why it happened, not who. Required to publish.", rows: 4 }, |
| 13 | { key: "went_well", title: "What went well", hint: "", rows: 3 }, |
| 14 | { key: "went_badly", title: "What went badly", hint: "", rows: 3 }, |
| 15 | { key: "action_items", title: "Action items", hint: "Filled in from the follow-ups. One per line, starting “- ”.", rows: 4 }, |
| 16 | ]; |
| 17 | |
| 18 | export type Block = { kind: "paragraph"; text: string } | { kind: "list"; items: string[] }; |
| 19 | |
| 20 | /** Blank lines between paragraphs; a block whose lines all start with "- " is a list. */ |
| 21 | export function proseBlocks(text: string): Block[] { |
| 22 | return text |
| 23 | .split(/\n{2,}/) |
| 24 | .map((block) => block.replace(/^\n+|\n+$/g, "")) |
| 25 | .filter(Boolean) |
| 26 | .map((block): Block => { |
| 27 | const lines = block.split("\n").filter((l) => l.trim() !== ""); |
| 28 | if (lines.every((l) => /^\s*[-*] /.test(l))) return { kind: "list", items: lines.map((l) => l.replace(/^\s*[-*] /, "")) }; |
| 29 | return { kind: "paragraph", text: block }; |
| 30 | }); |
| 31 | } |