Skip to content
2 changes: 1 addition & 1 deletion news/1 Enhancements/16102.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Move the Jupyter extension from being a hard dependency to an optional one.
Move the Jupyter extension from being a hard dependency to an optional one, and display an informational prompt if Jupyter commands try to be executed from the Start Page.
2 changes: 1 addition & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
"StartPage.createAPythonFile": "Create a Python File",
"StartPage.pythonFileDescription": "- Create a <div class=\"link\" role=\"button\" onclick={0}>new file</div> with a .py extension",
"StartPage.openInteractiveWindow": "Use the Interactive Window to develop Python Scripts",
"StartPage.interactiveWindowDesc": "- You can create cells on a Python file by typing \"#%%\" <br /> - Use \"<div class=\"italics\">Shift + Enter</div> \" to run a cell, the output will be shown in the interactive window",
"StartPage.interactiveWindowDesc": "- You can create cells on a Python file by typing \"#%%\". Make sure you have the Jupyter extension installed. <br /> - Use \"<div class=\"italics\">Shift + Enter</div> \" to run a cell, the output will be shown in the interactive window",
"StartPage.releaseNotes": "Take a look at our <a class=\"link\" href={0}>Release Notes</a> to learn more about the latest features.",
"StartPage.mailingList": "<a class=\"link\" href={0}>Sign up</a> for tips and tutorials through our mailing list.",
"StartPage.tutorialAndDoc": "Explore more features in our <a class=\"link\" href={0}>Tutorials</a> or check <a class=\"link\" href={1}>Documentation</a> for tips and troubleshooting.",
Expand Down
94 changes: 67 additions & 27 deletions src/client/common/startPage/startPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,27 @@

'use strict';

