Sfoglia il codice sorgente

Move shell into a provider, [WIP]

Afshin Darian 6 anni fa
parent
commit
dcc187f218

+ 15 - 3
packages/application-extension/src/index.tsx

@@ -2,11 +2,12 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
+  IApplicationShell,
+  ILayoutRestorer,
+  IRouter,
   JupyterClient,
   JupyterLab,
   JupyterLabPlugin,
-  ILayoutRestorer,
-  IRouter,
   LayoutRestorer,
   Router
 } from '@jupyterlab/application';
@@ -521,6 +522,16 @@ function addCommands(app: JupyterLab, palette: ICommandPalette): void {
   palette.addItem({ command, category });
 }
 
+/**
+ * The default JupyterLab application shell.
+ */
+const shell: JupyterLabPlugin<IApplicationShell> = {
+  id: '@jupyterlab/application-extension:shell',
+  activate: (app: JupyterLab) => app.shell,
+  autoStart: true,
+  provides: IApplicationShell
+};
+
 /**
  * Export the plugins as default.
  */
@@ -531,7 +542,8 @@ const plugins: JupyterLabPlugin<any>[] = [
   tree,
   notfound,
   busy,
-  sidebar
+  sidebar,
+  shell
 ];
 
 export default plugins;

+ 4 - 4
packages/application/src/index.ts

@@ -22,7 +22,7 @@ import { Widget } from '@phosphor/widgets';
 
 import { createRendermimePlugins } from './mimerenderers';
 
-import { ApplicationShell } from './shell';
+import { ApplicationShell, IApplicationShell } from './shell';
 
 import { ISignal, Signal } from '@phosphor/signaling';
 
@@ -32,7 +32,7 @@ export { IMimeDocumentTracker } from './mimerenderers';
 
 export { IRouter, Router } from './router';
 
-export { ApplicationShell } from './shell';
+export { ApplicationShell, IApplicationShell } from './shell';
 
 /**
  * The base Jupyter client application class.
@@ -121,7 +121,7 @@ export type JupyterLabPlugin<T> = IPlugin<JupyterClient, T>;
  */
 export class JupyterLab extends JupyterClient<
   ApplicationShell,
