|
@@ -11,6 +11,8 @@ import { JupyterLab, JupyterLabPlugin } from '@jupyterlab/application';
|
|
|
|
|
|
import { ICommandPalette, showDialog, Dialog } from '@jupyterlab/apputils';
|
|
import { ICommandPalette, showDialog, Dialog } from '@jupyterlab/apputils';
|
|
|
|
|
|
|
|
+import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
|
|
|
+
|
|
import {
|
|
import {
|
|
IMainMenu,
|
|
IMainMenu,
|
|
IMenuExtender,
|
|
IMenuExtender,
|
|
@@ -24,6 +26,8 @@ import {
|
|
TabsMenu
|
|
TabsMenu
|
|
} from '@jupyterlab/mainmenu';
|
|
} from '@jupyterlab/mainmenu';
|
|
|
|
|
|
|
|
+import { ServerConnection } from '@jupyterlab/services';
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* A namespace for command IDs of semantic extension points.
|
|
* A namespace for command IDs of semantic extension points.
|
|
*/
|
|
*/
|
|
@@ -49,6 +53,8 @@ export namespace CommandIDs {
|
|
|
|
|
|
export const createConsole = 'filemenu:create-console';
|
|
export const createConsole = 'filemenu:create-console';
|
|
|
|
|
|
|
|
+ export const quit = 'filemenu:quit';
|
|
|
|
+
|
|
export const interruptKernel = 'kernelmenu:interrupt';
|
|
export const interruptKernel = 'kernelmenu:interrupt';
|
|
|
|
|
|
export const restartKernel = 'kernelmenu:restart';
|
|
export const restartKernel = 'kernelmenu:restart';
|
|
@@ -94,6 +100,9 @@ const menuPlugin: JupyterLabPlugin<IMainMenu> = {
|
|
logo.addClass('jp-JupyterIcon');
|
|
logo.addClass('jp-JupyterIcon');
|
|
logo.id = 'jp-MainLogo';
|
|
logo.id = 'jp-MainLogo';
|
|
|
|
|
|
|
|
+ let quitButton = PageConfig.getOption('quit_button');
|
|
|
|
+ menu.fileMenu.quitEntry = quitButton === 'True';
|
|
|
|
+
|
|
// Create the application menus.
|
|
// Create the application menus.
|
|
createEditMenu(app, menu.editMenu);
|
|
createEditMenu(app, menu.editMenu);
|
|
createFileMenu(app, menu.fileMenu);
|
|
createFileMenu(app, menu.fileMenu);
|
|
@@ -103,6 +112,13 @@ const menuPlugin: JupyterLabPlugin<IMainMenu> = {
|
|
createViewMenu(app, menu.viewMenu);
|
|
createViewMenu(app, menu.viewMenu);
|
|
createTabsMenu(app, menu.tabsMenu);
|
|
createTabsMenu(app, menu.tabsMenu);
|
|
|
|
|
|
|
|
+ if (menu.fileMenu.quitEntry) {
|
|
|
|
+ palette.addItem({
|
|
|
|
+ command: CommandIDs.quit,
|
|
|
|
+ category: 'Main Area'
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
palette.addItem({
|
|
palette.addItem({
|
|
command: CommandIDs.shutdownAllKernels,
|
|
command: CommandIDs.shutdownAllKernels,
|
|
category: 'Kernel Operations'
|
|
category: 'Kernel Operations'
|
|
@@ -258,6 +274,43 @@ export function createFileMenu(app: JupyterLab, menu: FileMenu): void {
|
|
execute: Private.delegateExecute(app, menu.consoleCreators, 'createConsole')
|
|
execute: Private.delegateExecute(app, menu.consoleCreators, 'createConsole')
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+ commands.addCommand(CommandIDs.quit, {
|
|
|
|
+ label: 'Quit',
|
|
|
|
+ caption: 'Quit JupyterLab',
|
|
|
|
+ execute: () => {
|
|
|
|
+ showDialog({
|
|
|
|
+ title: 'Quit confirmation',
|
|
|
|
+ body: 'Please confirm you want to quit JupyterLab.',
|
|
|
|
+ buttons: [Dialog.cancelButton(), Dialog.warnButton({ label: 'Quit' })]
|
|
|
|
+ }).then(result => {
|
|
|
|
+ if (result.button.accept) {
|
|
|
|
+ let setting = ServerConnection.makeSettings();
|
|
|
|
+ let apiURL = URLExt.join(setting.baseUrl, 'api/shutdown');
|
|
|
|
+ ServerConnection.makeRequest(apiURL, { method: 'POST' }, setting)
|
|
|
|
+ .then(result => {
|
|
|
|
+ if (result.ok) {
|
|
|
|
+ // Close this window if the shutdown request has been successful
|
|
|
|
+ let body = document.createElement('div');
|
|
|
|
+ body.innerHTML = `<p>You have shut down the Jupyter server. You can now close this tab.</p>
|
|
|
|
+ <p>To use JupyterLab again, you will need to relaunch it.</p>`;
|
|
|
|
+ showDialog({
|
|
|
|
+ title: 'Server stopped',
|
|
|
|
+ body: new Widget({ node: body }),
|
|
|
|
+ buttons: []
|
|
|
|
+ });
|
|
|
|
+ window.close();
|
|
|
|
+ } else {
|
|
|
|
+ throw new ServerConnection.ResponseError(result);
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ .catch(data => {
|
|
|
|
+ throw new ServerConnection.NetworkError(data);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
// Add the new group
|
|
// Add the new group
|
|
const newGroup = [
|
|
const newGroup = [
|
|
{ type: 'submenu' as Menu.ItemType, submenu: menu.newMenu.menu },
|
|
{ type: 'submenu' as Menu.ItemType, submenu: menu.newMenu.menu },
|
|
@@ -298,11 +351,17 @@ export function createFileMenu(app: JupyterLab, menu: FileMenu): void {
|
|
return { command };
|
|
return { command };
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+ // Add the quit group.
|
|
|
|
+ const quitGroup = [{ command: 'filemenu:quit' }];
|
|
|
|
+
|
|
menu.addGroup(newGroup, 0);
|
|
menu.addGroup(newGroup, 0);
|
|
menu.addGroup(newViewGroup, 1);
|
|
menu.addGroup(newViewGroup, 1);
|
|
menu.addGroup(closeGroup, 2);
|
|
menu.addGroup(closeGroup, 2);
|
|
menu.addGroup(saveGroup, 3);
|
|
menu.addGroup(saveGroup, 3);
|
|
menu.addGroup(reGroup, 4);
|
|
menu.addGroup(reGroup, 4);
|
|
|
|
+ if (menu.quitEntry) {
|
|
|
|
+ menu.addGroup(quitGroup, 99);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|