+
diff --git a/src/sql/parts/notebook/notebook.component.ts b/src/sql/parts/notebook/notebook.component.ts
index 2b529cd88d..8df7bcabb7 100644
--- a/src/sql/parts/notebook/notebook.component.ts
+++ b/src/sql/parts/notebook/notebook.component.ts
@@ -12,36 +12,25 @@ import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, V
import URI from 'vs/base/common/uri';
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import * as themeColors from 'vs/workbench/common/theme';
-import { INotificationService } from 'vs/platform/notification/common/notification';
+import { INotificationService, INotification } from 'vs/platform/notification/common/notification';
+import { localize } from 'vs/nls';
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
import { AngularDisposable } from 'sql/base/common/lifecycle';
-import { CellTypes, CellType } from 'sql/parts/notebook/models/contracts';
-import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
+import { CellTypes, CellType, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
+import { ICellModel, INotebookModel, IModelFactory, INotebookModelOptions } from 'sql/parts/notebook/models/modelInterfaces';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
-import { INotebookService, INotebookParams } from 'sql/services/notebook/notebookService';
+import { INotebookService, INotebookParams, INotebookManager } from 'sql/services/notebook/notebookService';
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
+import { NotebookModel, ErrorInfo, MessageLevel, NotebookContentChange } from 'sql/parts/notebook/models/notebookModel';
+import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
+import * as notebookUtils from './notebookUtils';
+import { Deferred } from 'sql/base/common/promise';
+import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
-class CellModelStub implements ICellModel {
- public cellUri: URI;
- constructor(public id: string,
- public language: string,
- public source: string,
- public cellType: CellType,
- public trustedMode: boolean = false,
- public active: boolean = false
- ) { }
-
- equals(cellModel: ICellModel): boolean {
- throw new Error('Method not implemented.');
- }
- toJSON(): nb.ICell {
- throw new Error('Method not implemented.');
- }
-}
@Component({
selector: NOTEBOOK_SELECTOR,
@@ -49,8 +38,16 @@ class CellModelStub implements ICellModel {
})
export class NotebookComponent extends AngularDisposable implements OnInit {
@ViewChild('toolbar', { read: ElementRef }) private toolbar: ElementRef;
- protected cells: Array = [];
+ private _model: NotebookModel;
+ private _isInErrorState: boolean = false;
+ private _errorMessage: string;
private _activeCell: ICellModel;
+ protected isLoading: boolean;
+ private notebookManager: INotebookManager;
+ private _modelReadyDeferred = new Deferred();
+ private profile: IConnectionProfile;
+
+
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
@@ -61,17 +58,18 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
@Inject(IBootstrapParams) private notebookParams: INotebookParams
) {
super();
-
- // TODO NOTEBOOK REFACTOR: This is mock data for cells. Will remove this code when we have a service
- let cell1 : ICellModel = new CellModelStub ('1', 'sql', 'select * from sys.tables', CellTypes.Code);
- let cell2 : ICellModel = new CellModelStub ('2', 'sql', 'select 1', CellTypes.Code);
- let cell3 : ICellModel = new CellModelStub ('3', 'markdown', '## This is test!', CellTypes.Markdown);
- this.cells.push(cell1, cell2, cell3);
+ this.profile = this.notebookParams!.profile;
+ this.isLoading = true;
}
ngOnInit() {
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
this.updateTheme(this.themeService.getColorTheme());
+ this.doLoad();
+ }
+
+ protected get cells(): ReadonlyArray {
+ return this._model ? this._model.cells : [];
}
private updateTheme(theme: IColorTheme): void {
@@ -110,7 +108,84 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
}
}
- findCellIndex(cellModel: ICellModel): number {
- return this.cells.findIndex((cell) => cell.id === cellModel.id);
+ private async doLoad(): Promise {
+ try {
+ await this.loadModel();
+ this.setLoading(false);
+ this._modelReadyDeferred.resolve(this._model);
+ } catch (error) {
+ this.setViewInErrorState(localize('displayFailed', 'Could not display contents: {0}', error));
+ this.setLoading(false);
+ this._modelReadyDeferred.reject(error);
+ }
}
+
+ private setLoading(isLoading: boolean): void {
+ this.isLoading = isLoading;
+ this._changeRef.detectChanges();
+ }
+
+ private async loadModel(): Promise {
+ this.notebookManager = await this.notebookService.getOrCreateNotebookManager(this.notebookParams.providerId, this.notebookParams.notebookUri);
+ let model = new NotebookModel({
+ factory: this.modelFactory,
+ path: this.notebookParams.notebookUri.fsPath,
+ connectionService: this.connectionManagementService,
+ notificationService: this.notificationService,
+ notebookManager: this.notebookManager
+ }, false, this.profile);
+ model.onError((errInfo: INotification) => this.handleModelError(errInfo));
+ model.backgroundStartSession();
+ await model.requestModelLoad(this.notebookParams.isTrusted);
+ model.contentChanged((change) => this.handleContentChanged(change));
+ this._model = model;
+ this._register(model);
+ this._changeRef.detectChanges();
+ }
+
+ private get modelFactory(): IModelFactory {
+ if (!this.notebookParams.modelFactory) {
+ this.notebookParams.modelFactory = new ModelFactory();
+ }
+ return this.notebookParams.modelFactory;
+ }
+ private handleModelError(notification: INotification): void {
+ this.notificationService.notify(notification);
+ }
+
+ private handleContentChanged(change: NotebookContentChange) {
+ // Note: for now we just need to set dirty state and refresh the UI.
+ this.setDirty(true);
+ this._changeRef.detectChanges();
+ }
+
+ findCellIndex(cellModel: ICellModel): number {
+ return this._model.cells.findIndex((cell) => cell.id === cellModel.id);
+ }
+
+ private setViewInErrorState(error: any): any {
+ this._isInErrorState = true;
+ this._errorMessage = notebookUtils.getErrorMessage(error);
+ // For now, send message as error notification #870 covers having dedicated area for this
+ this.notificationService.error(error);
+ }
+
+ public async save(): Promise {
+ try {
+ let saved = await this._model.saveModel();
+ return saved;
+ } catch (err) {
+ this.notificationService.error(localize('saveFailed', 'Failed to save notebook: {0}', notebookUtils.getErrorMessage(err)));
+ return false;
+ }
+ }
+
+ private setDirty(isDirty: boolean): void {
+ // TODO reenable handling of isDirty
+ // if (this.editor) {
+ // this.editor.isDirty = isDirty;
+ // }
+ }
+
+
}
diff --git a/src/sql/parts/notebook/notebook.contribution.ts b/src/sql/parts/notebook/notebook.contribution.ts
index 86fa63417e..bcb6df8259 100644
--- a/src/sql/parts/notebook/notebook.contribution.ts
+++ b/src/sql/parts/notebook/notebook.contribution.ts
@@ -40,8 +40,8 @@ export class OpenNotebookAction extends Action {
public run(): TPromise {
return new TPromise((resolve, reject) => {
let untitledUri = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter++}`});
- let model = new NotebookInputModel(untitledUri, undefined, undefined);
- let input = new NotebookInput('modelViewId', model);
+ let model = new NotebookInputModel(untitledUri, undefined, false, undefined);
+ let input = new NotebookInput('modelViewId', model,);
this._editorService.openEditor(input, { pinned: true });
});
}
diff --git a/src/sql/parts/notebook/notebook.module.ts b/src/sql/parts/notebook/notebook.module.ts
index 0bc516dcb5..2c5964b99d 100644
--- a/src/sql/parts/notebook/notebook.module.ts
+++ b/src/sql/parts/notebook/notebook.module.ts
@@ -26,6 +26,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { CodeComponent } from 'sql/parts/notebook/cellViews/code.component';
import { CodeCellComponent } from 'sql/parts/notebook/cellViews/codeCell.component';
import { TextCellComponent } from 'sql/parts/notebook/cellViews/textCell.component';
+import LoadingSpinner from 'sql/parts/modelComponents/loadingSpinner.component';
export const NotebookModule = (params, selector: string, instantiationService: IInstantiationService): any => {
@NgModule({
@@ -34,6 +35,7 @@ export const NotebookModule = (params, selector: string, instantiationService: I
SelectBox,
EditableDropDown,
InputBox,
+ LoadingSpinner,
CodeComponent,
CodeCellComponent,
TextCellComponent,
diff --git a/src/sql/parts/notebook/notebookEditor.ts b/src/sql/parts/notebook/notebookEditor.ts
index 660362d310..3df4253354 100644
--- a/src/sql/parts/notebook/notebookEditor.ts
+++ b/src/sql/parts/notebook/notebookEditor.ts
@@ -86,7 +86,8 @@ export class NotebookEditor extends BaseEditor {
input.hasBootstrapped = true;
let params: INotebookParams = {
notebookUri: input.notebookUri,
- providerId: input.providerId ? input.providerId : DEFAULT_NOTEBOOK_PROVIDER
+ providerId: input.providerId ? input.providerId : DEFAULT_NOTEBOOK_PROVIDER,
+ isTrusted: input.isTrusted
};
bootstrapAngular(this.instantiationService,
NotebookModule,
diff --git a/src/sql/parts/notebook/notebookInput.ts b/src/sql/parts/notebook/notebookInput.ts
index 788bd73eff..117c54d244 100644
--- a/src/sql/parts/notebook/notebookInput.ts
+++ b/src/sql/parts/notebook/notebookInput.ts
@@ -17,7 +17,7 @@ export class NotebookInputModel extends EditorModel {
private dirty: boolean;
private readonly _onDidChangeDirty: Emitter = this._register(new Emitter());
private _providerId: string;
- constructor(public readonly notebookUri: URI, private readonly handle: number, private saveHandler?: ModeViewSaveHandler) {
+ constructor(public readonly notebookUri: URI, private readonly handle: number, private _isTrusted: boolean = false, private saveHandler?: ModeViewSaveHandler) {
super();
this.dirty = false;
}
@@ -30,6 +30,10 @@ export class NotebookInputModel extends EditorModel {
this._providerId = value;
}
+ get isTrusted(): boolean {
+ return this._isTrusted;
+ }
+
get onDidChangeDirty(): Event {
return this._onDidChangeDirty.event;
}
@@ -93,6 +97,10 @@ export class NotebookInput extends EditorInput {
return this._title;
}
+ public get isTrusted(): boolean {
+ return this._model.isTrusted;
+ }
+
public dispose(): void {
this._disposeContainer();
super.dispose();
diff --git a/src/sql/services/notebook/notebookService.ts b/src/sql/services/notebook/notebookService.ts
index 02a26008db..2ab77d9dfa 100644
--- a/src/sql/services/notebook/notebookService.ts
+++ b/src/sql/services/notebook/notebookService.ts
@@ -9,6 +9,8 @@ import * as sqlops from 'sqlops';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import URI from 'vs/base/common/uri';
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
+import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
+import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
export const SERVICE_ID = 'notebookService';
export const INotebookService = createDecorator(SERVICE_ID);
@@ -56,4 +58,7 @@ export interface INotebookManager {
export interface INotebookParams extends IBootstrapParams {
notebookUri: URI;
providerId: string;
+ isTrusted: boolean;
+ profile?: IConnectionProfile;
+ modelFactory?: ModelFactory;
}
\ No newline at end of file