Creating a fresh addition to the primary menu in Jupyterlabs

I'm currently working on developing a plugin to introduce a fresh menu into the existing menu structure within Jupyterlabs interface.... next to file, edit, ... Settings, and Help

The basic xkcd example is functioning correctly, and I've been thoroughly examining the code in packages/mainmenu in an attempt to utilize the tab menu as a guide (possibly incorporating contextual options later on...)

This is my current progress:

    import { PageConfig } from '@jupyterlab/coreutils';
    import { JupyterLab, JupyterLabPlugin } from '@jupyterlab/application';
    import { IMainMenu, IJupyterLabMenu, JupyterLabMenu } from '@jupyterlab/mainmenu';
    import { Menu } from '@phosphor/widgets';

    interface INoteableMenu extends IJupyterLabMenu {}

    class NoteableMenu extends JupyterLabMenu implements INoteableMenu {
      constructor(options: Menu.IOptions) {
        super(options);
        this.menu.title.label = 'Noteable';
      }
    }

    const extension: JupyterLabPlugin<void> = {
      id: 'noteable-menu',
      autoStart: true,
      activate: (app: JupyterLab) => {
        console.log('JupyterLab extension noteable is activated!');
        let mainMenu: IMainMenu;  //app.contextMenu??
        //let noteableMenu = new NoteableMenu({ commands: {} });
        mainMenu.addMenu(NoteableMenu.menu, { rank: 2000 });
      }
    };

    export default extension;

    export namespace CommandIDs {
      export const returnToHome = 'noteablemenu:home';
      export const switchToClassic = 'noteablemenu:classic';
    }

    export function createNoteableMenu(
      menu: NoteableMenu,
    ): void {
      const commands = menu.menu.commands;

      commands.addCommand(CommandIDs.returnToHome, {
        label: 'Jump to example page',
        execute: () => {
          location.assign(location.origin + '/example');
        }
      });

      commands.addCommand(CommandIDs.switchToClassic, {
        label: 'Switch to Classic Notebook',
        execute: () => {
          location.assign(PageConfig.getBaseUrl() + 'tree');
        }
      });
    }