-  ApplicationShell.ILayout
+  IApplicationShell.ILayout
 > {
   /**
    * Construct a new JupyterLab object.
@@ -189,7 +189,7 @@ export class JupyterLab extends JupyterClient<
    * Promise that resolves when state is first restored, returning layout
    * description.
    */
-  readonly restored: Promise<ApplicationShell.ILayout> = this.shell.restored;
+  readonly restored: Promise<IApplicationShell.ILayout> = this.shell.restored;
 
   /**
    * A method invoked on a document `'contextmenu'` event.

+ 15 - 15
packages/application/src/layoutrestorer.ts

@@ -20,7 +20,7 @@ import { AttachedProperty } from '@phosphor/properties';
 
 import { DockPanel, Widget } from '@phosphor/widgets';
 
-import { ApplicationShell } from './shell';
+import { IApplicationShell } from './shell';
 
 /* tslint:disable */
 /**
@@ -196,8 +196,8 @@ export class LayoutRestorer implements ILayoutRestorer {
    * Fetching the layout relies on all widget restoration to be complete, so
    * calls to `fetch` are guaranteed to return after restoration is complete.
    */
-  fetch(): Promise<ApplicationShell.ILayout> {
-    const blank: ApplicationShell.ILayout = {
+  fetch(): Promise<IApplicationShell.ILayout> {
+    const blank: IApplicationShell.ILayout = {
       fresh: true,
       mainArea: null,
       leftArea: null,
@@ -302,7 +302,7 @@ export class LayoutRestorer implements ILayoutRestorer {
   /**
    * Save the layout state for the application.
    */
-  save(data: ApplicationShell.ILayout): Promise<void> {
+  save(data: IApplicationShell.ILayout): Promise<void> {
     // If there are promises that are unresolved, bail.
     if (!this._promisesDone) {
       let warning = 'save() was called prematurely.';
@@ -328,7 +328,7 @@ export class LayoutRestorer implements ILayoutRestorer {
    * Dehydrate a main area description into a serializable object.
    */
   private _dehydrateMainArea(
-    area: ApplicationShell.IMainArea | null
+    area: IApplicationShell.IMainArea | null
   ): Private.IMainArea | null {
     if (!area) {
       return null;
@@ -345,7 +345,7 @@ export class LayoutRestorer implements ILayoutRestorer {
    */
   private _rehydrateMainArea(
     area?: Private.IMainArea | null
-  ): ApplicationShell.IMainArea | null {
+  ): IApplicationShell.IMainArea | null {
     if (!area) {
       return null;
     }
@@ -356,7 +356,7 @@ export class LayoutRestorer implements ILayoutRestorer {
    * Dehydrate a side area description into a serializable object.
    */
   private _dehydrateSideArea(
-    area?: ApplicationShell.ISideArea | null
+    area?: IApplicationShell.ISideArea | null
   ): Private.ISideArea | null {
     if (!area) {
       return null;
@@ -385,7 +385,7 @@ export class LayoutRestorer implements ILayoutRestorer {
    */
   private _rehydrateSideArea(
     area?: Private.ISideArea | null
-  ): ApplicationShell.ISideArea {
+  ): IApplicationShell.ISideArea {
     if (!area) {
       return { collapsed: true, currentWidget: null, widgets: null };
     }
@@ -585,7 +585,7 @@ namespace Private {
    * Serialize individual areas within the main area.
    */
   function serializeArea(
-    area: ApplicationShell.AreaConfig | null
+    area: IApplicationShell.AreaConfig | null
   ): ITabArea | ISplitArea | null {
     if (!area || !area.type) {
       return null;
@@ -612,7 +612,7 @@ namespace Private {
   /**
    * Return a dehydrated, serializable version of the main dock panel.
    */
-  export function serializeMain(area: ApplicationShell.IMainArea): IMainArea {
+  export function serializeMain(area: IApplicationShell.IMainArea): IMainArea {
     let dehydrated: IMainArea = {
       dock: (area && area.dock && serializeArea(area.dock.main)) || null
     };
@@ -641,7 +641,7 @@ namespace Private {
   function deserializeArea(
     area: JSONObject,
     names: Map<string, Widget>
-  ): ApplicationShell.AreaConfig | null {
+  ): IApplicationShell.AreaConfig | null {
     if (!area) {
       return null;
     }
@@ -656,7 +656,7 @@ namespace Private {
 
     if (type === 'tab-area') {
       const { currentIndex, widgets } = area as ITabArea;
-      let hydrated: ApplicationShell.AreaConfig = {
+      let hydrated: IApplicationShell.AreaConfig = {
         type: 'tab-area',
         currentIndex: currentIndex || 0,
         widgets:
@@ -676,7 +676,7 @@ namespace Private {
     }
 
     const { orientation, sizes, children } = area as ISplitArea;
-    let hydrated: ApplicationShell.AreaConfig = {
+    let hydrated: IApplicationShell.AreaConfig = {
       type: 'split-area',
       orientation: orientation,
       sizes: sizes || [],
@@ -684,7 +684,7 @@ namespace Private {
         (children &&
           (children
             .map(child => deserializeArea(child, names))
-            .filter(widget => !!widget) as ApplicationShell.AreaConfig[])) ||
+            .filter(widget => !!widget) as IApplicationShell.AreaConfig[])) ||
         []
     };
 
@@ -703,7 +703,7 @@ namespace Private {
   export function deserializeMain(
     area: JSONObject,
     names: Map<string, Widget>
-  ): ApplicationShell.IMainArea | null {
+  ): IApplicationShell.IMainArea | null {
     if (!area) {
       return null;
     }

+ 140 - 126
packages/application/src/shell.ts

@@ -3,7 +3,7 @@
 
 import { ArrayExt, find, IIterator, iter, toArray } from '@phosphor/algorithm';
 
-import { PromiseDelegate } from '@phosphor/coreutils';
+import { PromiseDelegate, Token } from '@phosphor/coreutils';
 
 import { Message, MessageLoop, IMessageHandler } from '@phosphor/messaging';
 
@@ -57,6 +57,126 @@ const MODE_ATTRIBUTE = 'data-shell-mode';
 
 const ACTIVITY_CLASS = 'jp-Activity';
 
+/* tslint:disable */
+/**
+ * The layout restorer token.
+ */
+export const IApplicationShell = new Token<IApplicationShell>(
+  '@jupyterlab/application:IApplicationShell'
+);
+/* tslint:enable */
+
+/**
+ * The JupyterLab application shell.
+ */
+export interface IApplicationShell extends ApplicationShell {}
+
+/**
+ * The namespace for `IApplicationShell` type information.
+ */
+export namespace IApplicationShell {
+  /**
+   * The areas of the application shell where widgets can reside.
+   */
+  export type Area = 'main' | 'top' | 'left' | 'right' | 'bottom';
+
+  /**
+   * The restorable description of an area within the main dock panel.
+   */
+  export type AreaConfig = DockLayout.AreaConfig;
+
+  /**
+   * An arguments object for the changed signals.
+   */
+  export type IChangedArgs = FocusTracker.IChangedArgs<Widget>;
+
+  /**
+   * A description of the application's user interface layout.
+   */
+  export interface ILayout {
+    /**
+     * Indicates whether fetched session restore data was actually retrieved
+     * from the state database or whether it is a fresh blank slate.
+     *
+     * #### Notes
+     * This attribute is only relevant when the layout data is retrieved via a
+     * `fetch` call. If it is set when being passed into `save`, it will be
+     * ignored.
+     */
+    readonly fresh?: boolean;
+
+    /**
+     * The main area of the user interface.
+     */
+    readonly mainArea: IMainArea | null;
+
+    /**
+     * The left area of the user interface.
+     */
+    readonly leftArea: ISideArea | null;
+
+    /**
+     * The right area of the user interface.
+     */
+    readonly rightArea: ISideArea | null;
+  }
+
+  /**
+   * The restorable description of the main application area.
+   */
+  export interface IMainArea {
+    /**
+     * The current widget that has application focus.
+     */
+    readonly currentWidget: Widget | null;
+
+    /**
+     * The contents of the main application dock panel.
+     */
+    readonly dock: DockLayout.ILayoutConfig | null;
+
+    /**
+     * The document mode (i.e., multiple/single) of the main dock panel.
+     */
+    readonly mode: DockPanel.Mode | null;
+  }
+
+  /**
+   * The restorable description of a sidebar in the user interface.
+   */
+  export interface ISideArea {
+    /**
+     * A flag denoting whether the sidebar has been collapsed.
+     */
+    readonly collapsed: boolean;
+
+    /**
+     * The current widget that has side area focus.
+     */
+    readonly currentWidget: Widget | null;
+
+    /**
+     * The collection of widgets held by the sidebar.
+     */
+    readonly widgets: Array<Widget> | null;
+  }
+
+  /**
+   * The options for adding a widget to a side area of the shell.
+   */
+  export interface ISideAreaOptions {
+    /**
+     * The rank order of the widget among its siblings.
+     */
+    rank?: number;
+  }
+
+  /**
+   * The options for adding a widget to a side area of the shell.
+   */
+  export interface IMainAreaOptions extends DocumentRegistry.IOpenOptions {}
+}
+
 /**
  * The application shell for JupyterLab.
  */
@@ -169,7 +289,7 @@ export class ApplicationShell extends Widget {
   /**
    * A signal emitted when main area's active focus changes.
    */
-  get activeChanged(): ISignal<this, ApplicationShell.IChangedArgs> {
+  get activeChanged(): ISignal<this, IApplicationShell.IChangedArgs> {
     return this._activeChanged;
   }
 
@@ -183,7 +303,7 @@ export class ApplicationShell extends Widget {
   /**
    * A signal emitted when main area's current focus changes.
    */
-  get currentChanged(): ISignal<this, ApplicationShell.IChangedArgs> {
+  get currentChanged(): ISignal<this, IApplicationShell.IChangedArgs> {
     return this._currentChanged;
   }
 
@@ -301,7 +421,7 @@ export class ApplicationShell extends Widget {
    * Promise that resolves when state is first restored, returning layout
    * description.
    */
-  get restored(): Promise<ApplicationShell.ILayout> {
+  get restored(): Promise<IApplicationShell.ILayout> {
     return this._restored.promise;
   }
 
@@ -402,7 +522,7 @@ export class ApplicationShell extends Widget {
    */
   addToLeftArea(
     widget: Widget,
-    options?: ApplicationShell.ISideAreaOptions
+    options?: IApplicationShell.ISideAreaOptions
   ): void {
     if (!widget.id) {
       console.error('Widgets added to app shell must have unique id property.');
@@ -428,7 +548,7 @@ export class ApplicationShell extends Widget {
    */
   addToMainArea(
     widget: Widget,
-    options: ApplicationShell.IMainAreaOptions = {}
+    options: IApplicationShell.IMainAreaOptions = {}
   ): void {
     if (!widget.id) {
       console.error('Widgets added to app shell must have unique id property.');
@@ -467,7 +587,7 @@ export class ApplicationShell extends Widget {
    */
   addToRightArea(
     widget: Widget,
-    options?: ApplicationShell.ISideAreaOptions
+    options?: IApplicationShell.ISideAreaOptions
   ): void {
     if (!widget.id) {
       console.error('Widgets added to app shell must have unique id property.');
@@ -488,7 +608,7 @@ export class ApplicationShell extends Widget {
    */
   addToTopArea(
     widget: Widget,
-    options: ApplicationShell.ISideAreaOptions = {}
+    options: IApplicationShell.ISideAreaOptions = {}
   ): void {
     if (!widget.id) {
       console.error('Widgets added to app shell must have unique id property.');
@@ -508,7 +628,7 @@ export class ApplicationShell extends Widget {
 
   addToBottomArea(
     widget: Widget,
-    options: ApplicationShell.ISideAreaOptions = {}
+    options: IApplicationShell.ISideAreaOptions = {}
   ): void {
     if (!widget.id) {
       console.error('Widgets added to app shell must have unique id property.');
@@ -576,7 +696,7 @@ export class ApplicationShell extends Widget {
   /**
    * True if the given area is empty.
    */
-  isEmpty(area: ApplicationShell.Area): boolean {
+  isEmpty(area: IApplicationShell.Area): boolean {
     switch (area) {
       case 'left':
         return this._leftHandler.stackedPanel.widgets.length === 0;
@@ -596,7 +716,7 @@ export class ApplicationShell extends Widget {
   /**
    * Restore the layout state for the application shell.
    */
-  restoreLayout(layout: ApplicationShell.ILayout): void {
+  restoreLayout(layout: IApplicationShell.ILayout): void {
     const { mainArea, leftArea, rightArea } = layout;
 
     // Rehydrate the main area.
@@ -636,7 +756,7 @@ export class ApplicationShell extends Widget {
   /**
    * Save the dehydrated state of the application shell.
    */
-  saveLayout(): ApplicationShell.ILayout {
+  saveLayout(): IApplicationShell.ILayout {
     // If the application is in single document mode, use the cached layout if
     // available. Otherwise, default to querying the dock panel for layout.
     return {
@@ -656,7 +776,7 @@ export class ApplicationShell extends Widget {
   /**
    * Returns the widgets for an application area.
    */
-  widgets(area: ApplicationShell.Area): IIterator<Widget> {
+  widgets(area: IApplicationShell.Area): IIterator<Widget> {
     switch (area) {
       case 'main':
         return this._dockPanel.widgets();
@@ -796,18 +916,18 @@ export class ApplicationShell extends Widget {
     return true;
   };
 
-  private _activeChanged = new Signal<this, ApplicationShell.IChangedArgs>(
+  private _activeChanged = new Signal<this, IApplicationShell.IChangedArgs>(
     this
   );
   private _cachedLayout: DockLayout.ILayoutConfig | null = null;
-  private _currentChanged = new Signal<this, ApplicationShell.IChangedArgs>(
+  private _currentChanged = new Signal<this, IApplicationShell.IChangedArgs>(
     this
   );
   private _dockPanel: DockPanel;
   private _isRestored = false;
   private _layoutModified = new Signal<this, void>(this);
   private _leftHandler: Private.SideBarHandler;
-  private _restored = new PromiseDelegate<ApplicationShell.ILayout>();
+  private _restored = new PromiseDelegate<IApplicationShell.ILayout>();
   private _rightHandler: Private.SideBarHandler;
   private _tracker = new FocusTracker<Widget>();
   private _topPanel: Panel;
@@ -815,120 +935,14 @@ export class ApplicationShell extends Widget {
   private _debouncer = 0;
   private _addOptionsCache = new Map<
     Widget,
-    ApplicationShell.IMainAreaOptions
+    IApplicationShell.IMainAreaOptions
   >();
   private _sideOptionsCache = new Map<
     Widget,
-    ApplicationShell.ISideAreaOptions
+    IApplicationShell.ISideAreaOptions
   >();
 }
 
-/**
- * The namespace for `ApplicationShell` class statics.
- */
-export namespace ApplicationShell {
-  /**
-   * The areas of the application shell where widgets can reside.
-   */
-  export type Area = 'main' | 'top' | 'left' | 'right' | 'bottom';
-
-  /**
-   * The restorable description of an area within the main dock panel.
-   */
-  export type AreaConfig = DockLayout.AreaConfig;
-
-  /**
-   * An arguments object for the changed signals.
-   */
-  export type IChangedArgs = FocusTracker.IChangedArgs<Widget>;
-
-  /**
-   * A description of the application's user interface layout.
-   */
-  export interface ILayout {
-    /**
-     * Indicates whether fetched session restore data was actually retrieved
-     * from the state database or whether it is a fresh blank slate.
-     *
-     * #### Notes
-     * This attribute is only relevant when the layout data is retrieved via a
-     * `fetch` call. If it is set when being passed into `save`, it will be
-     * ignored.
-     */
-    readonly fresh?: boolean;
-
-    /**
-     * The main area of the user interface.
-     */
-    readonly mainArea: IMainArea | null;
-
-    /**
-     * The left area of the user interface.
-     */
-    readonly leftArea: ISideArea | null;
-
-    /**
-     * The right area of the user interface.
-     */
-    readonly rightArea: ISideArea | null;
-  }
-
-  /**
-   * The restorable description of the main application area.
-   */
-  export interface IMainArea {
-    /**
-     * The current widget that has application focus.
-     */
-    readonly currentWidget: Widget | null;
-
-    /**
-     * The contents of the main application dock panel.
-     */
-    readonly dock: DockLayout.ILayoutConfig | null;
-
-    /**
-     * The document mode (i.e., multiple/single) of the main dock panel.
-     */
-    readonly mode: DockPanel.Mode | null;
-  }
-
-  /**
-   * The restorable description of a sidebar in the user interface.
-   */
-  export interface ISideArea {
-    /**
-     * A flag denoting whether the sidebar has been collapsed.
-     */
-    readonly collapsed: boolean;
-
-    /**
-     * The current widget that has side area focus.
-     */
-    readonly currentWidget: Widget | null;
-
-    /**
-     * The collection of widgets held by the sidebar.
-     */
-    readonly widgets: Array<Widget> | null;
-  }
-
-  /**
-   * The options for adding a widget to a side area of the shell.
-   */
-  export interface ISideAreaOptions {
-    /**
-     * The rank order of the widget among its siblings.
-     */
-    rank?: number;
-  }
-
-  /**
-   * The options for adding a widget to a side area of the shell.
-   */
-  export interface IMainAreaOptions extends DocumentRegistry.IOpenOptions {}
-}
-
 namespace Private {
   /**
    * An object which holds a widget and its sort rank.
@@ -1083,7 +1097,7 @@ namespace Private {
     /**
      * Dehydrate the side bar data.
      */
-    dehydrate(): ApplicationShell.ISideArea {
+    dehydrate(): IApplicationShell.ISideArea {
       let collapsed = this._sideBar.currentTitle === null;
       let widgets = toArray(this._stackedPanel.widgets);
       let currentWidget = widgets[this._sideBar.currentIndex];
@@ -1093,7 +1107,7 @@ namespace Private {
     /**
      * Rehydrate the side bar.
      */
-    rehydrate(data: ApplicationShell.ISideArea): void {
+    rehydrate(data: IApplicationShell.ISideArea): void {
       if (data.currentWidget) {
         this.activate(data.currentWidget.id);
       } else if (data.collapsed) {

+ 21 - 18
packages/filebrowser-extension/src/index.ts

@@ -2,9 +2,9 @@
 // Distributed under the terms of the Modified BSD License.
 
 import {
-  ApplicationShell,
+  IApplicationShell,
   ILayoutRestorer,
-  JupyterLab,
+  JupyterClient,
   JupyterLabPlugin
 } from '@jupyterlab/application';
 
@@ -101,6 +101,7 @@ const browser: JupyterLabPlugin<void> = {
   activate: activateBrowser,
   id: '@jupyterlab/filebrowser-extension:browser',
   requires: [
+    IApplicationShell,
     IFileBrowserFactory,
     ILayoutRestorer,
     IDocumentManager,
@@ -145,7 +146,7 @@ export const fileUploadStatus: JupyterLabPlugin<void> = {
   autoStart: true,
   requires: [IStatusBar, IFileBrowserFactory],
   activate: (
-    app: JupyterLab,
+    app: JupyterClient,
     statusBar: IStatusBar,
     browser: IFileBrowserFactory
   ) => {
@@ -187,7 +188,7 @@ export default plugins;
  * Activate the file browser factory provider.
  */
 function activateFactory(
-  app: JupyterLab,
+  app: JupyterClient,
   docManager: IDocumentManager,
   state: IStateDB
 ): IFileBrowserFactory {
@@ -232,14 +233,15 @@ function activateFactory(
  * Activate the default file browser in the sidebar.
  */
 function activateBrowser(
-  app: JupyterLab,
+  app: JupyterClient,
+  shell: IApplicationShell,
   factory: IFileBrowserFactory,
   restorer: ILayoutRestorer,
   docManager: IDocumentManager,
   settingRegistry: ISettingRegistry
 ): void {
   const browser = factory.defaultBrowser;
-  const { commands, shell } = app;
+  const { commands } = app;
 
   // Let the application restorer track the primary file browser (that is
   // automatically created) for restoration of application state (e.g. setting
@@ -265,7 +267,7 @@ function activateBrowser(
   Promise.all([app.restored, browser.model.restored]).then(() => {
     function maybeCreate() {
       // Create a launcher if there are no open items.
-      if (app.shell.isEmpty('main')) {
+      if (shell.isEmpty('main')) {
         createLauncher(commands, browser);
       }
     }
@@ -290,7 +292,7 @@ function activateBrowser(
       });
 
     // Whether to automatically navigate to a document's current directory
-    shell.currentChanged.connect((shell, change) => {
+    shell.currentChanged.connect((_, change) => {
       if (navigateToCurrentDirectory) {
         const { newValue } = change;
         const context = docManager.contextForWidget(newValue);
@@ -306,7 +308,7 @@ function activateBrowser(
 }
 
 function activateShareFile(
-  app: JupyterLab,
+  app: JupyterClient,
   factory: IFileBrowserFactory
 ): void {
   const { commands } = app;
@@ -335,9 +337,10 @@ function activateShareFile(
  * Add the main file browser commands to the application's command registry.
  */
 function addCommands(
-  app: JupyterLab,
+  app: JupyterClient,
   tracker: InstanceTracker<FileBrowser>,
-  browser: FileBrowser
+  browser: FileBrowser,
+  shell?: IApplicationShell
 ): void {
   const registry = app.docRegistry;
 
@@ -428,8 +431,8 @@ function addCommands(
   commands.addCommand(CommandIDs.hideBrowser, {
     execute: () => {
       const widget = tracker.currentWidget;
-      if (widget && !widget.isHidden) {
-        app.shell.collapseLeft();
+      if (shell && widget && !widget.isHidden) {
+        shell.collapseLeft();
       }
     }
   });
@@ -615,17 +618,17 @@ function addCommands(
         return;
       }
       // Shortcut if we are using the main file browser
-      if (browser === browserForPath) {
-        app.shell.activateById(browser.id);
+      if (shell && browser === browserForPath) {
+        shell.activateById(browser.id);
         return;
       } else {
-        const areas: ApplicationShell.Area[] = ['left', 'right'];
+        const areas: IApplicationShell.Area[] = ['left', 'right'];
         for (let area of areas) {
-          const it = app.shell.widgets(area);
+          const it = shell.widgets(area);
           let widget = it.next();
           while (widget) {
             if (widget.contains(browserForPath)) {
-              app.shell.activateById(widget.id);
+              shell.activateById(widget.id);
               return;
             }
             widget = it.next();