Update kernels dropdown after installing a notebook extension (#20759)

This commit is contained in:
Cory Rivera
2022-10-12 14:44:31 -07:00
committed by GitHub
parent 03fcaf837c
commit acc9780f04
17 changed files with 253 additions and 68 deletions

View File

@@ -27,7 +27,6 @@ import { ITextResourcePropertiesService } from 'vs/editor/common/services/textRe
import { TextResourceEditorModel } from 'vs/workbench/common/editor/textResourceEditorModel'; import { TextResourceEditorModel } from 'vs/workbench/common/editor/textResourceEditorModel';
import { UntitledTextEditorModel, IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel'; import { UntitledTextEditorModel, IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { AbstractResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput';
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
import { NotebookFindModel } from 'sql/workbench/contrib/notebook/browser/find/notebookFindModel'; import { NotebookFindModel } from 'sql/workbench/contrib/notebook/browser/find/notebookFindModel';
@@ -216,7 +215,7 @@ export class NotebookEditorModel extends EditorModel {
} }
} }
type TextInput = AbstractResourceEditorInput | UntitledTextEditorInput | FileEditorInput; type TextInput = UntitledTextEditorInput | FileEditorInput;
export abstract class NotebookInput extends EditorInput implements INotebookInput { export abstract class NotebookInput extends EditorInput implements INotebookInput {
private _providerId: string; private _providerId: string;
@@ -259,6 +258,10 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
} }
} }
public get languageMode(): string {
return this._textInput.getMode();
}
public get textInput(): TextInput { public get textInput(): TextInput {
return this._textInput; return this._textInput;
} }

View File

@@ -597,6 +597,9 @@ export class KernelsDropdown extends SelectBox {
this._register(this.model.kernelChanged((changedArgs: azdata.nb.IKernelChangedArgs) => { this._register(this.model.kernelChanged((changedArgs: azdata.nb.IKernelChangedArgs) => {
this.updateKernel(changedArgs.newValue, changedArgs.nbKernelAlias); this.updateKernel(changedArgs.newValue, changedArgs.nbKernelAlias);
})); }));
this._register(this.model.kernelsChanged(kernel => {
this.updateKernel(kernel);
}));
let kernel = this.model.clientSession && this.model.clientSession.kernel; let kernel = this.model.clientSession && this.model.clientSession.kernel;
this.updateKernel(kernel); this.updateKernel(kernel);
} }

View File

