pg_insights 0.1.0

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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +183 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/javascripts/pg_insights/application.js +436 -0
  6. data/app/assets/javascripts/pg_insights/health.js +104 -0
  7. data/app/assets/javascripts/pg_insights/results/chart_renderer.js +126 -0
  8. data/app/assets/javascripts/pg_insights/results/table_manager.js +378 -0
  9. data/app/assets/javascripts/pg_insights/results/view_toggles.js +25 -0
  10. data/app/assets/javascripts/pg_insights/results.js +13 -0
  11. data/app/assets/stylesheets/pg_insights/application.css +750 -0
  12. data/app/assets/stylesheets/pg_insights/health.css +501 -0
  13. data/app/assets/stylesheets/pg_insights/results.css +682 -0
  14. data/app/controllers/pg_insights/application_controller.rb +4 -0
  15. data/app/controllers/pg_insights/health_controller.rb +110 -0
  16. data/app/controllers/pg_insights/insights_controller.rb +77 -0
  17. data/app/controllers/pg_insights/queries_controller.rb +44 -0
  18. data/app/helpers/pg_insights/application_helper.rb +4 -0
  19. data/app/helpers/pg_insights/insights_helper.rb +190 -0
  20. data/app/jobs/pg_insights/application_job.rb +4 -0
  21. data/app/jobs/pg_insights/health_check_job.rb +45 -0
  22. data/app/jobs/pg_insights/health_check_scheduler_job.rb +52 -0
  23. data/app/jobs/pg_insights/recurring_health_checks_job.rb +49 -0
  24. data/app/models/pg_insights/application_record.rb +5 -0
  25. data/app/models/pg_insights/health_check_result.rb +46 -0
  26. data/app/models/pg_insights/query.rb +10 -0
  27. data/app/services/pg_insights/health_check_service.rb +298 -0
  28. data/app/services/pg_insights/insight_query_service.rb +21 -0
  29. data/app/views/layouts/pg_insights/application.html.erb +58 -0
  30. data/app/views/pg_insights/health/index.html.erb +324 -0
  31. data/app/views/pg_insights/insights/_chart_view.html.erb +25 -0
  32. data/app/views/pg_insights/insights/_column_panel.html.erb +18 -0
  33. data/app/views/pg_insights/insights/_query_examples.html.erb +32 -0
  34. data/app/views/pg_insights/insights/_query_panel.html.erb +36 -0
  35. data/app/views/pg_insights/insights/_result.html.erb +15 -0
  36. data/app/views/pg_insights/insights/_results_info.html.erb +19 -0
  37. data/app/views/pg_insights/insights/_results_panel.html.erb +13 -0
  38. data/app/views/pg_insights/insights/_results_table.html.erb +45 -0
  39. data/app/views/pg_insights/insights/_stats_view.html.erb +3 -0
  40. data/app/views/pg_insights/insights/_table_controls.html.erb +21 -0
  41. data/app/views/pg_insights/insights/_table_view.html.erb +5 -0
  42. data/app/views/pg_insights/insights/index.html.erb +5 -0
  43. data/config/default_queries.yml +85 -0
  44. data/config/routes.rb +22 -0
  45. data/lib/generators/pg_insights/clean_generator.rb +74 -0
  46. data/lib/generators/pg_insights/install_generator.rb +176 -0
  47. data/lib/pg_insights/engine.rb +40 -0
  48. data/lib/pg_insights/version.rb +3 -0
  49. data/lib/pg_insights.rb +83 -0
  50. data/lib/tasks/pg_insights.rake +172 -0
  51. metadata +124 -0
