pghero 3.1.0 → 3.7.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +78 -1
  3. data/LICENSE.txt +1 -1
  4. data/README.md +2 -2
  5. data/app/assets/javascripts/pghero/Chart.bundle.js +23379 -19766
  6. data/app/assets/javascripts/pghero/application.js +27 -12
  7. data/app/assets/javascripts/pghero/chartkick.js +834 -764
  8. data/app/assets/javascripts/pghero/highlight.min.js +440 -0
  9. data/app/assets/javascripts/pghero/jquery.js +318 -197
  10. data/app/assets/javascripts/pghero/nouislider.js +676 -1066
  11. data/app/assets/stylesheets/pghero/application.css +108 -2
  12. data/app/assets/stylesheets/pghero/nouislider.css +4 -10
  13. data/app/controllers/pg_hero/home_controller.rb +53 -16
  14. data/app/helpers/pg_hero/home_helper.rb +3 -3
  15. data/app/views/layouts/pg_hero/application.html.erb +3 -3
  16. data/app/views/pg_hero/home/_connections_table.html.erb +1 -1
  17. data/app/views/pg_hero/home/_live_queries_table.html.erb +8 -8
  18. data/app/views/pg_hero/home/_queries_table.html.erb +5 -5
  19. data/app/views/pg_hero/home/_query_stats_slider.html.erb +8 -8
  20. data/app/views/pg_hero/home/_suggested_index.html.erb +6 -5
  21. data/app/views/pg_hero/home/connections.html.erb +12 -12
  22. data/app/views/pg_hero/home/explain.html.erb +2 -2
  23. data/app/views/pg_hero/home/index.html.erb +22 -20
  24. data/app/views/pg_hero/home/index_bloat.html.erb +6 -6
  25. data/app/views/pg_hero/home/maintenance.html.erb +3 -3
  26. data/app/views/pg_hero/home/queries.html.erb +7 -5
  27. data/app/views/pg_hero/home/relation_space.html.erb +4 -4
  28. data/app/views/pg_hero/home/show_query.html.erb +35 -31
  29. data/app/views/pg_hero/home/space.html.erb +50 -46
  30. data/app/views/pg_hero/home/system.html.erb +18 -18
  31. data/app/views/pg_hero/home/tune.html.erb +2 -2
  32. data/lib/generators/pghero/query_stats_generator.rb +1 -0
  33. data/lib/generators/pghero/space_stats_generator.rb +1 -0
  34. data/lib/pghero/database.rb +2 -2
  35. data/lib/pghero/engine.rb +4 -3
  36. data/lib/pghero/methods/basic.rb +26 -31
  37. data/lib/pghero/methods/connections.rb +4 -4
  38. data/lib/pghero/methods/constraints.rb +1 -1
  39. data/lib/pghero/methods/explain.rb +4 -3
  40. data/lib/pghero/methods/indexes.rb +8 -8
  41. data/lib/pghero/methods/kill.rb +1 -1
  42. data/lib/pghero/methods/maintenance.rb +3 -3
  43. data/lib/pghero/methods/queries.rb +2 -2
  44. data/lib/pghero/methods/query_stats.rb +34 -24
  45. data/lib/pghero/methods/replication.rb +2 -2
  46. data/lib/pghero/methods/sequences.rb +10 -5
  47. data/lib/pghero/methods/settings.rb +8 -1
  48. data/lib/pghero/methods/space.rb +20 -14
  49. data/lib/pghero/methods/suggested_indexes.rb +14 -7
  50. data/lib/pghero/methods/system.rb +12 -6
  51. data/lib/pghero/methods/tables.rb +4 -5
  52. data/lib/pghero/version.rb +1 -1
  53. data/lib/pghero.rb +35 -36
  54. data/lib/tasks/pghero.rake +11 -1
  55. data/licenses/LICENSE-chart.js.txt +1 -1
  56. data/licenses/LICENSE-date-fns.txt +21 -20
  57. data/licenses/LICENSE-kurkle-color.txt +9 -0
  58. metadata +8 -11
  59. data/app/assets/javascripts/pghero/highlight.pack.js +0 -2
@@ -55,9 +55,11 @@
55
55
  Vacuuming healthy
56
56
  <% end %>
57
57
  </div>
