mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
SQL Kernel Improvements/Removing Spark Code from Core/Attach to Changes (#3790)
* Scenarios work besides loading saved kernel * Fix compilation issue * Save and load functional * Fix loading kernesl issue when sql kernel is not enabled * Fix language mapping to not be hardcoded any longer * Remove unnecessary comment * PR Comments vol. 1 * Code cleanup, use ConnectionProfile instead of IConnectionProfile when accessing serverName * PR changes vol. 2 * One final comment for PR * Fix linting issue
This commit is contained in:
@@ -15,7 +15,7 @@ import { IQueryEditorOptions } from 'sql/parts/query/common/queryEditorService';
|
|||||||
import { QueryPlanInput } from 'sql/parts/queryPlan/queryPlanInput';
|
import { QueryPlanInput } from 'sql/parts/queryPlan/queryPlanInput';
|
||||||
import { NotebookInput, NotebookInputModel, NotebookInputValidator } from 'sql/parts/notebook/notebookInput';
|
import { NotebookInput, NotebookInputModel, NotebookInputValidator } from 'sql/parts/notebook/notebookInput';
|
||||||
import { DEFAULT_NOTEBOOK_PROVIDER, INotebookService } from 'sql/workbench/services/notebook/common/notebookService';
|
import { DEFAULT_NOTEBOOK_PROVIDER, INotebookService } from 'sql/workbench/services/notebook/common/notebookService';
|
||||||
import { getProvidersForFileName } from 'sql/parts/notebook/notebookUtils';
|
import { getProvidersForFileName, getStandardKernelsForProvider } from 'sql/parts/notebook/notebookUtils';
|
||||||
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -69,6 +69,10 @@ export function convertEditorInput(input: EditorInput, options: IQueryEditorOpti
|
|||||||
let notebookInputModel = new NotebookInputModel(uri, undefined, false, undefined);
|
let notebookInputModel = new NotebookInputModel(uri, undefined, false, undefined);
|
||||||
notebookInputModel.providerId = providerIds.filter(provider => provider !== DEFAULT_NOTEBOOK_PROVIDER)[0];
|
notebookInputModel.providerId = providerIds.filter(provider => provider !== DEFAULT_NOTEBOOK_PROVIDER)[0];
|
||||||
notebookInputModel.providers = providerIds;
|
notebookInputModel.providers = providerIds;
|
||||||
|
notebookInputModel.providers.forEach(provider => {
|
||||||
|
let standardKernels = getStandardKernelsForProvider(provider, notebookService);
|
||||||
|
notebookInputModel.standardKernels = standardKernels;
|
||||||
|
});
|
||||||
let notebookInput: NotebookInput = instantiationService.createInstance(NotebookInput, fileName, notebookInputModel);
|
let notebookInput: NotebookInput = instantiationService.createInstance(NotebookInput, fileName, notebookInputModel);
|
||||||
return notebookInput;
|
return notebookInput;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ let modelId = 0;
|
|||||||
|
|
||||||
|
|
||||||
export class CellModel implements ICellModel {
|
export class CellModel implements ICellModel {
|
||||||
private static LanguageMapping: Map<string, string>;
|
|
||||||
|
|
||||||
private _cellType: nb.CellType;
|
private _cellType: nb.CellType;
|
||||||
private _source: string;
|
private _source: string;
|
||||||
private _language: string;
|
private _language: string;
|
||||||
@@ -37,7 +35,6 @@ export class CellModel implements ICellModel {
|
|||||||
|
|
||||||
constructor(private factory: IModelFactory, cellData?: nb.ICellContents, private _options?: ICellModelOptions) {
|
constructor(private factory: IModelFactory, cellData?: nb.ICellContents, private _options?: ICellModelOptions) {
|
||||||
this.id = `${modelId++}`;
|
this.id = `${modelId++}`;
|
||||||
CellModel.CreateLanguageMappings();
|
|
||||||
if (cellData) {
|
if (cellData) {
|
||||||
// Read in contents if available
|
// Read in contents if available
|
||||||
this.fromJSON(cellData);
|
this.fromJSON(cellData);
|
||||||
@@ -238,9 +235,9 @@ export class CellModel implements ICellModel {
|
|||||||
try {
|
try {
|
||||||
let result = output as nb.IDisplayResult;
|
let result = output as nb.IDisplayResult;
|
||||||
if (result && result.data && result.data['text/html']) {
|
if (result && result.data && result.data['text/html']) {
|
||||||
let nbm = (this as CellModel).options.notebook as NotebookModel;
|
let model = (this as CellModel).options.notebook as NotebookModel;
|
||||||
if (nbm.hadoopConnection) {
|
if (model.activeConnection) {
|
||||||
let host = nbm.hadoopConnection.host;
|
let host = model.activeConnection.serverName;
|
||||||
let html = result.data['text/html'];
|
let html = result.data['text/html'];
|
||||||
html = html.replace(/(https?:\/\/mssql-master.*\/proxy)(.*)/g, function (a, b, c) {
|
html = html.replace(/(https?:\/\/mssql-master.*\/proxy)(.*)/g, function (a, b, c) {
|
||||||
let ret = '';
|
let ret = '';
|
||||||
@@ -321,18 +318,6 @@ export class CellModel implements ICellModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CreateLanguageMappings(): void {
|
|
||||||
if (CellModel.LanguageMapping) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CellModel.LanguageMapping = new Map<string, string>();
|
|
||||||
CellModel.LanguageMapping['pyspark'] = 'python';
|
|
||||||
CellModel.LanguageMapping['pyspark3'] = 'python';
|
|
||||||
CellModel.LanguageMapping['python'] = 'python';
|
|
||||||
CellModel.LanguageMapping['scala'] = 'scala';
|
|
||||||
CellModel.LanguageMapping['sql'] = 'sql';
|
|
||||||
}
|
|
||||||
|
|
||||||
private get languageInfo(): nb.ILanguageInfo {
|
private get languageInfo(): nb.ILanguageInfo {
|
||||||
if (this._options && this._options.notebook && this._options.notebook.languageInfo) {
|
if (this._options && this._options.notebook && this._options.notebook.languageInfo) {
|
||||||
return this._options.notebook.languageInfo;
|
return this._options.notebook.languageInfo;
|
||||||
@@ -371,17 +356,15 @@ export class CellModel implements ICellModel {
|
|||||||
// Otherwise, default to python as the language
|
// Otherwise, default to python as the language
|
||||||
let languageInfo = this.languageInfo;
|
let languageInfo = this.languageInfo;
|
||||||
if (languageInfo) {
|
if (languageInfo) {
|
||||||
if (languageInfo.name) {
|
if (languageInfo.codemirror_mode) {
|
||||||
// check the LanguageMapping to determine if a mapping is necessary (example 'pyspark' -> 'python')
|
let codeMirrorMode: nb.ICodeMirrorMode = <nb.ICodeMirrorMode>(languageInfo.codemirror_mode);
|
||||||
if (CellModel.LanguageMapping[languageInfo.name]) {
|
if (codeMirrorMode && codeMirrorMode.name) {
|
||||||
this._language = CellModel.LanguageMapping[languageInfo.name];
|
this._language = codeMirrorMode.name;
|
||||||
}
|
}
|
||||||
else {
|
} else if (languageInfo.mimetype) {
|
||||||
this._language = languageInfo.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (languageInfo.mimetype) {
|
|
||||||
this._language = languageInfo.mimetype;
|
this._language = languageInfo.mimetype;
|
||||||
|
} else if (languageInfo.name) {
|
||||||
|
this._language = languageInfo.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,8 @@ import { IClientSession, IKernelPreference, IClientSessionOptions } from './mode
|
|||||||
import { Deferred } from 'sql/base/common/promise';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
|
|
||||||
import * as notebookUtils from '../notebookUtils';
|
import * as notebookUtils from '../notebookUtils';
|
||||||
import * as sparkUtils from '../spark/sparkUtils';
|
|
||||||
import { INotebookManager } from 'sql/workbench/services/notebook/common/notebookService';
|
import { INotebookManager } from 'sql/workbench/services/notebook/common/notebookService';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import { NotebookConnection } from 'sql/parts/notebook/models/notebookConnection';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of a client session. This is a model over session operations,
|
* Implementation of a client session. This is a model over session operations,
|
||||||
@@ -49,7 +47,6 @@ export class ClientSession implements IClientSession {
|
|||||||
private _session: nb.ISession;
|
private _session: nb.ISession;
|
||||||
private isServerStarted: boolean;
|
private isServerStarted: boolean;
|
||||||
private notebookManager: INotebookManager;
|
private notebookManager: INotebookManager;
|
||||||
private _connection: NotebookConnection;
|
|
||||||
private _kernelConfigActions: ((kernelName: string) => Promise<any>)[] = [];
|
private _kernelConfigActions: ((kernelName: string) => Promise<any>)[] = [];
|
||||||
|
|
||||||
constructor(private options: IClientSessionOptions) {
|
constructor(private options: IClientSessionOptions) {
|
||||||
@@ -60,10 +57,8 @@ export class ClientSession implements IClientSession {
|
|||||||
this._kernelChangeCompleted = new Deferred<void>();
|
this._kernelChangeCompleted = new Deferred<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async initialize(connection?: NotebookConnection): Promise<void> {
|
public async initialize(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this._kernelConfigActions.push((kernelName: string) => { return this.runTasksBeforeSessionStart(kernelName); });
|
|
||||||
this._connection = connection;
|
|
||||||
this._serverLoadFinished = this.startServer();
|
this._serverLoadFinished = this.startServer();
|
||||||
await this._serverLoadFinished;
|
await this._serverLoadFinished;
|
||||||
await this.initializeSession();
|
await this.initializeSession();
|
||||||
@@ -114,7 +109,7 @@ export class ClientSession implements IClientSession {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
// TODO move registration
|
// TODO move registration
|
||||||
if (err && err.response && err.response.status === 501) {
|
if (err && err.response && err.response.status === 501) {
|
||||||
this.options.notificationService.warn(nls.localize('sparkKernelRequiresConnection', 'Kernel {0} was not found. The default kernel will be used instead.', kernelName));
|
this.options.notificationService.warn(nls.localize('kernelRequiresConnection', 'Kernel {0} was not found. The default kernel will be used instead.', kernelName));
|
||||||
session = await this.notebookManager.sessionManager.startNew({
|
session = await this.notebookManager.sessionManager.startNew({
|
||||||
path: this.notebookUri.fsPath,
|
path: this.notebookUri.fsPath,
|
||||||
kernelName: undefined
|
kernelName: undefined
|
||||||
@@ -256,41 +251,22 @@ export class ClientSession implements IClientSession {
|
|||||||
return kernel;
|
return kernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async runTasksBeforeSessionStart(kernelName: string): Promise<void> {
|
public async configureKernel(options: nb.IKernelSpec): Promise<void> {
|
||||||
// TODO we should move all Spark-related code to SparkMagicContext
|
if (this._session) {
|
||||||
if (this._session && this._connection && this.isSparkKernel(kernelName)) {
|
await this._session.configureKernel(options);
|
||||||
// TODO may need to reenable a way to get the credential
|
|
||||||
// await this._connection.getCredential();
|
|
||||||
// %_do_not_call_change_endpoint is a SparkMagic command that lets users change endpoint options,
|
|
||||||
// such as user/profile/host name/auth type
|
|
||||||
|
|
||||||
let server = URI.parse(sparkUtils.getLivyUrl(this._connection.host, this._connection.knoxport)).toString();
|
|
||||||
let doNotCallChangeEndpointParams =
|
|
||||||
`%_do_not_call_change_endpoint --username=${this._connection.user} --password=${this._connection.password} --server=${server} --auth=Basic_Access`;
|
|
||||||
let future = this._session.kernel.requestExecute({
|
|
||||||
code: doNotCallChangeEndpointParams
|
|
||||||
}, true);
|
|
||||||
await future.done;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateConnection(connection: NotebookConnection): Promise<void> {
|
public async updateConnection(connection: IConnectionProfile): Promise<void> {
|
||||||
if (!this.kernel) {
|
if (!this.kernel) {
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
this._connection = (connection.connectionProfile.id !== '-1') ? connection : this._connection;
|
if (connection.id !== '-1') {
|
||||||
// if kernel is not set, don't run kernel config actions
|
await this._session.configureConnection(connection);
|
||||||
// this should only occur when a cell is cancelled, which interrupts the kernel
|
|
||||||
if (this.kernel && this.kernel.name) {
|
|
||||||
await this.runKernelConfigActions(this.kernel.name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isSparkKernel(kernelName: string): any {
|
|
||||||
return kernelName && kernelName.toLowerCase().indexOf('spark') > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kill the kernel and shutdown the session.
|
* Kill the kernel and shutdown the session.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -17,9 +17,11 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
|||||||
import { CellType, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
|
import { CellType, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
|
||||||
import { INotebookManager } from 'sql/workbench/services/notebook/common/notebookService';
|
import { INotebookManager } from 'sql/workbench/services/notebook/common/notebookService';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import { NotebookConnection } from 'sql/parts/notebook/models/notebookConnection';
|
|
||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
import { IStandardKernelWithProvider } from 'sql/parts/notebook/notebookUtils';
|
||||||
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
|
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
|
|
||||||
export interface IClientSessionOptions {
|
export interface IClientSessionOptions {
|
||||||
notebookUri: URI;
|
notebookUri: URI;
|
||||||
@@ -131,7 +133,7 @@ export interface IClientSession extends IDisposable {
|
|||||||
* This will optionally start a session if the kernel preferences
|
* This will optionally start a session if the kernel preferences
|
||||||
* indicate this is desired
|
* indicate this is desired
|
||||||
*/
|
*/
|
||||||
initialize(connection?: NotebookConnection): Promise<void>;
|
initialize(connection?: IConnectionProfile): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the current kernel associated with the document.
|
* Change the current kernel associated with the document.
|
||||||
@@ -140,6 +142,13 @@ export interface IClientSession extends IDisposable {
|
|||||||
options: nb.IKernelSpec
|
options: nb.IKernelSpec
|
||||||
): Promise<nb.IKernel>;
|
): Promise<nb.IKernel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the current kernel associated with the document.
|
||||||
|
*/
|
||||||
|
configureKernel(
|
||||||
|
options: nb.IKernelSpec
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kill the kernel and shutdown the session.
|
* Kill the kernel and shutdown the session.
|
||||||
*
|
*
|
||||||
@@ -191,12 +200,12 @@ export interface IClientSession extends IDisposable {
|
|||||||
/**
|
/**
|
||||||
* Updates the connection
|
* Updates the connection
|
||||||
*/
|
*/
|
||||||
updateConnection(connection: NotebookConnection): void;
|
updateConnection(connection: IConnectionProfile): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDefaultConnection {
|
export interface IDefaultConnection {
|
||||||
defaultConnection: IConnectionProfile;
|
defaultConnection: ConnectionProfile;
|
||||||
otherConnections: IConnectionProfile[];
|
otherConnections: ConnectionProfile[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -348,6 +357,8 @@ export interface INotebookModel {
|
|||||||
* @param edits The edit operations to perform
|
* @param edits The edit operations to perform
|
||||||
*/
|
*/
|
||||||
pushEditOperations(edits: ISingleNotebookEditOperation[]): void;
|
pushEditOperations(edits: ISingleNotebookEditOperation[]): void;
|
||||||
|
|
||||||
|
getApplicableConnectionProviderIds(kernelName: string): string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotebookContentChange {
|
export interface NotebookContentChange {
|
||||||
@@ -418,16 +429,14 @@ export interface INotebookModelOptions {
|
|||||||
|
|
||||||
notebookManagers: INotebookManager[];
|
notebookManagers: INotebookManager[];
|
||||||
providerId: string;
|
providerId: string;
|
||||||
|
standardKernels: IStandardKernelWithProvider[];
|
||||||
|
defaultKernel: nb.IKernelSpec;
|
||||||
|
|
||||||
notificationService: INotificationService;
|
notificationService: INotificationService;
|
||||||
connectionService: IConnectionManagementService;
|
connectionService: IConnectionManagementService;
|
||||||
|
capabilitiesService: ICapabilitiesService;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO would like to move most of these constants to an extension
|
|
||||||
export namespace notebookConstants {
|
export namespace notebookConstants {
|
||||||
export const hadoopKnoxProviderName = 'HADOOP_KNOX';
|
export const SQL = 'SQL';
|
||||||
export const python3 = 'python3';
|
|
||||||
export const python3DisplayName = 'Python 3';
|
|
||||||
export const defaultSparkKernel = 'pyspark3kernel';
|
|
||||||
export const hostPropName = 'host';
|
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,6 @@ import { localize } from 'vs/nls';
|
|||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
|
|
||||||
export namespace constants {
|
export namespace constants {
|
||||||
export const hostPropName = 'host';
|
|
||||||
export const userPropName = 'user';
|
export const userPropName = 'user';
|
||||||
export const knoxPortPropName = 'knoxport';
|
export const knoxPortPropName = 'knoxport';
|
||||||
export const clusterPropName = 'clustername';
|
export const clusterPropName = 'clustername';
|
||||||
@@ -52,7 +51,7 @@ export class NotebookConnection {
|
|||||||
* preference to the built in port.
|
* preference to the built in port.
|
||||||
*/
|
*/
|
||||||
private ensureHostAndPort(): void {
|
private ensureHostAndPort(): void {
|
||||||
this._host = this.connectionProfile.options[constants.hostPropName];
|
this._host = this.connectionProfile.serverName;
|
||||||
this._knoxPort = NotebookConnection.getKnoxPortOrDefault(this.connectionProfile);
|
this._knoxPort = NotebookConnection.getKnoxPortOrDefault(this.connectionProfile);
|
||||||
// determine whether the host has either a ',' or ':' in it
|
// determine whether the host has either a ',' or ':' in it
|
||||||
this.setHostAndPort(',');
|
this.setHostAndPort(',');
|
||||||
|
|||||||
152
src/sql/parts/notebook/models/notebookContexts.ts
Normal file
152
src/sql/parts/notebook/models/notebookContexts.ts
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { nb } from 'sqlops';
|
||||||
|
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
import { IDefaultConnection, notebookConstants, INotebookModelOptions } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
|
|
||||||
|
export class NotebookContexts {
|
||||||
|
private static MSSQL_PROVIDER = 'MSSQL';
|
||||||
|
|
||||||
|
private static get DefaultContext(): IDefaultConnection {
|
||||||
|
let defaultConnection: ConnectionProfile = <any>{
|
||||||
|
providerName: NotebookContexts.MSSQL_PROVIDER,
|
||||||
|
id: '-1',
|
||||||
|
serverName: localize('selectConnection', 'Select connection')
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
// default context if no other contexts are applicable
|
||||||
|
defaultConnection: defaultConnection,
|
||||||
|
otherConnections: [defaultConnection]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static get LocalContext(): IDefaultConnection {
|
||||||
|
let localConnection: ConnectionProfile = <any>{
|
||||||
|
providerName: NotebookContexts.MSSQL_PROVIDER,
|
||||||
|
id: '-1',
|
||||||
|
serverName: localize('localhost', 'localhost')
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
// default context if no other contexts are applicable
|
||||||
|
defaultConnection: localConnection,
|
||||||
|
otherConnections: [localConnection]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all of the applicable contexts for a given kernel
|
||||||
|
* @param connectionService connection management service
|
||||||
|
* @param connProviderIds array of connection provider ids applicable for a kernel
|
||||||
|
* @param kernelChangedArgs kernel changed args (both old and new kernel info)
|
||||||
|
* @param profile current connection profile
|
||||||
|
*/
|
||||||
|
public static async getContextsForKernel(connectionService: IConnectionManagementService, connProviderIds: string[], kernelChangedArgs?: nb.IKernelChangedArgs, profile?: IConnectionProfile): Promise<IDefaultConnection> {
|
||||||
|
let connections: IDefaultConnection = this.DefaultContext;
|
||||||
|
if (!profile) {
|
||||||
|
if (!kernelChangedArgs || !kernelChangedArgs.newValue ||
|
||||||
|
(kernelChangedArgs.oldValue && kernelChangedArgs.newValue.id === kernelChangedArgs.oldValue.id)) {
|
||||||
|
// nothing to do, kernels are the same or new kernel is undefined
|
||||||
|
return connections;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kernelChangedArgs && kernelChangedArgs.newValue && kernelChangedArgs.newValue.name && connProviderIds.length < 1) {
|
||||||
|
return connections;
|
||||||
|
} else {
|
||||||
|
connections = await this.getActiveContexts(connectionService, connProviderIds, profile);
|
||||||
|
}
|
||||||
|
return connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all active contexts and sort them
|
||||||
|
* @param apiWrapper ApiWrapper
|
||||||
|
* @param profile current connection profile
|
||||||
|
*/
|
||||||
|
public static async getActiveContexts(connectionService: IConnectionManagementService, connProviderIds: string[], profile: IConnectionProfile): Promise<IDefaultConnection> {
|
||||||
|
let defaultConnection: ConnectionProfile = NotebookContexts.DefaultContext.defaultConnection;
|
||||||
|
let activeConnections: ConnectionProfile[] = await connectionService.getActiveConnections();
|
||||||
|
if (activeConnections && activeConnections.length > 0) {
|
||||||
|
activeConnections = activeConnections.filter(conn => conn.id !== '-1');
|
||||||
|
}
|
||||||
|
// If no connection provider ids exist for a given kernel, the attach to should show localhost
|
||||||
|
if (connProviderIds.length === 0) {
|
||||||
|
return NotebookContexts.LocalContext;
|
||||||
|
}
|
||||||
|
// If no active connections exist, show "Select connection" as the default value
|
||||||
|
if (activeConnections.length === 0) {
|
||||||
|
return NotebookContexts.DefaultContext;
|
||||||
|
}
|
||||||
|
// Filter active connections by their provider ids to match kernel's supported connection providers
|
||||||
|
else if (activeConnections.length > 0) {
|
||||||
|
let connections = activeConnections.filter(connection => {
|
||||||
|
return connProviderIds.includes(connection.providerName);
|
||||||
|
});
|
||||||
|
if (connections && connections.length > 0) {
|
||||||
|
defaultConnection = connections[0];
|
||||||
|
if (profile && profile.options) {
|
||||||
|
if (connections.find(connection => connection.serverName === profile.serverName)) {
|
||||||
|
defaultConnection = connections.find(connection => connection.serverName === profile.serverName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activeConnections = [];
|
||||||
|
connections.forEach(connection => activeConnections.push(connection));
|
||||||
|
}
|
||||||
|
if (defaultConnection === NotebookContexts.DefaultContext.defaultConnection) {
|
||||||
|
let newConnection = <ConnectionProfile><any>{
|
||||||
|
providerName: 'SQL',
|
||||||
|
id: '-2',
|
||||||
|
serverName: localize('addConnection', 'Add new connection')
|
||||||
|
};
|
||||||
|
activeConnections.push(newConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
otherConnections: activeConnections,
|
||||||
|
defaultConnection: defaultConnection
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param specs kernel specs (comes from session manager)
|
||||||
|
* @param connectionInfo connection profile
|
||||||
|
* @param savedKernelInfo kernel info loaded from
|
||||||
|
*/
|
||||||
|
public static getDefaultKernel(specs: nb.IAllKernels, connectionInfo: IConnectionProfile, savedKernelInfo: nb.IKernelInfo): nb.IKernelSpec {
|
||||||
|
let defaultKernel: nb.IKernelSpec;
|
||||||
|
if (specs) {
|
||||||
|
// find the saved kernel (if it exists)
|
||||||
|
if (savedKernelInfo) {
|
||||||
|
defaultKernel = specs.kernels.find((kernel) => kernel.name === savedKernelInfo.name);
|
||||||
|
}
|
||||||
|
// if no saved kernel exists, use the default KernelSpec
|
||||||
|
if (!defaultKernel) {
|
||||||
|
defaultKernel = specs.kernels.find((kernel) => kernel.name === specs.defaultKernel);
|
||||||
|
}
|
||||||
|
if (defaultKernel) {
|
||||||
|
return defaultKernel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no default kernel specified (should never happen), default to SQL
|
||||||
|
if (!defaultKernel) {
|
||||||
|
defaultKernel = {
|
||||||
|
name: notebookConstants.SQL,
|
||||||
|
display_name: notebookConstants.SQL
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return defaultKernel;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,13 +17,13 @@ import { NotebookChangeType, CellType } from 'sql/parts/notebook/models/contract
|
|||||||
import { nbversion } from '../notebookConstants';
|
import { nbversion } from '../notebookConstants';
|
||||||
import * as notebookUtils from '../notebookUtils';
|
import * as notebookUtils from '../notebookUtils';
|
||||||
import { INotebookManager, SQL_NOTEBOOK_PROVIDER, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/common/notebookService';
|
import { INotebookManager, SQL_NOTEBOOK_PROVIDER, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/common/notebookService';
|
||||||
import { SparkMagicContexts } from 'sql/parts/notebook/models/sparkMagicContexts';
|
import { NotebookContexts } from 'sql/parts/notebook/models/notebookContexts';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import { NotebookConnection } from 'sql/parts/notebook/models/notebookConnection';
|
|
||||||
import { INotification, Severity } from 'vs/platform/notification/common/notification';
|
import { INotification, Severity } from 'vs/platform/notification/common/notification';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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,
|
||||||
@@ -58,11 +58,12 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
private _savedKernelInfo: nb.IKernelInfo;
|
private _savedKernelInfo: nb.IKernelInfo;
|
||||||
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 _hadoopConnection: NotebookConnection;
|
private _activeConnection: ConnectionProfile;
|
||||||
private _defaultKernel: nb.IKernelSpec;
|
|
||||||
private _activeCell: ICellModel;
|
private _activeCell: ICellModel;
|
||||||
private _providerId: string;
|
private _providerId: string;
|
||||||
private _isNewNotebook: boolean = true;
|
private _defaultKernel: nb.IKernelSpec;
|
||||||
|
private _kernelDisplayNameToConnectionProviderIds: Map<string, string[]> = new Map<string, string[]>();
|
||||||
|
private _kernelDisplayNameToNotebookProviderIds: Map<string, string> = new Map<string, string>();
|
||||||
|
|
||||||
constructor(private notebookOptions: INotebookModelOptions, startSessionImmediately?: boolean, private connectionProfile?: IConnectionProfile) {
|
constructor(private notebookOptions: INotebookModelOptions, startSessionImmediately?: boolean, private connectionProfile?: IConnectionProfile) {
|
||||||
super();
|
super();
|
||||||
@@ -74,6 +75,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
}
|
}
|
||||||
this._trustedMode = false;
|
this._trustedMode = false;
|
||||||
this._providerId = notebookOptions.providerId;
|
this._providerId = notebookOptions.providerId;
|
||||||
|
this.notebookOptions.standardKernels.forEach(kernel => {
|
||||||
|
this._kernelDisplayNameToConnectionProviderIds.set(kernel.name, kernel.connectionProviderIds);
|
||||||
|
this._kernelDisplayNameToNotebookProviderIds.set(kernel.name, kernel.notebookProvider);
|
||||||
|
});
|
||||||
|
this._defaultKernel = notebookOptions.defaultKernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get notebookManagers(): INotebookManager[] {
|
public get notebookManagers(): INotebookManager[] {
|
||||||
@@ -171,10 +177,6 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
return this._trustedMode;
|
return this._trustedMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get isNewNotebook(): boolean {
|
|
||||||
return this._isNewNotebook;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get providerId(): string {
|
public get providerId(): string {
|
||||||
return this._providerId;
|
return this._providerId;
|
||||||
}
|
}
|
||||||
@@ -188,8 +190,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public get hadoopConnection(): NotebookConnection {
|
public get activeConnection(): IConnectionProfile {
|
||||||
return this._hadoopConnection;
|
return this._activeConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -207,6 +209,14 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
return this._onClientSessionReady.event;
|
return this._onClientSessionReady.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getApplicableConnectionProviderIds(kernelDisplayName: string): string[] {
|
||||||
|
let ids = [];
|
||||||
|
if (kernelDisplayName) {
|
||||||
|
ids = this._kernelDisplayNameToConnectionProviderIds.get(kernelDisplayName);
|
||||||
|
}
|
||||||
|
return !ids ? [] : ids;
|
||||||
|
}
|
||||||
|
|
||||||
public async requestModelLoad(isTrusted: boolean = false): Promise<void> {
|
public async requestModelLoad(isTrusted: boolean = false): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this._trustedMode = isTrusted;
|
this._trustedMode = isTrusted;
|
||||||
@@ -223,9 +233,12 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
version: ''
|
version: ''
|
||||||
};
|
};
|
||||||
if (contents) {
|
if (contents) {
|
||||||
this._isNewNotebook = false;
|
|
||||||
this._defaultLanguageInfo = this.getDefaultLanguageInfo(contents);
|
this._defaultLanguageInfo = this.getDefaultLanguageInfo(contents);
|
||||||
this._savedKernelInfo = this.getSavedKernelInfo(contents);
|
this._savedKernelInfo = this.getSavedKernelInfo(contents);
|
||||||
|
this.setProviderIdForKernel(this._savedKernelInfo);
|
||||||
|
if (this._savedKernelInfo) {
|
||||||
|
this._defaultKernel = this._savedKernelInfo;
|
||||||
|
}
|
||||||
if (contents.cells && contents.cells.length > 0) {
|
if (contents.cells && contents.cells.length > 0) {
|
||||||
this._cells = contents.cells.map(c => factory.createCell(c, { notebook: this, isTrusted: isTrusted }));
|
this._cells = contents.cells.map(c => factory.createCell(c, { notebook: this, isTrusted: isTrusted }));
|
||||||
}
|
}
|
||||||
@@ -338,15 +351,15 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
if (!this._activeClientSession) {
|
if (!this._activeClientSession) {
|
||||||
this._activeClientSession = clientSession;
|
this._activeClientSession = clientSession;
|
||||||
}
|
}
|
||||||
let profile = this.connectionProfile as IConnectionProfile;
|
let profile = new ConnectionProfile(this.notebookOptions.capabilitiesService, this.connectionProfile);
|
||||||
|
|
||||||
if (this.isValidKnoxConnection(profile)) {
|
if (this.isValidConnection(profile)) {
|
||||||
this._hadoopConnection = new NotebookConnection(this.connectionProfile);
|
this._activeConnection = profile;
|
||||||
} else {
|
} else {
|
||||||
this._hadoopConnection = undefined;
|
this._activeConnection = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
clientSession.initialize(this._hadoopConnection);
|
clientSession.initialize(this._activeConnection);
|
||||||
this._sessionLoadFinished = clientSession.ready.then(async () => {
|
this._sessionLoadFinished = clientSession.ready.then(async () => {
|
||||||
if (clientSession.isInErrorState) {
|
if (clientSession.isInErrorState) {
|
||||||
this.setErrorState(clientSession.errorMessage);
|
this.setErrorState(clientSession.errorMessage);
|
||||||
@@ -360,8 +373,10 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private isValidKnoxConnection(profile: IConnectionProfile | connection.Connection) {
|
private isValidConnection(profile: IConnectionProfile | connection.Connection) {
|
||||||
return profile && profile.providerName === notebookConstants.hadoopKnoxProviderName && profile.options[notebookConstants.hostPropName] !== undefined;
|
let standardKernels = this.notebookOptions.standardKernels.find(kernel => this._savedKernelInfo && kernel.name === this._savedKernelInfo.display_name);
|
||||||
|
let connectionProviderIds = standardKernels ? standardKernels.connectionProviderIds : undefined;
|
||||||
|
return profile && connectionProviderIds && connectionProviderIds.find(provider => provider === profile.providerName) !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get languageInfo(): nb.ILanguageInfo {
|
public get languageInfo(): nb.ILanguageInfo {
|
||||||
@@ -380,45 +395,49 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public doChangeKernel(kernelSpec: nb.IKernelSpec): Promise<void> {
|
public doChangeKernel(kernelSpec: nb.IKernelSpec): Promise<void> {
|
||||||
this.findProviderIdForKernel(kernelSpec);
|
this.setProviderIdForKernel(kernelSpec);
|
||||||
|
if (this._activeClientSession && this._activeClientSession.isReady) {
|
||||||
return this._activeClientSession.changeKernel(kernelSpec)
|
return this._activeClientSession.changeKernel(kernelSpec)
|
||||||
.then((kernel) => {
|
.then((kernel) => {
|
||||||
|
this.updateKernelInfo(kernel);
|
||||||
kernel.ready.then(() => {
|
kernel.ready.then(() => {
|
||||||
if (kernel.info) {
|
if (kernel.info) {
|
||||||
this.updateLanguageInfo(kernel.info.language_info);
|
this.updateLanguageInfo(kernel.info.language_info);
|
||||||
}
|
}
|
||||||
}, err => undefined);
|
}, err => undefined);
|
||||||
return this.updateKernelInfo(kernel);
|
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
this.notifyError(localize('changeKernelFailed', 'Failed to change kernel: {0}', notebookUtils.getErrorMessage(err)));
|
this.notifyError(localize('changeKernelFailed', 'Failed to change kernel: {0}', notebookUtils.getErrorMessage(err)));
|
||||||
// TODO should revert kernels dropdown
|
// TODO should revert kernels dropdown
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.notifyError(localize('noActiveClientSessionFound', 'No active client session was found.'));
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
public changeContext(host: string, newConnection?: IConnectionProfile): void {
|
public changeContext(server: string, newConnection?: IConnectionProfile): void {
|
||||||
try {
|
try {
|
||||||
if (!newConnection) {
|
if (!newConnection) {
|
||||||
newConnection = this._activeContexts.otherConnections.find((connection) => connection.options['host'] === host);
|
newConnection = this._activeContexts.otherConnections.find((connection) => connection.serverName === server);
|
||||||
}
|
}
|
||||||
if (!newConnection && this._activeContexts.defaultConnection.options['host'] === host) {
|
if (!newConnection && (this._activeContexts.defaultConnection.serverName === server)) {
|
||||||
newConnection = this._activeContexts.defaultConnection;
|
newConnection = this._activeContexts.defaultConnection;
|
||||||
}
|
}
|
||||||
SparkMagicContexts.configureContext();
|
let newConnectionProfile = new ConnectionProfile(this.notebookOptions.capabilitiesService, newConnection);
|
||||||
this._hadoopConnection = new NotebookConnection(newConnection);
|
this._activeConnection = newConnectionProfile;
|
||||||
this.refreshConnections(newConnection);
|
this.refreshConnections(newConnectionProfile);
|
||||||
this._activeClientSession.updateConnection(this._hadoopConnection);
|
this._activeClientSession.updateConnection(this._activeConnection);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
let msg = notebookUtils.getErrorMessage(err);
|
let msg = notebookUtils.getErrorMessage(err);
|
||||||
this.notifyError(localize('changeContextFailed', 'Changing context failed: {0}', msg));
|
this.notifyError(localize('changeContextFailed', 'Changing context failed: {0}', msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private refreshConnections(newConnection: IConnectionProfile) {
|
private refreshConnections(newConnection: ConnectionProfile) {
|
||||||
if (this.isValidKnoxConnection(newConnection) &&
|
if (this.isValidConnection(newConnection) &&
|
||||||
this._hadoopConnection.connectionProfile.id !== '-1' &&
|
this._activeConnection.id !== '-1' &&
|
||||||
this._hadoopConnection.connectionProfile.id !== this._activeContexts.defaultConnection.id) {
|
this._activeConnection.id !== this._activeContexts.defaultConnection.id) {
|
||||||
// Put the defaultConnection to the head of otherConnections
|
// Put the defaultConnection to the head of otherConnections
|
||||||
if (this.isValidKnoxConnection(this._activeContexts.defaultConnection)) {
|
if (this.isValidConnection(this._activeContexts.defaultConnection)) {
|
||||||
this._activeContexts.otherConnections = this._activeContexts.otherConnections.filter(conn => conn.id !== this._activeContexts.defaultConnection.id);
|
this._activeContexts.otherConnections = this._activeContexts.otherConnections.filter(conn => conn.id !== this._activeContexts.defaultConnection.id);
|
||||||
this._activeContexts.otherConnections.unshift(this._activeContexts.defaultConnection);
|
this._activeContexts.otherConnections.unshift(this._activeContexts.defaultConnection);
|
||||||
}
|
}
|
||||||
@@ -439,18 +458,15 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
try {
|
try {
|
||||||
let sessionManager = this.notebookManager.sessionManager;
|
let sessionManager = this.notebookManager.sessionManager;
|
||||||
if (sessionManager) {
|
if (sessionManager) {
|
||||||
let defaultKernel = SparkMagicContexts.getDefaultKernel(sessionManager.specs, this.connectionProfile, this._savedKernelInfo, this.notebookOptions.notificationService);
|
if (!this._defaultKernel) {
|
||||||
this._defaultKernel = defaultKernel;
|
this._defaultKernel = NotebookContexts.getDefaultKernel(sessionManager.specs, this.connectionProfile, this._savedKernelInfo);
|
||||||
|
}
|
||||||
this._clientSessions.forEach(clientSession => {
|
this._clientSessions.forEach(clientSession => {
|
||||||
clientSession.statusChanged(async (session) => {
|
clientSession.statusChanged(async (session) => {
|
||||||
if (session && session.defaultKernelLoaded === true) {
|
this._kernelsChangedEmitter.fire(session.kernel);
|
||||||
this._kernelsChangedEmitter.fire(defaultKernel);
|
|
||||||
} else if (session && !session.defaultKernelLoaded) {
|
|
||||||
this._kernelsChangedEmitter.fire({ name: notebookConstants.python3, display_name: notebookConstants.python3DisplayName });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.doChangeKernel(defaultKernel);
|
this.doChangeKernel(this._defaultKernel);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
let msg = notebookUtils.getErrorMessage(err);
|
let msg = notebookUtils.getErrorMessage(err);
|
||||||
@@ -484,6 +500,15 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
return kernel;
|
return kernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getDisplayNameFromSpecName(kernelid: string): string {
|
||||||
|
let newKernel = this.notebookManager.sessionManager.specs.kernels.find(kernel => kernel.name === kernelid);
|
||||||
|
let newKernelDisplayName;
|
||||||
|
if (newKernel) {
|
||||||
|
newKernelDisplayName = newKernel.display_name;
|
||||||
|
}
|
||||||
|
return newKernelDisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
private setErrorState(errMsg: string): void {
|
private setErrorState(errMsg: string): void {
|
||||||
this._inErrorState = true;
|
this._inErrorState = true;
|
||||||
let msg = localize('startSessionFailed', 'Could not start session: {0}', errMsg);
|
let msg = localize('startSessionFailed', 'Could not start session: {0}', errMsg);
|
||||||
@@ -499,6 +524,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
public async handleClosed(): Promise<void> {
|
public async handleClosed(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
if (this._activeClientSession) {
|
if (this._activeClientSession) {
|
||||||
|
try {
|
||||||
|
await this._activeClientSession.ready;
|
||||||
|
} catch(err) {
|
||||||
|
this.notifyError(localize('shutdownClientSessionError', 'A client session error occurred when closing the notebook: {0}', err));
|
||||||
|
}
|
||||||
await this._activeClientSession.shutdown();
|
await this._activeClientSession.shutdown();
|
||||||
this._clientSessions = undefined;
|
this._clientSessions = undefined;
|
||||||
this._activeClientSession = undefined;
|
this._activeClientSession = undefined;
|
||||||
@@ -509,11 +539,13 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async loadActiveContexts(kernelChangedArgs: nb.IKernelChangedArgs): Promise<void> {
|
private async loadActiveContexts(kernelChangedArgs: nb.IKernelChangedArgs): Promise<void> {
|
||||||
this._activeContexts = await SparkMagicContexts.getContextsForKernel(this.notebookOptions.connectionService, kernelChangedArgs, this.connectionProfile);
|
if (kernelChangedArgs && kernelChangedArgs.newValue && kernelChangedArgs.newValue.name) {
|
||||||
|
let kernelDisplayName = this.getDisplayNameFromSpecName(kernelChangedArgs.newValue.name);
|
||||||
|
this._activeContexts = await NotebookContexts.getContextsForKernel(this.notebookOptions.connectionService, this.getApplicableConnectionProviderIds(kernelDisplayName), kernelChangedArgs, this.connectionProfile);
|
||||||
this._contextsChangedEmitter.fire();
|
this._contextsChangedEmitter.fire();
|
||||||
if (this.contexts.defaultConnection !== undefined && this.contexts.defaultConnection.options !== undefined) {
|
if (this.contexts.defaultConnection !== undefined && this.contexts.defaultConnection.serverName !== undefined) {
|
||||||
let defaultHadoopConnection = new NotebookConnection(this.contexts.defaultConnection);
|
this.changeContext(this.contexts.defaultConnection.serverName);
|
||||||
this.changeContext(defaultHadoopConnection.host);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,6 +587,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);
|
||||||
} 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
|
||||||
}
|
}
|
||||||
@@ -565,17 +598,27 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
* Set _providerId and _activeClientSession based on a kernelSpec representing new kernel
|
* Set _providerId and _activeClientSession based on a kernelSpec representing new kernel
|
||||||
* @param kernelSpec KernelSpec for new kernel
|
* @param kernelSpec KernelSpec for new kernel
|
||||||
*/
|
*/
|
||||||
private findProviderIdForKernel(kernelSpec: nb.IKernelSpec): void {
|
private setProviderIdForKernel(kernelSpec: nb.IKernelSpec): void {
|
||||||
|
let sessionManagerFound: boolean = false;
|
||||||
for (let i = 0; i < this.notebookManagers.length; i++) {
|
for (let i = 0; i < this.notebookManagers.length; i++) {
|
||||||
if (this.notebookManagers[i].sessionManager && this.notebookManagers[i].sessionManager.specs && this.notebookManagers[i].sessionManager.specs.kernels) {
|
if (this.notebookManagers[i].sessionManager && this.notebookManagers[i].sessionManager.specs && this.notebookManagers[i].sessionManager.specs.kernels) {
|
||||||
let index = this.notebookManagers[i].sessionManager.specs.kernels.findIndex(kernel => kernel.name === kernelSpec.name);
|
let index = this.notebookManagers[i].sessionManager.specs.kernels.findIndex(kernel => kernel.name === kernelSpec.name);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
this._activeClientSession = this._clientSessions[i];
|
this._activeClientSession = this._clientSessions[i];
|
||||||
this._providerId = this.notebookManagers[i].providerId;
|
this._providerId = this.notebookManagers[i].providerId;
|
||||||
|
sessionManagerFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no SessionManager exists, utilize passed in StandardKernels to see if we can intelligently set _providerId
|
||||||
|
if (!sessionManagerFound) {
|
||||||
|
let provider = this._kernelDisplayNameToNotebookProviderIds.get(kernelSpec.display_name);
|
||||||
|
if (provider) {
|
||||||
|
this._providerId = provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Serialize the model to JSON.
|
* Serialize the model to JSON.
|
||||||
|
|||||||
@@ -1,238 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import * as path from 'path';
|
|
||||||
import { nb } from 'sqlops';
|
|
||||||
|
|
||||||
import * as pfs from 'vs/base/node/pfs';
|
|
||||||
import { localize } from 'vs/nls';
|
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|
||||||
import { IDefaultConnection, notebookConstants, INotebookModelOptions } from 'sql/parts/notebook/models/modelInterfaces';
|
|
||||||
import * as notebookUtils from '../notebookUtils';
|
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
|
||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
|
||||||
|
|
||||||
const configBase = {
|
|
||||||
'kernel_python_credentials': {
|
|
||||||
'url': ''
|
|
||||||
},
|
|
||||||
'kernel_scala_credentials': {
|
|
||||||
'url': ''
|
|
||||||
},
|
|
||||||
'kernel_r_credentials': {
|
|
||||||
'url': ''
|
|
||||||
},
|
|
||||||
|
|
||||||
'ignore_ssl_errors': true,
|
|
||||||
|
|
||||||
'logging_config': {
|
|
||||||
'version': 1,
|
|
||||||
'formatters': {
|
|
||||||
'magicsFormatter': {
|
|
||||||
'format': '%(asctime)s\t%(levelname)s\t%(message)s',
|
|
||||||
'datefmt': ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'handlers': {
|
|
||||||
'magicsHandler': {
|
|
||||||
'class': 'hdijupyterutils.filehandler.MagicsFileHandler',
|
|
||||||
'formatter': 'magicsFormatter',
|
|
||||||
'home_path': ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'loggers': {
|
|
||||||
'magicsLogger': {
|
|
||||||
'handlers': ['magicsHandler'],
|
|
||||||
'level': 'DEBUG',
|
|
||||||
'propagate': 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export class SparkMagicContexts {
|
|
||||||
|
|
||||||
public static get DefaultContext(): IDefaultConnection {
|
|
||||||
// TODO NOTEBOOK REFACTOR fix default connection handling
|
|
||||||
let defaultConnection: IConnectionProfile = <any>{
|
|
||||||
providerName: notebookConstants.hadoopKnoxProviderName,
|
|
||||||
id: '-1',
|
|
||||||
options:
|
|
||||||
{
|
|
||||||
host: localize('selectConnection', 'Select connection')
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
// default context if no other contexts are applicable
|
|
||||||
defaultConnection: defaultConnection,
|
|
||||||
otherConnections: [defaultConnection]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all of the applicable contexts for a given kernel
|
|
||||||
* @param apiWrapper ApiWrapper
|
|
||||||
* @param kernelChangedArgs kernel changed args (both old and new kernel info)
|
|
||||||
* @param profile current connection profile
|
|
||||||
*/
|
|
||||||
public static async getContextsForKernel(connectionService: IConnectionManagementService, kernelChangedArgs?: nb.IKernelChangedArgs, profile?: IConnectionProfile): Promise<IDefaultConnection> {
|
|
||||||
let connections: IDefaultConnection = this.DefaultContext;
|
|
||||||
if (!profile) {
|
|
||||||
if (!kernelChangedArgs || !kernelChangedArgs.newValue ||
|
|
||||||
(kernelChangedArgs.oldValue && kernelChangedArgs.newValue.id === kernelChangedArgs.oldValue.id)) {
|
|
||||||
// nothing to do, kernels are the same or new kernel is undefined
|
|
||||||
return connections;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (kernelChangedArgs && kernelChangedArgs.newValue && kernelChangedArgs.newValue.name) {
|
|
||||||
switch (kernelChangedArgs.newValue.name) {
|
|
||||||
case (notebookConstants.python3):
|
|
||||||
// python3 case, use this.DefaultContext for the only connection
|
|
||||||
break;
|
|
||||||
//TO DO: Handle server connections based on kernel type. Right now, we call the same method for all kernel types.
|
|
||||||
default:
|
|
||||||
connections = await this.getActiveContexts(connectionService, profile);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
connections = await this.getActiveContexts(connectionService, profile);
|
|
||||||
}
|
|
||||||
return connections;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all active contexts and sort them
|
|
||||||
* @param apiWrapper ApiWrapper
|
|
||||||
* @param profile current connection profile
|
|
||||||
*/
|
|
||||||
public static async getActiveContexts(connectionService: IConnectionManagementService, profile: IConnectionProfile): Promise<IDefaultConnection> {
|
|
||||||
let defaultConnection: IConnectionProfile = SparkMagicContexts.DefaultContext.defaultConnection;
|
|
||||||
let activeConnections: IConnectionProfile[] = await connectionService.getActiveConnections();
|
|
||||||
// If no connections exist, only show 'n/a'
|
|
||||||
if (activeConnections && activeConnections.length > 0) {
|
|
||||||
// Remove all non-Spark connections
|
|
||||||
activeConnections = activeConnections.filter(conn => conn.providerName === notebookConstants.hadoopKnoxProviderName);
|
|
||||||
}
|
|
||||||
if (activeConnections.length === 0) {
|
|
||||||
return SparkMagicContexts.DefaultContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If launched from the right click or server dashboard, connection profile data exists, so use that as default
|
|
||||||
if (profile && profile.options) {
|
|
||||||
let profileConnection = activeConnections.filter(conn => conn.options['host'] === profile.options['host']);
|
|
||||||
if (profileConnection) {
|
|
||||||
defaultConnection = profileConnection[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (activeConnections.length > 0) {
|
|
||||||
defaultConnection = activeConnections[0];
|
|
||||||
} else {
|
|
||||||
// TODO NOTEBOOK REFACTOR change this so it's no longer incompatible with IConnectionProfile
|
|
||||||
defaultConnection = <IConnectionProfile><any>{
|
|
||||||
providerName: notebookConstants.hadoopKnoxProviderName,
|
|
||||||
id: '-1',
|
|
||||||
options:
|
|
||||||
{
|
|
||||||
host: localize('addConnection', 'Add new connection')
|
|
||||||
}
|
|
||||||
};
|
|
||||||
activeConnections.push(defaultConnection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
otherConnections: activeConnections,
|
|
||||||
defaultConnection: defaultConnection
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async configureContext(): Promise<object> {
|
|
||||||
let sparkmagicConfDir = path.join(notebookUtils.getUserHome(), '.sparkmagic');
|
|
||||||
// TODO NOTEBOOK REFACTOR re-enable this or move to extension. Requires config files to be available in order to work
|
|
||||||
await notebookUtils.mkDir(sparkmagicConfDir);
|
|
||||||
|
|
||||||
// Default to localhost in config file.
|
|
||||||
let creds: ICredentials = {
|
|
||||||
'url': 'http://localhost:8088'
|
|
||||||
};
|
|
||||||
|
|
||||||
let config: ISparkMagicConfig = Object.assign({}, configBase);
|
|
||||||
SparkMagicContexts.updateConfig(config, creds, sparkmagicConfDir);
|
|
||||||
|
|
||||||
let configFilePath = path.join(sparkmagicConfDir, 'config.json');
|
|
||||||
await pfs.writeFile(configFilePath, JSON.stringify(config));
|
|
||||||
|
|
||||||
return { 'SPARKMAGIC_CONF_DIR': sparkmagicConfDir };
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param specs kernel specs (comes from session manager)
|
|
||||||
* @param connectionInfo connection profile
|
|
||||||
* @param savedKernelInfo kernel info loaded from
|
|
||||||
*/
|
|
||||||
public static getDefaultKernel(specs: nb.IAllKernels, connectionInfo: IConnectionProfile, savedKernelInfo: nb.IKernelInfo, notificationService: INotificationService): nb.IKernelSpec {
|
|
||||||
let foundSavedKernelInSpecs;
|
|
||||||
let defaultKernel;
|
|
||||||
if (specs) {
|
|
||||||
defaultKernel = specs.kernels.find((kernel) => kernel.name === specs.defaultKernel);
|
|
||||||
if (savedKernelInfo) {
|
|
||||||
foundSavedKernelInSpecs = specs.kernels.find((kernel) => kernel.name === savedKernelInfo.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let profile = connectionInfo as IConnectionProfile;
|
|
||||||
if (specs && connectionInfo && profile.providerName === notebookConstants.hadoopKnoxProviderName) {
|
|
||||||
// set default kernel to default spark kernel if profile exists
|
|
||||||
// otherwise, set default to kernel info loaded from existing file
|
|
||||||
defaultKernel = !foundSavedKernelInSpecs ? specs.kernels.find((spec) => spec.name === notebookConstants.defaultSparkKernel) : foundSavedKernelInSpecs;
|
|
||||||
} else {
|
|
||||||
// Handle kernels
|
|
||||||
if (savedKernelInfo && savedKernelInfo.name.toLowerCase().indexOf('spark') > -1) {
|
|
||||||
notificationService.warn(localize('sparkKernelRequiresConnection', 'Cannot use kernel {0} as no connection is active. The default kernel of {1} will be used instead.', savedKernelInfo.display_name, defaultKernel.display_name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no default kernel specified (should never happen), default to python3
|
|
||||||
if (!defaultKernel) {
|
|
||||||
defaultKernel = {
|
|
||||||
name: notebookConstants.python3,
|
|
||||||
display_name: notebookConstants.python3DisplayName
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return defaultKernel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static updateConfig(config: ISparkMagicConfig, creds: ICredentials, homePath: string): void {
|
|
||||||
config.kernel_python_credentials = creds;
|
|
||||||
config.kernel_scala_credentials = creds;
|
|
||||||
config.kernel_r_credentials = creds;
|
|
||||||
config.logging_config.handlers.magicsHandler.home_path = homePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ICredentials {
|
|
||||||
'url': string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISparkMagicConfig {
|
|
||||||
kernel_python_credentials: ICredentials;
|
|
||||||
kernel_scala_credentials: ICredentials;
|
|
||||||
kernel_r_credentials: ICredentials;
|
|
||||||
ignore_ssl_errors?: boolean;
|
|
||||||
logging_config: {
|
|
||||||
handlers: {
|
|
||||||
magicsHandler: {
|
|
||||||
home_path: string;
|
|
||||||
class?: string;
|
|
||||||
formatter?: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IKernelJupyterID {
|
|
||||||
id: string;
|
|
||||||
jupyterId: string;
|
|
||||||
}
|
|
||||||
@@ -49,6 +49,7 @@ import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHos
|
|||||||
import { IResourceInput } from 'vs/platform/editor/common/editor';
|
import { IResourceInput } from 'vs/platform/editor/common/editor';
|
||||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||||
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||||
|
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
|
|
||||||
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
||||||
|
|
||||||
@@ -92,7 +93,8 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
@Inject(IWindowService) private windowService: IWindowService,
|
@Inject(IWindowService) private windowService: IWindowService,
|
||||||
@Inject(IViewletService) private viewletService: IViewletService,
|
@Inject(IViewletService) private viewletService: IViewletService,
|
||||||
@Inject(IUntitledEditorService) private untitledEditorService: IUntitledEditorService,
|
@Inject(IUntitledEditorService) private untitledEditorService: IUntitledEditorService,
|
||||||
@Inject(IEditorGroupsService) private editorGroupService: IEditorGroupsService
|
@Inject(IEditorGroupsService) private editorGroupService: IEditorGroupsService,
|
||||||
|
@Inject(ICapabilitiesService) private capabilitiesService: ICapabilitiesService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.updateProfile();
|
this.updateProfile();
|
||||||
@@ -105,11 +107,11 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
// use global connection if possible
|
// use global connection if possible
|
||||||
let profile = TaskUtilities.getCurrentGlobalConnection(this.objectExplorerService, this.connectionManagementService, this.editorService);
|
let profile = TaskUtilities.getCurrentGlobalConnection(this.objectExplorerService, this.connectionManagementService, this.editorService);
|
||||||
// TODO use generic method to match kernel with valid connection that's compatible. For now, we only have 1
|
// TODO use generic method to match kernel with valid connection that's compatible. For now, we only have 1
|
||||||
if (profile && profile.providerName === notebookConstants.hadoopKnoxProviderName) {
|
if (profile && profile.providerName) {
|
||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
} else {
|
} else {
|
||||||
// if not, try 1st active connection that matches our filter
|
// if not, try 1st active connection that matches our filter
|
||||||
let profiles = this.connectionManagementService.getActiveConnections([notebookConstants.hadoopKnoxProviderName]);
|
let profiles = this.connectionManagementService.getActiveConnections();
|
||||||
if (profiles && profiles.length > 0) {
|
if (profiles && profiles.length > 0) {
|
||||||
this.profile = profiles[0];
|
this.profile = profiles[0];
|
||||||
}
|
}
|
||||||
@@ -239,7 +241,10 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
connectionService: this.connectionManagementService,
|
connectionService: this.connectionManagementService,
|
||||||
notificationService: this.notificationService,
|
notificationService: this.notificationService,
|
||||||
notebookManagers: this.notebookManagers,
|
notebookManagers: this.notebookManagers,
|
||||||
providerId: notebookUtils.sqlNotebooksEnabled() ? 'sql' : 'jupyter' // this is tricky; really should also depend on the connection profile
|
standardKernels: this._notebookParams.input.standardKernels,
|
||||||
|
providerId: notebookUtils.sqlNotebooksEnabled() ? 'sql' : 'jupyter', // this is tricky; really should also depend on the connection profile
|
||||||
|
defaultKernel: this._notebookParams.input.defaultKernel,
|
||||||
|
capabilitiesService: this.capabilitiesService
|
||||||
}, false, this.profile);
|
}, false, this.profile);
|
||||||
model.onError((errInfo: INotification) => this.handleModelError(errInfo));
|
model.onError((errInfo: INotification) => this.handleModelError(errInfo));
|
||||||
await model.requestModelLoad(this._notebookParams.isTrusted);
|
await model.requestModelLoad(this._notebookParams.isTrusted);
|
||||||
@@ -324,7 +329,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
|
|
||||||
let attachToContainer = document.createElement('div');
|
let attachToContainer = document.createElement('div');
|
||||||
let attachTodropdwon = new AttachToDropdown(attachToContainer, this.contextViewService, this.modelRegistered,
|
let attachTodropdwon = new AttachToDropdown(attachToContainer, this.contextViewService, this.modelRegistered,
|
||||||
this.connectionManagementService, this.connectionDialogService, this.notificationService);
|
this.connectionManagementService, this.connectionDialogService, this.notificationService, this.capabilitiesService);
|
||||||
attachTodropdwon.render(attachToContainer);
|
attachTodropdwon.render(attachToContainer);
|
||||||
attachSelectBoxStyler(attachTodropdwon, this.themeService);
|
attachSelectBoxStyler(attachTodropdwon, this.themeService);
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,13 @@ import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview
|
|||||||
import { INotificationService, Severity, INotificationActions } from 'vs/platform/notification/common/notification';
|
import { INotificationService, Severity, INotificationActions } from 'vs/platform/notification/common/notification';
|
||||||
|
|
||||||
import { SelectBox, ISelectBoxOptionsWithLabel } from 'sql/base/browser/ui/selectBox/selectBox';
|
import { SelectBox, ISelectBoxOptionsWithLabel } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||||
import { INotebookModel, notebookConstants } from 'sql/parts/notebook/models/modelInterfaces';
|
import { INotebookModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
import { CellType } from 'sql/parts/notebook/models/contracts';
|
import { CellType } from 'sql/parts/notebook/models/contracts';
|
||||||
import { NotebookComponent } from 'sql/parts/notebook/notebook.component';
|
import { NotebookComponent } from 'sql/parts/notebook/notebook.component';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|
||||||
import { IConnectionManagementService, IConnectionDialogService } from 'sql/platform/connection/common/connectionManagement';
|
|
||||||
import { getErrorMessage } from 'sql/parts/notebook/notebookUtils';
|
import { getErrorMessage } from 'sql/parts/notebook/notebookUtils';
|
||||||
|
import { IConnectionManagementService, IConnectionDialogService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
|
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
import { noKernel } from 'sql/workbench/services/notebook/common/sessionManager';
|
import { noKernel } from 'sql/workbench/services/notebook/common/sessionManager';
|
||||||
|
|
||||||
const msgLoading = localize('loading', 'Loading kernels...');
|
const msgLoading = localize('loading', 'Loading kernels...');
|
||||||
@@ -26,7 +27,7 @@ const attachToLabel: string = localize('AttachTo', 'Attach to: ');
|
|||||||
const msgLoadingContexts = localize('loadingContexts', 'Loading contexts...');
|
const msgLoadingContexts = localize('loadingContexts', 'Loading contexts...');
|
||||||
const msgAddNewConnection = localize('addNewConnection', 'Add new connection');
|
const msgAddNewConnection = localize('addNewConnection', 'Add new connection');
|
||||||
const msgSelectConnection = localize('selectConnection', 'Select connection');
|
const msgSelectConnection = localize('selectConnection', 'Select connection');
|
||||||
const msgLocalHost = localize('localhost', 'Localhost');
|
const msgLocalHost = localize('localhost', 'localhost');
|
||||||
|
|
||||||
// Action to add a cell to notebook based on cell type(code/markdown).
|
// Action to add a cell to notebook based on cell type(code/markdown).
|
||||||
export class AddCellAction extends Action {
|
export class AddCellAction extends Action {
|
||||||
@@ -209,7 +210,8 @@ export class AttachToDropdown extends SelectBox {
|
|||||||
constructor(container: HTMLElement, contextViewProvider: IContextViewProvider, modelRegistered: Promise<INotebookModel>,
|
constructor(container: HTMLElement, contextViewProvider: IContextViewProvider, modelRegistered: Promise<INotebookModel>,
|
||||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||||
@IConnectionDialogService private _connectionDialogService: IConnectionDialogService,
|
@IConnectionDialogService private _connectionDialogService: IConnectionDialogService,
|
||||||
@INotificationService private _notificationService: INotificationService) {
|
@INotificationService private _notificationService: INotificationService,
|
||||||
|
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService) {
|
||||||
super([msgLoadingContexts], msgLoadingContexts, contextViewProvider, container, { labelText: attachToLabel, labelOnTop: false } as ISelectBoxOptionsWithLabel);
|
super([msgLoadingContexts], msgLoadingContexts, contextViewProvider, container, { labelText: attachToLabel, labelOnTop: false } as ISelectBoxOptionsWithLabel);
|
||||||
if (modelRegistered) {
|
if (modelRegistered) {
|
||||||
modelRegistered
|
modelRegistered
|
||||||
@@ -219,8 +221,8 @@ export class AttachToDropdown extends SelectBox {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.onDidSelect(e => {
|
this.onDidSelect(e => {
|
||||||
let connection = this.model.contexts.otherConnections.find((c) => c.options.host === e.selected);
|
let connection = this.model.contexts.otherConnections.find((c) => c.serverName === e.selected);
|
||||||
this.doChangeContext(connection);
|
this.doChangeContext(new ConnectionProfile(this._capabilitiesService, connection));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,54 +230,55 @@ export class AttachToDropdown extends SelectBox {
|
|||||||
this.model = model;
|
this.model = model;
|
||||||
model.contextsChanged(() => {
|
model.contextsChanged(() => {
|
||||||
if (this.model.clientSession.kernel && this.model.clientSession.kernel.name) {
|
if (this.model.clientSession.kernel && this.model.clientSession.kernel.name) {
|
||||||
let currentKernel = this.model.clientSession.kernel.name;
|
let currentKernelSpec = this.model.specs.kernels.find(kernel => kernel.name === this.model.clientSession.kernel.name);
|
||||||
this.loadAttachToDropdown(this.model, currentKernel);
|
this.loadAttachToDropdown(this.model, currentKernelSpec.display_name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load "Attach To" dropdown with the values corresponding to Kernel dropdown
|
// Load "Attach To" dropdown with the values corresponding to Kernel dropdown
|
||||||
public async loadAttachToDropdown(model: INotebookModel, currentKernel: string): Promise<void> {
|
public async loadAttachToDropdown(model: INotebookModel, currentKernel: string): Promise<void> {
|
||||||
if (currentKernel === notebookConstants.python3 || currentKernel === noKernel) {
|
let connProviderIds = this.model.getApplicableConnectionProviderIds(currentKernel);
|
||||||
|
if ((connProviderIds && connProviderIds.length === 0) || currentKernel === noKernel) {
|
||||||
this.setOptions([msgLocalHost]);
|
this.setOptions([msgLocalHost]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let hadoopConnections = this.getHadoopConnections(model);
|
let connections = this.getConnections(model);
|
||||||
this.enable();
|
this.enable();
|
||||||
if (hadoopConnections.length === 1 && hadoopConnections[0] === msgAddNewConnection) {
|
if (connections.length === 1 && connections[0] === msgAddNewConnection) {
|
||||||
hadoopConnections.unshift(msgSelectConnection);
|
connections.unshift(msgSelectConnection);
|
||||||
this.selectWithOptionName(msgSelectConnection);
|
this.selectWithOptionName(msgSelectConnection);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
hadoopConnections.push(msgAddNewConnection);
|
connections.push(msgAddNewConnection);
|
||||||
}
|
}
|
||||||
this.setOptions(hadoopConnections);
|
this.setOptions(connections);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get hadoop connections from context
|
//Get connections from context
|
||||||
public getHadoopConnections(model: INotebookModel): string[] {
|
public getConnections(model: INotebookModel): string[] {
|
||||||
let otherHadoopConnections: IConnectionProfile[] = [];
|
let otherConnections: ConnectionProfile[] = [];
|
||||||
model.contexts.otherConnections.forEach((conn) => { otherHadoopConnections.push(conn); });
|
model.contexts.otherConnections.forEach((conn) => { otherConnections.push(conn); });
|
||||||
this.selectWithOptionName(model.contexts.defaultConnection.options.host);
|
this.selectWithOptionName(model.contexts.defaultConnection.serverName);
|
||||||
otherHadoopConnections = this.setHadoopConnectionsList(model.contexts.defaultConnection, model.contexts.otherConnections);
|
otherConnections = this.setConnectionsList(model.contexts.defaultConnection, model.contexts.otherConnections);
|
||||||
let hadoopConnections = otherHadoopConnections.map((context) => context.options.host);
|
let connections = otherConnections.map((context) => context.serverName);
|
||||||
return hadoopConnections;
|
return connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setHadoopConnectionsList(defaultHadoopConnection: IConnectionProfile, otherHadoopConnections: IConnectionProfile[]) {
|
private setConnectionsList(defaultConnection: ConnectionProfile, otherConnections: ConnectionProfile[]) {
|
||||||
if (defaultHadoopConnection.options.host !== msgSelectConnection) {
|
if (defaultConnection.serverName !== msgSelectConnection) {
|
||||||
otherHadoopConnections = otherHadoopConnections.filter(conn => conn.options.host !== defaultHadoopConnection.options.host);
|
otherConnections = otherConnections.filter(conn => conn.serverName !== defaultConnection.serverName);
|
||||||
otherHadoopConnections.unshift(defaultHadoopConnection);
|
otherConnections.unshift(defaultConnection);
|
||||||
if (otherHadoopConnections.length > 1) {
|
if (otherConnections.length > 1) {
|
||||||
otherHadoopConnections = otherHadoopConnections.filter(val => val.options.host !== msgSelectConnection);
|
otherConnections = otherConnections.filter(val => val.serverName !== msgSelectConnection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return otherHadoopConnections;
|
return otherConnections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public doChangeContext(connection?: IConnectionProfile): void {
|
public doChangeContext(connection?: ConnectionProfile): void {
|
||||||
if (this.value === msgAddNewConnection) {
|
if (this.value === msgAddNewConnection) {
|
||||||
this.openConnectionDialog();
|
this.openConnectionDialog();
|
||||||
} else {
|
} else {
|
||||||
@@ -291,15 +294,15 @@ export class AttachToDropdown extends SelectBox {
|
|||||||
**/
|
**/
|
||||||
public async openConnectionDialog(): Promise<void> {
|
public async openConnectionDialog(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
//TODO: Figure out how to plumb through the correct provider here
|
await this._connectionDialogService.openDialogAndWait(this._connectionManagementService, { connectionType: 1, providers: this.model.getApplicableConnectionProviderIds(this.model.clientSession.kernel.name) }).then(connection => {
|
||||||
await this._connectionDialogService.openDialogAndWait(this._connectionManagementService, { connectionType: 1, providers: [notebookConstants.hadoopKnoxProviderName] }).then(connection => {
|
|
||||||
let attachToConnections = this.values;
|
let attachToConnections = this.values;
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
this.loadAttachToDropdown(this.model, this.model.clientSession.kernel.name);
|
this.loadAttachToDropdown(this.model, this.model.clientSession.kernel.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let connectedServer = connection.options[notebookConstants.hostPropName];
|
let connectionProfile = new ConnectionProfile(this._capabilitiesService, connection);
|
||||||
//Check to see if the same host is already there in dropdown. We only have host names in dropdown
|
let connectedServer = connectionProfile.serverName;
|
||||||
|
//Check to see if the same server is already there in dropdown. We only have server names in dropdown
|
||||||
if (attachToConnections.some(val => val === connectedServer)) {
|
if (attachToConnections.some(val => val === connectedServer)) {
|
||||||
this.loadAttachToDropdown(this.model, this.model.clientSession.kernel.name);
|
this.loadAttachToDropdown(this.model, this.model.clientSession.kernel.name);
|
||||||
this.doChangeContext();
|
this.doChangeContext();
|
||||||
@@ -320,7 +323,7 @@ export class AttachToDropdown extends SelectBox {
|
|||||||
this.select(index);
|
this.select(index);
|
||||||
|
|
||||||
// Call doChangeContext to set the newly chosen connection in the model
|
// Call doChangeContext to set the newly chosen connection in the model
|
||||||
this.doChangeContext(connection);
|
this.doChangeContext(connectionProfile);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ import { Emitter, Event } from 'vs/base/common/event';
|
|||||||
import URI from 'vs/base/common/uri';
|
import URI from 'vs/base/common/uri';
|
||||||
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import * as resources from 'vs/base/common/resources';
|
import * as resources from 'vs/base/common/resources';
|
||||||
|
import * as sqlops from 'sqlops';
|
||||||
|
|
||||||
|
import { IStandardKernelWithProvider } from 'sql/parts/notebook/notebookUtils';
|
||||||
import { INotebookService, INotebookEditor } from 'sql/workbench/services/notebook/common/notebookService';
|
import { INotebookService, INotebookEditor } from 'sql/workbench/services/notebook/common/notebookService';
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
@@ -27,10 +29,13 @@ export class NotebookInputModel extends EditorModel {
|
|||||||
private dirty: boolean;
|
private dirty: boolean;
|
||||||
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
||||||
private _providerId: string;
|
private _providerId: string;
|
||||||
|
private _standardKernels: IStandardKernelWithProvider[];
|
||||||
|
private _defaultKernel: sqlops.nb.IKernelSpec;
|
||||||
constructor(public readonly notebookUri: URI, private readonly handle: number, private _isTrusted: boolean = false, private saveHandler?: ModeViewSaveHandler, provider?: string, private _providers?: string[]) {
|
constructor(public readonly notebookUri: URI, private readonly handle: number, private _isTrusted: boolean = false, private saveHandler?: ModeViewSaveHandler, provider?: string, private _providers?: string[]) {
|
||||||
super();
|
super();
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
this._providerId = provider;
|
this._providerId = provider;
|
||||||
|
this._standardKernels = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public get providerId(): string {
|
public get providerId(): string {
|
||||||
@@ -49,6 +54,28 @@ export class NotebookInputModel extends EditorModel {
|
|||||||
this._providers = value;
|
this._providers = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get standardKernels(): IStandardKernelWithProvider[] {
|
||||||
|
return this._standardKernels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set standardKernels(value: IStandardKernelWithProvider[]) {
|
||||||
|
value.forEach(kernel => {
|
||||||
|
this._standardKernels.push({
|
||||||
|
connectionProviderIds: kernel.connectionProviderIds,
|
||||||
|
name: kernel.name,
|
||||||
|
notebookProvider: kernel.notebookProvider
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public get defaultKernel(): sqlops.nb.IKernelSpec {
|
||||||
|
return this._defaultKernel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set defaultKernel(kernel: sqlops.nb.IKernelSpec) {
|
||||||
|
this._defaultKernel = kernel;
|
||||||
|
}
|
||||||
|
|
||||||
get isTrusted(): boolean {
|
get isTrusted(): boolean {
|
||||||
return this._isTrusted;
|
return this._isTrusted;
|
||||||
}
|
}
|
||||||
@@ -116,6 +143,14 @@ export class NotebookInput extends EditorInput {
|
|||||||
return this._model.providers;
|
return this._model.providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get standardKernels(): IStandardKernelWithProvider[] {
|
||||||
|
return this._model.standardKernels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get defaultKernel(): sqlops.nb.IKernelSpec {
|
||||||
|
return this._model.defaultKernel;
|
||||||
|
}
|
||||||
|
|
||||||
public getTypeId(): string {
|
public getTypeId(): string {
|
||||||
return NotebookInput.ID;
|
return NotebookInput.ID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,28 @@ export function getProvidersForFileName(fileName: string, notebookService: INote
|
|||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getStandardKernelsForProvider(providerId: string, notebookService: INotebookService) : IStandardKernelWithProvider[] {
|
||||||
|
if (!providerId || !notebookService) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
let standardKernels = notebookService.getStandardKernelsForProvider(providerId);
|
||||||
|
standardKernels.forEach(kernel => {
|
||||||
|
Object.assign(<IStandardKernelWithProvider>kernel, {
|
||||||
|
name: kernel.name,
|
||||||
|
connectionProviderIds: kernel.connectionProviderIds,
|
||||||
|
notebookProvider: providerId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return <IStandardKernelWithProvider[]>(standardKernels);
|
||||||
|
}
|
||||||
|
|
||||||
// Private feature flag to enable Sql Notebook experience
|
// Private feature flag to enable Sql Notebook experience
|
||||||
export function sqlNotebooksEnabled() {
|
export function sqlNotebooksEnabled() {
|
||||||
return process.env['SQLOPS_SQL_NOTEBOOK'] !== undefined;
|
return process.env['SQLOPS_SQL_NOTEBOOK'] !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IStandardKernelWithProvider {
|
||||||
|
readonly name: string;
|
||||||
|
readonly connectionProviderIds: string[];
|
||||||
|
readonly notebookProvider: string;
|
||||||
|
}
|
||||||
@@ -325,7 +325,7 @@ output-component .jp-RenderedHTMLCommon table {
|
|||||||
border: none;
|
border: none;
|
||||||
color: var(--jp-ui-font-color1);
|
color: var(--jp-ui-font-color1);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
table-layout: fixed;
|
table-layout: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
@@ -338,7 +338,7 @@ output-component .jp-RenderedHTMLCommon thead {
|
|||||||
output-component .jp-RenderedHTMLCommon td,
|
output-component .jp-RenderedHTMLCommon td,
|
||||||
output-component .jp-RenderedHTMLCommon th,
|
output-component .jp-RenderedHTMLCommon th,
|
||||||
output-component .jp-RenderedHTMLCommon tr {
|
output-component .jp-RenderedHTMLCommon tr {
|
||||||
text-align: right;
|
text-align: left;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
padding: 0.5em 0.5em;
|
padding: 0.5em 0.5em;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
@@ -370,6 +370,7 @@ output-component .jp-RenderedHTMLCommon tbody tr:hover {
|
|||||||
|
|
||||||
output-component .jp-RenderedHTMLCommon table {
|
output-component .jp-RenderedHTMLCommon table {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
display: table-row;
|
||||||
}
|
}
|
||||||
|
|
||||||
output-component .jp-RenderedHTMLCommon p {
|
output-component .jp-RenderedHTMLCommon p {
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// TODO: The content of this file should be refactored to an extension
|
|
||||||
export function getKnoxUrl(host: string, port: string): string {
|
|
||||||
return `https://${host}:${port}/gateway`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getLivyUrl(serverName: string, port: string): string {
|
|
||||||
return getKnoxUrl(serverName, port) + '/default/livy/v1/';
|
|
||||||
}
|
|
||||||
16
src/sql/sqlops.proposed.d.ts
vendored
16
src/sql/sqlops.proposed.d.ts
vendored
@@ -1594,6 +1594,11 @@ declare module 'sqlops' {
|
|||||||
* Optional ID indicating the initial connection to use for this editor
|
* Optional ID indicating the initial connection to use for this editor
|
||||||
*/
|
*/
|
||||||
connectionId?: string;
|
connectionId?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default kernel for notebook
|
||||||
|
*/
|
||||||
|
defaultKernel?: nb.IKernelSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1666,9 +1671,14 @@ declare module 'sqlops' {
|
|||||||
*/
|
*/
|
||||||
export function registerNotebookProvider(provider: NotebookProvider): vscode.Disposable;
|
export function registerNotebookProvider(provider: NotebookProvider): vscode.Disposable;
|
||||||
|
|
||||||
|
export interface IStandardKernel {
|
||||||
|
readonly name: string;
|
||||||
|
readonly connectionProviderIds: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface NotebookProvider {
|
export interface NotebookProvider {
|
||||||
readonly providerId: string;
|
readonly providerId: string;
|
||||||
readonly standardKernels: string[];
|
readonly standardKernels: IStandardKernel[];
|
||||||
getNotebookManager(notebookUri: vscode.Uri): Thenable<NotebookManager>;
|
getNotebookManager(notebookUri: vscode.Uri): Thenable<NotebookManager>;
|
||||||
handleNotebookClosed(notebookUri: vscode.Uri): void;
|
handleNotebookClosed(notebookUri: vscode.Uri): void;
|
||||||
}
|
}
|
||||||
@@ -1945,6 +1955,10 @@ declare module 'sqlops' {
|
|||||||
defaultKernelLoaded?: boolean;
|
defaultKernelLoaded?: boolean;
|
||||||
|
|
||||||
changeKernel(kernelInfo: IKernelSpec): Thenable<IKernel>;
|
changeKernel(kernelInfo: IKernelSpec): Thenable<IKernel>;
|
||||||
|
|
||||||
|
configureKernel(kernelInfo: IKernelSpec): Thenable<void>;
|
||||||
|
|
||||||
|
configureConnection(connection: IConnectionProfile): Thenable<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISessionOptions {
|
export interface ISessionOptions {
|
||||||
|
|||||||
@@ -125,6 +125,16 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
return session.changeKernel(kernelInfo).then(kernel => this.saveKernel(kernel));
|
return session.changeKernel(kernelInfo).then(kernel => this.saveKernel(kernel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$configureKernel(sessionId: number, kernelInfo: sqlops.nb.IKernelSpec): Thenable<void> {
|
||||||
|
let session = this._getAdapter<sqlops.nb.ISession>(sessionId);
|
||||||
|
return session.configureKernel(kernelInfo).then(() => null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$configureConnection(sessionId: number, connection: sqlops.IConnectionProfile): Thenable<void> {
|
||||||
|
let session = this._getAdapter<sqlops.nb.ISession>(sessionId);
|
||||||
|
return session.configureConnection(connection).then(() => null);
|
||||||
|
}
|
||||||
|
|
||||||
$getKernelReadyStatus(kernelId: number): Thenable<sqlops.nb.IInfoReply> {
|
$getKernelReadyStatus(kernelId: number): Thenable<sqlops.nb.IInfoReply> {
|
||||||
let kernel = this._getAdapter<sqlops.nb.IKernel>(kernelId);
|
let kernel = this._getAdapter<sqlops.nb.IKernel>(kernelId);
|
||||||
return kernel.ready.then(success => kernel.info);
|
return kernel.ready.then(success => kernel.info);
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ export class ExtHostNotebookDocumentsAndEditors implements ExtHostNotebookDocume
|
|||||||
options.position = showOptions.viewColumn;
|
options.position = showOptions.viewColumn;
|
||||||
options.providerId = showOptions.providerId;
|
options.providerId = showOptions.providerId;
|
||||||
options.connectionId = showOptions.connectionId;
|
options.connectionId = showOptions.connectionId;
|
||||||
|
options.defaultKernel = showOptions.defaultKernel;
|
||||||
}
|
}
|
||||||
let id = await this._proxy.$tryShowNotebookDocument(uri, options);
|
let id = await this._proxy.$tryShowNotebookDocument(uri, options);
|
||||||
let editor = this.getEditor(id);
|
let editor = this.getEditor(id);
|
||||||
|
|||||||
@@ -288,11 +288,30 @@ class SessionWrapper implements sqlops.nb.ISession {
|
|||||||
return this.doChangeKernel(kernelInfo);
|
return this.doChangeKernel(kernelInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configureKernel(kernelInfo: sqlops.nb.IKernelSpec): Thenable<void> {
|
||||||
|
return this.doConfigureKernel(kernelInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
configureConnection(connection: sqlops.IConnectionProfile): Thenable<void> {
|
||||||
|
if (connection['capabilitiesService'] !== undefined) {
|
||||||
|
connection['capabilitiesService'] = undefined;
|
||||||
|
}
|
||||||
|
return this.doConfigureConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
private async doChangeKernel(kernelInfo: sqlops.nb.IKernelSpec): Promise<sqlops.nb.IKernel> {
|
private async doChangeKernel(kernelInfo: sqlops.nb.IKernelSpec): Promise<sqlops.nb.IKernel> {
|
||||||
let kernelDetails = await this._proxy.ext.$changeKernel(this.sessionDetails.sessionId, kernelInfo);
|
let kernelDetails = await this._proxy.ext.$changeKernel(this.sessionDetails.sessionId, kernelInfo);
|
||||||
this._kernel = new KernelWrapper(this._proxy, kernelDetails);
|
this._kernel = new KernelWrapper(this._proxy, kernelDetails);
|
||||||
return this._kernel;
|
return this._kernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async doConfigureKernel(kernelInfo: sqlops.nb.IKernelSpec): Promise<void> {
|
||||||
|
await this._proxy.ext.$configureKernel(this.sessionDetails.sessionId, kernelInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async doConfigureConnection(connection: sqlops.IConnectionProfile): Promise<void> {
|
||||||
|
await this._proxy.ext.$configureConnection(this.sessionDetails.sessionId, connection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KernelWrapper implements sqlops.nb.IKernel {
|
class KernelWrapper implements sqlops.nb.IKernel {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
import { NotebookInputModel, NotebookInput } from 'sql/parts/notebook/notebookInput';
|
import { NotebookInputModel, NotebookInput } from 'sql/parts/notebook/notebookInput';
|
||||||
import { INotebookService, INotebookEditor, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/common/notebookService';
|
import { INotebookService, INotebookEditor, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/common/notebookService';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { getProvidersForFileName } from 'sql/parts/notebook/notebookUtils';
|
import { getProvidersForFileName, getStandardKernelsForProvider } from 'sql/parts/notebook/notebookUtils';
|
||||||
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { disposed } from 'vs/base/common/errors';
|
import { disposed } from 'vs/base/common/errors';
|
||||||
import { ICellModel, NotebookContentChange } from 'sql/parts/notebook/models/modelInterfaces';
|
import { ICellModel, NotebookContentChange } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
@@ -332,6 +332,11 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
|||||||
}
|
}
|
||||||
model.providers = providers;
|
model.providers = providers;
|
||||||
model.providerId = providerId;
|
model.providerId = providerId;
|
||||||
|
model.defaultKernel = options && options.defaultKernel;
|
||||||
|
model.providers.forEach(provider => {
|
||||||
|
let standardKernels = getStandardKernelsForProvider(provider, this._notebookService);
|
||||||
|
model.standardKernels = standardKernels;
|
||||||
|
});
|
||||||
let input = this._instantiationService.createInstance(NotebookInput, undefined, model);
|
let input = this._instantiationService.createInstance(NotebookInput, undefined, model);
|
||||||
|
|
||||||
let editor = await this._editorService.openEditor(input, editorOptions, viewColumnToEditorGroup(this._editorGroupService, options.position));
|
let editor = await this._editorService.openEditor(input, editorOptions, viewColumnToEditorGroup(this._editorGroupService, options.position));
|
||||||
|
|||||||
@@ -773,6 +773,8 @@ export interface ExtHostNotebookShape {
|
|||||||
|
|
||||||
// Session APIs
|
// Session APIs
|
||||||
$changeKernel(sessionId: number, kernelInfo: sqlops.nb.IKernelSpec): Thenable<INotebookKernelDetails>;
|
$changeKernel(sessionId: number, kernelInfo: sqlops.nb.IKernelSpec): Thenable<INotebookKernelDetails>;
|
||||||
|
$configureKernel(sessionId: number, kernelInfo: sqlops.nb.IKernelSpec): Thenable<void>;
|
||||||
|
$configureConnection(sessionId: number, connection: sqlops.IConnectionProfile): Thenable<void>;
|
||||||
|
|
||||||
// Kernel APIs
|
// Kernel APIs
|
||||||
$getKernelReadyStatus(kernelId: number): Thenable<sqlops.nb.IInfoReply>;
|
$getKernelReadyStatus(kernelId: number): Thenable<sqlops.nb.IInfoReply>;
|
||||||
@@ -829,6 +831,7 @@ export interface INotebookShowOptions {
|
|||||||
preview?: boolean;
|
preview?: boolean;
|
||||||
providerId?: string;
|
providerId?: string;
|
||||||
connectionId?: string;
|
connectionId?: string;
|
||||||
|
defaultKernel?: sqlops.nb.IKernelSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtHostNotebookDocumentsAndEditorsShape {
|
export interface ExtHostNotebookDocumentsAndEditorsShape {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
|||||||
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import * as platform from 'vs/platform/registry/common/platform';
|
import * as platform from 'vs/platform/registry/common/platform';
|
||||||
|
import * as sqlops from 'sqlops';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
export const Extensions = {
|
export const Extensions = {
|
||||||
@@ -18,7 +19,7 @@ export const Extensions = {
|
|||||||
export interface NotebookProviderRegistration {
|
export interface NotebookProviderRegistration {
|
||||||
provider: string;
|
provider: string;
|
||||||
fileExtensions: string | string[];
|
fileExtensions: string | string[];
|
||||||
standardKernels: string | string[];
|
standardKernels: sqlops.nb.IStandardKernel | sqlops.nb.IStandardKernel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let notebookProviderType: IJSONSchema = {
|
let notebookProviderType: IJSONSchema = {
|
||||||
@@ -44,13 +45,40 @@ let notebookProviderType: IJSONSchema = {
|
|||||||
standardKernels: {
|
standardKernels: {
|
||||||
description: localize('carbon.extension.contributes.notebook.standardKernels', 'What kernels should be standard with this notebook provider'),
|
description: localize('carbon.extension.contributes.notebook.standardKernels', 'What kernels should be standard with this notebook provider'),
|
||||||
oneOf: [
|
oneOf: [
|
||||||
{ type: 'string' },
|
|
||||||
{
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
connectionProviderIds: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: {
|
items: {
|
||||||
type: 'string'
|
type: 'string'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
connectionProviderIds: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ export interface INotebookService {
|
|||||||
|
|
||||||
getProvidersForFileType(fileType: string): string[];
|
getProvidersForFileType(fileType: string): string[];
|
||||||
|
|
||||||
|
getStandardKernelsForProvider(provider: string): sqlops.nb.IStandardKernel[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes and returns a Notebook manager that can handle all important calls to open, display, and
|
* Initializes and returns a Notebook manager that can handle all important calls to open, display, and
|
||||||
* run cells in a notebook.
|
* run cells in a notebook.
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
private _onNotebookEditorRename = new Emitter<INotebookEditor>();
|
private _onNotebookEditorRename = new Emitter<INotebookEditor>();
|
||||||
private _editors = new Map<string, INotebookEditor>();
|
private _editors = new Map<string, INotebookEditor>();
|
||||||
private _fileToProviders = new Map<string, NotebookProviderRegistration[]>();
|
private _fileToProviders = new Map<string, NotebookProviderRegistration[]>();
|
||||||
|
private _providerToStandardKernels = new Map<string, nb.IStandardKernel[]>();
|
||||||
private _registrationComplete = new Deferred<void>();
|
private _registrationComplete = new Deferred<void>();
|
||||||
private _isRegistrationComplete = false;
|
private _isRegistrationComplete = false;
|
||||||
|
|
||||||
@@ -121,6 +122,9 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
this.addFileProvider(registration.fileExtensions, registration);
|
this.addFileProvider(registration.fileExtensions, registration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (registration.standardKernels) {
|
||||||
|
this.addStandardKernels(registration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerProvider(providerId: string, instance: INotebookProvider): void {
|
registerProvider(providerId: string, instance: INotebookProvider): void {
|
||||||
@@ -154,6 +158,26 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
this._fileToProviders.set(fileType.toUpperCase(), providers);
|
this._fileToProviders.set(fileType.toUpperCase(), providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Standard kernels are contributed where a list of kernels are defined that can be shown
|
||||||
|
// 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
|
||||||
|
// kernels to the dropdown
|
||||||
|
private addStandardKernels(provider: NotebookProviderRegistration) {
|
||||||
|
let providerUpperCase = provider.provider.toUpperCase();
|
||||||
|
let standardKernels = this._providerToStandardKernels.get(providerUpperCase);
|
||||||
|
if (!standardKernels) {
|
||||||
|
standardKernels = [];
|
||||||
|
}
|
||||||
|
if (Array.isArray(provider.standardKernels)) {
|
||||||
|
provider.standardKernels.forEach(kernel => {
|
||||||
|
standardKernels.push(kernel);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
standardKernels.push(provider.standardKernels);
|
||||||
|
}
|
||||||
|
this._providerToStandardKernels.set(providerUpperCase, standardKernels);
|
||||||
|
}
|
||||||
|
|
||||||
getSupportedFileExtensions(): string[] {
|
getSupportedFileExtensions(): string[] {
|
||||||
return Array.from(this._fileToProviders.keys());
|
return Array.from(this._fileToProviders.keys());
|
||||||
}
|
}
|
||||||
@@ -165,6 +189,10 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
return providers ? providers.map(provider => provider.provider) : undefined;
|
return providers ? providers.map(provider => provider.provider) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getStandardKernelsForProvider(provider: string): nb.IStandardKernel[] {
|
||||||
|
return this._providerToStandardKernels.get(provider.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
public shutdown(): void {
|
public shutdown(): void {
|
||||||
this._managersMap.forEach(manager => {
|
this._managersMap.forEach(manager => {
|
||||||
manager.forEach(m => {
|
manager.forEach(m => {
|
||||||
@@ -337,7 +365,7 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
notebookRegistry.registerNotebookProvider({
|
notebookRegistry.registerNotebookProvider({
|
||||||
provider: sqlProvider.providerId,
|
provider: sqlProvider.providerId,
|
||||||
fileExtensions: DEFAULT_NOTEBOOK_FILETYPE,
|
fileExtensions: DEFAULT_NOTEBOOK_FILETYPE,
|
||||||
standardKernels: ['SQL']
|
standardKernels: { name: 'SQL', connectionProviderIds: ['MSSQL'] }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -444,5 +472,4 @@ export class SqlNotebookManager implements INotebookManager {
|
|||||||
public get sessionManager(): nb.SessionManager {
|
public get sessionManager(): nb.SessionManager {
|
||||||
return this._sessionManager;
|
return this._sessionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
import { nb } from 'sqlops';
|
import { nb } from 'sqlops';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { FutureInternal } from 'sql/parts/notebook/models/modelInterfaces';
|
import { FutureInternal } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
|
|
||||||
export const noKernel: string = localize('noKernel', 'No Kernel');
|
export const noKernel: string = localize('noKernel', 'No Kernel');
|
||||||
const runNotebookDisabled = localize('runNotebookDisabled', 'Cannot run cells as no kernel has been configured');
|
const runNotebookDisabled = localize('runNotebookDisabled', 'Cannot run cells as no kernel has been configured');
|
||||||
@@ -91,6 +92,15 @@ export class EmptySession implements nb.ISession {
|
|||||||
changeKernel(kernelInfo: nb.IKernelSpec): Thenable<nb.IKernel> {
|
changeKernel(kernelInfo: nb.IKernelSpec): Thenable<nb.IKernel> {
|
||||||
return Promise.resolve(this.kernel);
|
return Promise.resolve(this.kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No kernel config necessary for empty session
|
||||||
|
configureKernel(kernelInfo: nb.IKernelSpec): Thenable<void> {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
configureConnection(connection: ConnectionProfile): Thenable<void> {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmptyKernel implements nb.IKernel {
|
class EmptyKernel implements nb.IKernel {
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ import Severity from 'vs/base/common/severity';
|
|||||||
import * as Utils from 'sql/platform/connection/common/utils';
|
import * as Utils from 'sql/platform/connection/common/utils';
|
||||||
import { Deferred } from 'sql/base/common/promise';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
|
||||||
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
||||||
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
|
|
||||||
export const sqlKernel: string = localize('sqlKernel', 'SQL');
|
export const sqlKernel: string = localize('sqlKernel', 'SQL');
|
||||||
export const sqlKernelError: string = localize("sqlKernelError", "SQL kernel error");
|
export const sqlKernelError: string = localize("sqlKernelError", "SQL kernel error");
|
||||||
@@ -63,6 +64,7 @@ export class SqlSessionManager implements nb.SessionManager {
|
|||||||
export class SqlSession implements nb.ISession {
|
export class SqlSession implements nb.ISession {
|
||||||
private _kernel: SqlKernel;
|
private _kernel: SqlKernel;
|
||||||
private _defaultKernelLoaded = false;
|
private _defaultKernelLoaded = false;
|
||||||
|
private _currentConnection: IConnectionProfile;
|
||||||
|
|
||||||
public set defaultKernelLoaded(value) {
|
public set defaultKernelLoaded(value) {
|
||||||
this._defaultKernelLoaded = value;
|
this._defaultKernelLoaded = value;
|
||||||
@@ -107,12 +109,25 @@ export class SqlSession implements nb.ISession {
|
|||||||
changeKernel(kernelInfo: nb.IKernelSpec): Thenable<nb.IKernel> {
|
changeKernel(kernelInfo: nb.IKernelSpec): Thenable<nb.IKernel> {
|
||||||
return Promise.resolve(this.kernel);
|
return Promise.resolve(this.kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configureKernel(kernelInfo: nb.IKernelSpec): Thenable<void> {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
configureConnection(connection: ConnectionProfile): Thenable<void> {
|
||||||
|
if (this._kernel) {
|
||||||
|
this._kernel.connection = connection;
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SqlKernel extends Disposable implements nb.IKernel {
|
class SqlKernel extends Disposable implements nb.IKernel {
|
||||||
private _queryRunner: QueryRunner;
|
private _queryRunner: QueryRunner;
|
||||||
private _columns: IDbColumn[];
|
private _columns: IDbColumn[];
|
||||||
private _rows: DbCellValue[][];
|
private _rows: DbCellValue[][];
|
||||||
|
private _currentConnection: IConnectionProfile;
|
||||||
|
static kernelId: number = 0;
|
||||||
|
|
||||||
constructor( @IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
constructor( @IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||||
@@ -121,7 +136,7 @@ class SqlKernel extends Disposable implements nb.IKernel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get id(): string {
|
public get id(): string {
|
||||||
return '-1';
|
return (SqlKernel.kernelId++).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get name(): string {
|
public get name(): string {
|
||||||
@@ -159,6 +174,12 @@ class SqlKernel extends Disposable implements nb.IKernel {
|
|||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set connection(conn: IConnectionProfile) {
|
||||||
|
this._currentConnection = conn;
|
||||||
|
this._queryRunner = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
getSpec(): Thenable<nb.IKernelSpec> {
|
getSpec(): Thenable<nb.IKernelSpec> {
|
||||||
return Promise.resolve(sqlKernelSpec);
|
return Promise.resolve(sqlKernelSpec);
|
||||||
}
|
}
|
||||||
@@ -167,11 +188,10 @@ class SqlKernel extends Disposable implements nb.IKernel {
|
|||||||
if (this._queryRunner) {
|
if (this._queryRunner) {
|
||||||
this._queryRunner.runQuery(content.code);
|
this._queryRunner.runQuery(content.code);
|
||||||
} else {
|
} else {
|
||||||
let connections = this._connectionManagementService.getActiveConnections();
|
let connectionUri = Utils.generateUri(this._currentConnection, 'notebook');
|
||||||
let connectionProfile = connections.find(connection => connection.providerName === mssqlProviderName);
|
|
||||||
let connectionUri = Utils.generateUri(connectionProfile, 'notebook');
|
|
||||||
this._queryRunner = this._instantiationService.createInstance(QueryRunner, connectionUri, undefined);
|
this._queryRunner = this._instantiationService.createInstance(QueryRunner, connectionUri, undefined);
|
||||||
this._connectionManagementService.connect(connectionProfile, connectionUri).then((result) => {
|
this._connectionManagementService.connect(this._currentConnection, connectionUri).then((result) =>
|
||||||
|
{
|
||||||
this.addQueryEventListeners(this._queryRunner);
|
this.addQueryEventListeners(this._queryRunner);
|
||||||
this._queryRunner.runQuery(content.code);
|
this._queryRunner.runQuery(content.code);
|
||||||
});
|
});
|
||||||
@@ -186,7 +206,9 @@ class SqlKernel extends Disposable implements nb.IKernel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interrupt(): Thenable<void> {
|
interrupt(): Thenable<void> {
|
||||||
return Promise.resolve(undefined);
|
// TODO: figure out what to do with the QueryCancelResult
|
||||||
|
return this._queryRunner.cancelQuery().then((cancelResult) => {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private addQueryEventListeners(queryRunner: QueryRunner): void {
|
private addQueryEventListeners(queryRunner: QueryRunner): void {
|
||||||
@@ -234,7 +256,11 @@ export class SQLFuture extends Disposable implements FutureInternal {
|
|||||||
get inProgress(): boolean {
|
get inProgress(): boolean {
|
||||||
return !this._queryRunner.hasCompleted;
|
return !this._queryRunner.hasCompleted;
|
||||||
}
|
}
|
||||||
|
set inProgress(val: boolean) {
|
||||||
|
if (this._queryRunner && !val) {
|
||||||
|
this._queryRunner.cancelQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
get msg(): nb.IMessage {
|
get msg(): nb.IMessage {
|
||||||
return this._msg;
|
return this._msg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ export class NotebookModelStub implements INotebookModel {
|
|||||||
get providerId(): string {
|
get providerId(): string {
|
||||||
throw new Error('method not implemented.');
|
throw new Error('method not implemented.');
|
||||||
}
|
}
|
||||||
|
get applicableConnectionProviderIds(): string[] {
|
||||||
|
throw new Error('method not implemented.');
|
||||||
|
}
|
||||||
changeKernel(displayName: string): void {
|
changeKernel(displayName: string): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
@@ -77,6 +80,9 @@ export class NotebookModelStub implements INotebookModel {
|
|||||||
pushEditOperations(edits: ISingleNotebookEditOperation[]): void {
|
pushEditOperations(edits: ISingleNotebookEditOperation[]): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
getApplicableConnectionProviderIds(kernelName: string): string[] {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotebookManagerStub implements INotebookManager {
|
export class NotebookManagerStub implements INotebookManager {
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import { Deferred } from 'sql/base/common/promise';
|
|||||||
import { ConnectionManagementService } from 'sql/platform/connection/common/connectionManagementService';
|
import { ConnectionManagementService } from 'sql/platform/connection/common/connectionManagementService';
|
||||||
import { Memento } from 'vs/workbench/common/memento';
|
import { Memento } from 'vs/workbench/common/memento';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
|
||||||
|
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
|
|
||||||
let expectedNotebookContent: nb.INotebookContents = {
|
let expectedNotebookContent: nb.INotebookContents = {
|
||||||
cells: [{
|
cells: [{
|
||||||
@@ -71,8 +73,9 @@ let mockClientSession: TypeMoq.Mock<IClientSession>;
|
|||||||
let sessionReady: Deferred<void>;
|
let sessionReady: Deferred<void>;
|
||||||
let mockModelFactory: TypeMoq.Mock<ModelFactory>;
|
let mockModelFactory: TypeMoq.Mock<ModelFactory>;
|
||||||
let notificationService: TypeMoq.Mock<INotificationService>;
|
let notificationService: TypeMoq.Mock<INotificationService>;
|
||||||
|
let capabilitiesService: TypeMoq.Mock<ICapabilitiesService>;
|
||||||
|
|
||||||
describe('notebook model', function (): void {
|
describe('notebook model', function(): void {
|
||||||
let notebookManagers = [new NotebookManagerStub()];
|
let notebookManagers = [new NotebookManagerStub()];
|
||||||
let memento: TypeMoq.Mock<Memento>;
|
let memento: TypeMoq.Mock<Memento>;
|
||||||
let queryConnectionService: TypeMoq.Mock<ConnectionManagementService>;
|
let queryConnectionService: TypeMoq.Mock<ConnectionManagementService>;
|
||||||
@@ -80,6 +83,7 @@ describe('notebook model', function (): void {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
sessionReady = new Deferred<void>();
|
sessionReady = new Deferred<void>();
|
||||||
notificationService = TypeMoq.Mock.ofType(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
notificationService = TypeMoq.Mock.ofType(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
||||||
|
capabilitiesService = TypeMoq.Mock.ofType(CapabilitiesTestService);
|
||||||
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
||||||
memento.setup(x => x.getMemento(TypeMoq.It.isAny())).returns(() => void 0);
|
memento.setup(x => x.getMemento(TypeMoq.It.isAny())).returns(() => void 0);
|
||||||
queryConnectionService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined);
|
queryConnectionService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined);
|
||||||
@@ -90,7 +94,10 @@ describe('notebook model', function (): void {
|
|||||||
notebookManagers,
|
notebookManagers,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
connectionService: queryConnectionService.object,
|
connectionService: queryConnectionService.object,
|
||||||
providerId: 'jupyter'
|
providerId: 'SQL',
|
||||||
|
standardKernels: [{ name: 'SQL', connectionProviderIds: ['MSSQL'], notebookProvider: 'sql' }],
|
||||||
|
defaultKernel: undefined,
|
||||||
|
capabilitiesService: capabilitiesService.object
|
||||||
};
|
};
|
||||||
mockClientSession = TypeMoq.Mock.ofType(ClientSession, undefined, defaultModelOptions);
|
mockClientSession = TypeMoq.Mock.ofType(ClientSession, undefined, defaultModelOptions);
|
||||||
mockClientSession.setup(c => c.initialize(TypeMoq.It.isAny())).returns(() => {
|
mockClientSession.setup(c => c.initialize(TypeMoq.It.isAny())).returns(() => {
|
||||||
@@ -104,7 +111,7 @@ describe('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should create no cells if model has no contents', async function (): Promise<void> {
|
it('Should create no cells if model has no contents', async function(): Promise<void> {
|
||||||
// Given an empty notebook
|
// Given an empty notebook
|
||||||
let emptyNotebook: nb.INotebookContents = {
|
let emptyNotebook: nb.INotebookContents = {
|
||||||
cells: [],
|
cells: [],
|
||||||
@@ -130,7 +137,7 @@ describe('notebook model', function (): void {
|
|||||||
should(model.cells).have.length(0);
|
should(model.cells).have.length(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should throw if model load fails', async function (): Promise<void> {
|
it('Should throw if model load fails', async function(): Promise<void> {
|
||||||
// Given a call to get Contents fails
|
// Given a call to get Contents fails
|
||||||
let error = new Error('File not found');
|
let error = new Error('File not found');
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager);
|
||||||
@@ -145,7 +152,7 @@ describe('notebook model', function (): void {
|
|||||||
should(model.inErrorState).be.true();
|
should(model.inErrorState).be.true();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should convert cell info to CellModels', async function (): Promise<void> {
|
it('Should convert cell info to CellModels', async function(): Promise<void> {
|
||||||
// Given a notebook with 2 cells
|
// Given a notebook with 2 cells
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager);
|
||||||
mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
@@ -161,7 +168,7 @@ describe('notebook model', function (): void {
|
|||||||
should(model.cells[1].source).be.equal(expectedNotebookContent.cells[1].source);
|
should(model.cells[1].source).be.equal(expectedNotebookContent.cells[1].source);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should load contents but then go to error state if client session startup fails', async function (): Promise<void> {
|
it('Should load contents but then go to error state if client session startup fails', async function(): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager);
|
||||||
mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContentOneCell));
|
mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContentOneCell));
|
||||||
notebookManagers[0].contentManager = mockContentManager.object;
|
notebookManagers[0].contentManager = mockContentManager.object;
|
||||||
@@ -172,7 +179,7 @@ describe('notebook model', function (): void {
|
|||||||
sessionReady.resolve();
|
sessionReady.resolve();
|
||||||
let sessionFired = false;
|
let sessionFired = false;
|
||||||
|
|
||||||
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);
|
let model = new NotebookModel(options);
|
||||||
@@ -190,7 +197,7 @@ describe('notebook model', function (): void {
|
|||||||
should(sessionFired).be.false();
|
should(sessionFired).be.false();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should not be in error state if client session initialization succeeds', async function (): Promise<void> {
|
it('Should not be in error state if client session initialization succeeds', async function(): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(LocalContentManager);
|
||||||
mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContentOneCell));
|
mockContentManager.setup(c => c.getNotebookContents(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedNotebookContentOneCell));
|
||||||
notebookManagers[0].contentManager = mockContentManager.object;
|
notebookManagers[0].contentManager = mockContentManager.object;
|
||||||
@@ -205,7 +212,7 @@ describe('notebook model', function (): void {
|
|||||||
sessionReady.resolve();
|
sessionReady.resolve();
|
||||||
let actualSession: IClientSession = undefined;
|
let actualSession: IClientSession = undefined;
|
||||||
|
|
||||||
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, false);
|
let model = new NotebookModel(options, false);
|
||||||
@@ -225,14 +232,14 @@ describe('notebook model', function (): void {
|
|||||||
should(model.clientSession).equal(mockClientSession.object);
|
should(model.clientSession).equal(mockClientSession.object);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should sanitize kernel display name when IP is included', async function (): Promise<void> {
|
it('Should sanitize kernel display name when IP is included', async function(): Promise<void> {
|
||||||
let model = new NotebookModel(defaultModelOptions);
|
let model = new NotebookModel(defaultModelOptions);
|
||||||
let displayName = 'PySpark (1.1.1.1)';
|
let displayName = 'PySpark (1.1.1.1)';
|
||||||
let sanitizedDisplayName = model.sanitizeDisplayName(displayName);
|
let sanitizedDisplayName = model.sanitizeDisplayName(displayName);
|
||||||
should(sanitizedDisplayName).equal('PySpark');
|
should(sanitizedDisplayName).equal('PySpark');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should sanitize kernel display name properly when IP is not included', async function (): Promise<void> {
|
it('Should sanitize kernel display name properly when IP is not included', async function(): Promise<void> {
|
||||||
let model = new NotebookModel(defaultModelOptions);
|
let model = new NotebookModel(defaultModelOptions);
|
||||||
let displayName = 'PySpark';
|
let displayName = 'PySpark';
|
||||||
let sanitizedDisplayName = model.sanitizeDisplayName(displayName);
|
let sanitizedDisplayName = model.sanitizeDisplayName(displayName);
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ suite('ExtHostNotebook Tests', () => {
|
|||||||
|
|
||||||
class NotebookProviderStub implements sqlops.nb.NotebookProvider {
|
class NotebookProviderStub implements sqlops.nb.NotebookProvider {
|
||||||
providerId: string = 'TestProvider';
|
providerId: string = 'TestProvider';
|
||||||
standardKernels: string[] = ['fakeKernel'];
|
standardKernels: sqlops.nb.IStandardKernel[] = [{name: 'fakeKernel', connectionProviderIds: ['MSSQL']}];
|
||||||
|
|
||||||
getNotebookManager(notebookUri: vscode.Uri): Thenable<sqlops.nb.NotebookManager> {
|
getNotebookManager(notebookUri: vscode.Uri): Thenable<sqlops.nb.NotebookManager> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
|
|||||||
@@ -149,6 +149,12 @@ class ExtHostNotebookStub implements ExtHostNotebookShape {
|
|||||||
$changeKernel(sessionId: number, kernelInfo: sqlops.nb.IKernelSpec): Thenable<INotebookKernelDetails> {
|
$changeKernel(sessionId: number, kernelInfo: sqlops.nb.IKernelSpec): Thenable<INotebookKernelDetails> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
$configureKernel(sessionId: number, kernelInfo: sqlops.nb.IKernelSpec): Thenable<void> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
$configureConnection(sessionId: number, conneection: sqlops.IConnectionProfile): Thenable<void> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
$getKernelReadyStatus(kernelId: number): Thenable<sqlops.nb.IInfoReply> {
|
$getKernelReadyStatus(kernelId: number): Thenable<sqlops.nb.IInfoReply> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user