@@ -12,8 +12,6 @@ import { IConnectionManagementService } from 'sql/platform/connection/common/con
import { CellMagicMapper } from 'sql/workbench/contrib/notebook/browser/models/cellMagicMapper'; import { CellMagicMapper } from 'sql/workbench/contrib/notebook/browser/models/cellMagicMapper';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import { ILogService } from 'vs/platform/log/common/log';
import { IModelFactory, ViewMode, NotebookContentChange, INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces'; import { IModelFactory, ViewMode, NotebookContentChange, INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -23,12 +21,10 @@ import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common
import { IAction, SubmenuAction } from 'vs/base/common/actions'; import { IAction, SubmenuAction } from 'vs/base/common/actions';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension'; import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
import { INotebookView } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews'; import { INotebookView } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
import { Deferred } from 'sql/base/common/promise'; import { Deferred } from 'sql/base/common/promise';
import { NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts'; import { NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import * as path from 'vs/base/common/path'; import * as path from 'vs/base/common/path';
@@ -53,19 +49,15 @@ export class NotebookEditorComponent extends AngularDisposable {
public ViewMode = ViewMode; //For use of the enum in the template public ViewMode = ViewMode; //For use of the enum in the template
constructor( constructor(
@Inject(ILogService) private readonly logService: ILogService,
@Inject(IBootstrapParams) private _notebookParams: INotebookParams, @Inject(IBootstrapParams) private _notebookParams: INotebookParams,
@Inject(INotebookService) private notebookService: INotebookService, @Inject(INotebookService) private notebookService: INotebookService,
@Inject(ICapabilitiesService) private capabilitiesService: ICapabilitiesService, @Inject(ICapabilitiesService) private capabilitiesService: ICapabilitiesService,
@Inject(IContextKeyService) private contextKeyService: IContextKeyService, @Inject(IContextKeyService) private contextKeyService: IContextKeyService,
@Inject(IMenuService) private menuService: IMenuService, @Inject(IMenuService) private menuService: IMenuService,
@Inject(INotificationService) private notificationService: INotificationService, @Inject(INotificationService) private notificationService: INotificationService,
@Inject(IAdsTelemetryService) private adstelemetryService: IAdsTelemetryService,
@Inject(IInstantiationService) private instantiationService: IInstantiationService, @Inject(IInstantiationService) private instantiationService: IInstantiationService,
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
@Inject(IConfigurationService) private _configurationService: IConfigurationService,
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService, @Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService,
@Inject(IUndoRedoService) private _undoService: IUndoRedoService,
) { ) {
super(); super();
this.updateProfile(); this.updateProfile();
@@ -128,7 +120,7 @@ export class NotebookEditorComponent extends AngularDisposable {
private async createModelAndLoadContents(): Promise<void> { private async createModelAndLoadContents(): Promise<void> {
let providerInfo = await this._notebookParams.providerInfo; let providerInfo = await this._notebookParams.providerInfo;
let model = new NotebookModel({ let model = this.instantiationService.createInstance(NotebookModel, {
factory: this.modelFactory, factory: this.modelFactory,
notebookUri: this._notebookParams.notebookUri, notebookUri: this._notebookParams.notebookUri,
connectionService: this.connectionManagementService, connectionService: this.connectionManagementService,
@@ -141,8 +133,9 @@ export class NotebookEditorComponent extends AngularDisposable {
defaultKernel: this._notebookParams.input.defaultKernel, defaultKernel: this._notebookParams.input.defaultKernel,
layoutChanged: this._notebookParams.input.layoutChanged, layoutChanged: this._notebookParams.input.layoutChanged,
capabilitiesService: this.capabilitiesService, capabilitiesService: this.capabilitiesService,
editorLoadedTimestamp: this._notebookParams.input.editorOpenedTimestamp editorLoadedTimestamp: this._notebookParams.input.editorOpenedTimestamp,
}, this.profile, this.logService, this.notificationService, this.adstelemetryService, this.connectionManagementService, this._configurationService, this._undoService, this.capabilitiesService); getInputLanguageMode: () => this._notebookParams.input.languageMode // Can't pass in languageMode directly since it can change after the editor loads
}, this.profile);
let trusted = await this.notebookService.isNotebookTrustCached(this._notebookParams.notebookUri, this.isDirty()); let trusted = await this.notebookService.isNotebookTrustCached(this._notebookParams.notebookUri, this.isDirty());
this.model = this._register(model); this.model = this._register(model);

View File

@@ -31,10 +31,12 @@ import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
import { nb } from 'azdata'; import { nb } from 'azdata';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService'; import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
suite('CellToolbarActions', function (): void { suite('CellToolbarActions', function (): void {
suite('removeDuplicatedAndStartingSeparators', function (): void { suite('removeDuplicatedAndStartingSeparators', function (): void {
@@ -236,7 +238,11 @@ export async function createandLoadNotebookModel(codeContent?: nb.INotebookConte
cellMagicMapper: undefined, cellMagicMapper: undefined,
defaultKernel: undefined, defaultKernel: undefined,
layoutChanged: undefined, layoutChanged: undefined,
capabilitiesService: undefined capabilitiesService: undefined,
getInputLanguageMode: () => undefined
}; };
return new NotebookModel(defaultModelOptions, undefined, undefined, undefined, new NullAdsTelemetryService(), undefined, undefined, undoRedoService); let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
return new NotebookModel(defaultModelOptions, undefined, undefined, undefined, new NullAdsTelemetryService(), undefined, undefined, undoRedoService, mockNotebookService.object, undefined, undefined);
} }

View File

@@ -11,7 +11,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel'; import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory'; import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces'; import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
@@ -34,6 +34,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { NotebookViewModel } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewModel'; import { NotebookViewModel } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewModel';
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService'; import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let initialNotebookContent: nb.INotebookContents = { let initialNotebookContent: nb.INotebookContents = {
cells: [{ cells: [{
@@ -239,7 +241,8 @@ suite('NotebookViewModel', function (): void {
cellMagicMapper: undefined, cellMagicMapper: undefined,
defaultKernel: undefined, defaultKernel: undefined,
layoutChanged: undefined, layoutChanged: undefined,
capabilitiesService: capabilitiesService.object capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
}; };
} }
@@ -247,8 +250,10 @@ suite('NotebookViewModel', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader); let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined, mockNotebookService.object, undefined, undefined);
await model.loadContents(); await model.loadContents();
await model.requestModelLoad(); await model.requestModelLoad();

View File

@@ -11,7 +11,7 @@ import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTeleme
import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput'; import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
import { DeleteViewAction, InsertCellAction } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsActions'; import { DeleteViewAction, InsertCellAction } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsActions';
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses'; import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory'; import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { ICellModel, INotebookModelOptions, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces'; import { ICellModel, INotebookModelOptions, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel'; import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
@@ -35,6 +35,8 @@ import { InsertCellsModal } from 'sql/workbench/contrib/notebook/browser/noteboo
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService'; import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let initialNotebookContent: nb.INotebookContents = { let initialNotebookContent: nb.INotebookContents = {
cells: [{ cells: [{
@@ -190,7 +192,8 @@ suite('Notebook Views Actions', function (): void {
cellMagicMapper: undefined, cellMagicMapper: undefined,
defaultKernel: undefined, defaultKernel: undefined,
layoutChanged: undefined, layoutChanged: undefined,
capabilitiesService: capabilitiesService.object capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
}; };
} }
@@ -198,8 +201,10 @@ suite('Notebook Views Actions', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader); let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined, mockNotebookService.object, undefined, undefined);
await model.loadContents(); await model.loadContents();
await model.requestModelLoad(); await model.requestModelLoad();

View File

@@ -11,7 +11,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel'; import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory'; import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces'; import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
@@ -37,6 +37,8 @@ import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService'; import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let initialNotebookContent: nb.INotebookContents = { let initialNotebookContent: nb.INotebookContents = {
cells: [{ cells: [{
@@ -171,7 +173,8 @@ suite('NotebookViews', function (): void {
cellMagicMapper: undefined, cellMagicMapper: undefined,
defaultKernel: undefined, defaultKernel: undefined,
layoutChanged: undefined, layoutChanged: undefined,
capabilitiesService: capabilitiesService.object capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
}; };
} }
@@ -179,8 +182,10 @@ suite('NotebookViews', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader); let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(initialNotebookContent)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(initialNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, undefined); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, mockNotebookService.object, undefined, undefined);
await model.loadContents(); await model.loadContents();
await model.requestModelLoad(); await model.requestModelLoad();

View File

@@ -42,6 +42,8 @@ import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTeleme
import { IProductService } from 'vs/platform/product/common/productService'; import { IProductService } from 'vs/platform/product/common/productService';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService'; import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
class ServiceAccessor { class ServiceAccessor {
@@ -175,7 +177,8 @@ suite('Notebook Editor Model', function (): void {
cellMagicMapper: undefined, cellMagicMapper: undefined,
defaultKernel: undefined, defaultKernel: undefined,
layoutChanged: undefined, layoutChanged: undefined,
capabilitiesService: capabilitiesService.object capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
}; };
}); });
@@ -983,7 +986,10 @@ suite('Notebook Editor Model', function (): void {
let options: INotebookModelOptions = Object.assign({}, defaultModelOptions, <Partial<INotebookModelOptions>><unknown>{ let options: INotebookModelOptions = Object.assign({}, defaultModelOptions, <Partial<INotebookModelOptions>><unknown>{
factory: mockModelFactory.object factory: mockModelFactory.object
}); });
notebookModel = new NotebookModel(options, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, undefined); let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
notebookModel = new NotebookModel(options, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, mockNotebookService.object, undefined, undefined);
await notebookModel.loadContents(); await notebookModel.loadContents();
} }

View File

@@ -7,7 +7,7 @@ import { nb } from 'azdata';
import * as assert from 'assert'; import * as assert from 'assert';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts'; import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
import { IClientSession, INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces'; import { IClientSession, INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel'; import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
@@ -34,6 +34,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService'; import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService';
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses'; import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let expectedNotebookContent: nb.INotebookContents = { let expectedNotebookContent: nb.INotebookContents = {
cells: [{ cells: [{
@@ -106,7 +108,8 @@ suite('Notebook Find Model', function (): void {
cellMagicMapper: undefined, cellMagicMapper: undefined,
defaultKernel: undefined, defaultKernel: undefined,
layoutChanged: undefined, layoutChanged: undefined,
capabilitiesService: capabilitiesService.object capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
}; };
mockClientSession = TypeMoq.Mock.ofType<IClientSession>(ClientSession, undefined, defaultModelOptions); mockClientSession = TypeMoq.Mock.ofType<IClientSession>(ClientSession, undefined, defaultModelOptions);
mockClientSession.setup(c => c.initialize()).returns(() => { mockClientSession.setup(c => c.initialize()).returns(() => {
@@ -603,8 +606,11 @@ suite('Notebook Find Model', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader); let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
// Initialize the model // Initialize the model
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined); model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined, mockNotebookService.object, undefined, undefined);
await model.loadContents(); await model.loadContents();
await model.requestModelLoad(); await model.requestModelLoad();
} }

View File

@@ -14,7 +14,7 @@ import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogSer
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs'; import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { NotebookModel, SplitCell } from 'sql/workbench/services/notebook/browser/models/notebookModel'; import { NotebookModel, SplitCell } from 'sql/workbench/services/notebook/browser/models/notebookModel';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory'; import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { IClientSession, INotebookModelOptions, NotebookContentChange, IClientSessionOptions, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces'; import { IClientSession, INotebookModelOptions, NotebookContentChange, IClientSessionOptions, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
@@ -42,8 +42,10 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService'; import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService'; import { DEFAULT_NOTEBOOK_FILETYPE, IExecuteManager, INotebookService, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let expectedNotebookContent: nb.INotebookContents = { let expectedNotebookContent: nb.INotebookContents = {
cells: [{ cells: [{
@@ -145,6 +147,7 @@ let undoRedoService: IUndoRedoService;
let capabilitiesService: ICapabilitiesService; let capabilitiesService: ICapabilitiesService;
let instantiationService: IInstantiationService; let instantiationService: IInstantiationService;
let configurationService: IConfigurationService; let configurationService: IConfigurationService;
let notebookService: INotebookService;
suite('notebook model', function (): void { suite('notebook model', function (): void {
let serializationManagers = [new SerializationManagerStub()]; let serializationManagers = [new SerializationManagerStub()];
@@ -163,6 +166,9 @@ suite('notebook model', function (): void {
dialogService = TypeMoq.Mock.ofType<IDialogService>(TestDialogService, TypeMoq.MockBehavior.Loose); dialogService = TypeMoq.Mock.ofType<IDialogService>(TestDialogService, TypeMoq.MockBehavior.Loose);
undoRedoService = new UndoRedoService(dialogService.object, notificationService.object); undoRedoService = new UndoRedoService(dialogService.object, notificationService.object);
capabilitiesService = new TestCapabilitiesService(); capabilitiesService = new TestCapabilitiesService();
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
notebookService = mockNotebookService.object;
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, ''); memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
memento.setup(x => x.getMemento(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => void 0); memento.setup(x => x.getMemento(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => void 0);
queryConnectionService = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined, new TestStorageService()); queryConnectionService = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined, new TestStorageService());
@@ -182,7 +188,8 @@ suite('notebook model', function (): void {
cellMagicMapper: undefined, cellMagicMapper: undefined,
defaultKernel: undefined, defaultKernel: undefined,
layoutChanged: undefined, layoutChanged: undefined,
capabilitiesService: capabilitiesService capabilitiesService: capabilitiesService,
getInputLanguageMode: () => 'notebook'
}; };
clientSessionOptions = { clientSessionOptions = {
executeManager: defaultModelOptions.executeManagers[0], executeManager: defaultModelOptions.executeManagers[0],
@@ -218,7 +225,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(emptyNotebook)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(emptyNotebook));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
// Then I expect to have 0 code cell as the contents // Then I expect to have 0 code cell as the contents
@@ -234,7 +241,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(true); await model.loadContents(true);
await model.requestModelLoad(); await model.requestModelLoad();
@@ -251,7 +258,7 @@ suite('notebook model', function (): void {
// When I initalize the model // When I initalize the model
// Then it should throw // Then it should throw
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
assert.strictEqual(model.inErrorState, false); assert.strictEqual(model.inErrorState, false);
await assert.rejects(async () => { await model.loadContents(); }); await assert.rejects(async () => { await model.loadContents(); });
assert.strictEqual(model.inErrorState, true); assert.strictEqual(model.inErrorState, true);
@@ -264,7 +271,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model // When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
// Then I expect all cells to be in the model // Then I expect all cells to be in the model
@@ -292,7 +299,7 @@ suite('notebook model', function (): void {
defaultModelOptions.providerId = 'jupyter'; defaultModelOptions.providerId = 'jupyter';
// When I initalize the model // When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
// I expect the default provider to be jupyter // I expect the default provider to be jupyter
@@ -302,7 +309,7 @@ suite('notebook model', function (): void {
defaultModelOptions.providerId = 'SQL'; defaultModelOptions.providerId = 'SQL';
// When I initalize the model // When I initalize the model
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
// I expect the default provider to be SQL // I expect the default provider to be SQL
@@ -327,7 +334,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model // When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
let activeCellChangeCount = 0; let activeCellChangeCount = 0;
@@ -384,7 +391,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI'); assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -412,7 +419,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI'); assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -436,7 +443,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI'); assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -457,7 +464,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI'); assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -476,7 +483,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI'); assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -496,7 +503,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI'); assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -517,7 +524,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model // When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
// Count number of times onError event is fired // Count number of times onError event is fired
@@ -569,7 +576,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model // When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
// Then I expect all cells to be in the model // Then I expect all cells to be in the model
@@ -591,7 +598,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
let firstCell = model.cells[0]; let firstCell = model.cells[0];
@@ -637,7 +644,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
let splitCells: SplitCell[] = [ let splitCells: SplitCell[] = [
@@ -657,7 +664,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model // When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
let notebookContentChange: NotebookContentChange; let notebookContentChange: NotebookContentChange;
@@ -673,7 +680,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
let newCell: ICellModel; let newCell: ICellModel;
@@ -705,7 +712,7 @@ suite('notebook model', function (): void {
sessionReady.resolve(); sessionReady.resolve();
let sessionFired = false; let sessionFired = false;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
model.onClientSessionReady((session) => sessionFired = true); model.onClientSessionReady((session) => sessionFired = true);
await model.loadContents(); await model.loadContents();
await model.requestModelLoad(); await model.requestModelLoad();
@@ -735,7 +742,7 @@ suite('notebook model', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader); let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.requestModelLoad(); await model.requestModelLoad();
let actualChanged: NotebookContentChange; let actualChanged: NotebookContentChange;
@@ -804,7 +811,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined, queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined, queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
let output = model.toJSON(); let output = model.toJSON();
@@ -937,7 +944,7 @@ suite('notebook model', function (): void {
sinon.stub(configurationService, 'getValue').returns(true); sinon.stub(configurationService, 'getValue').returns(true);
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
// I expect the saved connection name to be read // I expect the saved connection name to be read
@@ -966,7 +973,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model // When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
// I expect multiConnectionMode to be set to true // I expect multiConnectionMode to be set to true
@@ -997,7 +1004,7 @@ suite('notebook model', function (): void {
// Given I have a session that fails to start // Given I have a session that fails to start
sessionReady.resolve(); sessionReady.resolve();
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
await model.requestModelLoad(); await model.requestModelLoad();
@@ -1011,7 +1018,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
const newLanguage = 'CustomCellLanguage'; const newLanguage = 'CustomCellLanguage';
@@ -1025,7 +1032,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object; defaultModelOptions.contentLoader = mockContentManager.object;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService); let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(); await model.loadContents();
let cell = model.addCell(CellTypes.Code); let cell = model.addCell(CellTypes.Code);
@@ -1033,6 +1040,81 @@ suite('notebook model', function (): void {
assert.strictEqual(cell.language, expectedNotebookContent.metadata.language_info.name); assert.strictEqual(cell.language, expectedNotebookContent.metadata.language_info.name);
}); });
test('Should update kernels list when new kernels are installed', async function () {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
let kernelsAddedEmitter = new Emitter<IStandardKernelWithProvider[]>();
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => kernelsAddedEmitter.event);
let mockExecuteManager = TypeMoq.Mock.ofType<IExecuteManager>(ExecuteManagerStub);
mockNotebookService.setup(s => s.getOrCreateExecuteManager(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockExecuteManager.object));
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, mockNotebookService.object, undefined, undefined);
model.standardKernels = [{
name: 'SQL',
displayName: 'SQL',
connectionProviderIds: [],
notebookProvider: 'sql',
supportedLanguages: ['sql'],
supportedFileExtensions: ['.ipynb']
}];
await model.loadContents();
assert.strictEqual(model.standardKernels.length, 1, 'Should start with only 1 kernel in the notebook model.');
assert.strictEqual(model.executeManagers.length, 1, 'Should start with only 1 execute manager in the notebook model.');
let expectedKernel: IStandardKernelWithProvider = {
name: 'csharp-test',
displayName: 'CSharpTest',
connectionProviderIds: undefined,
notebookProvider: 'csharp-test',
supportedLanguages: ['csharp'],
supportedFileExtensions: [DEFAULT_NOTEBOOK_FILETYPE]
};
let kernelsAddedPromise = new Promise<void>(resolve => {
model.kernelsChanged(kernel => {
resolve();
});
});
let timeoutPromise = new Promise<void>((resolve, reject) => setTimeout(() => {
reject('KernelsAdded event failed to fire within expected time.');
}, 4000));
kernelsAddedEmitter.fire([expectedKernel]);
await Promise.race([kernelsAddedPromise, timeoutPromise]);
assert.strictEqual(model.standardKernels.length, 2, 'New kernel was not registered.');
assert.strictEqual(model.executeManagers.length, 2, 'Should create another execute manager when adding a new provider\'s kernel.');
assert.deepStrictEqual(model.standardKernels[1], expectedKernel, 'Did not add expected kernel.');
// Shouldn't add kernel if it's for a different file extension
let invalidKernel = {
name: 'html-test',
displayName: 'HtmlTest',
connectionProviderIds: undefined,
notebookProvider: 'html-test',
supportedLanguages: ['html'],
supportedFileExtensions: ['.html']
};
kernelsAddedPromise = new Promise<void>((resolve, reject) => {
model.kernelsChanged(kernel => {
reject('Should not have added a new kernel');
});
});
timeoutPromise = new Promise<void>((resolve, reject) => setTimeout(() => {
resolve();
}, 1000));
kernelsAddedEmitter.fire([invalidKernel]);
await Promise.race([kernelsAddedPromise, timeoutPromise]);
assert.strictEqual(model.standardKernels.length, 2, 'Should not have registered invalid kernel.');
assert.strictEqual(model.executeManagers.length, 2, 'Should not have created another execute manager for invalid kernel.');
assert.deepStrictEqual(model.standardKernels[1], expectedKernel, 'Did not keep old kernel.');
});
async function loadModelAndStartClientSession(notebookContent: nb.INotebookContents): Promise<NotebookModel> { async function loadModelAndStartClientSession(notebookContent: nb.INotebookContents): Promise<NotebookModel> {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader); let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebookContent)); mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebookContent));
@@ -1046,7 +1128,7 @@ suite('notebook model', function (): void {
let options: INotebookModelOptions = Object.assign({}, defaultModelOptions, <Partial<INotebookModelOptions>>{ let options: INotebookModelOptions = Object.assign({}, defaultModelOptions, <Partial<INotebookModelOptions>>{
factory: mockModelFactory.object factory: mockModelFactory.object
}); });
let model = new NotebookModel(options, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, capabilitiesService); let model = new NotebookModel(options, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, capabilitiesService, undefined);
model.onClientSessionReady((session) => actualSession = session); model.onClientSessionReady((session) => actualSession = session);
await model.requestModelLoad(); await model.requestModelLoad();

View File

@@ -236,6 +236,9 @@ export class ServerManagerStub implements nb.ServerManager {
} }
export class NotebookServiceStub implements INotebookService { export class NotebookServiceStub implements INotebookService {
get onNotebookKernelsAdded(): vsEvent.Event<IStandardKernelWithProvider[]> {
throw new Error('Method not implemented.');
}
getNotebookURIForCell(cellUri: URI): URI { getNotebookURIForCell(cellUri: URI): URI {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }

View File

@@ -23,6 +23,7 @@ export abstract class INotebookInput extends EditorInput {
readonly standardKernels: IStandardKernelWithProvider[]; readonly standardKernels: IStandardKernelWithProvider[];
readonly providersLoaded: Promise<void>; readonly providersLoaded: Promise<void>;
readonly showActions: boolean; readonly showActions: boolean;
readonly languageMode: string;
} }
export function isINotebookInput(value: any): value is INotebookInput { export function isINotebookInput(value: any): value is INotebookInput {

View File

@@ -622,6 +622,7 @@ export interface INotebookModelOptions {
notificationService: INotificationService; notificationService: INotificationService;
connectionService: IConnectionManagementService; connectionService: IConnectionManagementService;
capabilitiesService: ICapabilitiesService; capabilitiesService: ICapabilitiesService;
getInputLanguageMode: () => string;
editorLoadedTimestamp?: number; editorLoadedTimestamp?: number;
} }

View File

@@ -23,7 +23,7 @@ import { INotebookEditOperation, NotebookEditOperationType } from 'sql/workbench
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
import { uriPrefixes } from 'sql/platform/connection/common/utils'; import { uriPrefixes } from 'sql/platform/connection/common/utils';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { getErrorMessage } from 'vs/base/common/errors'; import { getErrorMessage, onUnexpectedError } from 'vs/base/common/errors';
import { notebookConstants } from 'sql/workbench/services/notebook/browser/interfaces'; import { notebookConstants } from 'sql/workbench/services/notebook/browser/interfaces';
import { IAdsTelemetryService, ITelemetryEvent, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry'; import { IAdsTelemetryService, ITelemetryEvent, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
import { Deferred } from 'sql/base/common/promise'; import { Deferred } from 'sql/base/common/promise';
@@ -40,6 +40,8 @@ import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { deepClone } from 'vs/base/common/objects'; import { deepClone } from 'vs/base/common/objects';
import { DotnetInteractiveDisplayName } from 'sql/workbench/api/common/notebooks/notebookUtils'; import { DotnetInteractiveDisplayName } from 'sql/workbench/api/common/notebooks/notebookUtils';
import { IPYKERNEL_DISPLAY_NAME } from 'sql/workbench/common/constants'; import { IPYKERNEL_DISPLAY_NAME } from 'sql/workbench/common/constants';
import * as path from 'vs/base/common/path';
import { IModeService } from 'vs/editor/common/services/modeService';
/* /*
* Used to control whether a message in a dialog/wizard is displayed as an error, * Used to control whether a message in a dialog/wizard is displayed as an error,
@@ -134,7 +136,9 @@ export class NotebookModel extends Disposable implements INotebookModel {
@IConnectionManagementService private connectionManagementService: IConnectionManagementService, @IConnectionManagementService private connectionManagementService: IConnectionManagementService,
@IConfigurationService private configurationService: IConfigurationService, @IConfigurationService private configurationService: IConfigurationService,
@IUndoRedoService private undoService: IUndoRedoService, @IUndoRedoService private undoService: IUndoRedoService,
@ICapabilitiesService private _capabilitiesService?: ICapabilitiesService, @INotebookService private _notebookService: INotebookService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
@IModeService private _modeService: IModeService,
) { ) {
super(); super();
if (!_notebookOptions || !_notebookOptions.notebookUri || !_notebookOptions.executeManagers) { if (!_notebookOptions || !_notebookOptions.notebookUri || !_notebookOptions.executeManagers) {
@@ -147,6 +151,45 @@ export class NotebookModel extends Disposable implements INotebookModel {
this._notebookOptions.layoutChanged(() => this._layoutChanged.fire()); this._notebookOptions.layoutChanged(() => this._layoutChanged.fire());
} }
this._defaultKernel = _notebookOptions.defaultKernel; this._defaultKernel = _notebookOptions.defaultKernel;
this._register(this._notebookService.onNotebookKernelsAdded(async kernels => this.handleNewKernelsAdded(kernels).catch(error => onUnexpectedError(error))));
}
// Add new kernels to the model's list as they're registered so that we don't
// need to restart the notebook to select them in the kernel dropdown.
private async handleNewKernelsAdded(kernels: notebookUtils.IStandardKernelWithProvider[]): Promise<void> {
// Kernels are file-specific, so we need to check the file extension
// to see if the kernel is supported for this notebook.
let extensions: string[];
let fileExt = path.extname(this._notebookOptions.notebookUri.path);
if (!fileExt) {
let languageMode = this._notebookOptions.getInputLanguageMode();
if (languageMode) {
let languageName = this._modeService.getLanguageName(languageMode);
let fileExtensions = this._modeService.getExtensions(languageName);
if (fileExtensions?.length > 0) {
extensions = fileExtensions;
} else {
this.logService.warn(`Could not retrieve file extensions for language mode '${languageMode}' in notebook '${this._notebookOptions.notebookUri.toString()}'`);
}
} else {
this.logService.warn(`Could not determine language mode for notebook '${this._notebookOptions.notebookUri.toString()}'`);
}
} else {
extensions = [fileExt];
}
// All kernels from the same provider share the same supported file extensions,
// so we only need to check the first one here.
if (extensions?.some(ext => kernels[0]?.supportedFileExtensions?.includes(ext))) {
this._standardKernels.push(...kernels);
this.setDisplayNameMapsForKernels(kernels);
// Also add corresponding execute manager so that we can change to the new kernels
let manager = await this._notebookService.getOrCreateExecuteManager(kernels[0].notebookProvider, this.notebookUri);
this._notebookOptions.executeManagers.push(manager);
this._kernelsChangedEmitter.fire(this._activeClientSession?.kernel);
}
} }
private get serializationManagers(): ISerializationManager[] { private get serializationManagers(): ISerializationManager[] {
@@ -401,7 +444,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
public set standardKernels(kernels: notebookUtils.IStandardKernelWithProvider[]) { public set standardKernels(kernels: notebookUtils.IStandardKernelWithProvider[]) {
this._standardKernels = kernels; this._standardKernels = kernels;
this.setKernelDisplayNameMapsWithStandardKernels(); this.setDisplayNameMapsForKernels(kernels);
} }
public getApplicableConnectionProviderIds(kernelDisplayName: string): string[] { public getApplicableConnectionProviderIds(kernelDisplayName: string): string[] {
@@ -1567,8 +1610,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
* Set maps with values to have a way to determine the connection * Set maps with values to have a way to determine the connection
* provider and notebook provider ids from a kernel display name * provider and notebook provider ids from a kernel display name
*/ */
private setKernelDisplayNameMapsWithStandardKernels(): void { private setDisplayNameMapsForKernels(kernels: notebookUtils.IStandardKernelWithProvider[]): void {
this._standardKernels.forEach(kernel => { kernels.forEach(kernel => {
let displayName = kernel.displayName; let displayName = kernel.displayName;
if (!displayName) { if (!displayName) {
displayName = kernel.name; displayName = kernel.name;

View File

@@ -65,6 +65,7 @@ export interface IStandardKernelWithProvider {
readonly connectionProviderIds: string[]; readonly connectionProviderIds: string[];
readonly notebookProvider: string; readonly notebookProvider: string;
readonly supportedLanguages: string[]; readonly supportedLanguages: string[];
readonly supportedFileExtensions?: string[];
} }
export interface IEndpoint { export interface IEndpoint {

View File

@@ -23,6 +23,7 @@ import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protoc
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension'; import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { ICodeEditorViewState } from 'vs/editor/common/editorCommon'; import { ICodeEditorViewState } from 'vs/editor/common/editorCommon';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
export const SERVICE_ID = 'sqlNotebookService'; export const SERVICE_ID = 'sqlNotebookService';
export const INotebookService = createDecorator<INotebookService>(SERVICE_ID); export const INotebookService = createDecorator<INotebookService>(SERVICE_ID);
@@ -55,6 +56,7 @@ export interface INotebookService {
readonly onNotebookEditorAdd: Event<INotebookEditor>; readonly onNotebookEditorAdd: Event<INotebookEditor>;
readonly onNotebookEditorRemove: Event<INotebookEditor>; readonly onNotebookEditorRemove: Event<INotebookEditor>;
onNotebookEditorRename: Event<INotebookEditor>; onNotebookEditorRename: Event<INotebookEditor>;
readonly onNotebookKernelsAdded: Event<IStandardKernelWithProvider[]>;
readonly isRegistrationComplete: boolean; readonly isRegistrationComplete: boolean;
readonly registrationComplete: Promise<void>; readonly registrationComplete: Promise<void>;

View File

@@ -54,6 +54,7 @@ import { DEFAULT_NB_LANGUAGE_MODE, INTERACTIVE_LANGUAGE_MODE, INTERACTIVE_PROVID
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { SqlSerializationProvider } from 'sql/workbench/services/notebook/browser/sql/sqlSerializationProvider'; import { SqlSerializationProvider } from 'sql/workbench/services/notebook/browser/sql/sqlSerializationProvider';
import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations); const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
@@ -178,6 +179,7 @@ export class NotebookService extends Disposable implements INotebookService {
private _onNotebookEditorAdd = new Emitter<INotebookEditor>(); private _onNotebookEditorAdd = new Emitter<INotebookEditor>();
private _onNotebookEditorRemove = new Emitter<INotebookEditor>(); private _onNotebookEditorRemove = new Emitter<INotebookEditor>();
private _onNotebookEditorRename = new Emitter<INotebookEditor>(); private _onNotebookEditorRename = new Emitter<INotebookEditor>();
private _onNotebookKernelsAdded = new Emitter<IStandardKernelWithProvider[]>();
private _editors = new Map<string, INotebookEditor>(); private _editors = new Map<string, INotebookEditor>();
private _fileToProviderDescriptions = new Map<string, ProviderDescriptionRegistration[]>(); private _fileToProviderDescriptions = new Map<string, ProviderDescriptionRegistration[]>();
private _providerToStandardKernels = new Map<string, StandardKernelsDescriptor>(); // Note: providerId key here should be in upper case private _providerToStandardKernels = new Map<string, StandardKernelsDescriptor>(); // Note: providerId key here should be in upper case
@@ -426,7 +428,7 @@ export class NotebookService extends Disposable implements INotebookService {
if (!this._executeProviders.has(p.id)) { if (!this._executeProviders.has(p.id)) {
this._executeProviders.set(p.id, new ExecuteProviderDescriptor(p.id)); this._executeProviders.set(p.id, new ExecuteProviderDescriptor(p.id));
} }
this.addStandardKernels(registration); this.addStandardKernels(registration, registration.fileExtensions);
} else { } else {
// Standard kernels might get registered later for VSCode notebooks, so add a descriptor to wait on // Standard kernels might get registered later for VSCode notebooks, so add a descriptor to wait on
if (!this._providerToStandardKernels.has(p.id)) { if (!this._providerToStandardKernels.has(p.id)) {
@@ -506,7 +508,7 @@ export class NotebookService extends Disposable implements INotebookService {
// in the kernels dropdown list before a SessionManager has been started; this way, // in the kernels dropdown list before a SessionManager has been started; this way,
// every NotebookProvider doesn't need to have an active SessionManager in order to contribute // every NotebookProvider doesn't need to have an active SessionManager in order to contribute
// kernels to the dropdown // kernels to the dropdown
private addStandardKernels(provider: ProviderDescriptionRegistration) { private addStandardKernels(provider: ProviderDescriptionRegistration, supportedFileExtensions?: string[]) {
let providerUpperCase = provider.provider.toUpperCase(); let providerUpperCase = provider.provider.toUpperCase();
let descriptor = this._providerToStandardKernels.get(providerUpperCase); let descriptor = this._providerToStandardKernels.get(providerUpperCase);
if (!descriptor) { if (!descriptor) {
@@ -526,6 +528,20 @@ export class NotebookService extends Disposable implements INotebookService {
} }
descriptor.instance = standardKernels; descriptor.instance = standardKernels;
this._providerToStandardKernels.set(providerUpperCase, descriptor); this._providerToStandardKernels.set(providerUpperCase, descriptor);
// Emit update event if the provider is not one of the default options
if (provider.provider !== SQL_NOTEBOOK_PROVIDER && provider.provider !== JUPYTER_PROVIDER_ID && standardKernels.length > 0) {
this._onNotebookKernelsAdded.fire(standardKernels.map(kernel => {
return {
name: kernel.name,
displayName: kernel.displayName,
connectionProviderIds: kernel.connectionProviderIds,
notebookProvider: provider.provider,
supportedLanguages: kernel.supportedLanguages,
supportedFileExtensions: supportedFileExtensions
};
}));
}
} }
getSupportedFileExtensions(): string[] { getSupportedFileExtensions(): string[] {
@@ -632,6 +648,10 @@ export class NotebookService extends Disposable implements INotebookService {
return this._onNotebookEditorRename.event; return this._onNotebookEditorRename.event;
} }
get onNotebookKernelsAdded(): Event<IStandardKernelWithProvider[]> {
return this._onNotebookKernelsAdded.event;
}
addNotebookEditor(editor: INotebookEditor): void { addNotebookEditor(editor: INotebookEditor): void {
this._editors.set(editor.id, editor); this._editors.set(editor.id, editor);
this._onNotebookEditorAdd.fire(editor); this._onNotebookEditorAdd.fire(editor);