code_healer 0.1.14 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f357d294ca82a2aaed146acf5f716b20c3839d2cd64ec72345589a794f5b32eb
4
- data.tar.gz: e4b6fff984ed96c58bf693b5252aa9747e87213cc97e80972a7cd4bbb0c1a488
3
+ metadata.gz: a0eb37a96fca96ae0321a1ee24addb93e3dee8d0755ca5df8934c04420ef3548
4
+ data.tar.gz: b49f5a80ae6cc86b5bc0cd1ccd798a7279ea5d444be32894fb5514599cd13482
5
5
  SHA512:
6
- metadata.gz: 2d5f0ee58ddf888178218cf6f06dfc98ca72548938c452a31acf7fc6e59c7a22041c3c2c08a44e8e8dd28eb8406952211d78219b9ec057679a1d5fb808cf4f0c
7
- data.tar.gz: 63e2cac8eceda44157e6c7afa12fbe4406ca9a5c39994298028662f1752cbf74d1be8aba566950646eeb2f4af0b9d2798e08f8f1931c328e21d9a137e0fb26e5
6
+ metadata.gz: 98e5125e4f561073f31a8f263b5aba7b4ec62dba1d7a9c6b3dca818aa412c5f4578a55ff28dc95dd27768aa86dc61353050c43960ed29d8cc2499790bccef987
7
+ data.tar.gz: 52611005c0b0e47e16e86fb6f0d62ff0aea6a338e42de0b725e5de7a1d77713f3e89494db821d5f06c350283bf6027d629c859a3515e8dcb7cdb0cda113823f7
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.15] - 2025-08-21
9
+
10
+ ### Fixed
11
+ - **Dashboard Template Loading**: Fixed template loading issues by explicitly specifying view paths
12
+ - **Engine Views Configuration**: Properly configured engine views path to resolve template missing errors
13
+ - **Controller Template Rendering**: Updated render calls to use explicit template paths
14
+
15
+ ### Changed
16
+ - **Template Rendering**: Changed from implicit template rendering to explicit template path specification
17
+ - **View Path Configuration**: Enhanced engine configuration for proper view loading
18
+
8
19
  ## [0.1.14] - 2025-08-21
9
20
 
10
21
  ### Added
data/config/routes.rb ADDED
@@ -0,0 +1,16 @@
1
+ CodeHealer::Engine.routes.draw do
2
+ get '/dashboard', to: 'dashboard#index'
3
+ get '/dashboard/metrics', to: 'dashboard#metrics'
4
+ get '/dashboard/trends', to: 'dashboard#trends'
5
+ get '/dashboard/performance', to: 'dashboard#performance'
6
+ get '/dashboard/healing/:healing_id', to: 'dashboard#healing_details'
7
+
8
+ # API endpoints (JSON only)
9
+ namespace :api do
10
+ get '/dashboard/summary', to: 'dashboard#summary'
11
+ get '/dashboard/metrics', to: 'dashboard#metrics'
12
+ get '/dashboard/trends', to: 'dashboard#trends'
13
+ get '/dashboard/performance', to: 'dashboard#performance'
14
+ get '/dashboard/healing/:healing_id', to: 'dashboard#healing_details'
15
+ end
16
+ end
@@ -1,11 +1,14 @@
1
1
  module CodeHealer
2
2
  class DashboardController < ActionController::Base
3
+ # Set the view path to look in the engine's views directory
4
+ self.view_paths = ["#{CodeHealer::Engine.root}/lib/code_healer/views"]
5
+
3
6
  def index
4
7
  @summary = MetricsCollector.dashboard_summary
5
8
  @recent_healings = HealingMetric.order(created_at: :desc).limit(10)
6
9
 
7
10
  respond_to do |format|
8
- format.html { render_dashboard }
11
+ format.html { render template: "dashboard/index" }
9
12
  format.json { render json: @summary }
10
13
  end
11
14
  end
@@ -20,7 +23,7 @@ module CodeHealer
20
23
  @metrics = @metrics.recent(params[:days].to_i) if params[:days].present?
21
24
 
22
25
  respond_to do |format|
23
- format.html { render :metrics }
26
+ format.html { render template: "dashboard/metrics" }
24
27
  format.json { render json: @metrics }
25
28
  end
26
29
  end
@@ -28,22 +31,27 @@ module CodeHealer
28
31
  def healing_details
29
32
  @healing = HealingMetric.find_by(healing_id: params[:healing_id])
30
33
 
