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
@@ -12,6 +12,7 @@
12
12
  border-spacing: 0;
13
13
  }
14
14
 
15
+ /* Header styles */
15
16
  .compact-table th {
16
17
  padding: 4px 8px;
17
18
  font-weight: 500;
@@ -27,6 +28,18 @@
27
28
  height: 32px;
28
29
  }
29
30
 
31
+ /* Cell styles */
32
+ .compact-table td {
33
+ padding: 2px 8px;
34
+ border-right: 1px solid var(--border-light);
35
+ border-bottom: 1px solid var(--border-light);
36
+ overflow: hidden;
37
+ text-overflow: ellipsis;
38
+ white-space: nowrap;
39
+ vertical-align: top;
40
+ }
41
+
42
+ /* Sticky columns */
30
43
  /* Enhanced sticky header styling */
31
44
  .compact-table th.sticky-left-0 {
32
45
  position: sticky;
@@ -49,16 +62,6 @@
49
62
  box-shadow: 2px 0px 3px rgba(0,0,0,0.05);
50
63
  }
51
64
 
52
- .compact-table td {
53
- padding: 2px 8px;
54
- border-right: 1px solid var(--border-light);
55
- border-bottom: 1px solid var(--border-light);
56
- overflow: hidden;
57
- text-overflow: ellipsis;
58
- white-space: nowrap;
59
- vertical-align: top;
60
- }
61
-
62
65
  /* Enhanced sticky cell styling */
63
66
  .compact-table td.sticky-left-0 {
64
67
  position: sticky;
@@ -84,19 +87,6 @@
84
87
  box-shadow: 2px 0px 3px rgba(0,0,0,0.05);
85
88
  }
86
89
 
87
- /* Special cell formatting */
88
- .compact-table td.highlight-change {
89
- background-color: var(--highlight-change);
90
- }
91
-
92
- .compact-table td.highlight-new {
93
- color: #047857;
94
- }
95
-
96
- .compact-table td.highlight-deleted {
97
- color: #b91c1c;
98
- }
99
-
100
90
  /* Row styles */
101
91
  .compact-table tr:hover td:not(.sticky-left-0):not(.sticky-left-1):not(.sticky-left-2) {
102
92
  background-color: rgba(243, 244, 246, 0.7);
@@ -118,7 +108,7 @@
118
108
  background-color: #e6f3ff;
119
109
  }
120
110
 
121
- /* Smart column width distribution */
111
+ /* Text overflow handling */
122
112
  .compact-table th,
123
113
  .compact-table td {
124
114
  overflow: hidden;
@@ -126,7 +116,7 @@
126
116
  white-space: nowrap;
127
117
  }
128
118
 
129
- /* Fixed widths for sticky columns only */
119
+ /* Fixed widths for common columns */
130
120
  .compact-table th:first-child,
131
121
  .compact-table td:first-child {
132
122
  width: 60px;
@@ -151,12 +141,79 @@
151
141
  font-size: 11px;
152
142
  }
153
143
 
144
+ /* Sessions table specific overrides */
145
+ .sessions-table th:nth-child(2),
146
+ .sessions-table td:nth-child(2) {
147
+ width: 22%;
148
+ min-width: 160px;
149
+ max-width: 260px;
150
+ text-align: left;
151
+ padding-left: 16px;
152
+ }
153
+
154
+ /* Enhanced sessions table styling */
155
+ .sessions-table tr {
156
+ border-bottom: 1px solid var(--border-light);
157
+ transition: all 0.15s ease;
158
+ }
159
+
160
+ .sessions-table tr:hover {
161
+ background-color: rgba(230, 243, 255, 0.5);
162
+ }
163
+
164
+ .sessions-table td {
165
+ padding: 6px 8px;
166
+ vertical-align: middle;
167
+ }
168
+
169
+ .sessions-table td:first-child .font-mono {
170
+ color: var(--navy-dark);
171
+ font-weight: 500;
172
+ background: var(--gray-50);
173
+ padding: 2px 4px;
174
+ border-radius: 3px;
175
+ border: 1px solid var(--border-medium);
176
+ display: inline-block;
177
+ }
178
+
179
+ .sessions-table .badge {
180
+ min-width: 60px;
181
+ width: auto;
182
+ height: auto;
183
+ padding: 2px 8px;
184
+ }
185
+
186
+ .sessions-table .actions-cell {
187
+ width: 80px;
188
+ }
189
+
190
+ .sessions-table .actions-cell .compact-button {
191
+ transition: transform 0.15s ease, background-color 0.15s ease;
192
+ }
193
+
194
+ .sessions-table .actions-cell .compact-button:hover {
195
+ transform: translateY(-1px);
196
+ }
197
+
154
198
  /* Font styling for specific column types */
