Fix for user using command palette (#18948)

* fix for user using command palette command

* rework if a user uses the create azure function via the command

* for now only show in vs code

* move logic to azureFunctionService + address comments

* fix command location

* address comments

* fix validateFunction
This commit is contained in:
Vasu Bhog
2022-04-08 10:28:45 -07:00
committed by GitHub
parent dc14201088
commit ed8d2f9927
5 changed files with 142 additions and 42 deletions

View File

@@ -12,15 +12,110 @@ import * as constants from '../common/constants';
import * as azureFunctionsContracts from '../contracts/azureFunctions/azureFunctionsContracts';
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
import { AddSqlBindingParams, BindingType, GetAzureFunctionsParams, GetAzureFunctionsResult, ResultStatus } from 'sql-bindings';
import { IConnectionInfo } from 'vscode-mssql';
import { IConnectionInfo, ITreeNodeInfo } from 'vscode-mssql';
export const hostFileName: string = 'host.json';
export async function createAzureFunction(connectionString: string, schema: string, table: string, connectionInfo: IConnectionInfo): Promise<void> {
export async function createAzureFunction(node?: ITreeNodeInfo): Promise<void> {
// telemetry properties for create azure function
let sessionId: string = uuid.v4();
let propertyBag: { [key: string]: string } = { sessionId: sessionId };
let quickPickStep: string = '';
let exitReason: string = 'cancelled';
TelemetryReporter.sendActionEvent(TelemetryViews.CreateAzureFunctionWithSqlBinding, TelemetryActions.startCreateAzureFunctionWithSqlBinding);
let selectedBindingType: BindingType | undefined;
let connectionInfo: IConnectionInfo | undefined;
let connectionURI: string;
let listDatabases: string[] | undefined;
let objectName: string | undefined;
const vscodeMssqlApi = await utils.getVscodeMssqlApi();
if (!node) {
// if user selects command in command palette we prompt user for information
quickPickStep = 'launchFromCommandPalette';
try {
// Ask binding type for promptObjectName
quickPickStep = 'getBindingType';
let selectedBinding = await azureFunctionsUtils.promptForBindingType();
if (!selectedBinding) {
return;
}
selectedBindingType = selectedBinding.type;
propertyBag.bindingType = selectedBindingType;
TelemetryReporter.createActionEvent(TelemetryViews.CreateAzureFunctionWithSqlBinding, TelemetryActions.startCreateAzureFunctionWithSqlBinding)
.withAdditionalProperties(propertyBag).send();
// prompt user for connection profile to get connection info
quickPickStep = 'getConnectionInfo';
connectionInfo = await vscodeMssqlApi.promptForConnection(true);
if (!connectionInfo) {
// User cancelled
return;
}
TelemetryReporter.createActionEvent(TelemetryViews.CreateAzureFunctionWithSqlBinding, TelemetryActions.startCreateAzureFunctionWithSqlBinding)
.withAdditionalProperties(propertyBag).withConnectionInfo(connectionInfo).send();
// list databases based on connection profile selected
connectionURI = await vscodeMssqlApi.connect(connectionInfo);
listDatabases = await vscodeMssqlApi.listDatabases(connectionURI);
const selectedDatabase = (await vscode.window.showQuickPick(listDatabases, {
canPickMany: false,
title: constants.selectDatabase,
ignoreFocusOut: true
}));
if (!selectedDatabase) {
// User cancelled
return;
}
connectionInfo.database = selectedDatabase;
// prompt user for object name to create function from
objectName = await azureFunctionsUtils.promptForObjectName(selectedBinding.type);
if (!objectName) {
// user cancelled
return;
}
} catch (e) {
void vscode.window.showErrorMessage(utils.getErrorMessage(e));
propertyBag.quickPickStep = quickPickStep;
exitReason = 'error';
TelemetryReporter.createErrorEvent(TelemetryViews.CreateAzureFunctionWithSqlBinding, TelemetryActions.exitCreateAzureFunctionQuickpick, undefined, utils.getErrorType(e))
.withAdditionalProperties(propertyBag).send();
return;
}
} else {
quickPickStep = 'launchFromTable';
connectionInfo = node.connectionInfo;
// set the database containing the selected table so it can be used
// for the initial catalog property of the connection string
let newNode: ITreeNodeInfo = node;
while (newNode) {
if (newNode.nodeType === 'Database') {
connectionInfo.database = newNode.metadata.name;
break;
} else {
newNode = newNode.parentNode;
}
}
// Ask binding type for promptObjectName
quickPickStep = 'getBindingType';
let selectedBinding = await azureFunctionsUtils.promptForBindingType();
if (!selectedBinding) {
// User cancelled
return;
}
selectedBindingType = selectedBinding.type;
propertyBag.bindingType = selectedBinding.type;
TelemetryReporter.createActionEvent(TelemetryViews.CreateAzureFunctionWithSqlBinding, TelemetryActions.startCreateAzureFunctionWithSqlBinding)
.withAdditionalProperties(propertyBag).withConnectionInfo(connectionInfo).send();
objectName = utils.generateQuotedFullName(node.metadata.schema, node.metadata.name);
}
const connectionDetails = vscodeMssqlApi.createConnectionDetails(connectionInfo);
const connectionString = await vscodeMssqlApi.getConnectionString(connectionDetails, false, false);
TelemetryReporter.createActionEvent(TelemetryViews.CreateAzureFunctionWithSqlBinding, TelemetryActions.startCreateAzureFunctionWithSqlBinding)
.withConnectionInfo(connectionInfo).send();
@@ -101,12 +196,14 @@ export async function createAzureFunction(connectionString: string, schema: stri
try {
// get function name from user
quickPickStep = 'getAzureFunctionName';
let uniqueFunctionName = await utils.getUniqueFileName(path.dirname(projectFile), table);
// remove special characters from function name
let uniqueObjectName = utils.santizeObjectName(objectName);
let uniqueFunctionName = await utils.getUniqueFileName(path.dirname(projectFile), uniqueObjectName);
functionName = await vscode.window.showInputBox({
title: constants.functionNameTitle,
value: uniqueFunctionName,
ignoreFocusOut: true,
validateInput: input => input ? undefined : constants.nameMustNotBeEmpty
validateInput: input => utils.validateFunctionName(input)
}) as string;
if (!functionName) {
return;
@@ -115,26 +212,12 @@ export async function createAzureFunction(connectionString: string, schema: stri
.withAdditionalProperties(propertyBag)
.withConnectionInfo(connectionInfo).send();
// select input or output binding
quickPickStep = 'getBindingType';
const selectedBinding = await azureFunctionsUtils.promptForBindingType();
if (!selectedBinding) {
return;
}
propertyBag.bindingType = selectedBinding.type;
TelemetryReporter.createActionEvent(TelemetryViews.CreateAzureFunctionWithSqlBinding, TelemetryActions.startCreateAzureFunctionWithSqlBinding)
.withAdditionalProperties(propertyBag)
.withConnectionInfo(connectionInfo).send();
// set the templateId based on the selected binding type
let templateId: string = selectedBinding.type === BindingType.input ? constants.inputTemplateID : constants.outputTemplateID;
let objectName = utils.generateQuotedFullName(schema, table);
let templateId: string = selectedBindingType === BindingType.input ? constants.inputTemplateID : constants.outputTemplateID;
// We need to set the azureWebJobsStorage to a placeholder
// to suppress the warning for opening the wizard
// issue https://github.com/microsoft/azuredatastudio/issues/18780
await azureFunctionsUtils.setLocalAppSetting(path.dirname(projectFile), constants.azureWebJobsStorageSetting, constants.azureWebJobsStoragePlaceholder);
// create C# Azure Function with SQL Binding
@@ -144,8 +227,8 @@ export async function createAzureFunction(connectionString: string, schema: stri
functionName: functionName,
functionSettings: {
connectionStringSetting: constants.sqlConnectionStringSetting,
...(selectedBinding.type === BindingType.input && { object: objectName }),
...(selectedBinding.type === BindingType.output && { table: objectName })
...(selectedBindingType === BindingType.input && { object: objectName }),
...(selectedBindingType === BindingType.output && { table: objectName })
},
folderPath: projectFile
});