dbwatcher 1.1.1 → 1.1.3

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -2
  3. data/app/assets/config/dbwatcher_manifest.js +1 -0
  4. data/app/assets/javascripts/dbwatcher/components/changes_table_hybrid.js +196 -119
  5. data/app/assets/javascripts/dbwatcher/components/dashboard.js +325 -0
  6. data/app/assets/javascripts/dbwatcher/components/timeline.js +211 -0
  7. data/app/assets/javascripts/dbwatcher/dbwatcher.js +5 -0
  8. data/app/assets/stylesheets/dbwatcher/application.css +691 -41
  9. data/app/assets/stylesheets/dbwatcher/application.scss +5 -0
  10. data/app/assets/stylesheets/dbwatcher/components/_badges.scss +68 -23
  11. data/app/assets/stylesheets/dbwatcher/components/_compact_table.scss +83 -26
  12. data/app/assets/stylesheets/dbwatcher/components/_diagrams.scss +3 -3
  13. data/app/assets/stylesheets/dbwatcher/components/_navigation.scss +9 -0
  14. data/app/assets/stylesheets/dbwatcher/components/_tabulator.scss +248 -0
  15. data/app/assets/stylesheets/dbwatcher/components/_timeline.scss +326 -0
  16. data/app/assets/stylesheets/dbwatcher/vendor/_tabulator_overrides.scss +37 -0
  17. data/app/controllers/dbwatcher/api/v1/sessions_controller.rb +18 -4
  18. data/app/controllers/dbwatcher/api/v1/system_info_controller.rb +180 -0
  19. data/app/controllers/dbwatcher/dashboard/system_info_controller.rb +64 -0
  20. data/app/controllers/dbwatcher/dashboard_controller.rb +17 -0
  21. data/app/controllers/dbwatcher/sessions_controller.rb +3 -19
  22. data/app/helpers/dbwatcher/application_helper.rb +43 -11
  23. data/app/helpers/dbwatcher/diagram_helper.rb +0 -88
  24. data/app/views/dbwatcher/dashboard/_layout.html.erb +27 -0
  25. data/app/views/dbwatcher/dashboard/_overview.html.erb +188 -0
  26. data/app/views/dbwatcher/dashboard/_system_info.html.erb +22 -0
  27. data/app/views/dbwatcher/dashboard/_system_info_content.html.erb +389 -0
  28. data/app/views/dbwatcher/dashboard/index.html.erb +8 -177
  29. data/app/views/dbwatcher/sessions/_layout.html.erb +26 -0
  30. data/app/views/dbwatcher/sessions/{_summary_tab.html.erb → _summary.html.erb} +1 -1
  31. data/app/views/dbwatcher/sessions/_tables.html.erb +170 -0
  32. data/app/views/dbwatcher/sessions/_timeline.html.erb +260 -0
  33. data/app/views/dbwatcher/sessions/index.html.erb +107 -87
  34. data/app/views/dbwatcher/sessions/show.html.erb +12 -4
  35. data/app/views/dbwatcher/tables/index.html.erb +32 -40
  36. data/app/views/layouts/dbwatcher/application.html.erb +101 -48
  37. data/config/routes.rb +25 -7
  38. data/lib/dbwatcher/configuration.rb +18 -1
  39. data/lib/dbwatcher/services/analyzers/table_summary_builder.rb +102 -1
  40. data/lib/dbwatcher/services/api/{changes_data_service.rb → tables_data_service.rb} +6 -6
  41. data/lib/dbwatcher/services/base_service.rb +2 -0
  42. data/lib/dbwatcher/services/system_info/database_info_collector.rb +263 -0
  43. data/lib/dbwatcher/services/system_info/machine_info_collector.rb +387 -0
  44. data/lib/dbwatcher/services/system_info/runtime_info_collector.rb +328 -0
  45. data/lib/dbwatcher/services/system_info/system_info_collector.rb +114 -0
  46. data/lib/dbwatcher/services/timeline_data_service/enhancement_utilities.rb +100 -0
  47. data/lib/dbwatcher/services/timeline_data_service/entry_builder.rb +125 -0
  48. data/lib/dbwatcher/services/timeline_data_service/metadata_builder.rb +93 -0
  49. data/lib/dbwatcher/services/timeline_data_service.rb +130 -0
  50. data/lib/dbwatcher/storage/api/concerns/table_analyzer.rb +1 -1
  51. data/lib/dbwatcher/storage/concerns/error_handler.rb +6 -6
  52. data/lib/dbwatcher/storage/session.rb +5 -0
  53. data/lib/dbwatcher/storage/system_info_storage.rb +242 -0
  54. data/lib/dbwatcher/storage.rb +12 -0
  55. data/lib/dbwatcher/version.rb +1 -1
  56. data/lib/dbwatcher.rb +16 -2
  57. metadata +28 -16
  58. data/app/helpers/dbwatcher/component_helper.rb +0 -29
  59. data/app/views/dbwatcher/sessions/_changes_tab.html.erb +0 -265
  60. data/app/views/dbwatcher/sessions/_tab_navigation.html.erb +0 -12
  61. data/app/views/dbwatcher/sessions/changes.html.erb +0 -21
  62. data/app/views/dbwatcher/sessions/components/changes/_filters.html.erb +0 -44
  63. data/app/views/dbwatcher/sessions/components/changes/_table_list.html.erb +0 -96
  64. data/app/views/dbwatcher/sessions/diagrams.html.erb +0 -21
  65. data/app/views/dbwatcher/sessions/shared/_layout.html.erb +0 -8
  66. data/app/views/dbwatcher/sessions/shared/_navigation.html.erb +0 -35
  67. data/app/views/dbwatcher/sessions/shared/_session_header.html.erb +0 -25
  68. data/app/views/dbwatcher/sessions/summary.html.erb +0 -21
  69. /data/app/views/dbwatcher/sessions/{_diagrams_tab.html.erb → _diagrams.html.erb} +0 -0