155
199
  .compact-table .text-right {
156
200
  font-family: monospace;
157
201
  }
158
202
 
203
+ /* Special cell formatting */
204
+ .compact-table td.highlight-change {
205
+ background-color: var(--highlight-change);
206
+ }
207
+
208
+ .compact-table td.highlight-new {
209
+ color: #047857;
210
+ }
211
+
212
+ .compact-table td.highlight-deleted {
213
+ color: #b91c1c;
214
+ }
215
+
159
216
  /* Highlight colors */
160
217
  .highlight-change { background: var(--highlight-change); }
161
218
  .highlight-new { background: var(--highlight-new); }
162
- .highlight-deleted { background: var(--highlight-deleted); }
219
+ .highlight-deleted { background: var(--highlight-deleted); }
@@ -2,7 +2,7 @@
2
2
  * Diagram Component Styles
3
3
  */
4
4
 
5
- // Code view styles
5
+ /* Code view container */
6
6
  .diagram-code-view {
7
7
  position: relative;
8
8
  height: 100%;
@@ -20,7 +20,7 @@
20
20
  }
21
21
  }
22
22
 
23
- // Mermaid diagram container
23
+ /* Mermaid diagram container */
24
24
  [x-ref="diagramContainer"] {
25
25
  .mermaid {
26
26
  overflow: auto;
@@ -28,7 +28,7 @@
28
28
  }
29
29
  }
30
30
 