@@ -0,0 +1,501 @@
1
+ /* PG Insights Health Dashboard - Clean & Simple Design */
2
+
3
+ /* Use specific selectors to avoid conflicts with other CSS files */
4
+ .health-overview-section,
5
+ .health-details,
6
+ .health-footer {
7
+ /* Reset any inherited styles */
8
+ box-sizing: border-box;
9
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
10
+ }
11
+
12
+ /* Page Header */
13
+ .health-overview-section .page-header {
14
+ text-align: center;
15
+ margin-bottom: 32px;
16
+ padding: 24px 0;
17
+ }
18
+
19
+ .health-overview-section .page-header h1 {
20
+ font-size: 32px;
21
+ font-weight: 700;
22
+ color: #1f2937;
23
+ margin: 0 0 8px 0;
24
+ line-height: 1.2;
25
+ }
26
+
27
+ .health-overview-section .page-header p {
28
+ font-size: 16px;
29
+ color: #6b7280;
30
+ margin: 0;
31
+ max-width: 600px;
32
+ margin-left: auto;
33
+ margin-right: auto;
34
+ }
35
+
36
+ /* Stats Grid */
37
+ .health-stats-grid {
38
+ display: grid;
39
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
40
+ gap: 20px;
41
+ margin-bottom: 40px;
42
+ }
43
+
44
+ /* Stat Card Link Wrapper */
45
+ .health-stats-grid .stat-card-link {
46
+ text-decoration: none;
47
+ color: inherit;
48
+ display: block;
49
+ border-radius: 12px;
50
+ transition: transform 0.2s ease;
51
+ }
52
+
53
+ .health-stats-grid .stat-card-link:hover {
54
+ text-decoration: none;
55
+ color: inherit;
56
+ transform: translateY(-2px);
57
+ }
58
+
59
+ .health-stats-grid .stat-card-link:focus {
60
+ outline: 2px solid #00979D;
61
+ outline-offset: 2px;
62
+ }
63
+
64
+ .health-stats-grid .stat-card-link.clicked {
65
+ transform: scale(0.98);
66
+ }
67
+
68
+ .health-stats-grid .stat-card {
69
+ background: white;
70
+ border-radius: 12px;
71
+ padding: 24px;
72
+ border: 1px solid #e5e7eb;
73
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
74
+ display: flex;
75
+ align-items: center;
76
+ gap: 16px;
77
+ transition: box-shadow 0.2s ease;
78
+ cursor: pointer;
79
+ }
80
+
81
+ .health-stats-grid .stat-card-link:hover .stat-card {
82
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
83
+ }
84
+
85
+ .health-stats-grid .stat-icon {
86
+ font-size: 32px;
87
+ width: 60px;
88
+ height: 60px;
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: center;
92
+ border-radius: 12px;
93
+ background: #f3f4f6;
94
+ flex-shrink: 0;
95
+ }
96
+
97
+ .health-stats-grid .unused-icon {
98
+ background: #fef2f2;
99
+ }
100
+
101
+ .health-stats-grid .slow-icon {
102
+ background: #fffbeb;
103
+ }
104
+
105
+ .health-stats-grid .bloat-icon {
106
+ background: #f0f9ff;
107
+ }
108
+
109
+ .health-stats-grid .scan-icon {
110
+ background: #f0fdf4;
111
+ }
112
+
113
+ .health-stats-grid .param-icon {
114
+ background: #f3f4f6;
115
+ }
116
+
117
+ .health-stats-grid .stat-content {
118
+ flex: 1;
119
+ }
120
+
121
+ .health-stats-grid .stat-number {
122
+ font-size: 28px;
123
+ font-weight: 800;
124
+ color: #00979D;
125
+ margin: 0 0 4px 0;
126
+ line-height: 1;
127
+ }
128
+
129
+ .health-stats-grid .stat-label {
130
+ font-size: 14px;
131
+ color: #6b7280;
132
+ font-weight: 500;
133
+ margin: 0;
134
+ }
135
+
136
+ /* Health Details */
137
+ .health-details {
138
+ display: flex;
139
+ flex-direction: column;
140
+ gap: 32px;
141
+ }
142
+
143
+ /* Health Section */
144
+ .health-details .health-section {
145
+ background: white;
146
+ border-radius: 12px;
147
+ border: 1px solid #e5e7eb;
148
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
149
+ overflow: hidden;
150
+ scroll-margin-top: 20px; /* Offset for smooth scrolling */
151
+ transition: box-shadow 0.3s ease, transform 0.3s ease;
152
+ }
153
+
154
+ /* Section highlighting animation */
155
+ .health-details .health-section.highlighted {
156
+ box-shadow: 0 0 0 3px rgba(0, 151, 157, 0.3), 0 4px 12px rgba(0, 0, 0, 0.15);
157
+ transform: scale(1.01);
158
+ }
159
+
160
+ .health-details .section-header {
161
+ padding: 24px 24px 16px 24px;
162
+ border-bottom: 1px solid #f3f4f6;
163
+ background: #f9fafb;
164
+ }
165
+
166
+ .health-details .section-header h2 {
167
+ font-size: 20px;
168
+ font-weight: 700;
169
+ color: #1f2937;
170
+ margin: 0 0 8px 0;
171
+ display: flex;
172
+ align-items: center;
173
+ gap: 8px;
174
+ }
175
+
176
+ .health-details .section-description {
177
+ font-size: 14px;
178
+ color: #6b7280;
179
+ margin: 0;
180
+ display: block;
181
+ }
182
+
183
+ .health-details .section-content {
184
+ padding: 24px;
185
+ }
186
+
187
+ /* Messages */
188
+ .health-details .success-message,
189
+ .health-details .error-message,
190
+ .health-details .info-message {
191
+ display: flex;
192
+ align-items: center;
193
+ gap: 12px;
194
+ padding: 16px;
195
+ border-radius: 8px;
196
+ font-weight: 500;
197
+ margin: 0;
198
+ }
199
+
200
+ .health-details .success-message {
201
+ background: #f0fdf4;
202
+ color: #166534;
203
+ border: 1px solid #bbf7d0;
204
+ }
205
+
206
+ .health-details .error-message {
207
+ background: #fef2f2;
208
+ color: #991b1b;
209
+ border: 1px solid #fecaca;
210
+ }
211
+
212
+ .health-details .info-message {
213
+ background: #eff6ff;
214
+ color: #1d4ed8;
215
+ border: 1px solid #dbeafe;
216
+ }
217
+
218
+ .health-details .error-message code {
219
+ background: rgba(255, 255, 255, 0.3);
220
+ padding: 2px 4px;
221
+ border-radius: 4px;
222
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
223
+ font-size: 13px;
224
+ }
225
+
226
+ /* Items List */
227
+ .health-details .items-list {
228
+ display: flex;
229
+ flex-direction: column;
230
+ gap: 0;
231
+ border: 1px solid #e5e7eb;
232
+ border-radius: 8px;
233
+ overflow: hidden;
234
+ }
235
+
236
+ .health-details .item-row {
237
+ display: flex;
238
+ justify-content: space-between;
239
+ align-items: flex-start;
240
+ padding: 20px;
241
+ border-bottom: 1px solid #f3f4f6;
242
+ background: white;
243
+ transition: background-color 0.2s ease;
244
+ }
245
+
246
+ .health-details .item-row:last-child {
247
+ border-bottom: none;
248
+ }
249
+
250
+ .health-details .item-row:hover {
251
+ background: #f9fafb;
252
+ }
253
+
254
+ .health-details .item-main {
255
+ flex: 1;
256
+ min-width: 0;
257
+ }
258
+
259
+ .health-details .item-title {
260
+ font-size: 16px;
261
+ font-weight: 600;
262
+ color: #1f2937;
263
+ margin: 0 0 4px 0;
264
+ word-break: break-word;
265
+ }
266
+
267
+ .health-details .item-subtitle {
268
+ font-size: 14px;
269
+ color: #6b7280;
270
+ margin: 0;
271
+ }
272
+
273
+ .health-details .item-details {
274
+ display: flex;
275
+ flex-direction: column;
276
+ gap: 8px;
277
+ margin-left: 20px;
278
+ flex-shrink: 0;
279
+ min-width: 200px;
280
+ }
281
+
282
+ .health-details .detail-item {
283
+ display: flex;
284
+ justify-content: space-between;
285
+ align-items: center;
286
+ gap: 12px;
287
+ }
288
+
289
+ .health-details .detail-label {
290
+ font-size: 13px;
291
+ color: #6b7280;
292
+ font-weight: 500;
293
+ white-space: nowrap;
294
+ }
295
+
296
+ .health-details .detail-value {
297
+ font-size: 13px;
298
+ font-weight: 600;
299
+ color: #1f2937;
300
+ text-align: right;
301
+ }
302
+
303
+ .health-details .detail-value.warning {
304
+ color: #d97706;
305
+ }
306
+
307
+ .health-details .detail-value.danger {
308
+ color: #dc2626;
309
+ }
310
+
311
+ .health-details .detail-value code {
312
+ background: #f3f4f6;
313
+ padding: 2px 6px;
314
+ border-radius: 4px;
315
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
316
+ font-size: 12px;
317
+ color: #1f2937;
318
+ }
319
+
320
+ /* Query Specific Styles */
321
+ .health-details .query-item .item-title {
322
+ margin-bottom: 0;
323
+ }
324
+
325
+ .health-details .query-text {
326
+ background: #f3f4f6;
327
+ padding: 8px 12px;
328
+ border-radius: 6px;
329
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
330
+ font-size: 13px;
331
+ color: #1f2937;
332
+ display: block;
333
+ overflow-x: auto;
334
+ white-space: nowrap;
335
+ margin: 0;
336
+ }
337
+
338
+ .health-details .query-item .item-details {
339
+ display: grid;
340
+ grid-template-columns: 1fr 1fr;
341
+ gap: 8px 16px;
342
+ min-width: 300px;
343
+ }
344
+
345
+ /* Recommendation Styles */
346
+ .health-details .recommendation {
347
+ grid-column: 1 / -1;
348
+ background: #f0f9ff;
349
+ padding: 8px;
350
+ border-radius: 6px;
351
+ border: 1px solid #e0f2fe;
352
+ }
353
+
354
+ .health-details .recommendation .detail-label {
355
+ color: #0c4a6e;
356
+ }
357
+
358
+ .health-details .recommendation .detail-value {
359
+ color: #0c4a6e;
360
+ font-weight: 500;
361
+ font-size: 12px;
362
+ white-space: normal;
363
+ text-align: left;
364
+ }
365
+
366
+ /* Footer */
367
+ .health-footer {
368
+ background: white;
369
+ border-radius: 12px;
370
+ padding: 20px;
371
+ border: 1px solid #e5e7eb;
372
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
373
+ margin-top: 32px;
374
+ text-align: center;
375
+ }
376
+
377
+ .health-footer .footer-text {
378
+ display: flex;
379
+ align-items: center;
380
+ justify-content: center;
381
+ gap: 8px;
382
+ color: #6b7280;
383
+ font-size: 14px;
384
+ margin: 0;
385
+ }
386
+
387
+ /* Responsive Design */
388
+ @media (max-width: 1024px) {
389
+ .health-stats-grid {
390
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
391
+ gap: 16px;
392
+ }
393
+
394
+ .health-details .item-details {
395
+ min-width: 180px;
396
+ }
397
+
398
+ .health-details .query-item .item-details {
399
+ min-width: 250px;
400
+ }
401
+ }
402
+
403
+ @media (max-width: 768px) {
404
+ .health-overview-section .page-header {
405
+ padding: 16px 0;
406
+ margin-bottom: 24px;
407
+ }
408
+
409
+ .health-overview-section .page-header h1 {
410
+ font-size: 28px;
411
+ }
412
+
413
+ .health-stats-grid {
414
+ grid-template-columns: 1fr;
415
+ gap: 16px;
416
+ margin-bottom: 32px;
417
+ }
418
+
419
+ .health-stats-grid .stat-card {
420
+ padding: 20px;
421
+ }
422
+
423
+ .health-details {
424
+ gap: 24px;
425
+ }
426
+
427
+ .health-details .section-header {
428
+ padding: 20px 20px 12px 20px;
429
+ }
430
+
431
+ .health-details .section-content {
432
+ padding: 20px;
433
+ }
434
+
435
+ .health-details .item-row {
436
+ flex-direction: column;
437
+ gap: 16px;
438
+ padding: 16px;
439
+ }
440
+
441
+ .health-details .item-details {
442
+ margin-left: 0;
443
+ min-width: auto;
444
+ width: 100%;
445
+ }
446
+
447
+ .health-details .query-item .item-details {
448
+ min-width: auto;
449
+ grid-template-columns: 1fr;
450
+ }
451
+
452
+ .health-details .recommendation {
453
+ grid-column: 1;
454
+ }
455
+ }
456
+
457
+ @media (max-width: 480px) {
458
+ .health-overview-section .page-header h1 {
459
+ font-size: 24px;
460
+ }
461
+
462
+ .health-overview-section .page-header p {
463
+ font-size: 14px;
464
+ }
465
+
466
+ .health-stats-grid .stat-card {
467
+ padding: 16px;
468
+ gap: 12px;
469
+ }
470
+
471
+ .health-stats-grid .stat-icon {
472
+ width: 50px;
473
+ height: 50px;
474
+ font-size: 24px;
475
+ }
476
+
477
+ .health-stats-grid .stat-number {
478
+ font-size: 24px;
479
+ }
480
+
481
+ .health-details .section-header {
482
+ padding: 16px;
483
+ }
484
+
485
+ .health-details .section-content {
486
+ padding: 16px;
487
+ }
488
+
489
+ .health-details .item-row {
490
+ padding: 12px;
491
+ }
492
+
493
+ .health-details .section-header h2 {
494
+ font-size: 18px;
495
+ }
496
+
497
+ .health-details .query-text {
498
+ font-size: 12px;
499
+ padding: 6px 8px;
500
+ }
501
+ }