ai_code_buddy/widget_states/
reports.rs1use crate::core::review::Review;
2use bevy::prelude::*;
3use serde_json;
4
5#[derive(Debug, Clone, Resource)]
6pub struct ReportsWidgetState {
7 pub review: Option<Review>,
8 pub selected_format: ReportFormat,
9 pub export_status: ExportStatus,
10 pub generated_report: Option<String>,
11 pub view_mode: ViewMode,
12}
13
14#[derive(Debug, Clone, PartialEq)]
15pub enum ViewMode {
16 Selection, Report, }
19
20#[derive(Debug, Clone, PartialEq)]
21pub enum ReportFormat {
22 Summary,
23 Detailed,
24 Json,
25 Markdown,
26}
27
28#[derive(Debug, Clone)]
29pub enum ExportStatus {
30 None,
31 Exporting(String), Success(String), }
34
35impl Default for ReportsWidgetState {
36 fn default() -> Self {
37 Self {
38 review: None,
39 selected_format: ReportFormat::Summary,
40 export_status: ExportStatus::None,
41 generated_report: None,
42 view_mode: ViewMode::Selection,
43 }
44 }
45}
46
47impl ReportsWidgetState {
48 pub fn set_review(&mut self, review: Review) {
49 self.review = Some(review);
50 }
51
52 pub fn next_format(&mut self) {
53 self.selected_format = match self.selected_format {
54 ReportFormat::Summary => ReportFormat::Detailed,
55 ReportFormat::Detailed => ReportFormat::Json,
56 ReportFormat::Json => ReportFormat::Markdown,
57 ReportFormat::Markdown => ReportFormat::Summary,
58 };
59 }
60
61 pub fn previous_format(&mut self) {
62 self.selected_format = match self.selected_format {
63 ReportFormat::Summary => ReportFormat::Markdown,
64 ReportFormat::Detailed => ReportFormat::Summary,
65 ReportFormat::Json => ReportFormat::Detailed,
66 ReportFormat::Markdown => ReportFormat::Json,
67 };
68 }
69
70 pub fn start_export(&mut self, format: String) {
71 self.export_status = ExportStatus::Exporting(format);
72 }
73
74 pub fn complete_export(&mut self, path: String) {
75 self.export_status = ExportStatus::Success(path);
76 }
77
78 pub fn generate_report(&mut self) -> Option<String> {
79 if let Some(review) = &self.review {
80 let report_content = match self.selected_format {
81 ReportFormat::Summary => self.generate_summary_report(review),
82 ReportFormat::Detailed => self.generate_detailed_report(review),
83 ReportFormat::Json => self.generate_json_report(review),
84 ReportFormat::Markdown => self.generate_markdown_report(review),
85 };
86 self.generated_report = Some(report_content.clone());
87 self.view_mode = ViewMode::Report;
88 Some(report_content)
89 } else {
90 None
91 }
92 }
93
94 pub fn back_to_selection(&mut self) {
95 self.view_mode = ViewMode::Selection;
96 }
97
98 fn generate_summary_report(&self, review: &Review) -> String {
99 format!(
100 "š¤ AI Code Review Summary\n\
101 ========================\n\n\
102 š Analysis Results:\n\
103 ⢠Files analyzed: {}\n\
104 ⢠Total issues found: {}\n\n\
105 šØ Issue Breakdown:\n\
106 ⢠Critical: {} issues\n\
107 ⢠High: {} issues\n\
108 ⢠Medium: {} issues\n\
109 ⢠Low: {} issues\n\n\
110 š Recommendations:\n\
111 {} Focus on addressing Critical and High severity issues first.\n\
112 {} Review Medium issues for code quality improvements.\n\
113 {} Low severity issues can be addressed as time permits.\n\n\
114 šÆ Next Steps:\n\
115 1. Review each Critical issue immediately\n\
116 2. Plan fixes for High severity issues\n\
117 3. Consider Medium issues for future iterations\n\
118 4. Use the detailed report for specific guidance",
119 review.files_count,
120 review.issues_count,
121 review.critical_issues,
122 review.high_issues,
123 review.medium_issues,
124 review.low_issues,
125 if review.critical_issues > 0 {
126 "ā ļø"
127 } else {
128 "ā
"
129 },
130 if review.medium_issues > 0 {
131 "š"
132 } else {
133 "ā
"
134 },
135 if review.low_issues > 0 { "š”" } else { "ā
" }
136 )
137 }
138
139 fn generate_detailed_report(&self, review: &Review) -> String {
140 let mut report = format!(
141 "š¤ AI Code Review - Detailed Report\n\
142 ===================================\n\n\
143 š Overview:\n\
144 ⢠Repository analyzed\n\
145 ⢠Files processed: {}\n\
146 ⢠Total issues: {}\n\n",
147 review.files_count, review.issues_count
148 );
149
150 if review.issues.is_empty() {
151 report.push_str("š No issues found! Your code looks great!\n");
152 return report;
153 }
154
155 let mut critical_issues = Vec::new();
157 let mut high_issues = Vec::new();
158 let mut medium_issues = Vec::new();
159 let mut low_issues = Vec::new();
160
161 for issue in &review.issues {
162 match issue.severity.as_str() {
163 "Critical" => critical_issues.push(issue),
164 "High" => high_issues.push(issue),
165 "Medium" => medium_issues.push(issue),
166 "Low" => low_issues.push(issue),
167 _ => low_issues.push(issue),
168 }
169 }
170
171 if !critical_issues.is_empty() {
173 report.push_str("šØ CRITICAL ISSUES (Immediate Action Required):\n");
174 report.push_str("=====================================================\n\n");
175 for (i, issue) in critical_issues.iter().enumerate() {
176 report.push_str(&format!(
177 "{}. File: {}\n Line: {}\n Category: {}\n Issue: {}\n\n",
178 i + 1,
179 issue.file,
180 issue.line,
181 issue.category,
182 issue.description
183 ));
184 }
185 }
186
187 if !high_issues.is_empty() {
189 report.push_str("ā ļø HIGH PRIORITY ISSUES:\n");
190 report.push_str("=========================\n\n");
191 for (i, issue) in high_issues.iter().enumerate() {
192 report.push_str(&format!(
193 "{}. File: {}\n Line: {}\n Category: {}\n Issue: {}\n\n",
194 i + 1,
195 issue.file,
196 issue.line,
197 issue.category,
198 issue.description
199 ));
200 }
201 }
202
203 if !medium_issues.is_empty() {
205 report.push_str("š¶ MEDIUM PRIORITY ISSUES:\n");
206 report.push_str("==========================\n\n");
207 for (i, issue) in medium_issues.iter().enumerate() {
208 report.push_str(&format!(
209 "{}. File: {}\n Line: {}\n Category: {}\n Issue: {}\n\n",
210 i + 1,
211 issue.file,
212 issue.line,
213 issue.category,
214 issue.description
215 ));
216 }
217 }
218
219 if !low_issues.is_empty() {
221 report.push_str("ā¹ļø LOW PRIORITY ISSUES:\n");
222 report.push_str("========================\n\n");
223 for (i, issue) in low_issues.iter().enumerate() {
224 report.push_str(&format!(
225 "{}. File: {}\n Line: {}\n Category: {}\n Issue: {}\n\n",
226 i + 1,
227 issue.file,
228 issue.line,
229 issue.category,
230 issue.description
231 ));
232 }
233 }
234
235 report.push_str("\nš End of Report\n");
236 report
237 }
238
239 fn generate_json_report(&self, review: &Review) -> String {
240 match serde_json::to_string_pretty(review) {
242 Ok(json) => json,
243 Err(_) => "Error generating JSON report".to_string(),
244 }
245 }
246
247 fn generate_markdown_report(&self, review: &Review) -> String {
248 let mut report = format!(
249 "# š¤ AI Code Review Report\n\n\
250 ## š Summary\n\n\
251 - **Files analyzed:** {}\n\
252 - **Total issues:** {}\n\
253 - **Critical issues:** {}\n\
254 - **High priority:** {}\n\
255 - **Medium priority:** {}\n\
256 - **Low priority:** {}\n\n",
257 review.files_count,
258 review.issues_count,
259 review.critical_issues,
260 review.high_issues,
261 review.medium_issues,
262 review.low_issues
263 );
264
265 if review.issues.is_empty() {
266 report.push_str("## š Results\n\nNo issues found! Your code looks great!\n");
267 return report;
268 }
269
270 report.push_str("## š Issues by Severity\n\n");
271
272 for severity in ["Critical", "High", "Medium", "Low"] {
274 let severity_issues: Vec<_> = review
275 .issues
276 .iter()
277 .filter(|issue| issue.severity == severity)
278 .collect();
279
280 if !severity_issues.is_empty() {
281 let icon = match severity {
282 "Critical" => "šØ",
283 "High" => "ā ļø",
284 "Medium" => "š¶",
285 "Low" => "ā¹ļø",
286 _ => "š",
287 };
288
289 report.push_str(&format!("### {icon} {severity} Priority Issues\n\n"));
290
291 for issue in severity_issues {
292 report.push_str(&format!(
293 "- **File:** `{}`\n **Line:** {}\n **Category:** {}\n **Issue:** {}\n\n",
294 issue.file, issue.line, issue.category, issue.description
295 ));
296 }
297 }
298 }
299
300 report.push_str("---\n\n*Report generated by AI Code Buddy*\n");
301 report
302 }
303}