intent_engine/dashboard/
models.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Serialize)]
6pub struct ApiResponse<T> {
7 pub data: T,
8}
9
10#[derive(Serialize)]
12pub struct ApiError {
13 pub code: String,
14 pub message: String,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub details: Option<Value>,
17}
18
19#[derive(Deserialize)]
21pub struct CreateTaskRequest {
22 pub name: String,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub spec: Option<String>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub priority: Option<i32>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub parent_id: Option<i64>,
29}
30
31#[derive(Deserialize)]
33pub struct UpdateTaskRequest {
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub name: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub spec: Option<String>,
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub priority: Option<i32>,
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub status: Option<String>,
42}
43
44#[derive(Deserialize)]
46pub struct CreateEventRequest {
47 #[serde(rename = "type")]
48 pub event_type: String,
49 pub data: String,
50}
51
52#[derive(Deserialize)]
54pub struct UpdateEventRequest {
55 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
56 pub event_type: Option<String>,
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub data: Option<String>,
59}
60
61#[derive(Deserialize)]
63pub struct SpawnSubtaskRequest {
64 pub name: String,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub spec: Option<String>,
67}
68
69#[derive(Deserialize)]
71pub struct TaskListQuery {
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub status: Option<String>,
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub parent: Option<String>,
76}
77
78#[derive(Deserialize)]
80pub struct EventListQuery {
81 #[serde(skip_serializing_if = "Option::is_none")]
82 pub event_type: Option<String>,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub since: Option<String>,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub limit: Option<i32>,
87}
88
89#[derive(Deserialize)]
91pub struct SwitchProjectRequest {
92 pub project_path: String,
93}
94
95#[derive(Deserialize)]
97pub struct SearchQuery {
98 pub query: String,
99 #[serde(default = "default_true")]
100 pub include_tasks: bool,
101 #[serde(default = "default_true")]
102 pub include_events: bool,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub limit: Option<i32>,
105}
106
107fn default_true() -> bool {
108 true
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_create_task_request_deserialization() {
117 let json = r#"{"name":"Test Task","spec":"Test spec","priority":1}"#;
118 let req: CreateTaskRequest = serde_json::from_str(json).unwrap();
119 assert_eq!(req.name, "Test Task");
120 assert_eq!(req.spec, Some("Test spec".to_string()));
121 assert_eq!(req.priority, Some(1));
122 }
123
124 #[test]
125 fn test_api_response_serialization() {
126 let response = ApiResponse { data: "test" };
127 let json = serde_json::to_string(&response).unwrap();
128 assert!(json.contains("\"data\""));
129 }
130
131 #[test]
132 fn test_api_error_serialization() {
133 let error = ApiError {
134 code: "TEST_ERROR".to_string(),
135 message: "Test message".to_string(),
136 details: None,
137 };
138 let json = serde_json::to_string(&error).unwrap();
139 assert!(json.contains("TEST_ERROR"));
140 assert!(!json.contains("details"));
141 }
142
143 #[test]
144 fn test_search_query_defaults() {
145 let json = r#"{"query":"test"}"#;
146 let query: SearchQuery = serde_json::from_str(json).unwrap();
147 assert_eq!(query.query, "test");
148 assert!(query.include_tasks);
149 assert!(query.include_events);
150 }
151
152 #[test]
153 fn test_update_task_request_deserialization() {
154 let json = r#"{"name":"Updated","spec":"New spec","status":"done"}"#;
155 let req: UpdateTaskRequest = serde_json::from_str(json).unwrap();
156 assert_eq!(req.name, Some("Updated".to_string()));
157 assert_eq!(req.spec, Some("New spec".to_string()));
158 assert_eq!(req.status, Some("done".to_string()));
159 }
160
161 #[test]
162 fn test_create_event_request_deserialization() {
163 let json = r#"{"type":"decision","data":"Made a decision"}"#;
164 let req: CreateEventRequest = serde_json::from_str(json).unwrap();
165 assert_eq!(req.event_type, "decision");
166 assert_eq!(req.data, "Made a decision");
167 }
168
169 #[test]
170 fn test_update_event_request_deserialization() {
171 let json = r#"{"type":"milestone","data":"Updated data"}"#;
172 let req: UpdateEventRequest = serde_json::from_str(json).unwrap();
173 assert_eq!(req.event_type, Some("milestone".to_string()));
174 assert_eq!(req.data, Some("Updated data".to_string()));
175 }
176
177 #[test]
178 fn test_spawn_subtask_request_deserialization() {
179 let json = r#"{"name":"Subtask","spec":"Subtask spec"}"#;
180 let req: SpawnSubtaskRequest = serde_json::from_str(json).unwrap();
181 assert_eq!(req.name, "Subtask");
182 assert_eq!(req.spec, Some("Subtask spec".to_string()));
183 }
184
185 #[test]
186 fn test_task_list_query_deserialization() {
187 let json = r#"{"status":"doing","parent":"null"}"#;
188 let query: TaskListQuery = serde_json::from_str(json).unwrap();
189 assert_eq!(query.status, Some("doing".to_string()));
190 assert_eq!(query.parent, Some("null".to_string()));
191 }
192
193 #[test]
194 fn test_event_list_query_deserialization() {
195 let json = r#"{"event_type":"decision","since":"7d","limit":10}"#;
196 let query: EventListQuery = serde_json::from_str(json).unwrap();
197 assert_eq!(query.event_type, Some("decision".to_string()));
198 assert_eq!(query.since, Some("7d".to_string()));
199 assert_eq!(query.limit, Some(10));
200 }
201
202 #[test]
203 fn test_switch_project_request_deserialization() {
204 let json = r#"{"project_path":"/path/to/project"}"#;
205 let req: SwitchProjectRequest = serde_json::from_str(json).unwrap();
206 assert_eq!(req.project_path, "/path/to/project");
207 }
208
209 #[test]
210 fn test_api_error_with_details() {
211 let details = serde_json::json!({"field": "name", "issue": "too short"});
212 let error = ApiError {
213 code: "VALIDATION_ERROR".to_string(),
214 message: "Validation failed".to_string(),
215 details: Some(details),
216 };
217 let json = serde_json::to_string(&error).unwrap();
218 assert!(json.contains("VALIDATION_ERROR"));
219 assert!(json.contains("details"));
220 assert!(json.contains("field"));
221 }
222
223 #[test]
224 fn test_search_query_with_overrides() {
225 let json = r#"{"query":"test","include_tasks":false,"include_events":true,"limit":20}"#;
226 let query: SearchQuery = serde_json::from_str(json).unwrap();
227 assert_eq!(query.query, "test");
228 assert!(!query.include_tasks);
229 assert!(query.include_events);
230 assert_eq!(query.limit, Some(20));
231 }
232}