kaneo (minimalist kanban) fork to experiment adding a tangled integration
github.com/usekaneo/kaneo
1import * as v from "valibot";
2
3export const labelSchema = v.object({
4 id: v.string(),
5 name: v.string(),
6 color: v.string(),
7 createdAt: v.date(),
8 taskId: v.nullable(v.string()),
9 workspaceId: v.nullable(v.string()),
10});
11
12export const projectSchema = v.object({
13 id: v.string(),
14 workspaceId: v.string(),
15 slug: v.string(),
16 icon: v.nullable(v.string()),
17 name: v.string(),
18 description: v.nullable(v.string()),
19 createdAt: v.date(),
20 isPublic: v.nullable(v.boolean()),
21 archivedAt: v.nullable(v.date()),
22});
23
24export const taskSchema = v.object({
25 id: v.string(),
26 projectId: v.string(),
27 position: v.nullable(v.number()),
28 number: v.nullable(v.number()),
29 userId: v.nullable(v.string()),
30 title: v.string(),
31 description: v.nullable(v.string()),
32 status: v.string(),
33 priority: v.picklist([
34 "no-priority",
35 "low",
36 "medium",
37 "high",
38 "urgent",
39 ] as const),
40 startDate: v.optional(v.date()),
41 dueDate: v.optional(v.date()),
42 createdAt: v.date(),
43});
44
45export const activitySchema = v.object({
46 id: v.string(),
47 taskId: v.string(),
48 type: v.picklist([
49 "comment",
50 "task",
51 "status_changed",
52 "priority_changed",
53 "unassigned",
54 "assignee_changed",
55 "due_date_changed",
56 "title_changed",
57 "description_changed",
58 "create",
59 ] as const),
60 createdAt: v.date(),
61 userId: v.nullable(v.string()),
62 content: v.nullable(v.string()),
63 eventData: v.nullable(v.record(v.string(), v.unknown())),
64 externalUserName: v.nullable(v.string()),
65 externalUserAvatar: v.nullable(v.string()),
66 externalSource: v.nullable(v.string()),
67 externalUrl: v.nullable(v.string()),
68});
69
70export const timeEntrySchema = v.object({
71 id: v.string(),
72 taskId: v.string(),
73 userId: v.nullable(v.string()),
74 description: v.nullable(v.string()),
75 startTime: v.date(),
76 endTime: v.optional(v.date()),
77 duration: v.nullable(v.number()),
78 createdAt: v.date(),
79});
80
81export const notificationSchema = v.object({
82 id: v.string(),
83 userId: v.string(),
84 title: v.nullable(v.string()),
85 content: v.nullable(v.string()),
86 type: v.picklist([
87 "info",
88 "task_created",
89 "workspace_created",
90 "task_status_changed",
91 "task_assignee_changed",
92 "time_entry_created",
93 "due_date_reminder",
94 "task_overdue",
95 ] as const),
96 eventData: v.nullable(v.record(v.string(), v.unknown())),
97 isRead: v.optional(v.boolean()),
98 resourceId: v.optional(v.string()),
99 resourceType: v.optional(v.picklist(["task", "workspace"] as const)),
100 createdAt: v.date(),
101});
102
103export const notificationPreferenceWorkspaceRuleSchema = v.object({
104 id: v.string(),
105 workspaceId: v.string(),
106 workspaceName: v.string(),
107 isActive: v.boolean(),
108 emailEnabled: v.boolean(),
109 ntfyEnabled: v.boolean(),
110 gotifyEnabled: v.boolean(),
111 webhookEnabled: v.boolean(),
112 projectMode: v.picklist(["all", "selected"] as const),
113 selectedProjectIds: v.array(v.string()),
114 createdAt: v.date(),
115 updatedAt: v.date(),
116});
117
118export const notificationPreferenceSchema = v.object({
119 emailAddress: v.nullable(v.string()),
120 emailEnabled: v.boolean(),
121 ntfyEnabled: v.boolean(),
122 ntfyConfigured: v.boolean(),
123 ntfyServerUrl: v.nullable(v.string()),
124 ntfyTopic: v.nullable(v.string()),
125 ntfyTokenConfigured: v.boolean(),
126 maskedNtfyToken: v.nullable(v.string()),
127 gotifyEnabled: v.boolean(),
128 gotifyConfigured: v.boolean(),
129 gotifyServerUrl: v.nullable(v.string()),
130 gotifyTokenConfigured: v.boolean(),
131 maskedGotifyToken: v.nullable(v.string()),
132 webhookEnabled: v.boolean(),
133 webhookConfigured: v.boolean(),
134 webhookUrl: v.nullable(v.string()),
135 webhookSecretConfigured: v.boolean(),
136 maskedWebhookSecret: v.nullable(v.string()),
137 workspaces: v.array(notificationPreferenceWorkspaceRuleSchema),
138 createdAt: v.nullable(v.date()),
139 updatedAt: v.nullable(v.date()),
140});
141
142export const githubIntegrationSchema = v.object({
143 id: v.string(),
144 projectId: v.string(),
145 repositoryOwner: v.string(),
146 repositoryName: v.string(),
147 installationId: v.nullable(v.number()),
148 branchPattern: v.optional(v.string()),
149 commentTaskLinkOnGitHubIssue: v.optional(v.boolean()),
150 isActive: v.nullable(v.boolean()),
151 createdAt: v.date(),
152 updatedAt: v.date(),
153});
154
155export const giteaIntegrationSchema = v.object({
156 id: v.string(),
157 projectId: v.string(),
158 baseUrl: v.string(),
159 repositoryOwner: v.string(),
160 repositoryName: v.string(),
161 maskedAccessToken: v.string(),
162 webhookUrl: v.optional(v.string()),
163 webhookSecret: v.optional(v.string()),
164 branchPattern: v.optional(v.string()),
165 commentTaskLinkOnGiteaIssue: v.optional(v.boolean()),
166 isActive: v.nullable(v.boolean()),
167 createdAt: v.date(),
168 updatedAt: v.date(),
169});
170
171export const integrationEventsSchema = v.object({
172 taskCreated: v.boolean(),
173 taskStatusChanged: v.boolean(),
174 taskPriorityChanged: v.boolean(),
175 taskTitleChanged: v.boolean(),
176 taskDescriptionChanged: v.boolean(),
177 taskCommentCreated: v.boolean(),
178});
179
180export const slackIntegrationSchema = v.object({
181 id: v.string(),
182 projectId: v.string(),
183 channelName: v.nullable(v.string()),
184 webhookConfigured: v.boolean(),
185 maskedWebhookUrl: v.string(),
186 events: integrationEventsSchema,
187 isActive: v.nullable(v.boolean()),
188 createdAt: v.date(),
189 updatedAt: v.date(),
190});
191
192export const discordIntegrationSchema = v.object({
193 id: v.string(),
194 projectId: v.string(),
195 channelName: v.nullable(v.string()),
196 webhookConfigured: v.boolean(),
197 maskedWebhookUrl: v.string(),
198 events: integrationEventsSchema,
199 isActive: v.nullable(v.boolean()),
200 createdAt: v.date(),
201 updatedAt: v.date(),
202});
203
204export const genericWebhookIntegrationSchema = v.object({
205 id: v.string(),
206 projectId: v.string(),
207 webhookConfigured: v.boolean(),
208 maskedWebhookUrl: v.nullable(v.string()),
209 secretConfigured: v.boolean(),
210 maskedSecret: v.nullable(v.string()),
211 events: integrationEventsSchema,
212 isActive: v.nullable(v.boolean()),
213 createdAt: v.date(),
214 updatedAt: v.date(),
215});
216
217export const telegramIntegrationSchema = v.object({
218 id: v.string(),
219 projectId: v.string(),
220 chatId: v.string(),
221 threadId: v.nullable(v.number()),
222 chatLabel: v.nullable(v.string()),
223 botTokenConfigured: v.boolean(),
224 maskedBotToken: v.string(),
225 events: integrationEventsSchema,
226 isActive: v.nullable(v.boolean()),
227 createdAt: v.date(),
228 updatedAt: v.date(),
229});
230
231export const commentSchema = v.object({
232 id: v.string(),
233 taskId: v.string(),
234 userId: v.string(),
235 content: v.string(),
236 createdAt: v.date(),
237 updatedAt: v.date(),
238 user: v.optional(
239 v.object({
240 name: v.string(),
241 image: v.nullable(v.string()),
242 }),
243 ),
244});
245
246export const configSchema = v.object({
247 disableRegistration: v.nullable(v.boolean()),
248 disablePasswordRegistration: v.nullable(v.boolean()),
249 isDemoMode: v.boolean(),
250 hasSmtp: v.boolean(),
251 hasGithubSignIn: v.nullable(v.boolean()),
252 hasGoogleSignIn: v.nullable(v.boolean()),
253 hasDiscordSignIn: v.nullable(v.boolean()),
254 hasCustomOAuth: v.nullable(v.boolean()),
255 hasGuestAccess: v.nullable(v.boolean()),
256});