From 14a6bf581c1e7c76c88777d7805b09495d29a2fb Mon Sep 17 00:00:00 2001 From: Kevin Cunnane Date: Mon, 10 Jun 2019 16:38:07 -0700 Subject: [PATCH] Fix New Notebook issues (#5958) * Fix New Notebook issues - Fix #5338 New Notebook menu item should be next to New Query - Fix #4936 Add a shortcut to create a notebook in the document well Created a built-in New Notebook command that routes to the existing extension-based command. This avoided a rearchitecture that was more complex that seemed worth it. Per VSCode patterns, used a _ modifier for the existing command so it's "private" --- extensions/notebook/package.json | 14 +++-------- extensions/notebook/src/extension.ts | 2 +- .../media/dark/new_notebook_inverse.svg | 1 + .../notebook/media/light/new_notebook.svg | 1 + .../parts/notebook/notebook.contribution.ts | 19 +++++++++++++++ src/sql/workbench/parts/notebook/notebook.css | 11 ++++++++- .../parts/notebook/notebookActions.ts | 23 +++++++++++++++++++ .../browser/serverTreeActionProvider.ts | 8 ++++--- .../contrib/watermark/browser/watermark.ts | 11 +++++++-- 9 files changed, 72 insertions(+), 18 deletions(-) create mode 100755 src/sql/workbench/parts/notebook/media/dark/new_notebook_inverse.svg create mode 100755 src/sql/workbench/parts/notebook/media/light/new_notebook.svg diff --git a/extensions/notebook/package.json b/extensions/notebook/package.json index eab99a14ff..e6ef3883e3 100644 --- a/extensions/notebook/package.json +++ b/extensions/notebook/package.json @@ -45,7 +45,7 @@ "title": "%notebook.analyzeJupyterNotebook%" }, { - "command": "notebook.command.new", + "command": "_notebook.command.new", "title": "%notebook.command.new%", "icon": { "dark": "resources/dark/new_notebook_inverse.svg", @@ -145,7 +145,8 @@ "when": "false" }, { - "command": "notebook.command.new" + "command": "_notebook.command.new", + "when": "false" }, { "command": "notebook.command.open" @@ -204,11 +205,6 @@ } ], "objectExplorer/item/context": [ - { - "command": "notebook.command.new", - "when": "isQueryProvider && nodeType == Server", - "group": "1root@1" - }, { "command": "notebook.command.analyzeNotebook", "when": "nodeType=~/^mssqlCluster/ && nodeLabel=~/[^\\s]+(\\.(csv|tsv|txt))$/ && nodeType == mssqlCluster:file", @@ -233,10 +229,6 @@ ] }, "keybindings": [ - { - "command": "notebook.command.new", - "key": "Ctrl+Shift+N" - }, { "command": "notebook.command.runactivecell", "key": "F5", diff --git a/extensions/notebook/src/extension.ts b/extensions/notebook/src/extension.ts index 9d51a1a0e5..d423dee50b 100644 --- a/extensions/notebook/src/extension.ts +++ b/extensions/notebook/src/extension.ts @@ -25,7 +25,7 @@ let controller: JupyterController; type ChooseCellType = { label: string, id: CellType }; export async function activate(extensionContext: vscode.ExtensionContext): Promise { - extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.new', (context?: azdata.ConnectedContext) => { + extensionContext.subscriptions.push(vscode.commands.registerCommand('_notebook.command.new', (context?: azdata.ConnectedContext) => { let connectionProfile: azdata.IConnectionProfile = undefined; if (context && context.connectionProfile) { connectionProfile = context.connectionProfile; diff --git a/src/sql/workbench/parts/notebook/media/dark/new_notebook_inverse.svg b/src/sql/workbench/parts/notebook/media/dark/new_notebook_inverse.svg new file mode 100755 index 0000000000..e0072afee1 --- /dev/null +++ b/src/sql/workbench/parts/notebook/media/dark/new_notebook_inverse.svg @@ -0,0 +1 @@ +new_notebook_inverse \ No newline at end of file diff --git a/src/sql/workbench/parts/notebook/media/light/new_notebook.svg b/src/sql/workbench/parts/notebook/media/light/new_notebook.svg new file mode 100755 index 0000000000..9618487568 --- /dev/null +++ b/src/sql/workbench/parts/notebook/media/light/new_notebook.svg @@ -0,0 +1 @@ +new_notebook \ No newline at end of file diff --git a/src/sql/workbench/parts/notebook/notebook.contribution.ts b/src/sql/workbench/parts/notebook/notebook.contribution.ts index 3f8e5f8990..076857504e 100644 --- a/src/sql/workbench/parts/notebook/notebook.contribution.ts +++ b/src/sql/workbench/parts/notebook/notebook.contribution.ts @@ -5,9 +5,14 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { NotebookInput } from 'sql/workbench/parts/notebook/notebookInput'; import { NotebookEditor } from 'sql/workbench/parts/notebook/notebookEditor'; +import { NewNotebookAction } from 'sql/workbench/parts/notebook/notebookActions'; +import { KeyMod } from 'vs/editor/common/standalone/standaloneBase'; +import { KeyCode } from 'vs/base/common/keyCodes'; // Model View editor registration const viewModelEditorDescriptor = new EditorDescriptor( @@ -18,3 +23,17 @@ const viewModelEditorDescriptor = new EditorDescriptor( Registry.as(EditorExtensions.Editors) .registerEditor(viewModelEditorDescriptor, [new SyncDescriptor(NotebookInput)]); + +// Global Actions +let actionRegistry = Registry.as(Extensions.WorkbenchActions); + +actionRegistry.registerWorkbenchAction( + new SyncActionDescriptor( + NewNotebookAction, + NewNotebookAction.ID, + NewNotebookAction.LABEL, + { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_N }, + + ), + NewNotebookAction.LABEL +); \ No newline at end of file diff --git a/src/sql/workbench/parts/notebook/notebook.css b/src/sql/workbench/parts/notebook/notebook.css index 5debe9b14b..7649c8bea1 100644 --- a/src/sql/workbench/parts/notebook/notebook.css +++ b/src/sql/workbench/parts/notebook/notebook.css @@ -115,4 +115,13 @@ .notebookEditor .notebook-cellTable .slick-viewport { min-height: 39px; -} \ No newline at end of file +} + +.monaco-workbench .notebook-action.new-notebook { + background: url('./media/light/new_notebook.svg') center center no-repeat; +} + +.vs-dark .monaco-workbench .notebook-action.new-notebook, +.hc-black .monaco-workbench .notebook-action.new-notebook { + background: url('./media/dark/new_notebook_inverse.svg') center center no-repeat; +} diff --git a/src/sql/workbench/parts/notebook/notebookActions.ts b/src/sql/workbench/parts/notebook/notebookActions.ts index a4e55a61dd..21669ab508 100644 --- a/src/sql/workbench/parts/notebook/notebookActions.ts +++ b/src/sql/workbench/parts/notebook/notebookActions.ts @@ -24,6 +24,7 @@ import { NotebookModel } from 'sql/workbench/parts/notebook/models/notebookModel import { generateUri } from 'sql/platform/connection/common/utils'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ILogService } from 'vs/platform/log/common/log'; +import { ICommandService } from 'vs/platform/commands/common/commands'; const msgLoading = localize('loading', "Loading kernels..."); const msgChanging = localize('changing', "Changing kernel..."); @@ -539,3 +540,25 @@ export class AttachToDropdown extends SelectBox { } } } + +export class NewNotebookAction extends Action { + + public static readonly ID = 'notebook.command.new'; + public static readonly LABEL = localize('newNotebookAction', "New Notebook"); + + private static readonly INTERNAL_NEW_NOTEBOOK_CMD_ID = '_notebook.command.new'; + constructor( + id: string, + label: string, + @ICommandService private commandService: ICommandService + ) { + super(id, label); + this.class = 'notebook-action new-notebook'; + } + + run(context?: azdata.ConnectedContext): Promise { + return this.commandService.executeCommand(NewNotebookAction.INTERNAL_NEW_NOTEBOOK_CMD_ID, context); + + } + +} \ No newline at end of file diff --git a/src/sql/workbench/parts/objectExplorer/browser/serverTreeActionProvider.ts b/src/sql/workbench/parts/objectExplorer/browser/serverTreeActionProvider.ts index c52d8e36f1..d3e365078d 100644 --- a/src/sql/workbench/parts/objectExplorer/browser/serverTreeActionProvider.ts +++ b/src/sql/workbench/parts/objectExplorer/browser/serverTreeActionProvider.ts @@ -31,6 +31,7 @@ import { IQueryManagementService } from 'sql/platform/query/common/queryManageme import { IScriptingService } from 'sql/platform/scripting/common/scriptingService'; import { ServerInfoContextKey } from 'sql/workbench/parts/connection/common/serverInfoContextKey'; import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { NewNotebookAction } from 'sql/workbench/parts/notebook/notebookActions'; /** * Provides actions for the server tree elements @@ -111,7 +112,7 @@ export class ServerTreeActionProvider extends ContributableActionProvider { private getBuiltinConnectionActions(context: ObjectExplorerContext): IAction[] { let actions: IAction[] = []; actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL, context.tree)); - this.addNewQueryAction(context, actions); + this.addNewQueryNotebookActions(context, actions); if (this._connectionManagementService.isProfileConnected(context.profile)) { actions.push(this._instantiationService.createInstance(DisconnectConnectionAction, DisconnectConnectionAction.ID, DisconnectConnectionAction.LABEL, context.profile)); @@ -165,7 +166,7 @@ export class ServerTreeActionProvider extends ContributableActionProvider { if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) { isAvailableDatabaseNode = true; actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL, context.tree)); - this.addNewQueryAction(context, actions); + this.addNewQueryNotebookActions(context, actions); } else { return actions; } @@ -186,9 +187,10 @@ export class ServerTreeActionProvider extends ContributableActionProvider { return actions; } - private addNewQueryAction(context: ObjectExplorerContext, actions: IAction[]): void { + private addNewQueryNotebookActions(context: ObjectExplorerContext, actions: IAction[]): void { if (this._queryManagementService.isProviderRegistered(context.profile.providerName)) { actions.push(this._instantiationService.createInstance(OEAction, NewQueryAction.ID, NewQueryAction.LABEL)); + actions.push(this._instantiationService.createInstance(OEAction, NewNotebookAction.ID, NewNotebookAction.LABEL)); } } diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index 6d3b96c616..4f436e03c2 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -31,6 +31,7 @@ import { IDimension } from 'vs/platform/layout/browser/layoutService'; // {{SQL CARBON EDIT}} import { OpenDataExplorerViewletAction } from 'sql/workbench/parts/dataExplorer/browser/dataExplorer.contribution'; +import { NewNotebookAction } from 'sql/workbench/parts/notebook/notebookActions'; const $ = dom.$; @@ -42,14 +43,18 @@ interface WatermarkEntry { // {{SQL CARBON EDIT}} const showServers: WatermarkEntry = { - text: nls.localize('watermark.showServers', 'Show Servers'), + text: nls.localize('watermark.showServers', "Show Servers"), id: OpenDataExplorerViewletAction.ID }; const newSqlFile: WatermarkEntry = { - text: nls.localize('watermark.newSqlFile', 'New SQL File'), + text: nls.localize('watermark.newSqlFile', "New SQL File"), id: GlobalNewUntitledFileAction.ID }; +const newNotebook: WatermarkEntry = { + text: nls.localize('watermark.newNotebook', "New Notebook"), + id: NewNotebookAction.ID +}; const showCommands: WatermarkEntry = { text: nls.localize('watermark.showCommands', "Show All Commands"), @@ -101,12 +106,14 @@ const startDebugging: WatermarkEntry = { const noFolderEntries = [ showServers, newSqlFile, + newNotebook, findInFiles ]; const folderEntries = [ showServers, newSqlFile, + newNotebook, findInFiles ]; // {{SQL CARBON EDIT}} - End