mongo_browser 0.1.3 → 0.2.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +3 -3
  3. data/README.md +1 -25
  4. data/Rakefile +0 -1
  5. data/app/assets/images/background.png +0 -0
  6. data/app/assets/javascripts/app/controllers/alerts.js.coffee +12 -0
  7. data/app/assets/javascripts/app/controllers/breadcrumbs.js.coffee +25 -0
  8. data/app/assets/javascripts/app/controllers/collections.js.coffee +40 -0
  9. data/app/assets/javascripts/app/controllers/databases.js.coffee +39 -0
  10. data/app/assets/javascripts/app/controllers/documents.js.coffee +49 -0
  11. data/app/assets/javascripts/app/controllers/main.js.coffee +10 -0
  12. data/app/assets/javascripts/app/controllers/server_info.js.coffee +14 -0
  13. data/app/assets/javascripts/app/controllers.js.coffee +2 -0
  14. data/app/assets/javascripts/app/directives.js.coffee +20 -0
  15. data/app/assets/javascripts/app/filters.js.coffee +48 -0
  16. data/app/assets/javascripts/app/modules/dialogs.js.coffee +29 -0
  17. data/app/assets/javascripts/app/modules/pager.js.coffee +87 -0
  18. data/app/assets/javascripts/app/modules/table_filter.js.coffee +27 -0
  19. data/app/assets/javascripts/app/resources.js.coffee +22 -0
  20. data/app/assets/javascripts/app/services.js.coffee +36 -0
  21. data/app/assets/javascripts/app.js.coffee +8 -0
  22. data/app/assets/javascripts/application.js.coffee +35 -6
  23. data/app/assets/javascripts/templates/.gitkeep +0 -0
  24. data/app/assets/javascripts/templates.js.coffee +1 -0
  25. data/app/assets/javascripts/vendor.js.coffee +5 -0
  26. data/app/assets/stylesheets/application.css.scss +46 -3
  27. data/app/assets/templates/collections.html +53 -0
  28. data/app/assets/templates/databases.html +32 -0
  29. data/app/assets/templates/documents.html +45 -0
  30. data/app/assets/templates/pager.html +13 -0
  31. data/app/{views/server_info.erb → assets/templates/server_info.html} +5 -7
  32. data/app/assets/templates/table_filter.html +10 -0
  33. data/bin/mongo_browser +8 -45
  34. data/config-e2e.ru +20 -0
  35. data/grunt.js +36 -0
  36. data/lib/mongo_browser/application.rb +143 -64
  37. data/lib/mongo_browser/middleware/sprockets_base.rb +11 -0
  38. data/lib/mongo_browser/middleware/sprockets_sinatra.rb +3 -7
  39. data/lib/mongo_browser/middleware/sprockets_specs.rb +18 -0
  40. data/lib/mongo_browser/models/collection.rb +67 -0
  41. data/lib/mongo_browser/models/database.rb +52 -0
  42. data/lib/mongo_browser/models/document.rb +17 -0
  43. data/lib/mongo_browser/models/pager.rb +30 -0
  44. data/lib/mongo_browser/models/server.rb +51 -0
  45. data/lib/mongo_browser/version.rb +1 -1
  46. data/lib/mongo_browser.rb +10 -5
  47. data/mongo_browser.gemspec +4 -11
  48. data/public/index.html +47 -0
  49. data/script/ci_all +21 -0
  50. data/script/ci_e2e +11 -0
  51. data/script/ci_javascripts +4 -0
  52. data/script/ci_rspec +3 -0
  53. data/spec/features/collections_list_spec.rb +6 -49
  54. data/spec/features/documents_list_spec.rb +15 -14
  55. data/spec/features/server_info_spec.rb +3 -3
  56. data/spec/javascripts/app/controllers/alerts_spec.js.coffee +36 -0
  57. data/spec/javascripts/app/controllers/breadcrumbs_spec.js.coffee +28 -0
  58. data/spec/javascripts/app/controllers/collections_spec.js.coffee +78 -0
  59. data/spec/javascripts/app/controllers/databases_spec.js.coffee +55 -0
  60. data/spec/javascripts/app/controllers/documents_spec.js.coffee +62 -0
  61. data/spec/javascripts/app/controllers/main_spec.js.coffee +20 -0
  62. data/spec/javascripts/app/controllers/server_info_spec.js.coffee +21 -0
  63. data/spec/javascripts/app/directives_spec.js.coffee +58 -0
  64. data/spec/javascripts/app/filters_spec.js.coffee +99 -0
  65. data/spec/javascripts/app/modules/dialogs_spec.js.coffee +51 -0
  66. data/spec/javascripts/app/modules/pager_spec.js.coffee +104 -0
  67. data/spec/javascripts/app/modules/table_filter_spec.js.coffee +76 -0
  68. data/spec/javascripts/app/services_spec.js.coffee +83 -0
  69. data/spec/javascripts/config/testacular-e2e.conf.js +19 -0
  70. data/spec/javascripts/config/testacular.conf.js +43 -0
  71. data/spec/javascripts/e2e/collections_scenario.js.coffee +49 -0
  72. data/spec/javascripts/e2e/databases_scenario.js.coffee +74 -0
  73. data/spec/javascripts/e2e/documents_scenario.js.coffee +18 -0
  74. data/spec/javascripts/e2e/server_info_scenario.js.coffee +12 -0
  75. data/spec/javascripts/helpers/matchers.js.coffee +5 -0
  76. data/spec/javascripts/helpers/mocks.js.coffee +7 -0
  77. data/spec/javascripts/helpers_e2e/app_element.js.coffee +6 -0
  78. data/spec/javascripts/lib/angular-mocks.js +1740 -0
  79. data/spec/javascripts/lib/angular-scenario.js +26147 -0
  80. data/spec/javascripts/lib/jasmine-html.js +681 -0
  81. data/spec/javascripts/lib/jasmine.css +82 -0
  82. data/spec/javascripts/lib/jasmine.js +2600 -0
  83. data/spec/javascripts/runner.html +54 -0
  84. data/spec/javascripts/runner_e2e.html +10 -0
  85. data/spec/javascripts/spec.js.coffee +2 -0
  86. data/spec/javascripts/spec_e2e.js.coffee +2 -0
  87. data/spec/lib/models/collection_spec.rb +80 -0
  88. data/spec/lib/models/database_spec.rb +75 -0
  89. data/spec/lib/models/document_spec.rb +17 -0
  90. data/spec/lib/models/pager_spec.rb +64 -0
  91. data/spec/lib/models/server_spec.rb +76 -0
  92. data/spec/lib/mongo_browser_spec.rb +1 -1
  93. data/spec/spec_helper.rb +2 -19
  94. data/spec/support/feature_example_group.rb +8 -3
  95. data/spec/support/fixtures/databases.json +8 -0
  96. data/spec/support/fixtures.rb +20 -3
  97. data/spec/support/matchers/have_flash_message.rb +1 -1
  98. data/spec/support/mongod.rb +37 -21
  99. data/spec/support/mongodb.conf +47 -0
  100. data/vendor/assets/javascripts/angular/angular-bootstrap.js +166 -0
  101. data/vendor/assets/javascripts/angular/angular-resource.js +435 -0
  102. data/vendor/assets/javascripts/angular/angular-sanitize.js +535 -0
  103. data/vendor/assets/javascripts/angular/angular.js +14531 -0
  104. data/vendor/assets/javascripts/underscore.js +1200 -0
  105. metadata +136 -148
  106. data/app/assets/javascripts/app/table_filter.js.coffee +0 -50
  107. data/app/assets/javascripts/ujs.js.coffee +0 -23
  108. data/app/views/collections/index.erb +0 -59
  109. data/app/views/databases/index.erb +0 -29
  110. data/app/views/documents/index.erb +0 -61
  111. data/app/views/layout/_flash_messages.erb +0 -10
  112. data/app/views/layout/_navbar.erb +0 -22
  113. data/app/views/layout.erb +0 -20
  114. data/app/views/shared/_filter.erb +0 -14
  115. data/features/mongo_browser.feature +0 -18
  116. data/features/step_definitions/mongo_browser_steps.rb +0 -1
  117. data/features/support/env.rb +0 -18
  118. data/spec/features/databases_list_spec.rb +0 -65
