diff --git a/src/bugsnag.js b/src/bugsnag.js index bef82d3a64c..17170df5e89 100644 --- a/src/bugsnag.js +++ b/src/bugsnag.js @@ -14,10 +14,10 @@ var _ = require('lodash'); var debug = require('debug')('scout:bugsnag'); var TOKEN = '0d11ab5f4d97452cc83d3365c21b491c'; - // @todo (imlucas): use mongodb-redact function beforeNotify(d) { app.sendMessage('show bugsnag OS notification', d.message); + app.statusbar.hide(); d.stacktrace = redact(d.stacktrace); d.context = redact(d.context); @@ -25,7 +25,6 @@ function beforeNotify(d) { d.message = redact(d.message); d.url = redact(d.url); d.name = redact(d.name); - d.file = redact(d.file); d.metaData = redact(d.metaData); debug('redacted bugsnag report\n', JSON.stringify(d, null, 2)); } diff --git a/src/home/collection.js b/src/home/collection.js index 63a4c3da720..15f3c677ffc 100644 --- a/src/home/collection.js +++ b/src/home/collection.js @@ -67,7 +67,6 @@ var MongoDBCollectionView = View.extend({ }, initialize: function() { this.model = new MongoDBCollection(); - app.statusbar.watch(this, this.schema); this.listenTo(this.schema, 'sync', this.schemaIsSynced.bind(this)); this.listenTo(this.schema, 'request', this.schemaIsRequested.bind(this)); this.listenToAndRun(this.parent, 'change:ns', this.onCollectionChanged.bind(this)); diff --git a/src/models/sampled-schema.js b/src/models/sampled-schema.js index c158f4f50b9..ef53def2c1d 100644 --- a/src/models/sampled-schema.js +++ b/src/models/sampled-schema.js @@ -165,21 +165,23 @@ module.exports = Schema.extend({ } model.documents.reset(docs); model.documents.trigger('sync'); + app.statusbar.hide(true); // @note (imlucas): Any other metrics? Feedback on `Schema *`? var totalTime = new Date() - start; var timeToFirstDoc = timeAtFirstDoc - start; metrics.track('Schema: Complete', { - Duration: totalTime, - 'Total Document Count': model.total, - 'Sample Size': model.documents.length, - 'Errored Document Count': erroredOnDocs.length, - 'Time to First Doc': timeToFirstDoc, - 'Average Time Per Doc': (totalTime - timeToFirstDoc) / model.documents.length - // 'Schema Height': model.height, // # of top level keys - // 'Schema Width': model.width, // max nesting depth - // 'Schema Sparsity': model.sparsity // lots of fields missing or consistent + duration: totalTime, + 'total document count': model.total, + 'sample size': model.documents.length, + 'errored document count': erroredOnDocs.length, + 'total sample time': timeToFirstDoc, + 'total analysis time': totalTime - timeToFirstDoc, + 'average analysis time per doc': (totalTime - timeToFirstDoc) / model.documents.length + // 'Schema Height': model.height, // # of top level keys + // 'Schema Width': model.width, // max nesting depth + // 'Schema Sparsity': model.sparsity // lots of fields missing or consistent }); options.success({}); }; @@ -199,9 +201,29 @@ module.exports = Schema.extend({ return onEmpty(); } - debug('creating sample stream'); + var status = 0; + var counter = 0; + var numSamples = Math.min(options.size, count.count); + var stepSize = Math.ceil(Math.max(1, numSamples / 10)); + + app.statusbar.show('Sampling collection...'); + app.statusbar.width = 1; + app.statusbar.trickle(true); app.client.sample(model.ns, options) .pipe(es.map(parse)) + .once('data', function() { + status = app.statusbar.width; + app.statusbar.message = 'Analyzing documents...'; + app.statusbar.trickle(false); + }) + .on('data', function() { + counter ++; + if (counter % stepSize === 0) { + var inc = (100 - status) * stepSize / numSamples; + debug(inc); + app.statusbar.width += inc; + } + }) .pipe(es.map(addToDocuments)) .pipe(es.wait(onEnd)); }); diff --git a/src/statusbar/index.jade b/src/statusbar/index.jade index 629fe09857b..0d1065bc057 100644 --- a/src/statusbar/index.jade +++ b/src/statusbar/index.jade @@ -3,6 +3,9 @@ .progress-bar.progress-bar-striped.active(data-hook='inner-bar') ul.message-background.with-sidebar.centered(data-hook='message-container'): li p(data-hook='message') - .spinner-circles(data-hook='loading') - .circle-1 - .circle-2 + .spinner(data-hook='loading') + .rect1 + .rect2 + .rect3 + .rect4 + .rect5 diff --git a/src/statusbar/index.js b/src/statusbar/index.js index 34297f0a4aa..419570ed441 100644 --- a/src/statusbar/index.js +++ b/src/statusbar/index.js @@ -1,6 +1,10 @@ var View = require('ampersand-view'); +var _ = require('lodash'); +// var debug = require('debug')('scout:statusbar:index'); + var StatusbarView = View.extend({ props: { + trickleTimer: 'any', width: { type: 'number', default: 0 @@ -8,14 +12,18 @@ var StatusbarView = View.extend({ message: { type: 'string' }, - loading: { + loadingIndicator: { type: 'boolean', default: true + }, + visible: { + type: 'boolean', + default: false } }, template: require('./index.jade'), bindings: { - loading: { + loadingIndicator: { hook: 'loading', type: 'booleanClass', yes: 'visible', @@ -46,9 +54,14 @@ var StatusbarView = View.extend({ }, { type: 'booleanClass', + hook: 'outer-bar', no: 'hidden' } - ] + ], + visible: { + type: 'booleanClass', + no: 'hidden' + } }, derived: { /** @@ -79,19 +92,43 @@ var StatusbarView = View.extend({ this.hide(); }, fatal: function(err) { - this.loading = false; + this.visible = true; + this.loadingIndicator = false; this.message = 'Fatal Error: ' + err.message; - this.width = 100; + this.width = 0; + this.trickle(false); + clearInterval(this.trickleTimer); + }, + trickle: function(bool) { + if (bool) { + this.trickleTimer = setInterval(function() { + this.width = Math.min(98, this.width + _.random(1, 3)); + }.bind(this), 800); + } else { + clearInterval(this.trickleTimer); + } }, show: function(message) { + this.visible = true; this.message = message || ''; this.width = 100; - this.loading = true; + this.loadingIndicator = true; }, - hide: function() { + hide: function(completed) { this.message = ''; - this.width = 0; - this.loading = false; + this.loadingIndicator = false; + clearInterval(this.trickleTimer); + if (completed) { + this.width = 100; + var model = this; + _.delay(function() { + model.width = 0; + model.visible = false; + }, 1000); + } else { + this.width = 0; + this.visible = false; + } } }); diff --git a/src/statusbar/index.less b/src/statusbar/index.less index ff3bdd0455a..4cbec6d80c8 100644 --- a/src/statusbar/index.less +++ b/src/statusbar/index.less @@ -24,45 +24,58 @@ } } .message-background { - .spinner-circles { - width: 40px; - height: 40px; - position: relative; - margin: 40px auto; + .spinner { + margin: 50px auto; + width: 65px; + height: 60px; + text-align: center; + font-size: 10px; + } - .circle-1, .circle-2 { - width: 100%; - height: 100%; - border-radius: 50%; - background-color: @mc-blue0; - opacity: 0.6; - position: absolute; - top: 0; - left: 0; + .spinner > div { + background-color: rgba(0, 0, 0, 0.2);; + margin: 0 3px 0 0; + height: 100%; + width: 10px; + display: inline-block; - -webkit-animation: bounce 2.0s infinite ease-in-out; - animation: bounce 2.0s infinite ease-in-out; - } + -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; + animation: sk-stretchdelay 1.2s infinite ease-in-out; + } - .circle-2 { - -webkit-animation-delay: -1.0s; - animation-delay: -1.0s; - } + .spinner .rect2 { + -webkit-animation-delay: -1.1s; + animation-delay: -1.1s; + } - @-webkit-keyframes bounce { - 0%, 100% { -webkit-transform: scale(0.0) } - 50% { -webkit-transform: scale(1.0) } - } + .spinner .rect3 { + -webkit-animation-delay: -1.0s; + animation-delay: -1.0s; + } + + .spinner .rect4 { + -webkit-animation-delay: -0.9s; + animation-delay: -0.9s; + } + + .spinner .rect5 { + -webkit-animation-delay: -0.8s; + animation-delay: -0.8s; + } + + @-webkit-keyframes sk-stretchdelay { + 0%, 40%, 100% { -webkit-transform: scaleY(0.4) } + 20% { -webkit-transform: scaleY(1.0) } + } - @keyframes bounce { - 0%, 100% { - transform: scale(0.0); - -webkit-transform: scale(0.0); - } 50% { - transform: scale(1.0); - -webkit-transform: scale(1.0); - } + @keyframes sk-stretchdelay { + 0%, 40%, 100% { + transform: scaleY(0.4); + -webkit-transform: scaleY(0.4); + } 20% { + transform: scaleY(1.0); + -webkit-transform: scaleY(1.0); } } } - } +} diff --git a/styles/10strap.less b/styles/10strap.less index 0016061290f..4d44aa36ccd 100644 --- a/styles/10strap.less +++ b/styles/10strap.less @@ -649,10 +649,10 @@ fieldset[disabled] .btn-link:focus { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; - -webkit-transition: width 0.6s ease; - -moz-transition: width 0.6s ease; - -o-transition: width 0.6s ease; - transition: width 0.6s ease; + -webkit-transition: width 0.8s ease; + -moz-transition: width 0.8s ease; + -o-transition: width 0.8s ease; + transition: width 0.8s ease; } .progress.active .progress-bar { -webkit-animation: progress-bar-stripes 0.6s linear infinite;