mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-09 17:52:34 -05:00
ML- Added a radio button to enter new model table name (#10343)
This commit is contained in:
@@ -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
|
||||
//
|
||||
|
||||
@@ -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<boolean> {
|
||||
return await this._apiWrapper.openExternal(vscode.Uri.parse(constants.mlsDocuments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if mls is installed in the give SQL server instance
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,13 +24,6 @@ function createContext(): TestContext {
|
||||
}
|
||||
|
||||
describe('Package Management Service', () => {
|
||||
it('openDocuments should open document in browser successfully', async function (): Promise<void> {
|
||||
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<void> {
|
||||
const context = createContext();
|
||||
context.queryRunner.setup(x => x.isMachineLearningServiceEnabled(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
|
||||
|
||||
@@ -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<azdata.DeclarativeTableComponent> = {
|
||||
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<azdata.ImageComponent> = {
|
||||
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!,
|
||||
|
||||
@@ -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([{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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<void> = new vscode.EventEmitter<void>();
|
||||
private _existingTablesSelected: boolean = true;
|
||||
public readonly onSelectedChanged: vscode.Event<void> = 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<void> {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user