kaneo (minimalist kanban) fork to experiment adding a tangled integration
github.com/usekaneo/kaneo
1type GitHubLabel = string | { name?: string };
2
3const VALID_PRIORITIES = ["low", "medium", "high", "urgent"] as const;
4const STATUS_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
5
6export type ValidPriority = (typeof VALID_PRIORITIES)[number];
7export type ValidStatus = string;
8
9/**
10 * Extract priority from GitHub issue labels.
11 * Returns null if no valid priority label found (lets Kaneo use its defaults).
12 */
13export function extractIssuePriority(
14 labels: GitHubLabel[] | undefined,
15): ValidPriority | null {
16 if (!labels) return null;
17
18 const priorityLabels = labels
19 .map((label) => (typeof label === "string" ? label : label?.name))
20 .filter((name) => name?.startsWith("priority:"));
21
22 const firstPriorityLabel = priorityLabels[0];
23 if (!firstPriorityLabel) return null;
24
25 const priority = firstPriorityLabel.replace("priority:", "");
26 return VALID_PRIORITIES.includes(priority as ValidPriority)
27 ? (priority as ValidPriority)
28 : null;
29}
30
31/**
32 * Extract status from GitHub issue labels.
33 * Returns null if no valid status label found (lets Kaneo use its defaults).
34 */
35export function extractIssueStatus(
36 labels: GitHubLabel[] | undefined,
37): ValidStatus | null {
38 if (!labels) return null;
39
40 const statusLabels = labels
41 .map((label) => (typeof label === "string" ? label : label?.name))
42 .filter((name) => name?.startsWith("status:"));
43
44 const firstStatusLabel = statusLabels[0];
45 if (!firstStatusLabel) return null;
46
47 const status = firstStatusLabel.replace("status:", "").trim().toLowerCase();
48 return STATUS_SLUG_PATTERN.test(status) ? status : null;
49}