import { inject, injectable } from 'inversify';
import { inject, injectable, named } from 'inversify';
import * as path from 'path';
import { ConfigurationTarget, EventEmitter, UIKind, Uri, ViewColumn } from 'vscode';
import { IExtensionSingleActivationService } from '../../activation/types';
import { EXTENSION_ROOT_DIR } from '../../constants';
import { IJupyterNotInstalledNotificationHelper, JupyterNotInstalledOrigin } from '../../jupyter/types';
import { sendTelemetryEvent } from '../../telemetry';
import {
IApplicationEnvironment,
IApplicationShell,
ICommandManager,
IDocumentManager,
IJupyterExtensionDependencyManager,
IWebviewPanelProvider,
IWorkspaceService,
} from '../application/types';
import { CommandSource } from '../constants';
import { CommandSource, STANDARD_OUTPUT_CHANNEL } from '../constants';
import { IFileSystem } from '../platform/types';
import { IConfigurationService, IExtensionContext, Resource } from '../types';
import { IConfigurationService, IExtensionContext, IOutputChannel, Resource } from '../types';
import * as localize from '../utils/localize';
import { Jupyter } from '../utils/localize';
import { StopWatch } from '../utils/stopWatch';
import { Telemetry } from './constants';
import { StartPageMessageListener } from './startPageMessageListener';
Expand Down Expand Up @@ -62,6 +65,10 @@ export class StartPage extends WebviewPanelHost<IStartPageMapping>
@inject(IApplicationShell) private appShell: IApplicationShell,
@inject(IExtensionContext) private readonly context: IExtensionContext,
@inject(IApplicationEnvironment) private appEnvironment: IApplicationEnvironment,
@inject(IJupyterNotInstalledNotificationHelper)
private notificationHelper: IJupyterNotInstalledNotificationHelper,
@inject(IJupyterExtensionDependencyManager) private depsManager: IJupyterExtensionDependencyManager,
@inject(IOutputChannel) @named(STANDARD_OUTPUT_CHANNEL) private readonly output: IOutputChannel,
) {
super(
configuration,
Expand Down Expand Up @@ -128,6 +135,9 @@ export class StartPage extends WebviewPanelHost<IStartPageMapping>
}

public async onMessage(message: string, payload: unknown): Promise<void> {
const shouldShowJupyterNotInstalledPrompt = await this.notificationHelper.shouldShowJupypterExtensionNotInstalledPrompt();
const isJupyterInstalled = this.depsManager.isJupyterExtensionInstalled;

switch (message) {
case StartPageMessages.Started:
this.webviewDidLoad = true;
Expand All @@ -140,19 +150,29 @@ export class StartPage extends WebviewPanelHost<IStartPageMapping>
break;
}
case StartPageMessages.OpenBlankNotebook: {
sendTelemetryEvent(Telemetry.StartPageOpenBlankNotebook);
this.setTelemetryFlags();

const savedVersion: string | undefined = this.context.globalState.get(EXTENSION_VERSION_MEMENTO);

if (savedVersion) {
await this.commandManager.executeCommand(
'jupyter.opennotebook',
undefined,
CommandSource.commandPalette,
);
if (!isJupyterInstalled) {
this.output.appendLine(Jupyter.jupyterExtensionNotInstalled());

if (shouldShowJupyterNotInstalledPrompt) {
await this.notificationHelper.showJupyterNotInstalledPrompt(
JupyterNotInstalledOrigin.StartPageOpenBlankNotebook,
);
}
} else {
this.openSampleNotebook().ignoreErrors();
sendTelemetryEvent(Telemetry.StartPageOpenBlankNotebook);
this.setTelemetryFlags();

const savedVersion: string | undefined = this.context.globalState.get(EXTENSION_VERSION_MEMENTO);

if (savedVersion) {
await this.commandManager.executeCommand(
'jupyter.opennotebook',
undefined,
CommandSource.commandPalette,
);
} else {
this.openSampleNotebook().ignoreErrors();
}
}
break;
}
Expand All @@ -168,15 +188,25 @@ export class StartPage extends WebviewPanelHost<IStartPageMapping>
break;
}
case StartPageMessages.OpenInteractiveWindow: {
sendTelemetryEvent(Telemetry.StartPageOpenInteractiveWindow);
this.setTelemetryFlags();

const doc2 = await this.documentManager.openTextDocument({
language: 'python',
content: `#%%\nprint("${localize.StartPage.helloWorld()}")`,
});
await this.documentManager.showTextDocument(doc2, 1, true);
await this.commandManager.executeCommand('jupyter.runallcells', Uri.parse(''));
if (!isJupyterInstalled) {
this.output.appendLine(Jupyter.jupyterExtensionNotInstalled());

if (shouldShowJupyterNotInstalledPrompt) {
await this.notificationHelper.showJupyterNotInstalledPrompt(
JupyterNotInstalledOrigin.StartPageOpenInteractiveWindow,
);
}
} else {
sendTelemetryEvent(Telemetry.StartPageOpenInteractiveWindow);
this.setTelemetryFlags();

const doc2 = await this.documentManager.openTextDocument({
language: 'python',
content: `#%%\nprint("${localize.StartPage.helloWorld()}")`,
});
await this.documentManager.showTextDocument(doc2, 1, true);
await this.commandManager.executeCommand('jupyter.runallcells', doc2.uri);
}
break;
}
case StartPageMessages.OpenCommandPalette:
Expand All @@ -192,10 +222,20 @@ export class StartPage extends WebviewPanelHost<IStartPageMapping>
await this.commandManager.executeCommand('workbench.action.quickOpen', '>Create New Blank Notebook');
break;
case StartPageMessages.OpenSampleNotebook:
sendTelemetryEvent(Telemetry.StartPageOpenSampleNotebook);
this.setTelemetryFlags();
if (!isJupyterInstalled) {
this.output.appendLine(Jupyter.jupyterExtensionNotInstalled());

if (shouldShowJupyterNotInstalledPrompt) {
await this.notificationHelper.showJupyterNotInstalledPrompt(
JupyterNotInstalledOrigin.StartPageOpenSampleNotebook,
);
}
} else {
sendTelemetryEvent(Telemetry.StartPageOpenSampleNotebook);
this.setTelemetryFlags();

this.openSampleNotebook().ignoreErrors();
this.openSampleNotebook().ignoreErrors();
}
break;
case StartPageMessages.OpenFileBrowser: {
sendTelemetryEvent(Telemetry.StartPageOpenFileBrowser);
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ export namespace StartPage {
);
export const interactiveWindowDesc = localize(
'StartPage.interactiveWindowDesc',
'- You can create cells on a Python file by typing "#%%" <br /> - Use "<div class="italics">Shift + Enter</div> " to run a cell, the output will be shown in the interactive window',
'- You can create cells on a Python file by typing "#%%". Make sure you have the Jupyter extension installed. <br /> - Use "<div class="italics">Shift + Enter</div> " to run a cell, the output will be shown in the interactive window',
);

export const releaseNotes = localize(
Expand Down
8 changes: 3 additions & 5 deletions src/client/jupyter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,10 @@ enum ColumnType {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type IRowsResponse = any[];

// Note: While #16102 is being worked on, this enum will be updated as we add ways to display this notification.
export enum JupyterNotInstalledOrigin {
StartPageCreateBlankNotebook = 'startpage_create_blank_notebook',
StartPageCreateJupyterNotebook = 'startpage_create_jupyter_notebook',
StartPageCreateSampleNotebook = 'startpage_sample_notebook',
StartPageUseInteractiveWindow = 'startpage_use_interactive_window',
StartPageOpenBlankNotebook = 'startpage_open_blank_notebook',
StartPageOpenSampleNotebook = 'startpage_open_sample_notebook',
StartPageOpenInteractiveWindow = 'startpage_open_interactive_window',
}

export const IJupyterNotInstalledNotificationHelper = Symbol('IJupyterNotInstalledNotificationHelper');
Expand Down
2 changes: 1 addition & 1 deletion src/startPage-ui/startPage/startPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export class StartPage extends React.Component<IStartPageProps> implements IMess
dangerouslySetInnerHTML={{
__html: getLocString(
'StartPage.interactiveWindowDesc',
'- You can create cells on a Python file by typing "#%%" <br /> - Use "<div class="italics">Shift + Enter</div> " to run a cell, the output will be shown in the interactive window',
'- You can create cells on a Python file by typing "#%%". Make sure you have the Jupyter extension installed. <br /> - Use "<div class="italics">Shift + Enter</div> " to run a cell, the output will be shown in the interactive window',
),
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ suite('Jupyter not installed notification helper', () => {
({ createGlobalPersistentState: createGlobalPersistentStateStub } as unknown) as IPersistentStateFactory,
{} as IJupyterExtensionDependencyManager,
);
await notificationHelper.showJupyterNotInstalledPrompt(JupyterNotInstalledOrigin.StartPageCreateBlankNotebook);
await notificationHelper.showJupyterNotInstalledPrompt(JupyterNotInstalledOrigin.StartPageOpenBlankNotebook);

sinon.assert.calledOnce(createGlobalPersistentStateStub);
sinon.assert.calledOnce(showInformationMessageStub);
Expand Down Expand Up @@ -142,7 +142,7 @@ suite('Jupyter not installed notification helper', () => {
({ createGlobalPersistentState: createGlobalPersistentStateStub } as unknown) as IPersistentStateFactory,
{} as IJupyterExtensionDependencyManager,
);
await notificationHelper.showJupyterNotInstalledPrompt(JupyterNotInstalledOrigin.StartPageCreateBlankNotebook);
await notificationHelper.showJupyterNotInstalledPrompt(JupyterNotInstalledOrigin.StartPageOpenBlankNotebook);

const result = notificationHelper.shouldShowJupypterExtensionNotInstalledPrompt();

Expand Down
Loading