1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct ClickUpUser {
14 pub id: u64,
15 pub username: String,
16 #[serde(default)]
17 pub email: Option<String>,
18 #[serde(default, rename = "profilePicture")]
19 pub profile_picture: Option<String>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct ClickUpTask {
28 pub id: String,
29 #[serde(default)]
30 pub custom_id: Option<String>,
31 pub name: String,
32 #[serde(default)]
33 pub description: Option<String>,
34 #[serde(default)]
35 pub text_content: Option<String>,
36 pub status: ClickUpStatus,
37 #[serde(default)]
38 pub priority: Option<ClickUpPriority>,
39 #[serde(default)]
40 pub tags: Vec<ClickUpTag>,
41 #[serde(default)]
42 pub assignees: Vec<ClickUpUser>,
43 #[serde(default)]
44 pub creator: Option<ClickUpUser>,
45 pub url: String,
46 #[serde(default)]
47 pub date_created: Option<String>,
48 #[serde(default)]
49 pub date_updated: Option<String>,
50 #[serde(default)]
51 pub parent: Option<String>,
52 #[serde(default)]
53 pub subtasks: Option<Vec<ClickUpTask>>,
54 #[serde(default)]
57 pub dependencies: Option<Vec<serde_json::Value>>,
58 #[serde(default)]
60 pub linked_tasks: Option<Vec<ClickUpLinkedTask>>,
61 #[serde(default)]
66 pub attachments: Vec<ClickUpAttachment>,
67 #[serde(default)]
73 pub custom_fields: Vec<ClickUpCustomField>,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct ClickUpCustomField {
79 pub id: String,
80 #[serde(default)]
81 pub name: Option<String>,
82 #[serde(default, rename = "type")]
85 pub field_type: Option<String>,
86 #[serde(default)]
89 pub value: Option<serde_json::Value>,
90 #[serde(default)]
96 pub type_config: Option<ClickUpFieldTypeConfig>,
97}
98
99#[derive(Debug, Clone, Default, Serialize, Deserialize)]
101pub struct ClickUpFieldTypeConfig {
102 #[serde(default)]
104 pub options: Vec<ClickUpFieldOptionInline>,
105}
106
107#[derive(Debug, Clone, Default, Serialize, Deserialize)]
111pub struct ClickUpFieldOptionInline {
112 #[serde(default)]
113 pub id: Option<String>,
114 #[serde(default, alias = "label")]
115 pub name: Option<String>,
116 #[serde(default)]
117 pub orderindex: Option<u32>,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct ClickUpAttachment {
123 pub id: String,
124 #[serde(default)]
125 pub title: Option<String>,
126 #[serde(default)]
128 pub url: Option<String>,
129 #[serde(default)]
131 pub size: Option<serde_json::Value>,
132 #[serde(default)]
134 pub extension: Option<String>,
135 #[serde(default)]
136 pub mimetype: Option<String>,
137 #[serde(default)]
139 pub date: Option<String>,
140 #[serde(default)]
142 pub user: Option<ClickUpUser>,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct ClickUpStatus {
148 pub status: String,
149 #[serde(default, rename = "type")]
150 pub status_type: Option<String>,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct ClickUpPriority {
156 pub id: String,
157 pub priority: String,
158 #[serde(default)]
159 pub color: Option<String>,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct ClickUpTag {
164 pub name: String,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct ClickUpLinkedTask {
170 pub task_id: String,
171 pub link_id: String,
172 #[serde(default)]
174 pub link_type: Option<String>,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct ClickUpTaskList {
184 pub tasks: Vec<ClickUpTask>,
185}
186
187#[derive(Debug, Clone, Deserialize)]
194pub struct ClickUpTeamsResponse {
195 #[serde(default)]
196 pub teams: Vec<ClickUpTeam>,
197}
198
199#[derive(Debug, Clone, Deserialize)]
200pub struct ClickUpTeam {
201 pub id: String,
202 #[serde(default)]
203 pub members: Vec<ClickUpTeamMember>,
204}
205
206#[derive(Debug, Clone, Deserialize)]
207pub struct ClickUpTeamMember {
208 pub user: ClickUpUser,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct ClickUpComment {
217 pub id: String,
218 pub comment_text: String,
219 #[serde(default)]
220 pub user: Option<ClickUpUser>,
221 #[serde(default)]
222 pub date: Option<String>,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct ClickUpCommentList {
228 pub comments: Vec<ClickUpComment>,
229}
230
231#[derive(Debug, Clone, Deserialize)]
237pub struct ClickUpListStatus {
238 pub status: String,
239 #[serde(default, rename = "type")]
240 pub status_type: Option<String>,
241 #[serde(default)]
242 pub color: Option<String>,
243 #[serde(default)]
244 pub orderindex: Option<u32>,
245}
246
247#[derive(Debug, Clone, Deserialize)]
249pub struct ClickUpListInfo {
250 pub statuses: Vec<ClickUpListStatus>,
251}
252
253#[derive(Debug, Clone, Deserialize)]
255pub struct ClickUpDependencyResponse {
256 #[serde(default)]
257 pub dependency: Option<serde_json::Value>,
258}
259
260#[derive(Debug, Clone, Deserialize)]
262pub struct ClickUpLinkResponse {
263 #[serde(default)]
264 pub link: Option<serde_json::Value>,
265}
266
267#[derive(Debug, Clone, Serialize)]
272pub struct CreateTaskRequest {
273 pub name: String,
274 #[serde(skip_serializing_if = "Option::is_none")]
275 pub description: Option<String>,
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub markdown_content: Option<String>,
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub parent: Option<String>,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub status: Option<String>,
282 #[serde(skip_serializing_if = "Option::is_none")]
283 pub priority: Option<u8>,
284 #[serde(skip_serializing_if = "Option::is_none")]
285 pub tags: Option<Vec<String>>,
286 #[serde(skip_serializing_if = "Option::is_none")]
287 pub assignees: Option<Vec<u64>>,
288}
289
290#[derive(Debug, Clone, Serialize, Default)]
291pub struct UpdateTaskRequest {
292 #[serde(skip_serializing_if = "Option::is_none")]
293 pub name: Option<String>,
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub description: Option<String>,
296 #[serde(skip_serializing_if = "Option::is_none")]
297 pub markdown_content: Option<String>,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub status: Option<String>,
300 #[serde(skip_serializing_if = "Option::is_none")]
301 pub priority: Option<u8>,
302 #[serde(skip_serializing_if = "Option::is_none")]
303 pub parent: Option<String>,
304 #[serde(skip_serializing_if = "Option::is_none")]
305 pub tags: Option<Vec<String>>,
306 #[serde(skip_serializing_if = "Option::is_none")]
311 pub assignees: Option<AssigneeDiff>,
312}
313
314#[derive(Debug, Clone, Default, Serialize)]
317pub struct AssigneeDiff {
318 #[serde(skip_serializing_if = "Vec::is_empty")]
319 pub add: Vec<u64>,
320 #[serde(skip_serializing_if = "Vec::is_empty")]
321 pub rem: Vec<u64>,
322}
323
324#[derive(Debug, Clone, Serialize)]
325pub struct CreateCommentRequest {
326 pub comment_text: String,
331 #[serde(skip_serializing_if = "Vec::is_empty")]
337 pub comment: Vec<crate::comment_format::CommentBlock>,
338}
339
340#[derive(Debug, Clone, Deserialize)]
343pub struct CreateCommentResponse {
344 #[serde(deserialize_with = "value_to_string")]
345 pub id: String,
346 #[serde(default, deserialize_with = "option_value_to_string")]
347 pub date: Option<String>,
348}
349
350fn value_to_string<'de, D>(deserializer: D) -> std::result::Result<String, D::Error>
352where
353 D: serde::Deserializer<'de>,
354{
355 let value = serde_json::Value::deserialize(deserializer)?;
356 match value {
357 serde_json::Value::String(s) => Ok(s),
358 serde_json::Value::Number(n) => Ok(n.to_string()),
359 other => Ok(other.to_string()),
360 }
361}
362
363fn option_value_to_string<'de, D>(deserializer: D) -> std::result::Result<Option<String>, D::Error>
365where
366 D: serde::Deserializer<'de>,
367{
368 let value = Option::<serde_json::Value>::deserialize(deserializer)?;
369 Ok(value.map(|v| match v {
370 serde_json::Value::String(s) => s,
371 serde_json::Value::Number(n) => n.to_string(),
372 other => other.to_string(),
373 }))
374}