Skip to content

Commit 44b8fde

Browse files
authored
Merge pull request #97 from wafflestudio/feature/tauri-ui2
feat(ui): add session statistics and flamechart timeline visualization
2 parents 3ab9b81 + ecfcc82 commit 44b8fde

File tree

14 files changed

+2942
-94
lines changed

14 files changed

+2942
-94
lines changed

src-tauri/src/commands/session.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,20 @@ pub async fn get_session_detail(
120120
tool_operations.len()
121121
);
122122

123+
// Create a map of tool_operation_id -> tool_operation for efficient lookup
124+
log::debug!("Building tool operation lookup map");
125+
let tool_op_by_id: std::collections::HashMap<_, _> = tool_operations
126+
.into_iter()
127+
.map(|op| (op.id, op))
128+
.collect();
129+
123130
// Create a map of message_id -> tool_operation
124-
log::debug!("Building tool operation map");
131+
log::debug!("Building message -> tool operation map");
125132
let mut tool_op_map = std::collections::HashMap::new();
126-
for tool_op in tool_operations {
127-
// Find the message that references this tool operation
128-
for msg in &response.messages {
129-
if msg.tool_operation_id == Some(tool_op.id) {
133+
for msg in &response.messages {
134+
if let Some(tool_op_id) = msg.tool_operation_id {
135+
if let Some(tool_op) = tool_op_by_id.get(&tool_op_id) {
130136
tool_op_map.insert(msg.id, tool_op.clone());
131-
break;
132137
}
133138
}
134139
}
@@ -159,6 +164,8 @@ pub async fn get_session_detail(
159164
timestamp: op.timestamp.to_rfc3339(),
160165
success: op.success,
161166
result_summary: op.result_summary.clone(),
167+
raw_input: op.raw_input.clone(),
168+
raw_result: op.raw_result.clone(),
162169
file_metadata: op.file_metadata.as_ref().map(|fm| FileMetadataItem {
163170
file_path: fm.file_path.clone(),
164171
file_extension: fm.file_extension.clone(),

src-tauri/src/dto.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ pub struct ToolOperationItem {
5151
pub result_summary: Option<String>,
5252
pub file_metadata: Option<FileMetadataItem>,
5353
pub bash_metadata: Option<serde_json::Value>,
54+
pub raw_input: Option<serde_json::Value>,
55+
pub raw_result: Option<serde_json::Value>,
5456
}
5557

5658
#[derive(Debug, Serialize, Deserialize)]

src/parsers/claude_code.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,12 @@ impl ClaudeCodeParser {
265265
}
266266
}
267267

268+
// Skip messages with no meaningful content and no tools
269+
if content == "[No content]" && tool_uses.is_empty() && tool_results.is_empty()
270+
{
271+
continue;
272+
}
273+
268274
let mut message = Message::new(session_id, role, content, timestamp, sequence);
269275

270276
message.id = message_id;

src/parsers/codex.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,11 @@ impl CodexParser {
316316
content.clone()
317317
};
318318

319+
// Skip messages with no meaningful content and no tools
320+
if content == "[No content]" {
321+
continue;
322+
}
323+
319324
// Generate a deterministic UUID for the message
320325
let message_id = self.generate_uuid_from_string(&format!("{session_id}-msg-{index}"));
321326

tests/unit/test_codex_parser.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,8 @@ async fn test_codex_parser_empty_content() -> Result<()> {
150150
assert!(result.is_ok());
151151
let (session, messages) = result.unwrap();
152152

153-
assert_eq!(session.message_count, 1);
154-
// Empty content should be replaced with "[No content]"
155-
assert_eq!(messages[0].content, "[No content]");
153+
// Empty content should be discarded so 0
154+
assert_eq!(session.message_count, 0);
156155

157156
Ok(())
158157
}

ui-react/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@
6060
"input-otp": "1.4.1",
6161
"lucide-react": "^0.553.0",
6262
"next-themes": "^0.4.6",
63+
"plotly.js": "^3.3.0",
6364
"react": "^19.1.1",
6465
"react-day-picker": "9.8.0",
6566
"react-dom": "^19.1.1",
6667
"react-hook-form": "^7.60.0",
6768
"react-hotkeys-hook": "^5.2.1",
6869
"react-markdown": "^10.1.0",
70+
"react-plotly.js": "^2.6.0",
6971
"react-resizable-panels": "^2.1.7",
7072
"recharts": "2.15.4",
7173
"remark-gfm": "^4.0.1",
@@ -79,6 +81,7 @@
7981
"@biomejs/biome": "^2.3.4",
8082
"@eslint/js": "^9.36.0",
8183
"@tailwindcss/postcss": "^4.1.17",
84+
"@types/plotly.js": "^3.0.8",
8285
"@types/react": "^19.1.16",
8386
"@types/react-dom": "^19.1.9",
8487
"@vitejs/plugin-react": "^5.0.4",

0 commit comments

Comments
 (0)