sql db deployments into main (WIP) (#12767)

* added my resource-deployment

* changed notebook message

* Add more advanced properties for spark job submission dialog (#12732)

* Add more advanced properties for spark job submission dialog

* Add queue

* Revert "Add more advanced properties for spark job submission dialog (#12732)"

This reverts commit e6a7e86ddbe70b39660098a8ebd9ded2a1c5530c.

* Changes made for simplification

* changed error messages

* tags added

* tags removed due to redundancy

* Update package.json

* Update resourceTypePickerDialog.ts

* changes based on feedback

* activaterealtimevalidation removed

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
Alex Ma
2020-10-09 15:46:41 -07:00
committed by GitHub
parent ef8e86a78d
commit 0f6bb683d6
13 changed files with 1821 additions and 14 deletions

View File

@@ -0,0 +1,211 @@
{
"metadata": {
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python",
"version": "3.6.6",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
}
},
"nbformat_minor": 2,
"nbformat": 4,
"cells": [
{
"cell_type": "markdown",
"source": [
"Create Azure SQL Database\n",
"============================================\n",
"\n",
"Steps of this procedure include:\n",
"1. Set variables and set up Notebook\n",
"1. Connect to Azure account and subscription\n",
"1. Provision firewall rules to allow local access\n",
"1. Create SQL database resource"
],
"metadata": {
"azdata_cell_guid": "6af59d69-ade7-480a-b33e-52a86fe5bfd3"
}
},
{
"cell_type": "markdown",
"source": [
"## Set variables\r\n",
"These variables are set based on your inputs in the deployment wizard. You can make changes to these variables but be aware of possible validation errors caused by your changes.\r\n",
"\r\n",
"\r\n",
"\r\n",
"\r\n",
""
],
"metadata": {
"azdata_cell_guid": "b57c46c8-4a34-49af-9b62-aa5688a02002"
}
},
{
"cell_type": "markdown",
"source": [
"## Notebook Setup "
],
"metadata": {
"azdata_cell_guid": "19ebf0fd-7010-4cd6-8bcd-d2f63dc75cfb"
}
},
{
"cell_type": "code",
"source": [
"import sys, os, json, time, string, random, subprocess\r\n",
"def run_command(command, json_decode = True, printOutput = True):\n",
" print(command)\n",
" process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\n",
" output, error = process.communicate()\n",
" if process.returncode != 0: \n",
" print(\"Process failed %d \\n%s\" % (process.returncode, error.decode(\"utf-8\")))\n",
" raise Exception()\n",
" if output:\n",
" output = output.decode(\"utf-8\")\n",
" if printOutput:\n",
" print(output)\n",
" try:\n",
" return json.loads(output)\n",
" except:\n",
" return output\r\n",
],
"metadata": {
"azdata_cell_guid": "c320ffe2-c488-4bd8-9886-c7deeae02996",
"tags": []
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"## Connecting to your Azure account\r\n",
""
],
"metadata": {
"azdata_cell_guid": "e34334a7-0d55-4c18-8c0a-1c4a673629cd"
}
},
{
"cell_type": "code",
"source": [
"subscriptions = run_command('az account list', printOutput = False)\r\n",
"if azure_sqldb_subscription not in (subscription[\"id\"] for subscription in subscriptions):\r\n",
" run_command('az login')"
],
"metadata": {
"azdata_cell_guid": "96800b54-48a8-463b-886c-3d0e96f29765"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"## Setting your Azure subscription\r\n",
""
],
"metadata": {
"azdata_cell_guid": "ed6b781d-ce7e-4b51-a7ec-1eeeb2032c73"
}
},
{
"cell_type": "code",
"source": [
"run_command(\r\n",
" 'az account set '\r\n",
" '--subscription {0}'\r\n",
" .format(\r\n",
" azure_sqldb_subscription));"
],
"metadata": {
"azdata_cell_guid": "17b57956-98cf-44de-9ab5-348469ddabf4"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"## Create a server firewall rule\r\n",
"\r\n",
"This firewall rule will allow you to access your server and database within IP range immediately after it is created."
],
"metadata": {
"azdata_cell_guid": "ba895abf-3176-48b5-9e49-a060b3f74370"
}
},
{
"cell_type": "code",
"source": [
"create_firewall_rule_result = run_command(\r\n",
" 'az sql server firewall-rule create '\r\n",
" '--start-ip-address {0} '\r\n",
" '--end-ip-address {1} '\r\n",
" '--server {2} '\r\n",
" '--name {3} '\r\n",
" '--resource-group {4} '\r\n",
" .format(\r\n",
" azure_sqldb_ip_start, \r\n",
" azure_sqldb_ip_end, \r\n",
" azure_sqldb_server_name, \r\n",
" azure_sqldb_firewall_name, \r\n",
" azure_sqldb_resource_group_name));"
],
"metadata": {
"azdata_cell_guid": "ceae5670-292f-4c45-9c10-4ac85baf2d07"
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"source": [
"## Create Azure SQL Database\r\n",
"\r\n",
"The database will be created based on all the settings previously specified. [Learn more](https://docs.microsoft.com/en-us/cli/azure/sql/db?view=azure-cli-latest#az_sql_db_create) about additonal options for creating the database."
],
"metadata": {
"azdata_cell_guid": "b460ca8f-65a7-4d6c-94b7-6d7dd9655fad"
}
},
{
"cell_type": "code",
"source": [
"create_database_result = run_command(\r\n",
" 'az sql db create '\r\n",
" '--server {0} '\r\n",
" '--name {1} '\r\n",
" '--edition GeneralPurpose '\r\n",
" '--compute-model Serverless '\r\n",
" '--family Gen5 '\r\n",
" '--resource-group {2} '\r\n",
" '--min-capacity 0.5 '\r\n",
" '--max-size 32GB '\r\n",
" '--capacity 1 '\r\n",
" '--collation {3} '\r\n",
" .format(\r\n",
" azure_sqldb_server_name, \r\n",
" azure_sqldb_database_name, \r\n",
" azure_sqldb_resource_group_name, \r\n",
" azure_sqldb_collation));"
],
"metadata": {
"azdata_cell_guid": "dc3b2f6f-83ac-4a4d-9d81-2f534e90913e"
},
"outputs": [],
"execution_count": null
}
]
}

View File

@@ -405,7 +405,20 @@
"dark": "./images/azure-sql-db.svg"
},
"tags": ["SQL Server", "Cloud"],
"okButtonText": "%azure-sqldb-ok-button-text%",
"okButtonText": [
{
"value": "%azure-sqldb-notebook-ok-button-text%",
"when": "resource-type=single-database"
},
{
"value": "%azure-sqldb-portal-ok-button-text%",
"when": "resource-type=elastic-pool"
},
{
"value": "%azure-sqldb-portal-ok-button-text%",
"when": "resource-type=database-server"
}
],
"options": [
{
"name": "resource-type",
@@ -428,8 +441,14 @@
],
"providers": [
{
"webPageUrl": "https://portal.azure.com/#create/Microsoft.SQLDatabase",
"requiredTools": [],
"azureSQLDBWizard":{
"notebook": "./notebooks/azuredb/create-sqldb.ipynb"
},
"requiredTools": [
{
"name": "azure-cli"
}
],
"when": "resource-type=single-database"
},
{

View File

@@ -70,9 +70,10 @@
"azure-sqlvm-password-label": "Password",
"azure-sqlvm-password-confirm-label": "Confirm password",
"azure-sqlvm-vm-summary-page-label": "Summary",
"azure-sqldb-display-name": "Azure SQL Database",
"azure-sqldb-description": "Select a resource type and then you will be taken to the Azure portal to create the Azure resource.",
"azure-sqldb-ok-button-text": "Create in Azure portal",
"azure-sqldb-display-name": "SQL Database on Azure Server",
"azure-sqldb-description": "Create SQL Databases on Azure. Best for new applications or existing on-premises applications.",
"azure-sqldb-portal-ok-button-text": "Create in Azure portal",
"azure-sqldb-notebook-ok-button-text": "Script to Notebook",
"resource-type-display-name": "Resource Type",
"sql-azure-single-database-display-name": "Single Database",
"sql-azure-elastic-pool-display-name": "Elastic Pool",

View File

@@ -19,7 +19,8 @@ export interface ResourceType {
providers: DeploymentProvider[];
agreement?: AgreementInfo;
displayIndex?: number;
okButtonText?: string;
okButtonText?: OkButtonTextValue[];
getOkButtonText(selectedOptions: { option: string, value: string }[]): string | undefined;
getProvider(selectedOptions: { option: string, value: string }[]): DeploymentProvider | undefined;
tags?: string[];
}
@@ -40,6 +41,11 @@ export interface ResourceTypeOptionValue {
displayName: string;
}
export interface OkButtonTextValue {
value: string;
when: string;
}
export interface DialogDeploymentProvider extends DeploymentProviderBase {
dialog: DialogInfo;
}
@@ -72,6 +78,10 @@ export interface AzureSQLVMDeploymentProvider extends DeploymentProviderBase {
azureSQLVMWizard: AzureSQLVMWizardInfo;
}
export interface AzureSQLDBDeploymentProvider extends DeploymentProviderBase {
azureSQLDBWizard: AzureSQLDBWizardInfo;
}
export function instanceOfDialogDeploymentProvider(obj: any): obj is DialogDeploymentProvider {
return obj && 'dialog' in obj;
}
@@ -104,12 +114,16 @@ export function instanceOfAzureSQLVMDeploymentProvider(obj: any): obj is AzureSQ
return obj && 'azureSQLVMWizard' in obj;
}
export function instanceOfAzureSQLDBDeploymentProvider(obj: any): obj is AzureSQLDBDeploymentProvider {
return obj && 'azureSQLDBWizard' in obj;
}
export interface DeploymentProviderBase {
requiredTools: ToolRequirementInfo[];
when: string;
}
export type DeploymentProvider = DialogDeploymentProvider | BdcWizardDeploymentProvider | NotebookWizardDeploymentProvider | NotebookDeploymentProvider | WebPageDeploymentProvider | DownloadDeploymentProvider | CommandDeploymentProvider | AzureSQLVMDeploymentProvider;
export type DeploymentProvider = DialogDeploymentProvider | BdcWizardDeploymentProvider | NotebookWizardDeploymentProvider | NotebookDeploymentProvider | WebPageDeploymentProvider | DownloadDeploymentProvider | CommandDeploymentProvider | AzureSQLVMDeploymentProvider | AzureSQLDBDeploymentProvider;
export interface BdcWizardInfo {
notebook: string | NotebookPathInfo;
@@ -182,6 +196,10 @@ export interface AzureSQLVMWizardInfo {
notebook: string | NotebookPathInfo;
}
export interface AzureSQLDBWizardInfo {
notebook: string | NotebookPathInfo;
}
export type DialogInfo = NotebookBasedDialogInfo | CommandBasedDialogInfo;
export function instanceOfNotebookBasedDialogInfo(obj: any): obj is NotebookBasedDialogInfo {

View File

@@ -10,8 +10,9 @@ import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { DeploymentProvider, instanceOfAzureSQLVMDeploymentProvider, instanceOfCommandDeploymentProvider, instanceOfDialogDeploymentProvider, instanceOfDownloadDeploymentProvider, instanceOfNotebookBasedDialogInfo, instanceOfNotebookDeploymentProvider, instanceOfNotebookWizardDeploymentProvider, instanceOfWebPageDeploymentProvider, instanceOfWizardDeploymentProvider, NotebookInfo, NotebookPathInfo, ResourceType, ResourceTypeOption } from '../interfaces';
import { DeploymentProvider, instanceOfAzureSQLVMDeploymentProvider, instanceOfAzureSQLDBDeploymentProvider, instanceOfCommandDeploymentProvider, instanceOfDialogDeploymentProvider, instanceOfDownloadDeploymentProvider, instanceOfNotebookBasedDialogInfo, instanceOfNotebookDeploymentProvider, instanceOfNotebookWizardDeploymentProvider, instanceOfWebPageDeploymentProvider, instanceOfWizardDeploymentProvider, NotebookInfo, NotebookPathInfo, ResourceType, ResourceTypeOption } from '../interfaces';
import { DeployAzureSQLVMWizard } from '../ui/deployAzureSQLVMWizard/deployAzureSQLVMWizard';
import { DeployAzureSQLDBWizard } from '../ui/deployAzureSQLDBWizard/deployAzureSQLDBWizard';
import { DeployClusterWizard } from '../ui/deployClusterWizard/deployClusterWizard';
import { DeploymentInputDialog } from '../ui/deploymentInputDialog';
import { NotebookWizard } from '../ui/notebookWizard/notebookWizard';
@@ -20,6 +21,7 @@ import { KubeService } from './kubeService';
import { INotebookService } from './notebookService';
import { IPlatformService } from './platformService';
import { IToolsService } from './toolsService';
import * as loc from './../localizedConstants';
const localize = nls.loadMessageBundle();
@@ -46,6 +48,7 @@ export class ResourceTypeService implements IResourceTypeService {
extensionResourceTypes.forEach((resourceType: ResourceType) => {
this.updatePathProperties(resourceType, extension.extensionPath);
resourceType.getProvider = (selectedOptions) => { return this.getProvider(resourceType, selectedOptions); };
resourceType.getOkButtonText = (selectedOptions) => { return this.getOkButtonText(resourceType, selectedOptions); };
this._resourceTypes.push(resourceType);
});
}
@@ -78,6 +81,9 @@ export class ResourceTypeService implements IResourceTypeService {
else if ('azureSQLVMWizard' in provider) {
this.updateNotebookPath(provider.azureSQLVMWizard, extensionPath);
}
else if ('azureSQLDBWizard' in provider) {
this.updateNotebookPath(provider.azureSQLDBWizard, extensionPath);
}
});
}
@@ -187,7 +193,8 @@ export class ResourceTypeService implements IResourceTypeService {
&& !instanceOfDownloadDeploymentProvider(provider)
&& !instanceOfWebPageDeploymentProvider(provider)
&& !instanceOfCommandDeploymentProvider(provider)
&& !instanceOfAzureSQLVMDeploymentProvider(provider)) {
&& !instanceOfAzureSQLVMDeploymentProvider(provider)
&& !instanceOfAzureSQLDBDeploymentProvider(provider)) {
errorMessages.push(`No deployment method defined for the provider, ${providerPositionInfo}`);
}
@@ -245,6 +252,21 @@ export class ResourceTypeService implements IResourceTypeService {
return undefined;
}
/**
* Get the ok button text based on the selected options
*/
private getOkButtonText(resourceType: ResourceType, selectedOptions: { option: string, value: string }[]): string | undefined {
if (resourceType.okButtonText && selectedOptions.length === 1) {
const optionGiven = `${selectedOptions[0].option}=${selectedOptions[0].value}`;
for (const possibleOption of resourceType.okButtonText) {
if (possibleOption.when === optionGiven || possibleOption.when === undefined || possibleOption.when.toString().toLowerCase() === 'true') {
return possibleOption.value;
}
}
}
return loc.select;
}
public startDeployment(provider: DeploymentProvider): void {
const self = this;
if (instanceOfWizardDeploymentProvider(provider)) {
@@ -283,6 +305,9 @@ export class ResourceTypeService implements IResourceTypeService {
} else if (instanceOfAzureSQLVMDeploymentProvider(provider)) {
const wizard = new DeployAzureSQLVMWizard(provider.azureSQLVMWizard, this.notebookService, this.toolsService);
wizard.open();
} else if (instanceOfAzureSQLDBDeploymentProvider(provider)) {
const wizard = new DeployAzureSQLDBWizard(provider.azureSQLDBWizard, this.notebookService, this.toolsService);
wizard.open();
}
}

View File

@@ -0,0 +1,45 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export const standardWidth: string = '480px';
// Deploy Azure SQL DB wizard constants
export const WizardTitle = localize('deployAzureSQLDB.NewSQLDBTitle', "Deploy Azure SQL DB");
export const WizardDoneButtonLabel = localize('deployAzureSQLDB.ScriptToNotebook', "Script to Notebook");
export const MissingRequiredInformationErrorMessage = localize('deployAzureSQLDB.MissingRequiredInfoError', "Please fill out the required fields marked with red asterisks.");
// Azure settings page constants
export const AzureSettingsPageTitle = localize('deployAzureSQLDB.AzureSettingsPageTitle', "Azure SQL Database - Azure Account Settings");
export const AzureSettingsSummaryPageTitle = localize('deployAzureSQLDB.AzureSettingsSummaryPageTitle', "Azure Account Settings");
export const AzureAccountDropdownLabel = localize('deployAzureSQLDB.AzureAccountDropdownLabel', "Azure Account");
export const AzureAccountSubscriptionDropdownLabel = localize('deployAzureSQLDB.AzureSubscriptionDropdownLabel', "Subscription");
export const AzureAccountDatabaseServersDropdownLabel = localize('deployAzureSQLDB.AzureDatabaseServersDropdownLabel', "Server");
export const AzureAccountResourceGroupDropdownLabel = localize('deployAzureSQLDB.ResourceGroup', "Resource Group");
//@todo alma1 9/8/20 Region label used for upcoming server creation feature.
//export const AzureAccountRegionDropdownLabel = localize('deployAzureSQLDB.AzureRegionDropdownLabel', "Region (for Public IP Address)");
//Azure settings Database hardware properties. //@todo alma1 9/8/20 labels used for upcoming database hardware creation feature.
// export const DatabaseHardwareInfoLabel = localize('deployAzureSQLDB.DatabaseHardwareInfo', "SQLDB Hardware Settings");
// export const DatabaseManagedInstanceDropdownLabel = localize('deployAzureSQLDB.DatabaseManagedInstanceDropdownLabel', "SQLDB Version");
// export const DatabaseSupportedEditionsDropdownLabel = localize('deployAzureSQLDB.DatabaseSupportedEditionsDropdownLabel', "Edition Type");
// export const DatabaseSupportedFamilyDropdownLabel = localize('deployAzureSQLDB.DatabaseSupportedFamilyDropdownLabel', "Family Type");
// export const DatabaseVCoreNumberDropdownLabel = localize('deployAzureSQLDB.DatabaseVCoreNumberDropdownLabel', "Number of Vcores");
// export const DatabaseMaxMemoryTextLabel = localize('deployAzureSQLDB.DatabaseMaxMemoryTextLabel', "Maximum Data Storage Capacity in GB, can go up to 1TB (1024 GB).");
// export const DatabaseMaxMemorySummaryTextLabel = localize('deployAzureSQLDB.DatabaseMaxMemorySummaryTextLabel', "Maximum Data Storage Capacity in GB");
// Database settings page constants
export const DatabaseSettingsPageTitle = localize('deployAzureSQLDB.DatabaseSettingsPageTitle', "Database settings");
export const FirewallRuleNameLabel = localize('deployAzureSQLDB.FirewallRuleNameLabel', "Firewall rule name");
export const DatabaseNameLabel = localize('deployAzureSQLDB.DatabaseNameLabel', "SQL database name");
export const CollationNameLabel = localize('deployAzureSQLDB.CollationNameLabel', "Database collation");
export const CollationNameSummaryLabel = localize('deployAzureSQLDB.CollationNameSummaryLabel', "Collation for database");
export const IpAddressInfoLabel = localize('deployAzureSQLDB.IpAddressInfoLabel', "Enter IP Addresses in IPv4 format.");
export const StartIpAddressLabel = localize('deployAzureSQLDB.StartIpAddressLabel', "Min IP Address in firewall Ip Range");
export const EndIpAddressLabel = localize('deployAzureSQLDB.EndIpAddressLabel', "Max IP Address in firewall IP Range");
export const StartIpAddressShortLabel = localize('deployAzureSQLDB.StartIpAddressShortLabel', "Min IP Address");
export const EndIpAddressShortLabel = localize('deployAzureSQLDB.EndIpAddressShortLabel', "Max IP Address");

View File

@@ -0,0 +1,175 @@
/*---------------------------------------------------------------------------------------------
* 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 * as vscode from 'vscode';
import * as constants from './constants';
import { INotebookService } from '../../services/notebookService';
import { IToolsService } from '../../services/toolsService';
import { WizardBase } from '../wizardBase';
import { WizardPageBase } from '../wizardPageBase';
import { DeployAzureSQLDBWizardModel } from './deployAzureSQLDBWizardModel';
import { AzureSQLDBWizardInfo } from '../../interfaces';
import { AzureSettingsPage } from './pages/azureSettingsPage';
import { DatabaseSettingsPage } from './pages/databaseSettingsPage';
import axios, { AxiosRequestConfig } from 'axios';
import { AzureSQLDBSummaryPage } from './pages/summaryPage';
import { EOL } from 'os';
export class DeployAzureSQLDBWizard extends WizardBase<DeployAzureSQLDBWizard, WizardPageBase<DeployAzureSQLDBWizard>, DeployAzureSQLDBWizardModel> {
constructor(private wizardInfo: AzureSQLDBWizardInfo, private _notebookService: INotebookService, private _toolsService: IToolsService) {
super(
constants.WizardTitle,
'DeployAzureSqlDBWizard',
new DeployAzureSQLDBWizardModel(),
_toolsService
);
}
private cache: Map<string, any> = new Map();
protected initialize(): void {
this.setPages(this.getPages());
this.wizardObject.generateScriptButton.hidden = true;
this.wizardObject.doneButton.label = constants.WizardDoneButtonLabel;
}
public get notebookService(): INotebookService {
return this._notebookService;
}
public get toolService(): IToolsService {
return this._toolsService;
}
protected async onOk(): Promise<void> {
await this.scriptToNotebook();
}
protected onCancel(): void {
}
private getPages(): WizardPageBase<DeployAzureSQLDBWizard>[] {
const pages: WizardPageBase<DeployAzureSQLDBWizard>[] = [];
pages.push(new AzureSettingsPage(this));
pages.push(new DatabaseSettingsPage(this));
pages.push(new AzureSQLDBSummaryPage(this));
return pages;
}
private async scriptToNotebook(): Promise<void> {
const variableValueStatements = this.model.getCodeCellContentForNotebook();
const insertionPosition = 2; // Cell number 2 is the position where the python variable setting statements need to be inserted in this.wizardInfo.notebook.
try {
await this.notebookService.openNotebookWithEdits(this.wizardInfo.notebook, variableValueStatements, insertionPosition);
} catch (error) {
vscode.window.showErrorMessage(error);
}
}
public async getRequest(url: string, useCache = false): Promise<any> {
if (useCache) {
if (this.cache.has(url)) {
return this.cache.get(url);
}
}
let token = this.model.securityToken.token;
const config: AxiosRequestConfig = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
validateStatus: () => true // Never throw
};
const response = await axios.get(url, config);
if (response.status !== 200) {
let errorMessage: string[] = [];
errorMessage.push(response.status.toString());
errorMessage.push(response.statusText);
if (response.data && response.data.error) {
errorMessage.push(`${response.data.error.code} : ${response.data.error.message}`);
}
vscode.window.showErrorMessage(errorMessage.join(EOL));
}
if (useCache) {
this.cache.set(url, response);
}
return response;
}
public createFormRowComponent(view: azdata.ModelView, title: string, description: string, component: azdata.Component, required: boolean): azdata.FlexContainer {
component.updateProperties({
required: required,
width: '480px'
});
const labelText = view.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>(
{
value: title,
width: '250px',
description: description,
requiredIndicator: required,
})
.component();
labelText.updateCssStyles({
'font-weight': '400',
'font-size': '13px',
});
const flexContainer = view.modelBuilder.flexContainer()
.withLayout(
{
flexFlow: 'row',
alignItems: 'center',
})
.withItems(
[labelText, component],
{
CSSStyles: { 'margin-right': '5px' }
})
.component();
return flexContainer;
}
public changeComponentDisplay(component: azdata.Component, display: ('none' | 'block')) {
component.updateProperties({
required: display === 'block'
});
component.updateCssStyles({
display: display
});
}
public changeRowDisplay(container: azdata.FlexContainer, display: ('none' | 'block')) {
container.items.map((component) => {
component.updateProperties({
required: (display === 'block'),
});
component.updateCssStyles({
display: display,
});
});
}
public addDropdownValues(component: azdata.DropDownComponent, values: azdata.CategoryValue[], width?: number) {
component.updateProperties({
values: values,
width: '480px'
});
}
public showErrorMessage(message: string) {
this.wizardObject.message = {
text: message,
level: azdata.window.MessageLevel.Error
};
}
}

View File

@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EOL } from 'os';
import * as azdata from 'azdata';
import { Model } from '../model';
export class DeployAzureSQLDBWizardModel extends Model {
public azureAccount!: azdata.Account;
public securityToken!: any;
public azureSubscription!: string;
public azureSubscriptionDisplayName!: string;
public azureResouceGroup!: string;
public azureServerName!: string;
public azureRegion!: string;
// public databaseEdition!: string; //@todo alma1 10/7/2020 used for upcoming database hardware creation feature
// public databaseFamily!: string;
// public vCoreNumber!: number;
// public storageInGB!: string;
public databaseName!: string;
//public newServer!: 'True' | 'False'; //@todo alma1 9/8/2020 used for upcoming server creation feature.
public startIpAddress!: string;
public endIpAddress!: string;
public firewallRuleName!: string;
public databaseCollation!: string;
constructor() {
super();
}
public getCodeCellContentForNotebook(): string[] {
const statements: string[] = [];
statements.push(`azure_sqldb_subscription = '${this.azureSubscription}'`);
statements.push(`azure_sqldb_resource_group_name = '${this.azureResouceGroup}'`);
statements.push(`azure_sqldb_server_name = '${this.azureServerName}'`);
//statements.push(`azure_sqldb_database_edition = '${this.databaseEdition}'`); //@todo alma1 10/7/2020 used for upcoming datbase hardware creation feature.
statements.push(`azure_sqldb_database_name = '${this.databaseName}'`);
//statements.push(`azure_sqldb_location = '${this.azureRegion}'`); //@todo alma1 9/10/2020 used for upcoming server creation feature.
statements.push(`azure_sqldb_ip_start = '${this.startIpAddress}'`);
statements.push(`azure_sqldb_ip_end = '${this.endIpAddress}'`);
statements.push(`azure_sqldb_firewall_name = '${this.firewallRuleName}'`);
statements.push(`azure_sqldb_collation = '${this.databaseCollation}'`);
// statements.push(`azure_sqldb_family = '${this.databaseFamily}'`); //@todo alma1 10/7/2020 used for upcoming datbase hardware creation feature.
// statements.push(`azure_sqldb_vcore = '${this.vCoreNumber}'`);
// statements.push(`azure_sqldb_maxmemory = '${this.storageInGB}'`);
//statements.push(`azure_sqldb_new_server = '${this.newServer}'`); //@todo alma1 9/8/2020 used for upcoming server creation feature.
return statements.map(line => line.concat(EOL));
}
}

View File

@@ -0,0 +1,765 @@
/*---------------------------------------------------------------------------------------------
* 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 { EOL } from 'os';
import * as constants from '../constants';
import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard';
import { apiService } from '../../../services/apiService';
import { azureResource } from 'azureResource';
import * as vscode from 'vscode';
import { BasePage } from './basePage';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export class AzureSettingsPage extends BasePage {
// <- means depends on
//dropdown for azure accounts
private _azureAccountsDropdown!: azdata.DropDownComponent;
private signInButton!: azdata.ButtonComponent;
private refreshButton!: azdata.ButtonComponent;
private buttonFlexContainer!: azdata.FlexContainer;
//dropdown for subscription accounts <- azure account dropdown
private _azureSubscriptionsDropdown!: azdata.DropDownComponent;
//dropdown for resource groups <- subscription dropdown //@todo alma1 9/9/2020 Used for upcoming server creation feature.
// private _resourceGroupDropdown!: azdata.DropDownComponent;
//dropdown for SQL servers <- subscription dropdown
private _serverGroupDropdown!: azdata.DropDownComponent;
// //dropdown for azure regions <- subscription dropdown //@todo alma1 9/8/2020 Region dropdown used for upcoming server creation feature.
// private _azureRegionsDropdown!: azdata.DropDownComponent;
// //information text about hardware settings. //@todo alma1 9/8/2020 components below are used for upcoming database hardware creation feature.
// private _dbHardwareInfoText!: azdata.TextComponent;
// //dropdown for Managed Instance Versions <- server dropdown.
// private _dbManagedInstanceDropdown!: azdata.DropDownComponent;
// //dropdown for Supported Editions <- Managed Instance dropdown.
// private _dbSupportedEditionsDropdown!: azdata.DropDownComponent;
// //dropdown for Supported Family <- Supported Editions dropdown.
// private _dbSupportedFamilyDropdown!: azdata.DropDownComponent;
// //dropdown for VCore <= Supported Family dropdown.
// private _dbVCoreDropdown!: azdata.DropDownComponent;
// //input box for maximum memory size, supports between 1 and 1024 GB (1 TB)
// private _dbMemoryTextBox!: azdata.InputBoxComponent;
private _form!: azdata.FormContainer;
private _accountsMap!: Map<string, azdata.Account>;
private _subscriptionsMap!: Map<string, azureResource.AzureResourceSubscription>;
constructor(wizard: DeployAzureSQLDBWizard) {
super(
constants.AzureSettingsPageTitle,
'',
wizard
);
this._accountsMap = new Map();
this._subscriptionsMap = new Map();
}
public async initialize() {
this.pageObject.registerContent(async (view: azdata.ModelView) => {
await Promise.all([
this.createAzureAccountsDropdown(view),
this.createAzureSubscriptionsDropdown(view),
//this.createResourceDropdown(view), //@todo alma1 9/8/2020 used for upcoming server creation feature.
this.createServerDropdown(view),
//this.createAzureRegionsDropdown(view) //@todo alma1 9/8/2020 used for upcoming server creation feature.
// this.createDatabaseHardwareSettingsText(view), //@todo alma1 9/8/2020 used for upcoming database hardware creation feature.
// this.createManagedInstanceDropdown(view),
// this.createSupportedEditionsDropdown(view),
// this.createSupportedFamilyDropdown(view),
// this.createVCoreDropdown(view),
// this.createMaxMemoryText(view),
]);
this.populateAzureAccountsDropdown();
this._form = view.modelBuilder.formContainer()
.withFormItems(
[
{
component: this.wizard.createFormRowComponent(view, constants.AzureAccountDropdownLabel, '', this._azureAccountsDropdown, true)
},
{
component: this.buttonFlexContainer
},
{
component: this.wizard.createFormRowComponent(view, constants.AzureAccountSubscriptionDropdownLabel, '', this._azureSubscriptionsDropdown, true)
},
// { //@todo alma1 9/9/2020 Used for upcoming server creation feature.
// component: this.wizard.createFormRowComponent(view, constants.AzureAccountResourceGroupDropdownLabel, '', this._resourceGroupDropdown, true)
// },
{
component: this.wizard.createFormRowComponent(view, constants.AzureAccountDatabaseServersDropdownLabel, '', this._serverGroupDropdown, true)
},
// { //@todo alma1 9/8/2020 Used for upcoming server creation feature.
// component: this.wizard.createFormRowComponent(view, constants.AzureAccountRegionDropdownLabel, '', this._azureRegionsDropdown, true)
// }
// { //@todo alma1 9/8/2020 Used for upcoming database hardware creation feature.
// component: this._dbHardwareInfoText
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseManagedInstanceDropdownLabel, '', this._dbManagedInstanceDropdown, true)
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseSupportedEditionsDropdownLabel, '', this._dbSupportedEditionsDropdown, true)
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseSupportedFamilyDropdownLabel, '', this._dbSupportedFamilyDropdown, true)
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseVCoreNumberDropdownLabel, '', this._dbVCoreDropdown, true)
// },
// {
// component: this.wizard.createFormRowComponent(view, constants.DatabaseMaxMemoryTextLabel, '', this._dbMemoryTextBox, true)
// }
],
{
horizontal: false,
componentWidth: '100%'
})
.withLayout({ width: '100%' })
.component();
return view.initializeModel(this._form);
});
}
public async onEnter(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator(async (pcInfo) => {
if (pcInfo.newPage < pcInfo.lastPage) {
return true;
}
let errorMessage = await this.validate();
if (errorMessage !== '') {
return false;
}
return true;
});
}
public async onLeave(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator((pcInfo) => {
return true;
});
}
private async createAzureAccountsDropdown(view: azdata.ModelView) {
this._azureAccountsDropdown = view.modelBuilder.dropDown().withProperties({}).component();
this._azureAccountsDropdown.onValueChanged(async (value) => {
this.wizard.model.azureAccount = this._accountsMap.get(value.selected)!;
this.populateAzureSubscriptionsDropdown();
});
this.signInButton = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
label: 'Sign In',
width: '100px'
}).component();
this.refreshButton = view.modelBuilder.button().withProperties<azdata.ButtonProperties>({
label: 'Refresh',
width: '100px'
}).component();
this.signInButton.onDidClick(async (event) => {
await vscode.commands.executeCommand('workbench.actions.modal.linkedAccount');
await this.populateAzureAccountsDropdown();
});
this.refreshButton.onDidClick(async (event) => {
await this.populateAzureAccountsDropdown();
});
this.buttonFlexContainer = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'row'
}).withItems([this.signInButton, this.refreshButton], { CSSStyles: { 'margin-right': '5px', } }).component();
}
private async populateAzureAccountsDropdown() {
this._azureAccountsDropdown.loading = true;
let accounts = await azdata.accounts.getAllAccounts();
if (accounts.length === 0) {
this.wizard.showErrorMessage(localize('deployAzureSQLDB.azureSignInError', "Sign in to an Azure account first"));
return;
} else {
this.wizard.showErrorMessage('');
}
this.wizard.addDropdownValues(
this._azureAccountsDropdown,
accounts.map((account): azdata.CategoryValue => {
let accountCategoryValue = {
displayName: account.displayInfo.displayName,
name: account.displayInfo.displayName
};
this._accountsMap.set(accountCategoryValue.displayName, account);
return accountCategoryValue;
}),
);
this.wizard.model.azureAccount = accounts[0];
this._azureAccountsDropdown.loading = false;
await this.populateAzureSubscriptionsDropdown();
}
private async createAzureSubscriptionsDropdown(view: azdata.ModelView) {
this._azureSubscriptionsDropdown = view.modelBuilder.dropDown().component();
this._azureSubscriptionsDropdown.onValueChanged(async (value) => {
let currentSubscriptionValue = this._azureSubscriptionsDropdown.value as azdata.CategoryValue;
this.wizard.model.azureSubscription = currentSubscriptionValue.name;
this.wizard.model.azureSubscriptionDisplayName = currentSubscriptionValue.displayName;
this.wizard.model.securityToken = await azdata.accounts.getAccountSecurityToken(
this.wizard.model.azureAccount,
this._subscriptionsMap.get(currentSubscriptionValue.name)?.tenant!,
azdata.AzureResource.ResourceManagement
);
await this.populateServerGroupDropdown();
//@todo alma1 9/8/2020 used for upcoming server creation feature.
//this.populateResourceGroupDropdown();
//this.populateAzureRegionsDropdown();
});
}
private async populateAzureSubscriptionsDropdown() {
this._azureSubscriptionsDropdown.loading = true;
let subService = await apiService.azurecoreApi;
let currentAccountDropdownValue = (this._azureAccountsDropdown.value as azdata.CategoryValue);
if (currentAccountDropdownValue === undefined) {
this._azureSubscriptionsDropdown.loading = false;
await this.populateServerGroupDropdown();
//@todo alma1 9/8/2020 used for upcoming server creation feature.
//await this.populateResourceGroupDropdown();
//await this.populateAzureRegionsDropdown();
return;
}
let currentAccount = this._accountsMap.get(currentAccountDropdownValue.name);
let subscriptions = (await subService.getSubscriptions(currentAccount, true)).subscriptions;
if (subscriptions === undefined || subscriptions.length === 0) {
this._azureSubscriptionsDropdown.updateProperties({
values: []
});
this._azureSubscriptionsDropdown.loading = false;
await this.populateServerGroupDropdown();
//@todo alma1 9/8/2020 used for upcoming server creation feature.
//await this.populateResourceGroupDropdown();
//await this.populateAzureRegionsDropdown();
return;
}
subscriptions.sort((a: any, b: any) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()));
this.wizard.addDropdownValues(
this._azureSubscriptionsDropdown,
subscriptions.map((subscription: any): azdata.CategoryValue => {
let subscriptionCategoryValue = {
displayName: subscription.name + ' - ' + subscription.id,
name: subscription.id
};
this._subscriptionsMap.set(subscriptionCategoryValue.name, subscription);
return subscriptionCategoryValue;
})
);
this.wizard.model.azureSubscription = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name;
this.wizard.model.azureSubscriptionDisplayName = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).displayName;
this.wizard.model.securityToken = await azdata.accounts.getAccountSecurityToken(
this.wizard.model.azureAccount,
this._subscriptionsMap.get((this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name)?.tenant!,
azdata.AzureResource.ResourceManagement
);
this._azureSubscriptionsDropdown.loading = false;
await this.populateServerGroupDropdown();
//@todo alma1 9/8/2020 used for upcoming server creation feature.
//await this.populateResourceGroupDropdown();
//await this.populateAzureRegionsDropdown();
}
private async createServerDropdown(view: azdata.ModelView) {
this._serverGroupDropdown = view.modelBuilder.dropDown().withProperties({
required: true,
}).component();
this._serverGroupDropdown.onValueChanged(async (value) => {
if (value.selected === ((this._serverGroupDropdown.value as azdata.CategoryValue).displayName)) {
this.wizard.model.azureServerName = value.selected;
this.wizard.model.azureResouceGroup = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), '');
this.wizard.model.azureRegion = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/location/'), '');
//this.populateManagedInstanceDropdown(); //@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
}
});
}
private async populateServerGroupDropdown() {
this._serverGroupDropdown.loading = true;
let currentSubscriptionValue = this._azureSubscriptionsDropdown.value as azdata.CategoryValue;
if (currentSubscriptionValue === undefined || currentSubscriptionValue.displayName === '') {
this._serverGroupDropdown.updateProperties({
values: []
});
this._serverGroupDropdown.loading = false;
// await this.populateManagedInstanceDropdown(); //@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
return;
}
let url = `https://management.azure.com/subscriptions/${this.wizard.model.azureSubscription}/providers/Microsoft.Sql/servers?api-version=2019-06-01-preview`;
let response = await this.wizard.getRequest(url);
if (response.data.value.length === 0) {
this._serverGroupDropdown.updateProperties({
values: [
{
displayName: localize('deployAzureSQLDB.NoServerLabel', "No servers found"),
name: ''
}
],
});
this._serverGroupDropdown.loading = false;
// await this.populateManagedInstanceDropdown(); //@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
return;
} else {
response.data.value.sort((a: azdata.CategoryValue, b: azdata.CategoryValue) => (a!.name > b!.name) ? 1 : -1);
}
this.wizard.addDropdownValues(
this._serverGroupDropdown,
response.data.value.map((value: any) => {
return {
displayName: value.name,
// remove location from this line and others when region population is enabled again.
name: value.id + '/location/' + value.location,
};
})
);
if (this._serverGroupDropdown.value) {
this.wizard.model.azureServerName = (this._serverGroupDropdown.value as azdata.CategoryValue).displayName;
this.wizard.model.azureResouceGroup = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), '');
this.wizard.model.azureRegion = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/location/'), '');
}
this._serverGroupDropdown.loading = false;
// await this.populateManagedInstanceDropdown(); //@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
return;
}
//@todo alma1 9/8/2020 functions below are used for upcoming server creation feature.
// private async createResourceDropdown(view: azdata.ModelView) {
// this._resourceGroupDropdown = view.modelBuilder.dropDown().withProperties({
// required: true
// }).component();
// this._resourceGroupDropdown.onValueChanged(async (value) => {
// this.wizard.model.azureResouceGroup = value.selected;
// this.populateServerGroupDropdown();
// });
// }
// private async populateResourceGroupDropdown() {
// this._resourceGroupDropdown.loading = true;
// let subService = await apiService.azurecoreApi;
// let currentSubscriptionValue = this._azureSubscriptionsDropdown.value as azdata.CategoryValue;
// if (currentSubscriptionValue === undefined || currentSubscriptionValue.displayName === '') {
// this._resourceGroupDropdown.updateProperties({
// values: []
// });
// this._resourceGroupDropdown.loading = false;
// await this.populateServerGroupDropdown();
// return;
// }
// let currentSubscription = this._subscriptionsMap.get(currentSubscriptionValue.name);
// let resourceGroups = (await subService.getResourceGroups(this.wizard.model.azureAccount, currentSubscription, true)).resourceGroups;
// if (resourceGroups === undefined || resourceGroups.length === 0) {
// this._resourceGroupDropdown.loading = false;
// this._resourceGroupDropdown.updateProperties({
// values: []
// });
// await this.populateServerGroupDropdown();
// return;
// }
// resourceGroups.sort((a: any, b: any) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()));
// this._resourceGroupDropdown.updateProperties({
// values: resourceGroups.map((resourceGroup: any) => {
// return {
// displayName: resourceGroup.name,
// name: resourceGroup.name
// };
// })
// });
// this.wizard.model.azureResouceGroup = (this._resourceGroupDropdown.value as azdata.CategoryValue).name;
// this._resourceGroupDropdown.loading = false;
// await this.populateServerGroupDropdown();
// }
// private async createAzureRegionsDropdown(view: azdata.ModelView) {
// this._azureRegionsDropdown = view.modelBuilder.dropDown().withProperties({
// required: true
// }).component();
// this._azureRegionsDropdown.onValueChanged((value) => {
// this.wizard.model.azureRegion = (this._azureRegionsDropdown.value as azdata.CategoryValue).name;
// });
// }
// private async populateAzureRegionsDropdown() {
// this._azureRegionsDropdown.loading = true;
// let supportedRegions = 'eastus, eastus2, westus, centralus, northcentralus, southcentralus, northeurope, westeurope, eastasia, southeastasia, japaneast, japanwest, australiaeast, australiasoutheast, australiacentral, brazilsouth, southindia, centralindia, westindia, canadacentral, canadaeast, westus2, westcentralus, uksouth, ukwest, koreacentral, koreasouth, francecentral, southafricanorth, uaenorth, switzerlandnorth, germanywestcentral, norwayeast';
// let supportedRegionsArray = supportedRegions.split(', ');
// let url = `https://management.azure.com/subscriptions/${this.wizard.model.azureSubscription}/locations?api-version=2020-01-01`;
// const response = await this.wizard.getRequest(url, true);
// response.data.value = response.data.value.sort((a: any, b: any) => (a.displayName > b.displayName) ? 1 : -1);
// this.wizard.addDropdownValues(
// this._azureRegionsDropdown,
// response.data.value.filter((value: any) => {
// return supportedRegionsArray.includes(value.name);
// }).map((value: any) => {
// return {
// displayName: value.displayName,
// name: value.name
// };
// })
// );
// this.wizard.model.azureRegion = (this._azureRegionsDropdown.value as azdata.CategoryValue).name;
// this._azureRegionsDropdown.loading = false;
// }
//@todo alma1 9/8/2020 functions below are used for upcoming database hardware creation feature.
// private createDatabaseHardwareSettingsText(view: azdata.ModelView) {
// this._dbHardwareInfoText = view.modelBuilder.text()
// .withProperties({
// value: constants.DatabaseHardwareInfoLabel
// }).component();
// }
// private async createManagedInstanceDropdown(view: azdata.ModelView) {
// this._dbManagedInstanceDropdown = view.modelBuilder.dropDown().withProperties({
// required: true,
// }).component();
// this._dbManagedInstanceDropdown.onValueChanged(async (value) => {
// this.populateSupportedEditionsDropdown();
// });
// }
// private async populateManagedInstanceDropdown() {
// this._dbManagedInstanceDropdown.loading = true;
// let currentSubscriptionValue = this._azureSubscriptionsDropdown.value as azdata.CategoryValue;
// if (!currentSubscriptionValue || currentSubscriptionValue.displayName === '') {
// this._dbManagedInstanceDropdown.updateProperties({
// values: []
// });
// this._dbManagedInstanceDropdown.loading = false;
// await this.populateSupportedEditionsDropdown();
// return;
// }
// let currentServerValue = this._serverGroupDropdown.value as azdata.CategoryValue;
// if (currentServerValue.name === '') {
// this._dbManagedInstanceDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoServerLabel', "No servers found"),
// name: '',
// supportedEditions: undefined
// }
// ]
// });
// this._dbManagedInstanceDropdown.loading = false;
// await this.populateSupportedEditionsDropdown();
// return;
// }
// let url = `https://management.azure.com/subscriptions/${this.wizard.model.azureSubscription}/providers/Microsoft.Sql/locations/${this.wizard.model.azureRegion}/capabilities?api-version=2017-10-01-preview`;
// let response = await this.wizard.getRequest(url);
// if (response.data.supportedManagedInstanceVersions.length === 0) {
// this._dbManagedInstanceDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoHardwareConfigLabel', "No database hardware configuration found"),
// name: '',
// supportedEditions: undefined
// }
// ],
// });
// this._dbManagedInstanceDropdown.loading = false;
// await this.populateSupportedEditionsDropdown();
// return;
// } else {
// response.data.supportedManagedInstanceVersions.sort((a: any, b: any) => (a!.name > b!.name) ? 1 : -1);
// }
// this.wizard.addDropdownValues(
// this._dbManagedInstanceDropdown,
// response.data.supportedManagedInstanceVersions.map((value: any) => {
// return {
// displayName: value.name,
// name: value.name,
// supportedEditions: value.supportedEditions
// };
// })
// );
// // if (this._serverGroupDropdown.value) {
// // this.wizard.model.azureServerName = (this._serverGroupDropdown.value as azdata.CategoryValue).displayName;
// // this.wizard.model.azureResouceGroup = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), '');
// // this.wizard.model.azureRegion = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/location/'), '');
// // }
// this._dbManagedInstanceDropdown.loading = false;
// await this.populateSupportedEditionsDropdown();
// return;
// }
// private async createSupportedEditionsDropdown(view: azdata.ModelView) {
// this._dbSupportedEditionsDropdown = view.modelBuilder.dropDown().withProperties({
// required: true,
// }).component();
// this._dbSupportedEditionsDropdown.onValueChanged(async (value) => {
// this.wizard.model.databaseEdition = value.selected;
// this.populateSupportedFamilyDropdown();
// });
// }
// private async populateSupportedEditionsDropdown() {
// this._dbSupportedEditionsDropdown.loading = true;
// if (!this._dbManagedInstanceDropdown.values || this._dbManagedInstanceDropdown.values!.length === 0) {
// this._dbSupportedEditionsDropdown.updateProperties({
// values: []
// });
// this._dbSupportedEditionsDropdown.loading = false;
// await this.populateSupportedFamilyDropdown();
// return;
// }
// let currentManagedInstanceValue = this._dbManagedInstanceDropdown.value as any;
// if (!currentManagedInstanceValue.supportedEditions) {
// this._dbSupportedEditionsDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoManagedInstanceLabel', "Managed instance not selected"),
// name: ''
// }
// ]
// });
// this._dbSupportedEditionsDropdown.loading = false;
// await this.populateSupportedFamilyDropdown();
// return;
// }
// if (currentManagedInstanceValue.supportedEditions.length === 0) {
// this._dbSupportedEditionsDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedEditionsLabel', "No supported editions found"),
// name: ''
// }
// ],
// });
// this._dbSupportedEditionsDropdown.loading = false;
// await this.populateSupportedFamilyDropdown();
// return;
// } else {
// currentManagedInstanceValue.supportedEditions.sort((a: any, b: any) => (a!.name > b!.name) ? 1 : -1);
// }
// this.wizard.addDropdownValues(
// this._dbSupportedEditionsDropdown,
// currentManagedInstanceValue.supportedEditions.map((value: any) => {
// return {
// displayName: value.name,
// name: value.supportedFamilies
// };
// })
// );
// if (this._dbSupportedEditionsDropdown.value) {
// this.wizard.model.databaseEdition = (this._dbSupportedEditionsDropdown.value as azdata.CategoryValue).displayName;
// }
// this._dbSupportedEditionsDropdown.loading = false;
// await this.populateSupportedFamilyDropdown();
// return;
// }
// private async createSupportedFamilyDropdown(view: azdata.ModelView) {
// this._dbSupportedFamilyDropdown = view.modelBuilder.dropDown().withProperties({
// required: true,
// }).component();
// this._dbSupportedFamilyDropdown.onValueChanged(async (value) => {
// this.wizard.model.databaseFamily = value.selected;
// this.populateVCoreDropdown();
// });
// }
// private async populateSupportedFamilyDropdown() {
// this._dbSupportedFamilyDropdown.loading = true;
// if (!this._dbSupportedEditionsDropdown.values || this._dbSupportedEditionsDropdown.values!.length === 0) {
// this._dbSupportedFamilyDropdown.updateProperties({
// values: []
// });
// this._dbSupportedFamilyDropdown.loading = false;
// await this.populateVCoreDropdown();
// return;
// }
// let currentSupportedEditionValue = this._dbSupportedEditionsDropdown.value as any;
// if (!currentSupportedEditionValue.name) {
// this._dbSupportedFamilyDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedEditionLabel', "Supported Edition not selected"),
// name: ''
// }
// ]
// });
// this._dbSupportedFamilyDropdown.loading = false;
// await this.populateVCoreDropdown();
// return;
// }
// if (currentSupportedEditionValue.name.length === 0) {
// this._dbSupportedFamilyDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedFamiliesLabel', "No database family types found."),
// name: ''
// }
// ],
// });
// this._dbSupportedFamilyDropdown.loading = false;
// await this.populateVCoreDropdown();
// return;
// } else {
// currentSupportedEditionValue.name.sort((a: any, b: any) => (a!.name > b!.name) ? 1 : -1);
// }
// this.wizard.addDropdownValues(
// this._dbSupportedFamilyDropdown,
// currentSupportedEditionValue.name.map((value: any) => {
// return {
// displayName: value.name,
// name: value
// };
// })
// );
// if (this._dbSupportedFamilyDropdown.value) {
// this.wizard.model.databaseFamily = (this._dbSupportedFamilyDropdown.value as any).displayName;
// }
// this._dbSupportedFamilyDropdown.loading = false;
// await this.populateVCoreDropdown();
// return;
// }
// private async createVCoreDropdown(view: azdata.ModelView) {
// this._dbVCoreDropdown = view.modelBuilder.dropDown().withProperties({
// required: true,
// }).component();
// this._dbVCoreDropdown.onValueChanged(async (value) => {
// this.wizard.model.vCoreNumber = value.selected;
// });
// }
// private async populateVCoreDropdown() {
// this._dbVCoreDropdown.loading = true;
// if (!this._dbSupportedFamilyDropdown.values || this._dbSupportedFamilyDropdown.values!.length === 0) {
// this._dbVCoreDropdown.updateProperties({
// values: []
// });
// this._dbVCoreDropdown.loading = false;
// return;
// }
// let currentSupportedFamilyValue = this._dbSupportedFamilyDropdown.value as any;
// if (!currentSupportedFamilyValue.name && !currentSupportedFamilyValue.name.supportedVcoresValues) {
// this._dbVCoreDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedFamilyLabel', "Supported Family not selected"),
// name: ''
// }
// ]
// });
// this._dbVCoreDropdown.loading = false;
// return;
// }
// if (currentSupportedFamilyValue.name.supportedVcoresValues === 0) {
// this._dbVCoreDropdown.updateProperties({
// values: [
// {
// displayName: localize('deployAzureSQLDB.NoSupportedVCoreValuesLabel', "No VCore values found."),
// name: ''
// }
// ],
// });
// this._dbVCoreDropdown.loading = false;
// return;
// } else {
// currentSupportedFamilyValue.name.supportedVcoresValues.sort((a: any, b: any) => (a!.value > b!.value) ? 1 : -1);
// }
// this.wizard.addDropdownValues(
// this._dbVCoreDropdown,
// currentSupportedFamilyValue.name.supportedVcoresValues.map((value: any) => {
// return {
// displayName: String(value.value),
// name: value.status
// };
// })
// );
// for (let i = 0; i < this._dbVCoreDropdown.values!.length; i++) {
// let value = this._dbVCoreDropdown.values![i] as azdata.CategoryValue;
// if (value.name === 'Default') {
// this._dbVCoreDropdown.value = this._dbVCoreDropdown.values![i];
// break;
// }
// }
// if (this._dbVCoreDropdown.value) {
// this.wizard.model.vCoreNumber = Number((this._dbVCoreDropdown.value as any).displayName);
// }
// this._dbVCoreDropdown.loading = false;
// return;
// }
// private createMaxMemoryText(view: azdata.ModelView) {
// this._dbMemoryTextBox = view.modelBuilder.inputBox().withProperties(<azdata.InputBoxProperties>{
// inputType: 'number',
// max: 1024,
// min: 1,
// value: '32',
// required: true
// }).component();
// this._dbMemoryTextBox.onTextChanged((value) => {
// this.wizard.model.storageInGB = value + 'GB';
// });
// }
protected async validate(): Promise<string> {
let errorMessages = [];
let serverName = (this._serverGroupDropdown.value as azdata.CategoryValue).name;
if (serverName === '') {
errorMessages.push(localize('deployAzureSQLDB.NoServerError', "No servers found in current subscription.\nSelect a different subscription containing at least one server"));
}
// let supportedEditionName = (this._dbSupportedEditionsDropdown.value as azdata.CategoryValue).name;
// if (supportedEditionName === '') {
// errorMessages.push(localize('deployAzureSQLDB.SupportedEditionError', "No Supported DB Edition found in current server.\nSelect a different server"));
// }
// let familyName = (this._dbSupportedFamilyDropdown.value as azdata.CategoryValue).name;
// if (familyName === '') {
// errorMessages.push(localize('deployAzureSQLDB.SupportedFamiliesError', "No Supported Family found in current DB edition.\nSelect a different edition"));
// }
this.wizard.showErrorMessage(errorMessages.join(EOL));
return errorMessages.join(EOL);
}
}

View File

@@ -0,0 +1,11 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { WizardPageBase } from '../../wizardPageBase';
import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard';
export abstract class BasePage extends WizardPageBase<DeployAzureSQLDBWizard> {
public abstract initialize(): void;
}

View File

@@ -0,0 +1,237 @@
/*---------------------------------------------------------------------------------------------
* 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 { EOL } from 'os';
import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard';
import * as constants from '../constants';
import { BasePage } from './basePage';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export class DatabaseSettingsPage extends BasePage {
private _startIpAddressTextRow!: azdata.FlexContainer;
private _startIpAddressTextbox!: azdata.InputBoxComponent;
private _endIpAddressTextRow!: azdata.FlexContainer;
private _endIpAddressTextbox!: azdata.InputBoxComponent;
private _firewallRuleNameTextbox!: azdata.InputBoxComponent;
private _firewallRuleNameTextRow!: azdata.FlexContainer;
private _databaseNameTextbox!: azdata.InputBoxComponent;
private _databaseNameTextRow!: azdata.FlexContainer;
private _collationTextbox!: azdata.InputBoxComponent;
private _collationTextRow!: azdata.FlexContainer;
private _IpInfoText!: azdata.TextComponent;
private _form!: azdata.FormContainer;
constructor(wizard: DeployAzureSQLDBWizard) {
super(
constants.DatabaseSettingsPageTitle,
'',
wizard
);
}
public async initialize() {
this.pageObject.registerContent(async (view: azdata.ModelView) => {
await Promise.all([
this.createIpAddressText(view),
this.createFirewallNameText(view),
this.createDatabaseNameText(view),
this.createCollationText(view)
]);
this._form = view.modelBuilder.formContainer()
.withFormItems(
[
{
component: this._databaseNameTextRow
},
{
component: this._collationTextRow
},
{
component: this._firewallRuleNameTextRow
},
{
component: this._startIpAddressTextRow
},
{
component: this._endIpAddressTextRow
},
{
component: this._IpInfoText
}
],
{
horizontal: false,
componentWidth: '100%'
})
.withLayout({ width: '100%' })
.component();
return view.initializeModel(this._form);
});
}
public async onEnter(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator(async (pcInfo) => {
if (pcInfo.newPage < pcInfo.lastPage) {
return true;
}
let errorMessage = await this.validate();
if (errorMessage !== '') {
return false;
}
return true;
});
}
public async onLeave(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator((pcInfo) => {
return true;
});
}
private createIpAddressText(view: azdata.ModelView) {
this._IpInfoText = view.modelBuilder.text()
.withProperties({
value: constants.IpAddressInfoLabel
}).component();
//Start IP Address Section:
this._startIpAddressTextbox = view.modelBuilder.inputBox().withProperties(<azdata.InputBoxProperties>{
inputType: 'text'
}).component();
this._startIpAddressTextbox.onTextChanged((value) => {
this.wizard.model.startIpAddress = value;
});
this._startIpAddressTextRow = this.wizard.createFormRowComponent(view, constants.StartIpAddressLabel, '', this._startIpAddressTextbox, true);
//End IP Address Section:
this._endIpAddressTextbox = view.modelBuilder.inputBox().withProperties(<azdata.InputBoxProperties>{
inputType: 'text'
}).component();
this._endIpAddressTextbox.onTextChanged((value) => {
this.wizard.model.endIpAddress = value;
});
this._endIpAddressTextRow = this.wizard.createFormRowComponent(view, constants.EndIpAddressLabel, '', this._endIpAddressTextbox, true);
}
private createFirewallNameText(view: azdata.ModelView) {
this._firewallRuleNameTextbox = view.modelBuilder.inputBox().component();
this._firewallRuleNameTextRow = this.wizard.createFormRowComponent(view, constants.FirewallRuleNameLabel, '', this._firewallRuleNameTextbox, true);
this._firewallRuleNameTextbox.onTextChanged((value) => {
this.wizard.model.firewallRuleName = value;
});
}
private createDatabaseNameText(view: azdata.ModelView) {
this._databaseNameTextbox = view.modelBuilder.inputBox().component();
this._databaseNameTextRow = this.wizard.createFormRowComponent(view, constants.DatabaseNameLabel, '', this._databaseNameTextbox, true);
this._databaseNameTextbox.onTextChanged((value) => {
this.wizard.model.databaseName = value;
});
}
private createCollationText(view: azdata.ModelView) {
this._collationTextbox = view.modelBuilder.inputBox().withProperties(<azdata.InputBoxProperties>{
inputType: 'text',
value: 'SQL_Latin1_General_CP1_CI_AS'
}).component();
this._collationTextbox.onTextChanged((value) => {
this.wizard.model.databaseCollation = value;
});
this._collationTextRow = this.wizard.createFormRowComponent(view, constants.CollationNameLabel, '', this._collationTextbox, true);
}
protected async validate(): Promise<string> {
let errorMessages = [];
let ipRegex = /(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)/;
let startipvalue = this._startIpAddressTextbox.value!;
let endipvalue = this._endIpAddressTextbox.value!;
let firewallname = this._firewallRuleNameTextbox.value!;
let databasename = this._databaseNameTextbox.value!;
let collationname = this._collationTextbox.value!;
if (!(ipRegex.test(startipvalue))) {
errorMessages.push(localize('deployAzureSQLDB.DBMinIpInvalidError', "Min Ip address is invalid"));
}
if (!(ipRegex.test(endipvalue))) {
errorMessages.push(localize('deployAzureSQLDB.DBMaxIpInvalidError', "Max Ip address is invalid"));
}
if (/^\d+$/.test(firewallname)) {
errorMessages.push(localize('deployAzureSQLDB.DBFirewallOnlyNumericNameError', "Firewall name cannot contain only numbers."));
}
if (firewallname.length < 1 || firewallname.length > 100) {
errorMessages.push(localize('deployAzureSQLDB.DBFirewallLengthError', "Firewall name must be between 1 and 100 characters long."));
}
if (/[\\\/"\'\[\]:\|<>\+=;,\?\*@\&,]/g.test(firewallname)) {
errorMessages.push(localize('deployAzureSQLDB.DBFirewallSpecialCharError', "Firewall name cannot contain special characters \/\"\"[]:|<>+=;,?*@&, ."));
}
if (/[A-Z]/g.test(firewallname)) {
errorMessages.push(localize('deployAzureSQLDB.DBFirewallUpperCaseError', "Upper case letters are not allowed for firealll name"));
}
if (/^\d+$/.test(databasename)) {
errorMessages.push(localize('deployAzureSQLDB.DBNameOnlyNumericNameError', "Database name cannot contain only numbers."));
}
if (databasename.length < 1 || databasename.length > 100) {
errorMessages.push(localize('deployAzureSQLDB.DBNameLengthError', "Database name must be between 1 and 100 characters long."));
}
if (/[\\\/"\'\[\]:\|<>\+=;,\?\*@\&,]/g.test(databasename)) {
errorMessages.push(localize('deployAzureSQLDB.DBNameSpecialCharError', "Database name cannot contain special characters \/\"\"[]:|<>+=;,?*@&, ."));
}
if (await this.databaseNameExists(databasename)) {
errorMessages.push(localize('deployAzureSQLDB.DBNameExistsError', "Database name must be unique in the current server."));
}
if (/^\d+$/.test(collationname)) {
errorMessages.push(localize('deployAzureSQLDB.DBCollationOnlyNumericNameError', "Collation name cannot contain only numbers."));
}
if (collationname.length < 1 || collationname.length > 100) {
errorMessages.push(localize('deployAzureSQLDB.DBCollationLengthError', "Collation name must be between 1 and 100 characters long."));
}
if (/[\\\/"\'\[\]:\|<>\+=;,\?\*@\&,]/g.test(collationname)) {
errorMessages.push(localize('deployAzureSQLDB.DBCollationSpecialCharError', "Collation name cannot contain special characters \/\"\"[]:|<>+=;,?*@&, ."));
}
this.wizard.showErrorMessage(errorMessages.join(EOL));
return errorMessages.join(EOL);
}
protected async databaseNameExists(dbName: string): Promise<boolean> {
const url = `https://management.azure.com` +
`/subscriptions/${this.wizard.model.azureSubscription}` +
`/resourceGroups/${this.wizard.model.azureResouceGroup}` +
`/providers/Microsoft.Sql` +
`/servers/${this.wizard.model.azureServerName}` +
`/databases?api-version=2017-10-01-preview`;
let response = await this.wizard.getRequest(url, true);
let nameArray = response.data.value.map((v: any) => { return v.name; });
return (nameArray.includes(dbName));
}
}

View File

@@ -0,0 +1,225 @@
/*---------------------------------------------------------------------------------------------
* 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 { WizardPageBase } from '../../wizardPageBase';
import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard';
import * as constants from '../constants';
import { SectionInfo, LabelPosition, FontWeight, FieldType } from '../../../interfaces';
import { createSection } from '../../modelViewUtils';
export class AzureSQLDBSummaryPage extends WizardPageBase<DeployAzureSQLDBWizard> {
private formItems: azdata.FormComponent[] = [];
private _form!: azdata.FormBuilder;
private _view!: azdata.ModelView;
constructor(wizard: DeployAzureSQLDBWizard) {
super(
'Summary',
'',
wizard
);
}
public async initialize() {
this.pageObject.registerContent(async (view: azdata.ModelView) => {
this._view = view;
this._form = view.modelBuilder.formContainer();
return view.initializeModel(this._form!.withLayout({ width: '100%' }).component());
});
}
public async onEnter(): Promise<void> {
this.formItems.forEach(item => {
this._form.removeFormItem(item);
});
this.formItems = [];
let model = this.wizard.model;
const labelWidth = '150px';
const inputWidth = '400px';
const fieldHeight = '20px';
const auzreSettingSection: SectionInfo = {
labelPosition: LabelPosition.Left,
labelWidth: labelWidth,
inputWidth: inputWidth,
fieldHeight: fieldHeight,
spaceBetweenFields: '0',
title: constants.AzureSettingsSummaryPageTitle,
fields: [
{
type: FieldType.ReadonlyText,
label: constants.AzureAccountDropdownLabel,
defaultValue: model.azureAccount.displayInfo.displayName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.AzureAccountSubscriptionDropdownLabel,
defaultValue: model.azureSubscriptionDisplayName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.AzureAccountResourceGroupDropdownLabel,
defaultValue: model.azureResouceGroup,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.AzureAccountDatabaseServersDropdownLabel,
defaultValue: model.azureServerName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
}
]
};
// const databaseHardwareSettingSection: SectionInfo = { //@todo alma1 9/8/2020 section used for upcoming database hardware creation feature.
// labelPosition: LabelPosition.Left,
// labelWidth: labelWidth,
// inputWidth: inputWidth,
// fieldHeight: fieldHeight,
// spaceBetweenFields: '0',
// title: constants.DatabaseHardwareInfoLabel,
// fields: [
// {
// type: FieldType.ReadonlyText,
// label: constants.DatabaseSupportedEditionsDropdownLabel,
// defaultValue: model.databaseEdition,
// labelCSSStyles: { fontWeight: FontWeight.Bold }
// },
// {
// type: FieldType.ReadonlyText,
// label: constants.DatabaseSupportedFamilyDropdownLabel,
// defaultValue: model.databaseFamily,
// labelCSSStyles: { fontWeight: FontWeight.Bold }
// },
// {
// type: FieldType.ReadonlyText,
// label: constants.DatabaseVCoreNumberDropdownLabel,
// defaultValue: String(model.vCoreNumber),
// labelCSSStyles: { fontWeight: FontWeight.Bold }
// },
// {
// type: FieldType.ReadonlyText,
// label: constants.DatabaseMaxMemorySummaryTextLabel,
// defaultValue: model.storageInGB,
// labelCSSStyles: { fontWeight: FontWeight.Bold }
// }
// ]
// };
const databaseSettingSection: SectionInfo = {
labelPosition: LabelPosition.Left,
labelWidth: labelWidth,
inputWidth: inputWidth,
fieldHeight: fieldHeight,
title: constants.DatabaseSettingsPageTitle,
fields: [
{
type: FieldType.ReadonlyText,
label: constants.DatabaseNameLabel,
defaultValue: model.databaseName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.CollationNameSummaryLabel,
defaultValue: model.databaseCollation,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.FirewallRuleNameLabel,
defaultValue: model.firewallRuleName,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.StartIpAddressShortLabel,
defaultValue: model.startIpAddress,
labelCSSStyles: { fontWeight: FontWeight.Bold }
},
{
type: FieldType.ReadonlyText,
label: constants.EndIpAddressShortLabel,
defaultValue: model.endIpAddress,
labelCSSStyles: { fontWeight: FontWeight.Bold }
}
]
};
const createSectionFunc = async (sectionInfo: SectionInfo): Promise<azdata.FormComponent> => {
return {
title: '',
component: await createSection({
container: this.wizard.wizardObject,
inputComponents: {},
sectionInfo: sectionInfo,
view: this._view,
onNewDisposableCreated: () => { },
onNewInputComponentCreated: () => { },
onNewValidatorCreated: () => { },
toolsService: this.wizard.toolsService
})
};
};
const azureSection = await createSectionFunc(auzreSettingSection);
//const databaseHardwareSection = await createSectionFunc(databaseHardwareSettingSection); //@todo alma1 9/8/2020 used for upcoming database hardware creation feature.
const databaseSection = await createSectionFunc(databaseSettingSection);
this.formItems.push(azureSection, /*databaseHardwareSection,*/ databaseSection);
this._form.addFormItems(this.formItems);
this.wizard.wizardObject.registerNavigationValidator((pcInfo) => {
return true;
});
}
public async onLeave(): Promise<void> {
this.wizard.wizardObject.registerNavigationValidator((pcInfo) => {
return true;
});
}
public createSummaryRow(view: azdata.ModelView, title: string, textComponent: azdata.TextComponent): azdata.FlexContainer {
const labelText = view.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>(
{
value: title,
width: '250px',
})
.component();
labelText.updateCssStyles({
'font-weight': '400',
'font-size': '13px',
});
const flexContainer = view.modelBuilder.flexContainer()
.withLayout(
{
flexFlow: 'row',
alignItems: 'center',
})
.withItems(
[labelText, textComponent],
{
CSSStyles: { 'margin-right': '5px' }
})
.component();
return flexContainer;
}
}

View File

@@ -274,9 +274,6 @@ export class ResourceTypePickerDialog extends DialogBase {
private selectResourceType(resourceType: ResourceType): void {
this._currentResourceTypeDisposables.forEach(disposable => disposable.dispose());
this._selectedResourceType = resourceType;
//handle special case when resource type has different OK button.
this._dialogObject.okButton.label = this._selectedResourceType.okButtonText || loc.select;
this._agreementCheckboxChecked = false;
this._agreementContainer.clearItems();
if (resourceType.agreement) {
@@ -299,15 +296,26 @@ export class ResourceTypePickerDialog extends DialogBase {
ariaLabel: option.displayName
}).component();
this._currentResourceTypeDisposables.push(optionSelectBox.onValueChanged(() => { this.updateToolsDisplayTable(); }));
this._currentResourceTypeDisposables.push(optionSelectBox.onValueChanged(() => {
this.updateOkButtonText();
this.updateToolsDisplayTable();
}));
this._optionDropDownMap.set(option.name, optionSelectBox);
const row = this._view.modelBuilder.flexContainer().withItems([optionLabel, optionSelectBox], { flex: '0 0 auto', CSSStyles: { 'margin-right': '20px' } }).withLayout({ flexFlow: 'row', alignItems: 'center' }).component();
this._optionsContainer.addItem(row);
});
}
this.updateOkButtonText();
this.updateToolsDisplayTable();
}
private updateOkButtonText(): void {
//handle special case when resource type has different OK button.
let text = this.getCurrentOkText();
this._dialogObject.okButton.label = text || loc.select;
}
private updateToolsDisplayTable(): void {
this.toolRefreshTimestamp = new Date().getTime();
const currentRefreshTimestamp = this.toolRefreshTimestamp;
@@ -482,6 +490,17 @@ export class ResourceTypePickerDialog extends DialogBase {
return this._selectedResourceType.getProvider(options)!;
}
private getCurrentOkText(): string {
const options: { option: string, value: string }[] = [];
this._optionDropDownMap.forEach((selectBox, option) => {
let selectedValue: azdata.CategoryValue = selectBox.value as azdata.CategoryValue;
options.push({ option: option, value: selectedValue.name });
});
return this._selectedResourceType.getOkButtonText(options)!;
}
protected async onComplete(): Promise<void> {
this.toolsService.toolsForCurrentProvider = this._tools;
this.resourceTypeService.startDeployment(this.getCurrentProvider());