Machine Learning Services - Enabling external script for package management only (#9519)

* Machine learning services extension - removed config table and added config update to package manager
This commit is contained in:
Leila Lali
2020-03-19 16:48:33 -07:00
committed by GitHub
parent 35b27f1304
commit 1520441b84
20 changed files with 145 additions and 340 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><defs><style>.cls-1{fill:url(#linear-gradient);}.cls-2{fill:url(#linear-gradient-2);}.cls-3{fill:url(#linear-gradient-3);}.cls-4{fill:none;}</style><linearGradient id="linear-gradient" x1="15.985" y1="32" x2="15.985" y2="7.226" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#5ea0ef"/><stop offset="1" stop-color="#83b9f9"/></linearGradient><linearGradient id="linear-gradient-2" x1="4.335" y1="31.971" x2="4.335" y2="14.658" gradientUnits="userSpaceOnUse"><stop offset="0.101" stop-color="#32bedd"/><stop offset="1" stop-color="#50e6ff"/></linearGradient><linearGradient id="linear-gradient-3" x1="27.665" y1="31.971" x2="27.665" gradientUnits="userSpaceOnUse"><stop offset="0.243" stop-color="#0078d7"/><stop offset="1" stop-color="#5ea0ef"/></linearGradient></defs><title>j_</title><rect class="cls-1" x="12.313" y="7.226" width="7.344" height="24.774" rx="0.826"/><rect class="cls-2" x="0.664" y="14.658" width="7.344" height="17.312" rx="0.826"/><rect class="cls-3" x="23.993" width="7.344" height="31.971" rx="0.826"/><rect class="cls-4" width="32" height="32"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{font-size:16px;font-family:FullMDL2Assets, Full MDL2 Assets;}</style></defs><title>v_</title><text class="cls-1" transform="translate(0 16)"></text></svg>

After

Width:  |  Height:  |  Size: 270 B

View File

@@ -1,5 +1,5 @@
{ {
"name": "machineLearningServices", "name": "machine-learning-services",
"displayName": "%displayName%", "displayName": "%displayName%",
"description": "%description%", "description": "%description%",
"version": "1.0.0", "version": "1.0.0",
@@ -14,7 +14,7 @@
"onDashboardOpen" "onDashboardOpen"
], ],
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt", "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
"icon": "images/ML_ExtensionIcon.png", "icon": "images/extensionIcon.png",
"aiKey": "AIF-37eefaf0-8022-4671-a3fb-64752724682e", "aiKey": "AIF-37eefaf0-8022-4671-a3fb-64752724682e",
"main": "./out/main", "main": "./out/main",
"repository": { "repository": {
@@ -59,7 +59,11 @@
}, },
{ {
"command": "mls.command.predictModel", "command": "mls.command.predictModel",
"title": "%mls.command.predictModel%" "title": "%mls.command.predictModel%",
"icon": {
"light": "./images/makePredictions.svg",
"dark": "./images/makePredictions.svg"
}
}, },
{ {
"command": "mls.command.manageModels", "command": "mls.command.manageModels",
@@ -67,7 +71,11 @@
}, },
{ {
"command": "mls.command.registerModel", "command": "mls.command.registerModel",
"title": "%mls.command.registerModel%" "title": "%mls.command.registerModel%",
"icon": {
"light": "./images/registerModel.svg",
"dark": "./images/registerModel.svg"
}
}, },
{ {
"command": "mls.command.manageLanguages", "command": "mls.command.manageLanguages",
@@ -95,20 +103,10 @@
"when": "connectionProvider == 'MSSQL' && !mssql:iscloud && dashboardContext == 'server'", "when": "connectionProvider == 'MSSQL' && !mssql:iscloud && dashboardContext == 'server'",
"container": { "container": {
"grid-container": [ "grid-container": [
{
"name": "%title.configurations%",
"row": 0,
"col": 0,
"widget": {
"modelview": {
"id": "ml.tasks"
}
}
},
{ {
"name": "%title.tasks%", "name": "%title.tasks%",
"row": 0, "row": 0,
"col": 1, "col": 0,
"widget": { "widget": {
"tasks-widget": [ "tasks-widget": [
"mls.command.managePackages", "mls.command.managePackages",
@@ -120,8 +118,8 @@
}, },
{ {
"name": "%title.documents%", "name": "%title.documents%",
"row": 1, "row": 0,
"col": 0, "col": 1,
"widget": { "widget": {
"tasks-widget": [ "tasks-widget": [
"mls.command.odbcdriver", "mls.command.odbcdriver",
@@ -138,7 +136,7 @@
"request": "^2.88.0", "request": "^2.88.0",
"vscode-nls": "^4.0.0", "vscode-nls": "^4.0.0",
"vscode-languageclient": "^5.3.0-next.1", "vscode-languageclient": "^5.3.0-next.1",
"@azure/arm-machinelearningservices" : "^3.0.0", "@azure/arm-machinelearningservices": "^3.0.0",
"polly-js": "^1.6.3" "polly-js": "^1.6.3"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -5,8 +5,8 @@
"title.documents": "Documents", "title.documents": "Documents",
"title.configurations": "Configurations", "title.configurations": "Configurations",
"title.endpoints": "Endpoints", "title.endpoints": "Endpoints",
"mls.command.managePackages": "Manage Packages in SQL Server", "mls.command.managePackages": "Manage packages in database",
"mls.command.manageLanguages": "Manage External Languages", "mls.command.manageLanguages": "Manage external languages",
"mls.command.predictModel": "Make prediction", "mls.command.predictModel": "Make prediction",
"mls.command.manageModels": "Manage models", "mls.command.manageModels": "Manage models",
"mls.command.registerModel": "Register model", "mls.command.registerModel": "Register model",

View File

@@ -50,6 +50,9 @@ export function taskFailedError(taskName: string, err: string): string { return
export const installDependenciesMsgTaskName = localize('mls.installDependencies.msgTaskName', "Installing Machine Learning extension dependencies"); export const installDependenciesMsgTaskName = localize('mls.installDependencies.msgTaskName', "Installing Machine Learning extension dependencies");
export const noResultError = localize('mls.noResultError', "No Result returned"); export const noResultError = localize('mls.noResultError', "No Result returned");
export const requiredPackagesNotInstalled = localize('mls.requiredPackagesNotInstalled', "The required dependencies are not installed"); export const requiredPackagesNotInstalled = localize('mls.requiredPackagesNotInstalled', "The required dependencies are not installed");
export const confirmEnableExternalScripts = localize('mls.confirmEnableExternalScripts', "External script is required for package management. Are you sure you want to enable that.");
export const enableExternalScriptsError = localize('mls.enableExternalScriptsError', "Failed to enable External script.");
export const externalScriptsIsRequiredError = localize('mls.externalScriptsIsRequiredError', "External script configuration is required for this action.");
export function confirmInstallPythonPackages(packages: string): string { export function confirmInstallPythonPackages(packages: string): string {
return localize('mls.installDependencies.confirmInstallPythonPackages' return localize('mls.installDependencies.confirmInstallPythonPackages'
, "The following Python packages are required to install: {0}. Are you sure you want to install?", packages); , "The following Python packages are required to install: {0}. Are you sure you want to install?", packages);
@@ -61,7 +64,6 @@ export const packageManagerNoConnection = localize('mls.packageManager.NoConnect
export const notebookExtensionNotLoaded = localize('mls.notebookExtensionNotLoaded', "Notebook extension is not loaded"); export const notebookExtensionNotLoaded = localize('mls.notebookExtensionNotLoaded', "Notebook extension is not loaded");
export const mssqlExtensionNotLoaded = localize('mls.mssqlExtensionNotLoaded', "MSSQL extension is not loaded"); export const mssqlExtensionNotLoaded = localize('mls.mssqlExtensionNotLoaded', "MSSQL extension is not loaded");
export const mlsEnabledMessage = localize('mls.enabledMessage', "Machine Learning Services Enabled"); export const mlsEnabledMessage = localize('mls.enabledMessage', "Machine Learning Services Enabled");
export const mlsDisabledMessage = localize('mls.disabledMessage', "Machine Learning Services Disabled");
export const mlsConfigUpdateFailed = localize('mls.configUpdateFailed', "Failed to modify Machine Learning Services configurations"); export const mlsConfigUpdateFailed = localize('mls.configUpdateFailed', "Failed to modify Machine Learning Services configurations");
export const mlsEnableButtonTitle = localize('mls.enableButtonTitle', "Enable"); export const mlsEnableButtonTitle = localize('mls.enableButtonTitle', "Enable");
export const mlsDisableButtonTitle = localize('mls.disableButtonTitle', "Disable"); export const mlsDisableButtonTitle = localize('mls.disableButtonTitle', "Disable");
@@ -92,7 +94,7 @@ export const extLangLanguagePlatform = localize('extLang.languagePlatform', "Pla
export const deleteTitle = localize('extLang.delete', "Delete"); export const deleteTitle = localize('extLang.delete', "Delete");
export const extLangInstallButtonText = localize('extLang.installButtonText', "Install"); export const extLangInstallButtonText = localize('extLang.installButtonText', "Install");
export const extLangCancelButtonText = localize('extLang.CancelButtonText', "Cancel"); export const extLangCancelButtonText = localize('extLang.CancelButtonText', "Cancel");
export const extLangDoneButtonText = localize('extLang.DoneButtonText', "Done"); export const extLangDoneButtonText = localize('extLang.DoneButtonText', "Close");
export const extLangOkButtonText = localize('extLang.OkButtonText', "OK"); export const extLangOkButtonText = localize('extLang.OkButtonText', "OK");
export const extLangSaveButtonText = localize('extLang.SaveButtonText', "Save"); export const extLangSaveButtonText = localize('extLang.SaveButtonText', "Save");
export const extLangLanguageName = localize('extLang.languageName', "Name"); export const extLangLanguageName = localize('extLang.languageName', "Name");
@@ -131,14 +133,15 @@ export const azureModels = localize('models.azureModels', "Models");
export const azureModelsTitle = localize('models.azureModelsTitle', "Azure models"); export const azureModelsTitle = localize('models.azureModelsTitle', "Azure models");
export const localModelsTitle = localize('models.localModelsTitle', "Local models"); export const localModelsTitle = localize('models.localModelsTitle', "Local models");
export const modelSourcesTitle = localize('models.modelSourcesTitle', "Source location"); export const modelSourcesTitle = localize('models.modelSourcesTitle', "Source location");
export const modelSourcePageTitle = localize('models.modelSourcePageTitle', "Ender model source details"); export const modelSourcePageTitle = localize('models.modelSourcePageTitle', "Enter model source details");
export const columnSelectionPageTitle = localize('models.columnSelectionPageTitle', "Select input columns"); export const columnSelectionPageTitle = localize('models.columnSelectionPageTitle', "Select input columns");
export const modelDetailsPageTitle = localize('models.modelDetailsPageTitle', "Provide model details"); export const modelDetailsPageTitle = localize('models.modelDetailsPageTitle', "Provide model details");
export const modelLocalSourceTitle = localize('models.modelLocalSourceTitle', "Source file"); export const modelLocalSourceTitle = localize('models.modelLocalSourceTitle', "Source file");
export const currentModelsTitle = localize('models.currentModelsTitle', "Models"); export const currentModelsTitle = localize('models.currentModelsTitle', "Models");
export const azureRegisterModel = localize('models.azureRegisterModel', "Register"); export const azureRegisterModel = localize('models.azureRegisterModel', "Deploy");
export const predictModel = localize('models.predictModel', "Predict"); export const predictModel = localize('models.predictModel', "Predict");
export const registerModelTitle = localize('models.RegisterWizard', "Register model"); export const registerModelTitle = localize('models.RegisterWizard', "Deployed models");
export const deployModelTitle = localize('models.deployModelTitle', "Deploy models");
export const makePredictionTitle = localize('models.makePredictionTitle', "Make prediction"); export const makePredictionTitle = localize('models.makePredictionTitle', "Make prediction");
export const modelRegisteredSuccessfully = localize('models.modelRegisteredSuccessfully', "Model registered successfully"); export const modelRegisteredSuccessfully = localize('models.modelRegisteredSuccessfully', "Model registered successfully");
export const modelFailedToRegister = localize('models.modelFailedToRegistered', "Model failed to register"); export const modelFailedToRegister = localize('models.modelFailedToRegistered', "Model failed to register");

View File

@@ -13,8 +13,7 @@ import { ApiWrapper } from '../common/apiWrapper';
import { QueryRunner } from '../common/queryRunner'; import { QueryRunner } from '../common/queryRunner';
import { ProcessService } from '../common/processService'; import { ProcessService } from '../common/processService';
import { Config } from '../configurations/config'; import { Config } from '../configurations/config';
import { ServerConfigWidget } from '../widgets/serverConfigWidgets'; import { PackageManagementService } from '../packageManagement/packageManagementService';
import { ServerConfigManager } from '../serverConfig/serverConfigManager';
import { HttpClient } from '../common/httpClient'; import { HttpClient } from '../common/httpClient';
import { LanguageController } from '../views/externalLanguages/languageController'; import { LanguageController } from '../views/externalLanguages/languageController';
import { LanguageService } from '../externalLanguage/languageService'; import { LanguageService } from '../externalLanguage/languageService';
@@ -38,7 +37,7 @@ export default class MainController implements vscode.Disposable {
private _queryRunner: QueryRunner, private _queryRunner: QueryRunner,
private _processService: ProcessService, private _processService: ProcessService,
private _packageManager?: PackageManager, private _packageManager?: PackageManager,
private _serverConfigManager?: ServerConfigManager, private _packageManagementService?: PackageManagementService,
private _httpClient?: HttpClient private _httpClient?: HttpClient
) { ) {
this._outputChannel = this._apiWrapper.createOutputChannel(constants.extensionOutputChannel); this._outputChannel = this._apiWrapper.createOutputChannel(constants.extensionOutputChannel);
@@ -91,9 +90,6 @@ export default class MainController implements vscode.Disposable {
let nbApis = await this.getNotebookExtensionApis(); let nbApis = await this.getNotebookExtensionApis();
await this._config.load(); await this._config.load();
let tasks = new ServerConfigWidget(this._apiWrapper, this.serverConfigManager);
tasks.register();
let packageManager = this.getPackageManager(nbApis); let packageManager = this.getPackageManager(nbApis);
this._apiWrapper.registerCommand(constants.mlManagePackagesCommand, (async () => { this._apiWrapper.registerCommand(constants.mlManagePackagesCommand, (async () => {
await packageManager.managePackages(); await packageManager.managePackages();
@@ -145,10 +141,10 @@ export default class MainController implements vscode.Disposable {
await modelManagementController.predictModel(); await modelManagementController.predictModel();
}); });
this._apiWrapper.registerTaskHandler(constants.mlOdbcDriverCommand, async () => { this._apiWrapper.registerTaskHandler(constants.mlOdbcDriverCommand, async () => {
await this.serverConfigManager.openOdbcDriverDocuments(); await this.packageManagementService.openOdbcDriverDocuments();
}); });
this._apiWrapper.registerTaskHandler(constants.mlsDocumentsCommand, async () => { this._apiWrapper.registerTaskHandler(constants.mlsDocumentsCommand, async () => {
await this.serverConfigManager.openDocuments(); await this.packageManagementService.openDocuments();
}); });
} }
@@ -157,7 +153,7 @@ export default class MainController implements vscode.Disposable {
*/ */
public getPackageManager(nbApis: nbExtensionApis.IExtensionApi): PackageManager { public getPackageManager(nbApis: nbExtensionApis.IExtensionApi): PackageManager {
if (!this._packageManager) { if (!this._packageManager) {
this._packageManager = new PackageManager(this._outputChannel, this._rootPath, this._apiWrapper, this._queryRunner, this._processService, this._config, this.httpClient); this._packageManager = new PackageManager(this._outputChannel, this._rootPath, this._apiWrapper, this.packageManagementService, this._processService, this._config, this.httpClient);
this._packageManager.init(); this._packageManager.init();
this._packageManager.packageManageProviders.forEach(provider => { this._packageManager.packageManageProviders.forEach(provider => {
nbApis.registerPackageManager(provider.providerId, provider); nbApis.registerPackageManager(provider.providerId, provider);
@@ -169,11 +165,11 @@ export default class MainController implements vscode.Disposable {
/** /**
* Returns the server config manager instance * Returns the server config manager instance
*/ */
public get serverConfigManager(): ServerConfigManager { public get packageManagementService(): PackageManagementService {
if (!this._serverConfigManager) { if (!this._packageManagementService) {
this._serverConfigManager = new ServerConfigManager(this._apiWrapper, this._queryRunner); this._packageManagementService = new PackageManagementService(this._apiWrapper, this._queryRunner);
} }
return this._serverConfigManager; return this._packageManagementService;
} }
/** /**

View File

@@ -9,8 +9,9 @@ import { QueryRunner } from '../common/queryRunner';
import * as constants from '../common/constants'; import * as constants from '../common/constants';
import { ApiWrapper } from '../common/apiWrapper'; import { ApiWrapper } from '../common/apiWrapper';
import * as utils from '../common/utils'; import * as utils from '../common/utils';
import * as nbExtensionApis from '../typings/notebookServices';
export class ServerConfigManager { export class PackageManagementService {
/** /**
* Creates a new instance of ServerConfigManager * Creates a new instance of ServerConfigManager
@@ -76,15 +77,41 @@ export class ServerConfigManager {
* @param connection SQL Connection * @param connection SQL Connection
* @param enable if true external script will be enabled * @param enable if true external script will be enabled
*/ */
public async updateExternalScriptConfig(connection: azdata.connection.ConnectionProfile, enable: boolean): Promise<boolean> { public async enableExternalScriptConfig(connection: azdata.connection.ConnectionProfile): Promise<boolean> {
await this._queryRunner.updateExternalScriptConfig(connection, enable);
let current = await this._queryRunner.isMachineLearningServiceEnabled(connection); let current = await this._queryRunner.isMachineLearningServiceEnabled(connection);
if (current === enable) {
this._apiWrapper.showInfoMessage(enable ? constants.mlsEnabledMessage : constants.mlsDisabledMessage); if (current) {
return current;
}
let confirmed = await utils.promptConfirm(constants.confirmEnableExternalScripts, this._apiWrapper);
if (confirmed) {
await this._queryRunner.updateExternalScriptConfig(connection, true);
current = await this._queryRunner.isMachineLearningServiceEnabled(connection);
if (current) {
this._apiWrapper.showInfoMessage(constants.mlsEnabledMessage);
} else { } else {
this._apiWrapper.showErrorMessage(constants.mlsConfigUpdateFailed); this._apiWrapper.showErrorMessage(constants.mlsConfigUpdateFailed);
} }
} else {
this._apiWrapper.showErrorMessage(constants.externalScriptsIsRequiredError);
}
return current; return current;
} }
/**
* Returns python packages installed in SQL server instance
* @param connection SQL Connection
*/
public async getPythonPackages(connection: azdata.connection.ConnectionProfile): Promise<nbExtensionApis.IPackageDetails[]> {
return this._queryRunner.getPythonPackages(connection);
}
/**
* Returns python packages installed in SQL server instance
* @param connection SQL Connection
*/
public async getRPackages(connection: azdata.connection.ConnectionProfile): Promise<nbExtensionApis.IPackageDetails[]> {
return this._queryRunner.getRPackages(connection);
}
} }

View File

@@ -7,7 +7,6 @@ import * as vscode from 'vscode';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as nbExtensionApis from '../typings/notebookServices'; import * as nbExtensionApis from '../typings/notebookServices';
import { SqlPythonPackageManageProvider } from './sqlPythonPackageManageProvider'; import { SqlPythonPackageManageProvider } from './sqlPythonPackageManageProvider';
import { QueryRunner } from '../common/queryRunner';
import * as utils from '../common/utils'; import * as utils from '../common/utils';
import * as constants from '../common/constants'; import * as constants from '../common/constants';
import { ApiWrapper } from '../common/apiWrapper'; import { ApiWrapper } from '../common/apiWrapper';
@@ -17,6 +16,7 @@ import { isNullOrUndefined } from 'util';
import { SqlRPackageManageProvider } from './sqlRPackageManageProvider'; import { SqlRPackageManageProvider } from './sqlRPackageManageProvider';
import { HttpClient } from '../common/httpClient'; import { HttpClient } from '../common/httpClient';
import { PackageConfigModel } from '../configurations/packageConfigModel'; import { PackageConfigModel } from '../configurations/packageConfigModel';
import { PackageManagementService } from './packageManagementService';
export class PackageManager { export class PackageManager {
@@ -31,12 +31,12 @@ export class PackageManager {
private _outputChannel: vscode.OutputChannel, private _outputChannel: vscode.OutputChannel,
private _rootFolder: string, private _rootFolder: string,
private _apiWrapper: ApiWrapper, private _apiWrapper: ApiWrapper,
private _queryRunner: QueryRunner, private _service: PackageManagementService,
private _processService: ProcessService, private _processService: ProcessService,
private _config: Config, private _config: Config,
private _httpClient: HttpClient) { private _httpClient: HttpClient) {
this._sqlPythonPackagePackageManager = new SqlPythonPackageManageProvider(this._outputChannel, this._apiWrapper, this._queryRunner, this._processService, this._config, this._httpClient); this._sqlPythonPackagePackageManager = new SqlPythonPackageManageProvider(this._outputChannel, this._apiWrapper, this._service, this._processService, this._config, this._httpClient);
this._sqlRPackageManager = new SqlRPackageManageProvider(this._outputChannel, this._apiWrapper, this._queryRunner, this._processService, this._config, this._httpClient); this._sqlRPackageManager = new SqlRPackageManageProvider(this._outputChannel, this._apiWrapper, this._service, this._processService, this._config, this._httpClient);
} }
/** /**
@@ -67,11 +67,13 @@ export class PackageManager {
*/ */
public async managePackages(): Promise<void> { public async managePackages(): Promise<void> {
try { try {
await this.enableExternalScript();
// Only execute the command if there's a valid connection with ml configuration enabled // Only execute the command if there's a valid connection with ml configuration enabled
// //
let connection = await this.getCurrentConnection(); let connection = await this.getCurrentConnection();
let isPythonInstalled = await this._queryRunner.isPythonInstalled(connection); let isPythonInstalled = await this._service.isPythonInstalled(connection);
let isRInstalled = await this._queryRunner.isRInstalled(connection); let isRInstalled = await this._service.isRInstalled(connection);
let defaultProvider: SqlRPackageManageProvider | SqlPythonPackageManageProvider | undefined; let defaultProvider: SqlRPackageManageProvider | SqlPythonPackageManageProvider | undefined;
if (connection && isPythonInstalled && this._sqlPythonPackagePackageManager.canUseProvider) { if (connection && isPythonInstalled && this._sqlPythonPackagePackageManager.canUseProvider) {
defaultProvider = this._sqlPythonPackagePackageManager; defaultProvider = this._sqlPythonPackagePackageManager;
@@ -80,10 +82,10 @@ export class PackageManager {
} }
if (connection && defaultProvider) { if (connection && defaultProvider) {
await this.enableExternalScript();
// Install dependencies // Install dependencies
// //
if (!this.dependenciesInstalled) { if (!this.dependenciesInstalled) {
this._apiWrapper.showInfoMessage(constants.installingDependencies);
await this.installDependencies(); await this.installDependencies();
this.dependenciesInstalled = true; this.dependenciesInstalled = true;
} }
@@ -99,7 +101,14 @@ export class PackageManager {
this._apiWrapper.showInfoMessage(constants.managePackageCommandError); this._apiWrapper.showInfoMessage(constants.managePackageCommandError);
} }
} catch (err) { } catch (err) {
this._outputChannel.appendLine(err); this._apiWrapper.showErrorMessage(err);
}
}
public async enableExternalScript(): Promise<void> {
let connection = await this.getCurrentConnection();
if (!await this._service.enableExternalScriptConfig(connection)) {
throw Error(constants.externalScriptsIsRequiredError);
} }
} }

View File

@@ -6,13 +6,13 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as nbExtensionApis from '../typings/notebookServices'; import * as nbExtensionApis from '../typings/notebookServices';
import { QueryRunner } from '../common/queryRunner';
import { ApiWrapper } from '../common/apiWrapper'; import { ApiWrapper } from '../common/apiWrapper';
import { ProcessService } from '../common/processService'; import { ProcessService } from '../common/processService';
import { Config } from '../configurations/config'; import { Config } from '../configurations/config';
import { SqlPackageManageProviderBase, ScriptMode } from './SqlPackageManageProviderBase'; import { SqlPackageManageProviderBase, ScriptMode } from './SqlPackageManageProviderBase';
import { HttpClient } from '../common/httpClient'; import { HttpClient } from '../common/httpClient';
import * as utils from '../common/utils'; import * as utils from '../common/utils';
import { PackageManagementService } from './packageManagementService';
/** /**
* Manage Package Provider for python packages inside SQL server databases * Manage Package Provider for python packages inside SQL server databases
@@ -26,7 +26,7 @@ export class SqlPythonPackageManageProvider extends SqlPackageManageProviderBase
constructor( constructor(
private _outputChannel: vscode.OutputChannel, private _outputChannel: vscode.OutputChannel,
apiWrapper: ApiWrapper, apiWrapper: ApiWrapper,
private _queryRunner: QueryRunner, private _service: PackageManagementService,
private _processService: ProcessService, private _processService: ProcessService,
private _config: Config, private _config: Config,
private _httpClient: HttpClient) { private _httpClient: HttpClient) {
@@ -51,7 +51,7 @@ export class SqlPythonPackageManageProvider extends SqlPackageManageProviderBase
* Returns list of packages * Returns list of packages
*/ */
protected async fetchPackages(): Promise<nbExtensionApis.IPackageDetails[]> { protected async fetchPackages(): Promise<nbExtensionApis.IPackageDetails[]> {
return await this._queryRunner.getPythonPackages(await this.getCurrentConnection()); return await this._service.getPythonPackages(await this.getCurrentConnection());
} }
/** /**
@@ -97,7 +97,7 @@ export class SqlPythonPackageManageProvider extends SqlPackageManageProviderBase
return false; return false;
} }
let connection = await this.getCurrentConnection(); let connection = await this.getCurrentConnection();
if (connection && await this._queryRunner.isPythonInstalled(connection)) { if (connection && await this._service.isPythonInstalled(connection)) {
return true; return true;
} }
return false; return false;

View File

@@ -7,13 +7,13 @@ import * as vscode from 'vscode';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as nbExtensionApis from '../typings/notebookServices'; import * as nbExtensionApis from '../typings/notebookServices';
import { QueryRunner } from '../common/queryRunner';
import { ApiWrapper } from '../common/apiWrapper'; import { ApiWrapper } from '../common/apiWrapper';
import { ProcessService } from '../common/processService'; import { ProcessService } from '../common/processService';
import { Config } from '../configurations/config'; import { Config } from '../configurations/config';
import { SqlPackageManageProviderBase, ScriptMode } from './SqlPackageManageProviderBase'; import { SqlPackageManageProviderBase, ScriptMode } from './SqlPackageManageProviderBase';
import { HttpClient } from '../common/httpClient'; import { HttpClient } from '../common/httpClient';
import * as constants from '../common/constants'; import * as constants from '../common/constants';
import { PackageManagementService } from './packageManagementService';
@@ -30,7 +30,7 @@ export class SqlRPackageManageProvider extends SqlPackageManageProviderBase impl
constructor( constructor(
private _outputChannel: vscode.OutputChannel, private _outputChannel: vscode.OutputChannel,
apiWrapper: ApiWrapper, apiWrapper: ApiWrapper,
private _queryRunner: QueryRunner, private _service: PackageManagementService,
private _processService: ProcessService, private _processService: ProcessService,
private _config: Config, private _config: Config,
private _httpClient: HttpClient) { private _httpClient: HttpClient) {
@@ -55,7 +55,7 @@ export class SqlRPackageManageProvider extends SqlPackageManageProviderBase impl
* Returns list of packages * Returns list of packages
*/ */
protected async fetchPackages(): Promise<nbExtensionApis.IPackageDetails[]> { protected async fetchPackages(): Promise<nbExtensionApis.IPackageDetails[]> {
return await this._queryRunner.getRPackages(await this.getCurrentConnection()); return await this._service.getRPackages(await this.getCurrentConnection());
} }
/** /**
@@ -96,7 +96,7 @@ export class SqlRPackageManageProvider extends SqlPackageManageProviderBase impl
return false; return false;
} }
let connection = await this.getCurrentConnection(); let connection = await this.getCurrentConnection();
if (connection && await this._queryRunner.isRInstalled(connection)) { if (connection && await this._service.isRInstalled(connection)) {
return true; return true;
} }
return false; return false;

View File

@@ -8,7 +8,7 @@ import { QueryRunner } from '../../common/queryRunner';
import { ApiWrapper } from '../../common/apiWrapper'; import { ApiWrapper } from '../../common/apiWrapper';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import * as should from 'should'; import * as should from 'should';
import { ServerConfigManager } from '../../serverConfig/serverConfigManager'; import { PackageManagementService } from '../../packageManagement/packageManagementService';
interface TestContext { interface TestContext {
@@ -23,32 +23,32 @@ function createContext(): TestContext {
}; };
} }
describe('Server Config Manager', () => { describe('Package Management Service', () => {
it('openDocuments should open document in browser successfully', async function (): Promise<void> { it('openDocuments should open document in browser successfully', async function (): Promise<void> {
const context = createContext(); const context = createContext();
context.apiWrapper.setup(x => x.openExternal(TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); context.apiWrapper.setup(x => x.openExternal(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let serverConfigManager = new ServerConfigManager(context.apiWrapper.object, context.queryRunner.object); let serverConfigManager = new PackageManagementService(context.apiWrapper.object, context.queryRunner.object);
should.equal(await serverConfigManager.openDocuments(), true); should.equal(await serverConfigManager.openDocuments(), true);
}); });
it('openOdbcDriverDocuments should open document in browser successfully', async function (): Promise<void> { it('openOdbcDriverDocuments should open document in browser successfully', async function (): Promise<void> {
const context = createContext(); const context = createContext();
context.apiWrapper.setup(x => x.openExternal(TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); context.apiWrapper.setup(x => x.openExternal(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let serverConfigManager = new ServerConfigManager(context.apiWrapper.object, context.queryRunner.object); let serverConfigManager = new PackageManagementService(context.apiWrapper.object, context.queryRunner.object);
should.equal(await serverConfigManager.openOdbcDriverDocuments(), true); should.equal(await serverConfigManager.openOdbcDriverDocuments(), true);
}); });
it('openInstallDocuments should open document in browser successfully', async function (): Promise<void> { it('openInstallDocuments should open document in browser successfully', async function (): Promise<void> {
const context = createContext(); const context = createContext();
context.apiWrapper.setup(x => x.openExternal(TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); context.apiWrapper.setup(x => x.openExternal(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let serverConfigManager = new ServerConfigManager(context.apiWrapper.object, context.queryRunner.object); let serverConfigManager = new PackageManagementService(context.apiWrapper.object, context.queryRunner.object);
should.equal(await serverConfigManager.openInstallDocuments(), true); should.equal(await serverConfigManager.openInstallDocuments(), true);
}); });
it('isMachineLearningServiceEnabled should return true if external script is enabled', async function (): Promise<void> { it('isMachineLearningServiceEnabled should return true if external script is enabled', async function (): Promise<void> {
const context = createContext(); const context = createContext();
context.queryRunner.setup(x => x.isMachineLearningServiceEnabled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); context.queryRunner.setup(x => x.isMachineLearningServiceEnabled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let serverConfigManager = new ServerConfigManager(context.apiWrapper.object, context.queryRunner.object); let serverConfigManager = new PackageManagementService(context.apiWrapper.object, context.queryRunner.object);
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
should.equal(await serverConfigManager.isMachineLearningServiceEnabled(connection), true); should.equal(await serverConfigManager.isMachineLearningServiceEnabled(connection), true);
}); });
@@ -56,7 +56,7 @@ describe('Server Config Manager', () => {
it('isRInstalled should return true if R is installed', async function (): Promise<void> { it('isRInstalled should return true if R is installed', async function (): Promise<void> {
const context = createContext(); const context = createContext();
context.queryRunner.setup(x => x.isRInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); context.queryRunner.setup(x => x.isRInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let serverConfigManager = new ServerConfigManager(context.apiWrapper.object, context.queryRunner.object); let serverConfigManager = new PackageManagementService(context.apiWrapper.object, context.queryRunner.object);
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
should.equal(await serverConfigManager.isRInstalled(connection), true); should.equal(await serverConfigManager.isRInstalled(connection), true);
}); });
@@ -64,33 +64,23 @@ describe('Server Config Manager', () => {
it('isPythonInstalled should return true if Python is installed', async function (): Promise<void> { it('isPythonInstalled should return true if Python is installed', async function (): Promise<void> {
const context = createContext(); const context = createContext();
context.queryRunner.setup(x => x.isPythonInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); context.queryRunner.setup(x => x.isPythonInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let serverConfigManager = new ServerConfigManager(context.apiWrapper.object, context.queryRunner.object); let serverConfigManager = new PackageManagementService(context.apiWrapper.object, context.queryRunner.object);
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
should.equal(await serverConfigManager.isPythonInstalled(connection), true); should.equal(await serverConfigManager.isPythonInstalled(connection), true);
}); });
it('updateExternalScriptConfig should show info message if updated successfully', async function (): Promise<void> { it('enableExternalScriptConfig should show error message if did not updated successfully', async function (): Promise<void> {
const context = createContext();
context.queryRunner.setup(x => x.updateExternalScriptConfig(TypeMoq.It.isAny(), true)).returns(() => Promise.resolve());
context.queryRunner.setup(x => x.isMachineLearningServiceEnabled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
context.apiWrapper.setup(x => x.showInfoMessage(TypeMoq.It.isAny())).returns(() => Promise.resolve(''));
context.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns(() => Promise.resolve(''));
let serverConfigManager = new ServerConfigManager(context.apiWrapper.object, context.queryRunner.object);
let connection = new azdata.connection.ConnectionProfile();
await serverConfigManager.updateExternalScriptConfig(connection, true);
context.apiWrapper.verify(x => x.showInfoMessage(TypeMoq.It.isAny()), TypeMoq.Times.once());
});
it('updateExternalScriptConfig should show error message if did not updated successfully', async function (): Promise<void> {
const context = createContext(); const context = createContext();
context.queryRunner.setup(x => x.updateExternalScriptConfig(TypeMoq.It.isAny(), true)).returns(() => Promise.resolve()); context.queryRunner.setup(x => x.updateExternalScriptConfig(TypeMoq.It.isAny(), true)).returns(() => Promise.resolve());
context.queryRunner.setup(x => x.isMachineLearningServiceEnabled(TypeMoq.It.isAny())).returns(() => Promise.resolve(false)); context.queryRunner.setup(x => x.isMachineLearningServiceEnabled(TypeMoq.It.isAny())).returns(() => Promise.resolve(false));
context.apiWrapper.setup(x => x.showInfoMessage(TypeMoq.It.isAny())).returns(() => Promise.resolve('')); context.apiWrapper.setup(x => x.showInfoMessage(TypeMoq.It.isAny())).returns(() => Promise.resolve(''));
context.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns(() => Promise.resolve('')); context.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns(() => Promise.resolve(''));
let serverConfigManager = new ServerConfigManager(context.apiWrapper.object, context.queryRunner.object); context.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
label: 'Yes'
}));
let serverConfigManager = new PackageManagementService(context.apiWrapper.object, context.queryRunner.object);
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
await serverConfigManager.updateExternalScriptConfig(connection, true); await serverConfigManager.enableExternalScriptConfig(connection);
context.apiWrapper.verify(x => x.showErrorMessage(TypeMoq.It.isAny()), TypeMoq.Times.once()); context.apiWrapper.verify(x => x.showErrorMessage(TypeMoq.It.isAny()), TypeMoq.Times.once());
}); });

View File

@@ -22,7 +22,8 @@ describe('Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => {return Promise.resolve(connection);}); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => {return Promise.resolve(connection);});
testContext.apiWrapper.setup(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {return Promise.resolve();}); testContext.apiWrapper.setup(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {return Promise.resolve();});
testContext.queryRunner.setup(x => x.isPythonInstalled(connection)).returns(() => {return Promise.resolve(true);}); testContext.serverConfigManager.setup(x => x.isPythonInstalled(connection)).returns(() => {return Promise.resolve(true);});
testContext.serverConfigManager.setup(x => x.enableExternalScriptConfig(connection)).returns(() => {return Promise.resolve(true);});
let packageManager = createPackageManager(testContext); let packageManager = createPackageManager(testContext);
await packageManager.managePackages(); await packageManager.managePackages();
testContext.apiWrapper.verify(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); testContext.apiWrapper.verify(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
@@ -33,8 +34,10 @@ describe('Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => {return Promise.resolve(connection);}); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => {return Promise.resolve(connection);});
testContext.apiWrapper.setup(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {return Promise.resolve();}); testContext.apiWrapper.setup(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {return Promise.resolve();});
testContext.queryRunner.setup(x => x.isPythonInstalled(connection)).returns(() => {return Promise.resolve(false);}); testContext.serverConfigManager.setup(x => x.isPythonInstalled(connection)).returns(() => {return Promise.resolve(false);});
testContext.queryRunner.setup(x => x.isRInstalled(connection)).returns(() => {return Promise.resolve(true);}); testContext.serverConfigManager.setup(x => x.isRInstalled(connection)).returns(() => {return Promise.resolve(true);});
testContext.serverConfigManager.setup(x => x.isPythonInstalled(connection)).returns(() => {return Promise.resolve(true);});
testContext.serverConfigManager.setup(x => x.enableExternalScriptConfig(connection)).returns(() => {return Promise.resolve(true);});
let packageManager = createPackageManager(testContext); let packageManager = createPackageManager(testContext);
await packageManager.managePackages(); await packageManager.managePackages();
testContext.apiWrapper.verify(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); testContext.apiWrapper.verify(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
@@ -46,8 +49,10 @@ describe('Package Manager', () => {
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => {return Promise.resolve(connection);}); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => {return Promise.resolve(connection);});
testContext.apiWrapper.setup(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {return Promise.resolve();}); testContext.apiWrapper.setup(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {return Promise.resolve();});
testContext.apiWrapper.setup(x => x.showInfoMessage(TypeMoq.It.isAny())); testContext.apiWrapper.setup(x => x.showInfoMessage(TypeMoq.It.isAny()));
testContext.queryRunner.setup(x => x.isPythonInstalled(connection)).returns(() => {return Promise.resolve(false);}); testContext.serverConfigManager.setup(x => x.isPythonInstalled(connection)).returns(() => {return Promise.resolve(false);});
testContext.queryRunner.setup(x => x.isRInstalled(connection)).returns(() => {return Promise.resolve(false);}); testContext.serverConfigManager.setup(x => x.isRInstalled(connection)).returns(() => {return Promise.resolve(false);});
testContext.serverConfigManager.setup(x => x.isPythonInstalled(connection)).returns(() => {return Promise.resolve(true);});
testContext.serverConfigManager.setup(x => x.enableExternalScriptConfig(connection)).returns(() => {return Promise.resolve(true);});
let packageManager = createPackageManager(testContext); let packageManager = createPackageManager(testContext);
await packageManager.managePackages(); await packageManager.managePackages();
testContext.apiWrapper.verify(x => x.showInfoMessage(TypeMoq.It.isAny()), TypeMoq.Times.once()); testContext.apiWrapper.verify(x => x.showInfoMessage(TypeMoq.It.isAny()), TypeMoq.Times.once());
@@ -59,6 +64,7 @@ describe('Package Manager', () => {
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => {return Promise.resolve(connection);}); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => {return Promise.resolve(connection);});
testContext.apiWrapper.setup(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {return Promise.resolve();}); testContext.apiWrapper.setup(x => x.executeCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => {return Promise.resolve();});
testContext.apiWrapper.setup(x => x.showInfoMessage(TypeMoq.It.isAny())); testContext.apiWrapper.setup(x => x.showInfoMessage(TypeMoq.It.isAny()));
testContext.serverConfigManager.setup(x => x.enableExternalScriptConfig(connection)).returns(() => {return Promise.resolve(true);});
let packageManager = createPackageManager(testContext); let packageManager = createPackageManager(testContext);
await packageManager.managePackages(); await packageManager.managePackages();
@@ -204,7 +210,7 @@ describe('Package Manager', () => {
testContext.outputChannel, testContext.outputChannel,
'', '',
testContext.apiWrapper.object, testContext.apiWrapper.object,
testContext.queryRunner.object, testContext.serverConfigManager.object,
testContext.processService.object, testContext.processService.object,
testContext.config.object, testContext.config.object,
testContext.httpClient.object); testContext.httpClient.object);

View File

@@ -40,7 +40,7 @@ describe('SQL Python Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.getPythonPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages)); testContext.serverConfigManager.setup(x => x.getPythonPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.listPackages(); let actual = await provider.listPackages();
@@ -72,7 +72,7 @@ describe('SQL Python Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.getPythonPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages)); testContext.serverConfigManager.setup(x => x.getPythonPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.listPackages(); let actual = await provider.listPackages();
@@ -95,7 +95,7 @@ describe('SQL Python Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
let packages: nbExtensionApis.IPackageDetails[]; let packages: nbExtensionApis.IPackageDetails[];
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.getPythonPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages)); testContext.serverConfigManager.setup(x => x.getPythonPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.listPackages(); let actual = await provider.listPackages();
@@ -108,7 +108,7 @@ describe('SQL Python Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.getPythonPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve([])); testContext.serverConfigManager.setup(x => x.getPythonPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve([]));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.listPackages(); let actual = await provider.listPackages();
@@ -298,7 +298,7 @@ describe('SQL Python Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.isPythonInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(false)); testContext.serverConfigManager.setup(x => x.isPythonInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(false));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.canUseProvider(); let actual = await provider.canUseProvider();
@@ -311,7 +311,7 @@ describe('SQL Python Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.isPythonInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); testContext.serverConfigManager.setup(x => x.isPythonInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.canUseProvider(); let actual = await provider.canUseProvider();
@@ -390,7 +390,7 @@ describe('SQL Python Package Manager', () => {
return new SqlPythonPackageManageProvider( return new SqlPythonPackageManageProvider(
testContext.outputChannel, testContext.outputChannel,
testContext.apiWrapper.object, testContext.apiWrapper.object,
testContext.queryRunner.object, testContext.serverConfigManager.object,
testContext.processService.object, testContext.processService.object,
testContext.config.object, testContext.config.object,
testContext.httpClient.object); testContext.httpClient.object);

View File

@@ -40,7 +40,7 @@ describe('SQL R Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.getRPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages)); testContext.serverConfigManager.setup(x => x.getRPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.listPackages(); let actual = await provider.listPackages();
@@ -63,7 +63,7 @@ describe('SQL R Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
let packages: nbExtensionApis.IPackageDetails[]; let packages: nbExtensionApis.IPackageDetails[];
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.getRPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages)); testContext.serverConfigManager.setup(x => x.getRPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve(packages));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.listPackages(); let actual = await provider.listPackages();
@@ -76,7 +76,7 @@ describe('SQL R Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.getRPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve([])); testContext.serverConfigManager.setup(x => x.getRPackages(TypeMoq.It.isAny())).returns(() => Promise.resolve([]));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.listPackages(); let actual = await provider.listPackages();
@@ -222,7 +222,7 @@ describe('SQL R Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.isRInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(false)); testContext.serverConfigManager.setup(x => x.isRInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(false));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.canUseProvider(); let actual = await provider.canUseProvider();
@@ -235,7 +235,7 @@ describe('SQL R Package Manager', () => {
let connection = new azdata.connection.ConnectionProfile(); let connection = new azdata.connection.ConnectionProfile();
testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); }); testContext.apiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(connection); });
testContext.queryRunner.setup(x => x.isRInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); testContext.serverConfigManager.setup(x => x.isRInstalled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
let provider = createProvider(testContext); let provider = createProvider(testContext);
let actual = await provider.canUseProvider(); let actual = await provider.canUseProvider();
@@ -316,7 +316,7 @@ describe('SQL R Package Manager', () => {
return new SqlRPackageManageProvider( return new SqlRPackageManageProvider(
testContext.outputChannel, testContext.outputChannel,
testContext.apiWrapper.object, testContext.apiWrapper.object,
testContext.queryRunner.object, testContext.serverConfigManager.object,
testContext.processService.object, testContext.processService.object,
testContext.config.object, testContext.config.object,
testContext.httpClient.object); testContext.httpClient.object);

View File

@@ -11,6 +11,7 @@ import { QueryRunner } from '../../common/queryRunner';
import { ProcessService } from '../../common/processService'; import { ProcessService } from '../../common/processService';
import { Config } from '../../configurations/config'; import { Config } from '../../configurations/config';
import { HttpClient } from '../../common/httpClient'; import { HttpClient } from '../../common/httpClient';
import { PackageManagementService } from '../../packageManagement/packageManagementService';
export interface TestContext { export interface TestContext {
@@ -22,6 +23,7 @@ export interface TestContext {
op: azdata.BackgroundOperation; op: azdata.BackgroundOperation;
getOpStatus: () => azdata.TaskStatus; getOpStatus: () => azdata.TaskStatus;
httpClient: TypeMoq.IMock<HttpClient>; httpClient: TypeMoq.IMock<HttpClient>;
serverConfigManager: TypeMoq.IMock<PackageManagementService>;
} }
export function createContext(): TestContext { export function createContext(): TestContext {
@@ -49,6 +51,7 @@ export function createContext(): TestContext {
id: '', id: '',
onCanceled: new vscode.EventEmitter<void>().event, onCanceled: new vscode.EventEmitter<void>().event,
}, },
getOpStatus: () => { return opStatus; } getOpStatus: () => { return opStatus; },
serverConfigManager: TypeMoq.Mock.ofType(PackageManagementService)
}; };
} }

View File

@@ -31,12 +31,12 @@ export class RegisteredModelsDialog extends ModelViewBase {
this.currentLanguagesTab = new CurrentModelsPage(this._apiWrapper, this); this.currentLanguagesTab = new CurrentModelsPage(this._apiWrapper, this);
let registerModelButton = this._apiWrapper.createButton(constants.registerModelTitle); let registerModelButton = this._apiWrapper.createButton(constants.deployModelTitle);
registerModelButton.onClick(async () => { registerModelButton.onClick(async () => {
await this.sendDataRequest(RegisterModelEventName); await this.sendDataRequest(RegisterModelEventName);
}); });
let dialog = this.dialogView.createDialog('', [this.currentLanguagesTab]); let dialog = this.dialogView.createDialog(constants.registerModelTitle, [this.currentLanguagesTab]);
dialog.customButtons = [registerModelButton]; dialog.customButtons = [registerModelButton];
this.mainViewPanel = dialog; this.mainViewPanel = dialog;
dialog.okButton.hidden = true; dialog.okButton.hidden = true;

View File

@@ -1,160 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { ApiWrapper } from '../common/apiWrapper';
import { ServerConfigManager } from '../serverConfig/serverConfigManager';
import * as constants from '../common/constants';
export class ConfigTable {
private _statusTable: azdata.DeclarativeTableComponent;
constructor(private _apiWrapper: ApiWrapper, private _serverConfigManager: ServerConfigManager, private _modelBuilder: azdata.ModelBuilder, private _loadingComponent: azdata.LoadingComponent) {
this._statusTable = this._modelBuilder.declarativeTable()
.withProperties<azdata.DeclarativeTableProperties>(
{
columns: [
{ // Config
displayName: constants.mlsConfigTitle,
valueType: azdata.DeclarativeDataType.component,
isReadOnly: true,
width: 175,
headerCssStyles: {
...constants.cssStyles.tableHeader
},
rowCssStyles: {
...constants.cssStyles.tableRow
},
},
{ // Status icon
displayName: constants.mlsConfigStatus,
ariaLabel: constants.mlsConfigStatus,
valueType: azdata.DeclarativeDataType.component,
isReadOnly: true,
width: 25,
headerCssStyles: {
...constants.cssStyles.tableHeader
},
rowCssStyles: {
...constants.cssStyles.tableRow
},
},
{ // Action
displayName: '',
valueType: azdata.DeclarativeDataType.component,
isReadOnly: true,
width: 150,
headerCssStyles: {
...constants.cssStyles.tableHeader
},
rowCssStyles: {
...constants.cssStyles.tableRow
},
}
],
data: [],
ariaLabel: constants.mlsConfigTitle
})
.component();
}
/**
* Returns the config table component
*/
public get component(): azdata.DeclarativeTableComponent {
return this._statusTable;
}
/**
* Refreshes the config table
*/
public async refresh(): Promise<void> {
this._loadingComponent.updateProperties({ loading: true });
let connection = await this.getCurrentConnection();
const externalScriptsConfig = await this.createTableRowComponents(constants.mlsExternalExecuteScriptTitle,
async () => {
return await this._serverConfigManager.isMachineLearningServiceEnabled(connection);
}, async (enable) => {
this._loadingComponent.updateProperties({ loading: true });
await this._serverConfigManager.updateExternalScriptConfig(connection, enable);
await this.refresh();
}
);
const pythonConfig = await this.createTableRowComponents(constants.mlsPythonLanguageTitle,
async () => {
return await this._serverConfigManager.isPythonInstalled(connection);
}, async () => {
await this._serverConfigManager.openInstallDocuments();
}
);
const rConfig = await this.createTableRowComponents(constants.mlsRLanguageTitle,
async () => {
return await this._serverConfigManager.isRInstalled(connection);
}, async () => {
await this._serverConfigManager.openInstallDocuments();
}
);
this._statusTable.data = [externalScriptsConfig, pythonConfig, rConfig];
this._loadingComponent.updateProperties({ loading: false });
}
private async getCurrentConnection(): Promise<azdata.connection.ConnectionProfile> {
return await this._apiWrapper.getCurrentConnection();
}
private async createTableRowComponents(configName: string, checkEnabledFunction: () => Promise<boolean>, updateFunction: (enable: boolean) => Promise<void>): Promise<azdata.Component[]> {
const isEnabled = await checkEnabledFunction();
const nameCell = this._modelBuilder.text()
.withProperties<azdata.TextComponentProperties>({
value: configName,
CSSStyles: { 'user-select': 'none', ...constants.cssStyles.text }
}).component();
const statusIconCell = this._modelBuilder.text()
.withProperties<azdata.TextComponentProperties>({
value: this.getConfigStatusIcon(isEnabled),
ariaRole: 'img',
title: this.getConfigStatusTest(isEnabled),
CSSStyles: { 'user-select': 'none', ...constants.cssStyles.text }
}).component();
const button = this._modelBuilder.button().withProperties<azdata.ButtonProperties>({
label: '',
title: ''
}).component();
button.label = this.getLabel(isEnabled);
button.onDidClick(async () => {
await updateFunction(!isEnabled);
const isEnabledNewValue = await checkEnabledFunction();
button.label = this.getLabel(isEnabledNewValue);
});
return [
nameCell,
statusIconCell,
button
];
}
private getConfigStatusIcon(enabled: boolean): string {
if (enabled) {
return '✔️';
} else {
return '❌';
}
}
private getConfigStatusTest(enabled: boolean): string {
if (enabled) {
return constants.mlsEnableButtonTitle;
} else {
return constants.mlsDisableButtonTitle;
}
}
private getLabel(isEnabled: boolean): string {
return isEnabled ? constants.mlsDisableButtonTitle : constants.mlsEnableButtonTitle;
}
}

View File

@@ -1,69 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { ApiWrapper } from '../common/apiWrapper';
import { ServerConfigManager } from '../serverConfig/serverConfigManager';
import { ConfigTable } from './configTable';
export class ServerConfigWidget {
constructor(private _apiWrapper: ApiWrapper, private _serverConfigManager: ServerConfigManager) {
}
/**
* Registers the widget and initializes the components
*/
public register(): void {
azdata.ui.registerModelViewProvider('ml.tasks', async (view) => {
const container = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column',
width: '100%',
height: '100%'
}).component();
const mainContainer = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column',
width: '270px',
height: '100%',
position: 'absolute'
}).component();
mainContainer.addItem(container, {
CSSStyles: {
'padding-top': '25px',
'padding-left': '5px'
}
});
let spinner = view.modelBuilder.loadingComponent()
.withItem(mainContainer)
.withProperties<azdata.LoadingComponentProperties>({ loading: true })
.component();
const configTable = new ConfigTable(this._apiWrapper, this._serverConfigManager, view.modelBuilder, spinner);
this.addRow(container, view, configTable.component);
await view.initializeModel(spinner);
await configTable.refresh();
});
}
private addRow(container: azdata.FlexContainer, view: azdata.ModelView, component: azdata.Component) {
const bookRow = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'row',
justifyContent: 'space-between',
height: '100'
}).component();
bookRow.addItem(component, {
CSSStyles: {
'width': '100',
'hight': '100',
'padding-top': '10px',
'text-align': 'left'
}
});
container.addItems([bookRow]);
}
}