31
- if @healing
32
- render json: {
33
- healing: @healing,
34
- timing: {
35
- total_duration: @healing.duration_seconds,
36
- ai_processing: @healing.ai_processing_seconds,
37
- git_operations: @healing.git_operations_seconds
38
- },
39
- status: {
40
- success: @healing.success_status,
41
- evolution_method: @healing.evolution_method_display,
42
- ai_provider: @healing.ai_provider_display
43
- }
44
- }
45
- else
46
- render json: { error: 'Healing not found' }, status: :not_found
34
+ respond_to do |format|
35
+ format.html { render template: "dashboard/healing_details" }
36
+ format.json do
37
+ if @healing
38
+ render json: {
39
+ healing: @healing,
40
+ timing: {
41
+ total_duration: @healing.duration_seconds,
42
+ ai_processing: @healing.ai_processing_seconds,
43
+ git_operations: @healing.git_operations_seconds
44
+ },
45
+ status: {
46
+ success: @healing.success_status,
47
+ evolution_method: @healing.evolution_method_display,
48
+ ai_provider: @healing.ai_provider_display
49
+ }
50
+ }
51
+ else
52
+ render json: { error: 'Healing not found' }, status: :not_found
53
+ end
54
+ end
47
55
  end
48
56
  end
49
57
 
@@ -77,16 +85,5 @@ module CodeHealer
77
85
  def summary
78
86
  render json: MetricsCollector.dashboard_summary
79
87
  end
80
-
81
- private
82
-
83
- def render_dashboard
84
- # This will be replaced with actual dashboard view
85
- render plain: "CodeHealer Dashboard - Coming Soon!\n\n" \
86
- "Total Healings: #{@summary[:total_healing]}\n" \
87
- "Success Rate: #{@summary[:success_rate]}%\n" \
88
- "Healings Today: #{@summary[:healings_today]}\n" \
89
- "Healings This Week: #{@summary[:healings_this_week]}"
90
- end
91
88
  end
92
89
  end
