Notebooks: Fix strict compile errors (#12591)

* strict compile for sqlSessionManager.ts

* start clientSession.ts fixes

* strict compile for clientSession.ts

* strict compile for notebookModel.ts

* add display name

* clean up code

* clean up code

* initialize string to empty string

* address PR comments

* address PR comments

* address PR comments

* remove errorMessage check
This commit is contained in:
Lucy Zhang
2020-10-08 15:39:57 -07:00
committed by GitHub
parent 3e0135b6b3
commit b910bf2f33
16 changed files with 244 additions and 200 deletions

View File

@@ -24,9 +24,9 @@ export const pySparkNotebookContent: azdata.nb.INotebookContents = {
execution_count: 1 execution_count: 1
}], }],
metadata: { metadata: {
'kernelspec': { kernelspec: {
'name': 'pysparkkernel', name: 'pysparkkernel',
'display_name': 'PySpark' display_name: 'PySpark'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -41,8 +41,9 @@ export const notebookContentForCellLanguageTest: azdata.nb.INotebookContents = {
execution_count: 1 execution_count: 1
}], }],
metadata: { metadata: {
'kernelspec': { kernelspec: {
'name': '' name: '',
display_name: ''
}, },
}, },
nbformat: 4, nbformat: 4,
@@ -72,9 +73,9 @@ export const pythonNotebookMultipleCellsContent: azdata.nb.INotebookContents = {
execution_count: 1 execution_count: 1
}], }],
metadata: { metadata: {
'kernelspec': { kernelspec: {
'name': 'python3', name: 'python3',
'display_name': 'Python 3' display_name: 'Python 3'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -89,9 +90,9 @@ export const sqlNotebookContent: azdata.nb.INotebookContents = {
execution_count: 1 execution_count: 1
}], }],
metadata: { metadata: {
'kernelspec': { kernelspec: {
'name': 'SQL', name: 'SQL',
'display_name': 'SQL' display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -116,9 +117,9 @@ export const sqlNotebookMultipleCellsContent: azdata.nb.INotebookContents = {
execution_count: 1 execution_count: 1
}], }],
metadata: { metadata: {
'kernelspec': { kernelspec: {
'name': 'SQL', name: 'SQL',
'display_name': 'SQL' display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -126,9 +127,9 @@ export const sqlNotebookMultipleCellsContent: azdata.nb.INotebookContents = {
}; };
export const pySparkKernelMetadata = { export const pySparkKernelMetadata = {
'kernelspec': { kernelspec: {
'name': 'pysparkkernel', name: 'pysparkkernel',
'display_name': 'PySpark' display_name: 'PySpark'
} }
}; };
@@ -138,9 +139,9 @@ export const pySparkKernelSpec = {
}; };
export const sqlKernelMetadata = { export const sqlKernelMetadata = {
'kernelspec': { kernelspec: {
'name': 'SQL', name: 'SQL',
'display_name': 'SQL' display_name: 'SQL'
} }
}; };
@@ -150,9 +151,9 @@ export const sqlKernelSpec: azdata.nb.IKernelSpec = {
}; };
export const pythonKernelMetadata = { export const pythonKernelMetadata = {
'kernelspec': { kernelspec: {
'name': 'python3', name: 'python3',
'display_name': 'Python 3' display_name: 'Python 3'
} }
}; };

View File

@@ -186,7 +186,8 @@ describe('Jupyter Session', function (): void {
// When I call changeKernel on the wrapper // When I call changeKernel on the wrapper
let kernel = await session.changeKernel({ let kernel = await session.changeKernel({
name: 'python' name: 'python',
display_name: 'Python'
}); });
// Then I expect it to have the ID, and only be called once // Then I expect it to have the ID, and only be called once
should(kernel.id).equal('id'); should(kernel.id).equal('id');

27
src/sql/azdata.d.ts vendored
View File

@@ -4653,11 +4653,14 @@ declare module 'azdata' {
} }
export interface INotebookMetadata { export interface INotebookMetadata {
kernelspec: IKernelInfo; kernelspec?: IKernelInfo | IKernelSpec;
language_info?: ILanguageInfo; language_info?: ILanguageInfo;
tags?: string[]; tags?: string[];
} }
/**
* @deprecated Use IKernelSpec instead
*/
export interface IKernelInfo { export interface IKernelInfo {
name: string; name: string;
language?: string; language?: string;
@@ -5059,8 +5062,8 @@ declare module 'azdata' {
* An arguments object for the kernel changed event. * An arguments object for the kernel changed event.
*/ */
export interface IKernelChangedArgs { export interface IKernelChangedArgs {
oldValue: IKernel | null; oldValue: IKernel | undefined;
newValue: IKernel | null; newValue: IKernel | undefined;
} }
/// -------- JSON objects, and objects primarily intended not to have methods ----------- /// -------- JSON objects, and objects primarily intended not to have methods -----------
@@ -5088,7 +5091,7 @@ declare module 'azdata' {
/** /**
* The original outgoing message. * The original outgoing message.
*/ */
readonly msg: IMessage; readonly msg: IMessage | undefined;
/** /**
* A Thenable that resolves when the future is done. * A Thenable that resolves when the future is done.
@@ -5183,7 +5186,7 @@ declare module 'azdata' {
*/ */
export interface IExecuteReply { export interface IExecuteReply {
status: 'ok' | 'error' | 'abort'; status: 'ok' | 'error' | 'abort';
execution_count: number | null; execution_count: number | null | undefined;
} }
/** /**
@@ -5199,11 +5202,11 @@ declare module 'azdata' {
* **See also:** [[IMessage]] * **See also:** [[IMessage]]
*/ */
export interface IHeader { export interface IHeader {
username: string;
version: string;
session: string;
msg_id: string;
msg_type: string; msg_type: string;
username?: string;
version?: string;
session?: string;
msg_id?: string;
} }
/** /**
@@ -5211,10 +5214,10 @@ declare module 'azdata' {
*/ */
export interface IMessage { export interface IMessage {
type: Channel; type: Channel;
header: IHeader;
parent_header: IHeader | {};
metadata: {};
content: any; content: any;
header?: IHeader;
parent_header?: IHeader | {};
metadata?: {};
} }
/** /**

View File

@@ -936,7 +936,7 @@ export interface MainThreadNotebookDocumentsAndEditorsShape extends IDisposable
$runAllCells(id: string, startCellUri?: UriComponents, endCellUri?: UriComponents): Promise<boolean>; $runAllCells(id: string, startCellUri?: UriComponents, endCellUri?: UriComponents): Promise<boolean>;
$clearOutput(id: string, cellUri: UriComponents): Promise<boolean>; $clearOutput(id: string, cellUri: UriComponents): Promise<boolean>;
$clearAllOutputs(id: string): Promise<boolean>; $clearAllOutputs(id: string): Promise<boolean>;
$changeKernel(id: string, kernel: azdata.nb.IKernelInfo): Promise<boolean>; $changeKernel(id: string, kernel: azdata.nb.IKernelSpec): Promise<boolean>;
$registerNavigationProvider(providerId: string, handle: number); $registerNavigationProvider(providerId: string, handle: number);
} }

View File

@@ -188,7 +188,8 @@ export async function createandLoadNotebookModel(codeContent?: nb.INotebookConte
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'python', name: 'python',
language: 'python' language: 'python',
display_name: 'Python 3'
} }
}, },
nbformat: 4, nbformat: 4,

View File

@@ -49,7 +49,7 @@ suite('Client Session', function (): void {
assert(!session.isReady); assert(!session.isReady);
assert.equal(session.status, 'starting'); assert.equal(session.status, 'starting');
assert(!session.isInErrorState); assert(!session.isInErrorState);
assert(isUndefinedOrNull(session.errorMessage)); assert.equal(session.errorMessage, '');
}); });
test('Should call on serverManager startup if set', async function (): Promise<void> { test('Should call on serverManager startup if set', async function (): Promise<void> {

View File

@@ -27,7 +27,8 @@ let expectedNotebookContent: nb.INotebookContents = {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -117,7 +118,8 @@ suite('Local Content Manager', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -158,7 +160,8 @@ suite('Local Content Manager', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -191,7 +194,8 @@ suite('Local Content Manager', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'Python 3', name: 'Python 3',
language: 'python3' language: 'python3',
display_name: 'Python 3'
} }
}, },
nbformat: 4, nbformat: 4,

View File

@@ -46,7 +46,8 @@ let expectedNotebookContent: nb.INotebookContents = {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -184,7 +185,8 @@ suite('Notebook Find Model', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -216,7 +218,8 @@ suite('Notebook Find Model', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'python', name: 'python',
language: 'python' language: 'python',
display_name: 'Python'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -241,7 +244,8 @@ suite('Notebook Find Model', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'python', name: 'python',
language: 'python' language: 'python',
display_name: 'Python'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -301,7 +305,8 @@ suite('Notebook Find Model', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'python', name: 'python',
language: 'python' language: 'python',
display_name: 'Python'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -333,7 +338,8 @@ suite('Notebook Find Model', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'python', name: 'python',
language: 'python' language: 'python',
display_name: 'Python'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -364,7 +370,8 @@ suite('Notebook Find Model', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,

View File

@@ -52,7 +52,8 @@ let expectedNotebookContent: nb.INotebookContents = {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -69,7 +70,8 @@ let expectedNotebookContentOneCell: nb.INotebookContents = {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,
@@ -140,7 +142,8 @@ suite('notebook model', function (): void {
metadata: { metadata: {
kernelspec: { kernelspec: {
name: 'mssql', name: 'mssql',
language: 'sql' language: 'sql',
display_name: 'SQL'
} }
}, },
nbformat: 4, nbformat: 4,

View File

@@ -52,7 +52,7 @@ export class NotebookModelStub implements INotebookModel {
get kernelChanged(): vsEvent.Event<nb.IKernelChangedArgs> { get kernelChanged(): vsEvent.Event<nb.IKernelChangedArgs> {
throw new Error('method not implemented.'); throw new Error('method not implemented.');
} }
get kernelsChanged(): vsEvent.Event<nb.IKernelSpec> { get kernelsChanged(): vsEvent.Event<nb.IKernel> {
throw new Error('method not implemented.'); throw new Error('method not implemented.');
} }
get layoutChanged(): vsEvent.Event<void> { get layoutChanged(): vsEvent.Event<void> {

View File

@@ -475,14 +475,12 @@ export class CellModel extends Disposable implements ICellModel {
await clientSession.kernelChangeCompleted; await clientSession.kernelChangeCompleted;
} }
if (!clientSession.kernel) { if (!clientSession.kernel) {
let defaultKernel = model && model.defaultKernel && model.defaultKernel.name; let defaultKernel = model && model.defaultKernel;
if (!defaultKernel) { if (!defaultKernel) {
this.sendNotification(notificationService, Severity.Error, localize('noDefaultKernel', "No kernel is available for this notebook")); this.sendNotification(notificationService, Severity.Error, localize('noDefaultKernel', "No kernel is available for this notebook"));
return undefined; return undefined;
} }
await clientSession.changeKernel({ await clientSession.changeKernel(defaultKernel);
name: defaultKernel
});
} }
return clientSession.kernel; return clientSession.kernel;
} }

View File

@@ -30,22 +30,22 @@ export class ClientSession implements IClientSession {
private _unhandledMessageEmitter = new Emitter<nb.IMessage>(); private _unhandledMessageEmitter = new Emitter<nb.IMessage>();
private _propertyChangedEmitter = new Emitter<'path' | 'name' | 'type'>(); private _propertyChangedEmitter = new Emitter<'path' | 'name' | 'type'>();
private _notebookUri: URI; private _notebookUri: URI;
private _type: string; private _type: string = '';
private _name: string; private _name: string = '';
private _isReady: boolean; private _isReady: boolean;
private _ready: Deferred<void>; private _ready: Deferred<void>;
private _kernelChangeCompleted: Deferred<void>; private _kernelChangeCompleted: Deferred<void>;
private _kernelDisplayName: string; private _kernelDisplayName: string = '';
private _errorMessage: string; private _errorMessage: string = '';
private _cachedKernelSpec: nb.IKernelSpec; private _cachedKernelSpec: nb.IKernelSpec | undefined;
private _kernelChangeHandlers: KernelChangeHandler[] = []; private _kernelChangeHandlers: KernelChangeHandler[] = [];
private _defaultKernel: nb.IKernelSpec; private _defaultKernel: nb.IKernelSpec;
//#endregion //#endregion
private _serverLoadFinished: Promise<void>; private _serverLoadFinished: Promise<void> = Promise.resolve();
private _session: nb.ISession; private _session: nb.ISession | undefined;
private isServerStarted: boolean; private isServerStarted: boolean = false;
private notebookManager: INotebookManager; private notebookManager: INotebookManager;
private _kernelConfigActions: ((kernelName: string) => Promise<any>)[] = []; private _kernelConfigActions: ((kernelName: string) => Promise<any>)[] = [];
private _connectionId: string = ''; private _connectionId: string = '';
@@ -72,7 +72,7 @@ export class ClientSession implements IClientSession {
this._isReady = true; this._isReady = true;
this._ready.resolve(); this._ready.resolve();
if (!this.isInErrorState && this._session && this._session.kernel) { if (!this.isInErrorState && this._session && this._session.kernel) {
await this.notifyKernelChanged(undefined, this._session.kernel); await this.notifyKernelChanged(this._session.kernel);
} }
} }
@@ -173,7 +173,7 @@ export class ClientSession implements IClientSession {
public get propertyChanged(): Event<'path' | 'name' | 'type'> { public get propertyChanged(): Event<'path' | 'name' | 'type'> {
return this._propertyChangedEmitter.event; return this._propertyChangedEmitter.event;
} }
public get kernel(): nb.IKernel | null { public get kernel(): nb.IKernel | undefined {
return this._session ? this._session.kernel : undefined; return this._session ? this._session.kernel : undefined;
} }
public get notebookUri(): URI { public get notebookUri(): URI {
@@ -210,7 +210,7 @@ export class ClientSession implements IClientSession {
return !!this._errorMessage; return !!this._errorMessage;
} }
public get cachedKernelSpec(): nb.IKernelSpec { public get cachedKernelSpec(): nb.IKernelSpec | undefined {
return this._cachedKernelSpec; return this._cachedKernelSpec;
} }
//#endregion //#endregion
@@ -219,29 +219,31 @@ export class ClientSession implements IClientSession {
/** /**
* Change the current kernel associated with the document. * Change the current kernel associated with the document.
*/ */
async changeKernel(options: nb.IKernelSpec, oldValue?: nb.IKernel): Promise<nb.IKernel> { async changeKernel(options: nb.IKernelSpec, oldValue?: nb.IKernel): Promise<nb.IKernel | undefined> {
this._kernelChangeCompleted = new Deferred<void>(); this._kernelChangeCompleted = new Deferred<void>();
this._isReady = false; this._isReady = false;
let oldKernel = oldValue ? oldValue : this.kernel; let oldKernel = oldValue ? oldValue : this.kernel;
let kernel = await this.doChangeKernel(options); let kernel = await this.doChangeKernel(options);
try { try {
await kernel.ready; await kernel?.ready;
} catch (error) { } catch (error) {
// Cleanup some state before re-throwing // Cleanup some state before re-throwing
this._isReady = kernel.isReady; this._isReady = kernel ? kernel.isReady : false;
this._kernelChangeCompleted.resolve(); this._kernelChangeCompleted.resolve();
throw error; throw error;
} }
let newKernel = this._session ? kernel : this._session.kernel; let newKernel = this._session ? this._session.kernel : kernel;
this._isReady = kernel.isReady; this._isReady = kernel ? kernel.isReady : false;
await this.updateCachedKernelSpec(); await this.updateCachedKernelSpec();
// Send resolution events to listeners // Send resolution events to listeners
await this.notifyKernelChanged(oldKernel, newKernel); if (newKernel) {
await this.notifyKernelChanged(newKernel, oldKernel);
}
return kernel; return kernel;
} }
private async notifyKernelChanged(oldKernel: nb.IKernel, newKernel: nb.IKernel): Promise<void> { private async notifyKernelChanged(newKernel: nb.IKernel, oldKernel?: nb.IKernel): Promise<void> {
let changeArgs: nb.IKernelChangedArgs = { let changeArgs: nb.IKernelChangedArgs = {
oldValue: oldKernel, oldValue: oldKernel,
newValue: newKernel newValue: newKernel
@@ -267,8 +269,8 @@ export class ClientSession implements IClientSession {
/** /**
* Helper method to either call ChangeKernel on current session, or start a new session * Helper method to either call ChangeKernel on current session, or start a new session
*/ */
private async doChangeKernel(options: nb.IKernelSpec): Promise<nb.IKernel> { private async doChangeKernel(options: nb.IKernelSpec): Promise<nb.IKernel | undefined> {
let kernel: nb.IKernel; let kernel: nb.IKernel | undefined;
if (this._session) { if (this._session) {
kernel = await this._session.changeKernel(options); kernel = await this._session.changeKernel(options);
await this.runKernelConfigActions(kernel.name); await this.runKernelConfigActions(kernel.name);
@@ -289,7 +291,7 @@ export class ClientSession implements IClientSession {
// TODO is there any case where skipping causes errors? So far it seems like it gets called twice // TODO is there any case where skipping causes errors? So far it seems like it gets called twice
return; return;
} }
if (connection.id !== '-1' && connection.id !== this._connectionId) { if (connection.id !== '-1' && connection.id !== this._connectionId && this._session) {
await this._session.configureConnection(connection); await this._session.configureConnection(connection);
this._connectionId = connection.id; this._connectionId = connection.id;
} }

View File

@@ -82,7 +82,7 @@ export interface IClientSession extends IDisposable {
/** /**
* The current kernel associated with the document. * The current kernel associated with the document.
*/ */
readonly kernel: nb.IKernel | null; readonly kernel: nb.IKernel | undefined;
/** /**
* The current path associated with the client session. * The current path associated with the client session.
@@ -133,7 +133,7 @@ export interface IClientSession extends IDisposable {
*/ */
readonly kernelDisplayName: string; readonly kernelDisplayName: string;
readonly cachedKernelSpec: nb.IKernelSpec; readonly cachedKernelSpec: nb.IKernelSpec | undefined;
/** /**
* Initializes the ClientSession, by starting the server and * Initializes the ClientSession, by starting the server and
@@ -149,7 +149,7 @@ export interface IClientSession extends IDisposable {
changeKernel( changeKernel(
options: nb.IKernelSpec, options: nb.IKernelSpec,
oldKernel?: nb.IKernel oldKernel?: nb.IKernel
): Promise<nb.IKernel>; ): Promise<nb.IKernel | undefined>;
/** /**
* Configure the current kernel associated with the document. * Configure the current kernel associated with the document.
@@ -222,7 +222,7 @@ export interface INotebookModel {
/** /**
* Cell List for this model * Cell List for this model
*/ */
readonly cells: ReadonlyArray<ICellModel>; readonly cells: ReadonlyArray<ICellModel> | undefined;
/** /**
* The active cell for this model. May be undefined * The active cell for this model. May be undefined
@@ -232,7 +232,7 @@ export interface INotebookModel {
/** /**
* Client Session in the notebook, used for sending requests to the notebook service * Client Session in the notebook, used for sending requests to the notebook service
*/ */
readonly clientSession: IClientSession; readonly clientSession: IClientSession | undefined;
/** /**
* Promise indicating when client session is ready to use. * Promise indicating when client session is ready to use.
*/ */
@@ -244,7 +244,7 @@ export interface INotebookModel {
/** /**
* LanguageInfo saved in the notebook * LanguageInfo saved in the notebook
*/ */
readonly languageInfo: nb.ILanguageInfo; readonly languageInfo: nb.ILanguageInfo | undefined;
/** /**
* Current default language for the notebook * Current default language for the notebook
*/ */
@@ -270,7 +270,7 @@ export interface INotebookModel {
* Event fired on first initialization of the kernels and * Event fired on first initialization of the kernels and
* on subsequent change events * on subsequent change events
*/ */
readonly kernelsChanged: Event<nb.IKernelSpec>; readonly kernelsChanged: Event<nb.IKernel>;
/** /**
* Default kernel * Default kernel
@@ -314,7 +314,7 @@ export interface INotebookModel {
/** /**
* Event fired on active cell change * Event fired on active cell change
*/ */
readonly onActiveCellChanged: Event<ICellModel>; readonly onActiveCellChanged: Event<ICellModel | undefined>;
/** /**
* Event fired on cell type change * Event fired on cell type change
@@ -389,7 +389,7 @@ export interface INotebookModel {
* Get the standardKernelWithProvider by name * Get the standardKernelWithProvider by name
* @param name The kernel name * @param name The kernel name
*/ */
getStandardKernelFromName(name: string): IStandardKernelWithProvider; getStandardKernelFromName(name: string): IStandardKernelWithProvider | undefined;
/** Event fired once we get call back from ConfigureConnection method in sqlops extension */ /** Event fired once we get call back from ConfigureConnection method in sqlops extension */
readonly onValidConnectionSelected: Event<boolean>; readonly onValidConnectionSelected: Event<boolean>;

View File

@@ -49,43 +49,43 @@ export class NotebookModel extends Disposable implements INotebookModel {
private _contextsChangedEmitter = new Emitter<void>(); private _contextsChangedEmitter = new Emitter<void>();
private _contextsLoadingEmitter = new Emitter<void>(); private _contextsLoadingEmitter = new Emitter<void>();
private _contentChangedEmitter = new Emitter<NotebookContentChange>(); private _contentChangedEmitter = new Emitter<NotebookContentChange>();
private _kernelsChangedEmitter = new Emitter<nb.IKernelSpec>(); private _kernelsChangedEmitter = new Emitter<nb.IKernel>();
private _kernelChangedEmitter = new Emitter<nb.IKernelChangedArgs>(); private _kernelChangedEmitter = new Emitter<nb.IKernelChangedArgs>();
private _layoutChanged = new Emitter<void>(); private _layoutChanged = new Emitter<void>();
private _inErrorState: boolean = false; private _inErrorState: boolean = false;
private _activeClientSession: IClientSession; private _activeClientSession: IClientSession | undefined;
private _sessionLoadFinished = new Deferred<void>(); private _sessionLoadFinished = new Deferred<void>();
private _onClientSessionReady = new Emitter<IClientSession>(); private _onClientSessionReady = new Emitter<IClientSession>();
private _onProviderIdChanged = new Emitter<string>(); private _onProviderIdChanged = new Emitter<string>();
private _trustedMode: boolean; private _trustedMode: boolean;
private _onActiveCellChanged = new Emitter<ICellModel>(); private _onActiveCellChanged = new Emitter<ICellModel | undefined>();
private _onCellTypeChanged = new Emitter<ICellModel>(); private _onCellTypeChanged = new Emitter<ICellModel>();
private _cells: ICellModel[]; private _cells: ICellModel[] | undefined;
private _defaultLanguageInfo: nb.ILanguageInfo; private _defaultLanguageInfo: nb.ILanguageInfo | undefined;
private _tags: string[]; private _tags: string[] | undefined;
private _existingMetadata = {}; private _existingMetadata: nb.INotebookMetadata = {};
private _language: string; private _language: string = '';
private _onErrorEmitter = new Emitter<INotification>(); private _onErrorEmitter = new Emitter<INotification>();
private _savedKernelInfo: nb.IKernelInfo; private _savedKernelInfo: nb.IKernelSpec | undefined;
private readonly _nbformat: number = nbversion.MAJOR_VERSION; private readonly _nbformat: number = nbversion.MAJOR_VERSION;
private readonly _nbformatMinor: number = nbversion.MINOR_VERSION; private readonly _nbformatMinor: number = nbversion.MINOR_VERSION;
private _activeConnection: ConnectionProfile; private _activeConnection: ConnectionProfile | undefined;
private _activeCell: ICellModel; private _activeCell: ICellModel | undefined;
private _providerId: string; private _providerId: string;
private _defaultKernel: nb.IKernelSpec; private _defaultKernel: nb.IKernelSpec;
private _kernelDisplayNameToConnectionProviderIds: Map<string, string[]> = new Map<string, string[]>(); private _kernelDisplayNameToConnectionProviderIds: Map<string, string[]> = new Map<string, string[]>();
private _kernelDisplayNameToNotebookProviderIds: Map<string, string> = new Map<string, string>(); private _kernelDisplayNameToNotebookProviderIds: Map<string, string> = new Map<string, string>();
private _onValidConnectionSelected = new Emitter<boolean>(); private _onValidConnectionSelected = new Emitter<boolean>();
private _oldKernel: nb.IKernel; private _oldKernel: nb.IKernel | undefined;
private _connectionUrisToDispose: string[] = []; private _connectionUrisToDispose: string[] = [];
private _textCellsLoading: number = 0; private _textCellsLoading: number = 0;
private _standardKernels: notebookUtils.IStandardKernelWithProvider[]; private _standardKernels: notebookUtils.IStandardKernelWithProvider[] = [];
private _kernelAliases: string[] = []; private _kernelAliases: string[] = [];
private _currentKernelAlias: string; private _currentKernelAlias: string | undefined;
private _selectedKernelDisplayName: string; private _selectedKernelDisplayName: string | undefined;
public requestConnectionHandler: () => Promise<boolean>; public requestConnectionHandler: (() => Promise<boolean>) | undefined;
constructor( constructor(
private _notebookOptions: INotebookModelOptions, private _notebookOptions: INotebookModelOptions,
@@ -117,7 +117,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
return notebookManagers; return notebookManagers;
} }
public get notebookManager(): INotebookManager { public get notebookManager(): INotebookManager | undefined {
let manager = this.notebookManagers.find(manager => manager.providerId === this._providerId); let manager = this.notebookManagers.find(manager => manager.providerId === this._providerId);
if (!manager) { if (!manager) {
// Note: this seems like a less than ideal scenario. We should ideally pass in the "correct" provider ID and allow there to be a default, // Note: this seems like a less than ideal scenario. We should ideally pass in the "correct" provider ID and allow there to be a default,
@@ -127,7 +127,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
return manager; return manager;
} }
public getNotebookManager(providerId: string): INotebookManager { public getNotebookManager(providerId: string): INotebookManager | undefined {
if (providerId) { if (providerId) {
return this.notebookManagers.find(manager => manager.providerId === providerId); return this.notebookManagers.find(manager => manager.providerId === providerId);
} }
@@ -147,7 +147,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
public get hasServerManager(): boolean { public get hasServerManager(): boolean {
// If the service has a server manager, then we can show the start button // If the service has a server manager, then we can show the start button
return !!this.notebookManager.serverManager; return !!this.notebookManager?.serverManager;
} }
public get contentChanged(): Event<NotebookContentChange> { public get contentChanged(): Event<NotebookContentChange> {
@@ -163,7 +163,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
* plus startup of the session manager which can return key metadata about the * plus startup of the session manager which can return key metadata about the
* notebook environment * notebook environment
*/ */
public get clientSession(): IClientSession { public get clientSession(): IClientSession | undefined {
return this._activeClientSession; return this._activeClientSession;
} }
@@ -171,7 +171,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._kernelChangedEmitter.event; return this._kernelChangedEmitter.event;
} }
public get kernelsChanged(): Event<nb.IKernelSpec> { public get kernelsChanged(): Event<nb.IKernel> {
return this._kernelsChangedEmitter.event; return this._kernelsChangedEmitter.event;
} }
@@ -191,17 +191,17 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._contextsLoadingEmitter.event; return this._contextsLoadingEmitter.event;
} }
public get cells(): ICellModel[] { public get cells(): ICellModel[] | undefined {
return this._cells; return this._cells;
} }
public get context(): ConnectionProfile { public get context(): ConnectionProfile | undefined {
return this._activeConnection; return this._activeConnection;
} }
public get specs(): nb.IAllKernels | undefined { public get specs(): nb.IAllKernels | undefined {
let specs: nb.IAllKernels = { let specs: nb.IAllKernels = {
defaultKernel: undefined, defaultKernel: '',
kernels: [] kernels: []
}; };
this.notebookManagers.forEach(manager => { this.notebookManagers.forEach(manager => {
@@ -241,11 +241,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._kernelAliases; return this._kernelAliases;
} }
public get currentKernelAlias(): string { public get currentKernelAlias(): string | undefined {
return this._currentKernelAlias; return this._currentKernelAlias;
} }
public get selectedKernelDisplayName(): string { public get selectedKernelDisplayName(): string | undefined {
return this._selectedKernelDisplayName; return this._selectedKernelDisplayName;
} }
@@ -296,7 +296,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._onValidConnectionSelected.event; return this._onValidConnectionSelected.event;
} }
public get onActiveCellChanged(): Event<ICellModel> { public get onActiveCellChanged(): Event<ICellModel | undefined> {
return this._onActiveCellChanged.event; return this._onActiveCellChanged.event;
} }
@@ -308,13 +308,13 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._standardKernels; return this._standardKernels;
} }
public set standardKernels(kernels) { public set standardKernels(kernels: notebookUtils.IStandardKernelWithProvider[]) {
this._standardKernels = kernels; this._standardKernels = kernels;
this.setKernelDisplayNameMapsWithStandardKernels(); this.setKernelDisplayNameMapsWithStandardKernels();
} }
public getApplicableConnectionProviderIds(kernelDisplayName: string): string[] { public getApplicableConnectionProviderIds(kernelDisplayName: string): string[] {
let ids = []; let ids;
if (kernelDisplayName) { if (kernelDisplayName) {
ids = this._kernelDisplayNameToConnectionProviderIds.get(kernelDisplayName); ids = this._kernelDisplayNameToConnectionProviderIds.get(kernelDisplayName);
} }
@@ -325,7 +325,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
try { try {
this._trustedMode = isTrusted; this._trustedMode = isTrusted;
let contents = null; let contents: nb.INotebookContents | undefined;
if (this._notebookOptions && this._notebookOptions.contentManager) { if (this._notebookOptions && this._notebookOptions.contentManager) {
contents = await this._notebookOptions.contentManager.loadContent(); contents = await this._notebookOptions.contentManager.loadContent();
@@ -334,16 +334,17 @@ export class NotebookModel extends Disposable implements INotebookModel {
// if cells already exist, create them with language info (if it is saved) // if cells already exist, create them with language info (if it is saved)
this._cells = []; this._cells = [];
if (contents) { if (contents) {
this._defaultLanguageInfo = contents.metadata && contents.metadata.language_info; this._defaultLanguageInfo = contents.metadata?.language_info;
this._savedKernelInfo = this.getSavedKernelInfo(contents); this._savedKernelInfo = this.getSavedKernelInfo(contents);
if (contents.metadata) { if (contents.metadata) {
//Telemetry of loading notebook //Telemetry of loading notebook
if (contents.metadata.azdata_notebook_guid && contents.metadata.azdata_notebook_guid.length === 36) { let metadata: any = contents.metadata;
if (metadata.azdata_notebook_guid && metadata.azdata_notebook_guid.length === 36) {
//Verify if it is actual GUID and then send it to the telemetry //Verify if it is actual GUID and then send it to the telemetry
let regex = new RegExp('(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}'); let regex = new RegExp('(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}');
if (regex.test(contents.metadata.azdata_notebook_guid)) { if (regex.test(metadata.azdata_notebook_guid)) {
this.adstelemetryService.createActionEvent(TelemetryKeys.TelemetryView.Notebook, TelemetryKeys.TelemetryAction.Open) this.adstelemetryService.createActionEvent(TelemetryKeys.TelemetryView.Notebook, TelemetryKeys.TelemetryAction.Open)
.withAdditionalProperties({ azdata_notebook_guid: contents.metadata.azdata_notebook_guid }) .withAdditionalProperties({ azdata_notebook_guid: metadata.azdata_notebook_guid })
.send(); .send();
} }
} }
@@ -399,9 +400,9 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._cells.findIndex(cell => cell.equals(cellModel)); return this._cells.findIndex(cell => cell.equals(cellModel));
} }
public addCell(cellType: CellType, index?: number): ICellModel { public addCell(cellType: CellType, index?: number): ICellModel | undefined {
if (this.inErrorState) { if (this.inErrorState) {
return null; return undefined;
} }
let cell = this.createCell(cellType); let cell = this.createCell(cellType);
@@ -425,7 +426,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
moveCell(cell: ICellModel, direction: MoveDirection): void { moveCell(cell: ICellModel, direction: MoveDirection): void {
if (this.inErrorState) { if (this.inErrorState) {
return null; return;
} }
let index = this.findCellIndex(cell); let index = this.findCellIndex(cell);
@@ -457,12 +458,12 @@ export class NotebookModel extends Disposable implements INotebookModel {
}); });
} }
public updateActiveCell(cell: ICellModel): void { public updateActiveCell(cell?: ICellModel): void {
if (this._activeCell) { if (this._activeCell) {
this._activeCell.active = false; this._activeCell.active = false;
} }
this._activeCell = cell; this._activeCell = cell;
if (cell) { if (this._activeCell) {
this._activeCell.active = true; this._activeCell.active = true;
} }
this._onActiveCellChanged.fire(cell); this._onActiveCellChanged.fire(cell);
@@ -501,7 +502,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
if (index > -1) { if (index > -1) {
this._cells.splice(index, 1); this._cells.splice(index, 1);
if (this._activeCell === cellModel) { if (this._activeCell === cellModel) {
this.updateActiveCell(undefined); this.updateActiveCell();
} }
this._contentChangedEmitter.fire({ this._contentChangedEmitter.fire({
changeType: NotebookChangeType.CellsModified, changeType: NotebookChangeType.CellsModified,
@@ -537,7 +538,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
} }
} }
public get activeCell(): ICellModel { public get activeCell(): ICellModel | undefined {
return this._activeCell; return this._activeCell;
} }
@@ -546,7 +547,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
} }
public async startSession(manager: INotebookManager, displayName?: string, setErrorStateOnFail?: boolean, kernelAlias?: string): Promise<void> { public async startSession(manager: INotebookManager, displayName?: string, setErrorStateOnFail?: boolean, kernelAlias?: string): Promise<void> {
if (displayName && this._standardKernels) { if (displayName) {
let standardKernel = this._standardKernels.find(kernel => kernel.displayName === displayName); let standardKernel = this._standardKernels.find(kernel => kernel.displayName === displayName);
if (standardKernel) { if (standardKernel) {
this._defaultKernel = { name: standardKernel.name, display_name: standardKernel.displayName }; this._defaultKernel = { name: standardKernel.name, display_name: standardKernel.displayName };
@@ -641,7 +642,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
this._defaultKernel = notebookConstants.sqlKernelSpec; this._defaultKernel = notebookConstants.sqlKernelSpec;
this._providerId = SQL_NOTEBOOK_PROVIDER; this._providerId = SQL_NOTEBOOK_PROVIDER;
} }
if (!this._defaultLanguageInfo || this._defaultLanguageInfo.name) { if (!this._defaultLanguageInfo?.name) {
// update default language // update default language
this._defaultLanguageInfo = { this._defaultLanguageInfo = {
name: this._providerId === SQL_NOTEBOOK_PROVIDER ? 'sql' : 'python', name: this._providerId === SQL_NOTEBOOK_PROVIDER ? 'sql' : 'python',
@@ -651,10 +652,9 @@ export class NotebookModel extends Disposable implements INotebookModel {
} }
private isValidConnection(profile: IConnectionProfile | connection.Connection) { private isValidConnection(profile: IConnectionProfile | connection.Connection) {
if (this._standardKernels) {
let standardKernels = this._standardKernels.find(kernel => this._defaultKernel && kernel.displayName === this._defaultKernel.display_name); let standardKernels = this._standardKernels.find(kernel => this._defaultKernel && kernel.displayName === this._defaultKernel.display_name);
let connectionProviderIds = standardKernels ? standardKernels.connectionProviderIds : undefined; let connectionProviderIds = standardKernels ? standardKernels.connectionProviderIds : undefined;
let providerFeatures = this._capabilitiesService.getCapabilities(profile.providerName); let providerFeatures = this._capabilitiesService?.getCapabilities(profile.providerName);
if (connectionProviderIds?.length) { if (connectionProviderIds?.length) {
this._currentKernelAlias = providerFeatures?.connection.notebookKernelAlias; this._currentKernelAlias = providerFeatures?.connection.notebookKernelAlias;
// Switching from Kusto to another kernel should set the currentKernelAlias to undefined // Switching from Kusto to another kernel should set the currentKernelAlias to undefined
@@ -667,30 +667,28 @@ export class NotebookModel extends Disposable implements INotebookModel {
} }
return this._currentKernelAlias || profile && connectionProviderIds && connectionProviderIds.find(provider => provider === profile.providerName) !== undefined; return this._currentKernelAlias || profile && connectionProviderIds && connectionProviderIds.find(provider => provider === profile.providerName) !== undefined;
} }
return false;
}
public getStandardKernelFromName(name: string): notebookUtils.IStandardKernelWithProvider { public getStandardKernelFromName(name: string): notebookUtils.IStandardKernelWithProvider | undefined {
if (name && this._standardKernels) { if (name) {
let kernel = this._standardKernels.find(kernel => kernel.name.toLowerCase() === name.toLowerCase()); let kernel = this._standardKernels.find(kernel => kernel.name.toLowerCase() === name.toLowerCase());
return kernel; return kernel;
} }
return undefined; return undefined;
} }
public getStandardKernelFromDisplayName(displayName: string): notebookUtils.IStandardKernelWithProvider { public getStandardKernelFromDisplayName(displayName: string): notebookUtils.IStandardKernelWithProvider | undefined {
if (displayName && this._standardKernels) { if (displayName) {
let kernel = this._standardKernels.find(kernel => kernel.displayName.toLowerCase() === displayName.toLowerCase()); let kernel = this._standardKernels.find(kernel => kernel.displayName.toLowerCase() === displayName.toLowerCase());
return kernel; return kernel;
} }
return undefined; return undefined;
} }
public get tags(): string[] { public get tags(): string[] | undefined {
return this._tags; return this._tags;
} }
public get languageInfo(): nb.ILanguageInfo { public get languageInfo(): nb.ILanguageInfo | undefined {
return this._defaultLanguageInfo; return this._defaultLanguageInfo;
} }
@@ -710,7 +708,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
// If the "name" property isn't defined, check the "mimeType" property // If the "name" property isn't defined, check the "mimeType" property
// Otherwise, default to python as the language // Otherwise, default to python as the language
let languageInfo = this.languageInfo; let languageInfo = this.languageInfo;
let language: string; let language: string = '';
if (languageInfo) { if (languageInfo) {
if (languageInfo.codemirror_mode) { if (languageInfo.codemirror_mode) {
let codeMirrorMode: nb.ICodeMirrorMode = <nb.ICodeMirrorMode>(languageInfo.codemirror_mode); let codeMirrorMode: nb.ICodeMirrorMode = <nb.ICodeMirrorMode>(languageInfo.codemirror_mode);
@@ -736,6 +734,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
} else if (language.toLowerCase() === 'c#') { } else if (language.toLowerCase() === 'c#') {
language = 'cs'; language = 'cs';
} }
} else {
language = 'python';
} }
this._language = language.toLowerCase(); this._language = language.toLowerCase();
@@ -743,8 +743,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
public changeKernel(displayName: string): void { public changeKernel(displayName: string): void {
this._selectedKernelDisplayName = displayName; this._selectedKernelDisplayName = displayName;
this._currentKernelAlias = this.context?.serverCapabilities.notebookKernelAlias; this._currentKernelAlias = this.context?.serverCapabilities?.notebookKernelAlias;
if (this.kernelAliases.includes(this.currentKernelAlias) && displayName === this.currentKernelAlias) { if (this._currentKernelAlias && this.kernelAliases.includes(this._currentKernelAlias) && displayName === this._currentKernelAlias) {
this.doChangeKernel(displayName, true).catch(e => this.logService.error(e)); this.doChangeKernel(displayName, true).catch(e => this.logService.error(e));
} else { } else {
this._currentKernelAlias = undefined; this._currentKernelAlias = undefined;
@@ -759,7 +759,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
return; return;
} }
let oldDisplayName = this._activeClientSession && this._activeClientSession.kernel ? this._activeClientSession.kernel.name : undefined; let oldDisplayName = this._activeClientSession && this._activeClientSession.kernel ? this._activeClientSession.kernel.name : undefined;
let nbKernelAlias: string; let nbKernelAlias: string | undefined;
if (this.kernelAliases.includes(displayName)) { if (this.kernelAliases.includes(displayName)) {
this._currentKernelAlias = displayName; this._currentKernelAlias = displayName;
displayName = 'SQL'; displayName = 'SQL';
@@ -778,7 +778,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
if (this._activeClientSession && this._activeClientSession.isReady) { if (this._activeClientSession && this._activeClientSession.isReady) {
let kernel = await this._activeClientSession.changeKernel(spec, this._oldKernel); let kernel = await this._activeClientSession.changeKernel(spec, this._oldKernel);
try { try {
await kernel.ready; await kernel?.ready;
await this.updateKernelInfoOnKernelChange(kernel, nbKernelAlias); await this.updateKernelInfoOnKernelChange(kernel, nbKernelAlias);
} catch (err2) { } catch (err2) {
// TODO should we handle this in any way? // TODO should we handle this in any way?
@@ -827,7 +827,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
// Ensure that the kernel we try to switch to is a valid kernel; if not, use the default // Ensure that the kernel we try to switch to is a valid kernel; if not, use the default
let kernelSpecs = this.getKernelSpecs(); let kernelSpecs = this.getKernelSpecs();
if (kernelSpecs && kernelSpecs.length > 0 && kernelSpecs.findIndex(k => k.display_name === spec.display_name) < 0) { if (kernelSpecs && kernelSpecs.length > 0 && kernelSpecs.findIndex(k => k.display_name === spec.display_name) < 0) {
spec = kernelSpecs.find(spec => spec.name === this.notebookManager.sessionManager.specs.defaultKernel); spec = kernelSpecs.find(spec => spec.name === this.notebookManager?.sessionManager.specs.defaultKernel);
} }
} }
else { else {
@@ -874,6 +874,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
private setActiveConnectionIfDifferent(newConnection: ConnectionProfile) { private setActiveConnectionIfDifferent(newConnection: ConnectionProfile) {
if (this.isValidConnection(newConnection) && if (this.isValidConnection(newConnection) &&
this._activeConnection &&
this._activeConnection.id !== '-1' && this._activeConnection.id !== '-1' &&
this._activeConnection.id !== newConnection.id) { this._activeConnection.id !== newConnection.id) {
// Change the active connection to newConnection // Change the active connection to newConnection
@@ -883,11 +884,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
// Get default kernel info if saved in notebook file // Get default kernel info if saved in notebook file
private getSavedKernelInfo(notebook: nb.INotebookContents): nb.IKernelInfo { private getSavedKernelInfo(notebook: nb.INotebookContents): nb.IKernelSpec | undefined {
return (notebook && notebook.metadata && notebook.metadata.kernelspec) ? notebook.metadata.kernelspec : undefined; return (notebook && notebook.metadata && notebook.metadata.kernelspec) ? notebook.metadata.kernelspec : undefined;
} }
private getKernelSpecFromDisplayName(displayName: string): nb.IKernelSpec { private getKernelSpecFromDisplayName(displayName: string): nb.IKernelSpec | undefined {
let kernel: nb.IKernelSpec = this.specs.kernels.find(k => k.display_name.toLowerCase() === displayName.toLowerCase()); let kernel: nb.IKernelSpec = this.specs.kernels.find(k => k.display_name.toLowerCase() === displayName.toLowerCase());
if (!kernel) { if (!kernel) {
return undefined; // undefined is handled gracefully in the session to default to the default kernel return undefined; // undefined is handled gracefully in the session to default to the default kernel
@@ -897,14 +898,13 @@ export class NotebookModel extends Disposable implements INotebookModel {
return kernel; return kernel;
} }
private sanitizeSavedKernelInfo() { private sanitizeSavedKernelInfo(): void {
if (this._savedKernelInfo) { if (this._savedKernelInfo) {
let displayName = this._savedKernelInfo.display_name; let displayName = this._savedKernelInfo.display_name;
if (this._savedKernelInfo.display_name !== displayName) { if (this._savedKernelInfo.display_name !== displayName) {
this._savedKernelInfo.display_name = displayName; this._savedKernelInfo.display_name = displayName;
} }
if (this._standardKernels) {
let standardKernel = this._standardKernels.find(kernel => kernel.displayName === displayName || startsWith(displayName, kernel.displayName)); let standardKernel = this._standardKernels.find(kernel => kernel.displayName === displayName || startsWith(displayName, kernel.displayName));
if (standardKernel && this._savedKernelInfo.name && this._savedKernelInfo.name !== standardKernel.name) { if (standardKernel && this._savedKernelInfo.name && this._savedKernelInfo.name !== standardKernel.name) {
this._savedKernelInfo.name = standardKernel.name; this._savedKernelInfo.name = standardKernel.name;
@@ -912,10 +912,9 @@ export class NotebookModel extends Disposable implements INotebookModel {
} }
} }
} }
}
public getDisplayNameFromSpecName(kernel: nb.IKernel): string { public getDisplayNameFromSpecName(kernel: nb.IKernel): string | undefined {
let specs = this.notebookManager.sessionManager.specs; let specs = this.notebookManager?.sessionManager.specs;
if (!specs || !specs.kernels) { if (!specs || !specs.kernels) {
return kernel.name; return kernel.name;
} }
@@ -972,7 +971,10 @@ export class NotebookModel extends Disposable implements INotebookModel {
private async loadActiveContexts(kernelChangedArgs: nb.IKernelChangedArgs): Promise<void> { private async loadActiveContexts(kernelChangedArgs: nb.IKernelChangedArgs): Promise<void> {
if (kernelChangedArgs && kernelChangedArgs.newValue && kernelChangedArgs.newValue.name) { if (kernelChangedArgs && kernelChangedArgs.newValue && kernelChangedArgs.newValue.name) {
let kernelDisplayName = this.getDisplayNameFromSpecName(kernelChangedArgs.newValue); let kernelDisplayName = this.getDisplayNameFromSpecName(kernelChangedArgs.newValue);
let context = NotebookContexts.getContextForKernel(this._activeConnection, this.getApplicableConnectionProviderIds(kernelDisplayName)); let context;
if (this._activeConnection) {
context = NotebookContexts.getContextForKernel(this._activeConnection, this.getApplicableConnectionProviderIds(kernelDisplayName));
}
if (context !== undefined && context.serverName !== undefined && context.title !== undefined) { if (context !== undefined && context.serverName !== undefined && context.title !== undefined) {
await this.changeContext(context.title, context); await this.changeContext(context.title, context);
} }
@@ -989,7 +991,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
display_name: spec.display_name, display_name: spec.display_name,
language: spec.language language: spec.language
}; };
this.clientSession.configureKernel(this._savedKernelInfo); this.clientSession?.configureKernel(this._savedKernelInfo);
} catch (err) { } catch (err) {
// Don't worry about this for now. Just use saved values // Don't worry about this for now. Just use saved values
} }
@@ -1024,7 +1026,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
return false; return false;
} }
private tryFindProviderForKernel(displayName: string, alwaysReturnId: boolean = false): string { private tryFindProviderForKernel(displayName: string, alwaysReturnId: boolean = false): string | undefined {
if (!displayName) { if (!displayName) {
return undefined; return undefined;
} }
@@ -1064,7 +1066,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
// Disconnect any connections that were added through the "Change connection" functionality in the Attach To dropdown // Disconnect any connections that were added through the "Change connection" functionality in the Attach To dropdown
private async disconnectAttachToConnections(): Promise<void> { private async disconnectAttachToConnections(): Promise<void> {
notebookUtils.asyncForEach(this._connectionUrisToDispose, async conn => { notebookUtils.asyncForEach(this._connectionUrisToDispose, async (conn: string) => {
await this.notebookOptions.connectionService.disconnect(conn).catch(e => this.logService.error(e)); await this.notebookOptions.connectionService.disconnect(conn).catch(e => this.logService.error(e));
}); });
this._connectionUrisToDispose = []; this._connectionUrisToDispose = [];
@@ -1095,7 +1097,6 @@ export class NotebookModel extends Disposable implements INotebookModel {
* provider and notebook provider ids from a kernel display name * provider and notebook provider ids from a kernel display name
*/ */
private setKernelDisplayNameMapsWithStandardKernels(): void { private setKernelDisplayNameMapsWithStandardKernels(): void {
if (this._standardKernels) {
this._standardKernels.forEach(kernel => { this._standardKernels.forEach(kernel => {
let displayName = kernel.displayName; let displayName = kernel.displayName;
if (!displayName) { if (!displayName) {
@@ -1105,13 +1106,12 @@ export class NotebookModel extends Disposable implements INotebookModel {
this._kernelDisplayNameToNotebookProviderIds.set(displayName, kernel.notebookProvider); this._kernelDisplayNameToNotebookProviderIds.set(displayName, kernel.notebookProvider);
}); });
} }
}
/** /**
* Serialize the model to JSON. * Serialize the model to JSON.
*/ */
toJSON(): nb.INotebookContents { toJSON(): nb.INotebookContents {
let cells: nb.ICellContents[] = this.cells.map(c => c.toJSON()); let cells: nb.ICellContents[] = this.cells?.map(c => c.toJSON());
let metadata = Object.create(null) as nb.INotebookMetadata; let metadata = Object.create(null) as nb.INotebookMetadata;
// TODO update language and kernel when these change // TODO update language and kernel when these change
metadata.kernelspec = this._savedKernelInfo; metadata.kernelspec = this._savedKernelInfo;
@@ -1150,7 +1150,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
serializationStateChanged(changeType: NotebookChangeType, cell?: ICellModel): void { serializationStateChanged(changeType: NotebookChangeType, cell?: ICellModel): void {
let changeInfo: NotebookContentChange = { let changeInfo: NotebookContentChange = {
changeType: changeType, changeType: changeType,
cells: [cell] cells: cell ? [cell] : []
}; };
this._contentChangedEmitter.fire(changeInfo); this._contentChangedEmitter.fire(changeInfo);

View File

@@ -28,7 +28,7 @@ export class SqlNotebookManager implements nb.NotebookProvider {
return this._contentManager; return this._contentManager;
} }
public get serverManager(): nb.ServerManager { public get serverManager(): nb.ServerManager | undefined {
return undefined; return undefined;
} }

View File

@@ -51,6 +51,26 @@ export interface SQLData {
rows: Array<Array<string>>; rows: Array<Array<string>>;
} }
export interface NotebookConfig {
cellToolbarLocation: string;
collapseBookItems: boolean;
diff: { enablePreview: boolean };
displayOrder: Array<string>;
kernelProviderAssociations: Array<string>;
maxBookSearchDepth: number;
maxTableRows: number;
overrideEditorTheming: boolean;
pinnedNotebooks: Array<string>;
pythonPath: string;
remoteBookDownloadTimeout: number;
showAllKernels: boolean;
showCellStatusBar: boolean;
showNotebookConvertActions: boolean;
sqlStopOnError: boolean;
trustedBooks: Array<string>;
useExistingPython: boolean;
}
export class SqlSessionManager implements nb.SessionManager { export class SqlSessionManager implements nb.SessionManager {
private static _sessions: nb.ISession[] = []; private static _sessions: nb.ISession[] = [];
@@ -162,8 +182,8 @@ class SqlKernel extends Disposable implements nb.IKernel {
private _currentConnectionProfile: ConnectionProfile; private _currentConnectionProfile: ConnectionProfile;
static kernelId: number = 0; static kernelId: number = 0;
private _id: string; private _id: string | undefined;
private _future: SQLFuture; private _future: SQLFuture | undefined;
private _executionCount: number = 0; private _executionCount: number = 0;
private _magicToExecutorMap = new Map<string, ExternalScriptMagic>(); private _magicToExecutorMap = new Map<string, ExternalScriptMagic>();
private _connectionPath: string; private _connectionPath: string;
@@ -301,7 +321,7 @@ class SqlKernel extends Disposable implements nb.IKernel {
} }
// TODO should we cleanup old future? I don't think we need to // TODO should we cleanup old future? I don't think we need to
return this._future; return <nb.IFuture>this._future;
} }
private getCodeWithoutCellMagic(content: nb.IExecuteRequest): string { private getCodeWithoutCellMagic(content: nb.IExecuteRequest): string {
@@ -377,9 +397,9 @@ class SqlKernel extends Disposable implements nb.IKernel {
} }
export class SQLFuture extends Disposable implements FutureInternal { export class SQLFuture extends Disposable implements FutureInternal {
private _msg: nb.IMessage = undefined; private _msg: nb.IMessage | undefined;
private ioHandler: nb.MessageHandler<nb.IIOPubMessage>; private ioHandler: nb.MessageHandler<nb.IIOPubMessage> | undefined;
private doneHandler: nb.MessageHandler<nb.IShellMessage>; private doneHandler: nb.MessageHandler<nb.IShellMessage> | undefined;
private doneDeferred = new Deferred<nb.IShellMessage>(); private doneDeferred = new Deferred<nb.IShellMessage>();
private configuredMaxRows: number = MAX_ROWS; private configuredMaxRows: number = MAX_ROWS;
private _outputAddedPromises: Promise<void>[] = []; private _outputAddedPromises: Promise<void>[] = [];
@@ -387,13 +407,13 @@ export class SQLFuture extends Disposable implements FutureInternal {
private _errorOccurred: boolean = false; private _errorOccurred: boolean = false;
private _stopOnError: boolean = true; private _stopOnError: boolean = true;
constructor( constructor(
private _queryRunner: QueryRunner, private _queryRunner: QueryRunner | undefined,
private _executionCount: number | undefined, private _executionCount: number | undefined,
configurationService: IConfigurationService, configurationService: IConfigurationService,
private readonly logService: ILogService private readonly logService: ILogService
) { ) {
super(); super();
let config = configurationService.getValue(NotebookConfigSectionName); let config: NotebookConfig = configurationService.getValue(NotebookConfigSectionName);
if (config) { if (config) {
let maxRows = config[MaxTableRowsConfigName] ? config[MaxTableRowsConfigName] : undefined; let maxRows = config[MaxTableRowsConfigName] ? config[MaxTableRowsConfigName] : undefined;
if (maxRows && maxRows > 0) { if (maxRows && maxRows > 0) {
@@ -404,14 +424,16 @@ export class SQLFuture extends Disposable implements FutureInternal {
} }
get inProgress(): boolean { get inProgress(): boolean {
return this._queryRunner && !this._queryRunner.hasCompleted; return this._queryRunner ? !this._queryRunner.hasCompleted : false;
} }
set inProgress(val: boolean) { set inProgress(val: boolean) {
if (this._queryRunner && !val) { if (this._queryRunner && !val) {
this._queryRunner.cancelQuery().catch(err => onUnexpectedError(err)); this._queryRunner.cancelQuery().catch(err => onUnexpectedError(err));
} }
} }
get msg(): nb.IMessage {
get msg(): nb.IMessage | undefined {
return this._msg; return this._msg;
} }
@@ -468,9 +490,11 @@ export class SQLFuture extends Disposable implements FutureInternal {
message = this.convertToDisplayMessage(msg); message = this.convertToDisplayMessage(msg);
} }
} }
if (message) {
this.ioHandler.handle(message); this.ioHandler.handle(message);
} }
} }
}
public handleBatchEnd(batch: BatchSummary): void { public handleBatchEnd(batch: BatchSummary): void {
if (this.ioHandler) { if (this.ioHandler) {
@@ -545,7 +569,7 @@ export class SQLFuture extends Disposable implements FutureInternal {
metadata: undefined, metadata: undefined,
parent_header: undefined parent_header: undefined
}; };
this.ioHandler.handle(msg); this.ioHandler?.handle(msg);
this._querySubsetResultMap.delete(resultSet.id); this._querySubsetResultMap.delete(resultSet.id);
} }
@@ -605,7 +629,7 @@ export class SQLFuture extends Disposable implements FutureInternal {
return htmlStringArr; return htmlStringArr;
} }
private convertToDisplayMessage(msg: IResultMessage | string): nb.IIOPubMessage { private convertToDisplayMessage(msg: IResultMessage | string): nb.IIOPubMessage | undefined {
if (msg) { if (msg) {
let msgData = typeof msg === 'string' ? msg : msg.message; let msgData = typeof msg === 'string' ? msg : msg.message;
return { return {
@@ -627,7 +651,7 @@ export class SQLFuture extends Disposable implements FutureInternal {
return undefined; return undefined;
} }
private convertToError(msg: IResultMessage | string): nb.IIOPubMessage { private convertToError(msg: IResultMessage | string): nb.IIOPubMessage | undefined {
this._errorOccurred = true; this._errorOccurred = true;
if (msg) { if (msg) {