diff --git a/extensions/notebook/package.json b/extensions/notebook/package.json index 00a5d60263..e36d97759a 100644 --- a/extensions/notebook/package.json +++ b/extensions/notebook/package.json @@ -30,6 +30,10 @@ } }, "commands": [ + { + "command": "notebook.command.analyzeNotebook", + "title": "%notebook.analyzeJupyterNotebook%" + }, { "command": "notebook.command.new", "title": "%notebook.command.new%", @@ -61,6 +65,9 @@ ], "menus": { "commandPalette": [ + { + "command": "notebook.command.analyzeNotebook" + }, { "command": "notebook.command.new" }, @@ -86,6 +93,13 @@ "when": "connectionProvider == MSSQL && nodeType && nodeType == Server", "group": "1root@1" } + ], + "objectExplorer/item/context": [ + { + "command": "notebook.command.analyzeNotebook", + "when": "nodeType=~/^mssqlCluster/ && nodeLabel=~/[^\\s]+(\\.(csv|tsv|txt))$/ && nodeType == mssqlCluster:file", + "group": "1notebook@1" + } ] }, "keybindings": [ diff --git a/extensions/notebook/package.nls.json b/extensions/notebook/package.nls.json index e087fea50c..98351cfd86 100644 --- a/extensions/notebook/package.nls.json +++ b/extensions/notebook/package.nls.json @@ -6,6 +6,7 @@ "notebook.sqlKernelEnabled.description": "Enable SQL kernel in notebook editor (Preview). Requires reloading this window to take effect", "notebook.command.new": "New Notebook", "notebook.command.open": "Open Notebook", + "notebook.analyzeJupyterNotebook": "Analyze in Notebook", "notebook.command.runactivecell": "Run Cell", "notebook.command.addcode": "Add Code Cell", "notebook.command.addtext": "Add Text Cell" diff --git a/extensions/notebook/src/extension.ts b/extensions/notebook/src/extension.ts index 2df8d3d960..bd63ab1ce3 100644 --- a/extensions/notebook/src/extension.ts +++ b/extensions/notebook/src/extension.ts @@ -7,13 +7,18 @@ import * as vscode from 'vscode'; import * as sqlops from 'sqlops'; +import * as os from 'os'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -let counter = 0; +const JUPYTER_NOTEBOOK_PROVIDER = 'jupyter'; +const msgSampleCodeDataFrame = localize('msgSampleCodeDataFrame', 'This sample code loads the file into a data frame and shows the first 10 results.'); const noNotebookVisible = localize('noNotebookVisible', 'No notebook editor is active'); + +let counter = 0; + export function activate(extensionContext: vscode.ExtensionContext) { - extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.new', ( connectionId? : string) => { + extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.new', (connectionId?: string) => { newNotebook(connectionId); })); extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.open', () => { @@ -28,6 +33,9 @@ export function activate(extensionContext: vscode.ExtensionContext) { extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.addtext', () => { addCell('markdown'); })); + extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.analyzeNotebook', (explorerContext: sqlops.ObjectExplorerContext) => { + analyzeNotebook(explorerContext); + })); } @@ -43,6 +51,7 @@ function newNotebook(connectionId: string) { defaultKernel: null } : null; sqlops.nb.showNotebookDocument(untitledUri, options).then(success => { + }, (err: Error) => { vscode.window.showErrorMessage(err.message); }); @@ -97,6 +106,33 @@ async function addCell(cellType: sqlops.nb.CellType): Promise { } } +async function analyzeNotebook(oeContext?: sqlops.ObjectExplorerContext): Promise { + // Ensure we get a unique ID for the notebook. For now we're using a different prefix to the built-in untitled files + // to handle this. We should look into improving this in the future + let untitledUri = vscode.Uri.parse(`untitled:Notebook-${counter++}`); + + let editor = await sqlops.nb.showNotebookDocument(untitledUri, { + connectionId: oeContext ? oeContext.connectionProfile.id : '', + providerId: JUPYTER_NOTEBOOK_PROVIDER + }); + if (oeContext && oeContext.nodeInfo && oeContext.nodeInfo.nodePath) { + // Get the file path after '/HDFS' + let hdfsPath: string = oeContext.nodeInfo.nodePath.substring(oeContext.nodeInfo.nodePath.indexOf('/HDFS') + '/HDFS'.length); + if (hdfsPath.length > 0) { + let analyzeCommand = "#" + msgSampleCodeDataFrame + os.EOL + "df = (spark.read.option(\"inferSchema\", \"true\")" + + os.EOL + ".option(\"header\", \"true\")" + os.EOL + ".csv('{0}'))" + os.EOL + "df.show(10)"; + + editor.edit(editBuilder => { + editBuilder.replace(0, { + cell_type: 'code', + source: analyzeCommand.replace('{0}', hdfsPath) + }); + }); + + } + } +} + // this method is called when your extension is deactivated export function deactivate() { }