Skip to content

Commit b3fb266

Browse files
authored
Fix opening sample notebook (microsoft#14362)
1 parent 47c8ad4 commit b3fb266

10 files changed

Lines changed: 73 additions & 10 deletions

File tree

package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,5 +207,6 @@
207207
"StartPage.sampleNotebook": "Notebooks intro",
208208
"StartPage.openFolder": "Open a Folder or Workspace",
209209
"StartPage.folderDesc": "- Open a <div class=\"link\" role=\"button\" onclick={0}>Folder</div><br /> - Open a <div class=\"link\" role=\"button\" onclick={1}>Workspace</div>",
210-
"StartPage.badWebPanelFormatString": "<html><body><h1>{0} is not a valid file name</h1></body></html>"
210+
"StartPage.badWebPanelFormatString": "<html><body><h1>{0} is not a valid file name</h1></body></html>",
211+
"Jupyter.extensionRequired": "The Jupyter extension is required to perform that task. Click Yes to open the Jupyter extension installation page."
211212
}

src/client/common/application/commandManager.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33

44
// tslint:disable:no-any
55

6-
import { injectable } from 'inversify';
6+
import { inject, injectable } from 'inversify';
77
import { commands, Disposable, TextEditor, TextEditorEdit } from 'vscode';
88
import { ICommandNameArgumentTypeMapping } from './commands';
9-
import { ICommandManager } from './types';
9+
import { ICommandManager, IJupyterExtensionDependencyManager } from './types';
1010

