浏览代码

Disambiguate paths dictionary and info dictionary. Move name/namespace/version into JupyterFrontEnd.

Afshin Darian 6 年之前
父节点
当前提交
750eda956f

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

@@ -568,7 +568,12 @@ const status: JupyterFrontEndPlugin<ILabStatus> = {
 };
 
 /**
- * The default JupyterLab application information provider.
+ * The default JupyterLab application-specific information provider.
+ *
+ * #### Notes
+ * This plugin should only be used by plugins that specifically need to access
+ * JupyterLab application information, e.g., listing extensions that have been
+ * loaded or deferred within JupyterLab.
  */
 const info: JupyterFrontEndPlugin<JupyterLab.IInfo> = {
   id: '@jupyterlab/application-extension:info',
@@ -582,15 +587,19 @@ const info: JupyterFrontEndPlugin<JupyterLab.IInfo> = {
   provides: JupyterLab.IInfo
 };
 
+/**
+ * The default JupyterLab paths dictionary provider.
+ */
 const paths: JupyterFrontEndPlugin<JupyterFrontEnd.IPaths> = {
   id: '@jupyterlab/apputils-extension:paths',
   activate: (app: JupyterFrontEnd): JupyterFrontEnd.IPaths => {
     if (!(app instanceof JupyterLab)) {
       throw new Error(`${paths.id} must be activated in JupyterLab.`);
     }
-    return app.info;
+    return app.paths;
   },
-  autoStart: true
+  autoStart: true,
+  provides: JupyterFrontEnd.IPaths
 };
 
 /**

+ 22 - 1
packages/application/src/frontend.ts

@@ -36,7 +36,7 @@ export type JupyterFrontEndPlugin<T> = IPlugin<JupyterFrontEnd, T>;
  * `T extends JupyterFrontEnd.Shell = JupyterFrontEnd.Shell` - the type of the
  * `shell` attribute of a `JupyterFrontEnd`.
  */
-export class JupyterFrontEnd<
+export abstract class JupyterFrontEnd<
   T extends JupyterFrontEnd.IShell = JupyterFrontEnd.IShell
 > extends Application<T> {
   /**
@@ -61,6 +61,21 @@ export class JupyterFrontEnd<
     this.serviceManager = options.serviceManager || new ServiceManager();
   }
 
+  /**
+   * The name of this Jupyter front-end application.
+   */
+  abstract readonly name: string;
+
+  /**
+   * A namespace/prefix plugins may use to denote their provenance.
+   */
+  abstract readonly namespace: string;
+
+  /**
+   * The version of this Jupyter front-end application.
+   */
+  abstract readonly version: string;
+
   /**
    * The command linker used by the application.
    */
@@ -213,8 +228,14 @@ export namespace JupyterFrontEnd {
     widgets(area?: string): IIterator<Widget>;
   }
 
+  /**
+   * The application paths dictionary token.
+   */
   export const IPaths = new Token<IPaths>('@jupyterlab/application:IPaths');
 
+  /**
+   * An interface for URL and directory paths used by a Jupyter front-end.
+   */
   export interface IPaths {
     /**
      * The urls used by the application.

+ 80 - 37
packages/application/src/lab.ts

@@ -97,6 +97,36 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell>
     // Populate application info.
     this._info = { ...JupyterLab.defaultInfo, ...info };
 
+    // Populate application paths override the defaults if necessary.
+    const defaultURLs = JupyterLab.defaultPaths.urls;
+    const defaultDirs = JupyterLab.defaultPaths.directories;
+    const optionURLs = (options.paths && options.paths.urls) || {};
+    const optionDirs = (options.paths && options.paths.directories) || {};
+
+    this._paths = {
+      urls: Object.keys(defaultURLs).reduce((acc, key) => {
+        if (key in optionURLs) {
+          const value = (optionURLs as any)[key];
+          (acc as any)[key] = value;
+        } else {
+          (acc as any)[key] = (defaultURLs as any)[key];
+        }
+        return acc;
+      }, {}),
+      directories: Object.keys(JupyterLab.defaultPaths.directories).reduce(
+        (acc, key) => {
+          if (key in optionDirs) {
+            const value = (optionDirs as any)[key];
+            (acc as any)[key] = value;
+          } else {
+            (acc as any)[key] = (defaultDirs as any)[key];
+          }
+          return acc;
+        },
+        {}
+      )
+    } as JupyterFrontEnd.IPaths;
+
     if (this._info.devMode) {
       this.shell.addClass('jp-mod-devMode');
     }
@@ -111,6 +141,16 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell>
     }
   }
 
+  /**
+   * The name of the JupyterLab application.
+   */
+  readonly name = PageConfig.getOption('appName') || 'JupyterLab';
+
+  /**
+   * A namespace/prefix plugins may use to denote their provenance.
+   */
+  readonly namespace = PageConfig.getOption('appNamespace') || this.name;
+
   /**
    * A list of all errors encountered when registering plugins.
    */
@@ -123,18 +163,9 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell>
   readonly restored: Promise<void>;
 
   /**
-   * Whether the application is dirty.
-   */
-  get isDirty(): boolean {
-    return this._dirtyCount > 0;
-  }
-
-  /**
-   * Whether the application is busy.
+   * The version of the JupyterLab application.
    */
-  get isBusy(): boolean {
-    return this._busyCount > 0;
-  }
+  readonly version = PageConfig.getOption('appVersion') || 'unknown';
 
   /**
    * Returns a signal for when application changes its busy status.
@@ -151,12 +182,33 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell>
   }
 
   /**
-   * The information about the application.
+   * The JupyterLab application information dictionary.
    */
   get info(): JupyterLab.IInfo {
     return this._info;
   }
 
+  /**
+   * Whether the application is busy.
+   */
+  get isBusy(): boolean {
+    return this._busyCount > 0;
+  }
+
+  /**
+   * Whether the application is dirty.
+   */
+  get isDirty(): boolean {
+    return this._dirtyCount > 0;
+  }
+
+  /**
+   * The JupyterLab application paths dictionary.
+   */
+  get paths(): JupyterFrontEnd.IPaths {
+    return this._paths;
+  }
+
   /**
    * Set the application state to dirty.
    *
@@ -231,11 +283,12 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell>
     });
   }
 
-  private _info: JupyterLab.IInfo;
-  private _dirtyCount = 0;
   private _busyCount = 0;
   private _busySignal: Signal<JupyterLab, boolean>;
+  private _dirtyCount = 0;
   private _dirtySignal: Signal<JupyterLab, boolean>;
+  private _info: JupyterLab.IInfo;
+  private _paths: JupyterFrontEnd.IPaths;
 }
 
 /**
@@ -247,7 +300,9 @@ export namespace JupyterLab {
    */
   export interface IOptions
     extends JupyterFrontEnd.IOptions<LabShell>,
-      Partial<IInfo> {}
+      Partial<IInfo> {
+    paths?: Partial<JupyterFrontEnd.IPaths>;
+  }
 
   /* tslint:disable */
   /**
@@ -259,22 +314,7 @@ export namespace JupyterLab {
   /**
    * The information about a JupyterLab application.
    */
-  export interface IInfo extends JupyterFrontEnd.IPaths {
-    /**
-     * The name of the JupyterLab application.
-     */
-    readonly name: string;
-
-    /**
-     * The version of the JupyterLab application.
-     */
-    readonly version: string;
-
-    /**
-     * The namespace/prefix plugins may use to denote their origin.
-     */
-    readonly namespace: string;
-
+  export interface IInfo {
     /**
      * Whether the application is in dev mode.
      */
@@ -302,16 +342,20 @@ export namespace JupyterLab {
   }
 
   /**
-   * The default application info.
+   * The default JupyterLab application info.
    */
   export const defaultInfo: IInfo = {
-    name: PageConfig.getOption('appName') || 'JupyterLab',
-    namespace: PageConfig.getOption('appNamespace'),
-    version: PageConfig.getOption('appVersion') || 'unknown',
     devMode: PageConfig.getOption('devMode').toLowerCase() === 'true',
     deferred: { patterns: [], matches: [] },
     disabled: { patterns: [], matches: [] },
     mimeExtensions: [],
+    filesCached: PageConfig.getOption('cacheFiles').toLowerCase() === 'true'
+  };
+
+  /**
+   * The default JupyterLab application paths.
+   */
+  export const defaultPaths: JupyterFrontEnd.IPaths = {
     urls: {
       base: PageConfig.getOption('baseUrl'),
       defaultWorkspace: PageConfig.getOption('defaultWorkspace'),
@@ -332,8 +376,7 @@ export namespace JupyterLab {
       userSettings: PageConfig.getOption('userSettingsDir'),
       serverRoot: PageConfig.getOption('serverRoot'),
       workspaces: PageConfig.getOption('workspacesDir')
-    },
-    filesCached: PageConfig.getOption('cacheFiles').toLowerCase() === 'true'
+    }
   };
 
   /**

+ 4 - 5
packages/apputils-extension/src/index.ts

@@ -7,7 +7,6 @@ import {
   ILayoutRestorer,
   IRouter,
   JupyterFrontEnd,
-  JupyterLab,
   JupyterFrontEndPlugin
 } from '@jupyterlab/application';
 
@@ -266,13 +265,13 @@ const state: JupyterFrontEndPlugin<IStateDB> = {
   id: '@jupyterlab/apputils-extension:state',
   autoStart: true,
   provides: IStateDB,
-  requires: [IRouter, IWindowResolver, JupyterLab.IInfo],
+  requires: [JupyterFrontEnd.IPaths, IRouter, IWindowResolver],
   optional: [ISplashScreen],
   activate: (
     app: JupyterFrontEnd,
+    paths: JupyterFrontEnd.IPaths,
     router: IRouter,
     resolver: IWindowResolver,
-    info: JupyterLab.IInfo,
     splash: ISplashScreen | null
   ) => {
     let debouncer: number;
@@ -283,7 +282,7 @@ const state: JupyterFrontEndPlugin<IStateDB> = {
     const workspace = resolver.name;
     const transform = new PromiseDelegate<StateDB.DataTransform>();
     const db = new StateDB({
-      namespace: info.namespace,
+      namespace: app.namespace,
       transform: transform.promise,
       windowName: workspace
     });
@@ -370,7 +369,7 @@ const state: JupyterFrontEndPlugin<IStateDB> = {
         }
 
         const { hash, path, search } = args;
-        const { urls } = info;
+        const { urls } = paths;
         const query = URLExt.queryStringToObject(search || '');
         const clone =
           typeof query['clone'] === 'string'

+ 3 - 5
packages/help-extension/src/index.tsx

@@ -4,7 +4,6 @@
 import {
   ILayoutRestorer,
   JupyterFrontEnd,
-  JupyterLab,
   JupyterFrontEndPlugin
 } from '@jupyterlab/application';
 
@@ -91,7 +90,7 @@ RESOURCES.sort((a: any, b: any) => {
 const plugin: JupyterFrontEndPlugin<void> = {
   activate,
   id: '@jupyterlab/help-extension:plugin',
-  requires: [JupyterLab.IInfo, IMainMenu],
+  requires: [IMainMenu],
   optional: [ICommandPalette, ILayoutRestorer],
   autoStart: true
 };
@@ -110,7 +109,6 @@ export default plugin;
  */
 function activate(
   app: JupyterFrontEnd,
-  info: JupyterLab.IInfo,
   mainMenu: IMainMenu,
   palette: ICommandPalette | null,
   restorer: ILayoutRestorer | null
@@ -278,12 +276,12 @@ function activate(
   });
 
   commands.addCommand(CommandIDs.about, {
-    label: `About ${info.name}`,
+    label: `About ${app.name}`,
     execute: () => {
       // Create the header of the about dialog
       let headerLogo = <div className="jp-About-header-logo" />;
       let headerWordmark = <div className="jp-About-header-wordmark" />;
-      let versionNumber = `Version ${info.version}`;
+      let versionNumber = `Version ${app.version}`;
       let versionInfo = (
         <span className="jp-About-version-info">
           <span className="jp-About-version">{versionNumber}</span>