diff --git a/IPython/html/notebookapp.py b/IPython/html/notebookapp.py index f2d1c53..bf7f4f8 100644 --- a/IPython/html/notebookapp.py +++ b/IPython/html/notebookapp.py @@ -173,6 +173,7 @@ class NotebookWebApplication(web.Application): mathjax_url=ipython_app.mathjax_url, config=ipython_app.config, jinja2_env=env, + terminals_available=False, # Set later if terminals are available ) # allow custom overrides for the tornado web app. @@ -765,10 +766,9 @@ class NotebookApp(BaseIPythonApplication): try: from .terminal import initialize initialize(self.web_app) - self.web_app.terminals_available = True + self.web_app.settings['terminals_available'] = True except ImportError as e: self.log.info("Terminals not available (error was %s)", e) - self.web_app.terminals_available = False def init_signal(self): if not sys.platform.startswith('win'): diff --git a/IPython/html/static/tree/js/main.js b/IPython/html/static/tree/js/main.js index ab0e08c..1f19758 100644 --- a/IPython/html/static/tree/js/main.js +++ b/IPython/html/static/tree/js/main.js @@ -11,6 +11,7 @@ require([ 'tree/js/clusterlist', 'tree/js/sessionlist', 'tree/js/kernellist', + 'tree/js/terminallist', 'auth/js/loginwidget', // only loaded, not used: 'jqueryui', @@ -25,7 +26,8 @@ require([ notebooklist, clusterlist, sesssionlist, - kernellist, + kernellist, + terminallist, loginwidget){ page = new page.Page(); @@ -44,6 +46,11 @@ require([ kernel_list = new kernellist.KernelList('#running_list', $.extend({ session_list: session_list}, common_options)); + + if (utils.get_body_data("terminalsAvailable") === "True") { + terminal_list = new terminallist.TerminalList('#terminal_list', common_options); + } + login_widget = new loginwidget.LoginWidget('#login_widget', common_options); $('#new_notebook').click(function (e) { diff --git a/IPython/html/static/tree/js/terminallist.js b/IPython/html/static/tree/js/terminallist.js new file mode 100644 index 0000000..c7ef391 --- /dev/null +++ b/IPython/html/static/tree/js/terminallist.js @@ -0,0 +1,103 @@ +// Copyright (c) IPython Development Team. +// Distributed under the terms of the Modified BSD License. + +define([ + 'base/js/namespace', + 'base/js/utils', + 'jquery', + 'tree/js/notebooklist', +], function(IPython, utils, $, notebooklist) { + "use strict"; + + var TerminalList = function (selector, options) { + // Constructor + // + // Parameters: + // selector: string + // options: dictionary + // Dictionary of keyword arguments. + // base_url: string + this.base_url = options.base_url || utils.get_body_data("baseUrl"); + this.element_name = options.element_name || 'terminal'; + this.selector = selector; + this.terminals = []; + if (this.selector !== undefined) { + this.element = $(selector); + this.style(); + this.bind_events(); + this.load_terminals(); + } + }; + + TerminalList.prototype = Object.create(notebooklist.NotebookList.prototype); + + TerminalList.prototype.bind_events = function () { + var that = this; + $('#refresh_' + this.element_name + '_list').click(function () { + that.load_terminals(); + }); + $('#new_terminal').click($.proxy(this.new_terminal, this)); + }; + + TerminalList.prototype.new_terminal = function() { + var url = utils.url_join_encode(this.base_url, 'terminals/new'); + window.open(url, '_blank'); + }; + + TerminalList.prototype.load_terminals = function() { + var that = this; + var url = utils.url_join_encode(this.base_url, 'api/terminals'); + $.ajax(url, { + type: "GET", + cache: false, + dataType: "json", + success: $.proxy(this.terminals_loaded, this), + error : utils.log_ajax_error + }); + }; + + TerminalList.prototype.terminals_loaded = function (data) { + this.terminals = data; + this.clear_list(); + var item, path_name, term; + for (var i=0; i < this.terminals.length; i++) { + term = this.terminals[i]; + item = this.new_item(-1); + this.add_link(term.name, item); + this.add_shutdown_button(term.name, item); + } + $('#terminal_list_header').toggle(data.length === 0); + }; + + TerminalList.prototype.add_link = function(name, item) { + item.data('term-name', name); + item.find(".item_name").text("terminals/" + name); + item.find(".item_icon").addClass("fa fa-terminal"); + var link = item.find("a.item_link") + .attr('href', utils.url_join_encode(this.base_url, "terminals", name)); + link.attr('target', '_blank'); + this.add_shutdown_button(name, item); + }; + + TerminalList.prototype.add_shutdown_button = function(name, item) { + var that = this; + var shutdown_button = $("").text("Shutdown").addClass("btn btn-xs btn-danger"). + click(function (e) { + var settings = { + processData : false, + type : "DELETE", + dataType : "json", + success : function () { + that.load_terminals(); + }, + error : utils.log_ajax_error, + }; + var url = utils.url_join_encode(that.base_url, 'api/terminals', name); + $.ajax(url, settings); + return false; + }); + item.find(".item_buttons").text("").append(shutdown_button); + }; + + return {TerminalList: TerminalList}; +}); diff --git a/IPython/html/templates/tree.html b/IPython/html/templates/tree.html index 3ecc07a..b800b69 100644 --- a/IPython/html/templates/tree.html +++ b/IPython/html/templates/tree.html @@ -12,6 +12,7 @@ data-base-url="{{base_url}}" data-notebook-path="{{notebook_path}}" +data-terminals-available="{{terminals_available}}" {% endblock %} @@ -24,6 +25,9 @@ data-notebook-path="{{notebook_path}}"
@@ -79,6 +83,29 @@ data-notebook-path="{{notebook_path}}" + + {% if terminals_available %} +