dbwatcher 1.1.0 → 1.1.2

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -2
  3. data/app/assets/javascripts/dbwatcher/components/changes_table_hybrid.js +12 -22
  4. data/app/assets/javascripts/dbwatcher/components/dashboard.js +325 -0
  5. data/app/assets/stylesheets/dbwatcher/application.css +394 -41
  6. data/app/assets/stylesheets/dbwatcher/application.scss +4 -0
  7. data/app/assets/stylesheets/dbwatcher/components/_badges.scss +68 -23
  8. data/app/assets/stylesheets/dbwatcher/components/_compact_table.scss +83 -26
  9. data/app/assets/stylesheets/dbwatcher/components/_diagrams.scss +3 -3
  10. data/app/assets/stylesheets/dbwatcher/components/_navigation.scss +9 -0
  11. data/app/assets/stylesheets/dbwatcher/components/_tabulator.scss +248 -0
  12. data/app/assets/stylesheets/dbwatcher/vendor/_tabulator_overrides.scss +37 -0
  13. data/app/controllers/dbwatcher/api/v1/system_info_controller.rb +180 -0
  14. data/app/controllers/dbwatcher/dashboard/system_info_controller.rb +64 -0
  15. data/app/controllers/dbwatcher/dashboard_controller.rb +17 -0
  16. data/app/controllers/dbwatcher/sessions_controller.rb +3 -19
  17. data/app/helpers/dbwatcher/application_helper.rb +43 -11
  18. data/app/helpers/dbwatcher/diagram_helper.rb +0 -88
  19. data/app/views/dbwatcher/dashboard/_layout.html.erb +27 -0
  20. data/app/views/dbwatcher/dashboard/_overview.html.erb +188 -0
  21. data/app/views/dbwatcher/dashboard/_system_info.html.erb +22 -0
  22. data/app/views/dbwatcher/dashboard/_system_info_content.html.erb +389 -0
  23. data/app/views/dbwatcher/dashboard/index.html.erb +8 -177
  24. data/app/views/dbwatcher/sessions/_changes.html.erb +91 -0
  25. data/app/views/dbwatcher/sessions/_layout.html.erb +23 -0
  26. data/app/views/dbwatcher/sessions/index.html.erb +107 -87
  27. data/app/views/dbwatcher/sessions/show.html.erb +10 -4
  28. data/app/views/dbwatcher/tables/index.html.erb +32 -40
  29. data/app/views/layouts/dbwatcher/application.html.erb +100 -48
  30. data/config/routes.rb +23 -6
  31. data/lib/dbwatcher/configuration.rb +18 -1
  32. data/lib/dbwatcher/services/base_service.rb +2 -0
  33. data/lib/dbwatcher/services/diagram_analyzers/model_association_analyzer.rb +177 -138
  34. data/lib/dbwatcher/services/diagram_data/dataset.rb +2 -0
  35. data/lib/dbwatcher/services/mermaid_syntax/class_diagram_builder.rb +13 -9
  36. data/lib/dbwatcher/services/mermaid_syntax/class_diagram_helper.rb +3 -1
  37. data/lib/dbwatcher/services/mermaid_syntax/sanitizer.rb +17 -1
  38. data/lib/dbwatcher/services/system_info/database_info_collector.rb +263 -0
  39. data/lib/dbwatcher/services/system_info/machine_info_collector.rb +387 -0
  40. data/lib/dbwatcher/services/system_info/runtime_info_collector.rb +328 -0
  41. data/lib/dbwatcher/services/system_info/system_info_collector.rb +114 -0
  42. data/lib/dbwatcher/storage/concerns/error_handler.rb +6 -6
  43. data/lib/dbwatcher/storage/session.rb +5 -0
  44. data/lib/dbwatcher/storage/system_info_storage.rb +242 -0
  45. data/lib/dbwatcher/storage.rb +12 -0
  46. data/lib/dbwatcher/version.rb +1 -1
  47. data/lib/dbwatcher.rb +15 -1
  48. metadata +20 -15
  49. data/app/helpers/dbwatcher/component_helper.rb +0 -29
  50. data/app/views/dbwatcher/sessions/_changes_tab.html.erb +0 -265
  51. data/app/views/dbwatcher/sessions/_tab_navigation.html.erb +0 -12
  52. data/app/views/dbwatcher/sessions/changes.html.erb +0 -21
  53. data/app/views/dbwatcher/sessions/components/changes/_filters.html.erb +0 -44
  54. data/app/views/dbwatcher/sessions/components/changes/_table_list.html.erb +0 -96
  55. data/app/views/dbwatcher/sessions/diagrams.html.erb +0 -21
  56. data/app/views/dbwatcher/sessions/shared/_layout.html.erb +0 -8
  57. data/app/views/dbwatcher/sessions/shared/_navigation.html.erb +0 -35
  58. data/app/views/dbwatcher/sessions/shared/_session_header.html.erb +0 -25
  59. data/app/views/dbwatcher/sessions/summary.html.erb +0 -21
  60. /data/app/views/dbwatcher/sessions/{_diagrams_tab.html.erb → _diagrams.html.erb} +0 -0
  61. /data/app/views/dbwatcher/sessions/{_summary_tab.html.erb → _summary.html.erb} +0 -0