Unfortunately, I encountered a build failure (using

jupyter labextension install . --no-build
resulting in the error

src/index.ts:26:35 - error TS2339: Property 'menu' does not exist on type 'typeof NoteableMenu'.
26     mainMenu.addMenu(NoteableMenu.menu, { rank: 2000 });
                                     ~~~~

I am struggling to identify the practical differences between my code and the provided examples.

Any tips, hints, or direct solutions would be greatly appreciated...

(for reference: nodejs: v8.10.0, jupyterlab: 0.35.5)

Answer №1

Below is the complete content of the index.ts file:

import { IMainMenu } from '@jupyterlab/mainmenu';
import { JupyterLab, JupyterLabPlugin } from '@jupyterlab/application';
import { Menu } from '@phosphor/widgets';
import { Token } from '@phosphor/coreutils';
import { PageConfig } from '@jupyterlab/coreutils';

export const EXTENSION_ID = 'jupyter.extensions.noteable_plugin';

/** Definition of interface for extension */
export interface INoteableExtension {}

// tslint:disable-next-line: variable-name
export const INoteableExtension = new Token<INoteableExtension>(EXTENSION_ID);

export class NoteableExtension implements INoteableExtension {
  // private app: JupyterLab;
  constructor( app: JupyterLab ) {}
  //{ this.app = app; }
}

/**
 * Command IDs used by the help plugin.
 */
export namespace CommandIDs {
  export const returnUI = 'noteable:returnUI';
  export const switchClassic = 'noteable:launch-classic-notebook';
}

/**
 * Default running sessions extension.
 */
const plugin: JupyterLabPlugin<INoteableExtension> = {
  id: 'jupyter.extensions.running-sessions-Noteable',
  requires: [
    IMainMenu,
  ],
  provides: INoteableExtension,
  activate,
  autoStart: true
};


/**
 * Export the plugin as default.
 */
export default plugin;

function activate(
  app: JupyterLab,
  mainMenu: IMainMenu,
): INoteableExtension {
  const { commands } = app;
  let noteableExtension = new NoteableExtension(app);
  const category = 'Noteable';

  // Rank has been chosen somewhat arbitrarily to give priority to the running
  // sessions widget in the sidebar.
  addCommands(app);
  let menu = new Menu({ commands });

  menu.title.label = category;
  [CommandIDs.returnUI, CommandIDs.switchClassic].forEach(
    command => {
      menu.addItem({ command });
    }
  );

  mainMenu.addMenu(menu, { rank: 60 });

  return noteableExtension;
}

/**
 * Add the commands for the git extension.
 */
export function addCommands(app: JupyterLab) {
  let { commands } = app;

  commands.addCommand(CommandIDs.returnUI, {
    label: 'Return to JupyterHub Home',
    execute: () => {
      location.assign(location.origin + '/home');
    }
  });

  commands.addCommand(CommandIDs.switchClassic, {
    label: 'Switch to Classic Notebook',
    execute: () => {
      location.assign(PageConfig.getBaseUrl() + 'tree');
    }
  });

}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to utilize the features of component A within component B when they exist as separate entities

Component A has all the necessary functionalities, and I want to use it in Component B. The code for ComponentA.ts is extensive, but it's not written in a service. How can I utilize the logic from Component A without using a service, considering both ...

What is the process for creating an Angular library using "npm pack" within a Java/Spring Boot application?

In my angular project, we have 5 custom libraries tailored to our needs. Using the com.github.eirslett maven plugin in our spring boot application, we build these libraries through the pom.xml file and then copy them to the dist/ folder. However, we also ...

Exclude the use of ':any' in React component

Currently, I am new to React and facing a challenge in sending a variable and function to my component. I understand that using :any is not the best practice, so I am seeking a better solution. I am working on creating a modal and passing data to my compo ...

Error: Unable to access the 'filter' property as it is undefined. TypeError occurred

findLoads(){ if(this.loggedInUser.userFullySetupFlag === 0 || this.loggedInUser.businessFullySetupFlag === 0){ swal( 'Incomplete Profile', 'To find loads and bid, all the details inside User Profile (My Profile) and Business Profil ...

Is it necessary to wait for the resolve function when using hooks in SvelteKit?

i have implemented this handle function for SvelteKit hooks and since it returns a promise of response, the resolve function does not necessarily need to be awaited. This is because it is a function that either directly returns a value or returns a promise ...

Angular Igx-calendar User Interface Component

I need assistance with implementing a form that includes a calendar for users to select specific dates. Below is the code snippet: Here is the HTML component file (about.component.html): <form [formGroup]="angForm" class="form-element"> <d ...

Enabling logging for the Mapnik SQL query while generating the map

Currently, I am utilizing the npm package known as Mapnik in conjunction with PostGIS. My goal is to include logging functionality that captures the SQL query executed by Mapnik, along with the value of the bbox parameter, when executing the render() funct ...

Utilizing the axios create method: troubleshooting and best practices

I am attempting to use the axios library in my Next.js app (written in TypeScript) to access a public API for retrieving IP addresses from . In my index.ts file, I have the following code: import axios from "axios"; export const ipApi = axios.cr ...

Error: The property 'process' cannot be read because it is not defined

Seeking help with a code issue Any advice on best practices would be greatly appreciated. Thank you! An error has occurred: TypeError: Cannot read property 'process' of undefined myComponent.ts ProcessInfo: any | false; showSaveItems = ...

Explore a vast array of items in a collection

I have a massive collection of various objects that I need to sift through. With over 60,000 elements, the search operation can sometimes be painfully slow. One typical object in this array has the following structure: { "title": "title" "company": ...

Specialized typescript function that is compatible with extended interfaces

Is there a way to create a versatile function that can be applied to any interface derived from a top-level interface? This function should take an unpersisted interface (without an id property) and return a persisted one (with an id property). The two ma ...

Issue with Angular: Global variable not updating within Subscription function

I'm encountering difficulties with updating a global variable in Angular 7 by using TypeScript. I am utilizing a service that retrieves JSON data from a database via a Restful API The service : export class myService { constructor(private client ...

Typescript's Intersection Types: The Key to Overlapping Properties

Looking to create a type-safe utility function in Typescript 4.0 for comparing properties of two objects, my initial code snippet is below: export function propertiesMatch<O extends object, T extends O, S extends O>(first: T, second: S, props: (keyof ...

Leverage the generic types of an extended interface to simplify the creation of a shorthand type

Attempting to streamline my action shorthand that interacts with AsyncActionCreators. A function has been crafted to accept a React dispatch: Dispatch<T> parameter: const fetchProfileAction = actionCreator.async<void, Profile, any>('FETC ...

Typescript | The extension of formikProps on IProps in Typescript is lacking 27 Props

I'm currently working with Formik in TypeScript and I'm trying to integrate a simple form component into TS within another component where I extract the defaultValues and validationSchemas. The challenge lies in accessing only the necessary form ...

Could a class instance be transformed into an object that holds the keys of its public properties in the interface?

For example, if we have a Person object defined like this: class PersonClass implements Person { private _name : string; private _age : number; get name() : string {return this._name} get age() : number {return this._age} constructor(name : strin ...

What is the best approach to obtain a Generic and static reference to a MongoDB collection?

My goal is to create a generic and static class method called getOne<T>() that can return MongoDB objects as an Item, where the Item can be either a Book or a Film. Initially, I had an idea on how to achieve this, but now I am struggling with dynamic ...

Encountering an Unexpected Index Error with ngFor in Angular 4/5

I am struggling to create a list of inputs and I can't seem to get ngFor to work properly. <div *ngFor="let q of questions; let i = index" class="col-3"> <div class="group"> <input [(ngModel)]="q" [class.ng-not-empty]="q.length & ...

Selecting the optimal data structure: weighing the benefits of using boolean check versus array .include (balancing performance and redundancy

My objects can have one or more properties assigned, with a total of 5 different properties in my case. To illustrate this, let's use a simple movie example where each movie can be assigned from 5 different genres. I have come up with two methods to ...

Transferring information between Puppeteer and a Vue JS Component

When my app's data flow starts with a backend API request that triggers a Vue component using puppeteer, is there a way to transfer that data from Backend (express) to the vue component without requiring the Vue component to make an additional backend ...