mongo_browser 0.1.3 → 0.2.0.rc2

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 (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