1111
@injectable()
1212
export class CommandManager implements ICommandManager {
13+
constructor(
14+
@inject(IJupyterExtensionDependencyManager)
15+
private jupyterExtensionDependencyManager: IJupyterExtensionDependencyManager
16+
) {}
17+
1318
/**
1419
* Registers a command that can be invoked via a keyboard shortcut,
1520
* a menu item, an action, or directly.
@@ -70,7 +75,11 @@ export class CommandManager implements ICommandManager {
7075
E extends keyof ICommandNameArgumentTypeMapping,
7176
U extends ICommandNameArgumentTypeMapping[E]
7277
>(command: E, ...rest: U): Thenable<T | undefined> {
73-
return commands.executeCommand<T>(command, ...rest);
78+
if (command.includes('jupyter') && !this.jupyterExtensionDependencyManager.isJupyterExtensionInstalled) {
79+
return this.jupyterExtensionDependencyManager.installJupyterExtension();
80+
} else {
81+
return commands.executeCommand<T>(command, ...rest);
82+
}
7483
}
7584

7685
/**

src/client/common/application/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,12 @@ export interface ICommandManager {
499499
getCommands(filterInternal?: boolean): Thenable<string[]>;
500500
}
501501

502+
export const IJupyterExtensionDependencyManager = Symbol('IJupyterExtensionDependencyManager');
503+
export interface IJupyterExtensionDependencyManager {
504+
readonly isJupyterExtensionInstalled: boolean;
505+
installJupyterExtension(): Promise<undefined>;
506+
}
507+
502508
export const IDocumentManager = Symbol('IDocumentManager');
503509

504510
export interface IDocumentManager {

src/client/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const PYTHON_ALLFILES = [{ language: PYTHON_LANGUAGE }];
1616
export const PVSC_EXTENSION_ID = 'ms-python.python';
1717
export const CODE_RUNNER_EXTENSION_ID = 'formulahendry.code-runner';
1818
export const PYLANCE_EXTENSION_ID = 'ms-python.vscode-pylance';
19+
export const JUPYTER_EXTENSION_ID = 'ms-toolsai.jupyter';
1920
export const AppinsightsKey = 'AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217';
2021

2122
export namespace Commands {

src/client/common/serviceRegistry.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { IExtensionSingleActivationService } from '../activation/types';
44
import { IExperimentService, IFileDownloader, IHttpClient, IInterpreterPathService } from '../common/types';
55
import { IServiceManager } from '../ioc/types';
6+
import { JupyterExtensionDependencyManager } from '../jupyter/jupyterExtensionDependencyManager';
67
import { ImportTracker } from '../telemetry/importTracker';
78
import { IImportTracker } from '../telemetry/types';
89
import { ActiveResourceService } from './application/activeResource';
@@ -28,6 +29,7 @@ import {
2829
ICustomEditorService,
2930
IDebugService,
3031
IDocumentManager,
32+
IJupyterExtensionDependencyManager,
3133
ILanguageService,
3234
ITerminalManager,
3335
IVSCodeNotebook,
@@ -129,6 +131,10 @@ export function registerTypes(serviceManager: IServiceManager) {
129131
serviceManager.addSingleton<IClipboard>(IClipboard, ClipboardService);
130132
serviceManager.addSingleton<ICurrentProcess>(ICurrentProcess, CurrentProcess);
131133
serviceManager.addSingleton<IInstaller>(IInstaller, ProductInstaller);
134+
serviceManager.addSingleton<IJupyterExtensionDependencyManager>(
135+
IJupyterExtensionDependencyManager,
136+
JupyterExtensionDependencyManager
137+
);
132138
serviceManager.addSingleton<ICommandManager>(ICommandManager, CommandManager);
133139
serviceManager.addSingleton<IConfigurationService>(IConfigurationService, ConfigurationService);
134140
serviceManager.addSingleton<IWorkspaceService>(IWorkspaceService, WorkspaceService);

src/client/common/startPage/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ export enum Telemetry {
3434
}
3535

3636
export namespace Commands {
37-
export const RunAllCells = 'python.datascience.runallcells';
38-
export const OpenNotebook = 'python.datascience.opennotebook';
37+
export const RunAllCells = 'jupyter.runallcells';
38+
export const OpenNotebook = 'jupyter.opennotebook';
3939
}

src/client/common/startPage/startPage.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export class StartPage extends WebviewPanelHost<IStartPageMapping>
130130

131131
if (savedVersion) {
132132
await this.commandManager.executeCommand(
133-
'python.datascience.opennotebook',
133+
'jupyter.opennotebook',
134134
undefined,
135135
CommandSource.commandPalette
136136
);
@@ -157,7 +157,7 @@ export class StartPage extends WebviewPanelHost<IStartPageMapping>
157157
content: `#%%\nprint("${localize.StartPage.helloWorld()}")`
158158
});
159159
await this.documentManager.showTextDocument(doc2, 1, true);
160-
await this.commandManager.executeCommand('python.datascience.runallcells', Uri.parse(''));
160+
await this.commandManager.executeCommand('jupyter.runallcells', Uri.parse(''));
161161
break;
162162
case StartPageMessages.OpenCommandPalette:
163163
sendTelemetryEvent(Telemetry.StartPageOpenCommandPalette);
@@ -296,7 +296,7 @@ export class StartPage extends WebviewPanelHost<IStartPageMapping>
296296
}
297297

298298
await this.commandManager.executeCommand(
299-
'python.datascience.opennotebook',
299+
'jupyter.opennotebook',
300300
Uri.file(sampleNotebookPath),
301301
CommandSource.commandPalette
302302
);

src/client/common/utils/localize.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ export namespace Pylance {
126126
);
127127
}
128128

129+
export namespace Jupyter {
130+
export const jupyterExtensionRequired = localize(
131+
'Jupyter.extensionRequired',
132+
'The Jupyter extension is required to perform that task. Click Yes to open the Jupyter extension installation page.'
133+
);
134+
}
135+
129136
export namespace LanguageService {
130137
export const startingJedi = localize('LanguageService.startingJedi', 'Starting Jedi Python language engine.');
131138
export const startingMicrosoft = localize(
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { inject, injectable } from 'inversify';
2+
import {
3+
IApplicationEnvironment,
4+
IApplicationShell,
5+
IJupyterExtensionDependencyManager
6+
} from '../common/application/types';
7+
import { JUPYTER_EXTENSION_ID } from '../common/constants';
8+
import { IExtensions } from '../common/types';
9+
import { Common, Jupyter } from '../common/utils/localize';
10+
11+
@injectable()
12+
export class JupyterExtensionDependencyManager implements IJupyterExtensionDependencyManager {
13+
constructor(
14+
@inject(IExtensions) private extensions: IExtensions,
15+
@inject(IApplicationShell) private appShell: IApplicationShell,
16+
@inject(IApplicationEnvironment) private appEnv: IApplicationEnvironment
17+
) {}
18+
19+
public get isJupyterExtensionInstalled() {
20+
return this.extensions.getExtension(JUPYTER_EXTENSION_ID) !== undefined;
21+
}
22+
23+
public async installJupyterExtension(): Promise<undefined> {
24+
const yes = Common.bannerLabelYes();
25+
const no = Common.bannerLabelNo();
26+
const answer = await this.appShell.showErrorMessage(Jupyter.jupyterExtensionRequired(), yes, no);
27+
if (answer === yes) {
28+
this.appShell.openUrl(`${this.appEnv.uriScheme}:extension/${JUPYTER_EXTENSION_ID}`);
29+
}
30+
return undefined;
31+
}
32+
}

src/client/jupyter/jupyterIntegration.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { dirname } from 'path';
1010
import { CancellationToken, Disposable, Event, Memento, Uri } from 'vscode';
1111
import * as lsp from 'vscode-languageserver-protocol';
1212
import { ILanguageServerCache, ILanguageServerConnection } from '../activation/types';
13+
import { JUPYTER_EXTENSION_ID } from '../common/constants';
1314
import { InterpreterUri } from '../common/installer/types';
1415
import {
1516
GLOBAL_MEMENTO,
@@ -144,7 +145,7 @@ export class JupyterExtensionIntegration {
144145
}
145146

146147
public async integrateWithJupyterExtension(): Promise<void> {
147-
const jupyterExtension = this.extensions.getExtension<JupyterExtensionApi>('ms-toolsai.jupyter');
148+
const jupyterExtension = this.extensions.getExtension<JupyterExtensionApi>(JUPYTER_EXTENSION_ID);
148149
if (!jupyterExtension) {
149150
return;
150151
}

0 commit comments

Comments
 (0)