@@ -0,0 +1,326 @@
1
+ // Timeline Component Styles
2
+ // Provides styles for the interactive timeline visualization
3
+
4
+ .timeline-container {
5
+ @apply h-full flex flex-col;
6
+ }
7
+
8
+ .timeline-controls {
9
+ @apply p-3 border-b border-gray-300 bg-gray-50;
10
+ }
11
+
12
+ .timeline-header {
13
+ @apply flex items-center justify-between mb-3;
14
+ }
15
+
16
+ .timeline-title {
17
+ @apply text-sm font-medium text-gray-900;
18
+ }
19
+
20
+ .timeline-zoom-controls {
21
+ @apply flex items-center gap-2;
22
+ }
23
+
24
+ .timeline-filter-controls {
25
+ @apply flex items-center gap-4 text-xs flex-wrap;
26
+ }
27
+
28
+ .timeline-filter-group {
29
+ @apply flex items-center gap-2;
30
+ }
31
+
32
+ .timeline-filter-label {
33
+ @apply text-gray-700 font-medium;
34
+ }
35
+
36
+ // Timeline visualization
37
+ .timeline-visualization {
38
+ @apply flex-1 overflow-hidden;
39
+ }
40
+
41
+ .timeline-time-header {
42
+ @apply h-8 bg-gray-100 border-b border-gray-200 relative;
43
+ }
44
+
45
+ .timeline-time-scale {
46
+ @apply absolute inset-0 flex items-center px-4;
47
+ }
48
+
49
+ .timeline-content {
50
+ @apply flex-1 overflow-auto p-4 bg-white;
51
+ }
52
+
53
+ .timeline-track {
54
+ @apply relative h-16 bg-gray-50 rounded border border-gray-200 mb-4;
55
+ }
56
+
57
+ .timeline-line {
58
+ @apply absolute top-1/2 left-4 right-4 h-0.5 bg-gray-300 transform -translate-y-1/2;
59
+ }
60
+
61
+ .timeline-marker {
62
+ @apply absolute top-1/2 transform -translate-y-1/2 -translate-x-1/2 cursor-pointer;
63
+
64
+ .timeline-marker-dot {
65
+ @apply w-3 h-3 rounded-full border-2 border-white shadow-sm transition-transform;
66
+
67
+ &:hover {
68
+ @apply scale-125;
69
+ }
70
+ }
71
+ }
72
+
73
+ // Timeline statistics
74
+ .timeline-stats {
75
+ @apply grid grid-cols-2 gap-4 text-xs;
76
+
77
+ @screen md {
78
+ @apply grid-cols-4;
79
+ }
80
+ }
81
+
82
+ .timeline-stat-card {
83
+ @apply bg-gray-50 p-3 rounded;
84
+ }
85
+
86
+ .timeline-stat-label {
87
+ @apply text-gray-500 font-medium;
88
+ }
89
+
90
+ .timeline-stat-value {
91
+ @apply text-lg font-bold text-gray-900;
92
+ }
93
+
94
+ .timeline-stat-detail {
95
+ @apply text-xs text-gray-500;
96
+ }
97
+
98
+ // Operation list
99
+ .timeline-operations {
100
+ @apply mt-6;
101
+ }
102
+
103
+ .timeline-operations-title {
104
+ @apply text-sm font-medium text-gray-900 mb-3;
105
+ }
106
+
107
+ .timeline-operations-list {
108
+ @apply space-y-2 max-h-64 overflow-auto;
109
+ }
110
+
111
+ .timeline-operation-item {
112
+ @apply flex items-center justify-between p-2 bg-gray-50 rounded hover:bg-gray-100 cursor-pointer text-xs;
113
+ }
114
+
115
+ .timeline-operation-info {
116
+ @apply flex items-center gap-3;
117
+ }
118
+
119
+ .timeline-operation-marker {
120
+ @apply w-2 h-2 rounded-full;
121
+ }
122
+
123
+ .timeline-operation-type {
124
+ @apply font-medium;
125
+ }
126
+
127
+ .timeline-operation-table {
128
+ // No additional styles needed - uses default text
129
+ }
130
+
131
+ .timeline-operation-time {
132
+ @apply text-gray-500;
133
+ }
134
+
135
+ .timeline-operation-record {
136
+ @apply text-gray-500;
137
+ }
138
+
139
+ // Empty state
140
+ .timeline-empty {
141
+ @apply text-center py-8 text-gray-500;
142
+ }
143
+
144
+ .timeline-empty-icon {
145
+ @apply w-12 h-12 mx-auto mb-4 text-gray-300;
146
+ }
147
+
148
+ .timeline-empty-text {
149
+ // No additional styles needed
150
+ }
151
+
152
+ .timeline-empty-action {
153
+ @apply mt-2 text-blue-600 underline;
154
+ }
155
+
156
+ // Loading state
157
+ .timeline-loading {
158
+ @apply flex items-center justify-center h-64;
159
+ }
160
+
161
+ .timeline-loading-spinner {
162
+ @apply animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500;
163
+ }
164
+
165
+ .timeline-loading-text {
166
+ @apply ml-2 text-gray-600;
167
+ }
168
+
169
+ // Error state
170
+ .timeline-error {
171
+ @apply p-4 bg-red-50 border border-red-200 rounded m-4;
172
+ }
173
+
174
+ .timeline-error-text {
175
+ @apply text-red-700;
176
+ }
177
+
178
+ .timeline-error-retry {
179
+ @apply mt-2 text-red-600 underline;
180
+ }
181
+
182
+ // Modal styles
183
+ .timeline-modal-overlay {
184
+ @apply fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50;
185
+ }
186
+
187
+ .timeline-modal-content {
188
+ @apply bg-white rounded-lg shadow-xl max-w-2xl w-full mx-4 max-h-96 overflow-auto;
189
+ }
190
+
191
+ .timeline-modal-header {
192
+ @apply p-4 border-b border-gray-200 flex justify-between items-center;
193
+ }
194
+
195
+ .timeline-modal-title {
196
+ @apply text-lg font-medium;
197
+ }
198
+
199
+ .timeline-modal-close {
200
+ @apply text-gray-400 hover:text-gray-600;
201
+ }
202
+
203
+ .timeline-modal-body {
204
+ @apply p-4;
205
+ }
206
+
207
+ .timeline-operation-details {
208
+ @apply grid grid-cols-1 gap-4 text-sm;
209
+
210
+ @screen md {
211
+ @apply grid-cols-2;
212
+ }
213
+ }
214
+
215
+ .timeline-operation-detail-item {
216
+ // No additional styles needed
217
+ }
218
+
219
+ .timeline-operation-detail-label {
220
+ @apply font-medium;
221
+ }
222
+
223
+ .timeline-operation-detail-value {
224
+ @apply ml-2;
225
+
226
+ &.operation-badge {
227
+ @apply px-2 py-1 rounded text-xs;
228
+ }
229
+
230
+ &.monospace {
231
+ @apply font-mono;
232
+ }
233
+
234
+ &.small {
235
+ @apply text-xs;
236
+ }
237
+ }
238
+
239
+ .timeline-changes-section {
240
+ @apply mt-4;
241
+ }
242
+
243
+ .timeline-changes-title {
244
+ @apply text-sm font-medium;
245
+ }
246
+
247
+ .timeline-changes-content {
248
+ @apply mt-2 p-3 bg-gray-50 rounded text-xs overflow-auto border max-h-32;
249
+ }
250
+
251
+ .timeline-metadata-section {
252
+ @apply mt-4;
253
+ }
254
+
255
+ .timeline-metadata-title {
256
+ @apply text-sm font-medium;
257
+ }
258
+
259
+ .timeline-metadata-grid {
260
+ @apply mt-2 grid grid-cols-2 gap-2 text-xs;
261
+ }
262
+
263
+ .timeline-metadata-item {
264
+ // No additional styles needed for items that are shown
265
+ }
266
+
267
+ .timeline-metadata-key {
268
+ @apply font-medium capitalize;
269
+ }
270
+
271
+ .timeline-metadata-value {
272
+ // No additional styles needed
273
+ }
274
+
275
+ // Responsive adjustments
276
+ @screen sm {
277
+ .timeline-filter-controls {
278
+ @apply flex-nowrap;
279
+ }
280
+
281
+ .timeline-stats {
282
+ @apply grid-cols-4;
283
+ }
284
+ }
285
+
286
+ // Operation color classes
287
+ .operation-insert {
288
+ @apply text-green-600 bg-green-100;
289
+ }
290
+
291
+ .operation-update {
292
+ @apply text-blue-600 bg-blue-100;
293
+ }
294
+
295
+ .operation-delete {
296
+ @apply text-red-600 bg-red-100;
297
+ }
298
+
299
+ .operation-select {
300
+ @apply text-purple-600 bg-purple-100;
301
+ }
302
+
303
+ // Transition classes for Alpine.js
304
+ .timeline-transition-enter {
305
+ @apply transition ease-out duration-300;
306
+ }
307
+
308
+ .timeline-transition-enter-start {
309
+ @apply opacity-0;
310
+ }
311
+
312
+ .timeline-transition-enter-end {
313
+ @apply opacity-100;
314
+ }
315
+
316
+ .timeline-transition-leave {
317
+ @apply transition ease-in duration-200;
318
+ }
319
+
320
+ .timeline-transition-leave-start {
321
+ @apply opacity-100;
322
+ }
323
+
324
+ .timeline-transition-leave-end {
325
+ @apply opacity-0;
326
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Tabulator Vendor Overrides
3
+ * Overrides for the Tabulator.js vendor CSS
4
+ */
5
+
6
+ // Override specific vendor styles that can't be handled in our component CSS
7
+ .tabulator {
8
+ // Force our font settings
9
+ font-family: 'Consolas', 'Monaco', 'Lucida Console', monospace !important;
10
+
11
+ // Ensure proper header styling
12
+ .tabulator-header {
13
+ background: #f3f3f3 !important;
14
+
15
+ .tabulator-col {
16
+ background: #f3f3f3 !important;
17
+ }
18
+ }
19
+
20
+ // Ensure proper row styling
21
+ .tabulator-tableholder .tabulator-table .tabulator-row {
22
+ background: white !important;
23
+
24
+ &:hover {
25
+ background: #f3f4f6 !important;
26
+ }
27
+
28
+ // Ensure proper hover state for sticky cells
29
+ &:hover .tabulator-cell {
30
+ &.sticky-left-0,
31
+ &.sticky-left-1,
32
+ &.sticky-left-2 {
33
+ background: #f9fafb !important;
34
+ }
35
+ }
36
+ }
37
+ }
@@ -6,12 +6,12 @@ module Dbwatcher
6
6
  class SessionsController < BaseController
7
7
  before_action :find_session, except: [:diagram_types]
8
8
 
9
- def changes_data
10
- Rails.logger.info "API::V1::SessionsController#changes_data: Getting changes for session #{@session.id}"
9
+ def tables_data
10
+ Rails.logger.info "API::V1::SessionsController#tables_data: Getting tables for session #{@session.id}"
11
11
 
12
- # Paginated, filtered changes data
12
+ # Paginated, filtered tables data
13
13
  # Convert ActionController::Parameters to a hash before passing to service
14
- service = Dbwatcher::Services::Api::ChangesDataService.new(@session, filter_params.to_h)
14
+ service = Dbwatcher::Services::Api::TablesDataService.new(@session, filter_params.to_h)
15
15
  render json: service.call
16
16
  end
17
17
 
@@ -39,6 +39,20 @@ module Dbwatcher
39
39
  end
40
40
  end
41
41
 
42
+ def timeline_data
43
+ Rails.logger.info "API::V1::SessionsController#timeline_data: Getting timeline for session #{@session.id}"
44
+
45
+ # Timeline data processed from session changes
46
+ service = Dbwatcher::Services::TimelineDataService.new(@session)
47
+ result = service.call
48
+
49
+ if result[:errors].any?
50
+ render json: { error: result[:errors].first[:message] }, status: :unprocessable_entity
51
+ else
52
+ render json: result
53
+ end
54
+ end
55
+
42
56
  def diagram_types
43
57
  Rails.logger.info "API::V1::SessionsController#diagram_types: Getting available diagram types"
44
58
 
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dbwatcher
4
+ module Api
5
+ module V1
6
+ # System information API controller
7
+ #
8
+ # Provides RESTful API endpoints for system information access.
9
+ # Supports JSON responses for programmatic access to system data.
10
+ # rubocop:disable Metrics/ClassLength
11
+ class SystemInfoController < BaseController
12
+ before_action :ensure_system_info_enabled
13
+
14
+ # Get complete system information
15
+ #
16
+ # @return [void]
17
+ def index
18
+ info = system_info_storage.cached_info
19
+
20
+ render json: {
21
+ status: :ok,
22
+ data: info,
23
+ timestamp: Time.current.iso8601,
24
+ cache_age: system_info_storage.info_age&.round(2)
25
+ }
26
+ rescue StandardError => e
27
+ log_error "API: Failed to get system information: #{e.message}"
28
+ render json: { error: e.message }, status: :internal_server_error
29
+ end
30
+
31
+ # Refresh system information
32
+ #
33
+ # @return [void]
34
+ def refresh
35
+ info = system_info_storage.refresh_info
36
+
37
+ render json: {
38
+ status: :ok,
39
+ data: info,
40
+ timestamp: Time.current.iso8601,
41
+ message: "System information refreshed successfully"
42
+ }
43
+ rescue StandardError => e
44
+ log_error "API: Failed to refresh system information: #{e.message}"
45
+ render json: { error: e.message }, status: :internal_server_error
46
+ end
47
+
48
+ # Get machine information only
49
+ #
50
+ # @return [void]
51
+ def machine
52
+ info = system_info_storage.cached_info
53
+
54
+ render json: {
55
+ status: :ok,
56
+ data: info[:machine] || {},
57
+ timestamp: Time.current.iso8601,
58
+ cache_age: system_info_storage.info_age&.round(2)
59
+ }
60
+ rescue StandardError => e
61
+ log_error "API: Failed to get machine information: #{e.message}"
62
+ render json: { error: e.message }, status: :internal_server_error
63
+ end
64
+
65
+ # Get database information only
66
+ #
67
+ # @return [void]
68
+ def database
69
+ info = system_info_storage.cached_info
70
+
71
+ render json: {
72
+ status: :ok,
73
+ data: info[:database] || {},
74
+ timestamp: Time.current.iso8601,
75
+ cache_age: system_info_storage.info_age&.round(2)
76
+ }
77
+ rescue StandardError => e
78
+ log_error "API: Failed to get database information: #{e.message}"
79
+ render json: { error: e.message }, status: :internal_server_error
80
+ end
81
+
82
+ # Get runtime information only
83
+ #
84
+ # @return [void]
85
+ def runtime
86
+ info = system_info_storage.cached_info
87
+
88
+ render json: {
89
+ status: :ok,
90
+ data: info[:runtime] || {},
91
+ timestamp: Time.current.iso8601,
92
+ cache_age: system_info_storage.info_age&.round(2)
93
+ }
94
+ rescue StandardError => e
95
+ log_error "API: Failed to get runtime information: #{e.message}"
96
+ render json: { error: e.message }, status: :internal_server_error
97
+ end
98
+
99
+ # Get system information summary
100
+ #
101
+ # @return [void]
102
+ def summary
103
+ summary_data = system_info_storage.summary
104
+
105
+ render json: {
106
+ status: :ok,
107
+ data: summary_data,
108
+ timestamp: Time.current.iso8601
109
+ }
110
+ rescue StandardError => e
111
+ log_error "API: Failed to get system info summary: #{e.message}"
112
+ render json: { error: e.message }, status: :internal_server_error
113
+ end
114
+
115
+ # Clear system information cache
116
+ #
117
+ # @return [void]
118
+ def clear_cache
119
+ system_info_storage.clear_cache
120
+
121
+ render json: {
122
+ status: :ok,
123
+ message: "System information cache cleared successfully",
124
+ timestamp: Time.current.iso8601
125
+ }
126
+ rescue StandardError => e
127
+ log_error "API: Failed to clear cache: #{e.message}"
128
+ render json: { error: e.message }, status: :internal_server_error
129
+ end
130
+
131
+ # Get cache status and metadata
132
+ #
133
+ # @return [void]
134
+ # rubocop:disable Metrics/MethodLength
135
+ def cache_status
136
+ info_available = system_info_storage.info_available?
137
+ cache_age = system_info_storage.info_age
138
+
139
+ render json: {
140
+ status: :ok,
141
+ data: {
142
+ cache_available: info_available,
143
+ cache_age: cache_age&.round(2),
144
+ cache_expired: cache_age && cache_age > Dbwatcher.configuration.system_info_cache_duration,
145
+ max_cache_age: Dbwatcher.configuration.system_info_cache_duration,
146
+ refresh_interval: Dbwatcher.configuration.system_info_refresh_interval
147
+ },
148
+ timestamp: Time.current.iso8601
149
+ }
150
+ rescue StandardError => e
151
+ log_error "API: Failed to get cache status: #{e.message}"
152
+ render json: { error: e.message }, status: :internal_server_error
153
+ end
154
+ # rubocop:enable Metrics/MethodLength
155
+
156
+ private
157
+
158
+ # Get system info storage instance
159
+ #
160
+ # @return [Storage::SystemInfoStorage] storage instance
161
+ def system_info_storage
162
+ @system_info_storage ||= Storage::SystemInfoStorage.new
163
+ end
164
+
165
+ # Check if system information collection is enabled
166
+ #
167
+ # @return [void]
168
+ def ensure_system_info_enabled
169
+ return if Dbwatcher.configuration.collect_system_info
170
+
171
+ render json: {
172
+ error: "System information collection is disabled",
173
+ status: :forbidden
174
+ }, status: :forbidden
175
+ end
176
+ end
177
+ # rubocop:enable Metrics/ClassLength
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dbwatcher
4
+ module Dashboard
5
+ class SystemInfoController < BaseController
6
+ def refresh
7
+ system_info_storage.refresh_info
8
+
9
+ respond_to do |format|
10
+ format.json do
11
+ render json: refresh_success_response
12
+ end
13
+ end
14
+ rescue StandardError => e
15
+ respond_to do |format|
16
+ format.json do
17
+ render json: { success: false, error: e.message }, status: :internal_server_error
18
+ end
19
+ end
20
+ end
21
+
22
+ def clear_cache
23
+ system_info_storage.clear_cache
24
+
25
+ respond_to do |format|
26
+ format.json do
27
+ render json: clear_cache_success_response
28
+ end
29
+ end
30
+ rescue StandardError => e
31
+ respond_to do |format|
32
+ format.json do
33
+ render json: { success: false, error: e.message }, status: :internal_server_error
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # Get system info storage instance
41
+ #
42
+ # @return [Storage::SystemInfoStorage] storage instance
43
+ def system_info_storage
44
+ @system_info_storage ||= Storage::SystemInfoStorage.new
45
+ end
46
+
47
+ def refresh_success_response
48
+ {
49
+ success: true,
50
+ message: "System information refreshed successfully",
51
+ data: system_info_storage.cached_info,
52
+ summary: system_info_storage.summary
53
+ }
54
+ end
55
+
56
+ def clear_cache_success_response
57
+ {
58
+ success: true,
59
+ message: "System information cache cleared successfully"
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -7,6 +7,14 @@ module Dbwatcher
7
7
  @recent_sessions = dashboard_data[:recent_sessions]
8
8
  @active_tables = dashboard_data[:active_tables]
9
9
  @query_stats = dashboard_data[:query_stats]
10
+ @active_tab = params[:tab] || "overview"
11
+
12
+ # Add system information if enabled
13
+ return unless Dbwatcher.configuration.collect_system_info
14
+
15
+ @system_info_summary = system_info_storage.summary
16
+ @system_info = system_info_storage.cached_info
17
+ @info_age = system_info_storage.info_age
10
18
  end
11
19
 
12
20
  def clear_all
@@ -16,5 +24,14 @@ module Dbwatcher
16
24
  root_path
17
25
  )
18
26
  end
27
+
28
+ private
29
+
30
+ # Get system info storage instance
31
+ #
32
+ # @return [Storage::SystemInfoStorage] storage instance
33
+ def system_info_storage
34
+ @system_info_storage ||= Storage::SystemInfoStorage.new
35
+ end
19
36
  end
20
37
  end
@@ -9,22 +9,9 @@ module Dbwatcher
9
9
  end
10
10
 
11
11
  def show
12
- redirect_to changes_session_path(@session.id)
13
- end
14
-
15
- def changes
16
- Rails.logger.info "SessionsController#changes: Loading changes for session #{@session.id}"
17
- # No server-side data processing - API-first architecture
18
- end
19
-
20
- def summary
21
- Rails.logger.info "SessionsController#summary: Loading summary for session #{@session.id}"
22
- # No server-side data processing - API-first architecture
23
- end
24
-
25
- def diagrams
26
- Rails.logger.info "SessionsController#diagrams: Loading diagrams for session #{@session.id}"
27
- # No server-side data processing - API-first architecture
12
+ @active_tab = params[:tab] || "tables"
13
+ # Debug logging
14
+ Rails.logger.info "SessionsController#show: Session ID: #{@session.id.inspect}, Class: #{@session.class}"
28
15
  end
29
16
 
30
17
  def clear
@@ -41,8 +28,5 @@ module Dbwatcher
41
28
  @session = Storage.sessions.find(params[:id])
42
29
  handle_not_found("Session", sessions_path) unless @session
43
30
  end
44
-
45
- # No longer needed with API-first architecture
46
- # All data processing happens in API services and is loaded via JavaScript
47
31
  end
48
32
  end