@jupyterlab/apputils#WidgetTracker TypeScript Examples

The following examples show how to use @jupyterlab/apputils#WidgetTracker. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.ts    From jupyterlab-ros with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
bag: JupyterFrontEndPlugin<void> = {
  id: 'jupyterlab-ros/bag',
  autoStart: true,
  requires: [IFileBrowserFactory, ILayoutRestorer],
  optional: [],
  activate: (app: JupyterFrontEnd, factory: IFileBrowserFactory, restorer: ILayoutRestorer) => {
    
    app.docRegistry.addFileType({
      name: 'bag',
      icon: runIcon,
      displayName: 'Bag File',
      extensions: ['.bag'],
      contentType: 'file',
      fileFormat: 'base64',
      iconClass: runIcon.name,
      iconLabel: runIcon.name,
      mimeTypes: ['application/octet-stream']
    });

    const tracker = new WidgetTracker<BagWidget>({ namespace: 'rosbag' });

    restorer.restore(tracker, {
      command: 'jupyterlab-ros/bag:launch',
      args: widget => ({ path: widget.content.model.session.path }),
      name: widget => widget.content.model.session.name
    });

    app.commands.addCommand('jupyterlab-ros/bag:launch', {
      label: 'Open Bag',
      caption: 'Open ROS bag file.',
      icon: runIcon,
      execute: (args: any) => {
        console.log("launch");

        const path = ( args.path || factory.tracker.currentWidget.selectedItems().next().path );

        app.serviceManager.sessions.findByPath(path)
        .then( model => {

          if (model) {
            const session = app.serviceManager.sessions.connectTo({ model });
            const widget = new BagWidget(new BagPanel(new BagModel(session)));
  
            app.shell.add(widget, 'main');
            tracker.add(widget);
          
          } else {
            const session = new SessionContext({
              sessionManager: app.serviceManager.sessions,
              specsManager: app.serviceManager.kernelspecs,
              name: path,
              path: path
            });
  
            session.initialize()
            .then( async value => {
              if (value) {
                await sessionContextDialogs.selectKernel(session);
                const widget = new BagWidget(new BagPanel(new BagModel(session.session)));
                
                app.shell.add(widget, 'main');
                tracker.add(widget);
              }
            }).catch( err => console.error(err) );
          }
          
        }).catch( err => console.log(err) );
      }
    });

    app.contextMenu.addItem({
      command: 'jupyterlab-ros/bag:launch',
      selector: '.jp-DirListing-item[data-file-type="bag"]',
      rank: 0
    });
  }
}
Example #2
Source File: index.ts    From jupyterlab-ros with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
logConsole: JupyterFrontEndPlugin<void> = {
  id: 'jupyterlab-ros/logConsole',
  autoStart: true,
  requires: [ICommandPalette, ILayoutRestorer],
  optional: [],
  activate: (app: JupyterFrontEnd, palette: ICommandPalette, restorer: ILayoutRestorer) => {
    const { commands } = app;

    let widget: LogConsoleWidget = null;

    const tracker = new WidgetTracker<LogConsoleWidget>({
      namespace: 'roslogconsole'
    });

    restorer.restore(tracker, {
      command: 'jupyterlab-ros/logConsole:open',
      name: () => 'roslogconsole'
    });

    // Creating some buttons for the widget toolbar
    commands.addCommand('jupyterlab-ros/logConsole:checkpoint', {
      execute: () => widget?.checkpoint(),
      icon: addIcon,
      label: 'Add Checkpoint'
    });

    commands.addCommand('jupyterlab-ros/logConsole:clear', {
      execute: () =>  widget?.clear(),
      icon: clearIcon,
      label: 'Clear Log'
    });

    commands.addCommand('jupyterlab-ros/logConsole:open', {
      label: 'Ros log',
      caption: 'Log console for ROS.',
      isVisible: () => true,
      isEnabled: () => true,
      isToggled: () => widget !== null,
      execute: () => {
        if (widget) {
          widget.dispose();
        } else {
          widget = new LogConsoleWidget(app);

          widget.disposed.connect(() => {
            widget = null;
            commands.notifyCommandChanged();
          });

          app.shell.add(widget, 'main', { mode: 'split-bottom' });
          tracker.add(widget);

          widget.update();
          commands.notifyCommandChanged();
        }
      }
    });

    palette.addItem({ command: 'jupyterlab-ros/logConsole:open', category: 'ROS' });
  }
}
Example #3
Source File: index.ts    From jupyterlab-ros with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
settings: JupyterFrontEndPlugin<void> = {
  id: 'jupyterlab-ros/settings',
  autoStart: true,
  requires: [ICommandPalette, ILayoutRestorer, ISettingRegistry],
  optional: [],
  activate: (app: JupyterFrontEnd, palette: ICommandPalette, restorer: ILayoutRestorer, settings: ISettingRegistry) => {
    const { commands } = app;
    const server = ServerConnection.makeSettings();
    const url = URLExt.join(server.baseUrl, 'ros/setting');

    let content: SettingsWidget = null;
    let widget: MainAreaWidget<SettingsWidget> = null;

    const tracker = new WidgetTracker<MainAreaWidget<SettingsWidget>>({
      namespace: 'rossettings'
    });

    restorer.restore(tracker, {
      command: 'jupyterlab-ros/settings:open',
      name: () => 'rossettings'
    });

    const command = 'jupyterlab-ros/settings:open';
    commands.addCommand(command, {
      label: 'Settings',
      caption: 'Specify your JupyterLab-ROS env.',
      isVisible: () => true,
      isEnabled: () => true,
      isToggled: () => widget !== null,
      execute: () => {
        if (widget) {
          widget.dispose();
        } else {
          content = new SettingsWidget(settings, '@robostack/jupyterlab-ros:settings');
          widget = new MainAreaWidget<SettingsWidget>({ content });
          widget.title.label = 'ROS Settings';

          widget.disposed.connect(() => {
            content.dispose();
            content = null;
            widget = null;
            commands.notifyCommandChanged();
          });

          app.shell.add(widget, 'main');
          tracker.add(widget);

          widget.update();
          commands.notifyCommandChanged();
        }
      }
    });

    palette.addItem({ command, category: 'ROS' });

    const loadSetting = (setting: ISettingRegistry.ISettings): void => {
      const env = setting.get('env').composite as string;
      const master = setting.get('master').composite as string;

      if ( env != "" || master != "" ) {
        const msg = { method: 'PUT', body: JSON.stringify({ env, master }) };
  
        ServerConnection.makeRequest(url, msg, server)
        .then( resp => {})
        .catch( err => console.log(err) );
      }
    }

    settings.load('@robostack/jupyterlab-ros:settings')
      .then(rosSetting => {
        rosSetting.changed.connect(loadSetting);
        loadSetting(rosSetting);
      }).catch(err => console.log(err));
  }
}
Example #4
Source File: index.ts    From jupyterlab-ros with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
zethus: JupyterFrontEndPlugin<void> = {
  id: "jupyterlab-ros/zethus",
  autoStart: true,
  requires: [ICommandPalette, ILayoutRestorer],
  activate: (app: JupyterFrontEnd, palette: ICommandPalette, restorer: ILayoutRestorer) => {
    const { commands } = app;
    let widget = null;

    const tracker = new WidgetTracker<ZethusWidget>({
      namespace: 'zethus'
    });

    restorer.restore(tracker, {
      command: 'jupyterlab-ros/zethus:open',
      name: () => 'zethus'
    });

    let command = 'jupyterlab-ros/zethus:open';
    commands.addCommand(command, {
      label: 'Open Zethus',
      caption: 'Open a new Zethus view.',
      isVisible: () => true,
      isEnabled: () => true,
      isToggled: () => widget !== null,
      execute: () => {
        if (widget) {
          widget.dispose();
        } else {
          widget = new ZethusWidget();

          widget.disposed.connect(() => {
            widget = null;
            commands.notifyCommandChanged();
          });

          app.shell.add(widget, 'main');
          tracker.add(widget);

          widget.update();
          commands.notifyCommandChanged();
        }
      }
    });

    palette.addItem({ command, category: 'ROS' });
  }
}
Example #5
Source File: dashboard.tsx    From jupyterlab-interactive-dashboard-editor with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
private _outputTracker: WidgetTracker<DashboardWidget>;
Example #6
Source File: dashboard.tsx    From jupyterlab-interactive-dashboard-editor with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
export class DashboardTracker extends WidgetTracker<Dashboard> {}
Example #7
Source File: layout.ts    From jupyterlab-interactive-dashboard-editor with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
// Output tracker to add new widgets to.
  private _outputTracker: WidgetTracker<DashboardWidget>;
