diff --git a/extensions/resource-deployment/src/services/resourceTypeService.ts b/extensions/resource-deployment/src/services/resourceTypeService.ts index e2430b7b5a..252d0628c4 100644 --- a/extensions/resource-deployment/src/services/resourceTypeService.ts +++ b/extensions/resource-deployment/src/services/resourceTypeService.ts @@ -11,10 +11,7 @@ import * as path from 'path'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; 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 { DeploymentInputDialog } from '../ui/deploymentInputDialog'; -import { NotebookWizard } from '../ui/notebookWizard/notebookWizard'; import { AzdataService } from './azdataService'; import { KubeService } from './kubeService'; import { INotebookService } from './notebookService'; @@ -253,13 +250,7 @@ export class ResourceTypeService implements IResourceTypeService { public startDeployment(resourceType: ResourceType, provider: DeploymentProvider): void { const self = this; - if (instanceOfWizardDeploymentProvider(provider)) { - const wizard = new ResourceTypeWizard(resourceType, provider, new KubeService(), new AzdataService(this.platformService), this.notebookService, this.toolsService, this.platformService); - wizard.open(); - } else if (instanceOfNotebookWizardDeploymentProvider(provider)) { - const wizard = new NotebookWizard(provider.notebookWizard, this.notebookService, this.platformService, this.toolsService); - wizard.open(); - } else if (instanceOfDialogDeploymentProvider(provider)) { + if (instanceOfDialogDeploymentProvider(provider)) { const dialog = new DeploymentInputDialog(this.notebookService, this.platformService, this.toolsService, provider.dialog); dialog.open(); } else if (instanceOfNotebookDeploymentProvider(provider)) { @@ -286,11 +277,8 @@ export class ResourceTypeService implements IResourceTypeService { vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(provider.webPageUrl)); } else if (instanceOfCommandDeploymentProvider(provider)) { vscode.commands.executeCommand(provider.command); - } 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); + } else { + const wizard = new ResourceTypeWizard(resourceType, provider, new KubeService(), new AzdataService(this.platformService), this.notebookService, this.toolsService, this.platformService); wizard.open(); } } diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/deployAzureSQLDBWizard.ts b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/deployAzureSQLDBWizard.ts deleted file mode 100644 index d3c23d7a9a..0000000000 --- a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/deployAzureSQLDBWizard.ts +++ /dev/null @@ -1,175 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as azdata from 'azdata'; -import * 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, DeployAzureSQLDBWizardModel> { - - constructor(private wizardInfo: AzureSQLDBWizardInfo, private _notebookService: INotebookService, private _toolsService: IToolsService) { - super( - constants.WizardTitle, - 'DeployAzureSqlDBWizard', - new DeployAzureSQLDBWizardModel(), - _toolsService - ); - } - - private cache: Map = 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 { - await this.scriptToNotebook(); - } - - protected onCancel(): void { - } - - private getPages(): WizardPageBase[] { - const pages: WizardPageBase[] = []; - pages.push(new AzureSettingsPage(this)); - pages.push(new DatabaseSettingsPage(this)); - pages.push(new AzureSQLDBSummaryPage(this)); - return pages; - } - - private async scriptToNotebook(): Promise { - 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 { - 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( - { - 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 - }; - } -} diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/deployAzureSQLDBWizardModel.ts b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/deployAzureSQLDBWizardModel.ts index 2298412bbc..7d69b07224 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/deployAzureSQLDBWizardModel.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/deployAzureSQLDBWizardModel.ts @@ -5,9 +5,22 @@ import { EOL } from 'os'; import * as azdata from 'azdata'; -import { Model } from '../model'; +import * as vscode from 'vscode'; +import * as constants from './constants'; +import axios, { AxiosRequestConfig } from 'axios'; +import { ResourceTypeModel } from '../resourceTypeModel'; +import { INotebookService } from '../../services/notebookService'; +import { IToolsService } from '../../services/toolsService'; +import { AzureSQLDBDeploymentProvider } from '../../interfaces'; +import { ResourceTypeWizard } from '../resourceTypeWizard'; +import { ResourceTypePage } from '../resourceTypePage'; +import { DatabaseSettingsPage } from './pages/databaseSettingsPage'; +import { AzureSQLDBSummaryPage } from './pages/summaryPage'; +import { AzureSettingsPage } from './pages/azureSettingsPage'; + +export class DeployAzureSQLDBWizardModel extends ResourceTypeModel { + private cache: Map = new Map(); -export class DeployAzureSQLDBWizardModel extends Model { public azureAccount!: azdata.Account; public securityToken!: any; public azureSubscription!: string; @@ -29,9 +42,142 @@ export class DeployAzureSQLDBWizardModel extends Model { public databaseCollation!: string; public newFirewallRule!: boolean; + public get notebookService(): INotebookService { + return this.wizard.notebookService; + } - constructor() { - super(); + public get toolService(): IToolsService { + return this.wizard.toolsService; + } + + constructor(public sqldbProvider: AzureSQLDBDeploymentProvider, wizard: ResourceTypeWizard) { + super(sqldbProvider, wizard); + this.wizard.wizardObject.title = constants.WizardTitle; + } + + initialize(): void { + this.wizard.setPages(this.getPages()); + this.wizard.wizardObject.generateScriptButton.hidden = true; + this.wizard.wizardObject.doneButton.label = constants.WizardDoneButtonLabel; + } + + async onOk(): Promise { + await this.scriptToNotebook(); + } + + onCancel(): void { + } + + private getPages(): ResourceTypePage[] { + const pages: ResourceTypePage[] = []; + pages.push(new AzureSettingsPage(this)); + pages.push(new DatabaseSettingsPage(this)); + pages.push(new AzureSQLDBSummaryPage(this)); + return pages; + } + + public async getRequest(url: string, useCache = false): Promise { + if (useCache) { + if (this.cache.has(url)) { + return this.cache.get(url); + } + } + let token = this.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( + { + 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' + }); + } + + private async scriptToNotebook(): Promise { + const variableValueStatements = this.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.sqldbProvider.azureSQLDBWizard.notebook, variableValueStatements, insertionPosition); + } catch (error) { + vscode.window.showErrorMessage(error); + } } public getCodeCellContentForNotebook(): string[] { diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/azureSettingsPage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/azureSettingsPage.ts index 6df73953a4..b5758a52f4 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/azureSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/azureSettingsPage.ts @@ -6,12 +6,12 @@ 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'; +import { DeployAzureSQLDBWizardModel } from '../deployAzureSQLDBWizardModel'; import * as localizedConstants from '../../../localizedConstants'; const localize = nls.loadMessageBundle(); @@ -59,11 +59,11 @@ export class AzureSettingsPage extends BasePage { private _accountsMap!: Map; private _subscriptionsMap!: Map; - constructor(wizard: DeployAzureSQLDBWizard) { + constructor(private _model: DeployAzureSQLDBWizardModel) { super( constants.AzureSettingsPageTitle, '', - wizard + _model.wizard ); this._accountsMap = new Map(); this._subscriptionsMap = new Map(); @@ -91,19 +91,19 @@ export class AzureSettingsPage extends BasePage { .withFormItems( [ { - component: this.wizard.createFormRowComponent(view, constants.AzureAccountDropdownLabel, '', this._azureAccountsDropdown, true) + component: this._model.createFormRowComponent(view, constants.AzureAccountDropdownLabel, '', this._azureAccountsDropdown, true) }, { component: this.buttonFlexContainer }, { - component: this.wizard.createFormRowComponent(view, constants.AzureAccountSubscriptionDropdownLabel, '', this._azureSubscriptionsDropdown, true) + component: this._model.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) + component: this._model.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) @@ -162,7 +162,7 @@ export class AzureSettingsPage extends BasePage { this._azureAccountsDropdown = view.modelBuilder.dropDown().withProperties({}).component(); this._azureAccountsDropdown.onValueChanged(async (value) => { - this.wizard.model.azureAccount = this._accountsMap.get(value.selected)!; + this._model.azureAccount = this._accountsMap.get(value.selected)!; this.populateAzureSubscriptionsDropdown(); }); @@ -193,13 +193,13 @@ export class AzureSettingsPage extends BasePage { let accounts = await azdata.accounts.getAllAccounts(); if (accounts.length === 0) { - this.wizard.showErrorMessage(localize('deployAzureSQLDB.azureSignInError', "Sign in to an Azure account first")); + this._model.wizard.showErrorMessage(localize('deployAzureSQLDB.azureSignInError', "Sign in to an Azure account first")); return; } else { - this.wizard.showErrorMessage(''); + this._model.wizard.showErrorMessage(''); } - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._azureAccountsDropdown, accounts.map((account): azdata.CategoryValue => { let accountCategoryValue = { @@ -211,7 +211,7 @@ export class AzureSettingsPage extends BasePage { }), ); - this.wizard.model.azureAccount = accounts[0]; + this._model.azureAccount = accounts[0]; this._azureAccountsDropdown.loading = false; await this.populateAzureSubscriptionsDropdown(); @@ -223,11 +223,11 @@ export class AzureSettingsPage extends BasePage { 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._model.azureSubscription = currentSubscriptionValue.name; + this._model.azureSubscriptionDisplayName = currentSubscriptionValue.displayName; - this.wizard.model.securityToken = await azdata.accounts.getAccountSecurityToken( - this.wizard.model.azureAccount, + this._model.securityToken = await azdata.accounts.getAccountSecurityToken( + this._model.azureAccount, this._subscriptionsMap.get(currentSubscriptionValue.name)?.tenant!, azdata.AzureResource.ResourceManagement ); @@ -266,7 +266,7 @@ export class AzureSettingsPage extends BasePage { } subscriptions.sort((a: any, b: any) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase())); - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._azureSubscriptionsDropdown, subscriptions.map((subscription: any): azdata.CategoryValue => { let subscriptionCategoryValue = { @@ -278,11 +278,11 @@ export class AzureSettingsPage extends BasePage { }) ); - this.wizard.model.azureSubscription = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name; - this.wizard.model.azureSubscriptionDisplayName = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).displayName; + this._model.azureSubscription = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name; + this._model.azureSubscriptionDisplayName = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).displayName; - this.wizard.model.securityToken = await azdata.accounts.getAccountSecurityToken( - this.wizard.model.azureAccount, + this._model.securityToken = await azdata.accounts.getAccountSecurityToken( + this._model.azureAccount, this._subscriptionsMap.get((this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name)?.tenant!, azdata.AzureResource.ResourceManagement ); @@ -299,9 +299,9 @@ export class AzureSettingsPage extends BasePage { }).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._model.azureServerName = value.selected; + this._model.azureResouceGroup = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), ''); + this._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. } }); @@ -318,8 +318,8 @@ export class AzureSettingsPage extends BasePage { // 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); + let url = `https://management.azure.com/subscriptions/${this._model.azureSubscription}/providers/Microsoft.Sql/servers?api-version=2019-06-01-preview`; + let response = await this._model.getRequest(url); if (response.data.value.length === 0) { this._serverGroupDropdown.updateProperties({ values: [ @@ -335,7 +335,7 @@ export class AzureSettingsPage extends BasePage { } else { response.data.value.sort((a: azdata.CategoryValue, b: azdata.CategoryValue) => (a!.name > b!.name) ? 1 : -1); } - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._serverGroupDropdown, response.data.value.map((value: any) => { return { @@ -346,9 +346,9 @@ export class AzureSettingsPage extends BasePage { }) ); 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._model.azureServerName = (this._serverGroupDropdown.value as azdata.CategoryValue).displayName; + this._model.azureResouceGroup = (this._serverGroupDropdown.value as azdata.CategoryValue).name.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), ''); + this._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. @@ -760,7 +760,7 @@ export class AzureSettingsPage extends BasePage { // errorMessages.push(localize('deployAzureSQLDB.SupportedFamiliesError', "No Supported Family found in current DB edition.\nSelect a different edition")); // } - this.wizard.showErrorMessage(errorMessages.join(EOL)); + this._model.wizard.showErrorMessage(errorMessages.join(EOL)); return errorMessages.join(EOL); } } diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/basePage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/basePage.ts index 2528167213..0e80db77dc 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/basePage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/basePage.ts @@ -3,9 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { WizardPageBase } from '../../wizardPageBase'; -import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard'; +import { ResourceTypePage } from '../../resourceTypePage'; -export abstract class BasePage extends WizardPageBase { +export abstract class BasePage extends ResourceTypePage { public abstract initialize(): void; } diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/databaseSettingsPage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/databaseSettingsPage.ts index 0985c975a2..58dac361db 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/databaseSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/databaseSettingsPage.ts @@ -5,10 +5,10 @@ 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'; +import { DeployAzureSQLDBWizardModel } from '../deployAzureSQLDBWizardModel'; import { createCheckbox, createFlexContainer, createLabel } from '../../modelViewUtils'; const localize = nls.loadMessageBundle(); @@ -32,11 +32,11 @@ export class DatabaseSettingsPage extends BasePage { private _form!: azdata.FormContainer; - constructor(wizard: DeployAzureSQLDBWizard) { + constructor(private _model: DeployAzureSQLDBWizardModel) { super( constants.DatabaseSettingsPageTitle, '', - wizard + _model.wizard ); } @@ -119,10 +119,10 @@ export class DatabaseSettingsPage extends BasePage { }).component(); this._startIpAddressTextbox.onTextChanged((value) => { - this.wizard.model.startIpAddress = value; + this._model.startIpAddress = value; }); - this._startIpAddressTextRow = this.wizard.createFormRowComponent(view, constants.StartIpAddressLabel, '', this._startIpAddressTextbox, true); + this._startIpAddressTextRow = this._model.createFormRowComponent(view, constants.StartIpAddressLabel, '', this._startIpAddressTextbox, true); //End IP Address Section: @@ -131,10 +131,10 @@ export class DatabaseSettingsPage extends BasePage { }).component(); this._endIpAddressTextbox.onTextChanged((value) => { - this.wizard.model.endIpAddress = value; + this._model.endIpAddress = value; }); - this._endIpAddressTextRow = this.wizard.createFormRowComponent(view, constants.EndIpAddressLabel, '', this._endIpAddressTextbox, true); + this._endIpAddressTextRow = this._model.createFormRowComponent(view, constants.EndIpAddressLabel, '', this._endIpAddressTextbox, true); } private createFirewallToggle(view: azdata.ModelView) { @@ -156,15 +156,15 @@ export class DatabaseSettingsPage extends BasePage { } }); - this.wizard.model.newFirewallRule = true; + this._model.newFirewallRule = true; this._firewallToggleDropdown.onChanged((value) => { let displayValue: 'block' | 'none' = (value) ? 'block' : 'none'; - this.wizard.changeRowDisplay(this._firewallRuleNameTextRow, displayValue); - this.wizard.changeRowDisplay(this._endIpAddressTextRow, displayValue); - this.wizard.changeRowDisplay(this._startIpAddressTextRow, displayValue); - this.wizard.changeComponentDisplay(this._IpInfoText, displayValue); - this.wizard.model.newFirewallRule = value; + this._model.changeRowDisplay(this._firewallRuleNameTextRow, displayValue); + this._model.changeRowDisplay(this._endIpAddressTextRow, displayValue); + this._model.changeRowDisplay(this._startIpAddressTextRow, displayValue); + this._model.changeComponentDisplay(this._IpInfoText, displayValue); + this._model.newFirewallRule = value; }); } @@ -172,10 +172,10 @@ export class DatabaseSettingsPage extends BasePage { this._firewallRuleNameTextbox = view.modelBuilder.inputBox().component(); - this._firewallRuleNameTextRow = this.wizard.createFormRowComponent(view, constants.FirewallRuleNameLabel, '', this._firewallRuleNameTextbox, true); + this._firewallRuleNameTextRow = this._model.createFormRowComponent(view, constants.FirewallRuleNameLabel, '', this._firewallRuleNameTextbox, true); this._firewallRuleNameTextbox.onTextChanged((value) => { - this.wizard.model.firewallRuleName = value; + this._model.firewallRuleName = value; }); } @@ -183,10 +183,10 @@ export class DatabaseSettingsPage extends BasePage { this._databaseNameTextbox = view.modelBuilder.inputBox().component(); - this._databaseNameTextRow = this.wizard.createFormRowComponent(view, constants.DatabaseNameLabel, '', this._databaseNameTextbox, true); + this._databaseNameTextRow = this._model.createFormRowComponent(view, constants.DatabaseNameLabel, '', this._databaseNameTextbox, true); this._databaseNameTextbox.onTextChanged((value) => { - this.wizard.model.databaseName = value; + this._model.databaseName = value; }); } @@ -197,10 +197,10 @@ export class DatabaseSettingsPage extends BasePage { }).component(); this._collationTextbox.onTextChanged((value) => { - this.wizard.model.databaseCollation = value; + this._model.databaseCollation = value; }); - this._collationTextRow = this.wizard.createFormRowComponent(view, constants.CollationNameLabel, '', this._collationTextbox, true); + this._collationTextRow = this._model.createFormRowComponent(view, constants.CollationNameLabel, '', this._collationTextbox, true); } @@ -213,7 +213,7 @@ export class DatabaseSettingsPage extends BasePage { let databasename = this._databaseNameTextbox.value!; let collationname = this._collationTextbox.value!; - if (this.wizard.model.newFirewallRule) { + if (this._model.newFirewallRule) { if (!(ipRegex.test(startipvalue))) { errorMessages.push(localize('deployAzureSQLDB.DBMinIpInvalidError', "Min Ip address is invalid")); } @@ -260,19 +260,19 @@ export class DatabaseSettingsPage extends BasePage { errorMessages.push(localize('deployAzureSQLDB.DBCollationSpecialCharError', "Collation name cannot contain special characters \/\"\"[]:|<>+=;,?*@&, .")); } - this.wizard.showErrorMessage(errorMessages.join(EOL)); + this._model.wizard.showErrorMessage(errorMessages.join(EOL)); return errorMessages.join(EOL); } protected async databaseNameExists(dbName: string): Promise { const url = `https://management.azure.com` + - `/subscriptions/${this.wizard.model.azureSubscription}` + - `/resourceGroups/${this.wizard.model.azureResouceGroup}` + + `/subscriptions/${this._model.azureSubscription}` + + `/resourceGroups/${this._model.azureResouceGroup}` + `/providers/Microsoft.Sql` + - `/servers/${this.wizard.model.azureServerName}` + + `/servers/${this._model.azureServerName}` + `/databases?api-version=2017-10-01-preview`; - let response = await this.wizard.getRequest(url, true); + let response = await this._model.getRequest(url, true); let nameArray = response.data.value.map((v: any) => { return v.name; }); return (nameArray.includes(dbName)); diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/summaryPage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/summaryPage.ts index 47d9314416..85387506ec 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/summaryPage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLDBWizard/pages/summaryPage.ts @@ -4,24 +4,24 @@ *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; -import { WizardPageBase } from '../../wizardPageBase'; -import { DeployAzureSQLDBWizard } from '../deployAzureSQLDBWizard'; import * as constants from '../constants'; import * as localizedConstants from '../../../localizedConstants'; import { SectionInfo, LabelPosition, FontWeight, FieldType } from '../../../interfaces'; import { createSection } from '../../modelViewUtils'; +import { BasePage } from '../../deployAzureSQLVMWizard/pages/basePage'; +import { DeployAzureSQLDBWizardModel } from '../deployAzureSQLDBWizardModel'; -export class AzureSQLDBSummaryPage extends WizardPageBase { +export class AzureSQLDBSummaryPage extends BasePage { private formItems: azdata.FormComponent[] = []; private _form!: azdata.FormBuilder; private _view!: azdata.ModelView; - constructor(wizard: DeployAzureSQLDBWizard) { + constructor(private _model: DeployAzureSQLDBWizardModel) { super( 'Summary', '', - wizard + _model.wizard ); } @@ -42,7 +42,7 @@ export class AzureSQLDBSummaryPage extends WizardPageBase, DeployAzureSQLVMWizardModel> { - private cache: Map = new Map(); - - constructor(private wizardInfo: AzureSQLVMWizardInfo, private _notebookService: INotebookService, private _toolsService: IToolsService) { - super( - constants.WizardTitle, - 'DeployAzureSqlVMWizard', - new DeployAzureSQLVMWizardModel(), - _toolsService - ); - } - - 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 { - await this.scriptToNotebook(); - } - - protected onCancel(): void { - } - - private getPages(): WizardPageBase[] { - const pages: WizardPageBase[] = []; - pages.push(new AzureSettingsPage(this)); - pages.push(new VmSettingsPage(this)); - pages.push(new NetworkSettingsPage(this)); - pages.push(new SqlServerSettingsPage(this)); - pages.push(new AzureSQLVMSummaryPage(this)); - return pages; - } - - private async scriptToNotebook(): Promise { - this.setEnvironmentVariables(process.env); - const variableValueStatements = this.model.getCodeCellContentForNotebook(); - const insertionPosition = 2; // Cell number 5 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); - } - } - - private setEnvironmentVariables(env: NodeJS.ProcessEnv): void { - env['AZDATA_NB_VAR_AZURE_SQLVM_PASSWORD'] = this.model.vmPassword; - env['AZDATA_NB_VAR_AZURE_SQLVM_SQL_PASSWORD'] = this.model.sqlAuthenticationPassword; - } - - public async getRequest(url: string, useCache = false): Promise { - 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( - { - 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 - }; - } - - public validatePassword(password: string): string[] { - /** - * 1. Password length should be between 12 and 123. - * 2. Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. - */ - - let errorMessages = []; - - if (password.length < 12 || password.length > 123) { - errorMessages.push(localize('sqlVMDeploymentWizard.PasswordLengthError', "Password must be between 12 and 123 characters long.")); - } - - let charTypeCounter = 0; - - if (new RegExp('.*[a-z].*').test(password)) { - charTypeCounter++; - } - - if (new RegExp('.*[A-Z].*').test(password)) { - charTypeCounter++; - } - - if (new RegExp('.*[0-9].*').test(password)) { - charTypeCounter++; - } - - if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/.test(password)) { - charTypeCounter++; - } - - if (charTypeCounter < 3) { - errorMessages.push(localize('sqlVMDeploymentWizard.PasswordSpecialCharRequirementError', "Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character.")); - } - - return errorMessages; - } -} diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/deployAzureSQLVMWizardModel.ts b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/deployAzureSQLVMWizardModel.ts index ccc2054ade..d24584c023 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/deployAzureSQLVMWizardModel.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/deployAzureSQLVMWizardModel.ts @@ -5,9 +5,27 @@ import { EOL } from 'os'; import * as azdata from 'azdata'; -import { Model } from '../model'; +import { ResourceTypeWizard } from '../resourceTypeWizard'; +import { AzureSQLVMDeploymentProvider } from '../../interfaces'; +import * as constants from './constants'; +import { IToolsService } from '../../services/toolsService'; +import { INotebookService } from '../../services/notebookService'; +import axios, { AxiosRequestConfig } from 'axios'; +import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; +import { AzureSettingsPage } from './pages/azureSettingsPage'; +import { VmSettingsPage } from './pages/vmSettingsPage'; +import { NetworkSettingsPage } from './pages/networkSettingsPage'; +import { SqlServerSettingsPage } from './pages/sqlServerSettingsPage'; +import { AzureSQLVMSummaryPage } from './pages/summaryPage'; +import { ResourceTypeModel } from '../resourceTypeModel'; +import { ResourceTypePage } from '../resourceTypePage'; +const localize = nls.loadMessageBundle(); + + +export class DeployAzureSQLVMWizardModel extends ResourceTypeModel { + private cache: Map = new Map(); -export class DeployAzureSQLVMWizardModel extends Model { public azureAccount!: azdata.Account; public securityToken!: any; public azureSubscription!: string; @@ -38,15 +56,197 @@ export class DeployAzureSQLVMWizardModel extends Model { public sqlAuthenticationPassword!: string; public sqlOptimizationDropdown!: string; - - constructor() { - super(); + public get notebookService(): INotebookService { + return this.wizard.notebookService; } + public get toolService(): IToolsService { + return this.wizard.toolsService; + } + + + constructor(public sqlvmProvider: AzureSQLVMDeploymentProvider, wizard: ResourceTypeWizard) { + super(sqlvmProvider, wizard); + this.wizard.wizardObject.title = constants.WizardTitle; + } + + initialize(): void { + this.wizard.setPages(this.getPages()); + this.wizard.wizardObject.generateScriptButton.hidden = true; + this.wizard.wizardObject.doneButton.label = constants.WizardDoneButtonLabel; + } + + async onOk(): Promise { + await this.scriptToNotebook(); + } + + onCancel(): void { + throw new Error('Method not implemented.'); + } + + private getPages(): ResourceTypePage[] { + const pages: ResourceTypePage[] = []; + pages.push(new AzureSettingsPage(this)); + pages.push(new VmSettingsPage(this)); + pages.push(new NetworkSettingsPage(this)); + pages.push(new SqlServerSettingsPage(this)); + pages.push(new AzureSQLVMSummaryPage(this)); + return pages; + } + + + private async scriptToNotebook(): Promise { + this.setNotebookEnvironmentVariables(process.env); + const variableValueStatements = this.getCodeCellContentForNotebook(); + const insertionPosition = 2; // Cell number 5 is the position where the python variable setting statements need to be inserted in this.wizardInfo.notebook. + try { + await this.notebookService.openNotebookWithEdits(this.sqlvmProvider.azureSQLVMWizard.notebook, variableValueStatements, insertionPosition); + } catch (error) { + vscode.window.showErrorMessage(error); + } + } + + private setNotebookEnvironmentVariables(env: NodeJS.ProcessEnv): void { + env['AZDATA_NB_VAR_AZURE_SQLVM_PASSWORD'] = this.vmPassword; + env['AZDATA_NB_VAR_AZURE_SQLVM_SQL_PASSWORD'] = this.sqlAuthenticationPassword; + } + + + public async getRequest(url: string, useCache = false): Promise { + if (useCache) { + if (this.cache.has(url)) { + return this.cache.get(url); + } + } + let token = this.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( + { + 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 validatePassword(password: string): string[] { + /** + * 1. Password length should be between 12 and 123. + * 2. Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. + */ + + let errorMessages = []; + + if (password.length < 12 || password.length > 123) { + errorMessages.push(localize('sqlVMDeploymentWizard.PasswordLengthError', "Password must be between 12 and 123 characters long.")); + } + + let charTypeCounter = 0; + + if (new RegExp('.*[a-z].*').test(password)) { + charTypeCounter++; + } + + if (new RegExp('.*[A-Z].*').test(password)) { + charTypeCounter++; + } + + if (new RegExp('.*[0-9].*').test(password)) { + charTypeCounter++; + } + + if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/.test(password)) { + charTypeCounter++; + } + + if (charTypeCounter < 3) { + errorMessages.push(localize('sqlVMDeploymentWizard.PasswordSpecialCharRequirementError', "Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character.")); + } + + return errorMessages; + } + + public getCodeCellContentForNotebook(): string[] { const statements: string[] = []; - statements.push('import os'); statements.push(`azure_sqlvm_nb_var_subscription = '${this.azureSubscription}'`); statements.push(`azure_sqlvm_nb_var_resource_group_name = '${this.azureResouceGroup}'`); diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/azureSettingsPage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/azureSettingsPage.ts index 2b6ab352e7..5730b37f94 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/azureSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/azureSettingsPage.ts @@ -5,14 +5,14 @@ import * as azdata from 'azdata'; import * as constants from '../constants'; -import { WizardPageBase } from '../../wizardPageBase'; -import { DeployAzureSQLVMWizard } from '../deployAzureSQLVMWizard'; import { apiService } from '../../../services/apiService'; import { azureResource } from 'azureResource'; import * as vscode from 'vscode'; import * as localizedConstants from '../../../localizedConstants'; +import { BasePage } from './basePage'; +import { DeployAzureSQLVMWizardModel } from '../deployAzureSQLVMWizardModel'; -export class AzureSettingsPage extends WizardPageBase { +export class AzureSettingsPage extends BasePage { // <- means depends on //dropdown for azure accounts private _azureAccountsDropdown!: azdata.DropDownComponent; @@ -34,11 +34,11 @@ export class AzureSettingsPage extends WizardPageBase { private _accountsMap!: Map; private _subscriptionsMap!: Map; - constructor(wizard: DeployAzureSQLVMWizard) { + constructor(private _model: DeployAzureSQLVMWizardModel) { super( constants.AzureSettingsPageTitle, '', - wizard + _model.wizard ); this._accountsMap = new Map(); this._subscriptionsMap = new Map(); @@ -59,19 +59,19 @@ export class AzureSettingsPage extends WizardPageBase { .withFormItems( [ { - component: this.wizard.createFormRowComponent(view, constants.AzureAccountDropdownLabel, '', this._azureAccountsDropdown, true) + component: this._model.createFormRowComponent(view, constants.AzureAccountDropdownLabel, '', this._azureAccountsDropdown, true) }, { component: this.buttonFlexContainer }, { - component: this.wizard.createFormRowComponent(view, constants.AzureAccountSubscriptionDropdownLabel, '', this._azureSubscriptionsDropdown, true) + component: this._model.createFormRowComponent(view, constants.AzureAccountSubscriptionDropdownLabel, '', this._azureSubscriptionsDropdown, true) }, { - component: this.wizard.createFormRowComponent(view, constants.AzureAccountResourceGroupDropdownLabel, '', this._resourceGroupDropdown, true) + component: this._model.createFormRowComponent(view, constants.AzureAccountResourceGroupDropdownLabel, '', this._resourceGroupDropdown, true) }, { - component: this.wizard.createFormRowComponent(view, constants.AzureAccountRegionDropdownLabel, '', this._azureRegionsDropdown, true) + component: this._model.createFormRowComponent(view, constants.AzureAccountRegionDropdownLabel, '', this._azureRegionsDropdown, true) } ], { @@ -85,13 +85,13 @@ export class AzureSettingsPage extends WizardPageBase { } public async onEnter(): Promise { - this.wizard.wizardObject.registerNavigationValidator((pcInfo) => { + this._model.wizard.wizardObject.registerNavigationValidator((pcInfo) => { return true; }); } public async onLeave(): Promise { - this.wizard.wizardObject.registerNavigationValidator((pcInfo) => { + this._model.wizard.wizardObject.registerNavigationValidator((pcInfo) => { return true; }); } @@ -101,7 +101,7 @@ export class AzureSettingsPage extends WizardPageBase { this._azureAccountsDropdown = view.modelBuilder.dropDown().withProperties({}).component(); this._azureAccountsDropdown.onValueChanged(async (value) => { - this.wizard.model.azureAccount = this._accountsMap.get(value.selected)!; + this._model.azureAccount = this._accountsMap.get(value.selected)!; this.populateAzureSubscriptionsDropdown(); }); @@ -132,13 +132,13 @@ export class AzureSettingsPage extends WizardPageBase { let accounts = await azdata.accounts.getAllAccounts(); if (accounts.length === 0) { - this.wizard.showErrorMessage('Sign in to an Azure account first'); + this._model.wizard.showErrorMessage('Sign in to an Azure account first'); return; } else { - this.wizard.showErrorMessage(''); + this._model.wizard.showErrorMessage(''); } - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._azureAccountsDropdown, accounts.map((account): azdata.CategoryValue => { let accountCategoryValue = { @@ -150,7 +150,7 @@ export class AzureSettingsPage extends WizardPageBase { }), ); - this.wizard.model.azureAccount = accounts[0]; + this._model.azureAccount = accounts[0]; this._azureAccountsDropdown.loading = false; await this.populateAzureSubscriptionsDropdown(); @@ -162,11 +162,11 @@ export class AzureSettingsPage extends WizardPageBase { 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._model.azureSubscription = currentSubscriptionValue.name; + this._model.azureSubscriptionDisplayName = currentSubscriptionValue.displayName; - this.wizard.model.securityToken = await azdata.accounts.getAccountSecurityToken( - this.wizard.model.azureAccount, + this._model.securityToken = await azdata.accounts.getAccountSecurityToken( + this._model.azureAccount, this._subscriptionsMap.get(currentSubscriptionValue.name)?.tenant!, azdata.AzureResource.ResourceManagement ); @@ -199,7 +199,7 @@ export class AzureSettingsPage extends WizardPageBase { } subscriptions.sort((a: any, b: any) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase())); - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._azureSubscriptionsDropdown, subscriptions.map((subscription: any): azdata.CategoryValue => { let subscriptionCategoryValue = { @@ -211,11 +211,11 @@ export class AzureSettingsPage extends WizardPageBase { }) ); - this.wizard.model.azureSubscription = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name; - this.wizard.model.azureSubscriptionDisplayName = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).displayName; + this._model.azureSubscription = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name; + this._model.azureSubscriptionDisplayName = (this._azureSubscriptionsDropdown.value as azdata.CategoryValue).displayName; - this.wizard.model.securityToken = await azdata.accounts.getAccountSecurityToken( - this.wizard.model.azureAccount, + this._model.securityToken = await azdata.accounts.getAccountSecurityToken( + this._model.azureAccount, this._subscriptionsMap.get((this._azureSubscriptionsDropdown.value as azdata.CategoryValue).name)?.tenant!, azdata.AzureResource.ResourceManagement ); @@ -229,7 +229,7 @@ export class AzureSettingsPage extends WizardPageBase { required: true }).component(); this._resourceGroupDropdown.onValueChanged(async (value) => { - this.wizard.model.azureResouceGroup = value.selected; + this._model.azureResouceGroup = value.selected; }); } @@ -246,7 +246,7 @@ export class AzureSettingsPage extends WizardPageBase { return; } let currentSubscription = this._subscriptionsMap.get(currentSubscriptionValue.name); - let resourceGroups = (await subService.getResourceGroups(this.wizard.model.azureAccount, currentSubscription, true)).resourceGroups; + let resourceGroups = (await subService.getResourceGroups(this._model.azureAccount, currentSubscription, true)).resourceGroups; if (resourceGroups === undefined || resourceGroups.length === 0) { this._resourceGroupDropdown.loading = false; this._resourceGroupDropdown.updateProperties({ @@ -264,7 +264,7 @@ export class AzureSettingsPage extends WizardPageBase { }; }) }); - this.wizard.model.azureResouceGroup = (this._resourceGroupDropdown.value as azdata.CategoryValue).name; + this._model.azureResouceGroup = (this._resourceGroupDropdown.value as azdata.CategoryValue).name; this._resourceGroupDropdown.loading = false; } @@ -274,7 +274,7 @@ export class AzureSettingsPage extends WizardPageBase { }).component(); this._azureRegionsDropdown.onValueChanged((value) => { - this.wizard.model.azureRegion = (this._azureRegionsDropdown.value as azdata.CategoryValue).name; + this._model.azureRegion = (this._azureRegionsDropdown.value as azdata.CategoryValue).name; }); } @@ -283,10 +283,10 @@ export class AzureSettingsPage extends WizardPageBase { 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, false); + let url = `https://management.azure.com/subscriptions/${this._model.azureSubscription}/locations?api-version=2020-01-01`; + const response = await this._model.getRequest(url, false); response.data.value = response.data.value.sort((a: any, b: any) => (a.displayName > b.displayName) ? 1 : -1); - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._azureRegionsDropdown, response.data.value.filter((value: any) => { return supportedRegionsArray.includes(value.name); @@ -297,7 +297,7 @@ export class AzureSettingsPage extends WizardPageBase { }; }) ); - this.wizard.model.azureRegion = (this._azureRegionsDropdown.value as azdata.CategoryValue).name; + this._model.azureRegion = (this._azureRegionsDropdown.value as azdata.CategoryValue).name; this._azureRegionsDropdown.loading = false; } } diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/basePage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/basePage.ts index 05ea9fb22c..ead357e31f 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/basePage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/basePage.ts @@ -3,10 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { WizardPageBase } from '../../wizardPageBase'; -import { DeployAzureSQLVMWizard } from '../deployAzureSQLVMWizard'; +import { ResourceTypePage } from '../../resourceTypePage'; -export abstract class BasePage extends WizardPageBase { +export abstract class BasePage extends ResourceTypePage { protected liveValidation!: boolean; diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/networkSettingsPage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/networkSettingsPage.ts index 41025292f3..fd20272a4c 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/networkSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/networkSettingsPage.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; -import { DeployAzureSQLVMWizard } from '../deployAzureSQLVMWizard'; import * as constants from '../constants'; import { BasePage } from './basePage'; import * as nls from 'vscode-nls'; +import { DeployAzureSQLVMWizardModel } from '../deployAzureSQLVMWizardModel'; const localize = nls.loadMessageBundle(); @@ -37,11 +37,11 @@ export class NetworkSettingsPage extends BasePage { private _form!: azdata.FormContainer; - constructor(wizard: DeployAzureSQLVMWizard) { + constructor(private _model: DeployAzureSQLVMWizardModel) { super( constants.NetworkSettingsPageTitle, constants.NetworkSettingsPageDescription, - wizard + _model.wizard ); } @@ -61,13 +61,13 @@ export class NetworkSettingsPage extends BasePage { .withFormItems( [ { - component: this.wizard.createFormRowComponent(view, constants.VirtualNetworkDropdownLabel, '', this._virtualNetworkFlexContainer, true) + component: this._model.createFormRowComponent(view, constants.VirtualNetworkDropdownLabel, '', this._virtualNetworkFlexContainer, true) }, { - component: this.wizard.createFormRowComponent(view, constants.SubnetDropdownLabel, '', this._subnetFlexContainer, true) + component: this._model.createFormRowComponent(view, constants.SubnetDropdownLabel, '', this._subnetFlexContainer, true) }, { - component: this.wizard.createFormRowComponent(view, constants.PublicIPDropdownLabel, '', this._publicIpFlexContainer, true) + component: this._model.createFormRowComponent(view, constants.PublicIPDropdownLabel, '', this._publicIpFlexContainer, true) }, { component: this._vmRDPAllowCheckbox @@ -88,7 +88,7 @@ export class NetworkSettingsPage extends BasePage { this.populateVirtualNetworkDropdown(); this.populatePublicIpkDropdown(); this.liveValidation = false; - this.wizard.wizardObject.registerNavigationValidator(async (pcInfo) => { + this._model.wizard.wizardObject.registerNavigationValidator(async (pcInfo) => { if (pcInfo.newPage < pcInfo.lastPage) { return true; } @@ -103,7 +103,7 @@ export class NetworkSettingsPage extends BasePage { } public async onLeave(): Promise { - this.wizard.wizardObject.registerNavigationValidator((pcInfo) => { + this._model.wizard.wizardObject.registerNavigationValidator((pcInfo) => { return true; }); } @@ -125,7 +125,7 @@ export class NetworkSettingsPage extends BasePage { }).component(); this._virtualNetworkDropdown.onValueChanged((value) => { - this.wizard.model.virtualNetworkName = (this._virtualNetworkDropdown.value as azdata.CategoryValue).name; + this._model.virtualNetworkName = (this._virtualNetworkDropdown.value as azdata.CategoryValue).name; this.populateSubnetDropdown(); }); @@ -136,7 +136,7 @@ export class NetworkSettingsPage extends BasePage { }).component(); this._newVirtualNetworkText.onTextChanged((e) => { - this.wizard.model.virtualNetworkName = e; + this._model.virtualNetworkName = e; this.activateRealTimeFormValidation(); }); @@ -182,28 +182,28 @@ export class NetworkSettingsPage extends BasePage { let newVirtualNetwork = this._newVirtualNetworkCheckbox.checked; - this.wizard.model.newVirtualNetwork = newVirtualNetwork ? 'True' : 'False'; + this._model.newVirtualNetwork = newVirtualNetwork ? 'True' : 'False'; if (newVirtualNetwork) { - this.wizard.changeComponentDisplay(this._virtualNetworkDropdown, 'none'); - this.wizard.changeComponentDisplay(this._newVirtualNetworkText, 'block'); + this._model.changeComponentDisplay(this._virtualNetworkDropdown, 'none'); + this._model.changeComponentDisplay(this._newVirtualNetworkText, 'block'); this._newSubnetCheckbox.enabled = false; - this.wizard.changeComponentDisplay(this._subnetDropdown, 'none'); - this.wizard.changeComponentDisplay(this._newsubnetText, 'block'); - this.wizard.model.virtualNetworkName = this._newVirtualNetworkText.value!; - this.wizard.model.newSubnet = 'True'; - this.wizard.model.subnetName = this._newsubnetText.value!; + this._model.changeComponentDisplay(this._subnetDropdown, 'none'); + this._model.changeComponentDisplay(this._newsubnetText, 'block'); + this._model.virtualNetworkName = this._newVirtualNetworkText.value!; + this._model.newSubnet = 'True'; + this._model.subnetName = this._newsubnetText.value!; } else { - this.wizard.changeComponentDisplay(this._virtualNetworkDropdown, 'block'); - this.wizard.changeComponentDisplay(this._newVirtualNetworkText, 'none'); + this._model.changeComponentDisplay(this._virtualNetworkDropdown, 'block'); + this._model.changeComponentDisplay(this._newVirtualNetworkText, 'none'); this._newSubnetCheckbox.enabled = true; - this.wizard.changeComponentDisplay(this._subnetDropdown, 'block'); - this.wizard.changeComponentDisplay(this._newsubnetText, 'none'); - this.wizard.model.virtualNetworkName = (this._virtualNetworkDropdown.value as azdata.CategoryValue).name; - this.wizard.model.newSubnet = this._newSubnetCheckbox.checked! ? 'True' : 'False'; + this._model.changeComponentDisplay(this._subnetDropdown, 'block'); + this._model.changeComponentDisplay(this._newsubnetText, 'none'); + this._model.virtualNetworkName = (this._virtualNetworkDropdown.value as azdata.CategoryValue).name; + this._model.newSubnet = this._newSubnetCheckbox.checked! ? 'True' : 'False'; } } @@ -225,7 +225,7 @@ export class NetworkSettingsPage extends BasePage { }).component(); this._subnetDropdown.onValueChanged((value) => { - this.wizard.model.subnetName = (this._subnetDropdown.value as azdata.CategoryValue).name; + this._model.subnetName = (this._subnetDropdown.value as azdata.CategoryValue).name; }); this._newsubnetText = view.modelBuilder.inputBox().withProperties({ @@ -235,7 +235,7 @@ export class NetworkSettingsPage extends BasePage { }).component(); this._newsubnetText.onTextChanged((e) => { - this.wizard.model.subnetName = e; + this._model.subnetName = e; this.activateRealTimeFormValidation(); }); @@ -278,16 +278,16 @@ export class NetworkSettingsPage extends BasePage { let newSubnet = this._newSubnetCheckbox.checked!; - this.wizard.model.newSubnet = newSubnet ? 'True' : 'False'; + this._model.newSubnet = newSubnet ? 'True' : 'False'; if (newSubnet) { - this.wizard.changeComponentDisplay(this._subnetDropdown, 'none'); - this.wizard.changeComponentDisplay(this._newsubnetText, 'block'); - this.wizard.model.subnetName = this._newsubnetText.value!; + this._model.changeComponentDisplay(this._subnetDropdown, 'none'); + this._model.changeComponentDisplay(this._newsubnetText, 'block'); + this._model.subnetName = this._newsubnetText.value!; } else { - this.wizard.changeComponentDisplay(this._subnetDropdown, 'block'); - this.wizard.changeComponentDisplay(this._newsubnetText, 'none'); - this.wizard.model.subnetName = (this._subnetDropdown.value as azdata.CategoryValue).name; + this._model.changeComponentDisplay(this._subnetDropdown, 'block'); + this._model.changeComponentDisplay(this._newsubnetText, 'none'); + this._model.subnetName = (this._subnetDropdown.value as azdata.CategoryValue).name; } } @@ -308,7 +308,7 @@ export class NetworkSettingsPage extends BasePage { }).component(); this._publicIpDropdown.onValueChanged((value) => { - this.wizard.model.publicIpName = (this._publicIpDropdown.value as azdata.CategoryValue).name; + this._model.publicIpName = (this._publicIpDropdown.value as azdata.CategoryValue).name; }); this._publicIpNetworkText = view.modelBuilder.inputBox().withProperties({ @@ -317,11 +317,11 @@ export class NetworkSettingsPage extends BasePage { }).component(); this._publicIpNetworkText.onTextChanged((e) => { - this.wizard.model.publicIpName = e; + this._model.publicIpName = e; this.activateRealTimeFormValidation(); }); - this.wizard.changeComponentDisplay(this._publicIpNetworkText, 'none'); + this._model.changeComponentDisplay(this._publicIpNetworkText, 'none'); this._publicIpFlexContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', @@ -362,16 +362,16 @@ export class NetworkSettingsPage extends BasePage { private toggleNewPublicIp() { let newPip = this._newPublicIpCheckbox.checked!; - this.wizard.model.newPublicIp = newPip ? 'True' : 'False'; + this._model.newPublicIp = newPip ? 'True' : 'False'; if (newPip) { - this.wizard.changeComponentDisplay(this._publicIpDropdown, 'none'); - this.wizard.changeComponentDisplay(this._publicIpNetworkText, 'block'); - this.wizard.model.publicIpName = this._publicIpNetworkText.value!; + this._model.changeComponentDisplay(this._publicIpDropdown, 'none'); + this._model.changeComponentDisplay(this._publicIpNetworkText, 'block'); + this._model.publicIpName = this._publicIpNetworkText.value!; } else { - this.wizard.changeComponentDisplay(this._publicIpDropdown, 'block'); - this.wizard.changeComponentDisplay(this._publicIpNetworkText, 'none'); - this.wizard.model.publicIpName = (this._publicIpDropdown.value as azdata.CategoryValue).name; + this._model.changeComponentDisplay(this._publicIpDropdown, 'block'); + this._model.changeComponentDisplay(this._publicIpNetworkText, 'none'); + this._model.publicIpName = (this._publicIpDropdown.value as azdata.CategoryValue).name; } } @@ -380,21 +380,21 @@ export class NetworkSettingsPage extends BasePage { label: constants.RDPAllowCheckboxLabel, }).component(); this._vmRDPAllowCheckbox.onChanged((value) => { - this.wizard.model.allowRDP = (value) ? 'True' : 'False'; + this._model.allowRDP = (value) ? 'True' : 'False'; }); - this.wizard.model.allowRDP = 'False'; + this._model.allowRDP = 'False'; } public async getVirtualNetworks(): Promise { let url = `https://management.azure.com` + - `/subscriptions/${this.wizard.model.azureSubscription}` + + `/subscriptions/${this._model.azureSubscription}` + `/providers/Microsoft.Network/virtualNetworks?api-version=2020-05-01`; - let response = await this.wizard.getRequest(url); + let response = await this._model.getRequest(url); let dropdownValues = response.data.value.filter((value: any) => { - return value.location === this.wizard.model.azureRegion; + return value.location === this._model.azureRegion; }).map((value: any) => { let resourceGroupName = value.id.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), ''); return { @@ -406,13 +406,13 @@ export class NetworkSettingsPage extends BasePage { } public async getSubnets(): Promise { - if (!this.wizard.model.virtualNetworkName) { + if (!this._model.virtualNetworkName) { return; } let url = `https://management.azure.com` + - `${this.wizard.model.virtualNetworkName}` + + `${this._model.virtualNetworkName}` + `/subnets?api-version=2020-05-01`; - let response = await this.wizard.getRequest(url); + let response = await this._model.getRequest(url); let dropdownValues = response.data.value.map((value: any) => { return { name: value.id, @@ -424,11 +424,11 @@ export class NetworkSettingsPage extends BasePage { public async getPips(): Promise { let url = `https://management.azure.com` + - `/subscriptions/${this.wizard.model.azureSubscription}` + + `/subscriptions/${this._model.azureSubscription}` + `/providers/Microsoft.Network/publicIPAddresses?api-version=2020-05-01`; - let response = await this.wizard.getRequest(url); + let response = await this._model.getRequest(url); let dropdownValues = response.data.value.filter((value: any) => { - return value.location === this.wizard.model.azureRegion; + return value.location === this._model.azureRegion; }).map((value: any) => { let resourceGroupName = value.id.replace(RegExp('^(.*?)/resourceGroups/'), '').replace(RegExp('/providers/.*'), ''); return { @@ -441,37 +441,37 @@ export class NetworkSettingsPage extends BasePage { protected async validatePage(): Promise { const errorMessages = []; - if (this.wizard.model.newVirtualNetwork === 'True') { - if (this.wizard.model.virtualNetworkName.length < 2 || this.wizard.model.virtualNetworkName.length > 64) { + if (this._model.newVirtualNetwork === 'True') { + if (this._model.virtualNetworkName.length < 2 || this._model.virtualNetworkName.length > 64) { errorMessages.push(localize('deployAzureSQLVM.VnetNameLengthError', "Virtual Network name must be between 2 and 64 characters long")); } } else { - if (this.wizard.model.virtualNetworkName === 'None') { + if (this._model.virtualNetworkName === 'None') { errorMessages.push(localize('deployAzureSQLVM.NewVnetError', "Create a new virtual network")); } } - if (this.wizard.model.newSubnet === 'True') { - if (this.wizard.model.subnetName.length < 1 || this.wizard.model.subnetName.length > 80) { + if (this._model.newSubnet === 'True') { + if (this._model.subnetName.length < 1 || this._model.subnetName.length > 80) { errorMessages.push(localize('deployAzureSQLVM.SubnetNameLengthError', "Subnet name must be between 1 and 80 characters long")); } } else { - if (this.wizard.model.subnetName === 'None') { + if (this._model.subnetName === 'None') { errorMessages.push(localize('deployAzureSQLVM.NewSubnetError', "Create a new sub network")); } } - if (this.wizard.model.newPublicIp === 'True') { - if (this.wizard.model.publicIpName.length < 1 || this.wizard.model.publicIpName.length > 80) { + if (this._model.newPublicIp === 'True') { + if (this._model.publicIpName.length < 1 || this._model.publicIpName.length > 80) { errorMessages.push(localize('deployAzureSQLVM.PipNameError', "Public IP name must be between 1 and 80 characters long")); } } else { - if (this.wizard.model.publicIpName === 'None') { + if (this._model.publicIpName === 'None') { errorMessages.push(localize('deployAzureSQLVM.NewPipError', "Create a new new public Ip")); } } - this.wizard.showErrorMessage(errorMessages.join('\n')); + this._model.wizard.showErrorMessage(errorMessages.join('\n')); return errorMessages.join('\n'); } diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/sqlServerSettingsPage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/sqlServerSettingsPage.ts index a0d1d30e35..d6036185f3 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/sqlServerSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/sqlServerSettingsPage.ts @@ -6,9 +6,9 @@ import * as azdata from 'azdata'; import { EOL } from 'os'; import * as constants from '../constants'; -import { DeployAzureSQLVMWizard } from '../deployAzureSQLVMWizard'; import { BasePage } from './basePage'; import * as nls from 'vscode-nls'; +import { DeployAzureSQLVMWizardModel } from '../deployAzureSQLVMWizardModel'; import * as localizedConstants from '../../../localizedConstants'; const localize = nls.loadMessageBundle(); @@ -29,11 +29,11 @@ export class SqlServerSettingsPage extends BasePage { private _form!: azdata.FormContainer; - constructor(wizard: DeployAzureSQLVMWizard) { + constructor(private _model: DeployAzureSQLVMWizardModel) { super( constants.SqlServerSettingsPageTitle, '', - wizard + _model.wizard ); } @@ -51,13 +51,13 @@ export class SqlServerSettingsPage extends BasePage { .withFormItems( [ { - component: this.wizard.createFormRowComponent(view, constants.SqlConnectivityTypeDropdownLabel, '', this._sqlConnectivityDropdown, true) + component: this._model.createFormRowComponent(view, constants.SqlConnectivityTypeDropdownLabel, '', this._sqlConnectivityDropdown, true) }, { component: this._portTextRow }, { - component: this.wizard.createFormRowComponent(view, constants.SqlEnableSQLAuthenticationLabel, '', this._sqlAuthenticationDropdown, true) + component: this._model.createFormRowComponent(view, constants.SqlEnableSQLAuthenticationLabel, '', this._sqlAuthenticationDropdown, true) }, { component: this._sqlAuthenticationTextRow @@ -84,7 +84,7 @@ export class SqlServerSettingsPage extends BasePage { this.liveValidation = false; - this.wizard.wizardObject.registerNavigationValidator(async (pcInfo) => { + this._model.wizard.wizardObject.registerNavigationValidator(async (pcInfo) => { if (pcInfo.newPage < pcInfo.lastPage) { return true; } @@ -101,7 +101,7 @@ export class SqlServerSettingsPage extends BasePage { } public async onLeave(): Promise { - this.wizard.wizardObject.registerNavigationValidator((pcInfo) => { + this._model.wizard.wizardObject.registerNavigationValidator((pcInfo) => { return true; }); } @@ -131,17 +131,17 @@ export class SqlServerSettingsPage extends BasePage { } }).component(); - this.wizard.model.sqlConnectivityType = (this._sqlConnectivityDropdown.value as azdata.CategoryValue).name; + this._model.sqlConnectivityType = (this._sqlConnectivityDropdown.value as azdata.CategoryValue).name; this._sqlConnectivityDropdown.onValueChanged((value) => { let connectivityValue = (this._sqlConnectivityDropdown.value as azdata.CategoryValue).name; - this.wizard.model.sqlConnectivityType = connectivityValue; + this._model.sqlConnectivityType = connectivityValue; if (connectivityValue === 'local') { - this.wizard.changeRowDisplay(this._portTextRow, 'none'); + this._model.changeRowDisplay(this._portTextRow, 'none'); } else { - this.wizard.changeRowDisplay(this._portTextRow, 'block'); + this._model.changeRowDisplay(this._portTextRow, 'block'); } }); @@ -156,11 +156,11 @@ export class SqlServerSettingsPage extends BasePage { }).component(); this._portTextBox.onTextChanged((value) => { - this.wizard.model.port = value; + this._model.port = value; this.activateRealTimeFormValidation(); }); - this._portTextRow = this.wizard.createFormRowComponent(view, constants.SqlPortLabel, '', this._portTextBox, true); + this._portTextRow = this._model.createFormRowComponent(view, constants.SqlPortLabel, '', this._portTextBox, true); } private createSqlAuthentication(view: azdata.ModelView) { @@ -181,39 +181,39 @@ export class SqlServerSettingsPage extends BasePage { this._sqlAuthenticationDropdown.onValueChanged((value) => { let dropdownValue = (this._sqlAuthenticationDropdown.value as azdata.CategoryValue).name; let displayValue: 'block' | 'none' = dropdownValue === 'True' ? 'block' : 'none'; - this.wizard.changeRowDisplay(this._sqlAuthenticationTextRow, displayValue); - this.wizard.changeRowDisplay(this._sqlAuthenticationPasswordTextRow, displayValue); - this.wizard.changeRowDisplay(this._sqlAuthenticationPasswordConfirmationTextRow, displayValue); - this.wizard.model.enableSqlAuthentication = dropdownValue; + this._model.changeRowDisplay(this._sqlAuthenticationTextRow, displayValue); + this._model.changeRowDisplay(this._sqlAuthenticationPasswordTextRow, displayValue); + this._model.changeRowDisplay(this._sqlAuthenticationPasswordConfirmationTextRow, displayValue); + this._model.enableSqlAuthentication = dropdownValue; }); - this.wizard.model.enableSqlAuthentication = (this._sqlAuthenticationDropdown.value as azdata.CategoryValue).name; + this._model.enableSqlAuthentication = (this._sqlAuthenticationDropdown.value as azdata.CategoryValue).name; this._sqlAuthenticationTextbox = view.modelBuilder.inputBox().component(); - this._sqlAuthenticationTextRow = this.wizard.createFormRowComponent(view, constants.SqlAuthenticationUsernameLabel, '', this._sqlAuthenticationTextbox, true); + this._sqlAuthenticationTextRow = this._model.createFormRowComponent(view, constants.SqlAuthenticationUsernameLabel, '', this._sqlAuthenticationTextbox, true); this._sqlAuthenticationPasswordTextbox = view.modelBuilder.inputBox().withProperties({ inputType: 'password' }).component(); - this._sqlAuthenticationPasswordTextRow = this.wizard.createFormRowComponent(view, constants.SqlAuthenticationPasswordLabel, '', this._sqlAuthenticationPasswordTextbox, true); + this._sqlAuthenticationPasswordTextRow = this._model.createFormRowComponent(view, constants.SqlAuthenticationPasswordLabel, '', this._sqlAuthenticationPasswordTextbox, true); this._sqlAuthenticationPasswordConfirmationTextbox = view.modelBuilder.inputBox().withProperties({ inputType: 'password' }).component(); - this._sqlAuthenticationPasswordConfirmationTextRow = this.wizard.createFormRowComponent(view, constants.SqlAuthenticationConfirmPasswordLabel, '', this._sqlAuthenticationPasswordConfirmationTextbox, true); + this._sqlAuthenticationPasswordConfirmationTextRow = this._model.createFormRowComponent(view, constants.SqlAuthenticationConfirmPasswordLabel, '', this._sqlAuthenticationPasswordConfirmationTextbox, true); this._sqlAuthenticationTextbox.onTextChanged((value) => { - this.wizard.model.sqlAuthenticationUsername = value; + this._model.sqlAuthenticationUsername = value; this.activateRealTimeFormValidation(); }); this._sqlAuthenticationPasswordTextbox.onTextChanged((value) => { - this.wizard.model.sqlAuthenticationPassword = value; + this._model.sqlAuthenticationPassword = value; this.activateRealTimeFormValidation(); }); @@ -235,7 +235,7 @@ export class SqlServerSettingsPage extends BasePage { errorMessages.push(localize('deployAzureSQLVM.SqlUsernameSpecialCharError', "Username cannot contain special characters \/\"\"[]:|<>+=;,?* .")); } - errorMessages.push(this.wizard.validatePassword(this._sqlAuthenticationPasswordTextbox.value!)); + errorMessages.push(this._model.validatePassword(this._sqlAuthenticationPasswordTextbox.value!)); if (this._sqlAuthenticationPasswordTextbox.value !== this._sqlAuthenticationPasswordConfirmationTextbox.value) { errorMessages.push(localize('deployAzureSQLVM.SqlConfirmPasswordError', "Password and confirm password must match.")); @@ -243,7 +243,7 @@ export class SqlServerSettingsPage extends BasePage { } - this.wizard.showErrorMessage(errorMessages.join(EOL)); + this._model.wizard.showErrorMessage(errorMessages.join(EOL)); return errorMessages.join(EOL); } diff --git a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/summaryPage.ts b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/summaryPage.ts index 8a71549101..fc0c1312d7 100644 --- a/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/summaryPage.ts +++ b/extensions/resource-deployment/src/ui/deployAzureSQLVMWizard/pages/summaryPage.ts @@ -4,23 +4,23 @@ *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; -import { WizardPageBase } from '../../wizardPageBase'; -import { DeployAzureSQLVMWizard } from '../deployAzureSQLVMWizard'; import * as constants from '../constants'; import { SectionInfo, LabelPosition, FontWeight, FieldType } from '../../../interfaces'; import { createSection } from '../../modelViewUtils'; +import { BasePage } from './basePage'; +import { DeployAzureSQLVMWizardModel } from '../deployAzureSQLVMWizardModel'; -export class AzureSQLVMSummaryPage extends WizardPageBase { +export class AzureSQLVMSummaryPage extends BasePage { private formItems: azdata.FormComponent[] = []; private _form!: azdata.FormBuilder; private _view!: azdata.ModelView; - constructor(wizard: DeployAzureSQLVMWizard) { + constructor(private _model: DeployAzureSQLVMWizardModel) { super( 'Summary', '', - wizard + _model.wizard ); } @@ -41,8 +41,6 @@ export class AzureSQLVMSummaryPage extends WizardPageBase { - this.wizard.model.vmName = value; + this._model.vmName = value; this.activateRealTimeFormValidation(); }); } @@ -154,7 +154,7 @@ export class VmSettingsPage extends BasePage { }).component(); this._adminUsernameTextBox.onTextChanged((value) => { - this.wizard.model.vmUsername = value; + this._model.vmUsername = value; this.activateRealTimeFormValidation(); }); } @@ -165,7 +165,7 @@ export class VmSettingsPage extends BasePage { }).component(); this._adminPasswordTextBox.onTextChanged((value) => { - this.wizard.model.vmPassword = value; + this._model.vmPassword = value; this.activateRealTimeFormValidation(); }); } @@ -185,7 +185,7 @@ export class VmSettingsPage extends BasePage { }).component(); this._vmImageDropdown.onValueChanged((value) => { - this.wizard.model.vmImage = (this._vmImageDropdown.value as azdata.CategoryValue).name; + this._model.vmImage = (this._vmImageDropdown.value as azdata.CategoryValue).name; this._vmImageSkuDropdown.loading = true; this._vmImageVersionDropdown.loading = true; this.populateVmImageSkuDropdown(); @@ -199,16 +199,16 @@ export class VmSettingsPage extends BasePage { this._vmImageVersionDropdown.loading = true; let url = `https://management.azure.com` + - `/subscriptions/${this.wizard.model.azureSubscription}` + + `/subscriptions/${this._model.azureSubscription}` + `/providers/Microsoft.Compute` + - `/locations/${this.wizard.model.azureRegion}` + + `/locations/${this._model.azureRegion}` + `/publishers/MicrosoftSQLServer` + `/artifacttypes/vmimage/offers` + `?api-version=2019-12-01`; - let response = await this.wizard.getRequest(url, true); + let response = await this._model.getRequest(url, true); response.data = response.data.reverse(); - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._vmImageDropdown, response.data.filter((value: any) => { return !new RegExp('-byol').test(value.name.toLowerCase()); @@ -227,7 +227,7 @@ export class VmSettingsPage extends BasePage { }) ); - this.wizard.model.vmImage = (this._vmImageDropdown.value as azdata.CategoryValue).name; + this._model.vmImage = (this._vmImageDropdown.value as azdata.CategoryValue).name; this._vmImageDropdown.loading = false; this.populateVmImageSkuDropdown(); } @@ -237,7 +237,7 @@ export class VmSettingsPage extends BasePage { }).component(); this._vmImageSkuDropdown.onValueChanged((value) => { - this.wizard.model.vmImageSKU = (this._vmImageSkuDropdown.value as azdata.CategoryValue).name; + this._model.vmImageSKU = (this._vmImageSkuDropdown.value as azdata.CategoryValue).name; this.populateVmImageVersionDropdown(); }); @@ -246,16 +246,16 @@ export class VmSettingsPage extends BasePage { private async populateVmImageSkuDropdown() { this._vmImageSkuDropdown.loading = true; let url = `https://management.azure.com` + - `/subscriptions/${this.wizard.model.azureSubscription}` + + `/subscriptions/${this._model.azureSubscription}` + `/providers/Microsoft.Compute` + - `/locations/${this.wizard.model.azureRegion}` + + `/locations/${this._model.azureRegion}` + `/publishers/MicrosoftSQLServer` + - `/artifacttypes/vmimage/offers/${this.wizard.model.vmImage}` + + `/artifacttypes/vmimage/offers/${this._model.vmImage}` + `/skus?api-version=2019-12-01`; - let response = await this.wizard.getRequest(url, true); + let response = await this._model.getRequest(url, true); - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._vmImageSkuDropdown, response.data.map((value: any) => { return { @@ -265,7 +265,7 @@ export class VmSettingsPage extends BasePage { }) ); - this.wizard.model.vmImageSKU = (this._vmImageSkuDropdown.value as azdata.CategoryValue).name; + this._model.vmImageSKU = (this._vmImageSkuDropdown.value as azdata.CategoryValue).name; this._vmImageSkuDropdown.loading = false; this.populateVmImageVersionDropdown(); } @@ -275,24 +275,24 @@ export class VmSettingsPage extends BasePage { }).component(); this._vmImageVersionDropdown.onValueChanged((value) => { - this.wizard.model.vmImageVersion = (this._vmImageVersionDropdown.value as azdata.CategoryValue).name; + this._model.vmImageVersion = (this._vmImageVersionDropdown.value as azdata.CategoryValue).name; }); } private async populateVmImageVersionDropdown() { this._vmImageVersionDropdown.loading = true; let url = `https://management.azure.com` + - `/subscriptions/${this.wizard.model.azureSubscription}` + + `/subscriptions/${this._model.azureSubscription}` + `/providers/Microsoft.Compute` + - `/locations/${this.wizard.model.azureRegion}` + + `/locations/${this._model.azureRegion}` + `/publishers/MicrosoftSQLServer` + - `/artifacttypes/vmimage/offers/${this.wizard.model.vmImage}` + - `/skus/${this.wizard.model.vmImageSKU}` + + `/artifacttypes/vmimage/offers/${this._model.vmImage}` + + `/skus/${this._model.vmImageSKU}` + `/versions?api-version=2019-12-01`; - let response = await this.wizard.getRequest(url, true); + let response = await this._model.getRequest(url, true); - this.wizard.addDropdownValues( + this._model.addDropdownValues( this._vmImageVersionDropdown, response.data.map((value: any) => { return { @@ -302,7 +302,7 @@ export class VmSettingsPage extends BasePage { }) ); - this.wizard.model.vmImageVersion = (this._vmImageVersionDropdown.value as azdata.CategoryValue).name; + this._model.vmImageVersion = (this._vmImageVersionDropdown.value as azdata.CategoryValue).name; this._vmImageVersionDropdown.loading = false; } @@ -313,7 +313,7 @@ export class VmSettingsPage extends BasePage { }).component(); this._vmSizeDropdown.onValueChanged((value) => { - this.wizard.model.vmSize = (this._vmSizeDropdown.value as azdata.CategoryValue).name; + this._model.vmSize = (this._vmSizeDropdown.value as azdata.CategoryValue).name; }); this._vmSizeLearnMoreLink = view.modelBuilder.hyperlink().withProperties({ @@ -326,12 +326,12 @@ export class VmSettingsPage extends BasePage { private async populateVmSizeDropdown() { this._vmSizeDropdown.loading = true; let url = `https://management.azure.com` + - `/subscriptions/${this.wizard.model.azureSubscription}` + + `/subscriptions/${this._model.azureSubscription}` + `/providers/Microsoft.Compute` + `/skus?api-version=2019-04-01` + - `&$filter=location eq '${this.wizard.model.azureRegion}'`; + `&$filter=location eq '${this._model.azureRegion}'`; - let response = await this.wizard.getRequest(url, true); + let response = await this._model.getRequest(url, true); let vmResouces: any[] = []; response.data.value.map((res: any) => { @@ -375,7 +375,7 @@ export class VmSettingsPage extends BasePage { value: dropDownValues[0], width: '480px' }); - this.wizard.model.vmSize = (this._vmSizeDropdown.value as azdata.CategoryValue).name; + this._model.vmSize = (this._vmSizeDropdown.value as azdata.CategoryValue).name; this._vmSizeDropdown.loading = false; } @@ -389,7 +389,7 @@ export class VmSettingsPage extends BasePage { * 3. Cannot start with underscore and end with period or hyphen * 4. Virtual machine name cannot contain special characters \/""[]:|<>+=;,?* */ - let vmname = this.wizard.model.vmName; + let vmname = this._model.vmName; if (vmname.length < 1 && vmname.length > 15) { errorMessages.push(localize('deployAzureSQLVM.VnameLengthError', "Virtual machine name must be between 1 and 15 characters long.")); } @@ -418,7 +418,7 @@ export class VmSettingsPage extends BasePage { 'aspnet', 'backup', 'console', 'david', 'guest', 'john', 'owner', 'root', 'server', 'sql', 'support', 'support_388945a0', 'sys', 'test2', 'test3', 'user4', 'user5' ]; - let username = this.wizard.model.vmUsername; + let username = this._model.vmUsername; if (username.length < 1 || username.length > 20) { errorMessages.push(localize('deployAzureSQLVM.VMUsernameLengthError', "Username must be between 1 and 20 characters long.")); } @@ -433,9 +433,9 @@ export class VmSettingsPage extends BasePage { errorMessages.push(localize('deployAzureSQLVM.VMUsernameReservedWordsError', "Username must not include reserved words.")); } - errorMessages.push(this.wizard.validatePassword(this.wizard.model.vmPassword)); + errorMessages.push(this._model.validatePassword(this._model.vmPassword)); - if (this.wizard.model.vmPassword !== this._adminComfirmPasswordTextBox.value) { + if (this._model.vmPassword !== this._adminComfirmPasswordTextBox.value) { errorMessages.push(localize('deployAzureSQLVM.VMConfirmPasswordError', "Password and confirm password must match.")); } @@ -443,19 +443,19 @@ export class VmSettingsPage extends BasePage { errorMessages.push(localize('deployAzureSQLVM.vmDropdownSizeError', "Select a valid virtual machine size.")); } - this.wizard.showErrorMessage(errorMessages.join(EOL)); + this._model.wizard.showErrorMessage(errorMessages.join(EOL)); return errorMessages.join(EOL); } protected async vmNameExists(vmName: string): Promise { const url = `https://management.azure.com` + - `/subscriptions/${this.wizard.model.azureSubscription}` + - `/resourceGroups/${this.wizard.model.azureResouceGroup}` + + `/subscriptions/${this._model.azureSubscription}` + + `/resourceGroups/${this._model.azureResouceGroup}` + `/providers/Microsoft.Compute` + `/virtualMachines?api-version=2019-12-01`; - let response = await this.wizard.getRequest(url, true); + let response = await this._model.getRequest(url, true); let nameArray = response.data.value.map((v: any) => { return v.name; }); return (nameArray.includes(vmName)); diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizardModel.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizardModel.ts index 7ea4bd62ff..49d6d6dbaf 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizardModel.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizardModel.ts @@ -13,7 +13,7 @@ import { KubeCtlToolName } from '../../services/tools/kubeCtlTool'; import { getErrorMessage, getRuntimeBinaryPathEnvironmentVariableName, setEnvironmentVariablesForInstallPaths } from '../../common/utils'; import { ToolsInstallPath } from '../../constants'; import * as VariableNames from './constants'; -import { ResourceTypeModel, ResourceTypePage, ResourceTypeWizard } from '../resourceTypeWizard'; +import { ResourceTypeWizard } from '../resourceTypeWizard'; import * as nls from 'vscode-nls'; import { InputComponents } from '../modelViewUtils'; import { INotebookService } from '../../services/notebookService'; @@ -26,6 +26,8 @@ import { ServiceSettingsPage } from './pages/serviceSettingsPage'; import { SummaryPage } from './pages/summaryPage'; import { TargetClusterContextPage } from './pages/targetClusterPage'; import { IToolsService } from '../../services/toolsService'; +import { ResourceTypeModel } from '../resourceTypeModel'; +import { ResourceTypePage } from '../resourceTypePage'; const localize = nls.loadMessageBundle(); export class DeployClusterWizardModel extends ResourceTypeModel { diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/azureSettingsPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/azureSettingsPage.ts index cf880ee270..b1947ef7d0 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/azureSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/azureSettingsPage.ts @@ -11,7 +11,7 @@ import { createSection, getDropdownComponent, InputComponentInfo, InputComponent import { AksName_VariableName, Location_VariableName, ResourceGroup_VariableName, SubscriptionId_VariableName, VMCount_VariableName, VMSize_VariableName } from '../constants'; import { AzureRegion } from 'azurecore'; import { DeployClusterWizardModel } from '../deployClusterWizardModel'; -import { ResourceTypePage } from '../../resourceTypeWizard'; +import { ResourceTypePage } from '../../resourceTypePage'; const localize = nls.loadMessageBundle(); const MissingRequiredInformationErrorMessage = localize('deployCluster.MissingRequiredInfoError', "Please fill out the required fields marked with red asterisks."); diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/clusterSettingsPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/clusterSettingsPage.ts index f2fa12fff0..e672800b3d 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/clusterSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/clusterSettingsPage.ts @@ -12,7 +12,7 @@ import { createSection, getInputBoxComponent, getInvalidSQLPasswordMessage, getP import * as VariableNames from '../constants'; import { AuthenticationMode, DeployClusterWizardModel } from '../deployClusterWizardModel'; import * as localizedConstants from '../../../localizedConstants'; -import { ResourceTypePage } from '../../resourceTypeWizard'; +import { ResourceTypePage } from '../../resourceTypePage'; const localize = nls.loadMessageBundle(); const ConfirmPasswordName = 'ConfirmPassword'; @@ -349,7 +349,7 @@ export class ClusterSettingsPage extends ResourceTypePage { }); if (messages.length > 0) { - this.wizard.wizardObject.message = { + this._model.wizard.wizardObject.message = { text: messages.length === 1 ? messages[0] : localize('deployCluster.ValidationError', "There are some errors on this page, click 'Show Details' to view the errors."), description: messages.length === 1 ? undefined : messages.join(EOL), level: azdata.window.MessageLevel.Error diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/deploymentProfilePage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/deploymentProfilePage.ts index 9451addd8f..537c70533f 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/deploymentProfilePage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/deploymentProfilePage.ts @@ -8,7 +8,7 @@ import * as nls from 'vscode-nls'; import { BdcDeploymentType } from '../../../interfaces'; import { BigDataClusterDeploymentProfile } from '../../../services/bigDataClusterDeploymentProfile'; import { createFlexContainer, createLabel } from '../../modelViewUtils'; -import { ResourceTypePage } from '../../resourceTypeWizard'; +import { ResourceTypePage } from '../../resourceTypePage'; import * as VariableNames from '../constants'; import { DeployClusterWizardModel } from '../deployClusterWizardModel'; const localize = nls.loadMessageBundle(); diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts index 65ba361a08..75465d4e95 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { FieldType, SectionInfo } from '../../../interfaces'; import { createFlexContainer, createGroupContainer, createLabel, createNumberInput, createSection, createTextInput, getCheckboxComponent, getDropdownComponent, getInputBoxComponent, InputComponentInfo, InputComponents, setModelValues, Validator } from '../../modelViewUtils'; -import { ResourceTypePage } from '../../resourceTypeWizard'; +import { ResourceTypePage } from '../../resourceTypePage'; import * as VariableNames from '../constants'; import { AuthenticationMode, DeployClusterWizardModel } from '../deployClusterWizardModel'; const localize = nls.loadMessageBundle(); diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/summaryPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/summaryPage.ts index 49c640c9e7..d5edc93728 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/summaryPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/summaryPage.ts @@ -9,7 +9,7 @@ import { createSection, createGroupContainer, createFlexContainer, createLabel } import * as VariableNames from '../constants'; import { AuthenticationMode, DeployClusterWizardModel } from '../deployClusterWizardModel'; import * as localizedConstants from '../../../localizedConstants'; -import { ResourceTypePage } from '../../resourceTypeWizard'; +import { ResourceTypePage } from '../../resourceTypePage'; const localize = nls.loadMessageBundle(); export class SummaryPage extends ResourceTypePage { diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/targetClusterPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/targetClusterPage.ts index 69d0e7a667..1ce8d6904c 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/targetClusterPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/targetClusterPage.ts @@ -8,8 +8,8 @@ import * as os from 'os'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { KubeClusterContext } from '../../../services/kubeService'; +import { ResourceTypePage } from '../../resourceTypePage'; import { ClusterContext_VariableName, KubeConfigPath_VariableName } from '../constants'; -import { ResourceTypePage } from '../../resourceTypeWizard'; import { DeployClusterWizardModel } from '../deployClusterWizardModel'; const localize = nls.loadMessageBundle(); diff --git a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardAutoSummaryPage.ts b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardAutoSummaryPage.ts index 5071399f8a..9f541150c4 100644 --- a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardAutoSummaryPage.ts +++ b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardAutoSummaryPage.ts @@ -7,7 +7,7 @@ import * as nls from 'vscode-nls'; import { SubFieldInfo, FieldType, FontWeight, LabelPosition, SectionInfo } from '../../interfaces'; import { createSection, DefaultInputWidth, DefaultLabelWidth, DefaultFieldAlignItems, DefaultFieldWidth, DefaultFieldHeight } from '../modelViewUtils'; -import { NotebookWizard } from './notebookWizard'; +import { NotebookWizardModel } from './notebookWizardModel'; import { NotebookWizardPage } from './notebookWizardPage'; const localize = nls.loadMessageBundle(); @@ -17,11 +17,11 @@ export class NotebookWizardAutoSummaryPage extends NotebookWizardPage { private form!: azdata.FormBuilder; private view!: azdata.ModelView; - constructor(wizard: NotebookWizard, _pageIndex: number) { - super(wizard, + constructor(_model: NotebookWizardModel, _pageIndex: number) { + super(_model, _pageIndex, - wizard.wizardInfo.pages[_pageIndex].title || localize('notebookWizard.autoSummaryPageTitle', "Review your configuration"), - wizard.wizardInfo.pages[_pageIndex].description || '' + _model.wizardInfo.pages[_pageIndex].title || localize('notebookWizard.autoSummaryPageTitle', "Review your configuration"), + _model.wizardInfo.pages[_pageIndex].description || '' ); } @@ -43,14 +43,14 @@ export class NotebookWizardAutoSummaryPage extends NotebookWizardPage { }); this.formItems = []; - const fieldWidth = this.pageInfo.fieldWidth || this.wizard.wizardInfo.fieldWidth || DefaultFieldWidth; - const fieldHeight = this.pageInfo.fieldHeight || this.wizard.wizardInfo.fieldHeight || DefaultFieldHeight; - const fieldAlignItems = this.pageInfo.fieldAlignItems || this.wizard.wizardInfo.fieldAlignItems || DefaultFieldAlignItems; - const labelWidth = this.pageInfo.labelWidth || this.wizard.wizardInfo.labelWidth || DefaultLabelWidth; - const labelPosition = this.pageInfo.labelPosition || this.wizard.wizardInfo.labelPosition || LabelPosition.Left; - const inputWidth = this.pageInfo.inputWidth || this.wizard.wizardInfo.inputWidth || DefaultInputWidth; + const fieldWidth = this.pageInfo.fieldWidth || this._model.wizardInfo.fieldWidth || DefaultFieldWidth; + const fieldHeight = this.pageInfo.fieldHeight || this._model.wizardInfo.fieldHeight || DefaultFieldHeight; + const fieldAlignItems = this.pageInfo.fieldAlignItems || this._model.wizardInfo.fieldAlignItems || DefaultFieldAlignItems; + const labelWidth = this.pageInfo.labelWidth || this._model.wizardInfo.labelWidth || DefaultLabelWidth; + const labelPosition = this.pageInfo.labelPosition || this._model.wizardInfo.labelPosition || LabelPosition.Left; + const inputWidth = this.pageInfo.inputWidth || this._model.wizardInfo.inputWidth || DefaultInputWidth; - const filteredPages = this.wizard.wizardInfo.pages.filter((undefined, index) => index < this._pageIndex); + const filteredPages = this._model.wizardInfo.pages.filter((undefined, index) => index < this._pageIndex); for (const pageInfo of filteredPages) { const summarySectionInfo: SectionInfo = { labelPosition: labelPosition, @@ -80,7 +80,7 @@ export class NotebookWizardAutoSummaryPage extends NotebookWizardPage { component: await createSection({ container: this.wizard.wizardObject, toolsService: this.wizard.toolsService, - inputComponents: this.wizard.inputComponents, + inputComponents: this._model.inputComponents, sectionInfo: summarySectionInfo, view: this.view, onNewDisposableCreated: () => { }, diff --git a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizard.ts b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardModel.ts similarity index 64% rename from extensions/resource-deployment/src/ui/notebookWizard/notebookWizard.ts rename to extensions/resource-deployment/src/ui/notebookWizard/notebookWizardModel.ts index 193fdda46d..bd833480c3 100644 --- a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizard.ts +++ b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardModel.ts @@ -5,58 +5,63 @@ import * as loc from '../../localizedConstants'; import { INotebookService, Notebook } from '../../services/notebookService'; import { IToolsService } from '../../services/toolsService'; -import { Model } from '../model'; import { InputComponents, setModelValues } from '../modelViewUtils'; -import { WizardBase } from '../wizardBase'; -import { DeploymentType, NotebookWizardInfo } from './../../interfaces'; -import { IPlatformService } from './../../services/platformService'; +import { ResourceTypeModel } from '../resourceTypeModel'; +import { ResourceTypeWizard } from '../resourceTypeWizard'; +import { DeploymentType, NotebookWizardDeploymentProvider, NotebookWizardInfo } from '../../interfaces'; +import { IPlatformService } from '../../services/platformService'; import { NotebookWizardAutoSummaryPage } from './notebookWizardAutoSummaryPage'; import { NotebookWizardPage } from './notebookWizardPage'; -export class NotebookWizard extends WizardBase { +export class NotebookWizardModel extends ResourceTypeModel { private _inputComponents: InputComponents = {}; public get notebookService(): INotebookService { - return this._notebookService; + return this.wizard.notebookService; } public get platformService(): IPlatformService { - return this._platformService; + return this.wizard.platformService; + } + + public get toolsService(): IToolsService { + return this.wizard.toolsService; } public get wizardInfo(): NotebookWizardInfo { - return this._wizardInfo; + return this.notebookProvider.notebookWizard; } public get inputComponents(): InputComponents { return this._inputComponents; } - constructor(private _wizardInfo: NotebookWizardInfo, private _notebookService: INotebookService, private _platformService: IPlatformService, toolsService: IToolsService) { - super(_wizardInfo.title, _wizardInfo.name || '', new Model(), toolsService); - if (this._wizardInfo.codeCellInsertionPosition === undefined) { - this._wizardInfo.codeCellInsertionPosition = 0; + constructor(public notebookProvider: NotebookWizardDeploymentProvider, wizard: ResourceTypeWizard) { + super(notebookProvider, wizard); + if (this.notebookProvider.notebookWizard.codeCellInsertionPosition === undefined) { + this.notebookProvider.notebookWizard.codeCellInsertionPosition = 0; } - this.wizardObject.doneButton.label = _wizardInfo.doneAction?.label || loc.deployNotebook; - this.wizardObject.generateScriptButton.label = _wizardInfo.scriptAction?.label || loc.scriptToNotebook; + this.wizard.wizardObject.title = this.notebookProvider.notebookWizard.title; + this.wizard.wizardObject.doneButton.label = this.notebookProvider.notebookWizard.doneAction?.label || loc.deployNotebook; + this.wizard.wizardObject.generateScriptButton.label = this.notebookProvider.notebookWizard.scriptAction?.label || loc.scriptToNotebook; } public get deploymentType(): DeploymentType | undefined { - return this._wizardInfo.type; + return this.notebookProvider.notebookWizard.type; } - protected initialize(): void { - this.setPages(this.getPages()); + public initialize(): void { + this.wizard.setPages(this.getPages()); } - protected onCancel(): void { + public onCancel(): void { } - protected async onGenerateScript(): Promise { + public async onGenerateScript(): Promise { const notebook = await this.prepareNotebookAndEnvironment(); await this.openNotebook(notebook); } - protected async onOk(): Promise { + public async onOk(): Promise { const notebook = await this.prepareNotebookAndEnvironment(); const openedNotebook = await this.openNotebook(notebook); openedNotebook.runAllCells(); @@ -68,15 +73,15 @@ export class NotebookWizard extends WizardBase { + this.setEnvironmentVariables(env, (varName) => { const isPassword = !!this.inputComponents[varName]?.isPassword; return isPassword; }); const notebook: Notebook = await this.notebookService.getNotebook(this.wizardInfo.notebook); // generate python code statements for all variables captured by the wizard - const statements = this.model.getCodeCellContentForNotebook( + const statements = this.getCodeCellContentForNotebook( this.toolsService.toolsForCurrentProvider, (varName) => { const isPassword = !!this.inputComponents[varName]?.isPassword; diff --git a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardPage.ts b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardPage.ts index 799c1fbcd2..3e5a170eae 100644 --- a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardPage.ts +++ b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardPage.ts @@ -8,28 +8,28 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { NotebookWizardPageInfo } from '../../interfaces'; import { initializeWizardPage, InputComponentInfo, setModelValues, Validator } from '../modelViewUtils'; -import { WizardPageBase } from '../wizardPageBase'; +import { ResourceTypePage } from '../resourceTypePage'; import { WizardPageInfo } from '../wizardPageInfo'; -import { NotebookWizard } from './notebookWizard'; +import { NotebookWizardModel } from './notebookWizardModel'; const localize = nls.loadMessageBundle(); -export class NotebookWizardPage extends WizardPageBase { +export class NotebookWizardPage extends ResourceTypePage { protected get pageInfo(): NotebookWizardPageInfo { - return this.wizard.wizardInfo.pages[this._pageIndex]; + return this._model.wizardInfo.pages[this._pageIndex]; } constructor( - wizard: NotebookWizard, + protected _model: NotebookWizardModel, protected _pageIndex: number, title?: string, description?: string ) { super( - wizard.wizardInfo.pages[_pageIndex].title || title || '', - wizard.wizardInfo.pages[_pageIndex].description || description || '', - wizard + _model.wizardInfo.pages[_pageIndex].title || title || '', + _model.wizardInfo.pages[_pageIndex].description || description || '', + _model.wizard ); } @@ -37,21 +37,21 @@ export class NotebookWizardPage extends WizardPageBase { * If the return value is true then done button should be visible to the user */ private get isDoneButtonVisible(): boolean { - return !!this.wizard.wizardInfo.doneAction; + return !!this._model.wizardInfo.doneAction; } /** * If the return value is true then generateScript button should be visible to the user */ private get isGenerateScriptButtonVisible(): boolean { - return !!this.wizard.wizardInfo.scriptAction; + return !!this._model.wizardInfo.scriptAction; } public initialize(): void { initializeWizardPage({ container: this.wizard.wizardObject, - inputComponents: this.wizard.inputComponents, - wizardInfo: this.wizard.wizardInfo, + inputComponents: this._model.inputComponents, + wizardInfo: this._model.wizardInfo, pageInfo: this.pageInfo, page: this.pageObject, onNewDisposableCreated: (disposable: vscode.Disposable): void => { @@ -62,7 +62,7 @@ export class NotebookWizardPage extends WizardPageBase { inputComponentInfo: InputComponentInfo ): void => { if (name) { - this.wizard.inputComponents[name] = inputComponentInfo; + this._model.inputComponents[name] = inputComponentInfo; } }, onNewValidatorCreated: (validator: Validator): void => { @@ -91,7 +91,7 @@ export class NotebookWizardPage extends WizardPageBase { } if (this.pageInfo.isSummaryPage) { - await setModelValues(this.wizard.inputComponents, this.wizard.model); + await setModelValues(this._model.inputComponents, this.wizard.model); } this.wizard.wizardObject.registerNavigationValidator((pcInfo) => { diff --git a/extensions/resource-deployment/src/ui/resourceTypeModel.ts b/extensions/resource-deployment/src/ui/resourceTypeModel.ts new file mode 100644 index 0000000000..6d8e56bce8 --- /dev/null +++ b/extensions/resource-deployment/src/ui/resourceTypeModel.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DeploymentProvider } from '../interfaces'; +import { Model } from './model'; +import { ResourceTypeWizard } from './resourceTypeWizard'; + +export abstract class ResourceTypeModel extends Model { + + constructor(public provider: DeploymentProvider, public wizard: ResourceTypeWizard) { + super(); + } + + abstract initialize(): void; + abstract async onOk(): Promise; + abstract onCancel(): void; + async onGenerateScript(): Promise { } + +} diff --git a/extensions/resource-deployment/src/ui/resourceTypePage.ts b/extensions/resource-deployment/src/ui/resourceTypePage.ts new file mode 100644 index 0000000000..2b04440e06 --- /dev/null +++ b/extensions/resource-deployment/src/ui/resourceTypePage.ts @@ -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 { ResourceTypeWizard } from './resourceTypeWizard'; +import { WizardPageBase } from './wizardPageBase'; + +export abstract class ResourceTypePage extends WizardPageBase{ + abstract initialize(): void; +} diff --git a/extensions/resource-deployment/src/ui/resourceTypeWizard.ts b/extensions/resource-deployment/src/ui/resourceTypeWizard.ts index 836b2b42b0..e67e096f36 100644 --- a/extensions/resource-deployment/src/ui/resourceTypeWizard.ts +++ b/extensions/resource-deployment/src/ui/resourceTypeWizard.ts @@ -5,16 +5,19 @@ import * as azdata from 'azdata'; import * as vscode from 'vscode'; -import { DeploymentProvider, instanceOfWizardDeploymentProvider, ResourceType } from '../interfaces'; -import { Model } from './model'; -import { WizardPageBase } from './wizardPageBase'; +import { DeploymentProvider, instanceOfAzureSQLDBDeploymentProvider, instanceOfAzureSQLVMDeploymentProvider, instanceOfNotebookWizardDeploymentProvider, instanceOfWizardDeploymentProvider, ResourceType } from '../interfaces'; import { DeployClusterWizardModel } from './deployClusterWizard/deployClusterWizardModel'; +import { DeployAzureSQLVMWizardModel } from './deployAzureSQLVMWizard/deployAzureSQLVMWizardModel'; import { WizardPageInfo } from './wizardPageInfo'; import { IKubeService } from '../services/kubeService'; import { IAzdataService } from '../services/azdataService'; import { INotebookService } from '../services/notebookService'; import { IToolsService } from '../services/toolsService'; import { IPlatformService } from '../services/platformService'; +import { ResourceTypeModel } from './resourceTypeModel'; +import { ResourceTypePage } from './resourceTypePage'; +import { NotebookWizardModel } from './notebookWizard/notebookWizardModel'; +import { DeployAzureSQLDBWizardModel } from './deployAzureSQLDBWizard/deployAzureSQLDBWizardModel'; export class ResourceTypeWizard { private customButtons: azdata.window.Button[] = []; @@ -49,6 +52,12 @@ export class ResourceTypeWizard { public getResourceProviderModel(): ResourceTypeModel | undefined { if (instanceOfWizardDeploymentProvider(this.provider)) { return new DeployClusterWizardModel(this.provider, this); + } else if (instanceOfAzureSQLVMDeploymentProvider(this.provider)) { + return new DeployAzureSQLVMWizardModel(this.provider, this); + } else if (instanceOfNotebookWizardDeploymentProvider(this.provider)) { + return new NotebookWizardModel(this.provider, this); + } else if (instanceOfAzureSQLDBDeploymentProvider(this.provider)) { + return new DeployAzureSQLDBWizardModel(this.provider, this); } // other types are undefined for now. return undefined; @@ -118,23 +127,11 @@ export class ResourceTypeWizard { this.toDispose.push(disposable); } -} - - - -export abstract class ResourceTypePage extends WizardPageBase{ - abstract initialize(): void; -} - -export abstract class ResourceTypeModel extends Model { - - constructor(public provider: DeploymentProvider, public wizard: ResourceTypeWizard) { - super(); + public showErrorMessage(message: string) { + this.wizardObject.message = { + text: message, + level: azdata.window.MessageLevel.Error + }; } - abstract initialize(): void; - abstract async onOk(): Promise; - abstract onCancel(): void; - async onGenerateScript(): Promise { } - }