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.
- checksums.yaml +4 -4
- data/README.md +24 -2
- data/app/assets/javascripts/dbwatcher/components/changes_table_hybrid.js +12 -22
- data/app/assets/javascripts/dbwatcher/components/dashboard.js +325 -0
- data/app/assets/stylesheets/dbwatcher/application.css +394 -41
- data/app/assets/stylesheets/dbwatcher/application.scss +4 -0
- data/app/assets/stylesheets/dbwatcher/components/_badges.scss +68 -23
- data/app/assets/stylesheets/dbwatcher/components/_compact_table.scss +83 -26
- data/app/assets/stylesheets/dbwatcher/components/_diagrams.scss +3 -3
- data/app/assets/stylesheets/dbwatcher/components/_navigation.scss +9 -0
- data/app/assets/stylesheets/dbwatcher/components/_tabulator.scss +248 -0
- data/app/assets/stylesheets/dbwatcher/vendor/_tabulator_overrides.scss +37 -0
- data/app/controllers/dbwatcher/api/v1/system_info_controller.rb +180 -0
- data/app/controllers/dbwatcher/dashboard/system_info_controller.rb +64 -0
- data/app/controllers/dbwatcher/dashboard_controller.rb +17 -0
- data/app/controllers/dbwatcher/sessions_controller.rb +3 -19
- data/app/helpers/dbwatcher/application_helper.rb +43 -11
- data/app/helpers/dbwatcher/diagram_helper.rb +0 -88
- data/app/views/dbwatcher/dashboard/_layout.html.erb +27 -0
- data/app/views/dbwatcher/dashboard/_overview.html.erb +188 -0
- data/app/views/dbwatcher/dashboard/_system_info.html.erb +22 -0
- data/app/views/dbwatcher/dashboard/_system_info_content.html.erb +389 -0
- data/app/views/dbwatcher/dashboard/index.html.erb +8 -177
- data/app/views/dbwatcher/sessions/_changes.html.erb +91 -0
- data/app/views/dbwatcher/sessions/_layout.html.erb +23 -0
- data/app/views/dbwatcher/sessions/index.html.erb +107 -87
- data/app/views/dbwatcher/sessions/show.html.erb +10 -4
- data/app/views/dbwatcher/tables/index.html.erb +32 -40
- data/app/views/layouts/dbwatcher/application.html.erb +100 -48
- data/config/routes.rb +23 -6
- data/lib/dbwatcher/configuration.rb +18 -1
- data/lib/dbwatcher/services/base_service.rb +2 -0
- data/lib/dbwatcher/services/diagram_analyzers/model_association_analyzer.rb +177 -138
- data/lib/dbwatcher/services/diagram_data/dataset.rb +2 -0
- data/lib/dbwatcher/services/mermaid_syntax/class_diagram_builder.rb +13 -9
- data/lib/dbwatcher/services/mermaid_syntax/class_diagram_helper.rb +3 -1
- data/lib/dbwatcher/services/mermaid_syntax/sanitizer.rb +17 -1
- data/lib/dbwatcher/services/system_info/database_info_collector.rb +263 -0
- data/lib/dbwatcher/services/system_info/machine_info_collector.rb +387 -0
- data/lib/dbwatcher/services/system_info/runtime_info_collector.rb +328 -0
- data/lib/dbwatcher/services/system_info/system_info_collector.rb +114 -0
- data/lib/dbwatcher/storage/concerns/error_handler.rb +6 -6
- data/lib/dbwatcher/storage/session.rb +5 -0
- data/lib/dbwatcher/storage/system_info_storage.rb +242 -0
- data/lib/dbwatcher/storage.rb +12 -0
- data/lib/dbwatcher/version.rb +1 -1
- data/lib/dbwatcher.rb +15 -1
- metadata +20 -15
- data/app/helpers/dbwatcher/component_helper.rb +0 -29
- data/app/views/dbwatcher/sessions/_changes_tab.html.erb +0 -265
- data/app/views/dbwatcher/sessions/_tab_navigation.html.erb +0 -12
- data/app/views/dbwatcher/sessions/changes.html.erb +0 -21
- data/app/views/dbwatcher/sessions/components/changes/_filters.html.erb +0 -44
- data/app/views/dbwatcher/sessions/components/changes/_table_list.html.erb +0 -96
- data/app/views/dbwatcher/sessions/diagrams.html.erb +0 -21
- data/app/views/dbwatcher/sessions/shared/_layout.html.erb +0 -8
- data/app/views/dbwatcher/sessions/shared/_navigation.html.erb +0 -35
- data/app/views/dbwatcher/sessions/shared/_session_header.html.erb +0 -25
- data/app/views/dbwatcher/sessions/summary.html.erb +0 -21
- /data/app/views/dbwatcher/sessions/{_diagrams_tab.html.erb → _diagrams.html.erb} +0 -0
- /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
|
-
/*
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
31
|
+
/* Code container scrollbar styling */
|
32
32
|
pre[x-ref="codeContainer"] {
|
33
33
|
&::-webkit-scrollbar {
|
34
34
|
width: 8px;
|
@@ -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
|