diff --git a/extensions/machine-learning/images/aiMlSqlServer.svg b/extensions/machine-learning/images/aiMlSqlServer.svg
new file mode 100644
index 0000000000..94fbb8932b
--- /dev/null
+++ b/extensions/machine-learning/images/aiMlSqlServer.svg
@@ -0,0 +1,9 @@
+
diff --git a/extensions/machine-learning/images/aml.svg b/extensions/machine-learning/images/aml.svg
new file mode 100644
index 0000000000..d0a0056eba
--- /dev/null
+++ b/extensions/machine-learning/images/aml.svg
@@ -0,0 +1,14 @@
+
diff --git a/extensions/machine-learning/images/fileUpload.svg b/extensions/machine-learning/images/fileUpload.svg
new file mode 100644
index 0000000000..4d114b1957
--- /dev/null
+++ b/extensions/machine-learning/images/fileUpload.svg
@@ -0,0 +1,18 @@
+
diff --git a/extensions/machine-learning/images/imported.svg b/extensions/machine-learning/images/imported.svg
new file mode 100644
index 0000000000..01246fddb6
--- /dev/null
+++ b/extensions/machine-learning/images/imported.svg
@@ -0,0 +1,35 @@
+
diff --git a/extensions/machine-learning/images/notebooksIntro.svg b/extensions/machine-learning/images/notebooksIntro.svg
new file mode 100644
index 0000000000..7086362ab1
--- /dev/null
+++ b/extensions/machine-learning/images/notebooksIntro.svg
@@ -0,0 +1,9 @@
+
diff --git a/extensions/machine-learning/images/sqlServerMl.svg b/extensions/machine-learning/images/sqlServerMl.svg
new file mode 100644
index 0000000000..1f1f586e01
--- /dev/null
+++ b/extensions/machine-learning/images/sqlServerMl.svg
@@ -0,0 +1,9 @@
+
diff --git a/extensions/machine-learning/images/video1.svg b/extensions/machine-learning/images/video1.svg
deleted file mode 100644
index 01f4180c8b..0000000000
--- a/extensions/machine-learning/images/video1.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/extensions/machine-learning/images/video2.svg b/extensions/machine-learning/images/video2.svg
deleted file mode 100644
index 618673834d..0000000000
--- a/extensions/machine-learning/images/video2.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/extensions/machine-learning/src/common/constants.ts b/extensions/machine-learning/src/common/constants.ts
index a497b52b9f..a5a0690bac 100644
--- a/extensions/machine-learning/src/common/constants.ts
+++ b/extensions/machine-learning/src/common/constants.ts
@@ -124,6 +124,8 @@ export const extLangUpdateFailedError = localize('extLang.updateFailedError', "F
export const modelUpdateFailedError = localize('models.modelUpdateFailedError', "Failed to update the model");
export const databaseName = localize('databaseName', "Models database");
export const tableName = localize('tableName', "Models table");
+export const existingTableName = localize('existingTableName', "Existing table");
+export const newTableName = localize('newTableName', "New table");
export const modelName = localize('models.name', "Name");
export const modelFileName = localize('models.fileName', "File");
export const modelDescription = localize('models.description', "Description");
@@ -211,20 +213,20 @@ export const sqlMlDocTitle = localize('sqlMlDocTitle', "SQL machine learning doc
export const sqlMlDocDesc = localize('sqlMlDocDesc', "Learn how to use machine learning in SQL Server and SQL on Azure, to run Python and R scripts on relational data.");
export const sqlMlsDocTitle = localize('sqlMlsDocTitle', "SQL Server Machine Learning Services (Python and R)");
export const sqlMlsDocDesc = localize('sqlMlsDocDesc', "Get started with Machine Learning Services on SQL Server and how to install it on Windows and Linux.");
-export const sqlMlsAzureDocTitle = localize('sqlMlsAzureDocTitle', "Machine Learning Services in Azure SQL Managed Instance (preview)");
-export const sqlMlsAzureDocDesc = localize('sqlMlsAzureDocDesc', "Get started with Machine Learning Services in Azure SQL Managed Instances.");
+export const sqlMlsMIDocTitle = localize('sqlMlsMIDocTitle', "Machine Learning Services in Azure SQL Managed Instance (preview)");
+export const sqlMlsMIDocDesc = localize('sqlMlsMIDocDesc', "Get started with Machine Learning Services in Azure SQL Managed Instances.");
export const mlsInstallOdbcDocTitle = localize('mlsInstallObdcDocTitle', "Install the Microsoft ODBC driver for SQL Server");
export const mlsInstallOdbcDocDesc = localize('mlsInstallOdbcDocDesc', "This document explains how to install the Microsoft ODBC Driver for SQL Server.");
+export const onnxOnEdgeOdbcDocTitle = localize('onnxOnEdgeOdbcDocTitle', "Machine learning and AI with ONNX in SQL Database Edge Preview");
+export const onnxOnEdgeOdbcDocDesc = localize('onnxOnEdgeOdbcDocDesc', "Get started with machine learning in Azure SQL Database Edge");
// Links
//
-export const mlsDocuments = 'https://docs.microsoft.com/sql/advanced-analytics/?view=sql-server-ver15';
-export const odbcDriverWindowsDocuments = 'https://docs.microsoft.com/sql/connect/odbc/windows/microsoft-odbc-driver-for-sql-server-on-windows?view=sql-server-ver15';
-export const odbcDriverLinuxDocuments = 'https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15';
-export const mlDocLink = 'https://docs.microsoft.com/sql/machine-learning/';
-export const mlsDocLink = 'https://docs.microsoft.com/sql/machine-learning/what-is-sql-server-machine-learning';
-export const mlsAzureDocLink = 'https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance-machine-learning-services-overview';
-export const installMlsWindowsDocs = 'https://docs.microsoft.com/sql/advanced-analytics/install/sql-machine-learning-services-windows-install?view=sql-server-ver15';
+export const odbcDriverDocuments = 'https://go.microsoft.com/fwlink/?linkid=2129818';
+export const mlDocLink = 'https://go.microsoft.com/fwlink/?linkid=2128671';
+export const mlsDocLink = 'https://go.microsoft.com/fwlink/?linkid=2128672';
+export const mlsAzureDocLink = 'https://go.microsoft.com/fwlink/?linkid=2128673';
+export const onnxOnEdgeDocs = 'https://go.microsoft.com/fwlink/?linkid=2128882';
// CSS Styles
//
diff --git a/extensions/machine-learning/src/packageManagement/packageManagementService.ts b/extensions/machine-learning/src/packageManagement/packageManagementService.ts
index b817b354e8..d22d604412 100644
--- a/extensions/machine-learning/src/packageManagement/packageManagementService.ts
+++ b/extensions/machine-learning/src/packageManagement/packageManagementService.ts
@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import * as vscode from 'vscode';
import * as azdata from 'azdata';
import { QueryRunner } from '../common/queryRunner';
import * as constants from '../common/constants';
@@ -22,13 +21,6 @@ export class PackageManagementService {
) {
}
- /**
- * Opens server config documents
- */
- public async openDocuments(): Promise {
- return await this._apiWrapper.openExternal(vscode.Uri.parse(constants.mlsDocuments));
- }
-
/**
* Returns true if mls is installed in the give SQL server instance
*/
diff --git a/extensions/machine-learning/src/prediction/predictService.ts b/extensions/machine-learning/src/prediction/predictService.ts
index db7682c5c5..7172bcf336 100644
--- a/extensions/machine-learning/src/prediction/predictService.ts
+++ b/extensions/machine-learning/src/prediction/predictService.ts
@@ -177,7 +177,7 @@ AS (
)
SELECT
${this.getPredictColumnNames(columns, 'predict_input')}, ${this.getPredictInputColumnNames(outputColumns, 'p')}
-FROM PREDICT(MODEL = @model, DATA = predict_input)
+FROM PREDICT(MODEL = @model, DATA = predict_input, runtime=onnx)
WITH (
${this.getOutputParameters(outputColumns)}
) AS p
@@ -198,7 +198,7 @@ AS (
)
SELECT
${this.getPredictColumnNames(columns, 'predict_input')}, ${this.getOutputColumnNames(outputColumns, 'p')}
-FROM PREDICT(MODEL = ${modelBytes}, DATA = predict_input)
+FROM PREDICT(MODEL = ${modelBytes}, DATA = predict_input, runtime=onnx)
WITH (
${this.getOutputParameters(outputColumns)}
) AS p
diff --git a/extensions/machine-learning/src/test/packageManagement/packageManagementService.test.ts b/extensions/machine-learning/src/test/packageManagement/packageManagementService.test.ts
index 86adf320a7..fb25c3f5db 100644
--- a/extensions/machine-learning/src/test/packageManagement/packageManagementService.test.ts
+++ b/extensions/machine-learning/src/test/packageManagement/packageManagementService.test.ts
@@ -24,13 +24,6 @@ function createContext(): TestContext {
}
describe('Package Management Service', () => {
- it('openDocuments should open document in browser successfully', async function (): Promise {
- const context = createContext();
- context.apiWrapper.setup(x => x.openExternal(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
- let serverConfigManager = new PackageManagementService(context.apiWrapper.object, context.queryRunner.object);
- should.equal(await serverConfigManager.openDocuments(), true);
- });
-
it('isMachineLearningServiceEnabled should return true if external script is enabled', async function (): Promise {
const context = createContext();
context.queryRunner.setup(x => x.isMachineLearningServiceEnabled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
diff --git a/extensions/machine-learning/src/test/views/utils.ts b/extensions/machine-learning/src/test/views/utils.ts
index 2ac5441332..b43f1ee7cd 100644
--- a/extensions/machine-learning/src/test/views/utils.ts
+++ b/extensions/machine-learning/src/test/views/utils.ts
@@ -115,6 +115,10 @@ export function createViewContext(): ViewTestContext {
onCardSelectedChanged: onClick.event
});
+ let group: () => azdata.GroupContainer = () => Object.assign({}, componentBase, container, {
+ collapsed: false,
+ });
+
let declarativeTableBuilder: azdata.ComponentBuilder = {
component: () => declarativeTable(),
withProperties: () => declarativeTableBuilder,
@@ -172,6 +176,15 @@ export function createViewContext(): ViewTestContext {
withProperties: () => cardBuilder,
withValidation: () => cardBuilder
};
+ let groupBuilder: azdata.GroupBuilder = {
+ component: () => {
+ return group();
+ },
+ withProperties: () => groupBuilder,
+ withValidation: () => groupBuilder,
+ withItems: () => groupBuilder,
+ withLayout: () => groupBuilder
+ };
let imageBuilder: azdata.ComponentBuilder = {
component: () => {
@@ -223,7 +236,7 @@ export function createViewContext(): ViewTestContext {
dashboardWidget: undefined!,
dashboardWebview: undefined!,
formContainer: () => formBuilder,
- groupContainer: undefined!,
+ groupContainer: () => groupBuilder,
toolbarContainer: undefined!,
loadingComponent: () => loadingBuilder,
fileBrowserTree: undefined!,
diff --git a/extensions/machine-learning/src/views/models/localModelsComponent.ts b/extensions/machine-learning/src/views/models/localModelsComponent.ts
index 1306d72938..1c5aefad59 100644
--- a/extensions/machine-learning/src/views/models/localModelsComponent.ts
+++ b/extensions/machine-learning/src/views/models/localModelsComponent.ts
@@ -62,9 +62,13 @@ export class LocalModelsComponent extends ModelViewBase implements IDataComponen
.withLayout({
flexFlow: 'row',
justifyContent: 'space-between',
- width: this.componentMaxLength + 200
+ width: this.componentMaxLength
}).withItems([
- this._localPath, this._localBrowse]
+ this._localPath, this._localBrowse], {
+ CSSStyles: {
+ 'padding-right': '5px'
+ }
+ }
).component();
this._form = modelBuilder.formContainer().withFormItems([{
diff --git a/extensions/machine-learning/src/views/models/modelSourcesComponent.ts b/extensions/machine-learning/src/views/models/modelSourcesComponent.ts
index 9fa58db490..d644f9ecc4 100644
--- a/extensions/machine-learning/src/views/models/modelSourcesComponent.ts
+++ b/extensions/machine-learning/src/views/models/modelSourcesComponent.ts
@@ -40,6 +40,7 @@ export class ModelSourcesComponent extends ModelViewBase implements IDataCompone
label: constants.localModelSource,
selected: this._sourceType === ModelSourceType.Local,
cardType: azdata.CardType.VerticalButton,
+ iconPath: { light: this.asAbsolutePath('images/fileUpload.svg'), dark: this.asAbsolutePath('images/fileUpload.svg') },
width: 50
}).component();
this._amlModel = modelBuilder.card()
@@ -49,6 +50,7 @@ export class ModelSourcesComponent extends ModelViewBase implements IDataCompone
label: constants.azureModelSource,
selected: this._sourceType === ModelSourceType.Azure,
cardType: azdata.CardType.VerticalButton,
+ iconPath: { light: this.asAbsolutePath('images/aml.svg'), dark: this.asAbsolutePath('images/aml.svg') },
width: 50
}).component();
@@ -59,6 +61,7 @@ export class ModelSourcesComponent extends ModelViewBase implements IDataCompone
label: constants.registeredModelsSource,
selected: this._sourceType === ModelSourceType.RegisteredModels,
cardType: azdata.CardType.VerticalButton,
+ iconPath: { light: this.asAbsolutePath('images/imported.svg'), dark: this.asAbsolutePath('images/imported.svg') },
width: 50
}).component();
diff --git a/extensions/machine-learning/src/views/models/tableSelectionComponent.ts b/extensions/machine-learning/src/views/models/tableSelectionComponent.ts
index 06eb5614cd..6c7b853566 100644
--- a/extensions/machine-learning/src/views/models/tableSelectionComponent.ts
+++ b/extensions/machine-learning/src/views/models/tableSelectionComponent.ts
@@ -29,6 +29,7 @@ export class TableSelectionComponent extends ModelViewBase implements IDataCompo
private _dbTableComponent: azdata.FlexContainer | undefined;
private tableMaxLength = this.componentMaxLength * 2 + 70;
private _onSelectedChanged: vscode.EventEmitter = new vscode.EventEmitter();
+ private _existingTablesSelected: boolean = true;
public readonly onSelectedChanged: vscode.Event = this._onSelectedChanged.event;
/**
@@ -45,24 +46,66 @@ export class TableSelectionComponent extends ModelViewBase implements IDataCompo
public registerComponent(modelBuilder: azdata.ModelBuilder, databaseTitle: string, tableTitle: string): azdata.Component {
this._databases = modelBuilder.dropDown().withProperties({
width: this.componentMaxLength,
- editable: this._settings.editable,
- fireOnTextChange: this._settings.editable
}).component();
this._tables = modelBuilder.dropDown().withProperties({
- width: this.componentMaxLength,
- editable: this._settings.editable,
- fireOnTextChange: this._settings.editable
+ width: this.componentMaxLength - 10,
}).component();
this._databases.onValueChanged(async () => {
await this.onDatabaseSelected();
});
+ const existingTableButton = modelBuilder.radioButton().withProperties({
+ name: 'tableName',
+ value: 'existing',
+ label: 'Existing table',
+ checked: true
+ }).component();
+ const newTableButton = modelBuilder.radioButton().withProperties({
+ name: 'tableName',
+ value: 'new',
+ label: 'New table',
+ checked: false
+ }).component();
+ const newTableName = modelBuilder.inputBox().withProperties({
+ width: this.componentMaxLength - 10,
+ enabled: false
+ }).component();
+ const group = modelBuilder.groupContainer().withItems([
+ existingTableButton,
+ this._tables,
+ newTableButton,
+ newTableName
+ ], {
+ CSSStyles: {
+ 'padding-top': '5px'
+ }
+ }).component();
+
+ existingTableButton.onDidClick(() => {
+ if (this._tables) {
+ this._tables.enabled = existingTableButton.checked;
+ }
+ newTableName.enabled = !existingTableButton.checked;
+ this._existingTablesSelected = existingTableButton.checked || false;
+ });
+ newTableButton.onDidClick(() => {
+ if (this._tables) {
+ this._tables.enabled = !newTableButton.checked;
+ }
+ newTableName.enabled = newTableButton.checked;
+ this._existingTablesSelected = existingTableButton.checked || false;
+ });
+ newTableName.onTextChanged(async () => {
+ this._selectedTableName = newTableName.value || '';
+ await this.onTableSelected();
+ });
+
this._tables.onValueChanged(async (value) => {
// There's an issue with dropdown doesn't set the value in editable mode. this is the workaround
if (this._tables && value) {
- this._selectedTableName = this._settings.editable ? value : value.selected;
+ this._selectedTableName = value.selected;
}
await this.onTableSelected();
});
@@ -73,22 +116,32 @@ export class TableSelectionComponent extends ModelViewBase implements IDataCompo
}], { info: databaseTitle }).withLayout({
padding: '0px'
}).component();
- const tableForm = modelBuilder.formContainer().withFormItems([{
- title: tableTitle,
- component: this._tables
- }], { info: tableTitle }).withLayout({
- padding: '0px'
- }).component();
+
+ const tableForm = modelBuilder.formContainer();
+ if (this._settings.editable) {
+ tableForm.addFormItem({
+ title: tableTitle,
+ component: group
+ }, { info: tableTitle });
+ } else {
+ tableForm.addFormItem({
+ title: tableTitle,
+ component: this._tables
+ }, { info: tableTitle });
+ }
+
this._dbTableComponent = modelBuilder.flexContainer().withItems([
databaseForm,
- tableForm
+ tableForm.withLayout({
+ padding: '0px'
+ }).component()
], {
flex: '0 0 auto',
CSSStyles: {
'align-items': 'flex-start'
}
}).withLayout({
- flexFlow: 'row',
+ flexFlow: this._settings.editable ? 'column' : 'row',
justifyContent: 'space-between',
width: this.tableMaxLength
}).component();
@@ -163,31 +216,33 @@ export class TableSelectionComponent extends ModelViewBase implements IDataCompo
}
private async onDatabaseSelected(): Promise {
- this._tableNames = await this.listTableNames(this.databaseName || '');
- let tableNames = this._tableNames;
+ if (this._existingTablesSelected) {
+ this._tableNames = await this.listTableNames(this.databaseName || '');
+ let tableNames = this._tableNames;
- if (this._tableNames && !this._settings.preSelected && !this._tableNames.find(x => x.tableName === constants.selectTableTitle)) {
- const firstRow: DatabaseTable = { tableName: constants.selectTableTitle, databaseName: '', schema: '' };
- tableNames = [firstRow].concat(this._tableNames);
- }
-
- if (this._tables && tableNames && tableNames.length > 0) {
- this._tables.values = tableNames.map(t => this.getTableFullName(t));
- if (this.importTable) {
- const selectedTable = tableNames.find(t => t.tableName === this.importTable?.tableName && t.schema === this.importTable?.schema);
- if (selectedTable) {
- this._selectedTableName = this.getTableFullName(selectedTable);
- this._tables.value = this.getTableFullName(selectedTable);
- } else {
- this._selectedTableName = this._settings.editable ? this.getTableFullName(this.importTable) : this.getTableFullName(tableNames[0]);
- }
- } else {
- this._selectedTableName = this.getTableFullName(tableNames[0]);
+ if (this._tableNames && !this._settings.preSelected && !this._tableNames.find(x => x.tableName === constants.selectTableTitle)) {
+ const firstRow: DatabaseTable = { tableName: constants.selectTableTitle, databaseName: '', schema: '' };
+ tableNames = [firstRow].concat(this._tableNames);
+ }
+
+ if (this._tables && tableNames && tableNames.length > 0) {
+ this._tables.values = tableNames.map(t => this.getTableFullName(t));
+ if (this.importTable) {
+ const selectedTable = tableNames.find(t => t.tableName === this.importTable?.tableName && t.schema === this.importTable?.schema);
+ if (selectedTable) {
+ this._selectedTableName = this.getTableFullName(selectedTable);
+ this._tables.value = this.getTableFullName(selectedTable);
+ } else {
+ this._selectedTableName = this._settings.editable ? this.getTableFullName(this.importTable) : this.getTableFullName(tableNames[0]);
+ }
+ } else {
+ this._selectedTableName = this.getTableFullName(tableNames[0]);
+ }
+ this._tables.value = this._selectedTableName;
+ } else if (this._tables) {
+ this._tables.values = [];
+ this._tables.value = '';
}
- this._tables.value = this._selectedTableName;
- } else if (this._tables) {
- this._tables.values = [];
- this._tables.value = '';
}
await this.onTableSelected();
}
diff --git a/extensions/machine-learning/src/views/widgets/dashboardWidget.ts b/extensions/machine-learning/src/views/widgets/dashboardWidget.ts
index 702bab5b70..8455425d32 100644
--- a/extensions/machine-learning/src/views/widgets/dashboardWidget.ts
+++ b/extensions/machine-learning/src/views/widgets/dashboardWidget.ts
@@ -8,7 +8,6 @@ import * as vscode from 'vscode';
import { ApiWrapper } from '../../common/apiWrapper';
import * as path from 'path';
import * as constants from '../../common/constants';
-import * as utils from '../../common/utils';
import { PredictService } from '../../prediction/predictService';
interface IActionMetadata {
@@ -182,12 +181,12 @@ export class DashboardWidget {
});
const videosContainer = this.createVideoLinkContainers(view, [
{
- iconPath: { light: 'images/video1.svg', dark: 'images/video1.svg' },
+ iconPath: { light: 'images/aiMlSqlServer.svg', dark: 'images/aiMlSqlServer.svg' },
description: 'Artificial intelligence and machine learning with SQL Server 2019',
link: 'https://www.youtube.com/watch?v=sE99cSoFOHs'
},
{
- iconPath: { light: 'images/video2.svg', dark: 'images/video2.svg' },
+ iconPath: { light: 'images/sqlServerMl.svg', dark: 'images/sqlServerMl.svg' },
description: 'SQL Server Machine Learning Services',
link: 'https://www.youtube.com/watch?v=R4GCBoxADyQ'
}
@@ -199,7 +198,7 @@ export class DashboardWidget {
const moreVideosContainer = this.createVideoLinkContainers(view, [
{
- iconPath: { light: 'images/video2.svg', dark: 'images/video2.svg' },
+ iconPath: { light: 'images/notebooksIntro.svg', dark: 'images/notebooksIntro.svg' },
description: 'Introduction to Azure Data Studio Notebooks',
link: 'https://www.youtube.com/watch?v=Nt4kIHQ0IOc'
}
@@ -316,7 +315,7 @@ export class DashboardWidget {
'background-position': 'top',
'width': `${maxWidth}px`,
'height': '110px',
- 'background-size': `{maxWidth}px 120px`
+ 'background-size': `${maxWidth}px 120px`
}
});
videosContainer.addItem(descriptionComponent);
@@ -349,15 +348,15 @@ export class DashboardWidget {
link: constants.mlsDocLink
},
{
- title: constants.sqlMlsAzureDocTitle,
- description: constants.sqlMlsAzureDocDesc,
- link: constants.mlsAzureDocLink
+ title: constants.onnxOnEdgeOdbcDocTitle,
+ description: constants.onnxOnEdgeOdbcDocDesc,
+ link: constants.onnxOnEdgeDocs
}];
const moreLink = {
title: constants.mlsInstallOdbcDocTitle,
description: constants.mlsInstallOdbcDocDesc,
- link: utils.isWindows() ? constants.odbcDriverWindowsDocuments : constants.odbcDriverLinuxDocuments
+ link: constants.odbcDriverDocuments
};
const styles = {
'padding': '10px'
@@ -499,7 +498,7 @@ export class DashboardWidget {
}
private createTaskButton(view: azdata.ModelView, taskMetaData: IActionMetadata): azdata.Component {
- const maxHeight = 106;
+ const maxHeight = 116;
const maxWidth = 250;
const mainContainer = view.modelBuilder.divContainer().withLayout({
width: maxWidth,