Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve local settings for V2 schema templates #3927

Merged
merged 13 commits into from
Jan 19, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@ import { type Progress } from 'vscode';
import { setLocalAppSetting } from '../../../funcConfig/local.settings';
import { localize } from '../../../localize';
import { type IBindingSetting } from '../../../templates/IBindingTemplate';
import { nonNullProp } from '../../../utils/nonNull';
import { setBindingSetting } from '../../createFunction/IFunctionWizardContext';
import { type IBindingWizardContext } from '../IBindingWizardContext';
import { type ParsedInput } from '../../../templates/script/parseScriptTemplatesV2';
import { setBindingSetting, type IFunctionWizardContext } from '../../createFunction/IFunctionWizardContext';

export interface IConnection {
name: string;
connectionString: string;
}

export abstract class AzureConnectionCreateStepBase<T extends IBindingWizardContext> extends AzureWizardExecuteStep<T> {
export abstract class AzureConnectionCreateStepBase<T extends IFunctionWizardContext> extends AzureWizardExecuteStep<T> {
public priority: number = 200;

private readonly _setting: IBindingSetting;
private readonly _setting: IBindingSetting | ParsedInput;
private readonly _resourceType: string;

constructor(setting: IBindingSetting) {
constructor(setting: IBindingSetting | ParsedInput) {
super();
this._setting = setting;
this._resourceType = (setting as IBindingSetting).resourceType ?? (setting as ParsedInput).resource ?? '';
}

public abstract getConnection(context: T): Promise<IConnection>;
Expand All @@ -33,7 +34,7 @@ export abstract class AzureConnectionCreateStepBase<T extends IBindingWizardCont
progress.report({ message: localize('retrieving', 'Retrieving connection string...') });

const result: IConnection = await this.getConnection(context);
let appSettingKey: string = `${result.name}_${nonNullProp(this._setting, 'resourceType').toUpperCase()}`;
let appSettingKey: string = `${result.name}_${this._resourceType.toUpperCase()}`;
appSettingKey = appSettingKey.replace(/[^a-z0-9_\.]/gi, ''); // remove invalid chars
setBindingSetting(context, this._setting, appSettingKey);
await setLocalAppSetting(context, context.projectPath, appSettingKey, result.connectionString);
Expand Down
20 changes: 11 additions & 9 deletions src/commands/addBinding/settingSteps/BindingSettingStepBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@
import { AzureWizardPromptStep } from "@microsoft/vscode-azext-utils";
import { type BindingSettingValue } from "../../../funcConfig/function";
import { type IBindingSetting } from "../../../templates/IBindingTemplate";
import { getBindingSetting, setBindingSetting } from "../../createFunction/IFunctionWizardContext";
import { type IBindingWizardContext } from "../IBindingWizardContext";
import { type ParsedInput } from "../../../templates/script/parseScriptTemplatesV2";
import { getBindingSetting, setBindingSetting, type IFunctionWizardContext } from "../../createFunction/IFunctionWizardContext";

export abstract class BindingSettingStepBase extends AzureWizardPromptStep<IBindingWizardContext> {
protected readonly _setting: IBindingSetting;
export abstract class BindingSettingStepBase extends AzureWizardPromptStep<IFunctionWizardContext> {
protected readonly _setting: IBindingSetting | ParsedInput;
protected readonly _resourceType: string;

constructor(setting: IBindingSetting) {
constructor(setting: IBindingSetting | ParsedInput) {
super();
this._setting = setting;
this.id = setting.name;
this._resourceType = (setting as IBindingSetting).resourceType ?? (setting as ParsedInput).resource ?? '';
}

public abstract promptCore(context: IBindingWizardContext): Promise<BindingSettingValue>;
public abstract promptCore(context: IFunctionWizardContext): Promise<BindingSettingValue>;

public async prompt(context: IBindingWizardContext): Promise<void> {
setBindingSetting(context, this._setting, await this.promptCore(context));
public async prompt(context: IFunctionWizardContext): Promise<void> {
setBindingSetting(context, this._setting as IBindingSetting, await this.promptCore(context));
}

public shouldPrompt(context: IBindingWizardContext): boolean {
public shouldPrompt(context: IFunctionWizardContext): boolean {
return !getBindingSetting(context, this._setting);
}
}
3 changes: 2 additions & 1 deletion src/commands/addBinding/settingSteps/BooleanPromptStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { type IAzureQuickPickItem } from "@microsoft/vscode-azext-utils";
import { type BindingSettingValue } from "../../../funcConfig/function";
import { type IBindingSetting } from "../../../templates/IBindingTemplate";
import { envUtils } from "../../../utils/envUtils";
import { type IBindingWizardContext } from "../IBindingWizardContext";
import { BindingSettingStepBase } from "./BindingSettingStepBase";
Expand All @@ -18,6 +19,6 @@ export class BooleanPromptStep extends BindingSettingStepBase {
picks = picks.reverse();
}

return (await context.ui.showQuickPick(picks, { placeHolder: this._setting.description || this._setting.label })).data;
return (await context.ui.showQuickPick(picks, { placeHolder: (this._setting as IBindingSetting).description || this._setting.label })).data;
}
}
3 changes: 2 additions & 1 deletion src/commands/addBinding/settingSteps/EnumPromptStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@

import { type IAzureQuickPickItem } from "@microsoft/vscode-azext-utils";
import { type BindingSettingValue } from "../../../funcConfig/function";
import { type IBindingSetting } from "../../../templates/IBindingTemplate";
import { type IBindingWizardContext } from "../IBindingWizardContext";
import { BindingSettingStepBase } from "./BindingSettingStepBase";

export class EnumPromptStep extends BindingSettingStepBase {
public async promptCore(context: IBindingWizardContext): Promise<BindingSettingValue> {
const picks: IAzureQuickPickItem<string>[] = this._setting.enums.map(e => { return { data: e.value, label: e.displayName }; });
const picks: IAzureQuickPickItem<string>[] = (this._setting as IBindingSetting).enums.map(e => { return { data: e.value, label: e.displayName }; });
return (await context.ui.showQuickPick(picks, { placeHolder: this._setting.label })).data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ import { localSettingsFileName } from '../../../constants';
import { setLocalAppSetting } from '../../../funcConfig/local.settings';
import { localize } from '../../../localize';
import { type IBindingSetting } from '../../../templates/IBindingTemplate';
import { type ParsedInput } from '../../../templates/script/parseScriptTemplatesV2';
import { nonNullProp, nonNullValue } from '../../../utils/nonNull';
import { getBindingSetting } from '../../createFunction/IFunctionWizardContext';
import { getBindingSetting, setBindingSetting } from '../../createFunction/IFunctionWizardContext';
import { type IBindingWizardContext } from '../IBindingWizardContext';

export class LocalAppSettingCreateStep extends AzureWizardExecuteStep<IBindingWizardContext> {
public priority: number = 210;

private readonly _setting: IBindingSetting;
private readonly _setting: IBindingSetting | ParsedInput;
private readonly _valueKey: string;

constructor(setting: IBindingSetting, valueKey: string) {
constructor(setting: IBindingSetting | ParsedInput, valueKey: string) {
super();
this._setting = setting;
this._valueKey = valueKey;
Expand All @@ -29,6 +30,10 @@ export class LocalAppSettingCreateStep extends AzureWizardExecuteStep<IBindingWi
progress.report({ message: localize('updatingLocalSettings', 'Updating {0}...', localSettingsFileName) });
const appSettingName = String(nonNullValue(getBindingSetting(context, this._setting), this._setting.name));
await setLocalAppSetting(context, context.projectPath, appSettingName, nonNullProp(context, this._valueKey as keyof IBindingWizardContext) as string);
// if the binding isn't already set then a new one was created
if (!getBindingSetting(context, this._setting)) {
setBindingSetting(context, this._setting, nonNullProp(context, this._valueKey as keyof IBindingWizardContext) as string);
}
}

public shouldExecute(context: IBindingWizardContext): boolean {
Expand Down
18 changes: 10 additions & 8 deletions src/commands/addBinding/settingSteps/LocalAppSettingListStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ import { getLocalSettingsJson, type ILocalSettingsJson } from '../../../funcConf
import { localize } from '../../../localize';
import { ResourceType } from '../../../templates/IBindingTemplate';
import { type IEventHubsConnectionWizardContext } from '../../appSettings/connectionSettings/eventHubs/IEventHubsConnectionWizardContext';
import { getBindingSetting } from '../../createFunction/IFunctionWizardContext';
import { getBindingSetting, type FunctionV2WizardContext, type IFunctionWizardContext } from '../../createFunction/IFunctionWizardContext';
import { EventHubsNamespaceListStep } from '../../createFunction/durableSteps/netherite/EventHubsNamespaceListStep';
import { type IBindingWizardContext } from '../IBindingWizardContext';
import { BindingSettingStepBase } from './BindingSettingStepBase';
import { LocalAppSettingCreateStep } from './LocalAppSettingCreateStep';
import { LocalAppSettingNameStep } from './LocalAppSettingNameStep';
Expand All @@ -33,7 +32,7 @@ const showHiddenValuesItem = { label: localize('showHiddenValues', '$(eye) Show
const hideHiddenValuesItem = { label: localize('hideHiddenValues', '$(eye-closed) Hide hidden values'), data: 'hiddenValues' }
export class LocalAppSettingListStep extends BindingSettingStepBase {
private _showHiddenValues: boolean = false;
public async promptCore(context: IBindingWizardContext): Promise<BindingSettingValue> {
public async promptCore(context: IFunctionWizardContext): Promise<BindingSettingValue> {
const localSettingsPath: string = path.join(context.projectPath, localSettingsFileName);
const settings: ILocalSettingsJson = await getLocalSettingsJson(context, localSettingsPath);
const existingSettings: [string, string][] = settings.Values ? Object.entries(settings.Values) : [];
Expand All @@ -43,7 +42,10 @@ export class LocalAppSettingListStep extends BindingSettingStepBase {
do {
let picks: IAzureQuickPickItem<string | undefined>[] = [{ label: localize('newAppSetting', '$(plus) Create new local app setting'), data: undefined }];
picks = picks.concat(existingSettings.map((s: [string, string]) => { return { data: s[0], label: s[0], description: this._showHiddenValues ? s[1] : '******' }; }));
picks.push(this._showHiddenValues ? hideHiddenValuesItem : showHiddenValuesItem);
if (picks.length > 1) {
// don't add hidden values item if there are no existing settings
picks.push(this._showHiddenValues ? hideHiddenValuesItem : showHiddenValuesItem);
}
result = (await context.ui.showQuickPick(picks, { placeHolder })).data;
if (result === 'hiddenValues') {
this._showHiddenValues = !this._showHiddenValues;
Expand All @@ -54,11 +56,11 @@ export class LocalAppSettingListStep extends BindingSettingStepBase {
} while (true);
}

public async getSubWizard(context: IBindingWizardContext): Promise<IWizardOptions<IBindingWizardContext> | undefined> {
public async getSubWizard(context: IFunctionWizardContext): Promise<IWizardOptions<IFunctionWizardContext & FunctionV2WizardContext> | undefined> {
if (!getBindingSetting(context, this._setting)) {
const azurePromptSteps: AzureWizardPromptStep<IBindingWizardContext & ISubscriptionActionContext & IEventHubsConnectionWizardContext>[] = [];
const azureExecuteSteps: AzureWizardExecuteStep<IBindingWizardContext & ISubscriptionActionContext & IEventHubsConnectionWizardContext>[] = [];
switch (this._setting.resourceType) {
const azurePromptSteps: AzureWizardPromptStep<IFunctionWizardContext & ISubscriptionActionContext & IEventHubsConnectionWizardContext>[] = [];
const azureExecuteSteps: AzureWizardExecuteStep<IFunctionWizardContext & ISubscriptionActionContext & IEventHubsConnectionWizardContext>[] = [];
switch (this._resourceType) {
case ResourceType.DocumentDB:
azurePromptSteps.push(new CosmosDBListStep());
azureExecuteSteps.push(new CosmosDBConnectionCreateStep(this._setting));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@

import { type BindingSettingValue } from '../../../funcConfig/function';
import { localize } from '../../../localize';
import { nonNullProp } from '../../../utils/nonNull';
import { type IBindingWizardContext } from '../IBindingWizardContext';
import { BindingSettingStepBase } from './BindingSettingStepBase';

export class LocalAppSettingNameStep extends BindingSettingStepBase {
public async promptCore(context: IBindingWizardContext): Promise<BindingSettingValue> {
const appSettingSuffix: string = `_${nonNullProp(this._setting, 'resourceType').toUpperCase()}`;
const appSettingSuffix: string = `_${this._resourceType.toUpperCase()}`;
return await context.ui.showInputBox({
placeHolder: localize('appSettingKeyPlaceholder', 'Local app setting key'),
prompt: localize('appSettingKeyPrompt', 'Provide a key for a connection string'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

import { type IStorageAccountWizardContext } from '@microsoft/vscode-azext-azureutils';
import { getStorageConnectionString } from '../../appSettings/connectionSettings/getLocalConnectionSetting';
import { type IBindingWizardContext } from '../IBindingWizardContext';
import { type IFunctionWizardContext } from '../../createFunction/IFunctionWizardContext';
import { AzureConnectionCreateStepBase, type IConnection } from './AzureConnectionCreateStepBase';

export class StorageConnectionCreateStep extends AzureConnectionCreateStepBase<IStorageAccountWizardContext & IBindingWizardContext> {
public async getConnection(context: IStorageAccountWizardContext & Partial<IBindingWizardContext>): Promise<IConnection> {
export class StorageConnectionCreateStep extends AzureConnectionCreateStepBase<IStorageAccountWizardContext & IFunctionWizardContext> {
public async getConnection(context: IStorageAccountWizardContext & IFunctionWizardContext): Promise<IConnection> {
return await getStorageConnectionString(context);
}

public shouldExecute(context: IStorageAccountWizardContext & Partial<IBindingWizardContext>): boolean {
public shouldExecute(context: IStorageAccountWizardContext & IFunctionWizardContext): boolean {
return !!context.storageAccount || !!context.useStorageEmulator;
}
}
19 changes: 10 additions & 9 deletions src/commands/addBinding/settingSteps/StorageTypePromptStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@ import { StorageAccountKind, StorageAccountListStep, StorageAccountPerformance,
import { AzureWizardPromptStep, type AzureWizardExecuteStep, type IAzureQuickPickItem, type ISubscriptionActionContext, type IWizardOptions } from "@microsoft/vscode-azext-utils";
import { localize } from "../../../localize";
import { type IBindingSetting } from "../../../templates/IBindingTemplate";
import { type ParsedInput } from "../../../templates/script/parseScriptTemplatesV2";
import { type IEventHubsConnectionWizardContext } from "../../appSettings/connectionSettings/eventHubs/IEventHubsConnectionWizardContext";
import { type IBindingWizardContext } from "../IBindingWizardContext";
import { type IFunctionWizardContext } from "../../createFunction/IFunctionWizardContext";
import { StorageConnectionCreateStep } from "./StorageConnectionCreateStep";

export class StorageTypePromptStep extends AzureWizardPromptStep<IBindingWizardContext> {
private readonly _setting: IBindingSetting;
export class StorageTypePromptStep extends AzureWizardPromptStep<IFunctionWizardContext> {
private readonly _setting: IBindingSetting | ParsedInput;

constructor(setting: IBindingSetting) {
constructor(setting: IBindingSetting | ParsedInput) {
super();
this._setting = setting;
}

public async prompt(context: IBindingWizardContext): Promise<void> {
public async prompt(context: IFunctionWizardContext): Promise<void> {
const picks: IAzureQuickPickItem<boolean>[] = [
{ label: localize('useAzurite', 'Use Azurite emulator for local storage'), data: true },
{ label: localize('useAzureStorage', 'Use Azure Storage for remote storage'), data: false }
Expand All @@ -29,13 +30,13 @@ export class StorageTypePromptStep extends AzureWizardPromptStep<IBindingWizardC
return;
}

public shouldPrompt(context: IBindingWizardContext): boolean {
public shouldPrompt(context: IFunctionWizardContext): boolean {
return context.useStorageEmulator === undefined;
}

public async getSubWizard(context: IBindingWizardContext): Promise<IWizardOptions<IBindingWizardContext> | undefined> {
const promptSteps: AzureWizardPromptStep<IBindingWizardContext & ISubscriptionActionContext & IEventHubsConnectionWizardContext>[] = [];
const executeSteps: AzureWizardExecuteStep<IBindingWizardContext & ISubscriptionActionContext & IEventHubsConnectionWizardContext>[] = [];
public async getSubWizard(context: IFunctionWizardContext): Promise<IWizardOptions<IFunctionWizardContext> | undefined> {
const promptSteps: AzureWizardPromptStep<IFunctionWizardContext & ISubscriptionActionContext & IEventHubsConnectionWizardContext>[] = [];
const executeSteps: AzureWizardExecuteStep<IFunctionWizardContext & ISubscriptionActionContext & IEventHubsConnectionWizardContext>[] = [];

if (!context.useStorageEmulator) {
promptSteps.push(new StorageAccountListStep(
Expand Down
6 changes: 4 additions & 2 deletions src/commands/addBinding/settingSteps/StringPromptStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@

import { type BindingSettingValue } from "../../../funcConfig/function";
import { localize } from "../../../localize";
import { type IBindingSetting } from "../../../templates/IBindingTemplate";
import { type IBindingWizardContext } from "../IBindingWizardContext";
import { BindingSettingStepBase } from "./BindingSettingStepBase";

// not used by v2 schema so assume IBindingSetting
export class StringPromptStep extends BindingSettingStepBase {
public async promptCore(context: IBindingWizardContext): Promise<BindingSettingValue> {
return await context.ui.showInputBox({
placeHolder: this._setting.label,
prompt: this._setting.description || localize('stringSettingPrompt', 'Provide a \'{0}\'', this._setting.label),
prompt: (this._setting as IBindingSetting).description || localize('stringSettingPrompt', 'Provide a \'{0}\'', this._setting.label),
validateInput: async (s): Promise<string | undefined> => await this.validateInput(context, s),
value: await this.getDefaultValue(context)
});
Expand All @@ -25,6 +27,6 @@ export class StringPromptStep extends BindingSettingStepBase {

// eslint-disable-next-line @typescript-eslint/require-await
public async validateInput(_wizardContext: IBindingWizardContext, val: string | undefined): Promise<string | undefined> {
return this._setting.validateSetting(val);
return (this._setting as IBindingSetting).validateSetting(val);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { type CosmosDBManagementClient, type DatabaseAccountGetResults, type Dat
import { getResourceGroupFromId } from '@microsoft/vscode-azext-azureutils';
import { createCosmosDBClient } from '../../../../utils/azureClients';
import { nonNullProp } from '../../../../utils/nonNull';
import { type IBindingWizardContext } from '../../IBindingWizardContext';
import { type IFunctionWizardContext } from '../../../createFunction/IFunctionWizardContext';
import { AzureConnectionCreateStepBase, type IConnection } from '../AzureConnectionCreateStepBase';
import { type ICosmosDBWizardContext } from './ICosmosDBWizardContext';

export class CosmosDBConnectionCreateStep extends AzureConnectionCreateStepBase<IBindingWizardContext & ICosmosDBWizardContext> {
export class CosmosDBConnectionCreateStep extends AzureConnectionCreateStepBase<IFunctionWizardContext & ICosmosDBWizardContext> {
public async getConnection(context: ICosmosDBWizardContext): Promise<IConnection> {
const databaseAccount: DatabaseAccountGetResults = nonNullProp(context, 'databaseAccount');
const name: string = nonNullProp(databaseAccount, 'name');
Expand Down
Loading
Loading