58
- <div class="alert alert-<%= @sequence_danger && @sequence_danger.empty? ? "success" : "warning" %>">
58
+ <div class="alert alert-<%= @sequence_danger && @sequence_danger.empty? && !@sequences_timeout ? "success" : "warning" %>">
59
59
  <% if @sequence_danger.any? %>
60
60
  <%= pluralize(@sequence_danger.size, "column") %> approaching overflow
61
+ <% elsif @sequences_timeout %>
62
+ Sequences not available (system catalog locked)
61
63
  <% else %>
62
64
  No columns near integer overflow
63
65
  <% end %>
@@ -125,7 +127,7 @@
125
127
  <table class="table">
126
128
  <thead>
127
129
  <tr>
128
- <th style="width: 33%;">Column</th>
130
+ <th class="width-33">Column</th>
129
131
  <th>Sequence</th>
130
132
  </tr>
131
133
  </thead>
@@ -249,7 +251,7 @@
249
251
  <thead>
250
252
  <tr>
251
253
  <th>Table</th>
252
- <th style="width: 20%;">Transactions Left</th>
254
+ <th class="width-20">Transactions Left</th>
253
255
  </tr>
254
256
  </thead>
255
257
  <tbody>
@@ -277,9 +279,9 @@
277
279
  <thead>
278
280
  <tr>
279
281
  <th>Column</th>
280
- <th style="width: 20%;">Type</th>
281
- <th style="width: 20%;">Values Left</th>
282
- <th style="width: 10%;">% Left</th>
282
+ <th class="width-20">Type</th>
283
+ <th class="width-20">Values Left</th>
284
+ <th class="width-10">% Left</th>
283
285
  </tr>
284
286
  </thead>
285
287
  <tbody>
@@ -330,7 +332,7 @@
330
332
  </td>
331
333
  </tr>
332
334
  <tr>
333
- <td style="border-top: none; padding: 0;">
335
+ <td class="query-row">
334
336
  <pre><code>DROP INDEX CONCURRENTLY <%= pghero_pretty_ident(index[:name], schema: index[:schema]) %>;
335
337
  <%= index[:definition].sub("CREATE INDEX ", "CREATE INDEX CONCURRENTLY ") %>;</code></pre>
336
338
  </td>
@@ -364,7 +366,7 @@
364
366
  </td>
365
367
  </tr>
366
368
  <tr>
367
- <td style="border-top: none; padding: 0;">
369
+ <td class="query-row">
368
370
  <pre><code>ALTER TABLE <%= pghero_pretty_ident(constraint[:table], schema: constraint[:schema]) %> VALIDATE CONSTRAINT <%= pghero_pretty_ident(constraint[:name]) %>;</code></pre>
369
371
  </td>
370
372
  </tr>
@@ -381,15 +383,15 @@
381
383
  <p>
382
384
  These indexes exist, but aren’t needed. Remove them
383
385
  <% if @show_migrations %>
384
- <a href="javascript: void(0);" onclick="document.getElementById('migration2').style.display = 'block';">with a migration</a>
386
+ <a href="#" class="migration-link">with a migration</a>
385
387
  <% end %>
386
388
  for faster writes.
387
389
  </p>
388
390
 
389
- <div id="migration2" style="display: none;">
391
+ <div class="migration">
390
392
  <pre>rails generate migration remove_unneeded_indexes</pre>
391
393
  <p>And paste</p>
392
- <pre style="overflow: scroll; white-space: pre; word-break: normal;"><% @duplicate_indexes.each do |query| %>
394
+ <pre><% @duplicate_indexes.each do |query| %>
393
395
  <%= pghero_remove_index(query[:unneeded_index]) %><% end %></pre>
394
396
  </div>
395
397
 
@@ -424,14 +426,14 @@
424
426
  Add indexes to speed up queries.
425
427
  <% if @show_migrations %>
426
428
  Here’s a
427
- <a href="javascript: void(0);" onclick="document.getElementById('migration3').style.display = 'block';">migration</a> to help.
429
+ <a href="#" class="migration-link">migration</a> to help.
428
430
  <% end %>
429
431
  </p>
430
432
 
431
- <div id="migration3" style="display: none;">
433
+ <div class="migration">
432
434
  <pre>rails generate migration add_suggested_indexes</pre>
433
435
  <p>And paste</p>