Example #8
Source File: index.ts    From jupyterlab-unfold with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
extension: JupyterFrontEndPlugin<IFileBrowserFactory> = {
  id: EXTENSION_ID,
  provides: IFileBrowserFactory,
  requires: [IDocumentManager, ITranslator, ISettingRegistry],
  optional: [IStateDB],
  activate: async (
    app: JupyterFrontEnd,
    docManager: IDocumentManager,
    translator: ITranslator,
    settings: ISettingRegistry,
    state: IStateDB | null
  ): Promise<IFileBrowserFactory> => {
    const setting = await settings.load(SETTINGS_ID);

    const tracker = new WidgetTracker<FileTreeBrowser>({ namespace });
    const createFileBrowser = (
      id: string,
      options: IFileBrowserFactory.IOptions = {}
    ) => {
      const model = new FilterFileTreeBrowserModel({
        translator: translator,
        auto: options.auto ?? true,
        manager: docManager,
        driveName: options.driveName || '',
        refreshInterval: options.refreshInterval,
        state:
          options.state === null
            ? undefined
            : options.state || state || undefined
      });
      const widget = new FileTreeBrowser({
        id,
        model,
        restore: true,
        translator,
        app
      });

      widget.listing.singleClickToUnfold = setting.get('singleClickToUnfold')
        .composite as boolean;

      setting.changed.connect(() => {
        widget.listing.singleClickToUnfold = setting.get('singleClickToUnfold')
          .composite as boolean;
      });

      // Track the newly created file browser.
      void tracker.add(widget);

      return widget;
    };

    // Manually restore and load the default file browser.
    const defaultBrowser = createFileBrowser(EXTENSION_ID, {
      auto: false,
      restore: false
    });

    // TODO Remove this! Why is this needed?
    // The @jupyterlab/filebrowser-extension:launcher-toolbar-button extension should take care of this
    const { commands } = app;
    const trans = translator.load('jupyterlab');

    // Add a launcher toolbar item.
    const launcher = new ToolbarButton({
      icon: addIcon,
      onClick: () => {
        if (commands.hasCommand('launcher:create')) {
          return commands.execute('launcher:create');
        }
      },
      tooltip: trans.__('New Launcher'),
      actualOnClick: true
    });
    defaultBrowser.toolbar.insertItem(0, 'launch', launcher);

    return { createFileBrowser, defaultBrowser, tracker };
  }
}
Example #9
Source File: index.ts    From jupyterlab-interactive-dashboard-editor with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
/**
 * Add commands to the main JupyterLab command registry.
 *
 * @param app - the JupyterLab instance.
 *
 * @param dashboardTracker - a tracker for dashboards.
 *
 * @param outputTracker - a tracker for dashboard outputs.
 *
 * @param clipboard - a set used to keep track of widgets for copy/pasting.
 *
 * @param docManager - a document manager used to create/rename files.
 *
 * @param notebookTracker - a tracker for notebooks.
 */
