Kaynağa Gözat

Merge pull request #892 from R-Brain/ak/kernel_toolbar

Fixes jupyter/jupyterlab#891: kernel toolbar
Steven Silvester 8 yıl önce
ebeveyn
işleme
ecf29fa7f2

+ 8 - 156
src/notebook/notebook/default-toolbar.ts

@@ -1,18 +1,10 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import {
-  IKernel
-} from 'jupyter-js-services';
-
 import {
   Widget
 } from 'phosphor/lib/ui/widget';
 
-import {
-  restartKernel
-} from '../../docregistry';
-
 import {
   NotebookActions
 } from './actions';
@@ -29,6 +21,13 @@ import {
   ToolbarButton
 } from '../../toolbar';
 
+import {
+  createInterruptButton,
+  createRestartButton,
+  createKernelNameItem,
+  createKernelStatusItem
+} from '../../toolbar/kernel';
+
 import {
   Notebook
 } from './widget';
@@ -64,16 +63,6 @@ const TOOLBAR_PASTE_CLASS = 'jp-Notebook-toolbarPaste';
  */
 const TOOLBAR_RUN_CLASS = 'jp-Notebook-toolbarRun';
 
-/**
- * The class name added to toolbar interrupt button.
- */
-const TOOLBAR_INTERRUPT_CLASS = 'jp-Notebook-toolbarInterrupt';
-
-/**
- * The class name added to toolbar restart button.
- */
-const TOOLBAR_RESTART_CLASS = 'jp-Notebook-toolbarRestart';
-
 /**
  * The class name added to toolbar cell type dropdown wrapper.
  */
@@ -84,21 +73,6 @@ const TOOLBAR_CELLTYPE_CLASS = 'jp-Notebook-toolbarCellType';
  */
 const TOOLBAR_CELLTYPE_DROPDOWN_CLASS = 'jp-Notebook-toolbarCellTypeDropdown';
 
-/**
- * The class name added to toolbar kernel name text.
- */
-const TOOLBAR_KERNEL_CLASS = 'jp-Notebook-toolbarKernelName';
-
-/**
- * The class name added to toolbar kernel indicator icon.
- */
-const TOOLBAR_INDICATOR_CLASS = 'jp-Notebook-toolbarKernelIndicator';
-
-/**
- * The class name added to a busy kernel indicator.
- */
-const TOOLBAR_BUSY_CLASS = 'jp-mod-busy';
-
 
 /**
  * A namespace for the default toolbar items.
@@ -189,36 +163,6 @@ namespace ToolbarItems {
     });
   }
 
-  /**
-   * Create an interrupt toolbar item.
-   */
-  export
-  function createInterruptButton(panel: NotebookPanel): ToolbarButton {
-    return new ToolbarButton({
-      className: TOOLBAR_INTERRUPT_CLASS,
-      onClick: () => {
-        if (panel.kernel) {
-          panel.context.kernel.interrupt();
-        }
-      },
-      tooltip: 'Interrupt the kernel'
-    });
-  }
-
-  /**
-   * Create a restart toolbar item.
-   */
-  export
-  function createRestartButton(panel: NotebookPanel): ToolbarButton {
-    return new ToolbarButton({
-      className: TOOLBAR_RESTART_CLASS,
-      onClick: () => {
-        restartKernel(panel.kernel, panel.node);
-      },
-      tooltip: 'Restart the kernel'
-    });
-  }
-
   /**
    * Create a cell type switcher item.
    *
@@ -235,56 +179,6 @@ namespace ToolbarItems {
     return new CellTypeSwitcher(panel.content);
   }
 
-  /**
-   * Create a kernel name indicator item.
-   *
-   * #### Notes
-   * It will display the `'display_name`' of the current kernel,
-   * or `'No Kernel!'` if there is no kernel.
-   * It can handle a change in context or kernel.
-   */
-  export
-  function createKernelNameItem(panel: NotebookPanel): Widget {
-    let widget = new Widget();
-    widget.addClass(TOOLBAR_KERNEL_CLASS);
-    updateKernelNameItem(widget, panel.kernel);
-    panel.kernelChanged.connect(() => {
-      updateKernelNameItem(widget, panel.kernel);
-    });
-    return widget;
-  }
-
-  /**
-   * Update the text of the kernel name item.
-   */
-  function updateKernelNameItem(widget: Widget, kernel: IKernel): void {
-    widget.node.textContent = 'No Kernel!';
-    if (!kernel) {
-      return;
-    }
-    if (kernel.spec) {
-      widget.node.textContent = kernel.spec.display_name;
-    } else {
-      kernel.getKernelSpec().then(spec => {
-        widget.node.textContent = kernel.spec.display_name;
-      });
-    }
-  }
-
-  /**
-   * Create a kernel status indicator item.
-   *
-   * #### Notes
-   * It show display a busy status if the kernel status is
-   * not idle.
-   * It will show the current status in the node title.
-   * It can handle a change to the context or the kernel.
-   */
-  export
-  function createKernelStatusItem(panel: NotebookPanel): Widget {
-    return new KernelIndicator(panel);
-  }
-
   /**
    * Add the default items to the panel toolbar.
    */
