mongo_browser 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.
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.travis.yml +12 -0
- data/Gemfile +19 -0
- data/LICENSE +22 -0
- data/README.md +31 -0
- data/README.rdoc +19 -0
- data/Rakefile +61 -0
- data/app/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
- data/app/assets/images/bootstrap/glyphicons-halflings.png +0 -0
- data/app/assets/javascripts/app/table_filter.js.coffee +50 -0
- data/app/assets/javascripts/application.js.coffee +32 -0
- data/app/assets/javascripts/vendor/bootbox.js +508 -0
- data/app/assets/javascripts/vendor/bootstrap.js +2025 -0
- data/app/assets/javascripts/vendor/jquery.js +9266 -0
- data/app/assets/stylesheets/application.css.scss +22 -0
- data/app/assets/stylesheets/vendor/bootstrap-responsive.css +1088 -0
- data/app/assets/stylesheets/vendor/bootstrap.css +5893 -0
- data/app/views/collections/show.erb +61 -0
- data/app/views/databases/show.erb +59 -0
- data/app/views/index.erb +29 -0
- data/app/views/layout.erb +19 -0
- data/app/views/layout/_breadcrumb.erb +13 -0
- data/app/views/layout/_flash_messages.erb +10 -0
- data/app/views/layout/_navbar.erb +21 -0
- data/app/views/server_info.erb +20 -0
- data/app/views/shared/_filter.erb +14 -0
- data/bin/mongo_browser +53 -0
- data/config.ru +4 -0
- data/features/mongo_browser.feature +18 -0
- data/features/step_definitions/mongo_browser_steps.rb +1 -0
- data/features/support/env.rb +18 -0
- data/lib/mongo_browser.rb +32 -0
- data/lib/mongo_browser/application.rb +108 -0
- data/lib/mongo_browser/middleware/sprockets_sinatra.rb +24 -0
- data/lib/mongo_browser/version.rb +3 -0
- data/mongo_browser.gemspec +32 -0
- data/spec/features/collections_list_spec.rb +105 -0
- data/spec/features/databases_list_spec.rb +60 -0
- data/spec/features/documents_list_spec.rb +136 -0
- data/spec/features/server_info_spec.rb +17 -0
- data/spec/fixtures/databases.json +40 -0
- data/spec/spec_helper.rb +56 -0
- data/spec/support/have_flash_message_matcher.rb +16 -0
- data/spec/support/integration.rb +26 -0
- data/spec/support/mongo_test_server.rb +50 -0
- metadata +313 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h2>Collection <%= params[:collection_name] %></h2>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<ul class="nav nav-tabs">
|
6
|
+
<li class="active">
|
7
|
+
<a href="#documents" data-toggle="tab">Documents</a>
|
8
|
+
</li>
|
9
|
+
<li><a href="#stats" data-toggle="tab">Stats</a></li>
|
10
|
+
</ul>
|
11
|
+
|
12
|
+
<div class="tab-content">
|
13
|
+
<div class="tab-pane active" id="documents">
|
14
|
+
<%= will_paginate(@pagination, renderer: BootstrapPagination::Sinatra) %>
|
15
|
+
|
16
|
+
<table class="table table-striped table-hover documents">
|
17
|
+
<thead>
|
18
|
+
<tr>
|
19
|
+
<th>Id</th>
|
20
|
+
<th>Data</th>
|
21
|
+
<th> </th>
|
22
|
+
</tr>
|
23
|
+
</thead>
|
24
|
+
<tbody>
|
25
|
+
<% @documents.each do |document| %>
|
26
|
+
<tr class="document">
|
27
|
+
<td><%= document['_id'] %></td>
|
28
|
+
<td><%= document.ai(html: true) %></td>
|
29
|
+
<td>
|
30
|
+
<a href="/databases/<%= params[:db_name] %>/collections/<%= params[:collection_name] %>/<%= document['_id'] %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">
|
31
|
+
<i class="icon-remove-circle"></i>
|
32
|
+
Delete
|
33
|
+
</a>
|
34
|
+
</td>
|
35
|
+
</tr>
|
36
|
+
<% end %>
|
37
|
+
</tbody>
|
38
|
+
</table>
|
39
|
+
|
40
|
+
<%= will_paginate(@pagination, renderer: BootstrapPagination::Sinatra) %>
|
41
|
+
</div>
|
42
|
+
|
43
|
+
<div class="tab-pane" id="stats">
|
44
|
+
<table class="table table-striped table-hover">
|
45
|
+
<thead>
|
46
|
+
<tr>
|
47
|
+
<th>Property</th>
|
48
|
+
<th>Value</th>
|
49
|
+
</tr>
|
50
|
+
</thead>
|
51
|
+
<tbody>
|
52
|
+
<% @stats.each do |property, value| %>
|
53
|
+
<tr>
|
54
|
+
<td><%= property %></td>
|
55
|
+
<td><%= value %></td>
|
56
|
+
</tr>
|
57
|
+
<% end %>
|
58
|
+
</tbody>
|
59
|
+
</table>
|
60
|
+
</div>
|
61
|
+
</div>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h2>Database <%= params[:db_name] %></h2>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<ul class="nav nav-tabs">
|
6
|
+
<li class="active">
|
7
|
+
<a href="#collections" data-toggle="tab">Collections</a>
|
8
|
+
</li>
|
9
|
+
<li><a href="#stats" data-toggle="tab">Stats</a></li>
|
10
|
+
</ul>
|
11
|
+
|
12
|
+
<div class="tab-content">
|
13
|
+
<div class="tab-pane active" id="collections">
|
14
|
+
<%= erb :"shared/_filter", {}, { filter_for: "collections", placeholder: "Collection name" } %>
|
15
|
+
|
16
|
+
<table class="table table-striped table-hover collections">
|
17
|
+
<thead>
|
18
|
+
<tr>
|
19
|
+
<th>Name</th>
|
20
|
+
<th>Size</th>
|
21
|
+
<th> </th>
|
22
|
+
</tr>
|
23
|
+
</thead>
|
24
|
+
<tbody>
|
25
|
+
<% @collections.each do |collection| %>
|
26
|
+
<tr class="collection">
|
27
|
+
<td><a href="/databases/<%= params[:db_name] %>/collections/<%= collection.name %>"><%= collection.name %></a></td>
|
28
|
+
<td><%= collection.size %></td>
|
29
|
+
<td>
|
30
|
+
<a href="/databases/<%= params[:db_name] %>/collections/<%= collection.name %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">
|
31
|
+
<i class="icon-remove-circle"></i>
|
32
|
+
Delete
|
33
|
+
</a>
|
34
|
+
</td>
|
35
|
+
</tr>
|
36
|
+
<% end %>
|
37
|
+
</tbody>
|
38
|
+
</table>
|
39
|
+
</div>
|
40
|
+
|
41
|
+
<div class="tab-pane" id="stats">
|
42
|
+
<table class="table table-striped table-hover">
|
43
|
+
<thead>
|
44
|
+
<tr>
|
45
|
+
<th>Property</th>
|
46
|
+
<th>Value</th>
|
47
|
+
</tr>
|
48
|
+
</thead>
|
49
|
+
<tbody>
|
50
|
+
<% @stats.each do |property, value| %>
|
51
|
+
<tr>
|
52
|
+
<td><%= property %></td>
|
53
|
+
<td><%= value %></td>
|
54
|
+
</tr>
|
55
|
+
<% end %>
|
56
|
+
</tbody>
|
57
|
+
</table>
|
58
|
+
</div>
|
59
|
+
</div>
|
data/app/views/index.erb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h2>Available databases</h2>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<%= erb :"shared/_filter", {}, { filter_for: "databases", placeholder: "Database name" } %>
|
6
|
+
|
7
|
+
<table class="table table-striped table-hover databases">
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th>Name</th>
|
11
|
+
<th>Size</th>
|
12
|
+
<th> </th>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tbody>
|
16
|
+
<% @databases.each do |db_name, db_size| %>
|
17
|
+
<tr>
|
18
|
+
<td><a href="/databases/<%= db_name %>"><%= db_name %></a></td>
|
19
|
+
<td><%= db_size %></td>
|
20
|
+
<td>
|
21
|
+
<a href="/databases/<%= db_name %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">
|
22
|
+
<i class="icon-remove-circle"></i>
|
23
|
+
Delete
|
24
|
+
</a>
|
25
|
+
</td>
|
26
|
+
</tr>
|
27
|
+
<% end %>
|
28
|
+
</tbody>
|
29
|
+
</table>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Mongo Browser</title>
|
5
|
+
<link href="/assets/application.css" rel="stylesheet" media="screen">
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<%= erb :"layout/_navbar" %>
|
9
|
+
|
10
|
+
<div class="container">
|
11
|
+
<%= erb :"layout/_flash_messages" %>
|
12
|
+
<%= erb :"layout/_breadcrumb" %>
|
13
|
+
|
14
|
+
<%= yield %>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<script src="/assets/application.js"></script>
|
18
|
+
</body>
|
19
|
+
</html>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% if params[:db_name] %>
|
2
|
+
<ul class="breadcrumb">
|
3
|
+
<li><a href="/">Databases</a><span class="divider">/</span></li>
|
4
|
+
|
5
|
+
<% unless params[:collection_name] %>
|
6
|
+
<li>db: <%= params[:db_name] %></li>
|
7
|
+
<% else %>
|
8
|
+
<li><a href="/databases/<%= params[:db_name] %>">db: <%= params[:db_name] %></a>
|
9
|
+
<span class="divider">/</span></li>
|
10
|
+
<li>collection: <%= params[:collection_name] %></li>
|
11
|
+
<% end %>
|
12
|
+
</ul>
|
13
|
+
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% unless flash(:flash).empty? %>
|
2
|
+
<div id="flash-messages">
|
3
|
+
<% flash(:flash).each do |message| %>
|
4
|
+
<div class="alert alert-<%= message[0] %>">
|
5
|
+
<button type="button" class="close" data-dismiss="alert">×</button>
|
6
|
+
<strong><%= message[0].capitalize %>!</strong> <%= message[1] %>
|
7
|
+
</div>
|
8
|
+
<% end %>
|
9
|
+
</div>
|
10
|
+
<% end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<div class="navbar navbar navbar-fixed-top">
|
2
|
+
<div class="navbar-inner">
|
3
|
+
<div class="container">
|
4
|
+
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
5
|
+
<span class="icon-bar"></span>
|
6
|
+
<span class="icon-bar"></span>
|
7
|
+
<span class="icon-bar"></span>
|
8
|
+
</a>
|
9
|
+
<a class="brand" href="/">Mongo Browser</a>
|
10
|
+
<div class="nav-collapse collapse">
|
11
|
+
<ul class="nav">
|
12
|
+
<li><a href="/server_info">Server Info</a></li>
|
13
|
+
</ul>
|
14
|
+
|
15
|
+
<ul class="nav pull-right">
|
16
|
+
<li><a>v. <%= MongoBrowser::VERSION %></a></li>
|
17
|
+
</ul>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
</div>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h2>Server info</h2>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<table class="table table-striped table-hover">
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<th>Property</th>
|
9
|
+
<th>Value</th>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<% @server_info.each do |property, value| %>
|
14
|
+
<tr>
|
15
|
+
<td><%= property %></td>
|
16
|
+
<td><%= value %></td>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
</tbody>
|
20
|
+
</table>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<form class="filter" data-filter-for="<%= filter_for %>">
|
2
|
+
<div class="input-append">
|
3
|
+
<input type="text" value="" class="span3" placeholder="<%= placeholder %>">
|
4
|
+
|
5
|
+
<button type="button" class="btn clear">
|
6
|
+
<i class="icon-remove-circle"></i>Clear
|
7
|
+
</button>
|
8
|
+
</div>
|
9
|
+
<span class="help-block">Press ESC to clear the filter</span>
|
10
|
+
</form>
|
11
|
+
|
12
|
+
<div class="filter alert" style="display: none;">
|
13
|
+
Nothing has been found.
|
14
|
+
</div>
|
data/bin/mongo_browser
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "methadone"
|
5
|
+
require "mongo_browser"
|
6
|
+
require "forever"
|
7
|
+
|
8
|
+
class App
|
9
|
+
include Methadone::Main
|
10
|
+
include Methadone::CLILogging
|
11
|
+
|
12
|
+
main do
|
13
|
+
app_port = options[:port] || 4567
|
14
|
+
info("Running on the master node #{MongoBrowser.mongodb_host}:#{MongoBrowser.mongodb_port}")
|
15
|
+
info("Application is accessible at http://localhost:#{app_port}")
|
16
|
+
|
17
|
+
if options[:demonize]
|
18
|
+
Forever.run do
|
19
|
+
pid '/tmp/mongo_browser.pid'
|
20
|
+
log '/tmp/mongo_browser.log'
|
21
|
+
|
22
|
+
on_ready do
|
23
|
+
MongoBrowser::Application.run!(port: app_port)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
else
|
27
|
+
MongoBrowser::Application.run!(port: app_port)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
version MongoBrowser::VERSION
|
32
|
+
|
33
|
+
on("--port PORT", "MongoBrowser port",
|
34
|
+
"(Default: 4567)")
|
35
|
+
|
36
|
+
on("--mongodb-host HOST", "Mongodb database host",
|
37
|
+
"(Default: #{MongoBrowser.mongodb_host})") do |host|
|
38
|
+
|
39
|
+
MongoBrowser.mongodb_host = host
|
40
|
+
end
|
41
|
+
|
42
|
+
on("--mongodb-port PORT", "Mongodb database port",
|
43
|
+
"(Default: #{MongoBrowser.mongodb_port})") do |port|
|
44
|
+
|
45
|
+
MongoBrowser.mongodb_port = port.to_i
|
46
|
+
end
|
47
|
+
|
48
|
+
on("--demonize", "Run the app in the background")
|
49
|
+
|
50
|
+
use_log_level_option
|
51
|
+
|
52
|
+
go!
|
53
|
+
end
|
data/config.ru
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: My bootstrapped app kinda works
|
2
|
+
In order to get going on coding my awesome app
|
3
|
+
I want to have aruba and cucumber setup
|
4
|
+
So I don't have to do it myself
|
5
|
+
|
6
|
+
Scenario: App just runs
|
7
|
+
When I get help for "mongo_browser"
|
8
|
+
Then the exit status should be 0
|
9
|
+
And the banner should be present
|
10
|
+
And the banner should document that this app takes options
|
11
|
+
And the following options should be documented:
|
12
|
+
| --version |
|
13
|
+
| --port |
|
14
|
+
| --mongodb-host |
|
15
|
+
| --mongodb-port |
|
16
|
+
| --demonize |
|
17
|
+
| --log-level |
|
18
|
+
And the banner should document that this app takes no arguments
|
@@ -0,0 +1 @@
|
|
1
|
+
# Put your step definitions here
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'aruba/cucumber'
|
2
|
+
require 'methadone/cucumber'
|
3
|
+
|
4
|
+
ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
5
|
+
LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
|
6
|
+
|
7
|
+
Before do
|
8
|
+
@aruba_timeout_seconds = 10
|
9
|
+
|
10
|
+
# Using "announce" causes massive warnings on 1.9.2
|
11
|
+
@puts = true
|
12
|
+
@original_rubylib = ENV['RUBYLIB']
|
13
|
+
ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
After do
|
17
|
+
ENV['RUBYLIB'] = @original_rubylib
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "mongo_browser/version"
|
2
|
+
|
3
|
+
require "sinatra"
|
4
|
+
require "sinatra/reloader"
|
5
|
+
require "sinatra/flash"
|
6
|
+
|
7
|
+
require "sprockets"
|
8
|
+
require "sass"
|
9
|
+
require "coffee_script"
|
10
|
+
|
11
|
+
require "will_paginate-bootstrap"
|
12
|
+
require "mongo"
|
13
|
+
require "json"
|
14
|
+
require "ap"
|
15
|
+
|
16
|
+
module MongoBrowser
|
17
|
+
class << self
|
18
|
+
attr_writer :mongodb_host
|
19
|
+
attr_writer :mongodb_port
|
20
|
+
|
21
|
+
def mongodb_host
|
22
|
+
@mongodb_host || "localhost"
|
23
|
+
end
|
24
|
+
|
25
|
+
def mongodb_port
|
26
|
+
@mongodb_port || 27017
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
require "mongo_browser/middleware/sprockets_sinatra"
|
32
|
+
require "mongo_browser/application"
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module MongoBrowser
|
2
|
+
class Application < Sinatra::Base
|
3
|
+
configure :development do
|
4
|
+
register Sinatra::Reloader
|
5
|
+
end
|
6
|
+
|
7
|
+
enable :sessions
|
8
|
+
register Sinatra::Flash
|
9
|
+
|
10
|
+
set :root, File.join(File.dirname(__FILE__), "../../app")
|
11
|
+
set :method_override, true
|
12
|
+
|
13
|
+
use MongoBrowser::Middleware::SprocketsSinatra, :root => settings.root, :path => "assets"
|
14
|
+
register WillPaginate::Sinatra
|
15
|
+
|
16
|
+
# Databases list
|
17
|
+
get "/" do
|
18
|
+
@databases = connection.database_info
|
19
|
+
erb :"index"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Collections list
|
23
|
+
get "/databases/:db_name" do
|
24
|
+
database = connection.db(params[:db_name])
|
25
|
+
@collections = database.collections
|
26
|
+
@stats = database.stats
|
27
|
+
|
28
|
+
erb :"databases/show"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Delete a database
|
32
|
+
delete "/databases/:db_name" do
|
33
|
+
connection.drop_database(params[:db_name])
|
34
|
+
|
35
|
+
flash[:info] = "Database #{params[:db_name]} has been deleted."
|
36
|
+
redirect "/"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Documents list
|
40
|
+
get "/databases/:db_name/collections/:collection_name" do
|
41
|
+
database = connection.db(params[:db_name])
|
42
|
+
collection = database.collection(params[:collection_name])
|
43
|
+
|
44
|
+
@stats = collection.stats
|
45
|
+
@documents, @pagination = paginate_documents_for(collection, params[:page])
|
46
|
+
|
47
|
+
erb :"collections/show"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Delete a collection
|
51
|
+
delete "/databases/:db_name/collections/:collection_name" do
|
52
|
+
begin
|
53
|
+
database = connection.db(params[:db_name])
|
54
|
+
database.drop_collection(params[:collection_name])
|
55
|
+
|
56
|
+
flash[:info] = "Collection #{params[:collection_name]} has been deleted."
|
57
|
+
rescue Mongo::OperationFailure => e
|
58
|
+
flash[:error] = e.message
|
59
|
+
end
|
60
|
+
|
61
|
+
redirect "/databases/#{params[:db_name]}"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Delete a document
|
65
|
+
delete "/databases/:db_name/collections/:collection_name/:id" do
|
66
|
+
database = connection.db(params[:db_name])
|
67
|
+
collection = database.collection(params[:collection_name])
|
68
|
+
|
69
|
+
id = BSON::ObjectId(params[:id])
|
70
|
+
collection.remove(_id: id)
|
71
|
+
|
72
|
+
flash[:info] = "Document #{params[:id]} has been deleted."
|
73
|
+
redirect "/databases/#{params[:db_name]}/collections/#{params[:collection_name]}"
|
74
|
+
end
|
75
|
+
|
76
|
+
# Server info
|
77
|
+
get "/server_info" do
|
78
|
+
@server_info = connection.server_info
|
79
|
+
erb :"server_info"
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def paginate_documents_for(collection, page = 1)
|
85
|
+
per_page = 25
|
86
|
+
|
87
|
+
count = collection.count
|
88
|
+
total_pages = (count.to_f / per_page).ceil
|
89
|
+
|
90
|
+
page = if page.to_i <= 0 then 1
|
91
|
+
else
|
92
|
+
[page.to_i, total_pages].min
|
93
|
+
end
|
94
|
+
|
95
|
+
offset = (page - 1) * per_page
|
96
|
+
documents = collection.find.skip(offset).limit(per_page)
|
97
|
+
pagination = OpenStruct.new \
|
98
|
+
total_pages: total_pages,
|
99
|
+
current_page: page
|
100
|
+
|
101
|
+
return documents, pagination
|
102
|
+
end
|
103
|
+
|
104
|
+
def connection
|
105
|
+
@connection ||= Mongo::Connection.new(MongoBrowser.mongodb_host, MongoBrowser.mongodb_port)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|