data/.gitignore CHANGED
@@ -11,3 +11,6 @@ Gemfile.lock
11
11
  .idea
12
12
  *.iml
13
13
  *.gem
14
+
15
+ # ignore compiled templates
16
+ app/assets/javascripts/templates/*.js
data/.travis.yml CHANGED
@@ -3,10 +3,10 @@ language: ruby
3
3
  rvm:
4
4
  - 1.9.3
5
5
 
6
- before_install:
6
+ before_script:
7
+ - "npm install -g grunt testacular@canary --quiet"
7
8
  - "export DISPLAY=:99.0"
8
9
  - "sh -e /etc/init.d/xvfb start"
9
10
 
10
11
  script:
11
- - "rspec spec"
12
- - "cucumber features"
12
+ - "./script/ci_all"
data/README.md CHANGED
@@ -16,33 +16,9 @@ Run the application
16
16
 
17
17
  $ mongo_browser
18
18
 
19
- Run the application as a daemon
20
-
21
- $ mongo_browser --demonize
22
-
23
- Application will be available by default at http://localhost:4567
19
+ Application will be available by default at http://localhost:5678
24
20
  In order to run it on custom port number pass the `--port` option with selected port.
25
21
 
26
- Other options are:
27
-
28
- $ mongo_browser --help
29
- [17/11 16:10:06] Usage: mongo_browser [options]
30
-
31
- v0.1.0
32
-
33
- Options:
34
- --version Show help/version info
35
- --port PORT MongoBrowser port
36
- (Default: 4567)
37
- --mongodb-host HOST Mongodb database host
38
- (Default: localhost)
39
- --mongodb-port PORT Mongodb database port
40
- (Default: 27017)
41
- --demonize Run the app in the background
42
- --log-level LEVEL Set the logging level
43
- (debug|info|warn|error|fatal)
44
- (Default: info)
45
-
46
22
  ## Contributing
47
23
 
48
24
  1. Fork it
data/Rakefile CHANGED
@@ -58,4 +58,3 @@ Rake::RDocTask.new do |rd|
58
58
  end
59
59
 
60
60
  task :default => [:test,:features]
61
-
Binary file
@@ -0,0 +1,12 @@
1
+ module = angular.module("mb.controllers")
2
+
3
+ class AlertsController
4
+ constructor: (@$scope, @alerts) ->
5
+ @$scope.alertMessages = @alerts.messages
6
+
7
+ @$scope.disposeAlert = (id) =>
8
+ @alerts.dispose(id)
9
+
10
+ AlertsController.$inject = ["$scope", "alerts"]
11
+
12
+ module.controller "alerts", AlertsController
@@ -0,0 +1,25 @@
1
+ module = angular.module("mb.controllers")
2
+
3
+ # TODO find better solution for breadcrumbs
4
+ class BreadcrumbsController
5
+ constructor: (@$rootScope, @$scope) ->
6
+
7
+ @$scope.showDatabase = => @$scope.dbName
8
+ @$scope.showCollection = => @$scope.collectionName
9
+
10
+ @$rootScope.$on "$routeChangeSuccess", (scope, route) =>
11
+ @$scope.dbName = route.params.dbName
12
+ @$scope.collectionName = route.params.collectionName
13
+
14
+ if @$scope.dbName
15
+ @$scope.database =
16
+ name: @$scope.dbName
17
+
18
+ if @$scope.collectionName
19
+ @$scope.collection =
20
+ dbName: @$scope.dbName
21
+ name: @$scope.collectionName
22
+
23
+ BreadcrumbsController.$inject = ["$rootScope", "$scope"]
24
+
25
+ module.controller "breadcrumbs", BreadcrumbsController
@@ -0,0 +1,40 @@
1
+ module = angular.module("mb.controllers")
2
+
3
+ # TODO clenup this controller, see DatabasesController
4
+ class CollectionsController
5
+ constructor: (@$scope, @$routeParams, @Collection, @$http, @confirmationDialog, @alerts) ->
6
+
7
+ @$scope.dbName = @$routeParams.dbName
8
+ @$scope.filterValue = ""
9
+
10
+ _onLoadComplete = (data) =>
11
+ @$scope.collections = data
12
+ @$scope.loading = false
13
+
14
+ @$scope.fetchCollections = =>
15
+ @$scope.loading = true
16
+ @$scope.collections = @Collection.query({ dbName: @$scope.dbName }, _onLoadComplete)
17
+
18
+ @$scope.fetchCollections()
19
+
20
+ # TODO create resource for this call
21
+ @$http.get("/api/databases/#{@$scope.dbName}/stats.json").success (data) =>
22
+ @$scope.dbStats = data
23
+
24
+ @$scope.isLoading = => @$scope.loading
25
+
26
+ @$scope.delete = (collection) =>
27
+ @confirmationDialog
28
+ message: "Deleting #{collection.name}. Are you sure?"
29
+ onOk: =>
30
+ resource = new @Collection()
31
+ params = dbName: collection.dbName, id: collection.name
32
+
33
+ resource.$delete params, =>
34
+ @alerts.info("Collection #{collection.name} has been deleted.")
35
+ @$scope.fetchCollections()
36
+
37
+ CollectionsController.$inject = ["$scope", "$routeParams",
38
+ "Collection", "$http", "confirmationDialog", "alerts"]
39
+
40
+ module.controller "collections", CollectionsController
@@ -0,0 +1,39 @@
1
+ module = angular.module("mb.controllers")
2
+
3
+ class DatabasesController
4
+ constructor: (@$scope, @Database, @confirmationDialog, @alerts) ->
5
+ @loading = false
6
+ @fetchDatabases()
7
+
8
+ # Scope variables
9
+ @$scope.filterValue = ""
10
+
11
+ # Scope methods
12
+ @$scope.isLoading = -> @loading
13
+ @$scope.delete = (database) => @dropWithConfirmation(database)
14
+
15
+ fetchDatabases: ->
16
+ @loading = true
17
+ @Database.query(@onLoadComplete)
18
+
19
+ onLoadComplete: (data) =>
20
+ @$scope.databases = data
21
+ @loading = false
22
+
23
+ dropWithConfirmation: (database) =>
24
+ @confirmationDialog
25
+ message: "Deleting #{database.name}. Are you sure?"
26
+ onOk: => @drop(database)
27
+
28
+ drop: (database) ->
29
+ resource = new @Database()
30
+ params = id: database.name
31
+
32
+ resource.$delete params, =>
33
+ @alerts.info("Database #{database.name} has been deleted.")
34
+ @fetchDatabases()
35
+
36
+ DatabasesController.$inject = ["$scope",
37
+ "Database", "confirmationDialog", "alerts"]
38
+
39
+ module.controller "databases", DatabasesController
@@ -0,0 +1,49 @@
1
+ module = angular.module("mb.controllers")
2
+
3
+ # TODO clenup this controller, see DatabasesController
4
+ class DocumentsController
5
+ constructor: (@$scope, @$routeParams, @$http, @Document, @confirmationDialog, @alerts) ->
6
+ @$scope.dbName = @$routeParams.dbName
7
+ @$scope.collectionName = @$routeParams.collectionName
8
+
9
+ @$scope.isLoading = => @$scope.loading
10
+
11
+ _onLoadComplete = (data) =>
12
+ @$scope.loading = false
13
+
14
+ @$scope.documents = data.documents
15
+ @$scope.page = data.page
16
+ @$scope.totalPages = data.totalPages
17
+ @$scope.size = data.size
18
+
19
+ @$scope.fetchDocuments = (page = 1) =>
20
+ return if @$scope.isLoading() # TODO workaround for doule request
21
+ @$scope.loading = true
22
+
23
+ params = dbName: @$scope.dbName, collectionName: @$scope.collectionName, page: page
24
+ @Document.query(params, _onLoadComplete)
25
+
26
+ @$scope.page = 1
27
+ @$scope.fetchDocuments()
28
+
29
+ @$scope.$watch "page", (page) =>
30
+ @$scope.fetchDocuments(page)
31
+
32
+ # TODO create resource for this call
33
+ @$http.get("/api/databases/#{@$scope.dbName}/collections/#{@$scope.collectionName}/stats.json").success (data) =>
34
+ @$scope.collectionStats = data
35
+
36
+ @$scope.delete = (document) =>
37
+ @confirmationDialog
38
+ message: "Are you sure?"
39
+ onOk: =>
40
+ resource = new @Document()
41
+ params = dbName: @$scope.dbName, collectionName: @$scope.collectionName, id: document.id
42
+
43
+ resource.$delete params, =>
44
+ @alerts.info("Document #{document.id} has been deleted.")
45
+ @$scope.fetchDocuments()
46
+
47
+ DocumentsController.$inject = ["$scope", "$routeParams", "$http", "Document", "confirmationDialog", "alerts"]
48
+
49
+ module.controller "documents", DocumentsController
@@ -0,0 +1,10 @@
1
+ module = angular.module("mb.controllers")
2
+
3
+ class MainController
4
+ constructor: (@$scope, @$http) ->
5
+ @$http.get("/api/version.json").success (data) =>
6
+ @$scope.appVersion = data.version
7
+
8
+ MainController.$inject = ["$scope", "$http"]
9
+
10
+ module.controller "main", MainController
@@ -0,0 +1,14 @@
1
+ module = angular.module("mb.controllers")
2
+
3
+ class ServerInfo
4
+ constructor: (@$scope, @$http) ->
5
+ @$scope.loading = true
6
+ @$http.get("/api/server_info.json").success(@onLoadComplete)
7
+
8
+ onLoadComplete: (data) =>
9
+ @$scope.serverInfo = data
10
+ @$scope.loading = false
11
+
12
+ ServerInfo.$inject = ["$scope", "$http"]
13
+
14
+ module.controller "serverInfo", ServerInfo
@@ -0,0 +1,2 @@
1
+ # Simply define a module for controllers..
2
+ angular.module("mb.controllers", ["mb.services", "mb.resources"])
@@ -0,0 +1,20 @@
1
+ module = angular.module("mb.directives", [])
2
+
3
+ # Handles ESC key
4
+ module.directive "onEsc", ->
5
+ EscapeCode = 27
6
+
7
+ ($scope, $element, attrs) ->
8
+ $element.bind "keyup", (event) ->
9
+ return unless event.keyCode is EscapeCode
10
+ $scope.$apply(attrs.onEsc)
11
+
12
+ module.directive "deleteButton", ->
13
+ replace: true
14
+ restrict: "E"
15
+ template: """
16
+ <a class="btn btn-danger">
17
+ <i class="icon-remove-circle"></i>
18
+ Delete
19
+ </a>
20
+ """
@@ -0,0 +1,48 @@
1
+ module = angular.module("mb.filters", [])
2
+
3
+ module.filter "humanSize", -> (bytes) ->
4
+ sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB']
5
+ n = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10)
6
+ scaledSize = (bytes / Math.pow(1024, n)).toFixed(0)
7
+
8
+ "#{scaledSize} #{sizes[n]}"
9
+
10
+ module.filter "jsonDocument", -> (document) ->
11
+ str = JSON.stringify(document, undefined, 2)
12
+
13
+ # Replace for the ObjectId
14
+ str = str.replace(/_id": {\s+"\$oid":\s+"(\w+)"\s+}/gm, '_id": ObjectId("$1")')
15
+
16
+ syntaxHighlight = (json) ->
17
+ json = json.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
18
+ json.replace /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, (match) ->
19
+ cls = "number"
20
+ if /^"/.test(match)
21
+ if /:$/.test(match)
22
+ # Remove quotes from a key
23
+ match = match.replace(/^"/, "").replace(/":$/, ":")
24
+
25
+ cls = "key"
26
+ else
27
+ cls = "string"
28
+ else if /true|false/.test(match)
29
+ cls = "boolean"
30
+ else
31
+ cls = "null" if /null/.test(match)
32
+
33
+ "<span class=\"#{cls}\">#{match}</span>"
34
+
35
+ "<pre>#{syntaxHighlight(str)}</pre>"
36
+
37
+ module.filter "collectionsPath", ->
38
+ (database = {}) ->
39
+ dbName = database.name || ":dbName"
40
+
41
+ "/databases/#{dbName}/collections"
42
+
43
+ module.filter "documentsPath", (collectionsPathFilter) ->
44
+ (collection = {}) ->
45
+ dbName = collection.dbName || ":dbName"
46
+ collectionName = collection.name || ":collectionName"
47
+
48
+ "#{collectionsPathFilter(name: dbName)}/#{collectionName}/documents"
@@ -0,0 +1,29 @@
1
+ dialogs = angular.module("mb.dialogs", [])
2
+
3
+ # Simple wrapper for http://bootboxjs.com library
4
+ #
5
+ # Usage:
6
+ # handler.confirm "the message", (confirmed) ->
7
+ # doSomething() if confirmed
8
+ dialogs.factory "dialogsHandler", -> bootbox
9
+
10
+ dialogs.factory "confirmationDialog", [
11
+ "$log", "dialogsHandler", ($log, handler) ->
12
+
13
+ # Options:
14
+ # message - a message to display inside the dialog
15
+ # default: "Are you sure?"
16
+ # onOk - a handler for Ok button
17
+ # onCancel - a handler for Cancel button
18
+ (options = {}) ->
19
+ options.message ||= "Are you sure?"
20
+ $log.info("Displaying confirmation dialog:", options.message)
21
+
22
+ handler.confirm options.message, (confirmed) ->
23
+ if confirmed
24
+ $log.info("Confirmation dialog was confirmed")
25
+ (options.onOk || ->)()
26
+ else
27
+ $log.info("Confirmation dialog was disposed")
28
+ (options.onCancel || ->)()
29
+ ]
@@ -0,0 +1,87 @@
1
+ pager = angular.module("mb.pager", [])
2
+
3
+ # TODO create just a injectable function
4
+ pager.factory "pager", ->
5
+ (options = {}) ->
6
+ page: options.page || 1
7
+ totalPages: options.totalPages
8
+ innerWindow: if options.innerWindow? then options.innerWindow else 4
9
+ outerWindow: if options.outerWindow? then options.outerWindow else 1
10
+
11
+ windowedPageNumbers: ->
12
+ windowFrom = @page - @innerWindow
13
+ windowTo = @page + @innerWindow
14
+
15
+ # adjust lower or upper limit if other is out of bounds
16
+ if windowTo > @totalPages
17
+ windowFrom -= windowTo - @totalPages
18
+ windowTo = @totalPages
19
+
20
+ if windowFrom < 1
21
+ windowFrom = 1
22
+ windowTo += windowTo - windowFrom
23
+ windowTo = @totalPages if windowTo > @totalPages
24
+
25
+ middle = [windowFrom..windowTo]
26
+
27
+ # left window
28
+ middleFirst = middle[0]
29
+ if @outerWindow + 3 < middleFirst # there's a gap
30
+ left = [1..(@outerWindow + 1)]
31
+ left.push(null)
32
+ else # runs into visible pages
33
+ left = [1...middleFirst]
34
+
35
+ # right window
36
+ middleLast = middle[middle.length - 1]
37
+ if @totalPages - @outerWindow - 2 > middleLast # again, gap
38
+ right = [(@totalPages - @outerWindow)..@totalPages]
39
+ right.unshift(null)
40
+ else # runs into visible pages
41
+ if middleLast < @totalPages
42
+ right = [(middleLast + 1)..@totalPages]
43
+ else
44
+ right = []
45
+
46
+ left.concat(middle).concat(right)
47
+
48
+ # TODO block button when the resource is loading
49
+ class PagerController
50
+ constructor: (@$scope, @pager) ->
51
+ @$scope.$watch "page", => @paginate()
52
+ @$scope.$watch "totalPages", => @paginate()
53
+
54
+ @$scope.setPage = (page) =>
55
+ return if page < 1 or page > @$scope.totalPages
56
+ @$scope.page = page
57
+
58
+ @$scope.next = =>
59
+ @$scope.page += 1 if @$scope.hasNext()
60
+
61
+ @$scope.hasNext = =>
62
+ @$scope.page < @$scope.totalPages
63
+
64
+ @$scope.prev = =>
65
+ @$scope.page -= 1 if @$scope.hasPrev()
66
+
67
+ @$scope.hasPrev = =>
68
+ @$scope.page > 1
69
+
70
+ @$scope.display = => @$scope.totalPages > 1
71
+
72
+ paginate: =>
73
+ prepare = @pager(page: @$scope.page, totalPages: @$scope.totalPages)
74
+ @$scope.windowedPageNumbers = prepare.windowedPageNumbers()
75
+
76
+ pager.controller "pager", PagerController
77
+
78
+ pager.directive "pager", ->
79
+ templateUrl: "/ng/templates/pager.html"
80
+ restrict: "E"
81
+ replace: true
82
+
83
+ scope:
84
+ page: "=page"
85
+ totalPages: "=totalPages"
86
+
87
+ controller: "pager"
@@ -0,0 +1,27 @@
1
+ taleFilter = angular.module("mb.tableFilter", [])
2
+
3
+ class TableFilterController
4
+ constructor: ($scope) ->
5
+ # Clears the filter value
6
+ $scope.clear = -> $scope.value = ""
7
+
8
+ # Reruns true when the filter is empty
9
+ $scope.isEmpty = -> !$scope.value
10
+
11
+ TableFilterController.$inject = ["$scope"]
12
+
13
+ taleFilter.controller "tableFilter", TableFilterController
14
+
15
+ # Filter for databases and collections
16
+ taleFilter.directive "tableFilter", ->
17
+ restrict: "E"
18
+ transclude: true
19
+
20
+ templateUrl: "/ng/templates/table_filter.html"
21
+ replace: true
22
+
23
+ scope:
24
+ placeholder: "@placeholder"
25
+ value: "=value"
26
+
27
+ controller: "tableFilter"
@@ -0,0 +1,22 @@
1
+ angular.module "mb.resources", ["ngResource", "mb.filters"], ($provide) ->
2
+
3
+ $provide.factory "Database", [
4
+ "$resource", (resource) ->
5
+
6
+ resource "/api/databases.json", {},
7
+ query: method: "GET", isArray: true
8
+ ]
9
+
10
+ $provide.factory "Collection", [
11
+ "$resource", "$filter", (resource, $filter) ->
12
+
13
+ resource "/api#{$filter("collectionsPath")()}.json", {},
14
+ query: method: "GET", isArray: true
15
+ ]
16
+
17
+ $provide.factory "Document", [
18
+ "$resource", "$filter", (resource, $filter) ->
19
+
20
+ resource "/api#{$filter("documentsPath")()}.json", {},
21
+ query: method: "GET", isArray: false
22
+ ]
@@ -0,0 +1,36 @@
1
+ angular.module "mb.services", [], ($provide) ->
2
+
3
+ $provide.factory "alerts", [
4
+ "$log", "$timeout", ($log, $timeout) ->
5
+ lastId: 0
6
+ messages: []
7
+
8
+ # Returns a next id for the new message
9
+ nextId: ->
10
+ @lastId += 1
11
+
12
+ push: (type, text) ->
13
+ id = @nextId()
14
+ $log.info("Alert [#{id}, #{type}]", text)
15
+
16
+ @messages.push(id: id, type: type, text: text)
17
+ @delayedDispose(id)
18
+
19
+ id
20
+
21
+ # Helper methods for various alerts types
22
+ info: (text) -> @push("info", text)
23
+ error: (text) -> @push("error", text)
24
+
25
+ # Disposes a message with the given id
26
+ dispose: (id) ->
27
+ at = @messages.map((message) -> message.id).indexOf(id)
28
+ @messages.splice(at, 1)
29
+
30
+ # Dispose the message after the given time in milliseconds
31
+ delayedDispose: (id, timeout = 3000) ->
32
+ disposeTheAlert = =>
33
+ $log.info("Disposing alert", id, "after", timeout, "milliseconds")
34
+ @dispose(id)
35
+ $timeout(disposeTheAlert, timeout)
36
+ ]
@@ -0,0 +1,8 @@
1
+ #= require app/services
2
+ #= require app/resources
3
+ #= require app/directives
4
+ #= require app/filters
5
+ #= require_tree ./app/modules
6
+
7
+ #= require app/controllers
8
+ #= require_tree ./app/controllers
@@ -1,7 +1,36 @@
1
- #= require ujs
2
- #= require app/table_filter
1
+ #= require app
3
2
 
4
- $(document).ready ->
5
- $("form.filter").each (index, form) ->
6
- $form = $(form)
7
- filter = new TableFilter($form)
3
+ # App Module
4
+ requires = [
5
+ "bootstrap", "ngSanitize",
6
+ "mb.controllers", "mb.directives", "mb.filters",
7
+ "mb.dialogs", "mb.pager", "mb.tableFilter"]
8
+
9
+ angular.module("mb", requires)
10
+ .config [
11
+ "$routeProvider", "$locationProvider", (route, location) ->
12
+ route
13
+ # Main page, list of all available databases
14
+ .when "/",
15
+ templateUrl: "/ng/templates/databases.html",
16
+ controller: "databases"
17
+
18
+ # List of collections for the given database
19
+ .when "/databases/:dbName/collections",
20
+ templateUrl: "/ng/templates/collections.html",
21
+ controller: "collections"
22
+
23
+ # list of documents for the given collection
24
+ .when "/databases/:dbName/collections/:collectionName/documents",
25
+ templateUrl: "/ng/templates/documents.html",
26
+ controller: "documents"
27
+
28
+ # Information about the server
29
+ .when "/server_info",
30
+ templateUrl: "/ng/templates/server_info.html",
31
+ controller: "serverInfo"
32
+
33
+ .otherwise(redirectTo: "/")
34
+
35
+ location.html5Mode(true)
36
+ ]
File without changes
@@ -0,0 +1 @@
1
+ #= require_tree ./templates
@@ -1,3 +1,8 @@
1
1
  #= require jquery
2
+ #= require underscore
2
3
  #= require bootstrap
3
4
  #= require bootbox
5
+ #= require angular/angular
6
+ #= require angular/angular-bootstrap
7
+ #= require angular/angular-resource
8
+ #= require angular/angular-sanitize