##// END OF EJS Templates
Better user experience when kernel isn't found
Jessica B. Hamrick -
Show More
@@ -1,118 +1,122 b''
1 """Tornado handlers for the sessions web service."""
1 """Tornado handlers for the sessions web service."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import json
6 import json
7
7
8 from tornado import web
8 from tornado import web
9
9
10 from ...base.handlers import IPythonHandler, json_errors
10 from ...base.handlers import IPythonHandler, json_errors
11 from IPython.utils.jsonutil import date_default
11 from IPython.utils.jsonutil import date_default
12 from IPython.html.utils import url_path_join, url_escape
12 from IPython.html.utils import url_path_join, url_escape
13 from IPython.kernel.kernelspec import NoSuchKernel
13 from IPython.kernel.kernelspec import NoSuchKernel
14
14
15
15
16 class SessionRootHandler(IPythonHandler):
16 class SessionRootHandler(IPythonHandler):
17
17
18 @web.authenticated
18 @web.authenticated
19 @json_errors
19 @json_errors
20 def get(self):
20 def get(self):
21 # Return a list of running sessions
21 # Return a list of running sessions
22 sm = self.session_manager
22 sm = self.session_manager
23 sessions = sm.list_sessions()
23 sessions = sm.list_sessions()
24 self.finish(json.dumps(sessions, default=date_default))
24 self.finish(json.dumps(sessions, default=date_default))
25
25
26 @web.authenticated
26 @web.authenticated
27 @json_errors
27 @json_errors
28 def post(self):
28 def post(self):
29 # Creates a new session
29 # Creates a new session
30 #(unless a session already exists for the named nb)
30 #(unless a session already exists for the named nb)
31 sm = self.session_manager
31 sm = self.session_manager
32 cm = self.contents_manager
32 cm = self.contents_manager
33 km = self.kernel_manager
33 km = self.kernel_manager
34
34
35 model = self.get_json_body()
35 model = self.get_json_body()
36 if model is None:
36 if model is None:
37 raise web.HTTPError(400, "No JSON data provided")
37 raise web.HTTPError(400, "No JSON data provided")
38 try:
38 try:
39 name = model['notebook']['name']
39 name = model['notebook']['name']
40 except KeyError:
40 except KeyError:
41 raise web.HTTPError(400, "Missing field in JSON data: notebook.name")
41 raise web.HTTPError(400, "Missing field in JSON data: notebook.name")
42 try:
42 try:
43 path = model['notebook']['path']
43 path = model['notebook']['path']
44 except KeyError:
44 except KeyError:
45 raise web.HTTPError(400, "Missing field in JSON data: notebook.path")
45 raise web.HTTPError(400, "Missing field in JSON data: notebook.path")
46 try:
46 try:
47 kernel_name = model['kernel']['name']
47 kernel_name = model['kernel']['name']
48 except KeyError:
48 except KeyError:
49 self.log.debug("No kernel name specified, using default kernel")
49 self.log.debug("No kernel name specified, using default kernel")
50 kernel_name = None
50 kernel_name = None
51
51
52 # Check to see if session exists
52 # Check to see if session exists
53 if sm.session_exists(name=name, path=path):
53 if sm.session_exists(name=name, path=path):
54 model = sm.get_session(name=name, path=path)
54 model = sm.get_session(name=name, path=path)
55 else:
55 else:
56 try:
56 try:
57 model = sm.create_session(name=name, path=path, kernel_name=kernel_name)
57 model = sm.create_session(name=name, path=path, kernel_name=kernel_name)
58 except NoSuchKernel:
58 except NoSuchKernel:
59 raise web.HTTPError(400, "No such kernel: %s" % kernel_name)
59 msg = ("The '%s' kernel is not available. Please pick another "
60 "suitable kernel instead, or install that kernel." % kernel_name)
61 status_msg = 'Kernel not found'
62 msg = dict(full=msg, short=status_msg)
63 raise web.HTTPError(400, json.dumps(msg))
60
64
61 location = url_path_join(self.base_url, 'api', 'sessions', model['id'])
65 location = url_path_join(self.base_url, 'api', 'sessions', model['id'])
62 self.set_header('Location', url_escape(location))
66 self.set_header('Location', url_escape(location))
63 self.set_status(201)
67 self.set_status(201)
64 self.finish(json.dumps(model, default=date_default))
68 self.finish(json.dumps(model, default=date_default))
65
69
66 class SessionHandler(IPythonHandler):
70 class SessionHandler(IPythonHandler):
67
71
68 SUPPORTED_METHODS = ('GET', 'PATCH', 'DELETE')
72 SUPPORTED_METHODS = ('GET', 'PATCH', 'DELETE')
69
73
70 @web.authenticated
74 @web.authenticated
71 @json_errors
75 @json_errors
72 def get(self, session_id):
76 def get(self, session_id):
73 # Returns the JSON model for a single session
77 # Returns the JSON model for a single session
74 sm = self.session_manager
78 sm = self.session_manager
75 model = sm.get_session(session_id=session_id)
79 model = sm.get_session(session_id=session_id)
76 self.finish(json.dumps(model, default=date_default))
80 self.finish(json.dumps(model, default=date_default))
77
81
78 @web.authenticated
82 @web.authenticated
79 @json_errors
83 @json_errors
80 def patch(self, session_id):
84 def patch(self, session_id):
81 # Currently, this handler is strictly for renaming notebooks
85 # Currently, this handler is strictly for renaming notebooks
82 sm = self.session_manager
86 sm = self.session_manager
83 model = self.get_json_body()
87 model = self.get_json_body()
84 if model is None:
88 if model is None:
85 raise web.HTTPError(400, "No JSON data provided")
89 raise web.HTTPError(400, "No JSON data provided")
86 changes = {}
90 changes = {}
87 if 'notebook' in model:
91 if 'notebook' in model:
88 notebook = model['notebook']
92 notebook = model['notebook']
89 if 'name' in notebook:
93 if 'name' in notebook:
90 changes['name'] = notebook['name']
94 changes['name'] = notebook['name']
91 if 'path' in notebook:
95 if 'path' in notebook:
92 changes['path'] = notebook['path']
96 changes['path'] = notebook['path']
93
97
94 sm.update_session(session_id, **changes)
98 sm.update_session(session_id, **changes)
95 model = sm.get_session(session_id=session_id)
99 model = sm.get_session(session_id=session_id)
96 self.finish(json.dumps(model, default=date_default))
100 self.finish(json.dumps(model, default=date_default))
97
101
98 @web.authenticated
102 @web.authenticated
99 @json_errors
103 @json_errors
100 def delete(self, session_id):
104 def delete(self, session_id):
101 # Deletes the session with given session_id
105 # Deletes the session with given session_id
102 sm = self.session_manager
106 sm = self.session_manager
103 sm.delete_session(session_id)
107 sm.delete_session(session_id)
104 self.set_status(204)
108 self.set_status(204)
105 self.finish()
109 self.finish()
106
110
107
111
108 #-----------------------------------------------------------------------------
112 #-----------------------------------------------------------------------------
109 # URL to handler mappings
113 # URL to handler mappings
110 #-----------------------------------------------------------------------------
114 #-----------------------------------------------------------------------------
111
115
112 _session_id_regex = r"(?P<session_id>\w+-\w+-\w+-\w+-\w+)"
116 _session_id_regex = r"(?P<session_id>\w+-\w+-\w+-\w+-\w+)"
113
117
114 default_handlers = [
118 default_handlers = [
115 (r"/api/sessions/%s" % _session_id_regex, SessionHandler),
119 (r"/api/sessions/%s" % _session_id_regex, SessionHandler),
116 (r"/api/sessions", SessionRootHandler)
120 (r"/api/sessions", SessionRootHandler)
117 ]
121 ]
118
122
@@ -1,319 +1,309 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 'base/js/dialog',
8 'base/js/dialog',
9 'notebook/js/notificationwidget',
9 'notebook/js/notificationwidget',
10 'moment'
10 'moment'
11 ], function(IPython, $, utils, dialog, notificationwidget, moment) {
11 ], function(IPython, $, utils, dialog, notificationwidget, moment) {
12 "use strict";
12 "use strict";
13
13
14 // store reference to the NotificationWidget class
14 // store reference to the NotificationWidget class
15 var NotificationWidget = notificationwidget.NotificationWidget;
15 var NotificationWidget = notificationwidget.NotificationWidget;
16
16
17 /**
17 /**
18 * Construct the NotificationArea object. Options are:
18 * Construct the NotificationArea object. Options are:
19 * events: $(Events) instance
19 * events: $(Events) instance
20 * save_widget: SaveWidget instance
20 * save_widget: SaveWidget instance
21 * notebook: Notebook instance
21 * notebook: Notebook instance
22 * keyboard_manager: KeyboardManager instance
22 * keyboard_manager: KeyboardManager instance
23 *
23 *
24 * @constructor
24 * @constructor
25 * @param {string} selector - a jQuery selector string for the
25 * @param {string} selector - a jQuery selector string for the
26 * notification area element
26 * notification area element
27 * @param {Object} [options] - a dictionary of keyword arguments.
27 * @param {Object} [options] - a dictionary of keyword arguments.
28 */
28 */
29 var NotificationArea = function (selector, options) {
29 var NotificationArea = function (selector, options) {
30 this.selector = selector;
30 this.selector = selector;
31 this.events = options.events;
31 this.events = options.events;
32 this.save_widget = options.save_widget;
32 this.save_widget = options.save_widget;
33 this.notebook = options.notebook;
33 this.notebook = options.notebook;
34 this.keyboard_manager = options.keyboard_manager;
34 this.keyboard_manager = options.keyboard_manager;
35 if (this.selector !== undefined) {
35 if (this.selector !== undefined) {
36 this.element = $(selector);
36 this.element = $(selector);
37 }
37 }
38 this.widget_dict = {};
38 this.widget_dict = {};
39 };
39 };
40
40
41 /**
41 /**
42 * Get a widget by name, creating it if it doesn't exist.
42 * Get a widget by name, creating it if it doesn't exist.
43 *
43 *
44 * @method widget
44 * @method widget
45 * @param {string} name - the widget name
45 * @param {string} name - the widget name
46 */
46 */
47 NotificationArea.prototype.widget = function (name) {
47 NotificationArea.prototype.widget = function (name) {
48 if (this.widget_dict[name] === undefined) {
48 if (this.widget_dict[name] === undefined) {
49 return this.new_notification_widget(name);
49 return this.new_notification_widget(name);
50 }
50 }
51 return this.get_widget(name);
51 return this.get_widget(name);
52 };
52 };
53
53
54 /**
54 /**
55 * Get a widget by name, throwing an error if it doesn't exist.
55 * Get a widget by name, throwing an error if it doesn't exist.
56 *
56 *
57 * @method get_widget
57 * @method get_widget
58 * @param {string} name - the widget name
58 * @param {string} name - the widget name
59 */
59 */
60 NotificationArea.prototype.get_widget = function (name) {
60 NotificationArea.prototype.get_widget = function (name) {
61 if(this.widget_dict[name] === undefined) {
61 if(this.widget_dict[name] === undefined) {
62 throw('no widgets with this name');
62 throw('no widgets with this name');
63 }
63 }
64 return this.widget_dict[name];
64 return this.widget_dict[name];
65 };
65 };
66
66
67 /**
67 /**
68 * Create a new notification widget with the given name. The
68 * Create a new notification widget with the given name. The
69 * widget must not already exist.
69 * widget must not already exist.
70 *
70 *
71 * @method new_notification_widget
71 * @method new_notification_widget
72 * @param {string} name - the widget name
72 * @param {string} name - the widget name
73 */
73 */
74 NotificationArea.prototype.new_notification_widget = function (name) {
74 NotificationArea.prototype.new_notification_widget = function (name) {
75 if (this.widget_dict[name] !== undefined) {
75 if (this.widget_dict[name] !== undefined) {
76 throw('widget with that name already exists!');
76 throw('widget with that name already exists!');
77 }
77 }
78
78
79 // create the element for the notification widget and add it
79 // create the element for the notification widget and add it
80 // to the notification aread element
80 // to the notification aread element
81 var div = $('<div/>').attr('id', 'notification_' + name);
81 var div = $('<div/>').attr('id', 'notification_' + name);
82 $(this.selector).append(div);
82 $(this.selector).append(div);
83
83
84 // create the widget object and return it
84 // create the widget object and return it
85 this.widget_dict[name] = new NotificationWidget('#notification_' + name);
85 this.widget_dict[name] = new NotificationWidget('#notification_' + name);
86 return this.widget_dict[name];
86 return this.widget_dict[name];
87 };
87 };
88
88
89 /**
89 /**
90 * Initialize the default set of notification widgets.
90 * Initialize the default set of notification widgets.
91 *
91 *
92 * @method init_notification_widgets
92 * @method init_notification_widgets
93 */
93 */
94 NotificationArea.prototype.init_notification_widgets = function () {
94 NotificationArea.prototype.init_notification_widgets = function () {
95 this.init_kernel_notification_widget();
95 this.init_kernel_notification_widget();
96 this.init_notebook_notification_widget();
96 this.init_notebook_notification_widget();
97 };
97 };
98
98
99 /**
99 /**
100 * Initialize the notification widget for kernel status messages.
100 * Initialize the notification widget for kernel status messages.
101 *
101 *
102 * @method init_kernel_notification_widget
102 * @method init_kernel_notification_widget
103 */
103 */
104 NotificationArea.prototype.init_kernel_notification_widget = function () {
104 NotificationArea.prototype.init_kernel_notification_widget = function () {
105 var that = this;
105 var that = this;
106 var knw = this.new_notification_widget('kernel');
106 var knw = this.new_notification_widget('kernel');
107 var $kernel_ind_icon = $("#kernel_indicator_icon");
107 var $kernel_ind_icon = $("#kernel_indicator_icon");
108 var $modal_ind_icon = $("#modal_indicator_icon");
108 var $modal_ind_icon = $("#modal_indicator_icon");
109
109
110 // Command/Edit mode
110 // Command/Edit mode
111 this.events.on('edit_mode.Notebook',function () {
111 this.events.on('edit_mode.Notebook',function () {
112 that.save_widget.update_document_title();
112 that.save_widget.update_document_title();
113 $modal_ind_icon.attr('class','edit_mode_icon').attr('title','Edit Mode');
113 $modal_ind_icon.attr('class','edit_mode_icon').attr('title','Edit Mode');
114 });
114 });
115
115
116 this.events.on('command_mode.Notebook',function () {
116 this.events.on('command_mode.Notebook',function () {
117 that.save_widget.update_document_title();
117 that.save_widget.update_document_title();
118 $modal_ind_icon.attr('class','command_mode_icon').attr('title','Command Mode');
118 $modal_ind_icon.attr('class','command_mode_icon').attr('title','Command Mode');
119 });
119 });
120
120
121 // Implicitly start off in Command mode, switching to Edit mode will trigger event
121 // Implicitly start off in Command mode, switching to Edit mode will trigger event
122 $modal_ind_icon.attr('class','command_mode_icon').attr('title','Command Mode');
122 $modal_ind_icon.attr('class','command_mode_icon').attr('title','Command Mode');
123
123
124 // Kernel events
124 // Kernel events
125 this.events.on('status_idle.Kernel',function () {
125 this.events.on('status_idle.Kernel',function () {
126 that.save_widget.update_document_title();
126 that.save_widget.update_document_title();
127 $kernel_ind_icon.attr('class','kernel_idle_icon').attr('title','Kernel Idle');
127 $kernel_ind_icon.attr('class','kernel_idle_icon').attr('title','Kernel Idle');
128 });
128 });
129
129
130 this.events.on('status_busy.Kernel',function () {
130 this.events.on('status_busy.Kernel',function () {
131 window.document.title='(Busy) '+window.document.title;
131 window.document.title='(Busy) '+window.document.title;
132 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
132 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
133 });
133 });
134
134
135 this.events.on('status_restarting.Kernel',function () {
135 this.events.on('status_restarting.Kernel',function () {
136 that.save_widget.update_document_title();
136 that.save_widget.update_document_title();
137 knw.set_message("Restarting kernel", 2000);
137 knw.set_message("Restarting kernel", 2000);
138 });
138 });
139
139
140 this.events.on('status_dead.Kernel',function () {
140 this.events.on('status_dead.Kernel',function () {
141 that.save_widget.update_document_title();
141 that.save_widget.update_document_title();
142 knw.danger("Dead kernel");
142 knw.danger("Dead kernel");
143 $kernel_ind_icon.attr('class','kernel_dead_icon').attr('title','Kernel Dead');
143 $kernel_ind_icon.attr('class','kernel_dead_icon').attr('title','Kernel Dead');
144 });
144 });
145
145
146 this.events.on('status_interrupting.Kernel',function () {
146 this.events.on('status_interrupting.Kernel',function () {
147 knw.set_message("Interrupting kernel", 2000);
147 knw.set_message("Interrupting kernel", 2000);
148 });
148 });
149
149
150 // Start the kernel indicator in the busy state, and send a kernel_info request.
150 // Start the kernel indicator in the busy state, and send a kernel_info request.
151 // When the kernel_info reply arrives, the kernel is idle.
151 // When the kernel_info reply arrives, the kernel is idle.
152 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
152 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
153
153
154 this.events.on('status_started.Kernel', function (evt, data) {
154 this.events.on('status_started.Kernel', function (evt, data) {
155 knw.info("Websockets Connected", 500);
155 knw.info("Websockets Connected", 500);
156 that.events.trigger('status_busy.Kernel');
156 that.events.trigger('status_busy.Kernel');
157 data.kernel.kernel_info(function () {
157 data.kernel.kernel_info(function () {
158 that.events.trigger('status_idle.Kernel');
158 that.events.trigger('status_idle.Kernel');
159 });
159 });
160 });
160 });
161
161
162 this.events.on('status_restart_failed.Kernel',function () {
162 this.events.on('status_restart_failed.Kernel',function () {
163 var msg = 'The kernel has died, and the automatic restart has failed.' +
163 var msg = 'The kernel has died, and the automatic restart has failed.' +
164 ' It is possible the kernel cannot be restarted.' +
164 ' It is possible the kernel cannot be restarted.' +
165 ' If you are not able to restart the kernel, you will still be able to save' +
165 ' If you are not able to restart the kernel, you will still be able to save' +
166 ' the notebook, but running code will no longer work until the notebook' +
166 ' the notebook, but running code will no longer work until the notebook' +
167 ' is reopened.';
167 ' is reopened.';
168
168
169 dialog.modal({
169 dialog.modal({
170 title: "Dead kernel",
170 title: "Dead kernel",
171 body : msg,
171 body : msg,
172 keyboard_manager: that.keyboard_manager,
172 keyboard_manager: that.keyboard_manager,
173 notebook: that.notebook,
173 notebook: that.notebook,
174 buttons : {
174 buttons : {
175 "Manual Restart": {
175 "Manual Restart": {
176 class: "btn-danger",
176 class: "btn-danger",
177 click: function () {
177 click: function () {
178 that.events.trigger('status_restarting.Kernel');
178 that.events.trigger('status_restarting.Kernel');
179 that.notebook.start_kernel();
179 that.notebook.start_kernel();
180 }
180 }
181 },
181 },
182 "Don't restart": {}
182 "Don't restart": {}
183 }
183 }
184 });
184 });
185 });
185 });
186
186
187 this.events.on('start_failed.Session',function (session, xhr, status, error) {
187 this.events.on('start_failed.Session',function (session, xhr, status, error) {
188 var msg = $('<div/>');
188 var msg = JSON.parse(status.responseJSON.message);
189 msg.append($('<div/>')
190 .text('The kernel could not be started. This might ' +
191 'happen if the notebook was previously run with a kernel ' +
192 'that you do not have installed. Please choose a different kernel, ' +
193 'or install the needed kernel and then refresh this page.')
194 .css('margin-bottom', '1em'));
195
196 msg.append($('<div/>')
197 .text('The exact error was:')
198 .css('margin-bottom', '1em'));
199
200 msg.append($('<div/>')
201 .attr('class', 'alert alert-danger')
202 .attr('role', 'alert')
203 .text(JSON.parse(status.responseText).message));
204
189
190 that.save_widget.update_document_title();
191 $kernel_ind_icon.attr('class','kernel_dead_icon').attr('title','Kernel Dead');
192 knw.danger(msg.short, undefined, function () {
205 dialog.modal({
193 dialog.modal({
206 title: "Failed to start the kernel",
194 title: "Failed to start the kernel",
207 body : msg,
195 body : msg.full,
208 keyboard_manager: that.keyboard_manager,
196 keyboard_manager: that.keyboard_manager,
209 notebook: that.notebook,
197 notebook: that.notebook,
210 buttons : {
198 buttons : {
211 "Ok": { class: 'btn-primary' }
199 "Ok": { class: 'btn-primary' }
212 }
200 }
213 });
201 });
202 return false;
203 });
214 });
204 });
215
205
216 this.events.on('websocket_closed.Kernel', function (event, data) {
206 this.events.on('websocket_closed.Kernel', function (event, data) {
217 var kernel = data.kernel;
207 var kernel = data.kernel;
218 var ws_url = data.ws_url;
208 var ws_url = data.ws_url;
219 var early = data.early;
209 var early = data.early;
220 var msg;
210 var msg;
221
211
222 $kernel_ind_icon
212 $kernel_ind_icon
223 .attr('class', 'kernel_disconnected_icon')
213 .attr('class', 'kernel_disconnected_icon')
224 .attr('title', 'No Connection to Kernel');
214 .attr('title', 'No Connection to Kernel');
225
215
226 if (!early) {
216 if (!early) {
227 knw.warning('Reconnecting');
217 knw.warning('Reconnecting');
228 setTimeout(function () {
218 setTimeout(function () {
229 kernel.start_channels();
219 kernel.start_channels();
230 }, 5000);
220 }, 5000);
231 return;
221 return;
232 }
222 }
233 console.log('WebSocket connection failed: ', ws_url);
223 console.log('WebSocket connection failed: ', ws_url);
234 msg = "A WebSocket connection could not be established." +
224 msg = "A WebSocket connection could not be established." +
235 " You will NOT be able to run code. Check your" +
225 " You will NOT be able to run code. Check your" +
236 " network connection or notebook server configuration.";
226 " network connection or notebook server configuration.";
237 dialog.modal({
227 dialog.modal({
238 title: "WebSocket connection failed",
228 title: "WebSocket connection failed",
239 body: msg,
229 body: msg,
240 keyboard_manager: that.keyboard_manager,
230 keyboard_manager: that.keyboard_manager,
241 notebook: that.notebook,
231 notebook: that.notebook,
242 buttons : {
232 buttons : {
243 "OK": {},
233 "OK": {},
244 "Reconnect": {
234 "Reconnect": {
245 click: function () {
235 click: function () {
246 knw.warning('Reconnecting');
236 knw.warning('Reconnecting');
247 setTimeout(function () {
237 setTimeout(function () {
248 kernel.start_channels();
238 kernel.start_channels();
249 }, 5000);
239 }, 5000);
250 }
240 }
251 }
241 }
252 }
242 }
253 });
243 });
254 });
244 });
255 };
245 };
256
246
257 /**
247 /**
258 * Initialize the notification widget for notebook status messages.
248 * Initialize the notification widget for notebook status messages.
259 *
249 *
260 * @method init_notebook_notification_widget
250 * @method init_notebook_notification_widget
261 */
251 */
262 NotificationArea.prototype.init_notebook_notification_widget = function () {
252 NotificationArea.prototype.init_notebook_notification_widget = function () {
263 var nnw = this.new_notification_widget('notebook');
253 var nnw = this.new_notification_widget('notebook');
264
254
265 // Notebook events
255 // Notebook events
266 this.events.on('notebook_loading.Notebook', function () {
256 this.events.on('notebook_loading.Notebook', function () {
267 nnw.set_message("Loading notebook",500);
257 nnw.set_message("Loading notebook",500);
268 });
258 });
269 this.events.on('notebook_loaded.Notebook', function () {
259 this.events.on('notebook_loaded.Notebook', function () {
270 nnw.set_message("Notebook loaded",500);
260 nnw.set_message("Notebook loaded",500);
271 });
261 });
272 this.events.on('notebook_saving.Notebook', function () {
262 this.events.on('notebook_saving.Notebook', function () {
273 nnw.set_message("Saving notebook",500);
263 nnw.set_message("Saving notebook",500);
274 });
264 });
275 this.events.on('notebook_saved.Notebook', function () {
265 this.events.on('notebook_saved.Notebook', function () {
276 nnw.set_message("Notebook saved",2000);
266 nnw.set_message("Notebook saved",2000);
277 });
267 });
278 this.events.on('notebook_save_failed.Notebook', function (evt, xhr, status, data) {
268 this.events.on('notebook_save_failed.Notebook', function (evt, xhr, status, data) {
279 nnw.warning(data || "Notebook save failed");
269 nnw.warning(data || "Notebook save failed");
280 });
270 });
281
271
282 // Checkpoint events
272 // Checkpoint events
283 this.events.on('checkpoint_created.Notebook', function (evt, data) {
273 this.events.on('checkpoint_created.Notebook', function (evt, data) {
284 var msg = "Checkpoint created";
274 var msg = "Checkpoint created";
285 if (data.last_modified) {
275 if (data.last_modified) {
286 var d = new Date(data.last_modified);
276 var d = new Date(data.last_modified);
287 msg = msg + ": " + moment(d).format("HH:mm:ss");
277 msg = msg + ": " + moment(d).format("HH:mm:ss");
288 }
278 }
289 nnw.set_message(msg, 2000);
279 nnw.set_message(msg, 2000);
290 });
280 });
291 this.events.on('checkpoint_failed.Notebook', function () {
281 this.events.on('checkpoint_failed.Notebook', function () {
292 nnw.warning("Checkpoint failed");
282 nnw.warning("Checkpoint failed");
293 });
283 });
294 this.events.on('checkpoint_deleted.Notebook', function () {
284 this.events.on('checkpoint_deleted.Notebook', function () {
295 nnw.set_message("Checkpoint deleted", 500);
285 nnw.set_message("Checkpoint deleted", 500);
296 });
286 });
297 this.events.on('checkpoint_delete_failed.Notebook', function () {
287 this.events.on('checkpoint_delete_failed.Notebook', function () {
298 nnw.warning("Checkpoint delete failed");
288 nnw.warning("Checkpoint delete failed");
299 });
289 });
300 this.events.on('checkpoint_restoring.Notebook', function () {
290 this.events.on('checkpoint_restoring.Notebook', function () {
301 nnw.set_message("Restoring to checkpoint...", 500);
291 nnw.set_message("Restoring to checkpoint...", 500);
302 });
292 });
303 this.events.on('checkpoint_restore_failed.Notebook', function () {
293 this.events.on('checkpoint_restore_failed.Notebook', function () {
304 nnw.warning("Checkpoint restore failed");
294 nnw.warning("Checkpoint restore failed");
305 });
295 });
306
296
307 // Autosave events
297 // Autosave events
308 this.events.on('autosave_disabled.Notebook', function () {
298 this.events.on('autosave_disabled.Notebook', function () {
309 nnw.set_message("Autosave disabled", 2000);
299 nnw.set_message("Autosave disabled", 2000);
310 });
300 });
311 this.events.on('autosave_enabled.Notebook', function (evt, interval) {
301 this.events.on('autosave_enabled.Notebook', function (evt, interval) {
312 nnw.set_message("Saving every " + interval / 1000 + "s", 1000);
302 nnw.set_message("Saving every " + interval / 1000 + "s", 1000);
313 });
303 });
314 };
304 };
315
305
316 IPython.NotificationArea = NotificationArea;
306 IPython.NotificationArea = NotificationArea;
317
307
318 return {'NotificationArea': NotificationArea};
308 return {'NotificationArea': NotificationArea};
319 });
309 });
@@ -1,150 +1,149 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 'services/kernels/js/kernel',
8 'services/kernels/js/kernel',
9 ], function(IPython, $, utils, kernel) {
9 ], function(IPython, $, utils, kernel) {
10 "use strict";
10 "use strict";
11
11
12 var Session = function(options){
12 var Session = function(options){
13 this.kernel = null;
13 this.kernel = null;
14 this.id = null;
14 this.id = null;
15 this.notebook = options.notebook;
15 this.notebook = options.notebook;
16 this.events = options.notebook.events;
16 this.events = options.notebook.events;
17 this.name = options.notebook_name;
17 this.name = options.notebook_name;
18 this.path = options.notebook_path;
18 this.path = options.notebook_path;
19 this.kernel_name = options.kernel_name;
19 this.kernel_name = options.kernel_name;
20 this.base_url = options.base_url;
20 this.base_url = options.base_url;
21 this.ws_url = options.ws_url;
21 this.ws_url = options.ws_url;
22 };
22 };
23
23
24 Session.prototype.start = function (success, error) {
24 Session.prototype.start = function (success, error) {
25 var that = this;
25 var that = this;
26 var model = {
26 var model = {
27 notebook : {
27 notebook : {
28 name : this.name,
28 name : this.name,
29 path : this.path
29 path : this.path
30 },
30 },
31 kernel : {
31 kernel : {
32 name : this.kernel_name
32 name : this.kernel_name
33 }
33 }
34 };
34 };
35 var settings = {
35 var settings = {
36 processData : false,
36 processData : false,
37 cache : false,
37 cache : false,
38 type : "POST",
38 type : "POST",
39 data: JSON.stringify(model),
39 data: JSON.stringify(model),
40 dataType : "json",
40 dataType : "json",
41 success : function (data, status, xhr) {
41 success : function (data, status, xhr) {
42 that._handle_start_success(data);
42 that._handle_start_success(data);
43 if (success) {
43 if (success) {
44 success(data, status, xhr);
44 success(data, status, xhr);
45 }
45 }
46 },
46 },
47 error : function (xhr, status, err) {
47 error : function (xhr, status, err) {
48 that._handle_start_failure(xhr, status, err);
48 that._handle_start_failure(xhr, status, err);
49 if (error !== undefined) {
49 if (error !== undefined) {
50 error(xhr, status, err);
50 error(xhr, status, err);
51 }
51 }
52 utils.log_ajax_error(xhr, status, err);
52 utils.log_ajax_error(xhr, status, err);
53 }
53 }
54 };
54 };
55 var url = utils.url_join_encode(this.base_url, 'api/sessions');
55 var url = utils.url_join_encode(this.base_url, 'api/sessions');
56 $.ajax(url, settings);
56 $.ajax(url, settings);
57 };
57 };
58
58
59 Session.prototype.rename_notebook = function (name, path) {
59 Session.prototype.rename_notebook = function (name, path) {
60 this.name = name;
60 this.name = name;
61 this.path = path;
61 this.path = path;
62 var model = {
62 var model = {
63 notebook : {
63 notebook : {
64 name : this.name,
64 name : this.name,
65 path : this.path
65 path : this.path
66 }
66 }
67 };
67 };
68 var settings = {
68 var settings = {
69 processData : false,
69 processData : false,
70 cache : false,
70 cache : false,
71 type : "PATCH",
71 type : "PATCH",
72 data: JSON.stringify(model),
72 data: JSON.stringify(model),
73 dataType : "json",
73 dataType : "json",
74 error : utils.log_ajax_error,
74 error : utils.log_ajax_error,
75 };
75 };
76 var url = utils.url_join_encode(this.base_url, 'api/sessions', this.id);
76 var url = utils.url_join_encode(this.base_url, 'api/sessions', this.id);
77 $.ajax(url, settings);
77 $.ajax(url, settings);
78 };
78 };
79
79
80 Session.prototype.delete = function (success, error) {
80 Session.prototype.delete = function (success, error) {
81 var settings = {
81 var settings = {
82 processData : false,
82 processData : false,
83 cache : false,
83 cache : false,
84 type : "DELETE",
84 type : "DELETE",
85 dataType : "json",
85 dataType : "json",
86 success : success,
86 success : success,
87 error : error || utils.log_ajax_error,
87 error : error || utils.log_ajax_error,
88 };
88 };
89 if (this.kernel) {
89 if (this.kernel) {
90 this.kernel.running = false;
90 this.kernel.running = false;
91 this.kernel.stop_channels();
91 this.kernel.stop_channels();
92 }
92 }
93 var url = utils.url_join_encode(this.base_url, 'api/sessions', this.id);
93 var url = utils.url_join_encode(this.base_url, 'api/sessions', this.id);
94 $.ajax(url, settings);
94 $.ajax(url, settings);
95 };
95 };
96
96
97 // Kernel related things
97 // Kernel related things
98 /**
98 /**
99 * Create the Kernel object associated with this Session.
99 * Create the Kernel object associated with this Session.
100 *
100 *
101 * @method _handle_start_success
101 * @method _handle_start_success
102 */
102 */
103 Session.prototype._handle_start_success = function (data, status, xhr) {
103 Session.prototype._handle_start_success = function (data, status, xhr) {
104 this.id = data.id;
104 this.id = data.id;
105 // If we asked for 'python', the response will have 'python3' or 'python2'.
105 // If we asked for 'python', the response will have 'python3' or 'python2'.
106 this.kernel_name = data.kernel.name;
106 this.kernel_name = data.kernel.name;
107 this.events.trigger('started.Session', this);
107 this.events.trigger('started.Session', this);
108 var kernel_service_url = utils.url_path_join(this.base_url, "api/kernels");
108 var kernel_service_url = utils.url_path_join(this.base_url, "api/kernels");
109 this.kernel = new kernel.Kernel(kernel_service_url, this.ws_url, this.notebook, this.kernel_name);
109 this.kernel = new kernel.Kernel(kernel_service_url, this.ws_url, this.notebook, this.kernel_name);
110 this.kernel._kernel_started(data.kernel);
110 this.kernel._kernel_started(data.kernel);
111 };
111 };
112
112
113 Session.prototype._handle_start_failure = function (xhr, status, error) {
113 Session.prototype._handle_start_failure = function (xhr, status, error) {
114 this.events.trigger('start_failed.Session', [this, xhr, status, error]);
114 this.events.trigger('start_failed.Session', [this, xhr, status, error]);
115 this.events.trigger('status_dead.Kernel');
116 };
115 };
117
116
118 /**
117 /**
119 * Prompt the user to restart the IPython kernel.
118 * Prompt the user to restart the IPython kernel.
120 *
119 *
121 * @method restart_kernel
120 * @method restart_kernel
122 */
121 */
123 Session.prototype.restart_kernel = function () {
122 Session.prototype.restart_kernel = function () {
124 this.kernel.restart();
123 this.kernel.restart();
125 };
124 };
126
125
127 Session.prototype.interrupt_kernel = function() {
126 Session.prototype.interrupt_kernel = function() {
128 this.kernel.interrupt();
127 this.kernel.interrupt();
129 };
128 };
130
129
131
130
132 Session.prototype.kill_kernel = function() {
131 Session.prototype.kill_kernel = function() {
133 this.kernel.kill();
132 this.kernel.kill();
134 };
133 };
135
134
136 var SessionAlreadyStarting = function (message) {
135 var SessionAlreadyStarting = function (message) {
137 this.name = "SessionAlreadyStarting";
136 this.name = "SessionAlreadyStarting";
138 this.message = (message || "");
137 this.message = (message || "");
139 };
138 };
140
139
141 SessionAlreadyStarting.prototype = Error.prototype;
140 SessionAlreadyStarting.prototype = Error.prototype;
142
141
143 // For backwards compatability.
142 // For backwards compatability.
144 IPython.Session = Session;
143 IPython.Session = Session;
145
144
146 return {
145 return {
147 Session: Session,
146 Session: Session,
148 SessionAlreadyStarting: SessionAlreadyStarting,
147 SessionAlreadyStarting: SessionAlreadyStarting,
149 };
148 };
150 });
149 });
General Comments 0
You need to be logged in to leave comments. Login now