function addCommands(
  app: JupyterFrontEnd,
  dashboardTracker: WidgetTracker<Dashboard>,
  outputTracker: WidgetTracker<DashboardWidget>,
  clipboard: Set<Widgetstore.WidgetInfo>,
  docManager: IDocumentManager,
  notebookTracker: INotebookTracker
): void {
  const { commands } = app;

  /**
   * Whether there is an active dashboard.
   */
  function hasDashboard(): boolean {
    return dashboardTracker.currentWidget !== null;
  }

  /**
   * Whether there is a dashboard output.
   */
  function hasOutput(): boolean {
    return outputTracker.currentWidget !== null;
  }

  function inToolbar(args: ReadonlyJSONObject): boolean {
    return args.toolbar as boolean;
  }

  /**
   * Deletes a selected DashboardWidget.
   */
  commands.addCommand(CommandIDs.deleteOutput, {
    label: 'Delete Output',
    execute: args => {
      const widget = outputTracker.currentWidget;
      const dashboard = dashboardTracker.currentWidget;
      dashboard.deleteWidget(widget);
    }
  });

  /**
   * Undo the last change to a dashboard.
   */
  commands.addCommand(CommandIDs.undo, {
    label: args => (inToolbar(args) ? '' : 'Undo'),
    icon: undoIcon,
    execute: args => {
      dashboardTracker.currentWidget.undo();
    },
    isEnabled: args =>
      inToolbar(args) ||
      (dashboardTracker.currentWidget &&
        dashboardTracker.currentWidget.model.widgetstore.hasUndo())
  });

  /**
   * Redo the last undo to a dashboard.
   */
  commands.addCommand(CommandIDs.redo, {
    label: args => (inToolbar(args) ? '' : 'Redo'),
    icon: redoIcon,
    execute: args => {
      dashboardTracker.currentWidget.redo();
    },
    isEnabled: args =>
      inToolbar(args) ||
      (dashboardTracker.currentWidget &&
        dashboardTracker.currentWidget.model.widgetstore.hasRedo())
  });

  commands.addCommand(CommandIDs.toggleFitContent, {
    label: args => 'Fit To Content',
    execute: args => {
      const widget = outputTracker.currentWidget;
      widget.fitToContent = !widget.fitToContent;
      if (widget.fitToContent) {
        widget.fitContent();
      }
    },
    isVisible: args => outputTracker.currentWidget.mode === 'free-edit',
    isToggled: args => outputTracker.currentWidget.fitToContent
  });

  commands.addCommand(CommandIDs.toggleMode, {
    icon: args => {
      const mode = dashboardTracker.currentWidget?.model.mode || 'present';
      if (mode === 'present') {
        return DashboardIcons.edit;
      } else {
        return DashboardIcons.view;
      }
    },
    label: args => {
      if (inToolbar(args)) {
        return '';
      }
      const mode = dashboardTracker.currentWidget?.model.mode || 'present';
      if (mode === 'present') {
        return 'Switch To Edit Mode';
      } else {
        return 'Switch To Presentation Mode';
      }
    },
    execute: args => {
      const dashboard = dashboardTracker.currentWidget;
      if (dashboard.model.mode === 'present') {
        dashboard.model.mode = 'free-edit';
      } else {
        dashboard.model.mode = 'present';
      }
    }
  });

  commands.addCommand(CommandIDs.runOutput, {
    label: args => (inToolbar(args) ? '' : 'Run Output'),
    icon: runIcon,
    execute: args => {
      const widget = outputTracker.currentWidget;
      const sessionContext = widget.notebook.sessionContext;
      CodeCell.execute(widget.cell as CodeCell, sessionContext);
    }
  });

  commands.addCommand(CommandIDs.setDimensions, {
    label: 'Set Dashboard Dimensions',
    execute: async args => {
      const model = dashboardTracker.currentWidget.model;
      const width = model.width ? model.width : Dashboard.DEFAULT_WIDTH;
      const height = model.height ? model.height : Dashboard.DEFAULT_HEIGHT;
      await showDialog({
        title: 'Enter Dimensions',
        body: new Private.ResizeHandler(width, height),
        focusNodeSelector: 'input',
        buttons: [Dialog.cancelButton(), Dialog.okButton()]
      }).then(result => {
        const value = result.value;
        let newWidth = value[0];
        let newHeight = value[1];
        if (value === null && model.width && model.height) {
          return;
        }
        if (!newWidth) {
          if (!model.width) {
            newWidth = Dashboard.DEFAULT_WIDTH;
          } else {
            newWidth = model.width;
          }
        }
        if (!newHeight) {
          if (!model.height) {
            newHeight = Dashboard.DEFAULT_HEIGHT;
          } else {
            newHeight = model.height;
          }
        }
        model.width = newWidth;
        model.height = newHeight;
      });
    },
    isEnabled: hasDashboard
  });

  commands.addCommand(CommandIDs.setTileSize, {
    label: 'Set Grid Dimensions',
    execute: async args => {
      const newSize = await InputDialog.getNumber({
        title: 'Enter Grid Size'
      });
      if (newSize.value) {
        const layout = dashboardTracker.currentWidget.layout as DashboardLayout;
        layout.setTileSize(newSize.value);
      }
    },
    isEnabled: hasDashboard
  });

  commands.addCommand(CommandIDs.copy, {
    label: args => (inToolbar(args) ? '' : 'Copy'),
    icon: copyIcon,
    execute: args => {
      const info = outputTracker.currentWidget.info;
      clipboard.clear();
      clipboard.add(info);
    },
    isEnabled: args => inToolbar(args) || hasOutput()
  });

  commands.addCommand(CommandIDs.cut, {
    label: args => (inToolbar(args) ? '' : 'Cut'),
    icon: cutIcon,
    execute: args => {
      const widget = outputTracker.currentWidget;
      const info = widget.info;
      const dashboard = dashboardTracker.currentWidget;
      clipboard.clear();
      clipboard.add(info);
      dashboard.deleteWidget(widget);
    },
    isEnabled: args => inToolbar(args) || hasOutput()
  });

  commands.addCommand(CommandIDs.paste, {
    label: args => (inToolbar(args) ? '' : 'Paste'),
    icon: pasteIcon,
    execute: args => {
      const id = args.dashboardId;
      let dashboard: Dashboard;
      if (id) {
        dashboard = dashboardTracker.find(widget => widget.id === id);
      } else {
        dashboard = dashboardTracker.currentWidget;
      }
      const widgetstore = dashboard.model.widgetstore;
      clipboard.forEach(info => {
        const widgetId = DashboardWidget.createDashboardWidgetId();
        const pos = info.pos;
        pos.left = Math.max(pos.left - 10, 0);
        pos.top = Math.max(pos.top - 10, 0);

        const newWidget = widgetstore.createWidget({ ...info, widgetId, pos });
        dashboard.addWidget(newWidget, pos);
      });
    },
    isEnabled: args => inToolbar(args) || (hasOutput() && clipboard.size !== 0)
  });

  commands.addCommand(CommandIDs.saveToMetadata, {
    label: 'Save Dashboard To Notebook Metadata',
    execute: args => {
      const dashboard = dashboardTracker.currentWidget;
      dashboard.saveToNotebookMetadata();
    }
  });

  commands.addCommand(CommandIDs.createNew, {
    label: 'Dashboard',
    icon: DashboardIcons.tealDashboard,
    execute: async args => {
      // A new file is created and opened separately to override the default
      // opening behavior when there's a notebook and open the dashboard in a
      // split pane instead of a tab.

      const notebook = notebookTracker.currentWidget;
      const newModel = await docManager.newUntitled({
        ext: 'dash',
        path: '/',
        type: 'file'
      });
      const path = newModel.path;
      if (notebook) {
        docManager.openOrReveal(`/${path}`, undefined, undefined, {
          mode: 'split-left',
          ref: notebook.id
        });
      } else {
        docManager.openOrReveal(`/${path}`);
      }
    }
  });

  // TODO: Make this optionally saveAs (based on filename?)
  commands.addCommand(CommandIDs.save, {
    label: args => (inToolbar(args) ? '' : 'Save'),
    icon: saveIcon,
    execute: args => {
      const dashboard = dashboardTracker.currentWidget;
      dashboard.context.save();
    },
    isEnabled: args => inToolbar(args) || hasDashboard()
  });

  commands.addCommand(CommandIDs.openFromMetadata, {
    label: 'Open Metadata Dashboard',
    execute: args => {
      const notebook = notebookTracker.currentWidget;
      const notebookMetadata = getMetadata(notebook);
      const notebookId = notebookMetadata.id;
      const cells = notebook.content.widgets;

      const widgetstore = new Widgetstore({ id: 0, notebookTracker });

      widgetstore.startBatch();

      for (const cell of cells) {
        const metadata = getMetadata(cell);
        if (metadata !== undefined && !metadata.hidden) {
          const widgetInfo: WidgetInfo = {
            widgetId: DashboardWidget.createDashboardWidgetId(),
            notebookId,
            cellId: metadata.id,
            pos: metadata.pos
          };
          widgetstore.addWidget(widgetInfo);
        }
      }

      widgetstore.endBatch();

      const model = new DashboardModel({
        widgetstore,
        notebookTracker
      });

      const dashboard = new Dashboard({
        outputTracker,
        model
      });

      dashboard.updateLayoutFromWidgetstore();
      dashboard.model.mode = 'present';

      notebook.context.addSibling(dashboard, { mode: 'split-left' });
    },
    isEnabled: args => {
      const notebook = notebookTracker.currentWidget;
      const metadata = getMetadata(notebook);
      if (metadata !== undefined && metadata.hasDashboard !== undefined) {
        return metadata.hasDashboard;
      }
      return false;
    }
  });

  commands.addCommand(CommandIDs.toggleWidgetMode, {
    label: 'Snap to Grid',
    isToggled: args => {
      const widget = outputTracker.currentWidget;
      return widget.mode === 'grid-edit';
    },
    execute: args => {
      const widget = outputTracker.currentWidget;
      if (widget.mode === 'grid-edit') {
        widget.mode = 'free-edit';
      } else if (widget.mode === 'free-edit') {
        widget.mode = 'grid-edit';
      }
    }
  });

  commands.addCommand(CommandIDs.toggleInfiniteScroll, {
    label: 'Infinite Scroll',
    isToggled: args =>
      dashboardTracker.currentWidget?.model.scrollMode === 'infinite',
    execute: args => {
      const dashboard = dashboardTracker.currentWidget;
      if (dashboard.model.scrollMode === 'infinite') {
        dashboard.model.scrollMode = 'constrained';
      } else {
        dashboard.model.scrollMode = 'infinite';
      }
    }
  });

  commands.addCommand(CommandIDs.trimDashboard, {
    label: 'Trim Dashboard',
    execute: args => {
      const dashboard = dashboardTracker.currentWidget;
      (dashboard.layout as DashboardLayout).trimDashboard();
    }
  });
}
Example #10
Source File: index.ts    From jupyterlab-interactive-dashboard-editor with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
extension: JupyterFrontEndPlugin<IDashboardTracker> = {
  id: 'jupyterlab-interactive-dashboard-editor',
  autoStart: true,
  requires: [INotebookTracker, IMainMenu, IDocumentManager, ILauncher],
  provides: IDashboardTracker,
  activate: (
    app: JupyterFrontEnd,
    notebookTracker: INotebookTracker,
    mainMenu: IMainMenu,
    docManager: IDocumentManager,
    launcher: ILauncher
  ): IDashboardTracker => {
    // Tracker for Dashboard
    const dashboardTracker = new DashboardTracker({ namespace: 'dashboards' });

    //Tracker for DashboardWidgets
    const outputTracker = new WidgetTracker<DashboardWidget>({
      namespace: 'dashboard-outputs'
    });

    // Clipboard for copy/pasting outputs.
    const clipboard = new Set<Widgetstore.WidgetInfo>();

    // Define dashboard file type.
    const dashboardFiletype: Partial<DocumentRegistry.IFileType> = {
      name: 'dashboard',
      displayName: 'Dashboard',
      contentType: 'file',
      extensions: ['.dashboard', '.dash'],
      fileFormat: 'text',
      icon: DashboardIcons.tealDashboard,
      iconLabel: 'Dashboard',
      mimeTypes: ['application/json']
    };
    // Add dashboard file type to the doc registry.
    app.docRegistry.addFileType(dashboardFiletype);

    addCommands(
      app,
      dashboardTracker,
      outputTracker,
      clipboard,
      docManager,
      notebookTracker
    );

    // Create a new model factory.
    const modelFactory = new DashboardModelFactory({ notebookTracker });

    // Create a new widget factory.
    const widgetFactory = new DashboardDocumentFactory({
      name: 'dashboard',
      modelName: 'dashboard',
      fileTypes: ['dashboard'],
      defaultFor: ['dashboard'],
      commandRegistry: app.commands,
      outputTracker
    });

    app.docRegistry.addModelFactory(modelFactory);
    app.docRegistry.addWidgetFactory(widgetFactory);

    // Add newly created dashboards to the tracker, set their icon and label,
    // and set the default width, height, and scrollMode.
    widgetFactory.widgetCreated.connect((_sender, widget) => {
      void dashboardTracker.add(widget.content);

      widget.title.icon = dashboardFiletype.icon;
      widget.title.iconClass = dashboardFiletype.iconClass || '';
      widget.title.iconLabel = dashboardFiletype.iconLabel || '';

      const model = widget.content.model;
      // TODO: Make scrollMode changable in JL. Default 'infinite' for now.
      model.scrollMode = 'infinite';
      model.width = Dashboard.DEFAULT_WIDTH;
      model.height = Dashboard.DEFAULT_HEIGHT;
    });

    // Add commands to context menus.
    app.contextMenu.addItem({
      command: CommandIDs.save,
      selector: '.pr-JupyterDashboard',
      rank: 3
    });

    app.contextMenu.addItem({
      command: CommandIDs.undo,
      selector: '.pr-JupyterDashboard',
      rank: 1
    });

    app.contextMenu.addItem({
      command: CommandIDs.redo,
      selector: '.pr-JupyterDashboard',
      rank: 2
    });

    app.contextMenu.addItem({
      command: CommandIDs.cut,
      selector: '.pr-JupyterDashboard',
      rank: 3
    });

    app.contextMenu.addItem({
      command: CommandIDs.copy,
      selector: '.pr-JupyterDashboard',
      rank: 4
    });

    app.contextMenu.addItem({
      command: CommandIDs.paste,
      selector: '.pr-JupyterDashboard',
      rank: 5
    });

    const experimentalMenu = new Menu({ commands: app.commands });
    experimentalMenu.title.label = 'Experimental';

    experimentalMenu.addItem({
      command: CommandIDs.saveToMetadata
    });

    experimentalMenu.addItem({
      command: CommandIDs.toggleInfiniteScroll
    });

    experimentalMenu.addItem({
      command: CommandIDs.trimDashboard
    });

    app.contextMenu.addItem({
      type: 'submenu',
      submenu: experimentalMenu,
      selector: '.pr-JupyterDashboard',
      rank: 6
    });

    app.contextMenu.addItem({
      command: CommandIDs.deleteOutput,
      selector: '.pr-EditableWidget',
      rank: 0
    });

    app.contextMenu.addItem({
      command: CommandIDs.toggleFitContent,
      selector: '.pr-EditableWidget',
      rank: 1
    });

    app.contextMenu.addItem({
      command: CommandIDs.toggleWidgetMode,
      selector: '.pr-EditableWidget',
      rank: 2
    });

    app.contextMenu.addItem({
      type: 'separator',
      selector: '.pr-EditableWidget',
      rank: 3
    });

    app.contextMenu.addItem({
      command: CommandIDs.openFromMetadata,
      selector: '.jp-Notebook',
      rank: 16
    });

    // Add commands to key bindings
    app.commands.addKeyBinding({
      command: CommandIDs.deleteOutput,
      args: {},
      keys: ['Backspace'],
      selector: '.pr-EditableWidget'
    });

    app.commands.addKeyBinding({
      command: CommandIDs.undo,
      args: {},
      keys: ['Z'],
      selector: '.pr-JupyterDashboard'
    });

    app.commands.addKeyBinding({
      command: CommandIDs.redo,
      args: {},
      keys: ['Shift Z'],
      selector: '.pr-JupyterDashboard'
    });

    app.commands.addKeyBinding({
      command: CommandIDs.cut,
      args: {},
      keys: ['Accel X'],
      selector: '.pr-JupyterDashboard'
    });

    app.commands.addKeyBinding({
      command: CommandIDs.copy,
      args: {},
      keys: ['Accel C'],
      selector: '.pr-JupyterDashboard'
    });

    app.commands.addKeyBinding({
      command: CommandIDs.paste,
      args: {},
      keys: ['Accel V'],
      selector: '.pr-JupyterDashboard'
    });

    app.commands.addKeyBinding({
      command: CommandIDs.toggleFitContent,
      args: {},
      keys: ['K'],
      selector: '.pr-EditableWidget'
    });

    // Add commands to edit menu.
    mainMenu.fileMenu.addGroup([
      {
        command: CommandIDs.setDimensions
      },
      {
        command: CommandIDs.setTileSize
      }
    ]);

    mainMenu.fileMenu.newMenu.addGroup([
      {
        command: CommandIDs.createNew
      }
    ]);

    launcher.add({
      command: CommandIDs.createNew,
      category: 'Other',
      rank: 1
    });

    return dashboardTracker;
  }
}
Example #11
Source File: index.ts    From jupyterlab-tabular-data-editor with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
function activateCsv(
  app: JupyterFrontEnd,
  browserFactory: IFileBrowserFactory,
  launcher: ILauncher | null,
  restorer: ILayoutRestorer | null,
  themeManager: IThemeManager | null,
  mainMenu: IMainMenu | null,
  searchregistry: ISearchProviderRegistry | null
): void {
  const factory = new EditableCSVViewerFactory(
    {
      name: FACTORY_CSV,
      fileTypes: ['csv'],
      defaultFor: ['csv'],
      readOnly: true
    },
    app.commands
  );
  const tracker = new WidgetTracker<IDocumentWidget<DSVEditor>>({
    namespace: 'editablecsvviewer'
  });

  // The current styles for the data grids.
  let style: DataGrid.Style = Private.LIGHT_STYLE;
  const extraStyle: PaintedGrid.ExtraStyle = LIGHT_EXTRA_STYLE;
  let rendererConfig: TextRenderConfig = Private.LIGHT_TEXT_CONFIG;

  if (restorer) {
    // Handle state restoration.
    void restorer.restore(tracker, {
      command: 'docmanager:open',
      args: widget => ({ path: widget.context.path, factory: FACTORY_CSV }),
      name: widget => widget.context.path
    });
  }

  app.docRegistry.addWidgetFactory(factory);
  const ft = app.docRegistry.getFileType('csv');
  factory.widgetCreated.connect((sender, widget) => {
    // Track the widget.
    void tracker.add(widget);
    // Notify the widget tracker if restore data needs to update.
    widget.context.pathChanged.connect(() => {
      void tracker.save(widget);
    });

    if (ft) {
      widget.title.icon = ft.icon;
      widget.title.iconClass = ft.iconClass || '';
      widget.title.iconLabel = ft.iconLabel || '';
    }
    // Set the theme for the new widget.
    widget.content.style = style;

    widget.content.rendererConfig = rendererConfig;

    widget.content.extraStyle = extraStyle;
  });

  // Keep the themes up-to-date.
  const updateThemes = (): void => {
    const isLight =
      themeManager && themeManager.theme
        ? themeManager.isLight(themeManager.theme)
        : true;
    style = isLight ? Private.LIGHT_STYLE : Private.DARK_STYLE;
    const extraStyle = isLight ? LIGHT_EXTRA_STYLE : DARK_EXTRA_STYLE;
    rendererConfig = isLight
      ? Private.LIGHT_TEXT_CONFIG
      : Private.DARK_TEXT_CONFIG;
    tracker.forEach(grid => {
      grid.content.style = style;
      grid.content.extraStyle = extraStyle;
      grid.content.rendererConfig = rendererConfig;
    });
  };
  if (themeManager) {
    themeManager.themeChanged.connect(updateThemes);
  }

  //TODO: Error with main menu
  // if (mainMenu) {
  //   addMenuEntries(mainMenu, tracker);
  // }

  if (searchregistry) {
    searchregistry.register('csv', CSVSearchProvider);
  }

  addCommands(app, tracker, browserFactory);

  // Add a new CSV launcher
  if (launcher) {
    launcher.add({ command: CommandIDs.createNewCSV });
  }
}
Example #12
Source File: index.ts    From jupyterlab-tabular-data-editor with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
/*
Creates commands, adds them to the context menu, and adds keybindings for common functionality
*/
function addCommands(
  app: JupyterFrontEnd,
  tracker: WidgetTracker<IDocumentWidget<DSVEditor>>,
  browserFactory: IFileBrowserFactory
): void {
  const { commands } = app;
  const GLOBAL_SELECTOR = '.jp-CSVViewer-grid';
  const BODY_SELECTOR = '.jp-background';
  const COLUMN_HEADER_SELECTOR = '.jp-column-header';
  const ROW_HEADER_SELECTOR = '.jp-row-header';

  // creates a new csv file and opens it
  commands.addCommand(CommandIDs.createNewCSV, {
    label: args => (args['isPalette'] ? 'New CSV File' : 'CSV File'),
    caption: 'Create a new CSV file',
    icon: args => (args['isPalette'] ? null : spreadsheetIcon),
    execute: async args => {
      // Get the directory in which the CSV file must be created;
      // otherwise take the current filebrowser directory
      const cwd = args['cwd'] || browserFactory.defaultBrowser.model.path;

      // Create a new untitled csv file
      const model: Contents.IModel = await commands.execute(
        'docmanager:new-untitled',
        {
          path: cwd,
          type: 'file',
          ext: 'csv'
        }
      );

      // Open the newly created file with the Tabular Data Editor
      return commands.execute('docmanager:open', {
        path: model.path,
        factory: FACTORY_CSV
      });
    }
  });

  commands.addCommand(CommandIDs.insertRowsAbove, {
    label: () => {
      const numRows = tracker.currentWidget.content.rowsSelected;
      return numRows === 1
        ? 'Insert Row Above'
        : `Insert ${numRows} Rows Above`;
    },
    execute: () => {
      // emit a signal to the EditableDSVModel
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('insert-rows-above');
    }
  });

  commands.addCommand(CommandIDs.insertRowsBelow, {
    label: () => {
      const numRows = tracker.currentWidget.content.rowsSelected;
      return numRows === 1
        ? 'Insert Row Below'
        : `Insert ${numRows} Rows Below`;
    },
    execute: () => {
      // emit a signal to the EditableDSVModel
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('insert-rows-below');
    }
  });

  commands.addCommand(CommandIDs.removeRows, {
    label: () => {
      const numRows = tracker.currentWidget.content.rowsSelected;
      return numRows === 1 ? 'Remove Row' : `Remove ${numRows} Rows`;
    },
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('remove-rows');
    }
  });

  commands.addCommand(CommandIDs.insertColumnsLeft, {
    label: () => {
      const numCols = tracker.currentWidget.content.columnsSelected;
      return numCols === 1
        ? 'Insert Column Left'
        : `Insert ${numCols} Columns Left`;
    },
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('insert-columns-left');
    }
  });

  commands.addCommand(CommandIDs.insertColumnsRight, {
    label: () => {
      const numCols = tracker.currentWidget.content.columnsSelected;
      return numCols === 1
        ? 'Insert Column Right'
        : `Insert ${numCols} Columns Right`;
    },
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit(
          'insert-columns-right'
        );
    }
  });

  commands.addCommand(CommandIDs.removeColumns, {
    label: () => {
      const numCols = tracker.currentWidget.content.columnsSelected;
      return numCols === 1 ? 'Remove Column' : `Remove ${numCols} Columns`;
    },
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('remove-columns');
    }
  });

  commands.addCommand(CommandIDs.copyToolbar, {
    icon: copyIcon,
    iconLabel: 'Copy',
    className: 'jp-toolbar-copy',
    caption: 'Copy',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('copy-cells');
    }
  });

  commands.addCommand(CommandIDs.cutToolbar, {
    icon: cutIcon,
    iconLabel: 'Cut',
    className: 'jp-toolbar-cut',
    caption: 'Cut',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('cut-cells');
    }
  });

  commands.addCommand(CommandIDs.pasteToolbar, {
    icon: pasteIcon,
    iconLabel: 'Paste',
    className: 'jp-toolbar-paste',
    caption: 'Paste',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('paste-cells');
    }
  });

  commands.addCommand(CommandIDs.copyContextMenu, {
    label: 'Copy',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('copy-cells');
    }
  });

  commands.addCommand(CommandIDs.cutContextMenu, {
    label: 'Cut',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('cut-cells');
    }
  });

  commands.addCommand(CommandIDs.pasteContextMenu, {
    label: 'Paste',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('paste-cells');
    }
  });

  commands.addCommand(CommandIDs.undo, {
    icon: undoIcon,
    iconLabel: 'Undo',
    className: 'jp-toolbar-undo',
    caption: 'Undo',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('undo');
    }
  });

  commands.addCommand(CommandIDs.redo, {
    icon: redoIcon,
    iconLabel: 'Redo',
    className: 'jp-toolbar-redo',
    caption: 'Redo',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('redo');
    }
  });

  commands.addCommand(CommandIDs.save, {
    icon: saveIcon,
    iconLabel: 'Save',
    className: 'jp-toolbar-save',
    caption: 'Save',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('save');
    }
  });

  commands.addCommand(CommandIDs.clearCells, {
    label: 'Clear Contents',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('clear-cells');
    }
  });

  commands.addCommand(CommandIDs.clearColumns, {
    label: 'Clear Columns',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('clear-columns');
    }
  });

  commands.addCommand(CommandIDs.clearRows, {
    label: 'Clear Rows',
    execute: () => {
      tracker.currentWidget &&
        tracker.currentWidget.content.commandSignal.emit('clear-rows');
    }
  });

  // these commands are standard for every context menu
  const standardContextMenu = [
    'cutContextMenu',
    'copyContextMenu',
    'pasteContextMenu',
    'separator'
  ];

  // extending the standard context menu for different parts of the data
  const bodyContextMenu = [
    ...standardContextMenu,
    'insertRowsAbove',
    'insertRowsBelow',
    'separator',
    'removeRows',
    'clearCells'
  ];
  const columnHeaderContextMenu = [
    ...standardContextMenu,
    'insertColumnsLeft',
    'insertColumnsRight',
    'separator',
    'removeColumns',
    'clearColumns'
  ];
  const rowHeaderContextMenu = [
    ...standardContextMenu,
    'insertRowsAbove',
    'insertRowsBelow',
    'separator',
    'removeRows',
    'clearRows'
  ];

  // build the different context menus
  buildContextMenu(app, bodyContextMenu, BODY_SELECTOR);
  buildContextMenu(app, columnHeaderContextMenu, COLUMN_HEADER_SELECTOR);
  buildContextMenu(app, rowHeaderContextMenu, ROW_HEADER_SELECTOR);

  // add keybindings
  app.commands.addKeyBinding({
    command: CommandIDs.copyContextMenu,
    args: {},
    keys: ['Accel C'],
    selector: GLOBAL_SELECTOR
  });

  app.commands.addKeyBinding({
    command: CommandIDs.save,
    args: {},
    keys: ['Accel S'],
    selector: GLOBAL_SELECTOR
  });

  app.commands.addKeyBinding({
    command: CommandIDs.cutContextMenu,
    args: {},
    keys: ['Accel X'],
    selector: GLOBAL_SELECTOR
  });

  app.commands.addKeyBinding({
    command: CommandIDs.undo,
    args: {},
    keys: ['Accel Z'],
    selector: GLOBAL_SELECTOR
  });
  app.commands.addKeyBinding({
    command: CommandIDs.redo,
    args: {},
    keys: ['Accel Shift Z'],
    selector: GLOBAL_SELECTOR
  });
  // app.commands.addKeyBinding({
  //   command: CommandIDs.clearContents,
  //   args: {},
  //   keys: ['Backspace'],
  //   selector: GLOBAL_SELECTOR
  // });
}
Example #13
Source File: plugin.ts    From jupyter-videochat with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
/**
 * Handle application-level concerns
 */