@@ -7,6 +7,11 @@ module CodeHealer
7
7
  app.config.autoload_paths += %W(#{config.root}/lib/code_healer)
8
8
  end
9
9
 
10
+ # Add views path to the main app
11
+ initializer "code_healer.add_views_path" do |app|
12
+ app.config.paths["app/views"] << "#{config.root}/lib/code_healer/views"
13
+ end
14
+
10
15
  # Copy migrations
11
16
  initializer "code_healer.copy_migrations" do |app|
12
17
  if app.root.to_s.match root.to_s
@@ -15,5 +20,12 @@ module CodeHealer
15
20
  end
16
21
  end
17
22
  end
23
+
24
+ # Ensure the engine is properly loaded
25
+ config.autoload_paths += %W(#{config.root}/lib)
26
+ config.eager_load_paths += %W(#{config.root}/lib)
27
+
28
+ # Configure the engine's own paths
29
+ config.paths["app/views"] = ["#{config.root}/lib/code_healer/views"]
18
30
  end
19
31
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CodeHealer
4
- VERSION = "0.1.14"
4
+ VERSION = "0.1.15"
5
5
  end
@@ -0,0 +1,356 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Healing Details - CodeHealer Dashboard</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
16
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
+ min-height: 100vh;
18
+ color: #333;
19
+ }
20
+
21
+ .container {
22
+ max-width: 1200px;
23
+ margin: 0 auto;
24
+ padding: 20px;
25
+ }
26
+
27
+ .header {
28
+ text-align: center;
29
+ margin-bottom: 40px;
30
+ color: white;
31
+ }
32
+
33
+ .header h1 {
34
+ font-size: 2.5rem;
35
+ font-weight: 700;
36
+ margin-bottom: 10px;
37
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
38
+ }
39
+
40
+ .back-link {
41
+ color: white;
42
+ text-decoration: none;
43
+ font-size: 1.1rem;
44
+ opacity: 0.9;
45
+ }
46
+
47
+ .back-link:hover {
48
+ opacity: 1;
49
+ }
50
+
51
+ .healing-card {
52
+ background: white;
53
+ border-radius: 16px;
54
+ padding: 30px;
55
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
56
+ margin-bottom: 30px;
57
+ }
58
+
59
+ .card-title {
60
+ font-size: 1.5rem;
61
+ font-weight: 600;
62
+ margin-bottom: 20px;
63
+ color: #333;
64
+ border-bottom: 2px solid #667eea;
65
+ padding-bottom: 10px;
66
+ }
67
+
68
+ .info-grid {
69
+ display: grid;
70
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
71
+ gap: 20px;
72
+ margin-bottom: 30px;
73
+ }
74
+
75
+ .info-section {
76
+ background: #f8f9fa;
77
+ padding: 20px;
78
+ border-radius: 12px;
79
+ border-left: 4px solid #667eea;
80
+ }
81
+
82
+ .info-section h3 {
83
+ font-size: 1.1rem;
84
+ font-weight: 600;
85
+ margin-bottom: 15px;
86
+ color: #333;
87
+ }
88
+
89
+ .info-item {
90
+ display: flex;
91
+ justify-content: space-between;
92
+ margin-bottom: 10px;
93
+ padding: 8px 0;
94
+ border-bottom: 1px solid #e9ecef;
95
+ }
96
+
97
+ .info-item:last-child {
98
+ border-bottom: none;
99
+ }
100
+
101
+ .info-label {
102
+ font-weight: 500;
103
+ color: #666;
104
+ }
105
+
106
+ .info-value {
107
+ font-weight: 600;
108
+ color: #333;
109
+ }
110
+
111
+ .status-badge {
112
+ padding: 6px 12px;
113
+ border-radius: 20px;
114
+ font-size: 0.8rem;
115
+ font-weight: 500;
116
+ text-transform: uppercase;
117
+ }
118
+
119
+ .status-success {
120
+ background-color: #d4edda;
121
+ color: #155724;
122
+ }
123
+
124
+ .status-failed {
125
+ background-color: #f8d7da;
126
+ color: #721c24;
127
+ }
128
+
129
+ .timing-chart {
130
+ background: #f8f9fa;
131
+ padding: 20px;
132
+ border-radius: 12px;
133
+ margin-top: 20px;
134
+ }
135
+
136
+ .timing-bar {
137
+ display: flex;
138
+ align-items: center;
139
+ margin-bottom: 15px;
140
+ }
141
+
142
+ .timing-label {
143
+ width: 120px;
144
+ font-weight: 500;
145
+ color: #666;
146
+ }
147
+
148
+ .timing-progress {
149
+ flex: 1;
150
+ height: 20px;
151
+ background: #e9ecef;
152
+ border-radius: 10px;
153
+ overflow: hidden;
154
+ margin: 0 15px;
155
+ }
156
+
157
+ .timing-fill {
158
+ height: 100%;
159
+ background: linear-gradient(90deg, #667eea, #764ba2);
160
+ transition: width 0.3s ease;
161
+ }
162
+
163
+ .timing-value {
164
+ width: 80px;
165
+ text-align: right;
166
+ font-weight: 600;
167
+ color: #333;
168
+ }
169
+
170
+ .error-details {
171
+ background: #fff5f5;
172
+ border: 1px solid #fed7d7;
173
+ border-radius: 12px;
174
+ padding: 20px;
175
+ margin-top: 20px;
176
+ }
177
+
178
+ .error-details h3 {
179
+ color: #c53030;
180
+ margin-bottom: 15px;
181
+ }
182
+
183
+ .code-block {
184
+ background: #2d3748;
185
+ color: #e2e8f0;
186
+ padding: 15px;
187
+ border-radius: 8px;
188
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
189
+ font-size: 0.9rem;
190
+ overflow-x: auto;
191
+ margin-top: 10px;
192
+ }
193
+
194
+ @media (max-width: 768px) {
195
+ .info-grid {
196
+ grid-template-columns: 1fr;
197
+ }
198
+
199
+ .header h1 {
200
+ font-size: 2rem;
201
+ }
202
+ }
203
+ </style>
204
+ </head>
205
+ <body>
206
+ <div class="container">
207
+ <div class="header">
208
+ <h1>🏥 Healing Details</h1>
209
+ <a href="/code_healer/dashboard" class="back-link">← Back to Dashboard</a>
210
+ </div>
211
+
212
+ <% if @healing %>
213
+ <div class="healing-card">
214
+ <div class="card-title">Healing Information</div>
215
+
216
+ <div class="info-grid">
217
+ <div class="info-section">
218
+ <h3>Basic Details</h3>
219
+ <div class="info-item">
220
+ <span class="info-label">Healing ID:</span>
221
+ <span class="info-value"><%= @healing.healing_id %></span>
222
+ </div>
223
+ <div class="info-item">
224
+ <span class="info-label">Class:</span>
225
+ <span class="info-value"><%= @healing.class_name %></span>
226
+ </div>
227
+ <div class="info-item">
228
+ <span class="info-label">Method:</span>
229
+ <span class="info-value"><%= @healing.method_name %></span>
230
+ </div>
231
+ <div class="info-item">
232
+ <span class="info-label">Status:</span>
233
+ <span class="status-badge status-<%= @healing.healing_successful ? 'success' : 'failed' %>">
234
+ <%= @healing.healing_successful ? '✅ Success' : '❌ Failed' %>
235
+ </span>
236
+ </div>
237
+ </div>
238
+
239
+ <div class="info-section">
240
+ <h3>AI & Evolution</h3>
241
+ <div class="info-item">
242
+ <span class="info-label">Evolution Method:</span>
243
+ <span class="info-value"><%= @healing.evolution_method_display %></span>
244
+ </div>
245
+ <div class="info-item">
246
+ <span class="info-label">AI Provider:</span>
247
+ <span class="info-value"><%= @healing.ai_provider_display %></span>
248
+ </div>
249
+ <div class="info-item">
250
+ <span class="info-label">AI Success:</span>
251
+ <span class="info-value"><%= @healing.ai_success ? '✅ Yes' : '❌ No' %></span>
252
+ </div>
253
+ <div class="info-item">
254
+ <span class="info-label">Tests Passed:</span>
255
+ <span class="info-value"><%= @healing.tests_passed ? '✅ Yes' : '❌ No' %></span>
256
+ </div>
257
+ </div>
258
+
259
+ <div class="info-section">
260
+ <h3>Timing & Performance</h3>
261
+ <div class="info-item">
262
+ <span class="info-label">Started:</span>
263
+ <span class="info-value"><%= @healing.healing_started_at&.strftime("%Y-%m-%d %H:%M:%S") || 'N/A' %></span>
264
+ </div>
265
+ <div class="info-item">
266
+ <span class="info-label">Completed:</span>
267
+ <span class="info-value"><%= @healing.healing_completed_at&.strftime("%Y-%m-%d %H:%M:%S") || 'N/A' %></span>
268
+ </div>
269
+ <div class="info-item">
270
+ <span class="info-label">Total Duration:</span>
271
+ <span class="info-value"><%= @healing.duration_seconds ? "#{@healing.duration_seconds}s" : 'N/A' %></span>
272
+ </div>
273
+ <div class="info-item">
274
+ <span class="info-label">Syntax Valid:</span>
275
+ <span class="info-value"><%= @healing.syntax_valid ? '✅ Yes' : '❌ No' %></span>
276
+ </div>
277
+ </div>
278
+ </div>
279
+
280
+ <div class="timing-chart">
281
+ <h3>Processing Breakdown</h3>
282
+ <div class="timing-bar">
283
+ <span class="timing-label">AI Processing:</span>
284
+ <div class="timing-progress">
285
+ <div class="timing-fill" style="width: <%= @healing.ai_processing_seconds ? (@healing.ai_processing_seconds / @healing.duration_seconds.to_f * 100).round(1) : 0 %>%"></div>
286
+ </div>
287
+ <span class="timing-value"><%= @healing.ai_processing_seconds ? "#{@healing.ai_processing_seconds}s" : 'N/A' %></span>
288
+ </div>
289
+ <div class="timing-bar">
290
+ <span class="timing-label">Git Operations:</span>
291
+ <div class="timing-progress">
292
+ <div class="timing-fill" style="width: <%= @healing.git_operations_seconds ? (@healing.git_operations_seconds / @healing.duration_seconds.to_f * 100).round(1) : 0 %>%"></div>
293
+ </div>
294
+ <span class="timing-value"><%= @healing.git_operations_seconds ? "#{@healing.git_operations_seconds}s" : 'N/A' %></span>
295
+ </div>
296
+ </div>
297
+
298
+ <% if @healing.error_class.present? %>
299
+ <div class="error-details">
300
+ <h3>Error Information</h3>
301
+ <div class="info-item">
302
+ <span class="info-label">Error Class:</span>
303
+ <span class="info-value"><%= @healing.error_class %></span>
304
+ </div>
305
+ <div class="info-item">
306
+ <span class="info-label">Error Message:</span>
307
+ <span class="info-value"><%= @healing.error_message %></span>
308
+ </div>
309
+ <div class="info-item">
310
+ <span class="info-label">File Path:</span>
311
+ <span class="info-value"><%= @healing.file_path %></span>
312
+ </div>
313
+ <% if @healing.failure_reason.present? %>
314
+ <div class="info-item">
315
+ <span class="info-label">Failure Reason:</span>
316
+ <span class="info-value"><%= @healing.failure_reason %></span>
317
+ </div>
318
+ <% end %>
319
+ </div>
320
+ <% end %>
321
+
322
+ <% if @healing.healing_branch.present? %>
323
+ <div class="info-section">
324
+ <h3>Git Operations</h3>
325
+ <div class="info-item">
326
+ <span class="info-label">Healing Branch:</span>
327
+ <span class="info-value"><%= @healing.healing_branch %></span>
328
+ </div>
329
+ <% if @healing.pull_request_url.present? %>
330
+ <div class="info-item">
331
+ <span class="info-label">Pull Request:</span>
332
+ <span class="info-value">
333
+ <a href="<%= @healing.pull_request_url %>" target="_blank" style="color: #667eea; text-decoration: none;">
334
+ 🔗 View PR
335
+ </a>
336
+ </span>
337
+ </div>
338
+ <% end %>
339
+ <div class="info-item">
340
+ <span class="info-label">PR Created:</span>
341
+ <span class="info-value"><%= @healing.pr_created ? '✅ Yes' : '❌ No' %></span>
342
+ </div>
343
+ </div>
344
+ <% end %>
345
+ </div>
346
+ <% else %>
347
+ <div class="healing-card">
348
+ <div class="error-details">
349
+ <h3>Healing Not Found</h3>
350
+ <p>The requested healing operation could not be found.</p>
351
+ </div>
352
+ </div>
353
+ <% end %>
354
+ </div>
355
+ </body>
356
+ </html>
@@ -1,161 +1,408 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html lang="en">
3
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4
6
  <title>CodeHealer Dashboard</title>
5
7
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
6
8
  <style>
7
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
8
- .container { max-width: 1200px; margin: 0 auto; }
9
- .header { background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
10
- .header h1 { margin: 0; color: #2c3e50; }
11
- .header p { margin: 10px 0 0 0; color: #7f8c8d; }
12
-
13
- .metrics-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 20px; }
14
- .metric-card { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
15
- .metric-card h3 { margin: 0 0 10px 0; color: #2c3e50; font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px; }
16
- .metric-card .value { font-size: 32px; font-weight: bold; color: #3498db; margin: 0; }
17
- .metric-card .label { color: #7f8c8d; font-size: 12px; margin: 5px 0 0 0; }
18
-
19
- .charts-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
20
- .chart-card { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
21
- .chart-card h3 { margin: 0 0 20px 0; color: #2c3e50; }
22
-
23
- .recent-healings { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
24
- .recent-healings h3 { margin: 0 0 20px 0; color: #2c3e50; }
25
- .healing-item { padding: 15px; border-bottom: 1px solid #ecf0f1; }
26
- .healing-item:last-child { border-bottom: none; }
27
- .healing-item .class-method { font-weight: bold; color: #2c3e50; }
28
- .healing-item .error { color: #e74c3c; font-size: 14px; }
29
- .healing-item .status { color: #27ae60; font-size: 12px; }
30
- .healing-item .time { color: #7f8c8d; font-size: 12px; }
31
-
32
- .success { color: #27ae60; }
33
- .warning { color: #f39c12; }
34
- .danger { color: #e74c3c; }
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
17
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
18
+ min-height: 100vh;
19
+ color: #333;
20
+ }
21
+
22
+ .dashboard-container {
23
+ max-width: 1400px;
24
+ margin: 0 auto;
25
+ padding: 20px;
26
+ }
27
+
28
+ .dashboard-header {
29
+ text-align: center;
30
+ margin-bottom: 40px;
31
+ color: white;
32
+ }
33
+
34
+ .dashboard-header h1 {
35
+ font-size: 3rem;
36
+ font-weight: 700;
37
+ margin-bottom: 10px;
38
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
39
+ }
40
+
41
+ .dashboard-header p {
42
+ font-size: 1.2rem;
43
+ opacity: 0.9;
44
+ }
45
+
46
+ .metrics-grid {
47
+ display: grid;
48
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
49
+ gap: 20px;
50
+ margin-bottom: 40px;
51
+ }
52
+
53
+ .metric-card {
54
+ background: white;
55
+ border-radius: 16px;
56
+ padding: 24px;
57
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
58
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
59
+ border: 1px solid rgba(255,255,255,0.2);
60
+ }
61
+
62
+ .metric-card:hover {
63
+ transform: translateY(-5px);
64
+ box-shadow: 0 20px 40px rgba(0,0,0,0.15);
65
+ }
66
+
67
+ .metric-value {
68
+ font-size: 2.5rem;
69
+ font-weight: 700;
70
+ color: #667eea;
71
+ margin-bottom: 8px;
72
+ }
73
+
74
+ .metric-label {
75
+ font-size: 0.9rem;
76
+ color: #666;
77
+ text-transform: uppercase;
78
+ letter-spacing: 0.5px;
79
+ font-weight: 500;
80
+ }
81
+
82
+ .metric-trend {
83
+ font-size: 0.8rem;
84
+ color: #28a745;
85
+ margin-top: 8px;
86
+ }
87
+
88
+ .charts-section {
89
+ display: grid;
90
+ grid-template-columns: 1fr 1fr;
91
+ gap: 30px;
92
+ margin-bottom: 40px;
93
+ }
94
+
95
+ .chart-container {
96
+ background: white;
97
+ border-radius: 16px;
98
+ padding: 24px;
99
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
100
+ }
101
+
102
+ .chart-title {
103
+ font-size: 1.2rem;
104
+ font-weight: 600;
105
+ margin-bottom: 20px;
106
+ color: #333;
107
+ text-align: center;
108
+ }
109
+
110
+ .recent-healings {
111
+ background: white;
112
+ border-radius: 16px;
113
+ padding: 24px;
114
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
115
+ }
116
+
117
+ .section-title {
118
+ font-size: 1.5rem;
119
+ font-weight: 600;
120
+ margin-bottom: 20px;
121
+ color: #333;
122
+ text-align: center;
123
+ }
124
+
125
+ .healing-item {
126
+ display: flex;
127
+ justify-content: space-between;
128
+ align-items: center;
129
+ padding: 16px;
130
+ border-bottom: 1px solid #eee;
131
+ transition: background-color 0.2s ease;
132
+ }
133
+
134
+ .healing-item:hover {
135
+ background-color: #f8f9fa;
136
+ }
137
+
138
+ .healing-item:last-child {
139
+ border-bottom: none;
140
+ }
141
+
142
+ .healing-info h4 {
143
+ font-size: 1rem;
144
+ font-weight: 600;
145
+ color: #333;
146
+ margin-bottom: 4px;
147
+ }
148
+
149
+ .healing-info p {
150
+ font-size: 0.9rem;
151
+ color: #666;
152
+ margin: 0;
153
+ }
154
+
155
+ .healing-status {
156
+ padding: 6px 12px;
157
+ border-radius: 20px;
158
+ font-size: 0.8rem;
159
+ font-weight: 500;
160
+ text-transform: uppercase;
161
+ }
162
+
163
+ .status-success {
164
+ background-color: #d4edda;
165
+ color: #155724;
166
+ }
167
+
168
+ .status-failed {
169
+ background-color: #f8d7da;
170
+ color: #721c24;
171
+ }
172
+
173
+ .status-pending {
174
+ background-color: #fff3cd;
175
+ color: #856404;
176
+ }
177
+
178
+ .view-details-btn {
179
+ background: #667eea;
180
+ color: white;
181
+ padding: 8px 16px;
182
+ border-radius: 20px;
183
+ text-decoration: none;
184
+ font-size: 0.8rem;
185
+ font-weight: 500;
186
+ transition: background-color 0.2s ease;
187
+ }
188
+
189
+ .view-details-btn:hover {
190
+ background: #5a6fd8;
191
+ }
192
+
193
+ @media (max-width: 768px) {
194
+ .charts-section {
195
+ grid-template-columns: 1fr;
196
+ }
197
+
198
+ .dashboard-header h1 {
199
+ font-size: 2rem;
200
+ }
201
+
202
+ .metric-value {
203
+ font-size: 2rem;
204
+ }
205
+ }
206
+
207
+ .loading {
208
+ text-align: center;
209
+ padding: 40px;
210
+ color: #666;
211
+ }
212
+
213
+ .error {
214
+ background: #f8d7da;
215
+ color: #721c24;
216
+ padding: 16px;
217
+ border-radius: 8px;
218
+ margin: 20px 0;
219
+ text-align: center;
220
+ }
35
221
  </style>
36
222
  </head>
37
223
  <body>
38
- <div class="container">
39
- <div class="header">
224
+ <div class="dashboard-container">
225
+ <div class="dashboard-header">
40
226
  <h1>🏥 CodeHealer Dashboard</h1>
41
- <p>Intelligent Code Healing Analytics & Insights</p>
227
+ <p>AI-Powered Code Healing & Self-Repair Analytics</p>
42
228
  </div>
43
-
229
+
44
230
  <div class="metrics-grid">
45
231
  <div class="metric-card">
46
- <h3>Total Healings</h3>
47
- <div class="value"><%= @summary[:total_healings] %></div>
48
- <div class="label">All time</div>
232
+ <div class="metric-value" id="total-healings">-</div>
233
+ <div class="metric-label">Total Healings</div>
234
+ <div class="metric-trend">📈 All time</div>
49
235
  </div>
50
236
 
51
237
  <div class="metric-card">
52
- <h3>Success Rate</h3>
53
- <div class="value <%= @summary[:success_rate] >= 80 ? 'success' : (@summary[:success_rate] >= 60 ? 'warning' : 'danger') %>">
54
- <%= @summary[:success_rate] %>%
55
- </div>
56
- <div class="label">Healing success</div>
238
+ <div class="metric-value" id="success-rate">-</div>
239
+ <div class="metric-label">Success Rate</div>
240
+ <div class="metric-trend">🎯 Performance</div>
57
241
  </div>
58
242
 
59
243
  <div class="metric-card">
60
- <h3>Today</h3>
61
- <div class="value"><%= @summary[:healings_today] %></div>
62
- <div class="label">Healings today</div>
244
+ <div class="metric-value" id="healings-today">-</div>
245
+ <div class="metric-label">Healings Today</div>
246
+ <div class="metric-trend">📅 Daily</div>
63
247
  </div>
64
248
 
65
249
  <div class="metric-card">
66
- <h3>This Week</h3>
67
- <div class="value"><%= @summary[:healings_this_week] %></div>
68
- <div class="label">Healings this week</div>
69
- </div>
70
-
71
- <div class="metric-card">
72
- <h3>This Month</h3>
73
- <div class="value"><%= @summary[:healings_this_month] %></div>
74
- <div class="label">Healings this month</div>
75
- </div>
76
-
77
- <div class="metric-card">
78
- <h3>Avg Resolution</h3>
79
- <div class="value">
80
- <%= @summary[:average_resolution_time] ? "#{(@summary[:average_resolution_time] / 1000.0).round(2)}s" : "N/A" %>
81
- </div>
82
- <div class="label">Average time to fix</div>
250
+ <div class="metric-value" id="avg-resolution">-</div>
251
+ <div class="metric-label">Avg Resolution Time</div>
252
+ <div class="metric-trend">⚡ Speed</div>
83
253
  </div>
84
254
  </div>
85
-
86
- <div class="charts-grid">
87
- <div class="chart-card">
88
- <h3>Daily Healing Trend (Last 7 Days)</h3>
89
- <canvas id="dailyTrendChart"></canvas>
255
+
256
+ <div class="charts-section">
257
+ <div class="chart-container">
258
+ <div class="chart-title">Daily Healing Trend (Last 7 Days)</div>
259
+ <canvas id="dailyTrendChart" width="400" height="200"></canvas>
90
260
  </div>
91
261
 
92
- <div class="chart-card">
93
- <h3>Evolution Method Distribution</h3>
94
- <canvas id="evolutionMethodsChart"></canvas>
262
+ <div class="chart-container">
263
+ <div class="chart-title">Evolution Methods Distribution</div>
264
+ <canvas id="evolutionMethodsChart" width="400" height="200"></canvas>
95
265
  </div>
96
266
  </div>
97
-
267
+
98
268
  <div class="recent-healings">
99
- <h3>Recent Healings</h3>
100
- <% @recent_healings.each do |healing| %>
101
- <div class="healing-item">
102
- <div class="class-method"><%= healing.class_name %>#<%= healing.method_name %></div>
103
- <div class="error"><%= healing.error_class %>: <%= healing.error_message&.truncate(100) %></div>
104
- <div class="status">
105
- <%= healing.success_status %> |
106
- <%= healing.evolution_method_display %> |
107
- <%= healing.ai_provider_display %>
108
- </div>
109
- <div class="time"><%= healing.created_at.strftime("%Y-%m-%d %H:%M:%S") %></div>
110
- </div>
111
- <% end %>
269
+ <div class="section-title">Recent Healing Operations</div>
270
+ <div id="recent-healings-list">
271
+ <div class="loading">Loading recent healings...</div>
272
+ </div>
112
273
  </div>
113
274
  </div>
114
-
275
+
115
276
  <script>
116
- // Daily Trend Chart
117
- const dailyTrendCtx = document.getElementById('dailyTrendChart').getContext('2d');
118
- new Chart(dailyTrendCtx, {
119
- type: 'line',
120
- data: {
121
- labels: <%= raw @summary[:daily_trend].keys.map { |date| Date.parse(date).strftime("%m/%d") }.to_json %>,
122
- datasets: [{
123
- label: 'Healings',
124
- data: <%= raw @summary[:daily_trend].values.to_json %>,
125
- borderColor: '#3498db',
126
- backgroundColor: 'rgba(52, 152, 219, 0.1)',
127
- tension: 0.4
128
- }]
129
- },
130
- options: {
131
- responsive: true,
132
- plugins: {
133
- legend: { display: false }
134
- },
135
- scales: {
136
- y: { beginAtZero: true, ticks: { stepSize: 1 } }
277
+ // Dashboard data loading
278
+ async function loadDashboardData() {
279
+ try {
280
+ const response = await fetch('/code_healer/api/dashboard/summary');
281
+ const data = await response.json();
282
+
283
+ if (response.ok) {
284
+ updateMetrics(data);
285
+ updateCharts(data);
286
+ loadRecentHealings();
287
+ } else {
288
+ throw new Error('Failed to load dashboard data');
137
289
  }
290
+ } catch (error) {
291
+ console.error('Error loading dashboard data:', error);
292
+ document.querySelector('.metrics-grid').innerHTML =
293
+ '<div class="error">Failed to load dashboard data. Please try again later.</div>';
138
294
  }
139
- });
140
-
141
- // Evolution Methods Chart
142
- const evolutionMethodsCtx = document.getElementById('evolutionMethodsChart').getContext('2d');
143
- new Chart(evolutionMethodsCtx, {
144
- type: 'doughnut',
145
- data: {
146
- labels: <%= raw @summary[:evolution_methods].keys.map(&:titleize).to_json %>,
147
- datasets: [{
148
- data: <%= raw @summary[:evolution_methods].values.to_json %>,
149
- backgroundColor: ['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6']
150
- }]
151
- },
152
- options: {
153
- responsive: true,
154
- plugins: {
155
- legend: { position: 'bottom' }
295
+ }
296
+
297
+ function updateMetrics(data) {
298
+ document.getElementById('total-healings').textContent = data.total_healings || 0;
299
+ document.getElementById('success-rate').textContent = `${data.success_rate || 0}%`;
300
+ document.getElementById('healings-today').textContent = data.healings_today || 0;
301
+ document.getElementById('avg-resolution').textContent = `${data.average_resolution_time || 0}ms`;
302
+ }
303
+
304
+ function updateCharts(data) {
305
+ // Daily Trend Chart
306
+ const dailyCtx = document.getElementById('dailyTrendChart').getContext('2d');
307
+ new Chart(dailyCtx, {
308
+ type: 'line',
309
+ data: {
310
+ labels: Object.keys(data.daily_trend || {}),
311
+ datasets: [{
312
+ label: 'Healings',
313
+ data: Object.values(data.daily_trend || {}),
314
+ borderColor: '#667eea',
315
+ backgroundColor: 'rgba(102, 126, 234, 0.1)',
316
+ tension: 0.4,
317
+ fill: true
318
+ }]
319
+ },
320
+ options: {
321
+ responsive: true,
322
+ plugins: {
323
+ legend: {
324
+ display: false
325
+ }
326
+ },
327
+ scales: {
328
+ y: {
329
+ beginAtZero: true,
330
+ ticks: {
331
+ stepSize: 1
332
+ }
333
+ }
334
+ }
335
+ }
336
+ });
337
+
338
+ // Evolution Methods Chart
339
+ const evolutionCtx = document.getElementById('evolutionMethodsChart').getContext('2d');
340
+ new Chart(evolutionCtx, {
341
+ type: 'doughnut',
342
+ data: {
343
+ labels: Object.keys(data.evolution_methods || {}),
344
+ datasets: [{
345
+ data: Object.values(data.evolution_methods || {}),
346
+ backgroundColor: [
347
+ '#667eea',
348
+ '#764ba2',
349
+ '#f093fb',
350
+ '#f5576c',
351
+ '#4facfe',
352
+ '#00f2fe'
353
+ ]
354
+ }]
355
+ },
356
+ options: {
357
+ responsive: true,
358
+ plugins: {
359
+ legend: {
360
+ position: 'bottom'
361
+ }
362
+ }
363
+ }
364
+ });
365
+ }
366
+
367
+ async function loadRecentHealings() {
368
+ try {
369
+ const response = await fetch('/code_healer/api/dashboard/metrics?limit=5');
370
+ const healings = await response.json();
371
+
372
+ const container = document.getElementById('recent-healings-list');
373
+ if (healings && healings.length > 0) {
374
+ container.innerHTML = healings.map(healing => `
375
+ <div class="healing-item">
376
+ <div class="healing-info">
377
+ <h4>${healing.class_name}#${healing.method_name}</h4>
378
+ <p>${healing.error_class}: ${healing.error_message}</p>
379
+ <small>${new Date(healing.created_at).toLocaleString()}</small>
380
+ </div>
381
+ <div style="display: flex; align-items: center; gap: 12px;">
382
+ <div class="healing-status status-${healing.healing_successful ? 'success' : 'failed'}">
383
+ ${healing.healing_successful ? '✅ Success' : '❌ Failed'}
384
+ </div>
385
+ <a href="/code_healer/dashboard/healing/${healing.healing_id}" class="view-details-btn">
386
+ View Details
387
+ </a>
388
+ </div>
389
+ </div>
390
+ `).join('');
391
+ } else {
392
+ container.innerHTML = '<div class="loading">No healing operations found yet.</div>';
156
393
  }
394
+ } catch (error) {
395
+ console.error('Error loading recent healings:', error);
396
+ document.getElementById('recent-healings-list').innerHTML =
397
+ '<div class="error">Failed to load recent healings.</div>';
157
398
  }
158
- });
399
+ }
400
+
401
+ // Initialize dashboard
402
+ document.addEventListener('DOMContentLoaded', loadDashboardData);
403
+
404
+ // Auto-refresh every 30 seconds
405
+ setInterval(loadDashboardData, 30000);
159
406
  </script>
160
407
  </body>
161
408
  </html>
data/lib/code_healer.rb CHANGED
@@ -72,33 +72,11 @@ if defined?(Rails)
72
72
  end
73
73
  end
74
74
 
75
- # Mount the engine to provide dashboard routes
75
+ # Mount the engine to provide dashboard routes and views
76
76
  initializer "code_healer.mount_engine" do |app|
77
77
  app.routes.prepend do
78
78
  mount CodeHealer::Engine => "/code_healer"
79
79
  end
80
80
  end
81
-
82
- # Add dashboard routes directly to the host app
83
- initializer "code_healer.add_dashboard_routes" do |app|
84
- app.routes.prepend do
85
- namespace :code_healer do
86
- get '/dashboard', to: 'dashboard#index'
87
- get '/dashboard/metrics', to: 'dashboard#metrics'
88
- get '/dashboard/trends', to: 'dashboard#trends'
89
- get '/dashboard/performance', to: 'dashboard#performance'
90
- get '/dashboard/healing/:healing_id', to: 'dashboard#healing_details'
91
-
92
- # API endpoints (JSON only)
93
- namespace :api do
94
- get '/dashboard/summary', to: 'dashboard#summary'
95
- get '/dashboard/metrics', to: 'dashboard#metrics'
96
- get '/dashboard/trends', to: 'dashboard#trends'
97
- get '/dashboard/performance', to: 'dashboard#performance'
98
- get '/dashboard/healing/:healing_id', to: 'dashboard#healing_details'
99
- end
100
- end
101
- end
102
- end
103
81
  end
104
82
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code_healer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Deepan Kumar
@@ -350,6 +350,7 @@ files:
350
350
  - README.md
351
351
  - code_healer.gemspec
352
352
  - config/code_healer.yml.example
353
+ - config/routes.rb
353
354
  - docs/INSTALLATION.md
354
355
  - examples/basic_usage.rb
355
356
  - exe/code_healer-setup
@@ -388,6 +389,7 @@ files:
388
389
  - lib/code_healer/terminal_integration.rb
389
390
  - lib/code_healer/usage_analyzer.rb
390
391
  - lib/code_healer/version.rb
392
+ - lib/code_healer/views/dashboard/healing_details.html.erb
391
393
  - lib/code_healer/views/dashboard/index.html.erb
392
394
  - lib/generators/code_healer/install_generator.rb
393
395
  - lib/generators/code_healer/templates/create_healing_metrics.rb