From 304abe653a7e3a72508df82922eb90ac87bf2433 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Tue, 10 Jun 2025 18:13:19 +0800 Subject: [PATCH] feat: optimize HTML report layout and clean up redundant code - Redesign planning section with three-column layout - Improve screenshot display with adaptive sizing - Enhance actions details presentation - Add compact request toggle functionality - Remove unused CSS styles and redundant code - Improve responsive design for mobile devices --- internal/version/VERSION | 2 +- report.go | 467 +++++++++++++++++++++++++-------------- 2 files changed, 306 insertions(+), 163 deletions(-) diff --git a/internal/version/VERSION b/internal/version/VERSION index fd2338ac..33c93ff1 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0-beta-2506101707 +v5.0.0-beta-2506101813 diff --git a/report.go b/report.go index 302ffb5e..d2b3625b 100644 --- a/report.go +++ b/report.go @@ -440,6 +440,9 @@ func (g *HTMLReportGenerator) GenerateReport(outputFile string) error { }, "mul": func(a, b float64) float64 { return a * b }, "add": func(a, b int) int { return a + b }, + "sub": func(a, b int) int { return a - b }, + "lt": func(a, b int) bool { return a < b }, + "gt": func(a, b int) bool { return a > b }, "base": filepath.Base, "index": func(m map[string]any, key string) any { return m[key] }, } @@ -1014,29 +1017,29 @@ const htmlTemplate = ` font-weight: bold; } - .plan-next-action { - margin: 15px 0; - padding: 15px; - background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); - border: 2px solid #dee2e6; - border-radius: 12px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - } - .plan-next-action h5 { - color: #495057; - margin-bottom: 10px; - font-size: 1.0em; - font-weight: 600; - } - .planning-two-columns { + .planning-three-columns { display: flex; gap: 20px; margin: 15px 0; } - .planning-column-left, .planning-column-right { + .planning-column-screenshot { + flex: 0.9; + min-width: 250px; + max-width: 35%; + } + + .planning-column-right-container { + flex: 1.6; + min-width: 350px; + display: flex; + flex-direction: column; + gap: 15px; + } + + .planning-column-model, .planning-column-actions { flex: 1; min-width: 0; } @@ -1046,6 +1049,11 @@ const htmlTemplate = ` border: 1px solid #dee2e6; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); + height: fit-content; + } + + .planning-column-screenshot .planning-step-compact { + height: auto; } .step-header-compact { @@ -1073,29 +1081,200 @@ const htmlTemplate = ` } .screenshot-item-compact .screenshot-image { - min-height: 200px; - padding: 10px 0; + padding: 15px; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 6px; display: flex; justify-content: center; align-items: center; + position: relative; + overflow: hidden; } .screenshot-item-compact .screenshot-image img { - max-width: 100%; - max-height: 180px; + width: 100%; + height: auto; + max-height: 400px; border-radius: 4px; cursor: pointer; transition: transform 0.2s; object-fit: contain; box-shadow: 0 2px 6px rgba(0,0,0,0.1); + display: block; + } + + /* Handle very tall screenshots */ + .screenshot-item-compact .screenshot-image img[style*="height"] { + max-height: 400px; + width: auto; + max-width: 100%; } .screenshot-item-compact .screenshot-image img:hover { transform: scale(1.02); } + .actions-details { + padding: 12px; + max-height: 300px; + overflow-y: auto; + } + + .action-detail-item { + background: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 6px; + padding: 8px; + margin: 6px 0; + font-size: 0.85em; + } + + .action-detail-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 6px; + } + + .action-detail-header .action-name { + background: #6f42c1; + color: white; + padding: 2px 6px; + border-radius: 10px; + font-size: 0.8em; + font-weight: bold; + } + + .action-detail-header .duration { + background: #6c757d; + color: white; + padding: 1px 4px; + border-radius: 8px; + font-size: 0.75em; + } + + .action-detail-header .success { + color: #28a745; + font-size: 0.9em; + } + + .action-detail-header .error { + color: #dc3545; + font-size: 0.9em; + } + + .action-arguments { + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 4px; + padding: 4px 6px; + margin: 4px 0; + font-family: monospace; + font-size: 0.8em; + color: #495057; + word-break: break-all; + } + + .action-requests { + margin-top: 6px; + } + + .requests-toggle-compact { + background: #6c757d; + color: white; + border: none; + padding: 4px 8px; + border-radius: 4px; + cursor: pointer; + font-size: 0.8em; + margin-bottom: 6px; + transition: background-color 0.3s; + display: block; + width: 100%; + text-align: left; + } + + .requests-toggle-compact:hover { + background: #5a6268; + } + + .requests-content-compact { + display: none; + } + + .requests-content-compact.show { + display: block; + } + + .request-item-compact { + background: #ffffff; + border: 1px solid #e9ecef; + border-radius: 4px; + padding: 6px; + margin: 4px 0; + font-size: 0.75em; + } + + .request-header-compact { + display: flex; + align-items: center; + gap: 6px; + margin-bottom: 4px; + flex-wrap: wrap; + } + + .request-header-compact .method { + background: #007bff; + color: white; + padding: 1px 4px; + border-radius: 3px; + font-size: 0.7em; + font-weight: bold; + } + + .url-compact { + color: #495057; + font-family: monospace; + font-size: 0.7em; + word-break: break-all; + flex: 1; + min-width: 0; + } + + .request-header-compact .status.success { + color: #28a745; + font-weight: bold; + font-size: 0.7em; + } + + .request-header-compact .status.failure { + color: #dc3545; + font-weight: bold; + font-size: 0.7em; + } + + .request-header-compact .duration { + background: #6c757d; + color: white; + padding: 1px 4px; + border-radius: 8px; + font-size: 0.7em; + font-weight: 500; + } + + .request-body-compact, .response-body-compact { + background: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 3px; + padding: 4px; + margin: 2px 0; + font-family: monospace; + font-size: 0.7em; + max-height: 60px; + overflow-y: auto; + word-break: break-all; + } + .model-output-compact { padding: 12px; } @@ -1111,10 +1290,31 @@ const htmlTemplate = ` } @media screen and (max-width: 768px) { - .planning-two-columns { + .planning-three-columns { flex-direction: column; gap: 15px; } + + .planning-column-screenshot { + flex: none; + min-width: auto; + max-width: none; + } + + .planning-column-right-container { + flex: none; + min-width: auto; + gap: 10px; + } + + .screenshot-item-compact .screenshot-image { + padding: 10px; + } + + .screenshot-item-compact .screenshot-image img { + width: 100%; + height: auto; + } } .raw-content { @@ -1160,51 +1360,9 @@ const htmlTemplate = ` - .sub-actions { - margin-top: 15px; - padding-left: 20px; - border-left: 3px solid #dee2e6; - } - .sub-action-item { - background: white; - border: 1px solid #e9ecef; - border-radius: 6px; - padding: 12px; - margin-bottom: 10px; - } - .sub-action-content { - display: flex; - gap: 20px; - align-items: flex-start; - } - .sub-action-left { - flex: 1; - min-width: 0; - } - - .sub-action-right { - flex: 1; - min-width: 0; - } - - .sub-action-header { - display: flex; - align-items: center; - gap: 10px; - margin-bottom: 8px; - } - - .action-name { - background: #6f42c1; - color: white; - padding: 2px 8px; - border-radius: 12px; - font-size: 0.8em; - font-weight: bold; - } .thought { background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%); @@ -1353,7 +1511,7 @@ const htmlTemplate = ` overflow-y: auto; } - .sub-action-screenshots, .screenshots-section { + .screenshots-section { background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border: 2px solid #28a745; border-radius: 12px; @@ -1361,7 +1519,7 @@ const htmlTemplate = ` box-shadow: 0 4px 12px rgba(40, 167, 69, 0.15); } - .sub-action-screenshots h5, .screenshots-section h4 { + .screenshots-section h4 { color: #155724; margin-bottom: 10px; font-size: 1.0em; @@ -1859,10 +2017,7 @@ const htmlTemplate = ` gap: 6px; } - .sub-action-content { - flex-direction: column; - gap: 15px; - } + .screenshots-grid { grid-template-columns: 1fr; @@ -2103,14 +2258,10 @@ const htmlTemplate = `
{{$planning.Thought}}
{{end}} - -
-
📋 Planning
- - -
- -
+ +
+ +
📸 Take Screenshot @@ -2132,106 +2283,85 @@ const htmlTemplate = `
- -
-
-
- 🤖 Call Model & Parse Result - {{formatDuration $planning.ModelCallElapsed}} -
-
- {{if $planning.ModelName}} -
🤖 Model: {{$planning.ModelName}}
- {{end}} - {{if $planning.Usage}} -
📊 Tokens: {{$planning.Usage.PromptTokens}} in / {{$planning.Usage.CompletionTokens}} out / {{$planning.Usage.TotalTokens}} total
- {{end}} - {{if $planning.ToolCallsCount}} -
🔧 Tool Calls: {{$planning.ToolCallsCount}}
- {{end}} - {{if $planning.ActionNames}} -
🎯 Actions: {{safeHTML (toJSON $planning.ActionNames)}}
- {{end}} -
-
-
-
-
- - {{if $planning.SubActions}} -
-
🎯 Actions
- {{range $subAction := $planning.SubActions}} -
-
- {{$subAction.ActionName}} - {{formatDuration $subAction.Elapsed}} - {{if $subAction.Error}}Error: {{$subAction.Error}}{{end}} -
- -
-
- {{if $subAction.Arguments}} -
Arguments: {{safeHTML (toJSON $subAction.Arguments)}}
- {{end}} - - {{if $subAction.Requests}} -
- -
- {{range $request := $subAction.Requests}} -
-
- {{$request.RequestMethod}} - {{$request.RequestUrl}} - Status: {{$request.ResponseStatus}} - {{formatDuration $request.ResponseDuration}} -
- {{if $request.RequestBody}} -
Request: {{$request.RequestBody}}
- {{end}} - {{if $request.ResponseBody}} -
Response: {{$request.ResponseBody}}
- {{end}} -
+ +
+ +
+
+
+ 🤖 Call Model & Parse Result + {{formatDuration $planning.ModelCallElapsed}} +
+
+ {{if $planning.ModelName}} +
🤖 Model: {{$planning.ModelName}}
+ {{end}} + {{if $planning.Usage}} +
📊 Tokens: {{$planning.Usage.PromptTokens}} in / {{$planning.Usage.CompletionTokens}} out / {{$planning.Usage.TotalTokens}} total
+ {{end}} + {{if $planning.ToolCallsCount}} +
🔧 Tool Calls: {{$planning.ToolCallsCount}}
+ {{end}} + {{if $planning.ActionNames}} +
🎯 Actions: {{safeHTML (toJSON $planning.ActionNames)}}
{{end}}
- {{end}}
- {{if $subAction.ScreenResults}} -
-
-
📸 Screenshots
-
- {{range $screenshot := $subAction.ScreenResults}} - {{$base64Image := encodeImageBase64 $screenshot.ImagePath}} - {{if $base64Image}} -
-
- {{base $screenshot.ImagePath}} - {{if $screenshot.Resolution}} - {{$screenshot.Resolution.Width}}x{{$screenshot.Resolution.Height}} - {{end}} + + {{if $planning.SubActions}} +
+
+
+ 🎯 Actions ({{len $planning.SubActions}}) +
+
+ {{range $subAction := $planning.SubActions}} +
+
+ {{$subAction.ActionName}} + {{formatDuration $subAction.Elapsed}} + {{if $subAction.Error}}{{else}}{{end}}
-
- Screenshot + {{if $subAction.Arguments}} +
{{safeHTML (toJSON $subAction.Arguments)}}
+ {{end}} + {{if $subAction.Requests}} +
+ +
+ {{range $request := $subAction.Requests}} +
+
+ {{$request.RequestMethod}} + {{$request.RequestUrl}} + {{$request.ResponseStatus}} + {{formatDuration $request.ResponseDuration}} +
+ {{if $request.RequestBody}} +
Request: {{$request.RequestBody}}
+ {{end}} + {{if $request.ResponseBody}} +
Response: {{$request.ResponseBody}}
+ {{end}} +
+ {{end}} +
+ {{end}}
{{end}} - {{end}}
{{end}}
- {{end}} -
- {{end}} + + {{/* SubActions are now displayed in the right panel, so we don't show them here */}}
{{end}}
@@ -2515,6 +2645,19 @@ const htmlTemplate = ` } } + function toggleRequestsCompact(buttonElement) { + const requestsDiv = buttonElement.parentElement; + const requestsContent = requestsDiv.querySelector('.requests-content-compact'); + + if (requestsContent.classList.contains('show')) { + requestsContent.classList.remove('show'); + buttonElement.textContent = buttonElement.textContent.replace('Hide', 'Show'); + } else { + requestsContent.classList.add('show'); + buttonElement.textContent = buttonElement.textContent.replace('Show', 'Hide'); + } + } + function toggleAction(stepIndex, actionIndex) { const content = document.getElementById('action-content-' + stepIndex + '-' + actionIndex); const toggle = document.getElementById('action-toggle-' + stepIndex + '-' + actionIndex);