diff --git a/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb b/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb index 2efd18cbd7..a38509df4e 100644 --- a/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb +++ b/extensions/arc/notebooks/arcDeployment/deploy.sql.existing.arc.ipynb @@ -95,6 +95,16 @@ " mssql_password = os.environ[\"AZDATA_NB_VAR_SQL_PASSWORD\"]\n", "else:\n", " sys.exit(f'environment variable: AZDATA_NB_VAR_SQL_PASSWORD was not defined. Exiting\\n') \n", + "env_var = \"AZDATA_NB_VAR_SQL_STORAGE_CLASS_DATA\" in os.environ\n", + "if env_var:\n", + " mssql_storage_class_data = os.environ[\"AZDATA_NB_VAR_SQL_STORAGE_CLASS_DATA\"]\n", + "else:\n", + " sys.exit(f'environment variable: AZDATA_NB_VAR_SQL_STORAGE_CLASS_DATA was not defined. Exiting\\n') \n", + "env_var = \"AZDATA_NB_VAR_SQL_STORAGE_CLASS_LOGS\" in os.environ\n", + "if env_var:\n", + " mssql_storage_class_logs = os.environ[\"AZDATA_NB_VAR_SQL_STORAGE_CLASS_LOGS\"]\n", + "else:\n", + " sys.exit(f'environment variable: AZDATA_NB_VAR_SQL_STORAGE_CLASS_LOGS was not defined. Exiting\\n') \n", "" ], "metadata": { @@ -119,7 +129,7 @@ "print (f'Creating Managed SQL Server instance on Azure Arc')\n", "\n", "os.environ[\"AZDATA_PASSWORD\"] = mssql_password\n", - "cmd = f'azdata arc sql mi create -n {mssql_instance_name}'\n", + "cmd = f'azdata arc sql mi create -n {mssql_instance_name} -scd {mssql_storage_class_data} -scl {mssql_storage_class_logs}'\n", "out=run_command()" ], "metadata": { diff --git a/extensions/arc/package.json b/extensions/arc/package.json index d17e509df3..68cd0ca8f8 100644 --- a/extensions/arc/package.json +++ b/extensions/arc/package.json @@ -603,6 +603,20 @@ "confirmationLabel": "%arc.confirm.password%", "defaultValue": "", "required": true + }, + { + "label": "%arc.sql.storage-class.data.label%", + "description": "%arc.sql.storage-class.data.description%", + "variableName": "AZDATA_NB_VAR_SQL_STORAGE_CLASS_DATA", + "type": "kube_storage_class", + "required": true + }, + { + "label": "%arc.sql.storage-class.logs.label%", + "description": "%arc.sql.storage-class.logs.description%", + "variableName": "AZDATA_NB_VAR_SQL_STORAGE_CLASS_LOGS", + "type": "kube_storage_class", + "required": true } ] } diff --git a/extensions/arc/package.nls.json b/extensions/arc/package.nls.json index c614bc47b7..cd04b46f4c 100644 --- a/extensions/arc/package.nls.json +++ b/extensions/arc/package.nls.json @@ -80,6 +80,10 @@ "arc.azure.section.title": "Azure information", "arc.sql.instance.name": "Instance name (lower case letters and digits only)", "arc.sql.username": "Username", + "arc.sql.storage-class.data.label": "Storage Class (Data)", + "arc.sql.storage-class.data.description": "The storage classes to be used for data (.mdf)", + "arc.sql.storage-class.logs.label": "Storage Class (Logs)", + "arc.sql.storage-class.logs.description": "The storage classes to be used for logs (/var/log)", "arc.password": "Password", "arc.confirm.password": "Confirm password", "arc.azure.account": "Azure account", diff --git a/extensions/resource-deployment/src/interfaces.ts b/extensions/resource-deployment/src/interfaces.ts index 82894fe0f7..57e691e33a 100644 --- a/extensions/resource-deployment/src/interfaces.ts +++ b/extensions/resource-deployment/src/interfaces.ts @@ -284,6 +284,7 @@ export enum FieldType { AzureLocations = 'azure_locations', FilePicker = 'file_picker', KubeClusterContextPicker = 'kube_cluster_context_picker', + KubeStorageClass = 'kube_storage_class' } export enum OptionsType { diff --git a/extensions/resource-deployment/src/main.ts b/extensions/resource-deployment/src/main.ts index f06ed78dd7..e83bbe306e 100644 --- a/extensions/resource-deployment/src/main.ts +++ b/extensions/resource-deployment/src/main.ts @@ -70,7 +70,7 @@ export async function activate(context: vscode.ExtensionContext): Promise } }); vscode.commands.registerCommand('azdata.openNotebookInputDialog', (dialogInfo: NotebookBasedDialogInfo) => { - const dialog = new DeploymentInputDialog(notebookService, platformService, dialogInfo); + const dialog = new DeploymentInputDialog(notebookService, platformService, toolsService, dialogInfo); dialog.open(); }); } diff --git a/extensions/resource-deployment/src/services/resourceTypeService.ts b/extensions/resource-deployment/src/services/resourceTypeService.ts index 385450e8d9..7c4ed9f374 100644 --- a/extensions/resource-deployment/src/services/resourceTypeService.ts +++ b/extensions/resource-deployment/src/services/resourceTypeService.ts @@ -245,7 +245,7 @@ export class ResourceTypeService implements IResourceTypeService { const wizard = new NotebookWizard(provider.notebookWizard, this.notebookService, this.platformService, this.toolsService); wizard.open(); } else if (instanceOfDialogDeploymentProvider(provider)) { - const dialog = new DeploymentInputDialog(this.notebookService, this.platformService, provider.dialog); + const dialog = new DeploymentInputDialog(this.notebookService, this.platformService, this.toolsService, provider.dialog); dialog.open(); } else if (instanceOfNotebookDeploymentProvider(provider)) { this.notebookService.launchNotebook(provider.notebook); diff --git a/extensions/resource-deployment/src/services/tools/azdataTool.ts b/extensions/resource-deployment/src/services/tools/azdataTool.ts index d132408dce..8806ccae29 100644 --- a/extensions/resource-deployment/src/services/tools/azdataTool.ts +++ b/extensions/resource-deployment/src/services/tools/azdataTool.ts @@ -37,7 +37,7 @@ export class AzdataTool extends ToolBase { } get displayName(): string { - return localize('resourceDeployment.AzdataDisplayName', "azdata"); + return localize('resourceDeployment.AzdataDisplayName', "Azure Data CLI"); } get homePage(): string { diff --git a/extensions/resource-deployment/src/services/tools/kubeCtlTool.ts b/extensions/resource-deployment/src/services/tools/kubeCtlTool.ts index 4f6762c8d7..215224e100 100644 --- a/extensions/resource-deployment/src/services/tools/kubeCtlTool.ts +++ b/extensions/resource-deployment/src/services/tools/kubeCtlTool.ts @@ -20,6 +20,27 @@ interface KubeCtlVersion { }; } +export interface KubeStorageClass { + apiVersion: string, // "storage.k8s.io/v1", + kind: string, // "StorageClass", + metadata: KubeStorageClassMetadata, + provisioner: string, // "kubernetes.io/no-provisioner", + reclaimPolicy: string, // "Delete", + volumeBindingMode: string, // "WaitForFirstConsumer" +} + +export interface KubeStorageClassMetadata { + annotations: { + 'kubectl.kubernetes.io/last-applied-configuration': string, // "{\"apiVersion\":\"storage.k8s.io/v1\",\"kind\":\"StorageClass\",\"metadata\":{\"annotations\":{},\"name\":\"local-storage\"},\"provisioner\":\"kubernetes.io/no-provisioner\",\"reclaimPolicy\":\"Delete\",\"volumeBindingMode\":\"WaitForFirstConsumer\"}\n", + 'storageclass.kubernetes.io/is-default-class': string, // "true" + }, + creationTimestamp: string, // "2020-08-17T19:55:23Z", + name: string, // "local-storage", + resourceVersion: string, // "256", + selfLink: string, // "/apis/storage.k8s.io/v1/storageclasses/local-storage", + uid: string, // "262615e9-618b-4052-b0d4-2ddd02794cb4" +} + export class KubeCtlTool extends ToolBase { constructor(platformService: IPlatformService) { super(platformService); @@ -45,6 +66,14 @@ export class KubeCtlTool extends ToolBase { return 'https://kubernetes.io/docs/tasks/tools/install-kubectl'; } + public async getStorageClasses(): Promise<{ storageClasses: string[], defaultStorageClass: string }> { + const storageClasses: KubeStorageClass[] = JSON.parse(await this.platformService.runCommand('kubectl get sc -o json')).items; + return { + storageClasses: storageClasses.map(sc => sc.metadata.name), + defaultStorageClass: storageClasses.find(sc => sc.metadata.annotations['storageclass.kubernetes.io/is-default-class'] === 'true')?.metadata.name ?? '' + }; + } + protected getVersionFromOutput(output: string): SemVer | undefined { let version: SemVer | undefined = undefined; if (output) { diff --git a/extensions/resource-deployment/src/services/tools/toolBase.ts b/extensions/resource-deployment/src/services/tools/toolBase.ts index 519ddd6184..3f53a376b5 100644 --- a/extensions/resource-deployment/src/services/tools/toolBase.ts +++ b/extensions/resource-deployment/src/services/tools/toolBase.ts @@ -40,7 +40,7 @@ export const messageByDependencyType: Map = new Map { @@ -101,11 +101,11 @@ export abstract class ToolBase implements ITool { return this.status === ToolStatus.NotInstalled && this.autoInstallSupported; } public get storagePath(): string { - return this._platformService.storagePath(); + return this.platformService.storagePath(); } public get osDistribution(): OsDistribution { - return this._platformService.osDistribution(); + return this.platformService.osDistribution(); } protected get version(): SemVer | undefined { @@ -136,7 +136,7 @@ export abstract class ToolBase implements ITool { protected async getPip3InstallLocation(packageName: string): Promise { const command = `pip3 show ${packageName}`; - const pip3ShowOutput: string = await this._platformService.runCommand(command, { sudo: false, ignoreError: true }); + const pip3ShowOutput: string = await this.platformService.runCommand(command, { sudo: false, ignoreError: true }); const installLocation = /^Location\: (.*)$/gim.exec(pip3ShowOutput); let retValue = installLocation && installLocation[1]; if (retValue === undefined || retValue === null) { @@ -150,11 +150,11 @@ export abstract class ToolBase implements ITool { } public get outputChannelName(): string { - return this._platformService.outputChannelName(); + return this.platformService.outputChannelName(); } public showOutputChannel(preserveFocus?: boolean | undefined): void { - this._platformService.showOutputChannel(preserveFocus); + this.platformService.showOutputChannel(preserveFocus); } @@ -197,7 +197,7 @@ export abstract class ToolBase implements ITool { throw new Error(localize('toolBase.installCore.CannotInstallTool', "Cannot install tool:{0}::{1} as installation commands are unknown for your OS distribution, Please install {0} manually before proceeding", this.displayName, this.description)); } for (let i: number = 0; i < installationCommands.length; i++) { - await this._platformService.runCommand(installationCommands[i].command, + await this.platformService.runCommand(installationCommands[i].command, { workingDirectory: installationCommands[i].workingDirectory || this.downloadPath, additionalEnvironmentVariables: installationCommands[i].additionalEnvironmentVariables, @@ -253,7 +253,7 @@ export abstract class ToolBase implements ITool { private async updateVersionAndStatus(): Promise { this._statusDescription = ''; await this.addInstallationSearchPathsToSystemPath(); - const commandOutput = await this._platformService.runCommand( + const commandOutput = await this.platformService.runCommand( this.versionCommand.command, { workingDirectory: this.versionCommand.workingDirectory, @@ -289,7 +289,7 @@ export abstract class ToolBase implements ITool { } protected async setInstallationPath() { - const commandOutput = await this._platformService.runCommand( + const commandOutput = await this.platformService.runCommand( this.discoveryCommand.command, { workingDirectory: this.discoveryCommand.workingDirectory, diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizard.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizard.ts index f6ae1ee681..34cb37f18b 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizard.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizard.ts @@ -57,8 +57,8 @@ export class DeployClusterWizard extends WizardBase { this.setEnvironmentVariables(process.env); - const variableValueStatements = this.model.getCodeCellContentForNotebook(this._toolsService.toolsForCurrentProvider); + const variableValueStatements = this.model.getCodeCellContentForNotebook(this.toolsService.toolsForCurrentProvider); const insertionPosition = 5; // Cell number 5 is the position where the python variable setting statements need to be inserted in this.wizardInfo.notebook. try { await this.notebookService.launchNotebookWithEdits(this.wizardInfo.notebook, variableValueStatements, insertionPosition); diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/azureSettingsPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/azureSettingsPage.ts index 0745d078df..c71e4f818f 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/azureSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/azureSettingsPage.ts @@ -139,7 +139,8 @@ export class AzureSettingsPage extends WizardPageBase { self.validators.push(validator); }, container: this.wizard.wizardObject, - inputComponents: this.wizard.inputComponents + inputComponents: this.wizard.inputComponents, + toolsService: this.wizard.toolsService }); const formBuilder = view.modelBuilder.formContainer().withFormItems( [{ diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/clusterSettingsPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/clusterSettingsPage.ts index f8d114abb8..b58e334b26 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/clusterSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/clusterSettingsPage.ts @@ -222,7 +222,8 @@ export class ClusterSettingsPage extends WizardPageBase { }, onNewValidatorCreated: (validator: Validator): void => { self.validators.push(validator); - } + }, + toolsService: this.wizard.toolsService }); const activeDirectorySettingsGroup = await createSection({ view: view, @@ -237,7 +238,8 @@ export class ClusterSettingsPage extends WizardPageBase { }, onNewValidatorCreated: (validator: Validator): void => { self.validators.push(validator); - } + }, + toolsService: this.wizard.toolsService }); const dockerSettingsGroup = await createSection({ view: view, @@ -252,7 +254,8 @@ export class ClusterSettingsPage extends WizardPageBase { }, onNewValidatorCreated: (validator: Validator): void => { self.validators.push(validator); - } + }, + toolsService: this.wizard.toolsService }); const basicSettingsFormItem = { title: '', component: basicSettingsGroup }; const dockerSettingsFormItem = { title: '', component: dockerSettingsGroup }; diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts index e0854441a0..33c63941aa 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts @@ -128,7 +128,8 @@ export class ServiceSettingsPage extends WizardPageBase { this.inputComponents[name] = { component: inputComponentInfo.component }; }, onNewValidatorCreated: (validator: Validator): void => { - } + }, + toolsService: this.wizard.toolsService }); }; const scaleSection = await createSectionFunc(scaleSectionInfo); diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/summaryPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/summaryPage.ts index 0c169926ce..67191cd8f7 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/summaryPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/summaryPage.ts @@ -296,7 +296,8 @@ export class SummaryPage extends WizardPageBase { view: this.view, onNewDisposableCreated: () => { }, onNewInputComponentCreated: () => { }, - onNewValidatorCreated: () => { } + onNewValidatorCreated: () => { }, + toolsService: this.wizard.toolsService }) }; }; diff --git a/extensions/resource-deployment/src/ui/deploymentInputDialog.ts b/extensions/resource-deployment/src/ui/deploymentInputDialog.ts index 30f024e4ff..60fdb079e9 100644 --- a/extensions/resource-deployment/src/ui/deploymentInputDialog.ts +++ b/extensions/resource-deployment/src/ui/deploymentInputDialog.ts @@ -13,6 +13,7 @@ import { IPlatformService } from '../services/platformService'; import { DialogBase } from './dialogBase'; import { Model } from './model'; import { initializeDialog, InputComponentInfo, InputComponents, setModelValues, Validator } from './modelViewUtils'; +import { IToolsService } from '../services/toolsService'; const localize = nls.loadMessageBundle(); @@ -22,6 +23,7 @@ export class DeploymentInputDialog extends DialogBase { constructor(private notebookService: INotebookService, private platformService: IPlatformService, + private toolsService: IToolsService, private dialogInfo: DialogInfo) { super(dialogInfo.title, dialogInfo.name, false); let okButtonText: string; @@ -51,7 +53,8 @@ export class DeploymentInputDialog extends DialogBase { }, onNewValidatorCreated: (validator: Validator): void => { validators.push(validator); - } + }, + toolsService: this.toolsService }); this._dialogObject.registerCloseValidator(() => { const messages: string[] = []; diff --git a/extensions/resource-deployment/src/ui/modelViewUtils.ts b/extensions/resource-deployment/src/ui/modelViewUtils.ts index 67a1fc0b29..b23c0d1cd9 100644 --- a/extensions/resource-deployment/src/ui/modelViewUtils.ts +++ b/extensions/resource-deployment/src/ui/modelViewUtils.ts @@ -17,6 +17,8 @@ import { assert, getDateTimeString, getErrorMessage } from '../utils'; import { WizardInfoBase } from './../interfaces'; import { Model } from './model'; import { RadioGroupLoadingComponentBuilder } from './radioGroupLoadingComponentBuilder'; +import { IToolsService } from '../services/toolsService'; +import { KubeCtlToolName, KubeCtlTool } from '../services/tools/kubeCtlTool'; const localize = nls.loadMessageBundle(); @@ -107,6 +109,7 @@ interface AzureAccountComponents { interface ContextBase { container: azdata.window.Dialog | azdata.window.Wizard; + toolsService: IToolsService, inputComponents: InputComponents; onNewValidatorCreated: (validator: Validator) => void; onNewDisposableCreated: (disposable: vscode.Disposable) => void; @@ -197,7 +200,8 @@ export function initializeDialog(dialogContext: DialogContext): void { onNewInputComponentCreated: dialogContext.onNewInputComponentCreated, onNewValidatorCreated: dialogContext.onNewValidatorCreated, container: dialogContext.container, - inputComponents: dialogContext.inputComponents + inputComponents: dialogContext.inputComponents, + toolsService: dialogContext.toolsService }); })); const formBuilder = view.modelBuilder.formContainer().withFormItems( @@ -229,6 +233,7 @@ export function initializeWizardPage(context: WizardPageContext): void { return createSection({ view: view, container: context.container, + toolsService: context.toolsService, inputComponents: context.inputComponents, onNewDisposableCreated: context.onNewDisposableCreated, onNewInputComponentCreated: context.onNewInputComponentCreated, @@ -299,7 +304,8 @@ async function processFields(fieldInfoArray: FieldInfo[], components: azdata.Com fieldInfo: fieldInfo, container: context.container, inputComponents: context.inputComponents, - components: components + components: components, + toolsService: context.toolsService }); if (spaceBetweenFields && i < fieldInfoArray.length - 1) { components.push(context.view.modelBuilder.divContainer().withLayout({ width: spaceBetweenFields }).component()); @@ -380,6 +386,9 @@ async function processField(context: FieldContext): Promise { case FieldType.KubeClusterContextPicker: processKubeConfigClusterPickerField(context); break; + case FieldType.KubeStorageClass: + await processKubeStorageClassField(context); + break; default: throw new Error(localize('UnknownFieldTypeError', "Unknown field type: \"{0}\"", context.fieldInfo.type)); } @@ -719,7 +728,8 @@ async function processKubeConfigClusterPickerField(context: KubeClusterContextFi variableName: kubeConfigFilePathVariableName, labelPosition: LabelPosition.Left, required: true - } + }, + toolsService: context.toolsService }; const filePicker = processFilePickerField(filePickerContext); context.fieldInfo.subFields = context.fieldInfo.subFields || []; @@ -840,6 +850,42 @@ async function processAzureAccountField(context: AzureAccountFieldContext): Prom }, 0); } +async function processKubeStorageClassField(context: FieldContext): Promise { + const label = createLabel(context.view, { + text: context.fieldInfo.label, + description: context.fieldInfo.description, + required: context.fieldInfo.required, + width: context.fieldInfo.labelWidth, + cssStyles: context.fieldInfo.labelCSSStyles + }); + + // Try to query for the available storage classes - but if this fails the dropdown is editable + // so users can still enter their own + let storageClasses: string[] = []; + let defaultStorageClass = ''; + try { + const kubeCtlTool = context.toolsService.getToolByName(KubeCtlToolName) as KubeCtlTool; + const response = await kubeCtlTool.getStorageClasses(); + storageClasses = response.storageClasses; + defaultStorageClass = response.defaultStorageClass; + } catch (err) { + vscode.window.showErrorMessage(localize('resourceDeployment.errorFetchingStorageClasses', "Unexpected error fetching available kubectl storage classes : {0}", err.message ?? err)); + } + + const storageClassDropdown = createDropdown(context.view, { + width: context.fieldInfo.inputWidth, + editable: true, + required: context.fieldInfo.required, + label: context.fieldInfo.label, + values: storageClasses, + defaultValue: defaultStorageClass + }); + storageClassDropdown.fireOnTextChange = true; + context.onNewInputComponentCreated(context.fieldInfo.variableName!, { component: storageClassDropdown }); + addLabelInputPairToContainer(context.view, context.components, label, storageClassDropdown, context.fieldInfo); +} + + function getAccountDisplayString(account: azdata.Account) { return `${account.displayInfo.displayName} (${account.displayInfo.userId})`; } diff --git a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizard.ts b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizard.ts index f4c5fd6755..0d7ca0ffd5 100644 --- a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizard.ts +++ b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizard.ts @@ -35,8 +35,8 @@ export class NotebookWizard extends WizardBase { const isPassword = !!this.inputComponents[varName]?.isPassword; return !isPassword; diff --git a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardAutoSummaryPage.ts b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardAutoSummaryPage.ts index 6b952160b8..21b21d02ae 100644 --- a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardAutoSummaryPage.ts +++ b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardAutoSummaryPage.ts @@ -79,6 +79,7 @@ export class NotebookWizardAutoSummaryPage extends NotebookWizardPage { title: pageInfo.title, component: await createSection({ container: this.wizard.wizardObject, + toolsService: this.wizard.toolsService, inputComponents: this.wizard.inputComponents, sectionInfo: summarySectionInfo, view: this.view, diff --git a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardPage.ts b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardPage.ts index 7e95b24c43..af688639a9 100644 --- a/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardPage.ts +++ b/extensions/resource-deployment/src/ui/notebookWizard/notebookWizardPage.ts @@ -53,6 +53,7 @@ export class NotebookWizardPage extends WizardPageBase { onNewValidatorCreated: (validator: Validator): void => { this.validators.push(validator); }, + toolsService: this.wizard.toolsService }); } diff --git a/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts b/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts index 0e443292f9..c84ea2efae 100644 --- a/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts +++ b/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts @@ -94,7 +94,7 @@ export class ResourceTypePickerDialog extends DialogBase { this._agreementContainer = view.modelBuilder.divContainer().component(); const toolColumn: azdata.TableColumn = { value: localize('deploymentDialog.toolNameColumnHeader', "Tool"), - width: 55 + width: 80 }; const descriptionColumn: azdata.TableColumn = { value: localize('deploymentDialog.toolDescriptionColumnHeader', "Description"), diff --git a/extensions/resource-deployment/src/ui/wizardBase.ts b/extensions/resource-deployment/src/ui/wizardBase.ts index 9ae86e1b70..0db589a26c 100644 --- a/extensions/resource-deployment/src/ui/wizardBase.ts +++ b/extensions/resource-deployment/src/ui/wizardBase.ts @@ -8,6 +8,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { WizardPageBase } from './wizardPageBase'; import { Model } from './model'; +import { IToolsService } from '../services/toolsService'; const localize = nls.loadMessageBundle(); export abstract class WizardBase, M extends Model> { @@ -20,7 +21,7 @@ export abstract class WizardBase, M extends Model return this._model; } - constructor(private title: string, private _model: M) { + constructor(private title: string, private _model: M, public toolsService: IToolsService) { this.wizardObject = azdata.window.createWizard(title); }