31
- // Code container scrollbar styling
31
+ /* Code container scrollbar styling */
32
32
  pre[x-ref="codeContainer"] {
33
33
  &::-webkit-scrollbar {
34
34
  width: 8px;
@@ -52,4 +52,13 @@
52
52
  background: white;
53
53
  color: var(--navy-dark);
54
54
  font-weight: 500;
55
+ }
56
+
57
+ /* Tab content styles */
58
+ .tab-content {
59
+ display: none;
60
+ }
61
+
62
+ .tab-content.active {
63
+ display: block;
55
64
  }
@@ -0,0 +1,248 @@
1
+ // Tabulator Component Styles
2
+ // Custom styling for the Tabulator.js library used in DBWatcher
3
+
4
+ // Base Tabulator styling
5
+ .tabulator {
6
+ font-family: 'Consolas', 'Monaco', 'Lucida Console', monospace;
7
+ font-size: 12px;
8
+ border: none;
9
+ background: white;
10
+ border-collapse: separate;
11
+ border-spacing: 0;
12
+ margin: 0;
13
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
14
+
15
+ // Header styling
16
+ .tabulator-header {
17
+ background: #f3f3f3;
18
+ border-bottom: 2px solid #e8e8e8;
19
+ font-size: 11px;
20
+
21
+ .tabulator-col {
22
+ background: #f3f3f3;
23
+ border-right: 1px solid #e8e8e8;
24
+ padding: 4px 8px;
25
+ font-weight: 500;
26
+ text-transform: none;
27
+ height: 32px;
28
+ text-align: left;
29
+ position: sticky;
30
+ top: 0;
31
+ z-index: 10;
32
+
33
+ // Sticky columns in header
34
+ &.sticky-left-0 {
35
+ position: sticky;
36
+ left: 0;
37
+ z-index: 20;
38
+ background: #f3f3f3;
39
+ box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
40
+ }
41
+
42
+ &.sticky-left-1 {
43
+ position: sticky;
44
+ left: 60px;
45
+ z-index: 19;
46
+ background: #f3f3f3;
47
+ box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
48
+ }
49
+
50
+ &.sticky-left-2 {
51
+ position: sticky;
52
+ left: 108px;
53
+ z-index: 18;
54
+ background: #f3f3f3;
55
+ box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
56
+ }
57
+ }
58
+ }
59
+
60
+ // Table body styling
61
+ .tabulator-tableholder {
62
+ .tabulator-table {
63
+ .tabulator-row {
64
+ background: white;
65
+ border-bottom: 1px solid #f0f0f0;
66
+ min-height: auto;
67
+ transition: background-color 0.15s ease;
68
+
69
+ &:hover {
70
+ background: #f3f4f6;
71
+ }
72
+
73
+ // Row colors based on operation
74
+ &.operation-insert {
75
+ background-color: rgba(16, 185, 129, 0.05);
76
+ &:hover {
77
+ background-color: rgba(16, 185, 129, 0.1);
78
+ }
79
+ }
80
+
81
+ &.operation-update {
82
+ background-color: rgba(108, 173, 223, 0.05);
83
+ &:hover {
84
+ background-color: rgba(108, 173, 223, 0.1);
85
+ }
86
+ }
87
+
88
+ &.operation-delete {
89
+ background-color: rgba(239, 68, 68, 0.05);
90
+ &:hover {
91
+ background-color: rgba(239, 68, 68, 0.1);
92
+ }
93
+ }
94
+
95
+ // Cell styling
96
+ .tabulator-cell {
97
+ border-right: 1px solid #f0f0f0;
98
+ padding: 2px 8px;
99
+ overflow: hidden;
100
+ text-overflow: ellipsis;
101
+ white-space: nowrap;
102
+ vertical-align: top;
103
+ font-size: 12px;
104
+ height: auto;
105
+ min-height: 28px;
106
+
107
+ // Special styling for cells with multi-line content
108
+ &:has(.space-y-1) {
109
+ white-space: normal;
110
+ height: auto;
111
+ padding: 4px 8px;
112
+ }
113
+
114
+ // Sticky columns in body
115
+ &.sticky-left-0 {
116
+ position: sticky;
117
+ left: 0;
118
+ background: white;
119
+ z-index: 5;
120
+ box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
121
+ }
122
+
123
+ &.sticky-left-1 {
124
+ position: sticky;
125
+ left: 60px;
126
+ background: white;
127
+ z-index: 4;
128
+ box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
129
+ }
130
+
131
+ &.sticky-left-2 {
132
+ position: sticky;
133
+ left: 108px;
134
+ background: white;
135
+ z-index: 3;
136
+ box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
137
+ }
138
+ }
139
+
140
+ // Hover state for sticky cells
141
+ &:hover {
142
+ .tabulator-cell {
143
+ &.sticky-left-0,
144
+ &.sticky-left-1,
145
+ &.sticky-left-2 {
146
+ background: #f9fafb;
147
+ }
148
+ }
149
+ }
150
+
151
+ // Operation-specific sticky cell backgrounds
152
+ &.operation-insert .tabulator-cell {
153
+ &.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
154
+ background-color: rgba(16, 185, 129, 0.05);
155
+ }
156
+ }
157
+
158
+ &.operation-update .tabulator-cell {
159
+ &.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
160
+ background-color: rgba(108, 173, 223, 0.05);
161
+ }
162
+ }
163
+
164
+ &.operation-delete .tabulator-cell {
165
+ &.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
166
+ background-color: rgba(239, 68, 68, 0.05);
167
+ }
168
+ }
169
+
170
+ // Operation-specific sticky cell hover backgrounds
171
+ &.operation-insert:hover .tabulator-cell {
172
+ &.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
173
+ background-color: rgba(16, 185, 129, 0.1);
174
+ }
175
+ }
176
+
177
+ &.operation-update:hover .tabulator-cell {
178
+ &.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
179
+ background-color: rgba(108, 173, 223, 0.1);
180
+ }
181
+ }
182
+
183
+ &.operation-delete:hover .tabulator-cell {
184
+ &.sticky-left-0, &.sticky-left-1, &.sticky-left-2 {
185
+ background-color: rgba(239, 68, 68, 0.1);
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ // Row detail styling for expanded rows
194
+ .row-detail {
195
+ border-top: 1px solid #e5e7eb;
196
+ background: #f9fafb;
197
+ padding: 0;
198
+
199
+ td {
200
+ padding: 8px;
201
+ vertical-align: top;
202
+ border-right: 1px solid #e5e7eb;
203
+ }
204
+
205
+ h4 {
206
+ font-weight: 600;
207
+ color: #374151;
208
+ margin-bottom: 8px;
209
+ }
210
+
211
+ // Sticky column in expanded view
212
+ .sticky-left-0 {
213
+ position: sticky;
214
+ left: 0;
215
+ z-index: 5;
216
+ background: #f9fafb;
217
+ box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
218
+ width: 268px;
219
+ min-width: 268px;
220
+ }
221
+ }
222
+
223
+ // Expand button styling
224
+ .expand-btn {
225
+ padding: 2px;
226
+ border-radius: 2px;
227
+ transition: all 0.15s ease;
228
+
229
+ &:hover {
230
+ background-color: #f3f4f6;
231
+ }
232
+ }
233
+
234
+ // Table container
235
+ .table-container {
236
+ min-height: 200px;
237
+ width: 100%;
238
+ overflow: auto;
239
+ border-bottom-left-radius: 0.25rem;
240
+ border-bottom-right-radius: 0.25rem;
241
+ }
242
+
243
+ // Column selector dropdown
244
+ .column-selector {
245
+ right: 1rem;
246
+ margin-top: -2px;
247
+ z-index: 100;
248
+ }
@@ -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
+ }
@@ -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