1use chrono::{DateTime, Duration, Local, NaiveDate};
4use serde::Deserialize;
5use serde_with::{DisplayFromStr, DurationSeconds, NoneAsEmptyString, serde_as};
6
7#[derive(Debug)]
9pub struct Project {
10 pub name: String,
12 pub time_logs: Vec<TimeLog>,
14 pub total_spent_time: Duration,
16}
17
18#[serde_as]
20#[derive(Debug, PartialEq, Default, Deserialize)]
21#[serde(rename_all = "camelCase")]
22#[serde(rename = "Nodes")]
23pub struct TimeLog {
24 pub spent_at: DateTime<Local>,
26 #[serde_as(as = "DurationSeconds<i64>")]
28 pub time_spent: Duration,
29 #[serde_as(as = "NoneAsEmptyString")]
32 pub summary: Option<String>,
33 pub user: User,
35 #[serde(flatten)]
37 pub trackable_item: TrackableItem,
38}
39
40#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, Deserialize)]
42pub struct UserNodes {
43 #[serde(rename = "nodes")]
44 pub users: Vec<User>,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Deserialize)]
49pub struct User {
50 pub name: String,
51 pub username: String,
52}
53
54impl std::fmt::Display for User {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 write!(f, "{}", self.name)
57 }
58}
59
60#[derive(Debug, PartialEq, Default, Eq, Hash, PartialOrd, Ord, Clone)]
62pub struct TrackableItem {
63 pub common: TrackableItemFields,
67 pub kind: TrackableItemKind,
69}
70
71#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
74pub enum TrackableItemKind {
75 Issue(Issue),
76 MergeRequest(MergeRequest),
77}
78
79impl Default for TrackableItemKind {
80 fn default() -> Self {
81 Self::Issue(Issue::default())
82 }
83}
84
85impl std::fmt::Display for TrackableItemKind {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 TrackableItemKind::Issue(_) => write!(f, "Issue"),
89 TrackableItemKind::MergeRequest(_) => write!(f, "Merge Request"),
90 }
91 }
92}
93
94#[serde_as]
96#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Default, Deserialize)]
97#[serde(rename_all = "camelCase")]
98pub struct TrackableItemFields {
99 #[serde(rename = "iid")]
101 #[serde_as(as = "DisplayFromStr")]
102 pub id: u32,
103 pub title: String,
105 #[serde_as(as = "DurationSeconds<i64>")]
107 pub time_estimate: Duration,
108 #[serde_as(as = "DurationSeconds<i64>")]
110 pub total_time_spent: Duration,
111 pub assignees: UserNodes,
113 pub milestone: Option<Milestone>,
115 pub labels: Labels,
117}
118
119#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, Deserialize)]
121pub struct Issue {}
122
123#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, Deserialize)]
125pub struct MergeRequest {
126 pub reviewers: UserNodes,
128}
129
130#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, Deserialize)]
132#[serde(rename_all = "camelCase")]
133pub struct Milestone {
134 pub title: String,
136 pub due_date: Option<NaiveDate>,
138}
139
140impl std::fmt::Display for Milestone {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 write!(f, "{}", self.title)
143 }
144}
145
146#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, Deserialize)]
148pub struct Labels {
149 #[serde(rename = "nodes")]
151 pub labels: Vec<Label>,
152}
153
154#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default, Deserialize)]
156pub struct Label {
157 pub title: String,
159}
160
161impl std::fmt::Display for Label {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 write!(f, "{}", self.title)
164 }
165}