|
|
|
|
@@ -18,12 +18,6 @@ import { IAction, Action, IActionItem } from 'vs/base/common/actions';
|
|
|
|
|
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
|
|
|
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|
|
|
|
import { fillInActions, LabeledMenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem';
|
|
|
|
|
import { Schemas } from 'vs/base/common/network';
|
|
|
|
|
import { URI } from 'vs/base/common/uri';
|
|
|
|
|
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
|
|
|
|
import * as paths from 'vs/base/common/paths';
|
|
|
|
|
import { IWindowService } from 'vs/platform/windows/common/windows';
|
|
|
|
|
import { TPromise } from 'vs/base/common/winjs.base';
|
|
|
|
|
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
|
|
|
|
import { VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/parts/extensions/common/extensions';
|
|
|
|
|
|
|
|
|
|
@@ -32,7 +26,7 @@ import { AngularDisposable } from 'sql/base/node/lifecycle';
|
|
|
|
|
import { CellTypes, CellType } from 'sql/parts/notebook/models/contracts';
|
|
|
|
|
import { ICellModel, IModelFactory, INotebookModel, NotebookContentChange, notebookConstants } from 'sql/parts/notebook/models/modelInterfaces';
|
|
|
|
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
|
|
|
|
import { INotebookService, INotebookParams, INotebookManager, INotebookEditor, DEFAULT_NOTEBOOK_FILETYPE, DEFAULT_NOTEBOOK_PROVIDER, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/common/notebookService';
|
|
|
|
|
import { INotebookService, INotebookParams, INotebookManager, INotebookEditor, DEFAULT_NOTEBOOK_PROVIDER, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/common/notebookService';
|
|
|
|
|
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
|
|
|
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
|
|
|
|
import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
|
|
|
|
|
@@ -40,11 +34,10 @@ import * as notebookUtils from 'sql/parts/notebook/notebookUtils';
|
|
|
|
|
import { Deferred } from 'sql/base/common/promise';
|
|
|
|
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|
|
|
|
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
|
|
|
|
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction, SaveNotebookAction } from 'sql/parts/notebook/notebookActions';
|
|
|
|
|
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction } from 'sql/parts/notebook/notebookActions';
|
|
|
|
|
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService';
|
|
|
|
|
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
|
|
|
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
|
|
|
|
import { IResourceInput } from 'vs/platform/editor/common/editor';
|
|
|
|
|
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
|
|
|
|
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
|
|
|
|
import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService';
|
|
|
|
|
@@ -90,11 +83,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|
|
|
|
@Inject(IContextKeyService) private contextKeyService: IContextKeyService,
|
|
|
|
|
@Inject(IMenuService) private menuService: IMenuService,
|
|
|
|
|
@Inject(IKeybindingService) private keybindingService: IKeybindingService,
|
|
|
|
|
@Inject(IHistoryService) private historyService: IHistoryService,
|
|
|
|
|
@Inject(IWindowService) private windowService: IWindowService,
|
|
|
|
|
@Inject(IViewletService) private viewletService: IViewletService,
|
|
|
|
|
@Inject(IUntitledEditorService) private untitledEditorService: IUntitledEditorService,
|
|
|
|
|
@Inject(IEditorGroupsService) private editorGroupService: IEditorGroupsService,
|
|
|
|
|
@Inject(ICapabilitiesService) private capabilitiesService: ICapabilitiesService
|
|
|
|
|
) {
|
|
|
|
|
super();
|
|
|
|
|
@@ -316,6 +305,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|
|
|
|
}
|
|
|
|
|
return this._notebookParams.modelFactory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private handleModelError(notification: INotification): void {
|
|
|
|
|
this.notificationService.notify(notification);
|
|
|
|
|
}
|
|
|
|
|
@@ -367,8 +357,6 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|
|
|
|
this._trustedAction = this.instantiationService.createInstance(TrustedAction, 'notebook.Trusted');
|
|
|
|
|
this._trustedAction.enabled = false;
|
|
|
|
|
|
|
|
|
|
let saveNotebookButton = this.instantiationService.createInstance(SaveNotebookAction, 'notebook.SaveNotebook', localize('save', 'Save'), 'notebook-button icon-save');
|
|
|
|
|
|
|
|
|
|
let taskbar = <HTMLElement>this.toolbar.nativeElement;
|
|
|
|
|
this._actionBar = new Taskbar(taskbar, this.contextMenuService, { actionItemProvider: action => this.actionItemProvider(action as Action) });
|
|
|
|
|
this._actionBar.context = this;
|
|
|
|
|
@@ -377,101 +365,11 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|
|
|
|
{ element: attachToContainer },
|
|
|
|
|
{ action: addCodeCellButton },
|
|
|
|
|
{ action: addTextCellButton },
|
|
|
|
|
{ action: saveNotebookButton },
|
|
|
|
|
{ action: this._trustedAction }
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gets file path from recent workspace in local
|
|
|
|
|
private getLastActiveFilePath(untitledResource: URI): string {
|
|
|
|
|
let fileName = untitledResource.path + '.' + DEFAULT_NOTEBOOK_FILETYPE.toLocaleLowerCase();
|
|
|
|
|
|
|
|
|
|
let lastActiveFile = this.historyService.getLastActiveFile(Schemas.file);
|
|
|
|
|
if (lastActiveFile) {
|
|
|
|
|
return URI.file(paths.join(paths.dirname(lastActiveFile.fsPath), fileName)).fsPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let lastActiveFolder = this.historyService.getLastActiveWorkspaceRoot('file');
|
|
|
|
|
if (lastActiveFolder) {
|
|
|
|
|
return URI.file(paths.join(lastActiveFolder.fsPath, fileName)).fsPath;
|
|
|
|
|
}
|
|
|
|
|
return fileName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
promptForPath(defaultPath: string): TPromise<string> {
|
|
|
|
|
return this.windowService.showSaveDialog({
|
|
|
|
|
defaultPath: defaultPath,
|
|
|
|
|
filters: [{ name: localize('notebookFile', 'Notebook'), extensions: ['ipynb'] }]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Entry point to save notebook
|
|
|
|
|
public async save(): Promise<boolean> {
|
|
|
|
|
let self = this;
|
|
|
|
|
let notebookUri = this.notebookParams.notebookUri;
|
|
|
|
|
if (notebookUri.scheme === Schemas.untitled) {
|
|
|
|
|
let dialogPath = this.getLastActiveFilePath(notebookUri);
|
|
|
|
|
return this.promptForPath(dialogPath).then(path => {
|
|
|
|
|
if (path) {
|
|
|
|
|
let target = URI.file(path);
|
|
|
|
|
let resource = self._model.notebookUri;
|
|
|
|
|
self._model.notebookUri = target;
|
|
|
|
|
this.saveNotebook().then(result => {
|
|
|
|
|
if (result) {
|
|
|
|
|
return this.replaceUntitledNotebookEditor(resource, target);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return false; // User clicks cancel
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return await this.saveNotebook();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Replaces untitled notebook editor with the saved file name
|
|
|
|
|
private async replaceUntitledNotebookEditor(resource: URI, target: URI): Promise<boolean> {
|
|
|
|
|
let encodingOfSource = this.untitledEditorService.getEncoding(resource);
|
|
|
|
|
const replacement: IResourceInput = {
|
|
|
|
|
resource: target,
|
|
|
|
|
encoding: encodingOfSource,
|
|
|
|
|
options: {
|
|
|
|
|
pinned: true
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return TPromise.join(this.editorGroupService.groups.map(g =>
|
|
|
|
|
this.editorService.replaceEditors([{
|
|
|
|
|
editor: { resource },
|
|
|
|
|
replacement
|
|
|
|
|
}], g))).then(() => {
|
|
|
|
|
this.notebookService.renameNotebookEditor(resource, target, this);
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async saveNotebook(): Promise<boolean> {
|
|
|
|
|
try {
|
|
|
|
|
let saved = await this._model.saveModel();
|
|
|
|
|
if (saved) {
|
|
|
|
|
this.setDirty(false);
|
|
|
|
|
}
|
|
|
|
|
return saved;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
this.notificationService.error(localize('saveFailed', 'Failed to save notebook: {0}', notebookUtils.getErrorMessage(err)));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private setDirty(isDirty: boolean): void {
|
|
|
|
|
if (this._notebookParams.input) {
|
|
|
|
|
this._notebookParams.input.setDirty(isDirty);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private actionItemProvider(action: Action): IActionItem {
|
|
|
|
|
// Check extensions to create ActionItem; otherwise, return undefined
|
|
|
|
|
// This is similar behavior that exists in MenuItemActionItem
|
|
|
|
|
|