434
- <pre style="overflow: scroll; white-space: pre; word-break: normal;">commit_db_transaction
436
+ <pre>commit_db_transaction
435
437
  <% @suggested_indexes.each do |index| %>
436
438
  <% if index[:using] && index[:using] != "btree" %>
437
439
  add_index <%= index[:table].to_sym.inspect %>, <%= index[:columns].first.inspect %>, using: <%= index[:using].inspect %>, algorithm: :concurrently
@@ -485,15 +487,15 @@ pg_stat_statements.track = all</pre>
485
487
  <p>
486
488
  Unused indexes cause unnecessary overhead. Remove them
487
489
  <% if @show_migrations %>
488
- <a href="javascript: void(0);" onclick="document.getElementById('migration').style.display = 'block';">with a migration</a>
490
+ <a href="#" class="migration-link">with a migration</a>
489
491
  <% end %>
490
492
  for faster writes.
491
493
  </p>
492
494
 
493
- <div id="migration" style="display: none;">
495
+ <div class="migration">
494
496
  <pre>rails generate migration remove_unused_indexes</pre>
495
497
  <p>And paste</p>
496
- <pre style="overflow: scroll; white-space: pre; word-break: normal;"><% @unused_indexes.each do |query| %>
498
+ <pre><% @unused_indexes.each do |query| %>
497
499
  <%= pghero_remove_index(query)%><% end %></pre>
498
500
  </div>
499
501
 
@@ -501,7 +503,7 @@ pg_stat_statements.track = all</pre>
501
503
  <thead>
502
504
  <tr>
503
505
  <th>Name</th>
504
- <th style="width: 20%;">Index Size</th>
506
+ <th class="width-20">Index Size</th>
505
507
  </tr>
506
508
  </thead>
507
509
  <tbody>
@@ -516,6 +518,6 @@ pg_stat_statements.track = all</pre>
516
518
  </div>
517
519
  <% end %>
518
520
 
519
- <script>
521
+ <%= javascript_tag nonce: true do %>
520
522
  highlightQueries();
521
- </script>
523
+ <% end %>
@@ -25,15 +25,15 @@ ALTER INDEX new_index RENAME TO index;</code></pre>
25
25
  <thead>
26
26
  <tr>
27
27
  <th>Index</th>
28
- <th style="width: 15%;">Bloat</th>
29
- <th style="width: 15%;">Size</th>
28
+ <th class="width-15">Bloat</th>
29
+ <th class="width-15">Size</th>
30
30
  </tr>
31
31
  </thead>
32
32
  <tbody>
33
33
  <% @index_bloat.each do |index| %>
34
34
  <tr>
35
35
  <td>
36
- <span style="word-break: break-all;"><%= index[:index] %></span>
36
+ <span class="break-all"><%= index[:index] %></span>
37
37
  <% if index[:primary] %>
38
38
  <span class="primary-key">PRIMARY</span>
39
39
  <% end %>
@@ -43,7 +43,7 @@ ALTER INDEX new_index RENAME TO index;</code></pre>
43
43
  </tr>
44
44
  <% if @show_sql && !index[:primary] %>
45
45
  <tr>
46
- <td colspan="3" style="border-top: none; padding: 0;">
46
+ <td colspan="3" class="query-row">
47
47
  <% new_index = "new_#{index[:index]}".first(63) %>
48
48
  <pre><code><%= index[:definition].sub(" INDEX ", " INDEX CONCURRENTLY \n ").sub(index[:index], new_index) %>;
49
49
 
@@ -67,6 +67,6 @@ ALTER INDEX <%= pghero_pretty_ident(new_index) %>
67
67
  <% end %>
68
68
  </div>
69
69
 
70
- <script>
70
+ <%= javascript_tag nonce: true do %>
71
71
  highlightQueries();
72
- </script>
72
+ <% end %>
@@ -5,10 +5,10 @@
5
5
  <thead>
6
6
  <tr>
7
7
  <th>Table</th>
8
- <th style="width: 20%;">Last Vacuum</th>
9
- <th style="width: 20%;">Last Analyze</th>
8
+ <th class="width-20">Last Vacuum</th>
9
+ <th class="width-20">Last Analyze</th>
10
10
  <% if @show_dead_rows %>
