kaneo (minimalist kanban) fork to experiment adding a tangled integration
github.com/usekaneo/kaneo
1import { eq } from "drizzle-orm";
2import db from "../../../database";
3import { labelTable, taskTable } from "../../../database/schema";
4import { findExternalLink } from "../services/link-manager";
5import {
6 findAllIntegrationsByRepo,
7 updateTaskStatus,
8} from "../services/task-service";
9import {
10 extractIssuePriority,
11 extractIssueStatus,
12} from "../utils/extract-priority";
13
14type IssueLabeledPayload = {
15 action: string;
16 issue: {
17 number: number;
18 labels?: Array<string | { name?: string }>;
19 };
20 label?: {
21 name: string;
22 color: string;
23 };
24 repository: {
25 owner: { login: string };
26 name: string;
27 };
28};
29
30export async function handleIssueLabeled(payload: IssueLabeledPayload) {
31 const { issue, repository, label: addedLabel } = payload;
32
33 const integrations = await findAllIntegrationsByRepo(
34 repository.owner.login,
35 repository.name,
36 );
37
38 for (const integration of integrations) {
39 const existingLink = await findExternalLink(
40 integration.id,
41 "issue",
42 issue.number.toString(),
43 );
44
45 if (!existingLink) {
46 continue;
47 }
48
49 const priority = extractIssuePriority(issue.labels);
50 const status = extractIssueStatus(issue.labels);
51
52 if (priority) {
53 await db
54 .update(taskTable)
55 .set({ priority })
56 .where(eq(taskTable.id, existingLink.taskId));
57 }
58
59 if (status) {
60 await updateTaskStatus(existingLink.taskId, status);
61 }
62
63 if (!addedLabel) {
64 return;
65 }
66
67 const isSystemLabel =
68 addedLabel.name.startsWith("priority:") ||
69 addedLabel.name.startsWith("status:");
70
71 if (isSystemLabel) {
72 return;
73 }
74
75 if (payload.action === "labeled") {
76 const task = await db.query.taskTable.findFirst({
77 where: eq(taskTable.id, existingLink.taskId),
78 with: {
79 project: true,
80 },
81 });
82
83 if (task?.project?.workspaceId) {
84 const existingLabel = await db.query.labelTable.findFirst({
85 where: (table, { and, eq }) =>
86 and(
87 eq(table.workspaceId, task.project.workspaceId),
88 eq(table.name, addedLabel.name),
89 eq(table.taskId, task.id),
90 ),
91 });
92
93 if (!existingLabel) {
94 const color = addedLabel.color ? `#${addedLabel.color}` : "#6B7280";
95 await db.insert(labelTable).values({
96 name: addedLabel.name,
97 color,
98 taskId: task.id,
99 workspaceId: task.project.workspaceId,
100 });
101 }
102 }
103 }
104
105 if (payload.action === "unlabeled") {
106 const labelsToDelete = await db.query.labelTable.findMany({
107 where: (table, { and, eq }) =>
108 and(
109 eq(table.taskId, existingLink.taskId),
110 eq(table.name, addedLabel.name),
111 ),
112 });
113
114 for (const label of labelsToDelete) {
115 await db.delete(labelTable).where(eq(labelTable.id, label.id));
116 }
117 }
118
119 return;
120 }
121}