async function activateCore(
  app: JupyterFrontEnd,
  settingRegistry: ISettingRegistry,
  translator?: ITranslator,
  palette?: ICommandPalette,
  launcher?: ILauncher,
  restorer?: ILayoutRestorer,
  mainmenu?: IMainMenu
): Promise<IVideoChatManager> {
  const { commands, shell } = app;

  const labShell = isFullLab(app) ? (shell as LabShell) : null;

  const manager = new VideoChatManager({
    trans: (translator || nullTranslator).load(NS),
  });

  const { __ } = manager;

  let widget: MainAreaWidget;
  let chat: VideoChat;
  let subject: string | null = null;

  const tracker = new WidgetTracker<MainAreaWidget>({ namespace: NS });

  if (!widget || widget.isDisposed) {
    // Create widget
    chat = new VideoChat(manager, {});
    widget = new MainAreaWidget({ content: chat });
    widget.addClass(`${CSS}-wrapper`);
    manager.setMainWidget(widget);

    widget.toolbar.addItem(ToolbarIds.SPACER_LEFT, Toolbar.createSpacerItem());

    widget.toolbar.addItem(ToolbarIds.TITLE, new RoomTitle(manager));

    widget.toolbar.addItem(ToolbarIds.SPACER_RIGHT, Toolbar.createSpacerItem());

    const disconnectBtn = new CommandToolbarButton({
      id: CommandIds.disconnect,
      commands,
      icon: stopIcon,
    });

    const onCurrentRoomChanged = () => {
      if (manager.currentRoom) {
        disconnectBtn.show();
      } else {
        disconnectBtn.hide();
      }
    };

    manager.currentRoomChanged.connect(onCurrentRoomChanged);

    widget.toolbar.addItem(ToolbarIds.DISCONNECT, disconnectBtn);

    onCurrentRoomChanged();

    chat.id = `id-${NS}`;
    chat.title.caption = __(DEFAULT_LABEL);
    chat.title.closable = false;
    chat.title.icon = chatIcon;
  }

  // hide the label when in sidebar, as it shows the rotated text
  function updateTitle() {
    if (subject != null) {
      widget.title.caption = subject;
    } else {
      widget.title.caption = __(DEFAULT_LABEL);
    }
    widget.title.label = manager.currentArea === 'main' ? widget.title.caption : '';
  }

  // add to shell, update tracker, title, etc.
  function addToShell(area?: ILabShell.Area, activate = true) {
    DEBUG && console.warn(`add to shell in are ${area}, ${!activate || 'not '} active`);
    area = area || manager.currentArea;
    if (labShell) {
      labShell.add(widget, area);
      updateTitle();
      widget.update();
      if (!tracker.has(widget)) {
        tracker.add(widget).catch(void 0);
      }
      if (activate) {
        shell.activateById(widget.id);
      }
    } else if (window.location.search.indexOf(FORCE_URL_PARAM) !== -1) {
      document.title = [document.title.split(' - ')[0], __(DEFAULT_LABEL)].join(' - ');
      app.shell.currentWidget.parent = null;
      app.shell.add(widget, 'main', { rank: 0 });
      const { parent } = widget;
      parent.addClass(`${CSS}-main-parent`);
      setTimeout(() => {
        parent.update();
        parent.fit();
        app.shell.fit();
        app.shell.update();
      }, 100);
    }
  }

  // listen for the subject to update the widget title dynamically
  manager.meetChanged.connect(() => {
    if (manager.meet) {
      manager.meet.on('subjectChange', (args: any) => {
        subject = args.subject;
        updateTitle();
      });
    } else {
      subject = null;
    }
    updateTitle();
  });

  // connect settings
  settingRegistry
    .load(corePlugin.id)
    .then((settings) => {
      manager.settings = settings;
      let lastArea = manager.settings.composite.area;
      settings.changed.connect(() => {
        if (lastArea !== manager.settings.composite.area) {
          addToShell();
        }
        lastArea = manager.settings.composite.area;
      });
      addToShell(null, false);
    })
    .catch(() => addToShell(null, false));

  // add commands
  commands.addCommand(CommandIds.open, {
    label: __(DEFAULT_LABEL),
    icon: prettyChatIcon,
    execute: async (args: IChatArgs) => {
      await manager.initialized;
      addToShell(null, true);
      // Potentially navigate to new room
      if (manager.currentRoom?.displayName !== args.displayName) {
        manager.currentRoom = { displayName: args.displayName };
      }
    },
  });

  commands.addCommand(CommandIds.disconnect, {
    label: __('Disconnect Video Chat'),
    execute: () => (manager.currentRoom = null),
    icon: stopIcon,
  });

  commands.addCommand(CommandIds.toggleArea, {
    label: __('Toggle Video Chat Sidebar'),
    icon: launcherIcon,
    execute: async () => {
      manager.currentArea = ['right', 'left'].includes(manager.currentArea)
        ? 'main'
        : 'right';
    },
  });

  // If available, add the commands to the palette
  if (palette) {
    palette.addItem({ command: CommandIds.open, category: __(category) });
  }

  // If available, add a card to the launcher
  if (launcher) {
    launcher.add({ command: CommandIds.open, args: { area: 'main' } });
  }

  // If available, restore the position
  if (restorer) {
    restorer
      .restore(tracker, { command: CommandIds.open, name: () => `id-${NS}` })
      .catch(console.warn);
  }

  // If available, add to the file->new menu.... new tab handled in retroPlugin
  if (mainmenu && labShell) {
    mainmenu.fileMenu.newMenu.addGroup([{ command: CommandIds.open }]);
  }

  // Return the manager that others extensions can use
  return manager;
}