11
- <th style="width: 20%;">Dead Rows</th>
11
+ <th class="width-20">Dead Rows</th>
12
12
  <% end %>
13
13
  </tr>
14
14
  </thead>
@@ -1,14 +1,16 @@
1
1
  <div class="content">
2
- <% if @query_stats_enabled %>
2
+ <% if @query_stats_enabled && !@historical_query_stats_enabled %>
3
3
  <%= button_to "Reset", reset_query_stats_path, class: "btn btn-danger", style: "float: right;" %>
4
4
  <% end %>
5
5
 
6
- <h1 style="float: left;">Queries</h1>
6
+ <% if !@historical_query_stats_enabled %>
7
+ <h1 class="push-left">Queries</h1>
8
+ <% end %>
7
9
 
8
10
  <% if @historical_query_stats_enabled %>
9
11
  <%= render partial: "query_stats_slider" %>
10
12
  <% elsif @database.query_stats_table_exists? && (columns = @database.missing_query_stats_columns).any? %>
11
- <div style="clear: both;">
13
+ <div class="clear-both">
12
14
  <p>Add missing columns to re-enable historical query stats.</p>
13
15
  <pre><code><% @database.missing_query_stats_columns.each do |column| %>ALTER TABLE pghero_query_stats ADD COLUMN "<%= column %>" <%= column == "query_hash" ? "bigint" : "text" %>;
14
16
  <% end %></code></pre>
@@ -21,9 +23,9 @@
21
23
  <div class="alert alert-danger">Cannot understand start or end time.</div>
22
24
  <% elsif @query_stats.any? || @historical_query_stats_enabled %>
23
25
  <%= render partial: "queries_table", locals: {queries: @query_stats, sort_headers: true} %>
24
- <script>
26
+ <%= javascript_tag nonce: true do %>
25
27
  highlightQueries();
26
- </script>
28
+ <% end %>
27
29
  <% else %>
28
30
  <p>Stats are not available yet. Come back soon!</p>
29
31
  <% end %>
@@ -7,8 +7,8 @@
7
7
  </h1>
8
8
 
9
9
  <h1>Size</h1>