@@ -0,0 +1,389 @@
1
+ <% if @system_info&.dig(:error) %>
2
+ <!-- Error State -->
3
+ <div class="bg-red-50 border border-red-200 rounded p-3 mb-3">
4
+ <div class="flex items-center">
5
+ <div class="flex-shrink-0">
6
+ <svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
7
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
8
+ </svg>
9
+ </div>
10
+ <div class="ml-3">
11
+ <h3 class="text-sm font-medium text-red-800">Error Loading System Information</h3>
12
+ <p class="text-sm text-red-700 mt-1"><%= @system_info[:error] %></p>
13
+ </div>
14
+ </div>
15
+ </div>
16
+ <% else %>
17
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-3">
18
+ <!-- Machine Information Section -->
19
+ <div class="border border-gray-200 rounded shadow-sm">
20
+ <div class="bg-gray-50 px-3 py-2 border-b border-gray-200 flex items-center">
21
+ <svg class="h-4 w-4 mr-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
22
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"/>
23
+ </svg>
24
+ <h3 class="text-xs font-medium text-gray-700">Machine Information</h3>
25
+ </div>
26
+ <div class="p-4">
27
+ <% if @system_info&.dig(:machine) %>
28
+ <div class="grid grid-cols-3 gap-4 text-sm">
29
+ <!-- Row 1 -->
30
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
31
+ <div class="flex items-center justify-between">
32
+ <span class="font-medium text-gray-600 text-xs">Hostname</span>
33
+ <div class="h-2 w-2 bg-blue-400 rounded-full"></div>
34
+ </div>
35
+ <div class="text-gray-900 font-semibold mt-1">
36
+ <%= @system_info[:machine][:hostname] || "N/A" %>
37
+ </div>
38
+ </div>
39
+
40
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
41
+ <div class="flex items-center justify-between">
42
+ <span class="font-medium text-gray-600 text-xs">OS</span>
43
+ <div class="h-2 w-2 bg-green-400 rounded-full"></div>
44
+ </div>
45
+ <div class="text-gray-900 font-semibold mt-1">
46
+ <%= @system_info[:machine][:os].is_a?(Hash) ? @system_info[:machine][:os][:name] : @system_info[:machine][:os] || "N/A" %>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
51
+ <div class="flex items-center justify-between">
52
+ <span class="font-medium text-gray-600 text-xs">Architecture</span>
53
+ <div class="h-2 w-2 bg-purple-400 rounded-full"></div>
54
+ </div>
55
+ <div class="text-gray-900 font-semibold mt-1">
56
+ <%= @system_info[:machine][:architecture] || "N/A" %>
57
+ </div>
58
+ </div>
59
+
60
+ <!-- Row 2 -->
61
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
62
+ <div class="flex items-center justify-between">
63
+ <span class="font-medium text-gray-600 text-xs">CPU Cores</span>
64
+ <div class="h-2 w-2 bg-orange-400 rounded-full"></div>
65
+ </div>
66
+ <div class="text-gray-900 font-semibold mt-1">
67
+ <%= @system_info[:machine][:cpu][:cores] || "N/A" %>
68
+ </div>
69
+ </div>
70
+
71
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
72
+ <div class="flex items-center justify-between">
73
+ <span class="font-medium text-gray-600 text-xs">Process ID</span>
74
+ <div class="h-2 w-2 bg-red-400 rounded-full"></div>
75
+ </div>
76
+ <div class="text-gray-900 font-semibold mt-1">
77
+ <%= @system_info[:machine][:process][:pid] || "N/A" %>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
82
+ <div class="flex items-center justify-between">
83
+ <span class="font-medium text-gray-600 text-xs">Load Avg (1m)</span>
84
+ <div class="h-2 w-2 bg-yellow-400 rounded-full"></div>
85
+ </div>
86
+ <div class="text-gray-900 font-semibold mt-1">
87
+ <%
88
+ load_avg = nil
89
+ if @system_info[:machine][:load]
90
+ load_avg = @system_info[:machine][:load][:one_minute]
91
+ elsif @system_info[:machine][:cpu][:load_average].is_a?(Hash)
92
+ load_avg = @system_info[:machine][:cpu][:load_average][:"1min"] ||
93
+ (@system_info[:machine][:cpu][:load_average]["1min"] rescue nil)
94
+ elsif @system_info[:machine][:cpu][:load_average].is_a?(Array) && @system_info[:machine][:cpu][:load_average].size > 0
95
+ load_avg = @system_info[:machine][:cpu][:load_average][0]
96
+ end
97
+ %>
98
+ <%= load_avg || "N/A" %>
99
+ </div>
100
+ </div>
101
+ </div>
102
+
103
+ <!-- Memory Information -->
104
+ <% if @system_info[:machine][:memory] %>
105
+ <div class="mt-3 pt-3 border-t border-gray-100">
106
+ <h4 class="text-xs font-medium text-gray-600 mb-2">Memory Usage</h4>
107
+ <div class="grid grid-cols-4 gap-2">
108
+ <div class="text-center bg-gray-50 rounded p-2">
109
+ <div class="text-sm font-bold text-navy-dark">
110
+ <%= number_to_human_size(@system_info[:machine][:memory][:total] || 0) %>
111
+ </div>
112
+ <div class="text-xs text-gray-500">Total</div>
113
+ </div>
114
+ <div class="text-center bg-orange-50 rounded p-2">
115
+ <div class="text-sm font-bold text-orange-600">
116
+ <%= number_to_human_size(@system_info[:machine][:memory][:used] || 0) %>
117
+ </div>
118
+ <div class="text-xs text-gray-500">Used</div>
119
+ </div>
120
+ <div class="text-center bg-green-50 rounded p-2">
121
+ <div class="text-sm font-bold text-green-600">
122
+ <%= number_to_human_size(@system_info[:machine][:memory][:available] || 0) %>
123
+ </div>
124
+ <div class="text-xs text-gray-500">Available</div>
125
+ </div>
126
+ <div class="text-center bg-blue-50 rounded p-2">
127
+ <div class="text-sm font-bold text-blue-600">
128
+ <%= @system_info[:machine][:memory][:usage_percent] ? "#{@system_info[:machine][:memory][:usage_percent]}%" : "N/A" %>
129
+ </div>
130
+ <div class="text-xs text-gray-500">Usage</div>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ <% end %>
135
+ <% else %>
136
+ <div class="text-center text-gray-500 text-sm py-8">
137
+ <div class="mb-2">
138
+ <svg class="w-8 h-8 mx-auto text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
139
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"/>
140
+ </svg>
141
+ </div>
142
+ Machine information not available
143
+ </div>
144
+ <% end %>
145
+ </div>
146
+ </div>
147
+
148
+ <!-- Database Information Section -->
149
+ <div class="border border-gray-200 rounded shadow-sm">
150
+ <div class="bg-gray-50 px-3 py-2 border-b border-gray-200 flex items-center">
151
+ <svg class="h-4 w-4 mr-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
152
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4"/>
153
+ </svg>
154
+ <h3 class="text-xs font-medium text-gray-700">Database Information</h3>
155
+ </div>
156
+ <div class="p-4">
157
+ <% if @system_info&.dig(:database) && !@system_info[:database].empty? %>
158
+ <div class="grid grid-cols-3 gap-4 text-sm">
159
+ <!-- Row 1 -->
160
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
161
+ <div class="flex items-center justify-between">
162
+ <span class="font-medium text-gray-600 text-xs">Adapter</span>
163
+ <div class="h-2 w-2 bg-blue-400 rounded-full"></div>
164
+ </div>
165
+ <div class="text-gray-900 font-semibold mt-1">
166
+ <% adapter = @system_info[:database][:adapter].is_a?(Hash) ? @system_info[:database][:adapter][:name] : @system_info[:database][:adapter] %>
167
+ <%= adapter || "N/A" %>
168
+ </div>
169
+ </div>
170
+
171
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
172
+ <div class="flex items-center justify-between">
173
+ <span class="font-medium text-gray-600 text-xs">Database</span>
174
+ <div class="h-2 w-2 bg-green-400 rounded-full"></div>
175
+ </div>
176
+ <div class="text-gray-900 font-semibold mt-1">
177
+ <%= @system_info[:database][:database] || "N/A" %>
178
+ </div>
179
+ </div>
180
+
181
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
182
+ <div class="flex items-center justify-between">
183
+ <span class="font-medium text-gray-600 text-xs">Version</span>
184
+ <div class="h-2 w-2 bg-purple-400 rounded-full"></div>
185
+ </div>
186
+ <div class="text-gray-900 font-semibold mt-1">
187
+ <%= @system_info[:database][:version] || "N/A" %>
188
+ </div>
189
+ </div>
190
+
191
+ <!-- Row 2 -->
192
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
193
+ <div class="flex items-center justify-between">
194
+ <span class="font-medium text-gray-600 text-xs">Pool Size</span>
195
+ <div class="h-2 w-2 bg-orange-400 rounded-full"></div>
196
+ </div>
197
+ <div class="text-gray-900 font-semibold mt-1">
198
+ <%= @system_info[:database][:pool_size] || @system_info[:database][:connection_pool]&.[](:size) || "N/A" %>
199
+ </div>
200
+ </div>
201
+
202
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
203
+ <div class="flex items-center justify-between">
204
+ <span class="font-medium text-gray-600 text-xs">Active Connections</span>
205
+ <div class="h-2 w-2 bg-red-400 rounded-full"></div>
206
+ </div>
207
+ <div class="text-gray-900 font-semibold mt-1">
208
+ <% active_conn = @system_info[:database][:active_connections] ||
209
+ @system_info[:database][:connection_pool]&.[](:connections) ||
210
+ @system_info[:database][:connection_pool]&.[](:checked_out) %>
211
+ <%= active_conn || "N/A" %>
212
+ </div>
213
+ </div>
214
+
215
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
216
+ <div class="flex items-center justify-between">
217
+ <span class="font-medium text-gray-600 text-xs">Tables Count</span>
218
+ <div class="h-2 w-2 bg-indigo-400 rounded-full"></div>
219
+ </div>
220
+ <div class="text-gray-900 font-semibold mt-1">
221
+ <%= @system_info[:database][:tables_count] || @system_info[:database][:tables]&.[](:count) || "N/A" %>
222
+ </div>
223
+ </div>
224
+ </div>
225
+ <% else %>
226
+ <div class="text-center text-gray-500 text-sm py-8">
227
+ <div class="mb-2">
228
+ <svg class="w-8 h-8 mx-auto text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
229
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4"/>
230
+ </svg>
231
+ </div>
232
+ Database information not available
233
+ </div>
234
+ <% end %>
235
+ </div>
236
+ </div>
237
+
238
+ <!-- Runtime Information Section -->
239
+ <div class="border border-gray-200 rounded shadow-sm">
240
+ <div class="bg-gray-50 px-3 py-2 border-b border-gray-200 flex items-center">
241
+ <svg class="h-4 w-4 mr-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
242
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
243
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
244
+ </svg>
245
+ <h3 class="text-xs font-medium text-gray-700">Runtime Information</h3>
246
+ </div>
247
+ <div class="p-4">
248
+ <% if @system_info&.dig(:runtime) %>
249
+ <div class="grid grid-cols-3 gap-4 text-sm">
250
+ <!-- Row 1 -->
251
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
252
+ <div class="flex items-center justify-between">
253
+ <span class="font-medium text-gray-600 text-xs">Ruby Version</span>
254
+ <div class="h-2 w-2 bg-red-400 rounded-full"></div>
255
+ </div>
256
+ <div class="text-gray-900 font-semibold mt-1">
257
+ <%= @system_info[:runtime][:ruby_version] || "N/A" %>
258
+ </div>
259
+ </div>
260
+
261
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
262
+ <div class="flex items-center justify-between">
263
+ <span class="font-medium text-gray-600 text-xs">Ruby Engine</span>
264
+ <div class="h-2 w-2 bg-pink-400 rounded-full"></div>
265
+ </div>
266
+ <div class="text-gray-900 font-semibold mt-1">
267
+ <%= @system_info[:runtime][:ruby_engine] || "N/A" %>
268
+ </div>
269
+ </div>
270
+
271
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
272
+ <div class="flex items-center justify-between">
273
+ <span class="font-medium text-gray-600 text-xs">Rails Version</span>
274
+ <div class="h-2 w-2 bg-blue-400 rounded-full"></div>
275
+ </div>
276
+ <div class="text-gray-900 font-semibold mt-1">
277
+ <%= @system_info[:runtime][:rails_version] || "N/A" %>
278
+ </div>
279
+ </div>
280
+
281
+ <!-- Row 2 -->
282
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
283
+ <div class="flex items-center justify-between">
284
+ <span class="font-medium text-gray-600 text-xs">Environment</span>
285
+ <div class="h-2 w-2 bg-green-400 rounded-full"></div>
286
+ </div>
287
+ <div class="text-gray-900 font-semibold mt-1">
288
+ <%= @system_info[:runtime][:environment] || "N/A" %>
289
+ </div>
290
+ </div>
291
+
292
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
293
+ <div class="flex items-center justify-between">
294
+ <span class="font-medium text-gray-600 text-xs">Process ID</span>
295
+ <div class="h-2 w-2 bg-yellow-400 rounded-full"></div>
296
+ </div>
297
+ <div class="text-gray-900 font-semibold mt-1">
298
+ <%= @system_info[:runtime][:pid] || "N/A" %>
299
+ </div>
300
+ </div>
301
+
302
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
303
+ <div class="flex items-center justify-between">
304
+ <span class="font-medium text-gray-600 text-xs">Loaded Gems</span>
305
+ <div class="h-2 w-2 bg-purple-400 rounded-full"></div>
306
+ </div>
307
+ <div class="text-gray-900 font-semibold mt-1">
308
+ <%= @system_info[:runtime][:gem_count] || "N/A" %>
309
+ </div>
310
+ </div>
311
+ </div>
312
+ <% else %>
313
+ <div class="text-center text-gray-500 text-sm py-8">
314
+ <div class="mb-2">
315
+ <svg class="w-8 h-8 mx-auto text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
316
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
317
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
318
+ </svg>
319
+ </div>
320
+ Runtime information not available
321
+ </div>
322
+ <% end %>
323
+ </div>
324
+ </div>
325
+
326
+ <!-- Collection Metadata -->
327
+ <div class="border border-gray-200 rounded shadow-sm">
328
+ <div class="bg-gray-50 px-3 py-2 border-b border-gray-200 flex items-center">
329
+ <svg class="h-4 w-4 mr-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
330
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
331
+ </svg>
332
+ <h3 class="text-xs font-medium text-gray-700">Collection Metadata</h3>
333
+ </div>
334
+ <div class="p-4">
335
+ <div class="grid grid-cols-2 gap-4 text-sm">
336
+ <!-- Row 1 -->
337
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
338
+ <div class="flex items-center justify-between">
339
+ <span class="font-medium text-gray-600 text-xs">Collected At</span>
340
+ <div class="h-2 w-2 bg-blue-400 rounded-full"></div>
341
+ </div>
342
+ <div class="text-gray-900 font-semibold mt-1">
343
+ <% if @system_info&.dig(:collected_at) %>
344
+ <%= Time.parse(@system_info[:collected_at]).strftime("%Y-%m-%d %H:%M:%S") %>
345
+ <% else %>
346
+ N/A
347
+ <% end %>
348
+ </div>
349
+ </div>
350
+
351
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
352
+ <div class="flex items-center justify-between">
353
+ <span class="font-medium text-gray-600 text-xs">Collection Duration</span>
354
+ <div class="h-2 w-2 bg-green-400 rounded-full"></div>
355
+ </div>
356
+ <div class="text-gray-900 font-semibold mt-1">
357
+ <%= @system_info&.dig(:collection_duration) ? "#{@system_info[:collection_duration]}s" : "N/A" %>
358
+ </div>
359
+ </div>
360
+
361
+ <!-- Row 2 -->
362
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
363
+ <div class="flex items-center justify-between">
364
+ <span class="font-medium text-gray-600 text-xs">Cache Age</span>
365
+ <div class="h-2 w-2 bg-orange-400 rounded-full"></div>
366
+ </div>
367
+ <div class="text-gray-900 font-semibold mt-1">
368
+ <%= @info_age ? "#{@info_age.round(2)}s" : "N/A" %>
369
+ </div>
370
+ </div>
371
+
372
+ <div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
373
+ <div class="flex items-center justify-between">
374
+ <span class="font-medium text-gray-600 text-xs">Cache TTL</span>
375
+ <div class="h-2 w-2 bg-purple-400 rounded-full"></div>
376
+ </div>
377
+ <div class="text-gray-900 font-semibold mt-1">
378
+ <% if @system_info&.dig(:application_config, :dbwatcher) %>
379
+ <%= @system_info[:application_config][:dbwatcher][:system_info_cache_duration] || "N/A" %>s
380
+ <% else %>
381
+ N/A
382
+ <% end %>
383
+ </div>
384
+ </div>
385
+ </div>
386
+ </div>
387
+ </div>
388
+ </div>
389
+ <% end %>
@@ -1,177 +1,8 @@
1
- <%# Dashboard Overview Page %>
2
- <div class="h-full flex flex-col">
3
- <!-- Compact Header -->
4
- <div class="h-10 bg-navy-dark text-white flex items-center px-4">
5
- <h1 class="text-sm font-medium">Dashboard</h1>
6
- <span class="ml-auto text-xs text-blue-light">
7
- <%= Time.current.strftime("%Y-%m-%d %H:%M:%S") %>
8
- </span>
9
- </div>
10
-
11
- <!-- Tab Bar -->
12
- <div class="tab-bar">
13
- <div class="tab-item active">Overview</div>
14
- <div class="tab-item">Statistics</div>
15
- <div class="tab-item">Recent Activity</div>
16
- </div>
17
-
18
- <!-- Content Area -->
19
- <div class="flex-1 overflow-auto p-4">
20
- <!-- Compact Stats Grid -->
21
- <div class="grid grid-cols-4 gap-3 mb-4">
22
- <!-- Sessions Card -->
23
- <%= render 'dbwatcher/shared/stats_card',
24
- label: 'Active Sessions',
25
- value: @recent_sessions&.count || 0,
26
- description: 'Last 24 hours',
27
- icon_html: stats_icon(:sessions) %>
28
-
29
- <!-- Tables Card -->
30
- <%= render 'dbwatcher/shared/stats_card',
31
- label: 'Modified Tables',
32
- value: @active_tables&.count || 0,
33
- description: 'With changes',
34
- icon_html: stats_icon(:tables) %>
35
-
36
- <!-- Queries Card -->
37
- <%= render 'dbwatcher/shared/stats_card',
38
- label: 'SQL Queries',
39
- value: @query_stats&.dig(:total) || 0,
40
- description: 'Today',
41
- icon_html: stats_icon(:queries) %>
42
-
43
- <!-- Performance Card -->
44
- <% slow_queries = @query_stats&.dig(:slow_queries) || 0 %>
45
- <%= render 'dbwatcher/shared/stats_card',
46
- label: 'Slow Queries',
47
- value: slow_queries,
48
- value_class: (slow_queries > 0 ? 'text-red-600' : 'text-navy-dark'),
49
- description: '> 100ms',
50
- icon_html: stats_icon(:performance) %>
51
- </div>
52
-
53
- <!-- Two Column Layout -->
54
- <div class="grid grid-cols-2 gap-4">
55
- <!-- Recent Sessions -->
56
- <div class="border border-gray-300 rounded">
57
- <div class="bg-gray-100 px-3 py-2 border-b border-gray-300">
58
- <h3 class="text-xs font-medium text-gray-700">Recent Sessions</h3>
59
- </div>
60
- <div class="max-h-64 overflow-auto">
61
- <% if @recent_sessions&.any? %>
62
- <table class="compact-table w-full">
63
- <thead>
64
- <tr>
65
- <th class="text-left">Session</th>
66
- <th class="text-center">Changes</th>
67
- <th class="text-right">Time</th>
68
- </tr>
69
- </thead>
70
- <tbody>
71
- <% @recent_sessions.each do |session| %>
72
- <tr class="hover:bg-blue-50">
73
- <td class="truncate max-w-xs" title="<%= session[:name] || session['name'] %>">
74
- <% session_id = session[:id] || session['id'] %>
75
- <% session_name = (session[:name] || session['name']).to_s.gsub(/^HTTP \w+ /, '') %>
76
- <%= link_to session_name, session_path(session_id), class: "text-navy-dark hover:text-blue-medium" %>
77
- </td>
78
- <td class="text-center">
79
- <span class="badge bg-gray-600 text-white">
80
- <%= session[:change_count] || session['change_count'] || 0 %>
81
- </span>
82
- </td>
83
- <td class="text-right text-gray-500">
84
- <% started_at = session[:started_at] || session['started_at'] %>
85
- <%= Time.parse(started_at).strftime("%H:%M:%S") rescue 'N/A' %>
86
- </td>
87
- </tr>
88
- <% end %>
89
- </tbody>
90
- </table>
91
- <% else %>
92
- <div class="p-4 text-center text-gray-500 text-xs">No recent sessions</div>
93
- <% end %>
94
- </div>
95
- </div>
96
-
97
- <!-- Active Tables -->
98
- <div class="border border-gray-300 rounded">
99
- <div class="bg-gray-100 px-3 py-2 border-b border-gray-300">
100
- <h3 class="text-xs font-medium text-gray-700">Most Active Tables</h3>
101
- </div>
102
- <div class="max-h-64 overflow-auto">
103
- <% if @active_tables&.any? %>
104
- <table class="compact-table w-full">
105
- <thead>
106
- <tr>
107
- <th class="text-left">Table</th>
108
- <th class="text-center">Operations</th>
109
- <th class="text-right">Changes</th>
110
- </tr>
111
- </thead>
112
- <tbody>
113
- <% @active_tables.first(10).each do |table_name, count| %>
114
- <tr class="hover:bg-blue-50">
115
- <td class="font-medium text-navy-dark">
116
- <%= link_to table_name, table_path(table_name), class: "text-navy-dark hover:text-blue-medium" %>
117
- </td>
118
- <td class="text-center">
119
- <div class="flex gap-1 justify-center">
120
- <span class="badge badge-insert" title="Inserts">I</span>
121
- <span class="badge badge-update" title="Updates">U</span>
122
- <span class="badge badge-delete" title="Deletes">D</span>
123
- </div>
124
- </td>
125
- <td class="text-right">
126
- <span class="text-sm font-medium"><%= count %></span>
127
- </td>
128
- </tr>
129
- <% end %>
130
- </tbody>
131
- </table>
132
- <% else %>
133
- <div class="p-4 text-center text-gray-500 text-xs">No active tables</div>
134
- <% end %>
135
- </div>
136
- </div>
137
- </div>
138
-
139
- <!-- Query Activity Section -->
140
- <div class="mt-4 border border-gray-300 rounded">
141
- <div class="bg-gray-100 px-3 py-2 border-b border-gray-300">
142
- <h3 class="text-xs font-medium text-gray-700">Query Activity</h3>
143
- </div>
144
- <div class="p-4">
145
- <% if @query_stats&.dig(:by_operation)&.any? %>
146
- <div class="grid grid-cols-4 gap-4 text-center">
147
- <% @query_stats[:by_operation].each do |operation, count| %>
148
- <div class="border border-gray-200 rounded p-2">
149
- <div class="text-lg font-bold text-navy-dark"><%= count %></div>
150
- <div class="text-xs text-gray-500 uppercase"><%= operation %></div>
151
- </div>
152
- <% end %>
153
- </div>
154
- <% else %>
155
- <div class="text-center text-gray-500 text-xs">No query activity</div>
156
- <% end %>
157
- </div>
158
- </div>
159
-
160
- <!-- Quick Actions -->
161
- <div class="mt-4 border border-gray-300 rounded">
162
- <div class="bg-gray-100 px-3 py-2 border-b border-gray-300">
163
- <h3 class="text-xs font-medium text-gray-700">Quick Actions</h3>
164
- </div>
165
- <div class="p-3">
166
- <div class="flex gap-2">
167
- <%= link_to "View All Sessions", sessions_path,
168
- class: "px-3 py-1 text-xs bg-blue-600 text-white rounded hover:bg-blue-700" %>
169
- <%= link_to "Browse Tables", tables_path,
170
- class: "px-3 py-1 text-xs bg-green-600 text-white rounded hover:bg-green-700" %>
171
- <%= link_to "SQL Logs", queries_path,
172
- class: "px-3 py-1 text-xs bg-purple-600 text-white rounded hover:bg-purple-700" %>
173
- </div>
174
- </div>
175
- </div>
176
- </div>
177
- </div>
1
+ <%# Dashboard Index Page - Main entry point for the dashboard %>
2
+ <%= render layout: 'layout', locals: { active_tab: @active_tab } do %>
3
+ <% if @active_tab == 'system_info' %>
4
+ <%= render partial: 'system_info' %>
5
+ <% else %>
6
+ <%= render partial: 'overview' %>
7
+ <% end %>
8
+ <% end %>