mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Add support for dynamic enablement of resource deployment components (#13464)
* saving wip to merge main * temp fixes for textValidation* removal * save wip to switch tasks * save wip to switch tasks * save wip to switch tasks * code complete - with known bugs * missed test file * fix extHostModelView changes * validation module * missed test changes * missed change * pr feedback * pr feedback * revert inadvertent change * remove unneeded change * merge from bug/12082-2 * pr feedback * pr feedback * bdd -> tdd for validation tests * bdd -> tdd for validation tests * pr feedback * remove unneeded file * pr feedback * EOL instead of '\n' * pr feedback * pr feedback * minor fixes. * pr feedback * fix comment * comments and var renames * test fixes * working version after validation simplification * working version after validation simplification * remove inadvertent change * simplified validations * undo uneeded change * cleanup * working version after latest merge * comments and whitespace fixes * remove is_integer checks * sentence case field validation messages * Use generic strings in sample fields * minor fixes to sample extension strings * spaces to tabs for indentation * request fields before limit fields * reaarange request/limit fields * is_integer checks for PG Server Group number fields * Thenable to Promise * InputBoxInfo * pr feedback * pr feedback * isUndefinedOrEmpty to utils * include asde package.json * use ValidationValueType * ValidationValueType -> InputValueType * Add support for dynamic enablement of resource deployment components * use instanceof function * getValue returns InputValueType Co-authored-by: Arvind Ranasaria <ranasaria@outlook.com>
This commit is contained in:
@@ -211,6 +211,10 @@ export function instanceOfCommandBasedDialogInfo(obj: any): obj is CommandBasedD
|
||||
return obj && 'command' in obj;
|
||||
}
|
||||
|
||||
export function instanceOfDynamicEnablementInfo(obj: any): obj is DynamicEnablementInfo {
|
||||
return (<DynamicEnablementInfo>obj)?.target !== undefined && (<DynamicEnablementInfo>obj)?.value !== undefined;
|
||||
}
|
||||
|
||||
export interface DialogInfoBase {
|
||||
title: string;
|
||||
name: string;
|
||||
@@ -252,6 +256,11 @@ export interface OptionsInfo {
|
||||
optionsType?: OptionsType
|
||||
}
|
||||
|
||||
export interface DynamicEnablementInfo {
|
||||
target: string,
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface FieldInfoBase {
|
||||
labelWidth?: string;
|
||||
inputWidth?: string;
|
||||
@@ -296,7 +305,7 @@ export interface FieldInfo extends SubFieldInfo, FieldInfoBase {
|
||||
fontWeight?: FontWeight;
|
||||
links?: azdata.LinkArea[];
|
||||
editable?: boolean; // for editable drop-down,
|
||||
enabled?: boolean;
|
||||
enabled?: boolean | DynamicEnablementInfo;
|
||||
isEvaluated?: boolean;
|
||||
valueLookup?: string; // for fetching dropdown options
|
||||
validationLookup?: string // for fetching text field validations
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { FieldType, LabelPosition, SectionInfo } from '../../../interfaces';
|
||||
import { createSection, getDropdownComponent, InputComponentInfo, InputComponents, setModelValues, Validator } from '../../modelViewUtils';
|
||||
import { createSection, getDropdownComponent, InputComponent, InputComponentInfo, InputComponents, setModelValues, Validator } from '../../modelViewUtils';
|
||||
import { AksName_VariableName, Location_VariableName, ResourceGroup_VariableName, SubscriptionId_VariableName, VMCount_VariableName, VMSize_VariableName } from '../constants';
|
||||
import { AzureRegion } from 'azurecore';
|
||||
import { DeployClusterWizardModel } from '../deployClusterWizardModel';
|
||||
@@ -132,7 +132,7 @@ export class AzureSettingsPage extends ResourceTypePage {
|
||||
onNewDisposableCreated: (disposable: vscode.Disposable): void => {
|
||||
self.wizard.registerDisposable(disposable);
|
||||
},
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo): void => {
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo<InputComponent>): void => {
|
||||
self.inputComponents[name] = inputComponentInfo;
|
||||
self._model.inputComponents[name] = inputComponentInfo;
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { FieldType, LabelPosition, SectionInfo } from '../../../interfaces';
|
||||
import * as localizedConstants from '../../../localizedConstants';
|
||||
import { createSection, getInputBoxComponent, getInvalidSQLPasswordMessage, getPasswordMismatchMessage, InputComponentInfo, InputComponents, isValidSQLPassword, setModelValues, Validator } from '../../modelViewUtils';
|
||||
import { createSection, getInputBoxComponent, getInvalidSQLPasswordMessage, getPasswordMismatchMessage, InputComponent, InputComponentInfo, InputComponents, isValidSQLPassword, setModelValues, Validator } from '../../modelViewUtils';
|
||||
import { ResourceTypePage } from '../../resourceTypePage';
|
||||
import { ValidationType } from '../../validation/validations';
|
||||
import * as VariableNames from '../constants';
|
||||
@@ -219,7 +219,7 @@ export class ClusterSettingsPage extends ResourceTypePage {
|
||||
onNewDisposableCreated: (disposable: vscode.Disposable): void => {
|
||||
self.wizard.registerDisposable(disposable);
|
||||
},
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo): void => {
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo<InputComponent>): void => {
|
||||
self.inputComponents[name] = inputComponentInfo;
|
||||
self._model.inputComponents[name] = inputComponentInfo;
|
||||
},
|
||||
@@ -236,7 +236,7 @@ export class ClusterSettingsPage extends ResourceTypePage {
|
||||
onNewDisposableCreated: (disposable: vscode.Disposable): void => {
|
||||
self.wizard.registerDisposable(disposable);
|
||||
},
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo): void => {
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo<InputComponent>): void => {
|
||||
self.inputComponents[name] = inputComponentInfo;
|
||||
self._model.inputComponents[name] = inputComponentInfo;
|
||||
},
|
||||
@@ -253,7 +253,7 @@ export class ClusterSettingsPage extends ResourceTypePage {
|
||||
onNewDisposableCreated: (disposable: vscode.Disposable): void => {
|
||||
self.wizard.registerDisposable(disposable);
|
||||
},
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo): void => {
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo<InputComponent>): void => {
|
||||
self.inputComponents[name] = inputComponentInfo;
|
||||
self._model.inputComponents[name] = inputComponentInfo;
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { FieldType, SectionInfo } from '../../../interfaces';
|
||||
import { createFlexContainer, createGroupContainer, createLabel, createNumberInput, createSection, createInputBox, getCheckboxComponent, getDropdownComponent, getInputBoxComponent, InputComponentInfo, InputComponents, setModelValues, Validator } from '../../modelViewUtils';
|
||||
import { createFlexContainer, createGroupContainer, createLabel, createNumberInput, createSection, createInputBox, getCheckboxComponent, getDropdownComponent, getInputBoxComponent, InputComponentInfo, InputComponents, setModelValues, Validator, InputComponent } from '../../modelViewUtils';
|
||||
import { ResourceTypePage } from '../../resourceTypePage';
|
||||
import * as VariableNames from '../constants';
|
||||
import { AuthenticationMode, DeployClusterWizardModel } from '../deployClusterWizardModel';
|
||||
@@ -124,7 +124,7 @@ export class ServiceSettingsPage extends ResourceTypePage {
|
||||
onNewDisposableCreated: (disposable: vscode.Disposable): void => {
|
||||
self.wizard.registerDisposable(disposable);
|
||||
},
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo): void => {
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo<InputComponent>): void => {
|
||||
self.onNewInputComponentCreated(name, inputComponentInfo);
|
||||
},
|
||||
onNewValidatorCreated: (validator: Validator): void => {
|
||||
@@ -153,7 +153,7 @@ export class ServiceSettingsPage extends ResourceTypePage {
|
||||
});
|
||||
}
|
||||
|
||||
private onNewInputComponentCreated(name: string, inputComponentInfo: InputComponentInfo) {
|
||||
private onNewInputComponentCreated(name: string, inputComponentInfo: InputComponentInfo<InputComponent>) {
|
||||
this.inputComponents[name] = inputComponentInfo;
|
||||
this._model.inputComponents[name] = inputComponentInfo;
|
||||
}
|
||||
@@ -175,46 +175,58 @@ export class ServiceSettingsPage extends ResourceTypePage {
|
||||
this.endpointHeaderRow = createFlexContainer(view, [this.endpointNameColumnHeader, this.dnsColumnHeader, this.portColumnHeader]);
|
||||
|
||||
this.controllerNameLabel = createLabel(view, { text: localize('deployCluster.ControllerText', "Controller"), width: labelWidth, required: true });
|
||||
this.controllerDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.ControllerDNSName', "Controller DNS name"), required: false, width: inputWidth });
|
||||
this.controllerPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.ControllerPortName', "Controller port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
const controllerDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.ControllerDNSName', "Controller DNS name"), required: false, width: inputWidth });
|
||||
this.controllerDNSInput = controllerDNSInput.component;
|
||||
const controllerPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.ControllerPortName', "Controller port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
this.controllerPortInput = controllerPortInput.component;
|
||||
this.controllerEndpointRow = createFlexContainer(view, [this.controllerNameLabel, this.controllerDNSInput, this.controllerPortInput]);
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerDNSName_VariableName, { component: this.controllerDNSInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerPort_VariableName, { component: this.controllerPortInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerDNSName_VariableName, controllerDNSInput);
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerPort_VariableName, controllerPortInput);
|
||||
|
||||
this.SqlServerNameLabel = createLabel(view, { text: localize('deployCluster.MasterSqlText', "SQL Server Master"), width: labelWidth, required: true });
|
||||
this.sqlServerDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.MasterSQLServerDNSName', "SQL Server Master DNS name"), required: false, width: inputWidth });
|
||||
this.sqlServerPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.MasterSQLServerPortName', "SQL Server Master port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
const sqlServerDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.MasterSQLServerDNSName', "SQL Server Master DNS name"), required: false, width: inputWidth });
|
||||
this.sqlServerDNSInput = sqlServerDNSInput.component;
|
||||
const sqlServerPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.MasterSQLServerPortName', "SQL Server Master port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
this.sqlServerPortInput = sqlServerPortInput.component;
|
||||
this.sqlServerEndpointRow = createFlexContainer(view, [this.SqlServerNameLabel, this.sqlServerDNSInput, this.sqlServerPortInput]);
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerDNSName_VariableName, { component: this.sqlServerDNSInput });
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerPort_VariableName, { component: this.sqlServerPortInput });
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerDNSName_VariableName, sqlServerDNSInput);
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerPort_VariableName, sqlServerPortInput);
|
||||
|
||||
this.gatewayNameLabel = createLabel(view, { text: localize('deployCluster.GatewayText', "Gateway"), width: labelWidth, required: true });
|
||||
this.gatewayDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.GatewayDNSName', "Gateway DNS name"), required: false, width: inputWidth });
|
||||
this.gatewayPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.GatewayPortName', "Gateway port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
const gatewayDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.GatewayDNSName', "Gateway DNS name"), required: false, width: inputWidth });
|
||||
this.gatewayDNSInput = gatewayDNSInput.component;
|
||||
const gatewayPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.GatewayPortName', "Gateway port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
this.gatewayPortInput = gatewayPortInput.component;
|
||||
this.gatewayEndpointRow = createFlexContainer(view, [this.gatewayNameLabel, this.gatewayDNSInput, this.gatewayPortInput]);
|
||||
this.onNewInputComponentCreated(VariableNames.GatewayDNSName_VariableName, { component: this.gatewayDNSInput });
|
||||
this.onNewInputComponentCreated(VariableNames.GateWayPort_VariableName, { component: this.gatewayPortInput });
|
||||
this.onNewInputComponentCreated(VariableNames.GatewayDNSName_VariableName, gatewayDNSInput);
|
||||
this.onNewInputComponentCreated(VariableNames.GateWayPort_VariableName, gatewayPortInput);
|
||||
|
||||
this.serviceProxyNameLabel = createLabel(view, { text: localize('deployCluster.ServiceProxyText', "Management proxy"), width: labelWidth, required: true });
|
||||
this.serviceProxyDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.ServiceProxyDNSName', "Management proxy DNS name"), required: false, width: inputWidth });
|
||||
this.serviceProxyPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.ServiceProxyPortName', "Management proxy port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
const serviceProxyDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.ServiceProxyDNSName', "Management proxy DNS name"), required: false, width: inputWidth });
|
||||
this.serviceProxyDNSInput = serviceProxyDNSInput.component;
|
||||
const serviceProxyPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.ServiceProxyPortName', "Management proxy port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
this.serviceProxyPortInput = serviceProxyPortInput.component;
|
||||
this.serviceProxyEndpointRow = createFlexContainer(view, [this.serviceProxyNameLabel, this.serviceProxyDNSInput, this.serviceProxyPortInput]);
|
||||
this.onNewInputComponentCreated(VariableNames.ServiceProxyDNSName_VariableName, { component: this.serviceProxyDNSInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ServiceProxyPort_VariableName, { component: this.serviceProxyPortInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ServiceProxyDNSName_VariableName, serviceProxyDNSInput);
|
||||
this.onNewInputComponentCreated(VariableNames.ServiceProxyPort_VariableName, serviceProxyPortInput);
|
||||
|
||||
this.appServiceProxyNameLabel = createLabel(view, { text: localize('deployCluster.AppServiceProxyText', "Application proxy"), width: labelWidth, required: true });
|
||||
this.appServiceProxyDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.AppServiceProxyDNSName', "Application proxy DNS name"), required: false, width: inputWidth });
|
||||
this.appServiceProxyPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.AppServiceProxyPortName', "Application proxy port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
const appServiceProxyDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.AppServiceProxyDNSName', "Application proxy DNS name"), required: false, width: inputWidth });
|
||||
this.appServiceProxyDNSInput = appServiceProxyDNSInput.component;
|
||||
const appServiceProxyPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.AppServiceProxyPortName', "Application proxy port"), required: true, width: NumberInputWidth, min: 1 });
|
||||
this.appServiceProxyPortInput = appServiceProxyPortInput.component;
|
||||
this.appServiceProxyEndpointRow = createFlexContainer(view, [this.appServiceProxyNameLabel, this.appServiceProxyDNSInput, this.appServiceProxyPortInput]);
|
||||
this.onNewInputComponentCreated(VariableNames.AppServiceProxyDNSName_VariableName, { component: this.appServiceProxyDNSInput });
|
||||
this.onNewInputComponentCreated(VariableNames.AppServiceProxyPort_VariableName, { component: this.appServiceProxyPortInput });
|
||||
this.onNewInputComponentCreated(VariableNames.AppServiceProxyDNSName_VariableName, appServiceProxyDNSInput);
|
||||
this.onNewInputComponentCreated(VariableNames.AppServiceProxyPort_VariableName, appServiceProxyPortInput);
|
||||
|
||||
this.readableSecondaryNameLabel = createLabel(view, { text: localize('deployCluster.ReadableSecondaryText', "Readable secondary"), width: labelWidth, required: true });
|
||||
this.readableSecondaryDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.ReadableSecondaryDNSName', "Readable secondary DNS name"), required: false, width: inputWidth });
|
||||
this.readableSecondaryPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.ReadableSecondaryPortName', "Readable secondary port"), required: false, width: NumberInputWidth, min: 1 });
|
||||
const readableSecondaryDNSInput = createInputBox(view, { ariaLabel: localize('deployCluster.ReadableSecondaryDNSName', "Readable secondary DNS name"), required: false, width: inputWidth });
|
||||
this.readableSecondaryDNSInput = readableSecondaryDNSInput.component;
|
||||
const readableSecondaryPortInput = createNumberInput(view, { ariaLabel: localize('deployCluster.ReadableSecondaryPortName', "Readable secondary port"), required: false, width: NumberInputWidth, min: 1 });
|
||||
this.readableSecondaryPortInput = readableSecondaryPortInput.component;
|
||||
this.readableSecondaryEndpointRow = createFlexContainer(view, [this.readableSecondaryNameLabel, this.readableSecondaryDNSInput, this.readableSecondaryPortInput]);
|
||||
this.onNewInputComponentCreated(VariableNames.ReadableSecondaryDNSName_VariableName, { component: this.readableSecondaryDNSInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ReadableSecondaryPort_VariableName, { component: this.readableSecondaryPortInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ReadableSecondaryDNSName_VariableName, readableSecondaryDNSInput);
|
||||
this.onNewInputComponentCreated(VariableNames.ReadableSecondaryPort_VariableName, readableSecondaryPortInput);
|
||||
|
||||
return createGroupContainer(view, [this.endpointHeaderRow, this.controllerEndpointRow, this.sqlServerEndpointRow, this.gatewayEndpointRow, this.serviceProxyEndpointRow, this.appServiceProxyEndpointRow, this.readableSecondaryEndpointRow], {
|
||||
header: localize('deployCluster.EndpointSettings', "Endpoint settings"),
|
||||
@@ -270,22 +282,22 @@ export class ServiceSettingsPage extends ResourceTypePage {
|
||||
const sqlServerMasterLogsStorageClassInput = createInputBox(view, { ariaLabel: localize('deployCluster.sqlServerMasterLogsStorageClass', "SQL Server master's logs storage class"), width: inputWidth, required: false, placeHolder: hintTextForStorageFields });
|
||||
const sqlServerMasterLogsStorageClaimSizeInput = createNumberInput(view, { ariaLabel: localize('deployCluster.sqlServerMasterLogsStorageClaimSize', "SQL Server master's logs storage claim size"), width: inputWidth, required: false, min: 1, placeHolder: hintTextForStorageFields });
|
||||
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerDataStorageClassName_VariableName, { component: controllerDataStorageClassInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerDataStorageSize_VariableName, { component: controllerDataStorageClaimSizeInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerLogsStorageClassName_VariableName, { component: controllerLogsStorageClassInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerLogsStorageSize_VariableName, { component: controllerLogsStorageClaimSizeInput });
|
||||
this.onNewInputComponentCreated(VariableNames.HDFSDataStorageClassName_VariableName, { component: storagePoolDataStorageClassInput });
|
||||
this.onNewInputComponentCreated(VariableNames.HDFSDataStorageSize_VariableName, { component: storagePoolDataStorageClaimSizeInput });
|
||||
this.onNewInputComponentCreated(VariableNames.HDFSLogsStorageClassName_VariableName, { component: storagePoolLogsStorageClassInput });
|
||||
this.onNewInputComponentCreated(VariableNames.HDFSLogsStorageSize_VariableName, { component: storagePoolLogsStorageClaimSizeInput });
|
||||
this.onNewInputComponentCreated(VariableNames.DataPoolDataStorageClassName_VariableName, { component: dataPoolDataStorageClassInput });
|
||||
this.onNewInputComponentCreated(VariableNames.DataPoolDataStorageSize_VariableName, { component: dataPoolDataStorageClaimSizeInput });
|
||||
this.onNewInputComponentCreated(VariableNames.DataPoolLogsStorageClassName_VariableName, { component: dataPoolLogsStorageClassInput });
|
||||
this.onNewInputComponentCreated(VariableNames.DataPoolLogsStorageSize_VariableName, { component: dataPoolLogsStorageClaimSizeInput });
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerDataStorageClassName_VariableName, { component: sqlServerMasterDataStorageClassInput });
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerDataStorageSize_VariableName, { component: sqlServerMasterDataStorageClaimSizeInput });
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerLogsStorageClassName_VariableName, { component: sqlServerMasterLogsStorageClassInput });
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerLogsStorageSize_VariableName, { component: sqlServerMasterLogsStorageClaimSizeInput });
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerDataStorageClassName_VariableName, controllerDataStorageClassInput);
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerDataStorageSize_VariableName, controllerDataStorageClaimSizeInput);
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerLogsStorageClassName_VariableName, controllerLogsStorageClassInput);
|
||||
this.onNewInputComponentCreated(VariableNames.ControllerLogsStorageSize_VariableName, controllerLogsStorageClaimSizeInput);
|
||||
this.onNewInputComponentCreated(VariableNames.HDFSDataStorageClassName_VariableName, storagePoolDataStorageClassInput);
|
||||
this.onNewInputComponentCreated(VariableNames.HDFSDataStorageSize_VariableName, storagePoolDataStorageClaimSizeInput);
|
||||
this.onNewInputComponentCreated(VariableNames.HDFSLogsStorageClassName_VariableName, storagePoolLogsStorageClassInput);
|
||||
this.onNewInputComponentCreated(VariableNames.HDFSLogsStorageSize_VariableName, storagePoolLogsStorageClaimSizeInput);
|
||||
this.onNewInputComponentCreated(VariableNames.DataPoolDataStorageClassName_VariableName, dataPoolDataStorageClassInput);
|
||||
this.onNewInputComponentCreated(VariableNames.DataPoolDataStorageSize_VariableName, dataPoolDataStorageClaimSizeInput);
|
||||
this.onNewInputComponentCreated(VariableNames.DataPoolLogsStorageClassName_VariableName, dataPoolLogsStorageClassInput);
|
||||
this.onNewInputComponentCreated(VariableNames.DataPoolLogsStorageSize_VariableName, dataPoolLogsStorageClaimSizeInput);
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerDataStorageClassName_VariableName, sqlServerMasterDataStorageClassInput);
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerDataStorageSize_VariableName, sqlServerMasterDataStorageClaimSizeInput);
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerLogsStorageClassName_VariableName, sqlServerMasterLogsStorageClassInput);
|
||||
this.onNewInputComponentCreated(VariableNames.SQLServerLogsStorageSize_VariableName, sqlServerMasterLogsStorageClaimSizeInput);
|
||||
|
||||
const storageSettingTable = view.modelBuilder.declarativeTable()
|
||||
.withProperties<azdata.DeclarativeTableProperties>(
|
||||
|
||||
@@ -12,7 +12,7 @@ import { INotebookService } from '../services/notebookService';
|
||||
import { IPlatformService } from '../services/platformService';
|
||||
import { DialogBase } from './dialogBase';
|
||||
import { Model } from './model';
|
||||
import { initializeDialog, InputComponentInfo, InputComponents, setModelValues, Validator } from './modelViewUtils';
|
||||
import { initializeDialog, InputComponent, InputComponentInfo, InputComponents, setModelValues, Validator } from './modelViewUtils';
|
||||
import { IToolsService } from '../services/toolsService';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
@@ -69,7 +69,7 @@ export class DeploymentInputDialog extends DialogBase {
|
||||
onNewDisposableCreated: (disposable: vscode.Disposable): void => {
|
||||
this._toDispose.push(disposable);
|
||||
},
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo): void => {
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo<InputComponent>): void => {
|
||||
this.inputComponents[name] = inputComponentInfo;
|
||||
},
|
||||
onNewValidatorCreated: (validator: Validator): void => {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IOptionsSourceProvider } from 'resource-deployment';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { getDateTimeString, getErrorMessage, throwUnless } from '../common/utils';
|
||||
import { AzureAccountFieldInfo, AzureLocationsFieldInfo, ComponentCSSStyles, DialogInfoBase, FieldInfo, FieldType, FilePickerFieldInfo, IOptionsSource, KubeClusterContextFieldInfo, LabelPosition, NoteBookEnvironmentVariablePrefix, OptionsInfo, OptionsType, PageInfoBase, RowInfo, SectionInfo, TextCSSStyles } from '../interfaces';
|
||||
import { AzureAccountFieldInfo, AzureLocationsFieldInfo, ComponentCSSStyles, DialogInfoBase, FieldInfo, FieldType, FilePickerFieldInfo, instanceOfDynamicEnablementInfo, IOptionsSource, KubeClusterContextFieldInfo, LabelPosition, NoteBookEnvironmentVariablePrefix, OptionsInfo, OptionsType, PageInfoBase, RowInfo, SectionInfo, TextCSSStyles } from '../interfaces';
|
||||
import * as loc from '../localizedConstants';
|
||||
import { apiService } from '../services/apiService';
|
||||
import { getDefaultKubeConfigPath, getKubeConfigClusterContexts } from '../services/kubeService';
|
||||
@@ -35,14 +35,16 @@ export type Validator = () => { valid: boolean, message: string };
|
||||
export type InputValueType = string | number | undefined;
|
||||
export type InputValueTransformer = (inputValue: string) => InputValueType | Promise<InputValueType>;
|
||||
export type InputComponent = azdata.TextComponent | azdata.InputBoxComponent | azdata.DropDownComponent | azdata.CheckBoxComponent | RadioGroupLoadingComponentBuilder;
|
||||
export type InputComponentInfo = {
|
||||
component: InputComponent;
|
||||
export type InputComponentInfo<T extends InputComponent> = {
|
||||
component: T;
|
||||
getValue: () => Promise<InputValueType>;
|
||||
onValueChanged: vscode.Event<void>;
|
||||
inputValueTransformer?: InputValueTransformer;
|
||||
isPassword?: boolean
|
||||
};
|
||||
|
||||
export type InputComponents = {
|
||||
[s: string]: InputComponentInfo
|
||||
[s: string]: InputComponentInfo<InputComponent>
|
||||
};
|
||||
|
||||
export function getInputBoxComponent(name: string, inputComponents: InputComponents): azdata.InputBoxComponent {
|
||||
@@ -124,7 +126,7 @@ interface ContextBase {
|
||||
inputComponents: InputComponents;
|
||||
onNewValidatorCreated: (validator: Validator) => void;
|
||||
onNewDisposableCreated: (disposable: vscode.Disposable) => void;
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo) => void;
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo<InputComponent>) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,15 +177,15 @@ function createInputBoxField({ context, inputBoxType = 'text' }: { context: Fiel
|
||||
max: context.fieldInfo.max,
|
||||
placeHolder: context.fieldInfo.placeHolder,
|
||||
width: context.fieldInfo.inputWidth,
|
||||
enabled: context.fieldInfo.enabled,
|
||||
enabled: instanceOfDynamicEnablementInfo(context.fieldInfo.enabled) ? false : context.fieldInfo.enabled, // Dynamic enablement is initially set to false
|
||||
validations: context.fieldValidations
|
||||
});
|
||||
addLabelInputPairToContainer(context.view, context.components, label, input, context.fieldInfo);
|
||||
addLabelInputPairToContainer(context.view, context.components, label, input.component, context.fieldInfo);
|
||||
return input;
|
||||
}
|
||||
|
||||
export function createInputBox(view: azdata.ModelView, inputInfo: InputBoxInfo): azdata.InputBoxComponent {
|
||||
return view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
export function createInputBox(view: azdata.ModelView, inputInfo: InputBoxInfo): InputComponentInfo<azdata.InputBoxComponent> {
|
||||
const component = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
value: inputInfo.defaultValue,
|
||||
ariaLabel: inputInfo.ariaLabel,
|
||||
inputType: inputInfo.type || 'text',
|
||||
@@ -194,6 +196,11 @@ export function createInputBox(view: azdata.ModelView, inputInfo: InputBoxInfo):
|
||||
width: inputInfo.width,
|
||||
enabled: inputInfo.enabled
|
||||
}).withValidation(async (component) => await validateInputBoxComponent(component, inputInfo.validations)).component();
|
||||
return {
|
||||
component: component,
|
||||
getValue: async (): Promise<InputValueType> => component.value || '',
|
||||
onValueChanged: component.onTextChanged
|
||||
};
|
||||
}
|
||||
|
||||
export function createLabel(view: azdata.ModelView, info: { text: string, description?: string, required?: boolean, width?: string, links?: azdata.LinkArea[], cssStyles?: TextCSSStyles }): azdata.TextComponent {
|
||||
@@ -222,7 +229,7 @@ export function createLabel(view: azdata.ModelView, info: { text: string, descri
|
||||
* @param view - the ModelView object used to create the inputBox
|
||||
* @param info - an object to define the properties of the 'number' inputBox component. If the type property is set then it is overridden with 'number' type.
|
||||
*/
|
||||
export function createNumberInput(view: azdata.ModelView, info: InputBoxInfo): azdata.InputBoxComponent {
|
||||
export function createNumberInput(view: azdata.ModelView, info: InputBoxInfo): InputComponentInfo<azdata.InputBoxComponent> {
|
||||
info.type = 'number'; // for the type to be 'number'
|
||||
return createInputBox(view, info);
|
||||
}
|
||||
@@ -307,6 +314,7 @@ export function initializeWizardPage(context: WizardPageContext): void {
|
||||
sectionInfo: sectionInfo
|
||||
});
|
||||
}));
|
||||
await hookUpDynamicEnablement(context);
|
||||
const formBuilder = view.modelBuilder.formContainer().withFormItems(
|
||||
sections.map(section => { return { title: '', component: section }; }),
|
||||
{
|
||||
@@ -319,6 +327,49 @@ export function initializeWizardPage(context: WizardPageContext): void {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks up the dynamic enablement for fields which use that. This will attach a listener to the target component
|
||||
* for when the value changes and update the enabled state of the source component based on the current value
|
||||
* of the target component.
|
||||
*
|
||||
* Note that currently this is only supported for Notebook Wizard Pages and only supports direct equals comparison
|
||||
* for the value currently selected.
|
||||
*
|
||||
* Additionally this only supports hooking up components that are on the same page.
|
||||
* @param context The page context
|
||||
*/
|
||||
async function hookUpDynamicEnablement(context: WizardPageContext): Promise<void> {
|
||||
await Promise.all(context.pageInfo.sections.map(async section => {
|
||||
if (!section.fields) {
|
||||
return;
|
||||
}
|
||||
await Promise.all(section.fields.map(async field => {
|
||||
if (instanceOfDynamicEnablementInfo(field.enabled)) {
|
||||
const fieldKey = field.variableName || field.label;
|
||||
const fieldComponent = context.inputComponents[fieldKey];
|
||||
const targetComponent = context.inputComponents[field.enabled.target];
|
||||
const targetValue = field.enabled.value;
|
||||
if (!targetComponent) {
|
||||
console.error(`Could not find target component ${field.enabled.target} when hooking up dynamic enablement for ${field.label}`);
|
||||
return;
|
||||
}
|
||||
const updateFields = async () => {
|
||||
const targetComponentValue = await targetComponent.getValue();
|
||||
fieldComponent.component.enabled = targetComponentValue === targetValue;
|
||||
// We also need to update the required flag so that when the component is disabled it won't block the page from proceeding
|
||||
if ('required' in fieldComponent.component) {
|
||||
fieldComponent.component.required = fieldComponent.component.enabled === false ? false : field.required;
|
||||
}
|
||||
};
|
||||
targetComponent.onValueChanged(() => {
|
||||
updateFields();
|
||||
});
|
||||
await updateFields();
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
export async function createSection(context: SectionContext): Promise<azdata.GroupContainer> {
|
||||
const components: azdata.Component[] = [];
|
||||
context.sectionInfo.inputWidth = context.sectionInfo.inputWidth || DefaultInputWidth;
|
||||
@@ -427,7 +478,7 @@ async function processField(context: FieldContext): Promise<void> {
|
||||
await inputBox.updateProperty('validationErrorMessage', validationMessage);
|
||||
}
|
||||
},
|
||||
() => getInputComponentValue(context.inputComponents[context.fieldInfo.variableName || context.fieldInfo.label]), // callback to fetch the value of this field, and return the default value if the field value is undefined
|
||||
() => context.inputComponents[context.fieldInfo.variableName || context.fieldInfo.label].getValue(), // callback to fetch the value of this field, and return the default value if the field value is undefined
|
||||
(variable: string) => getInputComponentValue(context.inputComponents[variable]), // callback to fetch the value of a variable corresponding to any field already defined.
|
||||
(targetVariable: string) => (<azdata.InputBoxComponent>context.inputComponents[targetVariable].component).onValidityChanged,
|
||||
(disposable: vscode.Disposable) => context.onNewDisposableCreated(disposable)
|
||||
@@ -514,7 +565,7 @@ async function processOptionsTypeField(context: FieldContext): Promise<void> {
|
||||
}
|
||||
context.fieldInfo.subFields = context.fieldInfo.subFields || [];
|
||||
}
|
||||
let optionsComponent: InputComponent;
|
||||
let optionsComponent: RadioGroupLoadingComponentBuilder | azdata.DropDownComponent;
|
||||
if (context.fieldInfo.options.optionsType === OptionsType.Radio) {
|
||||
optionsComponent = await processRadioOptionsTypeField(context);
|
||||
} else {
|
||||
@@ -530,7 +581,7 @@ async function processOptionsTypeField(context: FieldContext): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function configureOptionsSourceSubfields(context: FieldContext, optionsSource: IOptionsSource, variableKey: string, optionsComponent: InputComponent, optionsSourceProvider: IOptionsSourceProvider) {
|
||||
async function configureOptionsSourceSubfields(context: FieldContext, optionsSource: IOptionsSource, variableKey: string, optionsComponent: RadioGroupLoadingComponentBuilder | azdata.DropDownComponent, optionsSourceProvider: IOptionsSourceProvider) {
|
||||
context.fieldInfo.subFields!.push({
|
||||
label: context.fieldInfo.label,
|
||||
variableName: optionsSource.variableNames![variableKey]
|
||||
@@ -550,7 +601,9 @@ async function configureOptionsSourceSubfields(context: FieldContext, optionsSou
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
isPassword: await optionsSourceProvider.getIsPassword!(variableKey)
|
||||
isPassword: await optionsSourceProvider.getIsPassword!(variableKey),
|
||||
getValue: async (): Promise<InputValueType> => (typeof optionsComponent.value === 'string' ? optionsComponent.value : optionsComponent.value?.displayName) || '',
|
||||
onValueChanged: optionsComponent.onValueChanged
|
||||
});
|
||||
}
|
||||
|
||||
@@ -566,7 +619,11 @@ function processDropdownOptionsTypeField(context: FieldContext): azdata.DropDown
|
||||
label: context.fieldInfo.label
|
||||
});
|
||||
dropdown.fireOnTextChange = true;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: dropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
getValue: async (): Promise<InputValueType> => typeof dropdown.value === 'string' ? dropdown.value : dropdown.value?.displayName || '',
|
||||
onValueChanged: dropdown.onValueChanged,
|
||||
component: dropdown
|
||||
});
|
||||
addLabelInputPairToContainer(context.view, context.components, label, dropdown, context.fieldInfo);
|
||||
return dropdown;
|
||||
}
|
||||
@@ -574,22 +631,29 @@ function processDropdownOptionsTypeField(context: FieldContext): azdata.DropDown
|
||||
function processDateTimeTextField(context: FieldContext): void {
|
||||
context.fieldInfo.defaultValue = context.fieldInfo.defaultValue + getDateTimeString();
|
||||
const input = createInputBoxField({ context });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: input });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
component: input.component,
|
||||
getValue: async (): Promise<InputValueType> => input.component.value || '',
|
||||
onValueChanged: input.component.onTextChanged
|
||||
});
|
||||
}
|
||||
|
||||
function processNumberField(context: FieldContext): void {
|
||||
const input = createInputBoxField({ context, inputBoxType: 'number' });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
component: input,
|
||||
component: input.component,
|
||||
getValue: input.getValue,
|
||||
onValueChanged: input.onValueChanged,
|
||||
inputValueTransformer: (value: string | number | undefined) => (typeof value === 'string') && value.length > 0 ? parseFloat(value) : value
|
||||
});
|
||||
}
|
||||
|
||||
function processTextField(context: FieldContext): azdata.InputBoxComponent {
|
||||
function processTextField(context: FieldContext): InputComponentInfo<azdata.InputBoxComponent> {
|
||||
const isPasswordField = context.fieldInfo.type === FieldType.Password || context.fieldInfo.type === FieldType.SQLPassword;
|
||||
const inputBoxType = isPasswordField ? 'password' : 'text';
|
||||
const input = createInputBoxField({ context, inputBoxType });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: input, isPassword: isPasswordField });
|
||||
input.isPassword = isPasswordField;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, input);
|
||||
return input;
|
||||
|
||||
}
|
||||
@@ -598,14 +662,14 @@ function processPasswordField(context: FieldContext): void {
|
||||
|
||||
if (context.fieldInfo.type === FieldType.SQLPassword) {
|
||||
const invalidPasswordMessage = getInvalidSQLPasswordMessage(context.fieldInfo.label);
|
||||
context.onNewDisposableCreated(passwordInput.onTextChanged(() => {
|
||||
if (context.fieldInfo.type === FieldType.SQLPassword && isValidSQLPassword(passwordInput.value!, context.fieldInfo.userName)) {
|
||||
context.onNewDisposableCreated(passwordInput.component.onTextChanged(() => {
|
||||
if (context.fieldInfo.type === FieldType.SQLPassword && isValidSQLPassword(passwordInput.component.value!, context.fieldInfo.userName)) {
|
||||
removeValidationMessage(context.container, invalidPasswordMessage);
|
||||
}
|
||||
}));
|
||||
|
||||
context.onNewValidatorCreated((): { valid: boolean, message: string } => {
|
||||
return { valid: isValidSQLPassword(passwordInput.value!, context.fieldInfo.userName), message: invalidPasswordMessage };
|
||||
return { valid: isValidSQLPassword(passwordInput.component.value!, context.fieldInfo.userName), message: invalidPasswordMessage };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -621,17 +685,17 @@ function processPasswordField(context: FieldContext): void {
|
||||
|
||||
addLabelInputPairToContainer(context.view, context.components, confirmPasswordLabel, confirmPasswordInput, context.fieldInfo);
|
||||
context.onNewValidatorCreated((): { valid: boolean, message: string } => {
|
||||
const passwordMatches = passwordInput.value === confirmPasswordInput.value;
|
||||
const passwordMatches = passwordInput.component.value === confirmPasswordInput.value;
|
||||
return { valid: passwordMatches, message: passwordNotMatchMessage };
|
||||
});
|
||||
|
||||
const updatePasswordMismatchMessage = () => {
|
||||
if (passwordInput.value === confirmPasswordInput.value) {
|
||||
if (passwordInput.component.value === confirmPasswordInput.value) {
|
||||
removeValidationMessage(context.container, passwordNotMatchMessage);
|
||||
}
|
||||
};
|
||||
|
||||
context.onNewDisposableCreated(passwordInput.onTextChanged(() => {
|
||||
context.onNewDisposableCreated(passwordInput.component.onTextChanged(() => {
|
||||
updatePasswordMismatchMessage();
|
||||
}));
|
||||
context.onNewDisposableCreated(confirmPasswordInput.onTextChanged(() => {
|
||||
@@ -668,8 +732,12 @@ function processHyperlinkedTextField(context: FieldContext): ReadOnlyFieldInputs
|
||||
|
||||
function processEvaluatedTextField(context: FieldContext): ReadOnlyFieldInputs {
|
||||
const readOnlyField = processReadonlyTextField(context, false /*allowEvaluation*/);
|
||||
const onChangedEmitter = new vscode.EventEmitter<void>(); // Stub event since we don't currently supp
|
||||
context.onNewDisposableCreated(onChangedEmitter);
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
component: readOnlyField.text!,
|
||||
getValue: async (): Promise<InputValueType> => readOnlyField.text?.value || '',
|
||||
onValueChanged: onChangedEmitter.event,
|
||||
inputValueTransformer: async () => {
|
||||
readOnlyField.text!.value = await substituteVariableValues(context.inputComponents, context.fieldInfo.defaultValue);
|
||||
return readOnlyField.text?.value!;
|
||||
@@ -702,7 +770,15 @@ async function substituteVariableValues(inputComponents: InputComponents, inputV
|
||||
function processCheckboxField(context: FieldContext): void {
|
||||
const checkbox = createCheckbox(context.view, { initialValue: context.fieldInfo.defaultValue! === 'true', label: context.fieldInfo.label, required: context.fieldInfo.required });
|
||||
context.components.push(checkbox);
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: checkbox });
|
||||
const onChangedEmitter = new vscode.EventEmitter<void>();
|
||||
context.onNewDisposableCreated(onChangedEmitter);
|
||||
const onChangedEvent = checkbox.onChanged(() => onChangedEmitter.fire());
|
||||
context.onNewDisposableCreated(onChangedEvent);
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
getValue: async (): Promise<InputValueType> => checkbox.checked?.toString() || '',
|
||||
onValueChanged: onChangedEmitter.event,
|
||||
component: checkbox
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -720,11 +796,11 @@ function processFilePickerField(context: FieldContext): FilePickerInputs {
|
||||
required: context.fieldInfo.required,
|
||||
placeHolder: context.fieldInfo.placeHolder,
|
||||
width: `${inputWidth - buttonWidth}px`,
|
||||
enabled: context.fieldInfo.enabled,
|
||||
enabled: typeof context.fieldInfo.enabled === 'boolean' ? context.fieldInfo.enabled : false,
|
||||
validations: context.fieldValidations
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: input });
|
||||
input.enabled = false;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, input);
|
||||
input.component.enabled = false;
|
||||
const browseFileButton = context.view!.modelBuilder.button().withProperties<azdata.ButtonProperties>({ label: loc.browse, width: buttonWidth }).component();
|
||||
const fieldInfo = context.fieldInfo as FilePickerFieldInfo;
|
||||
let filter: { [name: string]: string[] } | undefined = undefined;
|
||||
@@ -738,7 +814,7 @@ function processFilePickerField(context: FieldContext): FilePickerInputs {
|
||||
canSelectFiles: true,
|
||||
canSelectFolders: false,
|
||||
canSelectMany: false,
|
||||
defaultUri: input.value ? vscode.Uri.file(path.dirname(input.value)) : undefined,
|
||||
defaultUri: input.component.value ? vscode.Uri.file(path.dirname(input.component.value)) : undefined,
|
||||
openLabel: loc.select,
|
||||
filters: filter
|
||||
});
|
||||
@@ -746,11 +822,11 @@ function processFilePickerField(context: FieldContext): FilePickerInputs {
|
||||
return;
|
||||
}
|
||||
let fileUri = fileUris[0];
|
||||
input.value = fileUri.fsPath;
|
||||
input.component.value = fileUri.fsPath;
|
||||
}));
|
||||
const component = createFlexContainer(context.view, [input, browseFileButton], true, context.fieldInfo.inputWidth);
|
||||
const component = createFlexContainer(context.view, [input.component, browseFileButton], true, context.fieldInfo.inputWidth);
|
||||
addLabelInputPairToContainer(context.view, context.components, label, component, context.fieldInfo);
|
||||
return { input: input, browseButton: browseFileButton };
|
||||
return { input: input.component, browseButton: browseFileButton };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -851,7 +927,11 @@ async function createRadioOptions(context: FieldContext, getRadioButtonInfo?: ((
|
||||
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 });
|
||||
const radioGroupLoadingComponentBuilder = new RadioGroupLoadingComponentBuilder(context.view, context.onNewDisposableCreated, context.fieldInfo);
|
||||
context.fieldInfo.labelPosition = LabelPosition.Left;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: radioGroupLoadingComponentBuilder });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
component: radioGroupLoadingComponentBuilder,
|
||||
getValue: async (): Promise<InputValueType> => radioGroupLoadingComponentBuilder.value || '',
|
||||
onValueChanged: radioGroupLoadingComponentBuilder.onValueChanged,
|
||||
});
|
||||
addLabelInputPairToContainer(context.view, context.components, label, radioGroupLoadingComponentBuilder.component(), context.fieldInfo);
|
||||
const options = context.fieldInfo.options as OptionsInfo;
|
||||
await radioGroupLoadingComponentBuilder.loadOptions(
|
||||
@@ -886,18 +966,22 @@ async function processAzureAccountField(context: AzureAccountFieldContext): Prom
|
||||
const resourceGroupDropdown = createAzureResourceGroupsDropdown(context, accountDropdown, accountValueToAccountMap, subscriptionDropdown, subscriptionValueToSubscriptionMap);
|
||||
if (context.fieldInfo.allowNewResourceGroup) {
|
||||
const newRGCheckbox = createCheckbox(context.view, { initialValue: false, label: loc.createNewResourceGroup });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.newResourceGroupFlagVariableName!, { component: newRGCheckbox });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.newResourceGroupFlagVariableName!, {
|
||||
component: newRGCheckbox,
|
||||
getValue: async (): Promise<InputValueType> => newRGCheckbox.checked?.toString() || '',
|
||||
onValueChanged: newRGCheckbox.onChanged
|
||||
});
|
||||
const newRGNameInput = createInputBox(context.view, { ariaLabel: loc.NewResourceGroupAriaLabel });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.newResourceGroupNameVariableName!, { component: newRGNameInput });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.newResourceGroupNameVariableName!, newRGNameInput);
|
||||
context.components.push(newRGCheckbox);
|
||||
context.components.push(newRGNameInput);
|
||||
context.components.push(newRGNameInput.component);
|
||||
const setRGStatus = (newRG: boolean) => {
|
||||
resourceGroupDropdown.required = !newRG;
|
||||
resourceGroupDropdown.enabled = !newRG;
|
||||
newRGNameInput.required = newRG;
|
||||
newRGNameInput.enabled = newRG;
|
||||
newRGNameInput.component.required = newRG;
|
||||
newRGNameInput.component.enabled = newRG;
|
||||
if (!newRG) {
|
||||
newRGNameInput.value = '';
|
||||
newRGNameInput.component.value = '';
|
||||
}
|
||||
};
|
||||
context.onNewDisposableCreated(newRGCheckbox.onChanged(() => {
|
||||
@@ -974,7 +1058,11 @@ async function processKubeStorageClassField(context: FieldContext): Promise<void
|
||||
defaultValue: defaultStorageClass
|
||||
});
|
||||
storageClassDropdown.fireOnTextChange = true;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: storageClassDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
component: storageClassDropdown,
|
||||
getValue: async (): Promise<InputValueType> => (typeof storageClassDropdown.value === 'string' ? storageClassDropdown.value : storageClassDropdown.value?.displayName) || '',
|
||||
onValueChanged: storageClassDropdown.onValueChanged
|
||||
});
|
||||
addLabelInputPairToContainer(context.view, context.components, label, storageClassDropdown, context.fieldInfo);
|
||||
}
|
||||
|
||||
@@ -998,7 +1086,11 @@ function createAzureAccountDropdown(context: AzureAccountFieldContext): AzureAcc
|
||||
label: loc.account
|
||||
});
|
||||
accountDropdown.fireOnTextChange = true;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: accountDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
component: accountDropdown,
|
||||
getValue: async (): Promise<InputValueType> => (typeof accountDropdown.value === 'string' ? accountDropdown.value : accountDropdown.value?.displayName) || '',
|
||||
onValueChanged: accountDropdown.onValueChanged
|
||||
});
|
||||
const signInButton = context.view!.modelBuilder.button().withProperties<azdata.ButtonProperties>({ label: loc.signIn, width: '100px' }).component();
|
||||
const refreshButton = context.view!.modelBuilder.button().withProperties<azdata.ButtonProperties>({ label: loc.refresh, width: '100px' }).component();
|
||||
addLabelInputPairToContainer(context.view, context.components, label, accountDropdown, context.fieldInfo);
|
||||
@@ -1037,6 +1129,8 @@ function createAzureSubscriptionDropdown(
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.subscriptionVariableName || context.fieldInfo.label, {
|
||||
component: subscriptionDropdown,
|
||||
getValue: async (): Promise<InputValueType> => (typeof subscriptionDropdown.value === 'string' ? subscriptionDropdown.value : subscriptionDropdown.value?.displayName) || '',
|
||||
onValueChanged: subscriptionDropdown.onValueChanged,
|
||||
inputValueTransformer: (inputValue: string) => {
|
||||
return subscriptionValueToSubscriptionMap.get(inputValue)?.id || inputValue;
|
||||
}
|
||||
@@ -1046,7 +1140,11 @@ function createAzureSubscriptionDropdown(
|
||||
label: label.value!,
|
||||
variableName: context.fieldInfo.displaySubscriptionVariableName
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.displaySubscriptionVariableName!, { component: subscriptionDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.displaySubscriptionVariableName!, {
|
||||
component: subscriptionDropdown,
|
||||
getValue: async (): Promise<InputValueType> => (typeof subscriptionDropdown.value === 'string' ? subscriptionDropdown.value : subscriptionDropdown.value?.displayName) || '',
|
||||
onValueChanged: subscriptionDropdown.onValueChanged,
|
||||
});
|
||||
}
|
||||
addLabelInputPairToContainer(context.view, context.components, label, subscriptionDropdown, context.fieldInfo);
|
||||
return subscriptionDropdown;
|
||||
@@ -1175,7 +1273,11 @@ function createAzureResourceGroupsDropdown(
|
||||
});
|
||||
const rgValueChangedEmitter = new vscode.EventEmitter<void>();
|
||||
resourceGroupDropdown.onValueChanged(() => rgValueChangedEmitter.fire());
|
||||
context.onNewInputComponentCreated(context.fieldInfo.resourceGroupVariableName || context.fieldInfo.label, { component: resourceGroupDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.resourceGroupVariableName || context.fieldInfo.label, {
|
||||
component: resourceGroupDropdown,
|
||||
getValue: async (): Promise<InputValueType> => (typeof resourceGroupDropdown.value === 'string' ? resourceGroupDropdown.value : resourceGroupDropdown.value?.displayName) || '',
|
||||
onValueChanged: resourceGroupDropdown.onValueChanged,
|
||||
});
|
||||
addLabelInputPairToContainer(context.view, context.components, label, resourceGroupDropdown, context.fieldInfo);
|
||||
subscriptionDropdown.onValueChanged(async selectedItem => {
|
||||
const selectedAccount = !accountDropdown || !accountDropdown.value ? undefined : accountValueToAccountMap.get(accountDropdown.value.toString());
|
||||
@@ -1260,14 +1362,23 @@ async function processAzureLocationsField(context: AzureLocationsFieldContext):
|
||||
label: label.value!,
|
||||
variableName: context.fieldInfo.locationVariableName
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.locationVariableName, { component: locationDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.locationVariableName, {
|
||||
component: locationDropdown,
|
||||
getValue: async (): Promise<InputValueType> => (typeof locationDropdown.value === 'string' ? locationDropdown.value : locationDropdown.value?.displayName) || '',
|
||||
onValueChanged: locationDropdown.onValueChanged,
|
||||
});
|
||||
}
|
||||
if (context.fieldInfo.displayLocationVariableName) {
|
||||
context.fieldInfo.subFields!.push({
|
||||
label: label.value!,
|
||||
variableName: context.fieldInfo.displayLocationVariableName
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.displayLocationVariableName, { component: locationDropdown, inputValueTransformer: (value => apiService.azurecoreApi.getRegionDisplayName(value)) });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.displayLocationVariableName, {
|
||||
component: locationDropdown,
|
||||
inputValueTransformer: (value => apiService.azurecoreApi.getRegionDisplayName(value)),
|
||||
getValue: async (): Promise<InputValueType> => (typeof locationDropdown.value === 'string' ? locationDropdown.value : locationDropdown.value?.displayName) || '',
|
||||
onValueChanged: locationDropdown.onValueChanged,
|
||||
});
|
||||
}
|
||||
addLabelInputPairToContainer(context.view, context.components, label, locationDropdown, context.fieldInfo);
|
||||
return locationDropdown;
|
||||
@@ -1307,7 +1418,7 @@ export async function setModelValues(inputComponents: InputComponents, model: Mo
|
||||
}));
|
||||
}
|
||||
|
||||
async function getInputComponentValue(inputComponentInfo: InputComponentInfo): Promise<InputValueType> {
|
||||
async function getInputComponentValue(inputComponentInfo: InputComponentInfo<InputComponent>): Promise<InputValueType> {
|
||||
const input = inputComponentInfo.component;
|
||||
if (input === undefined) {
|
||||
return undefined;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { EOL } from 'os';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { NotebookWizardPageInfo } from '../../interfaces';
|
||||
import { initializeWizardPage, InputComponentInfo, setModelValues, Validator } from '../modelViewUtils';
|
||||
import { initializeWizardPage, InputComponent, InputComponentInfo, setModelValues, Validator } from '../modelViewUtils';
|
||||
import { ResourceTypePage } from '../resourceTypePage';
|
||||
import { WizardPageInfo } from '../wizardPageInfo';
|
||||
import { NotebookWizardModel } from './notebookWizardModel';
|
||||
@@ -59,7 +59,7 @@ export class NotebookWizardPage extends ResourceTypePage {
|
||||
},
|
||||
onNewInputComponentCreated: (
|
||||
name: string,
|
||||
inputComponentInfo: InputComponentInfo
|
||||
inputComponentInfo: InputComponentInfo<InputComponent>
|
||||
): void => {
|
||||
if (name) {
|
||||
this._model.inputComponents[name] = inputComponentInfo;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { OptionsInfo, FieldInfo } from '../interfaces';
|
||||
import { OptionsInfo, FieldInfo, instanceOfDynamicEnablementInfo } from '../interfaces';
|
||||
import { getErrorMessage } from '../common/utils';
|
||||
|
||||
export class RadioGroupLoadingComponentBuilder implements azdata.ComponentBuilder<azdata.LoadingComponent, azdata.LoadingComponentProperties> {
|
||||
@@ -51,7 +51,7 @@ export class RadioGroupLoadingComponentBuilder implements azdata.ComponentBuilde
|
||||
label: option.displayName,
|
||||
checked: option.displayName === defaultValue,
|
||||
name: option.name,
|
||||
enabled: this._fieldInfo.enabled
|
||||
enabled: instanceOfDynamicEnablementInfo(this._fieldInfo.enabled) ? false : this._fieldInfo.enabled // Dynamic enablement is initially set to false
|
||||
}).component();
|
||||
if (radioOption.checked) {
|
||||
this._currentRadioOption = radioOption;
|
||||
@@ -82,6 +82,12 @@ export class RadioGroupLoadingComponentBuilder implements azdata.ComponentBuilde
|
||||
return this._currentRadioOption;
|
||||
}
|
||||
|
||||
set enabled(enabled: boolean) {
|
||||
this._optionsDivContainer.items.forEach(radioButton => {
|
||||
radioButton.enabled = enabled;
|
||||
});
|
||||
}
|
||||
|
||||
get onValueChanged(): vscode.Event<void> {
|
||||
return this._onValueChangedEmitter.event;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user