10
- <div id="chart-1" class="chart" style="margin-bottom: 20px;">Loading...</div>
11
- <script>
12
- new Chartkick.LineChart("chart-1", <%= json_escape(@chart_data.to_json).html_safe %>, {colors: ["#5bc0de"], legend: false, min: null, bytes: true, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
13
- </script>
10
+ <div id="chart-1" class="chart">Loading...</div>
11
+ <%= javascript_tag nonce: true do %>
12
+ new Chartkick.LineChart("chart-1", <%= pghero_js_value(@chart_data) %>, {colors: ["#5bc0de"], legend: false, min: null, bytes: true, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
13
+ <% end %>
14
14
  </div>
@@ -1,8 +1,8 @@
1
1
  <div class="content">
2
- <pre><code style="max-height: 230px; overflow: hidden;" onclick="this.style.maxHeight = 'none';"><%= @query %></code></pre>
3
- <script>
2
+ <pre><code class="query-code"><%= @query %></code></pre>
3
+ <%= javascript_tag nonce: true do %>
4
4
  highlightQueries()
5
- </script>
5
+ <% end %>
6
6
 
7
7
  <% if @explain_enabled && @explainable_query %>
8
8
  <p>
@@ -11,11 +11,11 @@
11
11
  <% end %>
12
12
 
13
13
  <% if @origins && @origins.keys.select { |k| k.length > 0 }.any? %>
14
- <table style="table-layout: auto;">
14
+ <table class="origins-table">
15
15
  <thead>
16
16
  <tr>
17
17
  <th colspan="2">
18
- <div style="float: right;">Approx. Time</div>
18
+ <div class="push-right">Approx. Time</div>
19
19
  Origin
20
20
  </th>
21
21
  </tr>
@@ -23,14 +23,14 @@
23
23
  <tbody>
24
24
  <% @origins.sort_by { |o, c| [-c, o.to_s] }.each do |origin, count| %>
25
25
  <tr>
26
- <td class="origin" style="width: 90%;">
26
+ <td class="origin">
27
27
  <% if origin.length > 0 %>
28
28
  <%= origin %>
29
29
  <% else %>
30
30
  <span class="text-muted">Unknown</span>
31
31
  <% end %>
32
32
  </td>
33
- <td style="text-align: right; width: 10%;">
33
+ <td class="origin-pct">
34
34
  <% pct = (100.0 * count / @total_count).round %>
35
35
  <% if pct == 0 %>
36
36
  &lt; 1%
@@ -47,22 +47,22 @@
47
47
  <!-- chart -->
48
48
  <% if @chart_data %>
49
49
  <h1>Total Time <small>ms</small></h1>
50
- <div id="chart-1" class="chart" style="margin-bottom: 20px;">Loading...</div>
51
- <script>
52
- new Chartkick.LineChart("chart-1", <%= json_escape(@chart_data.to_json).html_safe %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
53
- </script>
50
+ <div id="chart-1" class="chart">Loading...</div>
51
+ <%= javascript_tag nonce: true do %>
52
+ new Chartkick.LineChart("chart-1", <%= pghero_js_value(@chart_data) %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
53
+ <% end %>
54
54
 
55
55
  <h1>Average Time <small>ms</small></h1>
56
- <div id="chart-2" class="chart" style="margin-bottom: 20px;">Loading...</div>
57
- <script>
58
- new Chartkick.LineChart("chart-2", <%= json_escape(@chart2_data.to_json).html_safe %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
59
- </script>
56
+ <div id="chart-2" class="chart">Loading...</div>
57
+ <%= javascript_tag nonce: true do %>
58
+ new Chartkick.LineChart("chart-2", <%= pghero_js_value(@chart2_data) %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
59
+ <% end %>
60
60
 
61
61
  <h1>Calls</h1>
62
- <div id="chart-3" class="chart" style="margin-bottom: 20px;">Loading...</div>
63
- <script>
64
- new Chartkick.LineChart("chart-3", <%= json_escape(@chart3_data.to_json).html_safe %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
65
- </script>
62
+ <div id="chart-3" class="chart">Loading...</div>
63
+ <%= javascript_tag nonce: true do %>
64
+ new Chartkick.LineChart("chart-3", <%= pghero_js_value(@chart3_data) %>, {colors: ["#5bc0de"], legend: false, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
65
+ <% end %>
66
66
  <% else %>
67
67
  <p>
68
68
  Enable
@@ -77,8 +77,8 @@
77
77
  <table>
78
78
  <thead>
79
79
  <tr>
80
- <th style="width: 25%;">Name</th>
81
- <th style="width: 25%;">Rows</th>
80
+ <th class="width-25">Name</th>
81
+ <th class="width-25">Rows</th>
82
82
  <th>Indexes</th>
83
83
  </tr>
84
84
  </thead>
@@ -86,17 +86,21 @@
86
86
  <% @tables.each do |table| %>
87
87
  <tr>
88
88
  <td><%= table %></td>
89
- <td><%= @row_counts[table] %></td>
89
+ <td><%= number_with_delimiter(@row_counts[table]) if @row_counts[table] %></td>
90
90
  <td>
91
- <ul>
92
- <% @indexes_by_table[table].to_a.sort_by { |i| [i[:primary] ? 0 : 1, i[:columns]] }.each do |i3| %>
93
- <li>
94
- <%= i3[:columns].join(", ") %><% if i3[:using] != "btree" %>
95
- <%= i3[:using].to_s.upcase %><% end %>
96
- <% if i3[:primary] %> PRIMARY<% elsif i3[:unique] %> UNIQUE<% end %>
97
- </li>
98
- <% end %>
99
- </ul>
91
+ <% if @indexes_timeout %>
92
+ Not available
93
+ <% else %>
94
+ <ul>
95
+ <% @indexes_by_table[table].to_a.sort_by { |i| [i[:primary] ? 0 : 1, i[:columns]] }.each do |i3| %>
96
+ <li>
97
+ <%= i3[:columns].join(", ") %><% if i3[:using] != "btree" %>
98
+ <%= i3[:using].to_s.upcase %><% end %>
99
+ <% if i3[:primary] %> PRIMARY<% elsif i3[:unique] %> UNIQUE<% end %>
100
+ </li>
101
+ <% end %>
102
+ </ul>
103
+ <% end %>
100
104
  </td>
101
105
  </tr>
102
106
  <% end %>
@@ -4,10 +4,10 @@
4
4
  <p>Database Size: <%= @database_size %></p>
5
5
 
6
6
  <% if @system_stats_enabled %>
7
- <div id="chart-1" class="chart" style="margin-bottom: 20px;">Loading...</div>
8
- <script>
9
- new Chartkick.LineChart("chart-1", <%= json_escape(free_space_stats_path.to_json).html_safe %>, {colors: ["#5bc0de"], bytes: true, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
10
- </script>
7
+ <div id="chart-1" class="chart">Loading...</div>
8
+ <%= javascript_tag nonce: true do %>
9
+ new Chartkick.LineChart("chart-1", <%= pghero_js_value(free_space_stats_path) %>, {colors: ["#5bc0de"], bytes: true, library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
10
+ <% end %>
11
11
  <% end %>
12
12
 
13
13
  <!--
@@ -20,7 +20,7 @@
20
20
  <p>
21
21
  <%= pluralize(@unused_indexes.size, "unused index") %>. Remove them
22
22
  <% if @show_migrations %>
23
- <a href="javascript: void(0);" onclick="document.getElementById('migration').style.display = 'block';">with a migration</a>
23
+ <a href="#" class="migration-link">with a migration</a>
24
24
  <% end %>
25
25
  for faster writes.
26
26
 
@@ -29,55 +29,59 @@
29
29
  <% end %>
30
30
  </p>
31
31
 
32
- <div id="migration" style="display: none;">
32
+ <div class="migration">
33
33
  <pre>rails generate migration remove_unused_indexes</pre>
34
34
  <p>And paste</p>
35
- <pre style="overflow: scroll; white-space: pre; word-break: normal;"><% @unused_indexes.sort_by { |q| [-q[:size_bytes], q[:index]] }.each do |query| %>
35
+ <pre><% @unused_indexes.sort_by { |q| [-q[:size_bytes], q[:index]] }.each do |query| %>
36
36
  <%= pghero_remove_index(query) %><% end %></pre>
37
37
  </div>
38
38
  <% end %>
39
39
 
40
- <table class="table space-table">
41
- <thead>
42
- <tr>
43
- <th><%= link_to (@only_tables ? "Table" : "Relation"), @header_options.merge(sort: "name") %></th>
44
- <th style="width: 15%;"><%= link_to "Size", @header_options %></th>
45
- <% if @space_stats_enabled %>
46
- <th style="width: 15%;"><%= link_to "#{@days}d Growth", @header_options.merge(sort: "growth") %></th>
47
- <% end %>
48
- </tr>
49
- </thead>
50
- <tbody>
51
- <% @relation_sizes.each do |query| %>
40
+ <% if @sizes_timeout %>
41
+ <p>Breakdown not available (system catalog locked)</p>
42
+ <% else %>
43
+ <table class="table space-table">
44
+ <thead>
52
45
  <tr>
53
- <td style="<%= query[:type] == "index" ? "font-style: italic;" : "" %>">
54
- <span style="word-break: break-all;">
55
- <% name = query[:relation] || query[:table] %>
56
- <% if @space_stats_enabled %>
57
- <%= link_to name, relation_space_path(name, schema: query[:schema]), target: "_blank", style: "color: inherit;" %>
58
- <% else %>
59
- <%= name %>
60
- <% end %>
61
- </span>
62
- <% if query[:schema] != "public" %>
63
- <span class="text-muted"><%= query[:schema] %></span>
64
- <% end %>
65
- <% if @unused_index_names.include?(query[:relation]) %>
66
- <span class="unused-index">UNUSED</span>
67
- <% end %>
68
- </td>
69
- <td><%= query[:size] %></td>
46
+ <th><%= link_to (@only_tables ? "Table" : "Relation"), @header_options.merge(sort: "name") %></th>
47
+ <th class="width-15"><%= link_to "Size", @header_options %></th>
70
48
  <% if @space_stats_enabled %>
71
- <td>
72
- <% if @growth_bytes_by_relation[[query[:schema], query[:relation]]] %>
73
- <% if @growth_bytes_by_relation[[query[:schema], query[:relation]]] < 0 %>-<% end %><%= PgHero.pretty_size(@growth_bytes_by_relation[[query[:schema], query[:relation]]].abs) %>
74
- <% else %>
75
- <span class="text-muted">Unknown</span>
76
- <% end %>
77
- </td>
49
+ <th class="width-15"><%= link_to "#{@days}d Growth", @header_options.merge(sort: "growth") %></th>
78
50
  <% end %>
79
51
  </tr>
80
- <% end %>
81
- </tbody>
82
- </table>
52
+ </thead>
53
+ <tbody>
54
+ <% @relation_sizes.each do |query| %>
55
+ <tr>
56
+ <td class="<%= query[:type] == "index" ? "space-index" : "" %>">
57
+ <span class="break-all">
58
+ <% name = query[:relation] || query[:table] %>
59
+ <% if @space_stats_enabled %>
60
+ <%= link_to name, relation_space_path(name, schema: query[:schema]), target: "_blank", class: "relation-link" %>
61
+ <% else %>
62
+ <%= name %>
63
+ <% end %>
64
+ </span>
65
+ <% if query[:schema] != "public" %>
66
+ <span class="text-muted"><%= query[:schema] %></span>
67
+ <% end %>
68
+ <% if @unused_index_names.include?(query[:relation]) %>
69
+ <span class="unused-index">UNUSED</span>
70
+ <% end %>
71
+ </td>
72
+ <td><%= query[:size] %></td>
73
+ <% if @space_stats_enabled %>
74
+ <td>
75
+ <% if @growth_bytes_by_relation[[query[:schema], query[:relation]]] %>
76
+ <% if @growth_bytes_by_relation[[query[:schema], query[:relation]]] < 0 %>-<% end %><%= PgHero.pretty_size(@growth_bytes_by_relation[[query[:schema], query[:relation]]].abs) %>
77
+ <% else %>
78
+ <span class="text-muted">Unknown</span>
79
+ <% end %>
80
+ </td>
81
+ <% end %>
82
+ </tr>
83
+ <% end %>
84
+ </tbody>
85
+ </table>
86
+ <% end %>
83
87
  </div>
@@ -1,34 +1,34 @@
1
1
  <div class="content">
2
2
  <p id="periods">
3
3
  <% @periods.each do |name, options| %>
4
- <%= link_to name, system_path(options) %>
4
+ <%= link_to name, system_path(params: options) %>
5
5
  <% end %>
6
6
  </p>
7
- <% path_options = {duration: @duration, period: @period} %>
7
+ <% path_options = {params: {duration: @duration, period: @period}} %>
8
8
 
9
9
  <h1>CPU</h1>
10
- <div id="chart-1" class="chart" style="margin-bottom: 20px;">Loading...</div>
11
- <script>
12
- new Chartkick.LineChart("chart-1", <%= json_escape(cpu_usage_path(path_options).to_json).html_safe %>, {max: 100, colors: ["#5bc0de"], suffix: "%", library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
13
- </script>
10
+ <div id="chart-1" class="chart">Loading...</div>
11
+ <%= javascript_tag nonce: true do %>
12
+ new Chartkick.LineChart("chart-1", <%= pghero_js_value(cpu_usage_path(path_options)) %>, {max: 100, colors: ["#5bc0de"], suffix: "%", library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
13
+ <% end %>
14
14
 
15
15
  <h1>Load</h1>
16
- <div id="chart-2" class="chart" style="margin-bottom: 20px;">Loading...</div>
17
- <script>
18
- new Chartkick.LineChart("chart-2", <%= json_escape(load_stats_path(path_options).to_json).html_safe %>, {colors: ["#5bc0de", "#d9534f"], library: {plugins: {tooltip: {intersect: false, mode: "nearest"}}}})
19
- </script>
16
+ <div id="chart-2" class="chart">Loading...</div>
17
+ <%= javascript_tag nonce: true do %>
18
+ new Chartkick.LineChart("chart-2", <%= pghero_js_value(load_stats_path(path_options)) %>, {colors: ["#5bc0de", "#d9534f"], library: {plugins: {tooltip: {intersect: false, mode: "nearest"}}}})
19
+ <% end %>
20
20
 
21
21
  <h1>Connections</h1>
22
- <div id="chart-3" class="chart" style="margin-bottom: 20px;">Loading...</div>
23
- <script>
24
- new Chartkick.LineChart("chart-3", <%= json_escape(connection_stats_path(path_options).to_json).html_safe %>, {colors: ["#5bc0de"], library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
25
- </script>
22
+ <div id="chart-3" class="chart">Loading...</div>
23
+ <%= javascript_tag nonce: true do %>
24
+ new Chartkick.LineChart("chart-3", <%= pghero_js_value(connection_stats_path(path_options)) %>, {colors: ["#5bc0de"], library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
25
+ <% end %>
26
26
 
27
27
  <% if @database.replica? %>
28
28
  <h1>Replication Lag</h1>
29
- <div id="chart-4" class="chart" style="margin-bottom: 20px;">Loading...</div>
30
- <script>
31
- new Chartkick.LineChart("chart-4", <%= json_escape(replication_lag_stats_path(path_options).to_json).html_safe %>, {colors: ["#5bc0de"], library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
32
- </script>
29
+ <div id="chart-4" class="chart">Loading...</div>
30
+ <%= javascript_tag nonce: true do %>
31
+ new Chartkick.LineChart("chart-4", <%= pghero_js_value(replication_lag_stats_path(path_options)) %>, {colors: ["#5bc0de"], library: {plugins: {tooltip: {intersect: false, mode: "index"}}}})
32
+ <% end %>
33
33
  <% end %>
34
34
  </div>
@@ -5,7 +5,7 @@
5
5
  <thead>
6
6
  <tr>
7
7
  <th>Setting</th>
8
- <th style="width: 20%;">Value</th>
8
+ <th class="width-20">Value</th>
9
9
  </tr>
10
10
  </thead>
11
11
  <tbody>
@@ -30,7 +30,7 @@
30
30
  <thead>
31
31
  <tr>
32
32
  <th>Setting</th>
33
- <th style="width: 20%;">Value</th>
33
+ <th class="width-20">Value</th>
34
34
  </tr>
35
35
  </thead>
36
36
  <tbody>
@@ -1,3 +1,4 @@
1
+ require "rails/generators"
1
2
  require "rails/generators/active_record"
2
3
 
3
4
  module Pghero
@@ -1,3 +1,4 @@
1
+ require "rails/generators"
1
2
  require "rails/generators/active_record"
2
3
 
3
4
  module Pghero
@@ -126,7 +126,7 @@ module PgHero
126
126
  # rough check for Postgres adapter
127
127
  # keep this message generic so it's useful
128
128
  # when empty url set in Docker image pghero.yml
129
- unless @connection_model.connection.adapter_name =~ /postg/i
129
+ unless @connection_model.connection_db_config.adapter.to_s.match?(/postg/i)
130
130
  raise Error, "Invalid connection URL"
131
131
  end
132
132
  @adapter_checked = true
@@ -145,7 +145,7 @@ module PgHero
145
145
  config_options = {env_name: PgHero.env, PgHero.spec_name_key => config["spec"], PgHero.include_replicas_key => true}
146
146
  resolved = ActiveRecord::Base.configurations.configs_for(**config_options)
147
147
  raise Error, "Spec not found: #{config["spec"]}" unless resolved
148
- url = ActiveRecord::VERSION::STRING.to_f >= 6.1 ? resolved.configuration_hash : resolved.config
148
+ url = resolved.configuration_hash
149
149
  end
150
150
 
151
151
  url = url.dup
data/lib/pghero/engine.rb CHANGED
@@ -4,8 +4,8 @@ module PgHero
4
4
 
5
5
  initializer "pghero", group: :all do |app|
6
6
  # check if Rails api mode
7
- if app.config.respond_to?(:assets)
8
- if defined?(Sprockets) && Sprockets::VERSION >= "4"
7
+ if app.config.respond_to?(:assets) && defined?(Sprockets)
8
+ if Sprockets::VERSION.to_i >= 4
9
9
  app.config.assets.precompile << "pghero/application.js"
10
10
  app.config.assets.precompile << "pghero/application.css"
11
11
  app.config.assets.precompile << "pghero/favicon.png"
@@ -17,7 +17,8 @@ module PgHero
17
17
  end
18
18
  end
19
19
 
20
- PgHero.time_zone = PgHero.config["time_zone"] if PgHero.config["time_zone"]
20
+ file_config = PgHero.file_config || {}
21
+ PgHero.time_zone = file_config["time_zone"] if file_config["time_zone"]
21
22
  end
22
23
  end
23
24
  end