Merge pull request #7227 from jdfreder/undead

Add visual cue for widgets with dead comms
This commit is contained in:
Brian E. Granger 2014-12-16 14:56:58 -08:00
commit 6c55690994
6 changed files with 100 additions and 2 deletions

View File

@ -117,6 +117,7 @@ define([
this.last_msg_id = null; this.last_msg_id = null;
this.completer = null; this.completer = null;
this.widget_views = []; this.widget_views = [];
this._widgets_live = true;
Cell.apply(this,[{ Cell.apply(this,[{
config: $.extend({}, CodeCell.options_default), config: $.extend({}, CodeCell.options_default),
@ -224,7 +225,12 @@ define([
.click(function() { .click(function() {
widget_area.slideUp('', function(){ widget_area.slideUp('', function(){
for (var i = 0; i < that.widget_views.length; i++) { for (var i = 0; i < that.widget_views.length; i++) {
that.widget_views[i].remove(); var view = that.widget_views[i];
view.remove();
// Remove widget live events.
view.off('comm:live', that._widget_live);
view.off('comm:dead', that._widget_dead);
} }
that.widget_views = []; that.widget_views = [];
widget_subarea.html(''); widget_subarea.html('');
@ -258,10 +264,49 @@ define([
that.widget_area.show(); that.widget_area.show();
dummy.replaceWith(view.$el); dummy.replaceWith(view.$el);
that.widget_views.push(view); that.widget_views.push(view);
// Check the live state of the view's model.
if (view.model.comm_live) {
that._widget_live(view);
} else {
that._widget_dead(view);
}
// Listen to comm live events for the view.
view.on('comm:live', that._widget_live, that);
view.on('comm:dead', that._widget_dead, that);
return view; return view;
}); });
}; };
/**
* Handles when a widget loses it's comm connection.
* @param {WidgetView} view
*/
CodeCell.prototype._widget_dead = function(view) {
if (this._widgets_live) {
this._widgets_live = false;
this.widget_area.addClass('connection-problems');
}
};
/**
* Handles when a widget is connected to a live comm.
* @param {WidgetView} view
*/
CodeCell.prototype._widget_live = function(view) {
if (!this._widgets_live) {
// Check that the other widgets are live too. O(N) operation.
// Abort the function at the first dead widget found.
for (var i = 0; i < this.widget_views.length; i++) {
if (!this.widget_views[i].model.comm_live) return;
}
this._widgets_live = true;
this.widget_area.removeClass('connection-problems');
}
};
/** @method bind_events */ /** @method bind_events */
CodeCell.prototype.bind_events = function () { CodeCell.prototype.bind_events = function () {
Cell.prototype.bind_events.apply(this); Cell.prototype.bind_events.apply(this);
@ -375,7 +420,12 @@ define([
// Clear widget area // Clear widget area
for (var i = 0; i < this.widget_views.length; i++) { for (var i = 0; i < this.widget_views.length; i++) {
this.widget_views[i].remove(); var view = this.widget_views[i];
view.remove();
// Remove widget live events.
view.off('comm:live', this._widget_live);
view.off('comm:dead', this._widget_dead);
} }
this.widget_views = []; this.widget_views = [];
this.widget_subarea.html(''); this.widget_subarea.html('');

View File

@ -2,6 +2,9 @@
@import "../components/bootstrap/less/variables.less"; @import "../components/bootstrap/less/variables.less";
@import "../components/bootstrap/less/mixins.less"; @import "../components/bootstrap/less/mixins.less";
// minimal imports from font-awesome
@import "../components/font-awesome/less/variables.less";
// base // base
@import "../base/less/style.less"; @import "../base/less/style.less";

View File

@ -1255,6 +1255,14 @@ h6:hover .anchor-link {
/* Modern browsers */ /* Modern browsers */
align-items: flex-start; align-items: flex-start;
} }
.widget-area.connection-problems .prompt:after {
content: "\f127";
font-family: 'FontAwesome';
color: #d9534f;
font-size: 14px;
top: 3px;
padding: 3px;
}
/* THE CLASSES BELOW CAN APPEAR ANYWHERE IN THE DOM (POSSIBLEY OUTSIDE OF /* THE CLASSES BELOW CAN APPEAR ANYWHERE IN THE DOM (POSSIBLEY OUTSIDE OF
THE WIDGET AREA). */ THE WIDGET AREA). */
.slide-track { .slide-track {

View File

@ -9125,6 +9125,14 @@ h6:hover .anchor-link {
/* Modern browsers */ /* Modern browsers */
align-items: flex-start; align-items: flex-start;
} }
.widget-area.connection-problems .prompt:after {
content: "\f127";
font-family: 'FontAwesome';
color: #d9534f;
font-size: 14px;
top: 3px;
padding: 3px;
}
/* THE CLASSES BELOW CAN APPEAR ANYWHERE IN THE DOM (POSSIBLEY OUTSIDE OF /* THE CLASSES BELOW CAN APPEAR ANYWHERE IN THE DOM (POSSIBLEY OUTSIDE OF
THE WIDGET AREA). */ THE WIDGET AREA). */
.slide-track { .slide-track {

View File

@ -47,6 +47,17 @@ define(["widgets/js/manager",
} else { } else {
this.set_comm_live(false); this.set_comm_live(false);
} }
// Listen for the events that lead to the websocket being terminated.
var that = this;
var died = function() {
that.set_comm_live(false);
};
widget_manager.notebook.events.on('kernel_disconnected.Kernel', died);
widget_manager.notebook.events.on('kernel_killed.Kernel', died);
widget_manager.notebook.events.on('kernel_restarting.Kernel', died);
widget_manager.notebook.events.on('kernel_dead.Kernel', died);
return Backbone.Model.apply(this); return Backbone.Model.apply(this);
}, },
@ -384,6 +395,15 @@ define(["widgets/js/manager",
* Public constructor. * Public constructor.
*/ */
this.model.on('change',this.update,this); this.model.on('change',this.update,this);
// Bubble the comm live events.
this.model.on('comm:live', function() {
this.trigger('comm:live', this);
}, this);
this.model.on('comm:dead', function() {
this.trigger('comm:dead', this);
}, this);
this.options = parameters.options; this.options = parameters.options;
this.on('displayed', function() { this.on('displayed', function() {
this.is_displayed = true; this.is_displayed = true;

View File

@ -26,6 +26,15 @@
.box-flex2(); .box-flex2();
.align-start(); .align-start();
} }
&.connection-problems .prompt:after {
content: @fa-var-chain-broken;
font-family: 'FontAwesome';
color: @brand-danger;
font-size: @notebook_font_size;
top: 3px;
padding: 3px;
}
} }
/* THE CLASSES BELOW CAN APPEAR ANYWHERE IN THE DOM (POSSIBLEY OUTSIDE OF /* THE CLASSES BELOW CAN APPEAR ANYWHERE IN THE DOM (POSSIBLEY OUTSIDE OF