Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions packages/tree-extension/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
caretDownIcon,
folderIcon,
runningIcon,
terminalIcon,
} from '@jupyterlab/ui-components';

import { Menu, MenuBar } from '@lumino/widgets';
Expand All @@ -54,6 +55,9 @@ const FILE_BROWSER_FACTORY = 'FileBrowser';
* The namespace for command IDs.
*/
namespace CommandIDs {
// Create a terminal in the current file browser directory.
export const createNewTerminal = 'filebrowser:create-new-terminal';

// The command to show the filebrowser widget in tree view.
export const openDirectory = 'filebrowser:open-directory';

Expand All @@ -74,17 +78,39 @@ const createNew: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/tree-extension:new',
description:
'Plugin to add extra commands to the file browser to create new notebooks, files, consoles and terminals.',
requires: [ITranslator],
requires: [IFileBrowserFactory, ITranslator],
optional: [IToolbarWidgetRegistry],
autoStart: true,
activate: (
app: JupyterFrontEnd,
fileBrowserFactory: IFileBrowserFactory,
translator: ITranslator,
toolbarRegistry: IToolbarWidgetRegistry | null
) => {
const { commands, serviceManager } = app;
const trans = translator.load('notebook');

commands.addCommand(CommandIDs.createNewTerminal, {
label: trans.__('Terminal'),
icon: terminalIcon,
isEnabled: () => commands.isEnabled('terminal:create-new'),
isVisible: () => commands.isVisible('terminal:create-new'),
execute: () => {
const browser = fileBrowserFactory.tracker.currentWidget;
if (browser) {
return commands.execute('terminal:create-new', {
cwd: browser.model.path,
});
}
},
describedBy: {
args: {
type: 'object',
properties: {},
},
},
});

const overflowOptions = {
overflowMenuOptions: { isVisible: false },
};
Expand All @@ -105,7 +131,7 @@ const createNew: JupyterFrontEndPlugin<void> = {
}

const baseCommands = [
'terminal:create-new',
CommandIDs.createNewTerminal,
'console:create',
'filebrowser:create-new-file',
'filebrowser:create-new-directory',
Expand Down
38 changes: 38 additions & 0 deletions ui-tests/test/tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,44 @@ test('should update url when navigating in filebrowser', async ({
expect(url.pathname).toEqual(`/tree/${tmpPath}/${SUBFOLDER}`);
});

test('should create a terminal in the current directory', async ({
page,
tmpPath,
}) => {
const dir = `${tmpPath}/${SUBFOLDER}`;
const marker = 'terminal-cwd.txt';
await page.contents.createDirectory(dir);
await page.filebrowser.refresh();
await page.dblclick(`.jp-FileBrowser-listing >> text=${SUBFOLDER}`);
await page.waitForSelector(`.jp-FileBrowser-crumbs >> text=/${SUBFOLDER}/`);

const [terminal] = await Promise.all([
page.waitForEvent('popup'),
page.menu.clickMenuItem('New>Terminal'),
]);

const terminalPanel = terminal.locator('.jp-Terminal');
await terminalPanel.waitFor();
await terminalPanel.locator('.xterm-screen').click();
const input = terminalPanel.locator('[aria-label="Terminal input"]');
await input.waitFor({ state: 'attached' });
await expect(input).toBeFocused();
await terminal.keyboard.type(`pwd > ${marker}`);
await terminal.keyboard.press('Enter');

const markerItem = page.locator(`.jp-FileBrowser-listing >> text=${marker}`);
await expect
.poll(
async () => {
await page.filebrowser.refresh();
return markerItem.count();
},
{ timeout: 10_000 }
)
.toBeGreaterThan(0);
await terminal.close();
});

test('Should redirect from notebooks route to tree route for directories', async ({
page,
tmpPath,
Expand Down
Loading