rails-pg-extras-web 1.6.0 → 3.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.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/app/controllers/rails_pg_extras_web/actions_controller.rb +26 -0
- data/app/controllers/rails_pg_extras_web/application_controller.rb +9 -0
- data/app/controllers/rails_pg_extras_web/queries_controller.rb +19 -26
- data/app/views/layouts/rails_pg_extras_web/application.html.erb +20 -13
- data/app/views/rails_pg_extras_web/queries/_diagnose.html.erb +9 -0
- data/app/views/rails_pg_extras_web/queries/_result.html.erb +21 -0
- data/app/views/rails_pg_extras_web/queries/_unavailable_extensions_warning.html.erb +13 -0
- data/app/views/rails_pg_extras_web/queries/index.html.erb +21 -72
- data/app/views/rails_pg_extras_web/queries/show.html.erb +24 -0
- data/app/views/rails_pg_extras_web/shared/_queries_selector.html.erb +11 -0
- data/config/routes.rb +5 -1
- data/lib/rails_pg_extras_web/version.rb +1 -1
- metadata +14 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ca457b8f7491e7b1eab0a053ec0fd563db431209718b40203a121dc31ecf453
|
4
|
+
data.tar.gz: aa628d82e9b6858f565ea0b6fbb57c4c945706e684ba9c9e85530bbaf728fa69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70c68e56d0f99bb4511b23ac98d246e381e67634b751f02b6c6e57906ca8efd9a6c07861c75cb15a043fb8654d89c1a991ec9288b1cd07a087e9eefcbc45eecd
|
7
|
+
data.tar.gz: d9d877137d79912412c3d7885e8b49bdf1d4a3ad0024d37908f99dc4567de864ab963359ee9158288a2ece7b82e6444d78cd9eb7c1a9468a4467578522b3e12b
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# RailsPgExtrasWeb
|
2
|
-
Web UI for rails-pg-extras-
|
2
|
+
Web UI for [rails-pg-extras](https://github.com/pawurb/rails-pg-extras)
|
3
|
+
|
4
|
+

|
3
5
|
|
4
6
|
## Installation
|
5
7
|
Add this line to your application's Gemfile:
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RailsPgExtrasWeb
|
2
|
+
class ActionsController < ApplicationController
|
3
|
+
def kill_all
|
4
|
+
run(:kill_all)
|
5
|
+
end
|
6
|
+
|
7
|
+
def pg_stat_statements_reset
|
8
|
+
run(:pg_stat_statements_reset)
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_extensions
|
12
|
+
run(:add_extensions)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def run(action)
|
18
|
+
begin
|
19
|
+
RailsPGExtras.run_query(query_name: action, in_format: :raw)
|
20
|
+
redirect_to root_path, notice: "Successfully ran #{action}"
|
21
|
+
rescue ActiveRecord::StatementInvalid => e
|
22
|
+
redirect_to root_path, alert: "Error: #{e.message}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,9 +1,18 @@
|
|
1
1
|
require "rails-pg-extras"
|
2
|
+
require "rails-pg-extras/version"
|
2
3
|
|
3
4
|
module RailsPgExtrasWeb
|
4
5
|
class ApplicationController < ActionController::Base
|
5
6
|
layout "rails_pg_extras_web/application"
|
6
7
|
|
8
|
+
REQUIRED_EXTENSIONS = {
|
9
|
+
pg_stat_statements: %i[calls outliers pg_stat_statements_reset],
|
10
|
+
pg_buffercache: %i[buffercache_stats buffercache_usage],
|
11
|
+
sslinfo: %i[ssl_used]
|
12
|
+
}
|
13
|
+
|
14
|
+
ACTIONS = %i[kill_all pg_stat_statements_reset add_extensions]
|
15
|
+
|
7
16
|
if Rails.env.production? && ENV['PG_EXTRAS_USER'].present? && ENV['PG_EXTRAS_PASSWORD'].present?
|
8
17
|
http_basic_authenticate_with name: ENV['PG_EXTRAS_USER'], password: ENV['PG_EXTRAS_PASSWORD']
|
9
18
|
end
|
@@ -1,51 +1,44 @@
|
|
1
1
|
module RailsPgExtrasWeb
|
2
2
|
class QueriesController < ApplicationController
|
3
|
-
REQUIRED_EXTENSIONS = {
|
4
|
-
pg_stat_statements: %i[calls outliers],
|
5
|
-
pg_buffercache: %i[buffercache_stats buffercache_usage]
|
6
|
-
}
|
7
|
-
|
8
3
|
before_action :load_queries
|
9
4
|
helper_method :unavailable_extensions
|
10
5
|
|
11
6
|
def index
|
12
|
-
|
13
|
-
|
7
|
+
if params[:query_name].present?
|
8
|
+
@query_name = params[:query_name].to_sym.presence_in(@all_queries.keys)
|
9
|
+
return unless @query_name
|
10
|
+
|
11
|
+
begin
|
12
|
+
@result = RailsPGExtras.run_query(query_name: @query_name.to_sym, in_format: :raw)
|
13
|
+
rescue ActiveRecord::StatementInvalid => e
|
14
|
+
@error = e.message
|
15
|
+
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
@error = e.message
|
17
|
+
render :show
|
18
|
+
end
|
18
19
|
end
|
19
20
|
|
20
21
|
private
|
21
22
|
|
22
23
|
def load_queries
|
23
|
-
@all_queries = {}
|
24
|
+
@all_queries = (RailsPGExtras::QUERIES - ACTIONS).inject({}) do |memo, query_name|
|
25
|
+
unless query_name.in? %i[mandelbrot]
|
26
|
+
memo[query_name] = { disabled: query_disabled?(query_name) }
|
27
|
+
end
|
24
28
|
|
25
|
-
|
26
|
-
@all_queries[query_name] = {
|
27
|
-
disabled: query_disabled?(query_name),
|
28
|
-
command: query_name == :kill_all
|
29
|
-
}
|
29
|
+
memo
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
def query_disabled?(query_name)
|
34
|
-
|
35
|
-
when :calls, :outliers
|
36
|
-
unavailable_extensions.key?(:pg_stat_statements)
|
37
|
-
when :buffercache_stats, :buffercache_usage
|
38
|
-
unavailable_extensions.key?(:pg_buffercache)
|
39
|
-
else
|
40
|
-
false
|
41
|
-
end
|
34
|
+
unavailable_extensions.values.flatten.include?(query_name)
|
42
35
|
end
|
43
36
|
|
44
37
|
def unavailable_extensions
|
45
38
|
return @unavailable_extensions if defined?(@unavailable_extensions)
|
46
39
|
|
47
|
-
|
48
|
-
@unavailable_extensions = REQUIRED_EXTENSIONS.
|
40
|
+
enabled_extensions = ActiveRecord::Base.connection.extensions
|
41
|
+
@unavailable_extensions = REQUIRED_EXTENSIONS.delete_if { |ext| ext.to_s.in?(enabled_extensions) }
|
49
42
|
end
|
50
43
|
end
|
51
44
|
end
|
@@ -1,19 +1,26 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
|
-
<head>
|
4
|
-
|
5
|
-
|
6
|
-
<
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
%>
|
3
|
+
<head>
|
4
|
+
<title><%= content_for :title %> | v<%= RailsPGExtras::VERSION %></title>
|
5
|
+
<%= javascript_include_tag "https://unpkg.com/@rails/ujs" %>
|
6
|
+
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body class="p-5 text-xs">
|
10
|
+
<% if flash[:notice] %>
|
11
|
+
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-4" role="alert">
|
12
|
+
<p class="font-bold">Notice</p>
|
13
|
+
<p><%= flash[:notice] %></p>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
11
16
|
|
12
|
-
|
13
|
-
|
17
|
+
<% if flash[:alert] %>
|
18
|
+
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4" role="alert">
|
19
|
+
<p class="font-bold">Alert</p>
|
20
|
+
<p><%= flash[:alert] %></p>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
14
23
|
|
15
|
-
<div style='margin-top: 20px'>
|
16
24
|
<%= yield %>
|
17
|
-
</
|
18
|
-
</body>
|
25
|
+
</body>
|
19
26
|
</html>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<h1 class="font-bold text-xl my-5">Diagnose</h1>
|
2
|
+
<table class="w-full font-mono border-collapse border my-5">
|
3
|
+
<% RailsPGExtras.diagnose(in_format: :hash).each do |diagnosis| %>
|
4
|
+
<tr class="<%= diagnosis[:ok] ? 'bg-green-300' : 'bg-red-300' %>">
|
5
|
+
<td class='p-1 border font-bold'><%= diagnosis[:check_name] %></td>
|
6
|
+
<td class='p-1 border'><%= diagnosis[:message] %></td>
|
7
|
+
</tr>
|
8
|
+
<% end %>
|
9
|
+
</table>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<h1 class="font-bold text-xl my-5"><%= title %></h1>
|
2
|
+
|
3
|
+
<table class="w-full font-mono border-collapse border my-5">
|
4
|
+
<thead>
|
5
|
+
<tr class="bg-gray-300">
|
6
|
+
<% headers.each do |header| %>
|
7
|
+
<th class="p-2 border text-left"><%= header %></th>
|
8
|
+
<% end %>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<tbody>
|
12
|
+
<% rows.each.with_index do |row, i| %>
|
13
|
+
<tr class="hover:bg-gray-400 hover:text-white <%= i.even? ? "bg-gray-100" : "bg-gray-200" %>">
|
14
|
+
<% row.each do |column| %>
|
15
|
+
<td class="p-1 border"><%= column %></td>
|
16
|
+
<% end %>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
</tbody>
|
20
|
+
</table>
|
21
|
+
<span class="italic">run_at: <%= Time.now.utc %></span>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<div class="text-red-500 p-3 font-mono my-5">
|
2
|
+
<% unavailable_extensions.each do |extension, queries| %>
|
3
|
+
WARNING: Queries <%= queries.map { |q| "<b><u>#{q}</u></b>" }.join(", ").html_safe %> require extension: <b><%= extension %></b>
|
4
|
+
<br>
|
5
|
+
<% end %>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<%= link_to "Enable extensions", add_extensions_action_path,
|
9
|
+
method: "post",
|
10
|
+
data: {
|
11
|
+
confirm: "This command will enable following extensions: #{unavailable_extensions.keys.join(', ')}. Do you want to proceeed?"
|
12
|
+
}, class: 'border p-3 bg-green-500 text-white hover:bg-green-600 font-bold rounded' %>
|
13
|
+
|
@@ -1,72 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
<% @result[0].keys.each do |header| %>
|
23
|
-
<th><%= header %></th>
|
24
|
-
<% end %>
|
25
|
-
</tr>
|
26
|
-
</thead>
|
27
|
-
<tbody>
|
28
|
-
<% @result.values.each do |row| %>
|
29
|
-
<tr>
|
30
|
-
<% row.each do |column| %>
|
31
|
-
<td><%= column %></td>
|
32
|
-
<% end %>
|
33
|
-
</tr>
|
34
|
-
<% end %>
|
35
|
-
</tbody>
|
36
|
-
</table>
|
37
|
-
|
38
|
-
<pre>run_at: <%= Time.now.utc %></pre>
|
39
|
-
<% else %>
|
40
|
-
<pre>No results</pre>
|
41
|
-
<% end %>
|
42
|
-
<% end %>
|
43
|
-
|
44
|
-
<style media="screen">
|
45
|
-
table {
|
46
|
-
font-family: monospace;
|
47
|
-
border-collapse: collapse;
|
48
|
-
width: 100%;
|
49
|
-
}
|
50
|
-
|
51
|
-
table th {
|
52
|
-
background-color: #c9c9;
|
53
|
-
}
|
54
|
-
|
55
|
-
table th, table td {
|
56
|
-
text-align: left;
|
57
|
-
border: 1px solid #c9c9;
|
58
|
-
padding: 3px;
|
59
|
-
}
|
60
|
-
|
61
|
-
table td {
|
62
|
-
overflow: hidden;
|
63
|
-
text-overflow: ellipsis;
|
64
|
-
white-space: nowrap;
|
65
|
-
}
|
66
|
-
|
67
|
-
table caption {
|
68
|
-
padding: 5px;
|
69
|
-
font-size: 15px;
|
70
|
-
font-weight: bold;
|
71
|
-
}
|
72
|
-
</style>
|
1
|
+
<%= content_for :title, "pg_extras" %>
|
2
|
+
<%= render "rails_pg_extras_web/shared/queries_selector" %>
|
3
|
+
<%= render "unavailable_extensions_warning" if unavailable_extensions.any? %>
|
4
|
+
<%= render "diagnose" if unavailable_extensions.none? %>
|
5
|
+
|
6
|
+
<h1 class="font-bold text-xl my-5">Actions</h1>
|
7
|
+
|
8
|
+
<%= link_to "kill_all", kill_all_action_path,
|
9
|
+
method: "post",
|
10
|
+
data: {
|
11
|
+
confirm: "This commands kills all the currently active connections to the database. Do you want to proceed?"
|
12
|
+
},
|
13
|
+
class: 'border p-3 bg-red-500 text-white hover:bg-red-600 font-bold rounded'
|
14
|
+
%>
|
15
|
+
|
16
|
+
<%= link_to "pg_stat_statements_reset", pg_stat_statements_reset_action_path,
|
17
|
+
method: "post",
|
18
|
+
data: {
|
19
|
+
confirm: "This command discards all statistics gathered so far by pg_stat_statements. Do you want to proceed?"
|
20
|
+
}, class: 'border p-3 bg-blue-500 text-white hover:bg-blue-600 font-bold rounded'
|
21
|
+
%>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<%= content_for :title, params[:query_name].presence || "pg_extras" %>
|
2
|
+
<%= render "rails_pg_extras_web/shared/queries_selector" %>
|
3
|
+
|
4
|
+
<% if @error %>
|
5
|
+
<div class="text-red-500 p-3 font-mono my-5"><%= @error %></div>
|
6
|
+
<% else %>
|
7
|
+
<% if @result&.any? %>
|
8
|
+
<%= render "result",
|
9
|
+
title: RubyPGExtras.description_for(query_name: @query_name),
|
10
|
+
headers: @result[0].keys,
|
11
|
+
rows: @result.values
|
12
|
+
%>
|
13
|
+
<% else %>
|
14
|
+
<div class="font-mono p-3 bg-gray-100 mt-3">No results</div>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
17
|
+
|
18
|
+
<style>
|
19
|
+
@media print {
|
20
|
+
form {
|
21
|
+
display: none
|
22
|
+
}
|
23
|
+
}
|
24
|
+
</style>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<%= form_with url: queries_path, id: "queries", method: :get do |f| %>
|
2
|
+
<%= f.select :query_name, options_for_select(@all_queries, params[:query_name]),
|
3
|
+
{prompt: "--- select query ---"},
|
4
|
+
{class: "border p-2 font-bold", autofocus: true}
|
5
|
+
%>
|
6
|
+
<% end %>
|
7
|
+
<script>
|
8
|
+
document.getElementById('queries').addEventListener('change', (e) => {
|
9
|
+
e.target.form.submit()
|
10
|
+
})
|
11
|
+
</script>
|
data/config/routes.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
RailsPgExtrasWeb::Engine.routes.draw do
|
2
|
-
resources :queries, only: :index
|
2
|
+
resources :queries, only: [:index]
|
3
|
+
|
4
|
+
post "/actions/kill_all" => "actions#kill_all", as: :kill_all_action
|
5
|
+
post "/actions/pg_stat_statements_reset" => "actions#pg_stat_statements_reset", as: :pg_stat_statements_reset_action
|
6
|
+
post "/actions/add_extensions" => "actions#add_extensions", as: :add_extensions_action
|
3
7
|
|
4
8
|
root to: "queries#index"
|
5
9
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-pg-extras-web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomasz Mazur
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -30,15 +30,15 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1
|
33
|
+
version: '3.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 1
|
41
|
-
description:
|
40
|
+
version: '3.1'
|
41
|
+
description:
|
42
42
|
email:
|
43
43
|
- tomasz.mazur@hey.com
|
44
44
|
executables: []
|
@@ -48,10 +48,16 @@ files:
|
|
48
48
|
- MIT-LICENSE
|
49
49
|
- README.md
|
50
50
|
- Rakefile
|
51
|
+
- app/controllers/rails_pg_extras_web/actions_controller.rb
|
51
52
|
- app/controllers/rails_pg_extras_web/application_controller.rb
|
52
53
|
- app/controllers/rails_pg_extras_web/queries_controller.rb
|
53
54
|
- app/views/layouts/rails_pg_extras_web/application.html.erb
|
55
|
+
- app/views/rails_pg_extras_web/queries/_diagnose.html.erb
|
56
|
+
- app/views/rails_pg_extras_web/queries/_result.html.erb
|
57
|
+
- app/views/rails_pg_extras_web/queries/_unavailable_extensions_warning.html.erb
|
54
58
|
- app/views/rails_pg_extras_web/queries/index.html.erb
|
59
|
+
- app/views/rails_pg_extras_web/queries/show.html.erb
|
60
|
+
- app/views/rails_pg_extras_web/shared/_queries_selector.html.erb
|
55
61
|
- config/routes.rb
|
56
62
|
- lib/rails-pg-extras-web.rb
|
57
63
|
- lib/rails_pg_extras_web/engine.rb
|
@@ -60,7 +66,7 @@ homepage: https://github.com/defkode/rails-pg-extras-web
|
|
60
66
|
licenses:
|
61
67
|
- MIT
|
62
68
|
metadata: {}
|
63
|
-
post_install_message:
|
69
|
+
post_install_message:
|
64
70
|
rdoc_options: []
|
65
71
|
require_paths:
|
66
72
|
- lib
|
@@ -76,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
82
|
version: '0'
|
77
83
|
requirements: []
|
78
84
|
rubygems_version: 3.1.6
|
79
|
-
signing_key:
|
85
|
+
signing_key:
|
80
86
|
specification_version: 4
|
81
87
|
summary: Web UI for rails-pg-extras
|
82
88
|
test_files: []
|