mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-09 09:42:34 -05:00
Improved Validations for ARC Wizards (#12945)
This commit is contained in:
@@ -7,25 +7,33 @@ import { azureResource } from 'azureResource';
|
||||
import * as fs from 'fs';
|
||||
import { EOL } from 'os';
|
||||
import * as path from 'path';
|
||||
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 * as loc from '../localizedConstants';
|
||||
import { apiService } from '../services/apiService';
|
||||
import { getDefaultKubeConfigPath, getKubeConfigClusterContexts } from '../services/kubeService';
|
||||
import { optionsSourcesService } from '../services/optionSourcesService';
|
||||
import { KubeCtlTool, KubeCtlToolName } from '../services/tools/kubeCtlTool';
|
||||
import { IToolsService } from '../services/toolsService';
|
||||
import { getDateTimeString, getErrorMessage, throwUnless } from '../common/utils';
|
||||
import { WizardInfoBase } from './../interfaces';
|
||||
import { Model } from './model';
|
||||
import { RadioGroupLoadingComponentBuilder } from './radioGroupLoadingComponentBuilder';
|
||||
import { optionsSourcesService } from '../services/optionSourcesService';
|
||||
import { IOptionsSourceProvider } from 'resource-deployment';
|
||||
import { createValidation, validateInputBoxComponent, Validation } from './validation/validations';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
/*
|
||||
* A quick note on the naming convention for some functions in this module.
|
||||
* 'Field' suffix is used for functions that create a label+input component pair and the one without this suffix just creates one of these items.
|
||||
*
|
||||
*/
|
||||
|
||||
export type Validator = () => { valid: boolean, message: string };
|
||||
export type InputValueTransformer = (inputValue: string) => string | Promise<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;
|
||||
@@ -80,6 +88,7 @@ export interface FieldContext extends ContextBase {
|
||||
fieldInfo: FieldInfo;
|
||||
components: azdata.Component[];
|
||||
view: azdata.ModelView;
|
||||
fieldValidations?: Validation[]
|
||||
}
|
||||
|
||||
export interface FilePickerInputs {
|
||||
@@ -118,32 +127,73 @@ interface ContextBase {
|
||||
onNewInputComponentCreated: (name: string, inputComponentInfo: InputComponentInfo) => void;
|
||||
}
|
||||
|
||||
export function createTextInput(view: azdata.ModelView, inputInfo: {
|
||||
type?: azdata.InputBoxInputType,
|
||||
defaultValue?: string,
|
||||
ariaLabel: string,
|
||||
required?: boolean,
|
||||
placeHolder?: string,
|
||||
width?: string,
|
||||
enabled?: boolean,
|
||||
validationRegex?: RegExp,
|
||||
validationErrorMessage?: string
|
||||
}): azdata.InputBoxComponent {
|
||||
/**
|
||||
* An object to define the properties of an InputBox
|
||||
*/
|
||||
interface InputBoxInfo {
|
||||
/**
|
||||
* the type of inputBox, default value is 'text'
|
||||
*/
|
||||
type?: azdata.InputBoxInputType;
|
||||
defaultValue?: string;
|
||||
ariaLabel: string;
|
||||
required?: boolean;
|
||||
/**
|
||||
* the min value of this field when the type is 'number', value set is ignored if the type is not 'number'
|
||||
*/
|
||||
min?: number;
|
||||
/**
|
||||
* the min value of this field when the type is 'number', value set is ignored if the type is not 'number'
|
||||
*/
|
||||
max?: number;
|
||||
/**
|
||||
* an informational string to display in the inputBox when no value has been set.
|
||||
*/
|
||||
placeHolder?: string;
|
||||
width?: string;
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* an array of validation objects used to validate the inputBox
|
||||
*/
|
||||
validations?: Validation[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an inputBox using the properties defined in context.fieldInfo object
|
||||
*
|
||||
* @param context - the fieldContext object for this field
|
||||
* @param inputBoxType - the type of inputBox
|
||||
*/
|
||||
function createInputBoxField({ context, inputBoxType = 'text' }: { context: FieldContext; inputBoxType?: azdata.InputBoxInputType; }) {
|
||||
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 input = createInputBox(context.view, {
|
||||
type: inputBoxType,
|
||||
defaultValue: context.fieldInfo.defaultValue,
|
||||
ariaLabel: context.fieldInfo.label,
|
||||
required: context.fieldInfo.required,
|
||||
min: context.fieldInfo.min,
|
||||
max: context.fieldInfo.max,
|
||||
placeHolder: context.fieldInfo.placeHolder,
|
||||
width: context.fieldInfo.inputWidth,
|
||||
enabled: context.fieldInfo.enabled,
|
||||
validations: context.fieldValidations
|
||||
});
|
||||
addLabelInputPairToContainer(context.view, context.components, label, input, context.fieldInfo);
|
||||
return input;
|
||||
}
|
||||
|
||||
export function createInputBox(view: azdata.ModelView, inputInfo: InputBoxInfo): azdata.InputBoxComponent {
|
||||
return view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
value: inputInfo.defaultValue,
|
||||
ariaLabel: inputInfo.ariaLabel,
|
||||
inputType: inputInfo.type || 'text',
|
||||
required: inputInfo.required,
|
||||
min: inputInfo.min,
|
||||
max: inputInfo.max,
|
||||
placeHolder: inputInfo.placeHolder,
|
||||
width: inputInfo.width,
|
||||
enabled: inputInfo.enabled,
|
||||
validationErrorMessage: inputInfo.validationErrorMessage
|
||||
}).withValidation(component => {
|
||||
if (inputInfo.validationRegex?.test(component.value || '') === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
enabled: inputInfo.enabled
|
||||
}).withValidation(async (component) => await validateInputBoxComponent(component, inputInfo.validations)).component();
|
||||
}
|
||||
|
||||
export function createLabel(view: azdata.ModelView, info: { text: string, description?: string, required?: boolean, width?: string, links?: azdata.LinkArea[], cssStyles?: TextCSSStyles }): azdata.TextComponent {
|
||||
@@ -166,17 +216,15 @@ export function createLabel(view: azdata.ModelView, info: { text: string, descri
|
||||
return text;
|
||||
}
|
||||
|
||||
export function createNumberInput(view: azdata.ModelView, info: { defaultValue?: string, ariaLabel?: string, min?: number, max?: number, required?: boolean, width?: string, placeHolder?: string }): azdata.InputBoxComponent {
|
||||
return view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
value: info.defaultValue,
|
||||
ariaLabel: info.ariaLabel,
|
||||
inputType: 'number',
|
||||
min: info.min,
|
||||
max: info.max,
|
||||
required: info.required,
|
||||
width: info.width,
|
||||
placeHolder: info.placeHolder
|
||||
}).component();
|
||||
/**
|
||||
* Creates an inputBox component of 'number' type.
|
||||
*
|
||||
* @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 {
|
||||
info.type = 'number'; // for the type to be 'number'
|
||||
return createInputBox(view, info);
|
||||
}
|
||||
|
||||
export function createCheckbox(view: azdata.ModelView, info: { initialValue: boolean, label: string, required?: boolean }): azdata.CheckBoxComponent {
|
||||
@@ -369,6 +417,21 @@ function addLabelInputPairToContainer(view: azdata.ModelView, components: azdata
|
||||
}
|
||||
|
||||
async function processField(context: FieldContext): Promise<void> {
|
||||
//populate the fieldValidations objects for each field based on the information from the fieldInfo
|
||||
context.fieldValidations = context.fieldInfo.validations?.map((validation => createValidation(
|
||||
validation,
|
||||
async (isValid: boolean) => {
|
||||
const inputBox = (<azdata.InputBoxComponent>context.inputComponents[context.fieldInfo.variableName || context.fieldInfo.label].component);
|
||||
const validationMessage = (isValid) ? '' : validation.description;
|
||||
if (inputBox.validationErrorMessage !== validationMessage) { // unset validationErrorMessage if it is set
|
||||
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
|
||||
(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)
|
||||
)));
|
||||
switch (context.fieldInfo.type) {
|
||||
case FieldType.Options:
|
||||
await processOptionsTypeField(context);
|
||||
@@ -503,79 +566,33 @@ function processDropdownOptionsTypeField(context: FieldContext): azdata.DropDown
|
||||
label: context.fieldInfo.label
|
||||
});
|
||||
dropdown.fireOnTextChange = true;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName!, { component: dropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: dropdown });
|
||||
addLabelInputPairToContainer(context.view, context.components, label, dropdown, context.fieldInfo);
|
||||
return dropdown;
|
||||
}
|
||||
|
||||
function processDateTimeTextField(context: FieldContext): void {
|
||||
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 defaultValue = context.fieldInfo.defaultValue + getDateTimeString();
|
||||
const input = context.view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
|
||||
value: defaultValue,
|
||||
ariaLabel: context.fieldInfo.label,
|
||||
inputType: 'text',
|
||||
required: context.fieldInfo.required,
|
||||
placeHolder: context.fieldInfo.placeHolder
|
||||
}).component();
|
||||
input.width = context.fieldInfo.inputWidth;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName!, { component: input });
|
||||
addLabelInputPairToContainer(context.view, context.components, label, input, context.fieldInfo);
|
||||
context.fieldInfo.defaultValue = context.fieldInfo.defaultValue + getDateTimeString();
|
||||
const input = createInputBoxField({ context });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: input });
|
||||
}
|
||||
|
||||
function processNumberField(context: FieldContext): void {
|
||||
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 input = createNumberInput(context.view, {
|
||||
defaultValue: context.fieldInfo.defaultValue,
|
||||
ariaLabel: context.fieldInfo.label,
|
||||
min: context.fieldInfo.min,
|
||||
max: context.fieldInfo.max,
|
||||
required: context.fieldInfo.required,
|
||||
width: context.fieldInfo.inputWidth,
|
||||
placeHolder: context.fieldInfo.placeHolder
|
||||
const input = createInputBoxField({ context, inputBoxType: 'number' });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, {
|
||||
component: input,
|
||||
inputValueTransformer: (value: string | number | undefined) => (typeof value === 'string') && value.length > 0 ? parseFloat(value) : value
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName!, { component: input });
|
||||
addLabelInputPairToContainer(context.view, context.components, label, input, context.fieldInfo);
|
||||
}
|
||||
|
||||
function processTextField(context: FieldContext): azdata.InputBoxComponent {
|
||||
const isPasswordField = context.fieldInfo.type === FieldType.Password || context.fieldInfo.type === FieldType.SQLPassword;
|
||||
let validationRegex: RegExp | undefined = context.fieldInfo.textValidationRequired ? new RegExp(context.fieldInfo.textValidationRegex!) : undefined;
|
||||
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 input = createTextInput(context.view, {
|
||||
type: isPasswordField ? 'password' : 'text',
|
||||
defaultValue: context.fieldInfo.defaultValue,
|
||||
ariaLabel: context.fieldInfo.label,
|
||||
required: context.fieldInfo.required,
|
||||
placeHolder: context.fieldInfo.placeHolder,
|
||||
width: context.fieldInfo.inputWidth,
|
||||
enabled: context.fieldInfo.enabled,
|
||||
validationRegex: validationRegex,
|
||||
validationErrorMessage: context.fieldInfo.textValidationDescription
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName!, { component: input, isPassword: isPasswordField });
|
||||
addLabelInputPairToContainer(context.view, context.components, label, input, context.fieldInfo);
|
||||
|
||||
if (context.fieldInfo.textValidationRequired) {
|
||||
const removeInvalidInputMessage = (): void => {
|
||||
if (validationRegex!.test(input.value!)) { // input is valid
|
||||
removeValidationMessage(context.container, context.fieldInfo.textValidationDescription!);
|
||||
}
|
||||
};
|
||||
|
||||
context.onNewDisposableCreated(input.onTextChanged(() => {
|
||||
removeInvalidInputMessage();
|
||||
}));
|
||||
|
||||
const inputValidator: Validator = (): { valid: boolean; message: string; } => {
|
||||
const inputIsValid = validationRegex!.test(input.value!);
|
||||
return { valid: inputIsValid, message: context.fieldInfo.textValidationDescription! };
|
||||
};
|
||||
context.onNewValidatorCreated(inputValidator);
|
||||
}
|
||||
const inputBoxType = isPasswordField ? 'password' : 'text';
|
||||
const input = createInputBoxField({ context, inputBoxType });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: input, isPassword: isPasswordField });
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
||||
function processPasswordField(context: FieldContext): void {
|
||||
const passwordInput = processTextField(context);
|
||||
|
||||
@@ -674,9 +691,9 @@ async function substituteVariableValues(inputComponents: InputComponents, inputV
|
||||
await Promise.all(Object.keys(inputComponents)
|
||||
.filter(key => key.startsWith(NoteBookEnvironmentVariablePrefix))
|
||||
.map(async key => {
|
||||
const value = (await getInputComponentValue(inputComponents, key)) ?? '<undefined>';
|
||||
const value = (await getInputComponentValue(inputComponents[key])) ?? '<undefined>';
|
||||
const re: RegExp = new RegExp(`\\\$\\\(${key}\\\)`, 'gi');
|
||||
inputValue = inputValue?.replace(re, value);
|
||||
inputValue = inputValue?.replace(re, value.toString());
|
||||
})
|
||||
);
|
||||
return inputValue;
|
||||
@@ -685,7 +702,7 @@ 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!, { component: checkbox });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: checkbox });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -697,15 +714,16 @@ function processFilePickerField(context: FieldContext): FilePickerInputs {
|
||||
const buttonWidth = 100;
|
||||
|
||||
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 input = createTextInput(context.view, {
|
||||
const input = createInputBox(context.view, {
|
||||
defaultValue: context.fieldInfo.defaultValue || '',
|
||||
ariaLabel: context.fieldInfo.label,
|
||||
required: context.fieldInfo.required,
|
||||
placeHolder: context.fieldInfo.placeHolder,
|
||||
width: `${inputWidth - buttonWidth}px`,
|
||||
enabled: context.fieldInfo.enabled
|
||||
enabled: context.fieldInfo.enabled,
|
||||
validations: context.fieldValidations
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName!, { component: input });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: input });
|
||||
input.enabled = false;
|
||||
const browseFileButton = context.view!.modelBuilder.button().withProperties<azdata.ButtonProperties>({ label: loc.browse, width: buttonWidth }).component();
|
||||
const fieldInfo = context.fieldInfo as FilePickerFieldInfo;
|
||||
@@ -833,7 +851,7 @@ 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!, { component: radioGroupLoadingComponentBuilder });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: radioGroupLoadingComponentBuilder });
|
||||
addLabelInputPairToContainer(context.view, context.components, label, radioGroupLoadingComponentBuilder.component(), context.fieldInfo);
|
||||
const options = context.fieldInfo.options as OptionsInfo;
|
||||
await radioGroupLoadingComponentBuilder.loadOptions(
|
||||
@@ -869,7 +887,7 @@ async function processAzureAccountField(context: AzureAccountFieldContext): Prom
|
||||
if (context.fieldInfo.allowNewResourceGroup) {
|
||||
const newRGCheckbox = createCheckbox(context.view, { initialValue: false, label: loc.createNewResourceGroup });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.newResourceGroupFlagVariableName!, { component: newRGCheckbox });
|
||||
const newRGNameInput = createTextInput(context.view, { ariaLabel: loc.NewResourceGroupAriaLabel });
|
||||
const newRGNameInput = createInputBox(context.view, { ariaLabel: loc.NewResourceGroupAriaLabel });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.newResourceGroupNameVariableName!, { component: newRGNameInput });
|
||||
context.components.push(newRGCheckbox);
|
||||
context.components.push(newRGNameInput);
|
||||
@@ -956,7 +974,7 @@ async function processKubeStorageClassField(context: FieldContext): Promise<void
|
||||
defaultValue: defaultStorageClass
|
||||
});
|
||||
storageClassDropdown.fireOnTextChange = true;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName!, { component: storageClassDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: storageClassDropdown });
|
||||
addLabelInputPairToContainer(context.view, context.components, label, storageClassDropdown, context.fieldInfo);
|
||||
}
|
||||
|
||||
@@ -980,7 +998,7 @@ function createAzureAccountDropdown(context: AzureAccountFieldContext): AzureAcc
|
||||
label: loc.account
|
||||
});
|
||||
accountDropdown.fireOnTextChange = true;
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName!, { component: accountDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.variableName || context.fieldInfo.label, { component: accountDropdown });
|
||||
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);
|
||||
@@ -1017,7 +1035,7 @@ function createAzureSubscriptionDropdown(
|
||||
label: label.value!,
|
||||
variableName: context.fieldInfo.subscriptionVariableName
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.subscriptionVariableName!, {
|
||||
context.onNewInputComponentCreated(context.fieldInfo.subscriptionVariableName || context.fieldInfo.label, {
|
||||
component: subscriptionDropdown,
|
||||
inputValueTransformer: (inputValue: string) => {
|
||||
return subscriptionValueToSubscriptionMap.get(inputValue)?.id || inputValue;
|
||||
@@ -1028,7 +1046,7 @@ function createAzureSubscriptionDropdown(
|
||||
label: label.value!,
|
||||
variableName: context.fieldInfo.displaySubscriptionVariableName
|
||||
});
|
||||
context.onNewInputComponentCreated(context.fieldInfo.displaySubscriptionVariableName, { component: subscriptionDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.displaySubscriptionVariableName!, { component: subscriptionDropdown });
|
||||
}
|
||||
addLabelInputPairToContainer(context.view, context.components, label, subscriptionDropdown, context.fieldInfo);
|
||||
return subscriptionDropdown;
|
||||
@@ -1157,7 +1175,7 @@ function createAzureResourceGroupsDropdown(
|
||||
});
|
||||
const rgValueChangedEmitter = new vscode.EventEmitter<void>();
|
||||
resourceGroupDropdown.onValueChanged(() => rgValueChangedEmitter.fire());
|
||||
context.onNewInputComponentCreated(context.fieldInfo.resourceGroupVariableName!, { component: resourceGroupDropdown });
|
||||
context.onNewInputComponentCreated(context.fieldInfo.resourceGroupVariableName || context.fieldInfo.label, { component: resourceGroupDropdown });
|
||||
addLabelInputPairToContainer(context.view, context.components, label, resourceGroupDropdown, context.fieldInfo);
|
||||
subscriptionDropdown.onValueChanged(async selectedItem => {
|
||||
const selectedAccount = !accountDropdown || !accountDropdown.value ? undefined : accountValueToAccountMap.get(accountDropdown.value.toString());
|
||||
@@ -1284,24 +1302,24 @@ export function getPasswordMismatchMessage(fieldName: string): string {
|
||||
|
||||
export async function setModelValues(inputComponents: InputComponents, model: Model): Promise<void> {
|
||||
await Promise.all(Object.keys(inputComponents).map(async key => {
|
||||
const value = await getInputComponentValue(inputComponents, key);
|
||||
const value = await getInputComponentValue(inputComponents[key]);
|
||||
model.setPropertyValue(key, value);
|
||||
}));
|
||||
}
|
||||
|
||||
async function getInputComponentValue(inputComponents: InputComponents, key: string): Promise<string | undefined> {
|
||||
const input = inputComponents[key].component;
|
||||
async function getInputComponentValue(inputComponentInfo: InputComponentInfo): Promise<InputValueType> {
|
||||
const input = inputComponentInfo.component;
|
||||
if (input === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
let value: string | undefined;
|
||||
let value: string | number | undefined;
|
||||
if (input instanceof RadioGroupLoadingComponentBuilder) {
|
||||
value = input.value;
|
||||
} else if ('checked' in input) { // CheckBoxComponent
|
||||
value = input.checked ? 'true' : 'false';
|
||||
} else if ('value' in input) { // InputBoxComponent or DropDownComponent
|
||||
const inputValue = input.value;
|
||||
if (typeof inputValue === 'string' || typeof inputValue === 'undefined') {
|
||||
if (typeof inputValue === 'string' || typeof inputValue === 'undefined' || typeof inputValue === 'number') {
|
||||
value = inputValue;
|
||||
} else {
|
||||
value = inputValue.name;
|
||||
@@ -1309,7 +1327,7 @@ async function getInputComponentValue(inputComponents: InputComponents, key: str
|
||||
} else {
|
||||
throw new Error(`Unknown input type with ID ${input.id}`);
|
||||
}
|
||||
return inputComponents[key].inputValueTransformer ? await inputComponents[key].inputValueTransformer!(value ?? '') : value;
|
||||
return inputComponentInfo.inputValueTransformer ? await inputComponentInfo.inputValueTransformer(value ?? '') : value;
|
||||
}
|
||||
|
||||
export function isInputBoxEmpty(input: azdata.InputBoxComponent): boolean {
|
||||
|
||||
Reference in New Issue
Block a user