@@ -298,7 +192,7 @@ namespace ToolbarItems {
     toolbar.add('paste', createPasteButton(panel));
     toolbar.add('run', createRunButton(panel));
     toolbar.add('interrupt', createInterruptButton(panel));
-    toolbar.add('restart', createRestartButton(panel));
+    toolbar.add('restart', createRestartButton(panel, panel.node));
     toolbar.add('cellType', createCellTypeItem(panel));
     toolbar.add('kernelName', createKernelNameItem(panel));
     toolbar.add('kernelStatus', createKernelStatusItem(panel));
@@ -396,45 +290,3 @@ function createCellTypeSwitcherNode(): HTMLElement {
   div.appendChild(select);
   return div;
 }
-
-
-/**
- * A toolbar item that displays kernel status.
- */
-class KernelIndicator extends Widget {
-  /**
-   * Construct a new kernel status widget.
-   */
-  constructor(panel: NotebookPanel) {
-    super();
-    this.addClass(TOOLBAR_INDICATOR_CLASS);
-    if (panel.kernel) {
-      this._handleStatus(panel.kernel, panel.kernel.status);
-      panel.kernel.statusChanged.connect(this._handleStatus, this);
-    } else {
-      this.addClass(TOOLBAR_BUSY_CLASS);
-      this.node.title = 'No Kernel!';
-    }
-    panel.kernelChanged.connect((c, kernel) => {
-      if (kernel) {
-        this._handleStatus(kernel, kernel.status);
-        kernel.statusChanged.connect(this._handleStatus, this);
-      } else {
-        this.node.title = 'No Kernel!';
-        this.addClass(TOOLBAR_BUSY_CLASS);
-      }
-    });
-  }
-
-  /**
-   * Handle a status on a kernel.
-   */
-  private _handleStatus(kernel: IKernel, status: IKernel.Status) {
-    if (this.isDisposed) {
-      return;
-    }
-    this.toggleClass(TOOLBAR_BUSY_CLASS, status !== 'idle');
-    let title = 'Kernel ' + status[0].toUpperCase() + status.slice(1);
-    this.node.title = title;
-  }
-}

+ 7 - 7
src/notebook/toolbar.css

@@ -4,7 +4,7 @@
 |----------------------------------------------------------------------------*/
 
 
-.jp-Toolbar-item.jp-Notebook-toolbarKernelIndicator {
+.jp-Toolbar-item.jp-Kernel-toolbarKernelIndicator {
   font-family: FontAwesome;
   text-align: center;
   display: inline-block;
@@ -26,14 +26,14 @@
 }
 
 
-.jp-Toolbar > .jp-Toolbar-item.jp-Notebook-toolbarKernelName {
+.jp-Toolbar > .jp-Toolbar-item.jp-Kernel-toolbarKernelName {
   text-align: right;
   flex-grow: 1;
   flex-shrink: 1;
 }
 
 
-.jp-Toolbar-item.jp-Notebook-toolbarKernelIndicator {
+.jp-Toolbar-item.jp-Kernel-toolbarKernelIndicator {
   border-right: none;
 }
 
@@ -68,21 +68,21 @@
 }
 
 
-.jp-Notebook-toolbarInterrupt::before {
+.jp-Kernel-toolbarInterrupt::before {
   content: "\f04d";  /* stop */
 }
 
 
-.jp-Notebook-toolbarRestart::before {
+.jp-Kernel-toolbarRestart::before {
   content: "\f01e";  /* rotate-right */
 }
 
 
-.jp-Notebook-toolbarKernelIndicator::before {
+.jp-Kernel-toolbarKernelIndicator::before {
   content: "\f10c";  /* circle-o */
 }
 
 
-.jp-Notebook-toolbarKernelIndicator.jp-mod-busy::before {
+.jp-Kernel-toolbarKernelIndicator.jp-mod-busy::before {
   content: "\f111";  /* circle */
 }

+ 183 - 0
src/toolbar/kernel.ts

@@ -0,0 +1,183 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  IKernel
+} from 'jupyter-js-services';
+
+import {
+  ISignal
+} from 'phosphor/lib/core/signaling';
+
+import {
+  Widget
+} from 'phosphor/lib/ui/widget';
+
+import {
+  restartKernel
+} from '../docregistry';
+
+import {
+  ToolbarButton
+} from './index';
+
+/**
+ * The class name added to toolbar interrupt button.
+ */
+const TOOLBAR_INTERRUPT_CLASS = 'jp-Kernel-toolbarInterrupt';
+
+/**
+ * The class name added to toolbar restart button.
+ */
+const TOOLBAR_RESTART_CLASS = 'jp-Kernel-toolbarRestart';
+
+/**
+ * The class name added to toolbar kernel name text.
+ */
+const TOOLBAR_KERNEL_CLASS = 'jp-Kernel-toolbarKernelName';
+
+/**
+ * The class name added to toolbar kernel indicator icon.
+ */
+const TOOLBAR_INDICATOR_CLASS = 'jp-Kernel-toolbarKernelIndicator';
+
+/**
+ * The class name added to a busy kernel indicator.
+ */
+const TOOLBAR_BUSY_CLASS = 'jp-mod-busy';
+
+/**
+ * A kernel owner interface.
+ */
+export
+interface IKernelOwner {
+  /**
+   * An associated kernel.
+   */
+  kernel: IKernel;
+  /**
+   * A signal emitted when the kernel is changed.
+   */
+  kernelChanged: ISignal<IKernelOwner, IKernel>;
+}
+
+/**
+ * Create an interrupt toolbar item.
+ */
+export
+function createInterruptButton(kernelOwner: IKernelOwner): ToolbarButton {
+  return new ToolbarButton({
+    className: TOOLBAR_INTERRUPT_CLASS,
+    onClick: () => {
+      if (kernelOwner.kernel) {
+        kernelOwner.kernel.interrupt();
+      }
+    },
+    tooltip: 'Interrupt the kernel'
+  });
+}
+
+/**
+ * Create a restart toolbar item.
+ */
+export
+function createRestartButton(kernelOwner: IKernelOwner, host?: HTMLElement): ToolbarButton {
+  return new ToolbarButton({
+    className: TOOLBAR_RESTART_CLASS,
+    onClick: () => {
+      restartKernel(kernelOwner.kernel, host);
+    },
+    tooltip: 'Restart the kernel'
+  });
+}
+
+/**
+ * Create a kernel name indicator item.
+ *
+ * #### Notes
+ * It will display the `'display_name`' of the current kernel,
+ * or `'No Kernel!'` if there is no kernel.
+ * It can handle a change in context or kernel.
+ */
+export
+function createKernelNameItem(kernelOwner: IKernelOwner): Widget {
+  let widget = new Widget();
+  widget.addClass(TOOLBAR_KERNEL_CLASS);
+  updateKernelNameItem(widget, kernelOwner.kernel);
+  kernelOwner.kernelChanged.connect(() => {
+    updateKernelNameItem(widget, kernelOwner.kernel);
+  });
+  return widget;
+}
+
+/**
+ * Update the text of the kernel name item.
+ */
+function updateKernelNameItem(widget: Widget, kernel: IKernel): void {
+  widget.node.textContent = 'No Kernel!';
+  if (!kernel) {
+    return;
+  }
+  if (kernel.spec) {
+    widget.node.textContent = kernel.spec.display_name;
+  } else {
+    kernel.getKernelSpec().then(spec => {
+      widget.node.textContent = kernel.spec.display_name;
+    });
+  }
+}
+
+/**
+ * Create a kernel status indicator item.
+ *
+ * #### Notes
+ * It show display a busy status if the kernel status is
+ * not idle.
+ * It will show the current status in the node title.
+ * It can handle a change to the context or the kernel.
+ */
+export
+function createKernelStatusItem(kernelOwner: IKernelOwner): Widget {
+  return new KernelIndicator(kernelOwner);
+}
+
+/**
+ * A toolbar item that displays kernel status.
+ */
+class KernelIndicator extends Widget {
+  /**
+   * Construct a new kernel status widget.
+   */
+  constructor(kernelOwner: IKernelOwner) {
+    super();
+    this.addClass(TOOLBAR_INDICATOR_CLASS);
+    if (kernelOwner.kernel) {
+      this._handleStatus(kernelOwner.kernel, kernelOwner.kernel.status);
+      kernelOwner.kernel.statusChanged.connect(this._handleStatus, this);
+    } else {
+      this.addClass(TOOLBAR_BUSY_CLASS);
+      this.node.title = 'No Kernel!';
+    }
+    kernelOwner.kernelChanged.connect((c, kernel) => {
+      if (kernel) {
+        this._handleStatus(kernel, kernel.status);
+        kernel.statusChanged.connect(this._handleStatus, this);
+      } else {
+        this.node.title = 'No Kernel!';
+        this.addClass(TOOLBAR_BUSY_CLASS);
+      }
+    });
+  }
+
+  /**
+   * Handle a status on a kernel.
+   */
+  private _handleStatus(kernel: IKernel, status: IKernel.Status) {
+    if (this.isDisposed) {
+      return;
+    }
+    this.toggleClass(TOOLBAR_BUSY_CLASS, status !== 'idle');
+    let title = 'Kernel ' + status[0].toUpperCase() + status.slice(1);
+    this.node.title = title;
+  }
+}

+ 23 - 16
test/src/notebook/notebook/default-toolbar.spec.ts

@@ -19,6 +19,13 @@ import {
   JUPYTER_CELL_MIME, NotebookActions
 } from '../../../../lib/notebook/notebook/actions';
 
+import {
+ createInterruptButton,
+ createKernelNameItem,
+ createKernelStatusItem,
+ createRestartButton
+} from '../../../../lib/toolbar/kernel';
+
 import {
  ToolbarItems
 } from '../../../../lib/notebook/notebook/default-toolbar';
@@ -206,7 +213,7 @@ describe('notebook/notebook/default-toolbar', () => {
     describe('#createInterruptButton()', () => {
 
       it('should interrupt the kernel when clicked', (done) => {
-        let button = ToolbarItems.createInterruptButton(panel);
+        let button = createInterruptButton(panel);
         Widget.attach(button, document.body);
         button.node.click();
         expect(panel.context.kernel.status).to.be('busy');
@@ -218,18 +225,18 @@ describe('notebook/notebook/default-toolbar', () => {
         });
       });
 
-      it('should have the `\'jp-Notebook-toolbarInterrupt\'` class', () => {
-        let button = ToolbarItems.createInterruptButton(panel);
-        expect(button.hasClass('jp-Notebook-toolbarInterrupt')).to.be(true);
+      it('should have the `\'jp-Kernel-toolbarInterrupt\'` class', () => {
+        let button = createInterruptButton(panel);
+        expect(button.hasClass('jp-Kernel-toolbarInterrupt')).to.be(true);
       });
 
     });
 
     describe('#createRestartButton()', () => {
 
-      it('should have the `\'jp-Notebook-toolbarRestart\'` class', () => {
-        let button = ToolbarItems.createRestartButton(panel);
-        expect(button.hasClass('jp-Notebook-toolbarRestart')).to.be(true);
+      it('should have the `\'jp-Kernel-toolbarRestart\'` class', () => {
+        let button = createRestartButton(panel);
+        expect(button.hasClass('jp-Kernel-toolbarRestart')).to.be(true);
       });
 
     });
@@ -279,7 +286,7 @@ describe('notebook/notebook/default-toolbar', () => {
     describe('#createKernelNameItem()', () => {
 
       it('should display the `\'display_name\'` of the kernel', (done) => {
-        let item = ToolbarItems.createKernelNameItem(panel);
+        let item = createKernelNameItem(panel);
         panel.kernel.getKernelSpec().then(spec => {
           expect(item.node.textContent).to.be(spec.display_name);
           done();
@@ -288,12 +295,12 @@ describe('notebook/notebook/default-toolbar', () => {
 
       it('should display `\'No Kernel!\'` if there is no kernel', () => {
         panel.context = null;
-        let item = ToolbarItems.createKernelNameItem(panel);
+        let item = createKernelNameItem(panel);
         expect(item.node.textContent).to.be('No Kernel!');
       });
 
       it('should handle a change in kernel', (done) => {
-        let item = ToolbarItems.createKernelNameItem(panel);
+        let item = createKernelNameItem(panel);
         panel.context.changeKernel({ name: 'shell' }).then(kernel => {
           kernel.getKernelSpec().then(spec => {
             expect(item.node.textContent).to.be(spec.display_name);
@@ -303,7 +310,7 @@ describe('notebook/notebook/default-toolbar', () => {
       });
 
       it('should handle a change in context', (done) => {
-        let item = ToolbarItems.createKernelNameItem(panel);
+        let item = createKernelNameItem(panel);
         panel.kernel.getKernelSpec().then(spec => {
           panel.context = null;
           expect(item.node.textContent).to.be('No Kernel!');
@@ -315,7 +322,7 @@ describe('notebook/notebook/default-toolbar', () => {
     describe('#createKernelStatusItem()', () => {
 
       it('should display a busy status if the kernel status is not idle', (done) => {
-        let item = ToolbarItems.createKernelStatusItem(panel);
+        let item = createKernelStatusItem(panel);
         expect(item.hasClass('jp-mod-busy')).to.be(false);
         panel.kernel.statusChanged.connect(() => {
           if (panel.kernel.status === 'busy') {
@@ -327,7 +334,7 @@ describe('notebook/notebook/default-toolbar', () => {
       });
 
       it('should show the current status in the node title', (done) => {
-        let item = ToolbarItems.createKernelStatusItem(panel);
+        let item = createKernelStatusItem(panel);
         let status = panel.kernel.status;
         expect(item.node.title.toLowerCase()).to.contain(status);
         panel.kernel.statusChanged.connect(() => {
@@ -340,7 +347,7 @@ describe('notebook/notebook/default-toolbar', () => {
       });
 
       it('should handle a change to the kernel', (done) => {
-        let item = ToolbarItems.createKernelStatusItem(panel);
+        let item = createKernelStatusItem(panel);
         panel.context.changeKernel({ name: 'shell' }).then(() => {
           panel.kernel.statusChanged.connect(() => {
             if (panel.kernel.status === 'busy') {
@@ -353,7 +360,7 @@ describe('notebook/notebook/default-toolbar', () => {
       });
 
       it('should handle a null kernel', (done) => {
-        let item = ToolbarItems.createKernelStatusItem(panel);
+        let item = createKernelStatusItem(panel);
         panel.context.changeKernel(void 0).then(() => {
           expect(item.node.title).to.be('No Kernel!');
           expect(item.hasClass('jp-mod-busy')).to.be(true);
@@ -361,7 +368,7 @@ describe('notebook/notebook/default-toolbar', () => {
       });
 
       it('should handle a change to the context', (done) => {
-        let item = ToolbarItems.createKernelStatusItem(panel);
+        let item = createKernelStatusItem(panel);
         let model = new NotebookModel();
         model.fromJSON(DEFAULT_CONTENT);
         context = new MockContext<NotebookModel>(model);