redis_web_manager 0.1.6 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +2 -0
- data/.travis.yml +1 -0
- data/Gemfile.lock +23 -1
- data/README.md +95 -4
- data/Rakefile +1 -1
- data/app/controllers/redis_web_manager/actions_controller.rb +15 -3
- data/app/controllers/redis_web_manager/application_controller.rb +4 -0
- data/app/controllers/redis_web_manager/clients_controller.rb +1 -1
- data/app/controllers/redis_web_manager/configuration_controller.rb +1 -1
- data/app/controllers/redis_web_manager/dashboard_controller.rb +23 -3
- data/app/controllers/redis_web_manager/information_controller.rb +1 -1
- data/app/controllers/redis_web_manager/keys_controller.rb +135 -0
- data/app/helpers/redis_web_manager/application_helper.rb +16 -0
- data/app/helpers/redis_web_manager/dashboard_helper.rb +1 -1
- data/app/views/redis_web_manager/dashboard/index.html.erb +20 -1
- data/app/views/redis_web_manager/keys/edit.html.erb +14 -0
- data/app/views/redis_web_manager/keys/index.html.erb +54 -0
- data/app/views/redis_web_manager/keys/show.html.erb +30 -0
- data/app/views/redis_web_manager/shared/_header.html.erb +12 -2
- data/app/views/redis_web_manager/shared/_status.html.erb +2 -2
- data/bin/rails +1 -1
- data/config/routes.rb +8 -0
- data/lib/redis_web_manager.rb +1 -1
- data/lib/redis_web_manager/action.rb +1 -1
- data/lib/redis_web_manager/data.rb +16 -0
- data/lib/redis_web_manager/version.rb +1 -1
- data/redis_web_manager.gemspec +6 -4
- data/spec/controllers/redis_web_manager/actions_controller_spec.rb +16 -1
- data/spec/controllers/redis_web_manager/clients_controller_spec.rb +1 -1
- data/spec/controllers/redis_web_manager/keys_controller_spec.rb +139 -0
- data/spec/helpers/application_helper_spec.rb +13 -1
- data/spec/helpers/dashboard_helper_spec.rb +1 -1
- data/spec/redis_web_manager_data_spec.rb +23 -0
- data/spec/routing/actions_controller_spec.rb +6 -0
- data/spec/routing/keys_controller_spec.rb +39 -0
- data/spec/spec_helper.rb +6 -0
- metadata +295 -342
@@ -2,6 +2,22 @@
|
|
2
2
|
|
3
3
|
module RedisWebManager
|
4
4
|
module ApplicationHelper
|
5
|
+
require 'pagy'
|
6
|
+
|
7
|
+
include ::Pagy::Frontend
|
8
|
+
|
9
|
+
def status(value)
|
10
|
+
if value
|
11
|
+
content_tag(:kbd, 'ON', class: 'bg-success bounce')
|
12
|
+
else
|
13
|
+
content_tag(:kbd, 'OFF', class: 'bg-danger bounce')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def url(value)
|
18
|
+
content_tag(:kbd, value, class: 'bg-dark')
|
19
|
+
end
|
20
|
+
|
5
21
|
def expire(value)
|
6
22
|
if value == -1
|
7
23
|
'No expiration date'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<div class="container">
|
2
2
|
<%= render 'redis_web_manager/shared/status' %>
|
3
3
|
<div class="row my-4">
|
4
|
-
<div class="col-sm-12 col-md-
|
4
|
+
<div class="col-sm-12 col-md-9">
|
5
5
|
<div class="row mb-4">
|
6
6
|
<div class="col-12">
|
7
7
|
<div class="card">
|
@@ -45,5 +45,24 @@
|
|
45
45
|
</div>
|
46
46
|
</div>
|
47
47
|
</div>
|
48
|
+
<div class="col-sm-12 col-md-3">
|
49
|
+
<div class="card">
|
50
|
+
<div class="card-header">
|
51
|
+
<h5 class="card-title mb-0">
|
52
|
+
Information
|
53
|
+
</h5>
|
54
|
+
</div>
|
55
|
+
<div class="card-body p-0">
|
56
|
+
<ul class="list-group list-group-flush">
|
57
|
+
<% @information.each do |data| %>
|
58
|
+
<li class="list-group-item d-flex justify-content-between">
|
59
|
+
<div class="font-weight-normal"><%= data[:name] %></div>
|
60
|
+
<div class="font-weight-light"><%= data[:value] %></div>
|
61
|
+
</li>
|
62
|
+
<% end %>
|
63
|
+
</ul>
|
64
|
+
</div>
|
65
|
+
</div>
|
66
|
+
</div>
|
48
67
|
</div>
|
49
68
|
</div>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<div class="row my-4">
|
3
|
+
<div class="col-sm-6 offset-sm-3">
|
4
|
+
<%= form_tag update_key_path, method: :put, class: "form-horizontal center" do %>
|
5
|
+
<div class="form-group">
|
6
|
+
<%= label_tag :key, "Name key:", class: "control-label" %>
|
7
|
+
<%= text_field_tag :key, @key[:key], class: "form-control" %>
|
8
|
+
<%= hidden_field_tag :old_key, @key[:key] %>
|
9
|
+
</div>
|
10
|
+
<%= submit_tag "Submit", class: "btn btn-default btn-primary" %>
|
11
|
+
<% end %>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</div>
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<%= render 'redis_web_manager/shared/status' %>
|
3
|
+
<div class="row my-4">
|
4
|
+
<div class="col-12">
|
5
|
+
<div class="card">
|
6
|
+
<div class="card-header">
|
7
|
+
<h5 class="card-title mb-0">
|
8
|
+
Keys
|
9
|
+
</h5>
|
10
|
+
</div>
|
11
|
+
<div class="card-body p-0">
|
12
|
+
<%= form_tag(keys_path, method: :get, class: 'p-4', enforce_utf8: false) do %>
|
13
|
+
<div class="input-group">
|
14
|
+
<%= text_field_tag :query, params[:query], class: 'form-control', placeholder: 'Search key(s)' %>
|
15
|
+
<div class="input-group-append">
|
16
|
+
<%= submit_tag 'Search', class: 'btn btn-primary', name: nil %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
<% end %>
|
20
|
+
<div class="table-responsive">
|
21
|
+
<table class="table mb-0">
|
22
|
+
<thead>
|
23
|
+
<tr>
|
24
|
+
<th>Name</th>
|
25
|
+
<th>Expiration Date</th>
|
26
|
+
<th>Size</th>
|
27
|
+
<th>Type</th>
|
28
|
+
<th>Options</th>
|
29
|
+
</tr>
|
30
|
+
</thead>
|
31
|
+
<tbody>
|
32
|
+
<% @keys.each do |key| %>
|
33
|
+
<tr>
|
34
|
+
<td><%= link_to (key[:key]).truncate(45), key_path(key: key[:key]), title: "Show #{key[:key]}" %></td>
|
35
|
+
<td><%= expire(key[:expire]) %></td>
|
36
|
+
<td><code><%= number_to_human_size(key[:memory]) %></code></td>
|
37
|
+
<td><kbd class="bg-dark"><%= key[:type] %></kbd></td>
|
38
|
+
<td>
|
39
|
+
<%= link_to 'Edit', edit_key_path(key: key[:key]), title: "Edit #{key[:key]}", class: 'btn btn-sm btn-primary ml-2' %>
|
40
|
+
<%= link_to 'Delete', destroy_key_path(key: key[:key]), method: :delete, data: {confirm: 'Are you sure ?'}, title: "Delete #{key[:key]}", class: 'btn btn-sm btn-danger ml-2' %>
|
41
|
+
</td>
|
42
|
+
</tr>
|
43
|
+
<% end %>
|
44
|
+
</tbody>
|
45
|
+
</table>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
<div class="d-flex align-items-center justify-content-center mt-3">
|
50
|
+
<%= pagy_bootstrap_nav(@pagy).html_safe %>
|
51
|
+
</div>
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
</div>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<div class="container mt-4">
|
2
|
+
<div class="row">
|
3
|
+
<div class="col-12">
|
4
|
+
<label class="font-weight-normal">Key:</label>
|
5
|
+
<p class="font-weight-light">
|
6
|
+
<code><%= @key[:key] %></code>
|
7
|
+
</p>
|
8
|
+
<label class="font-weight-normal">Value:</label>
|
9
|
+
<p class="font-weight-light">
|
10
|
+
<code><%= @key[:node][:value] %></code>
|
11
|
+
</p>
|
12
|
+
<label class="font-weight-normal">Expires in:</label>
|
13
|
+
<p class="font-weight-light">
|
14
|
+
<%= expire(@key[:expire]) %>
|
15
|
+
</p>
|
16
|
+
<label class="font-weight-normal">Size:</label>
|
17
|
+
<p class="font-weight-light">
|
18
|
+
<code><%= number_to_human_size(@key[:memory]) %></code>
|
19
|
+
</p>
|
20
|
+
<label class="font-weight-normal">Type:</label>
|
21
|
+
<p class="font-weight-light">
|
22
|
+
<kbd class="bg-dark"><%= @key[:type] %></kbd>
|
23
|
+
</p>
|
24
|
+
<p class="font-weight-light">
|
25
|
+
<%= link_to 'Delete', destroy_key_path(key: @key[:key]), method: :delete, data: {confirm: 'Are you sure ?'}, title: "Delete #{@key}", class: 'btn btn-sm btn-danger w-100 mb-2' %>
|
26
|
+
<%= link_to 'Back', keys_path, title: 'View keys', class: 'btn btn-sm btn-primary w-100' %>
|
27
|
+
</p>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</div>
|
@@ -23,15 +23,25 @@
|
|
23
23
|
</li>
|
24
24
|
</ul>
|
25
25
|
<ul class="navbar-nav ml-auto">
|
26
|
+
<li class="nav-item">
|
27
|
+
<%= link_to 'Reset statistics',
|
28
|
+
reset_path,
|
29
|
+
title: 'Reset statistics',
|
30
|
+
method: :delete,
|
31
|
+
data: {
|
32
|
+
confirm: 'Are you sure you want to reset statistics ?'
|
33
|
+
},
|
34
|
+
class: 'btn btn-sm btn-info nav-link text-white mr-xs-0 mr-lg-2 mb-2 mb-lg-0' %>
|
35
|
+
</li>
|
26
36
|
<li class="nav-item">
|
27
37
|
<%= link_to 'Flush ALL',
|
28
|
-
|
38
|
+
flushall_path,
|
29
39
|
title: 'Flush ALL',
|
30
40
|
method: :delete,
|
31
41
|
data: {
|
32
42
|
confirm: 'Are you sure you want to flush all DB ?'
|
33
43
|
},
|
34
|
-
class: 'btn btn-sm btn-
|
44
|
+
class: 'btn btn-sm btn-dark nav-link text-white mr-xs-0 mr-lg-2 mb-2 mb-lg-0' %>
|
35
45
|
</li>
|
36
46
|
<li class="nav-item">
|
37
47
|
<%= link_to 'Flush DB',
|
data/bin/rails
CHANGED
data/config/routes.rb
CHANGED
@@ -7,10 +7,18 @@ RedisWebManager::Engine.routes.draw do
|
|
7
7
|
# Information
|
8
8
|
get :information, to: 'information#index'
|
9
9
|
|
10
|
+
# Keys
|
11
|
+
get 'keys' => 'keys#index'
|
12
|
+
get 'key' => 'keys#show'
|
13
|
+
get 'key/edit' => 'keys#edit', as: :edit_key
|
14
|
+
put 'keys' => 'keys#update', as: :update_key
|
15
|
+
delete 'keys' => 'keys#destroy', as: :destroy_key
|
16
|
+
|
10
17
|
# Clients
|
11
18
|
get :clients, to: 'clients#index'
|
12
19
|
|
13
20
|
# Actions
|
21
|
+
delete :reset, to: 'actions#reset'
|
14
22
|
delete :flushdb, to: 'actions#flushdb'
|
15
23
|
delete :flushall, to: 'actions#flushall'
|
16
24
|
|
data/lib/redis_web_manager.rb
CHANGED
@@ -10,8 +10,8 @@ require 'redis'
|
|
10
10
|
|
11
11
|
module RedisWebManager
|
12
12
|
mattr_accessor :redis, default: ::Redis.new
|
13
|
-
mattr_accessor :authenticate, default: nil
|
14
13
|
mattr_accessor :lifespan, default: 15.days
|
14
|
+
mattr_accessor :authenticate, default: nil
|
15
15
|
|
16
16
|
class << self
|
17
17
|
def configure
|
@@ -4,14 +4,30 @@ module RedisWebManager
|
|
4
4
|
class Data < Base
|
5
5
|
BASE = 'RedisWebManager'
|
6
6
|
|
7
|
+
def keys
|
8
|
+
data.map { |key| JSON.parse(redis.get(key), symbolize_names: true) }
|
9
|
+
end
|
10
|
+
|
7
11
|
def perform
|
8
12
|
now = Time.now.to_i
|
9
13
|
seconds = (now + lifespan.to_i) - now
|
10
14
|
redis.setex("#{BASE}_#{now}", seconds, serialize.to_json)
|
11
15
|
end
|
12
16
|
|
17
|
+
def flush
|
18
|
+
data.map { |key| redis.del(key) }
|
19
|
+
end
|
20
|
+
|
13
21
|
private
|
14
22
|
|
23
|
+
def data
|
24
|
+
@data ||= redis.scan_each(match: "#{BASE}_*").to_a
|
25
|
+
end
|
26
|
+
|
27
|
+
def lifespan
|
28
|
+
@lifespan ||= RedisWebManager.lifespan
|
29
|
+
end
|
30
|
+
|
15
31
|
def serialize
|
16
32
|
{
|
17
33
|
date: Time.now,
|
data/redis_web_manager.gemspec
CHANGED
@@ -10,11 +10,10 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.name = 'redis_web_manager'
|
11
11
|
spec.version = RedisWebManager::VERSION
|
12
12
|
|
13
|
-
spec.authors = ['Boris BRESCIANI', 'Benjamin DARCET', 'Olivier DUMAS'
|
13
|
+
spec.authors = ['Boris BRESCIANI', 'Benjamin DARCET', 'Olivier DUMAS']
|
14
14
|
spec.email = %w[boris2bresciani@gmail.com
|
15
15
|
b.darcet@gmail.com
|
16
|
-
dumas.olivier@outlook.fr
|
17
|
-
sylvain.kraisin@gmail.com]
|
16
|
+
dumas.olivier@outlook.fr]
|
18
17
|
|
19
18
|
spec.summary = 'Manage your Redis instance (See keys, memory used, connected client, etc...)'
|
20
19
|
spec.description = 'Manage your Redis instance (See keys, memory used, connected client, configuration, information)'
|
@@ -35,8 +34,11 @@ Gem::Specification.new do |spec|
|
|
35
34
|
spec.require_paths = ['lib']
|
36
35
|
spec.test_files = Dir['spec/**/*']
|
37
36
|
|
37
|
+
spec.add_development_dependency 'coveralls', '~> 0.8'
|
38
38
|
spec.add_development_dependency 'rspec-rails', '= 4.0.0.beta3'
|
39
|
+
spec.add_development_dependency 'simplecov', '~> 0.16'
|
39
40
|
|
41
|
+
spec.add_dependency 'pagy', '~> 3.7'
|
40
42
|
spec.add_dependency 'rails', '>= 5.2', '< 7'
|
41
43
|
spec.add_dependency 'redis', '~> 4.1.0'
|
42
|
-
end
|
44
|
+
end
|
@@ -5,9 +5,24 @@ require 'rails_helper'
|
|
5
5
|
RSpec.describe RedisWebManager::ActionsController, type: :controller do
|
6
6
|
routes { RedisWebManager::Engine.routes }
|
7
7
|
|
8
|
+
describe 'DELETE #reset' do
|
9
|
+
it 'returns a success response' do
|
10
|
+
delete :reset
|
11
|
+
expect(response).to be_redirect
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
8
15
|
describe 'DELETE #flushdb' do
|
16
|
+
it 'returns a success response' do
|
17
|
+
delete :flushdb
|
18
|
+
expect(response).to be_redirect
|
19
|
+
end
|
9
20
|
end
|
10
21
|
|
11
22
|
describe 'DELETE #flushall' do
|
23
|
+
it 'returns a success response' do
|
24
|
+
delete :flushall
|
25
|
+
expect(response).to be_redirect
|
26
|
+
end
|
12
27
|
end
|
13
|
-
end
|
28
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe RedisWebManager::KeysController, type: :controller do
|
6
|
+
routes { RedisWebManager::Engine.routes }
|
7
|
+
let(:redis) do
|
8
|
+
::Redis.new
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'GET #index' do
|
12
|
+
it 'returns a success response' do
|
13
|
+
get :index
|
14
|
+
expect(response).to be_successful
|
15
|
+
get :index, params: { query: 'Search' }
|
16
|
+
expect(response).to be_successful
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'GET #show' do
|
21
|
+
it 'returns a success response' do
|
22
|
+
redis.set('test', 'test')
|
23
|
+
get :show, params: { key: 'test' }
|
24
|
+
expect(response).to be_successful
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'GET #edit' do
|
29
|
+
it 'returns a success response' do
|
30
|
+
redis.set('test', 'test')
|
31
|
+
get :edit, params: { key: 'test' }
|
32
|
+
expect(response).to be_successful
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'GET #update' do
|
37
|
+
it 'returns a success response' do
|
38
|
+
redis.set('test', 'test')
|
39
|
+
put :update, params: { old_name: 'test', new_name: 'testtest' }
|
40
|
+
expect(response).to be_redirect
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'GET #destroy' do
|
45
|
+
it 'returns a success response' do
|
46
|
+
redis.set('test', 'test')
|
47
|
+
delete :destroy, params: { key: 'test' }
|
48
|
+
expect(response).to be_redirect
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'Methods' do
|
53
|
+
it 'returns a hash value (get_value - string)' do
|
54
|
+
redis.set('test', 'test')
|
55
|
+
eql = {
|
56
|
+
value: 'test'
|
57
|
+
}
|
58
|
+
expect(controller.send(:get_value, 'test')).to eql(eql)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns a hash value (get_value - hgetall)' do
|
62
|
+
eql = {
|
63
|
+
value: {
|
64
|
+
'name' => {
|
65
|
+
type: 'string',
|
66
|
+
value: 'hgetall'
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
redis.hset('hgetall', 'name', 'hgetall')
|
71
|
+
expect(controller.send(:get_value, 'hgetall')).to eql(eql)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'returns a hash value (get_value - lrange)' do
|
75
|
+
redis.lpush('lrange', '1')
|
76
|
+
redis.lpush('lrange', '2')
|
77
|
+
eql = {
|
78
|
+
length: 2,
|
79
|
+
values: [
|
80
|
+
{
|
81
|
+
index: 0,
|
82
|
+
type: 'json',
|
83
|
+
value: 2
|
84
|
+
},
|
85
|
+
{
|
86
|
+
index: 1,
|
87
|
+
type: 'json',
|
88
|
+
value: 1
|
89
|
+
}
|
90
|
+
]
|
91
|
+
}
|
92
|
+
expect(controller.send(:get_value, 'lrange')).to eql(eql)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns a hash value (get_value - set)' do
|
96
|
+
redis.sadd('smembers', 'smembers')
|
97
|
+
eql = {
|
98
|
+
values: [{ type: 'string', value: 'smembers' }]
|
99
|
+
}
|
100
|
+
expect(controller.send(:get_value, 'smembers')).to eql(eql)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'returns a hash value (get_value - zset)' do
|
104
|
+
redis.zadd('zrange', 10, '1')
|
105
|
+
redis.zadd('zrange', 20, '2')
|
106
|
+
redis.zadd('zrange', 30, '3')
|
107
|
+
eql = {
|
108
|
+
values: [
|
109
|
+
{
|
110
|
+
score: 10.0,
|
111
|
+
type: 'json',
|
112
|
+
value: 1
|
113
|
+
},
|
114
|
+
{
|
115
|
+
score: 20.0,
|
116
|
+
type: 'json',
|
117
|
+
value: 2
|
118
|
+
},
|
119
|
+
{
|
120
|
+
score: 30.0,
|
121
|
+
type: 'json',
|
122
|
+
value: 3
|
123
|
+
}
|
124
|
+
]
|
125
|
+
}
|
126
|
+
expect(controller.send(:get_value, 'zrange')).to eql(eql)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'returns a hash value (get_value - not found)' do
|
130
|
+
redis.zadd('zrange', 10, '1')
|
131
|
+
redis.zadd('zrange', 20, '2')
|
132
|
+
redis.zadd('zrange', 30, '3')
|
133
|
+
eql = {
|
134
|
+
value: 'Not found'
|
135
|
+
}
|
136
|
+
expect(controller.send(:get_value, 'testtesttesttesttest')).to eql(eql)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|