Add support for init function app and create function

These are just simple wrappers for the cli at this point
This commit is contained in:
Eric Jizba 2017-09-21 16:21:48 -07:00
Родитель 71a8d1be9a
Коммит c86211518e
9 изменённых файлов: 144 добавлений и 14 удалений

Просмотреть файл

@ -35,8 +35,26 @@
"title": "Refresh",
"category": "Azure Functions",
"icon": {
"light": "resources/light/refresh.svg",
"dark": "resources/dark/refresh.svg"
"light": "resources/light/Refresh.svg",
"dark": "resources/dark/Refresh.svg"
}
},
{
"command": "azureFunctions.initFunctionApp",
"title": "Initialize Function App",
"category": "Azure Functions",
"icon": {
"light": "resources/light/InitFunctionApp.svg",
"dark": "resources/dark/InitFunctionApp.svg"
}
},
{
"command": "azureFunctions.createFunction",
"title": "Create Function",
"category": "Azure Functions",
"icon": {
"light": "resources/light/AddFunction.svg",
"dark": "resources/dark/AddFunction.svg"
}
},
{
@ -56,9 +74,19 @@
"menus": {
"view/title": [
{
"command": "azureFunctions.refresh",
"command": "azureFunctions.initFunctionApp",
"when": "view == azureFunctionsExplorer",
"group": "navigation@1"
},
{
"command": "azureFunctions.createFunction",
"when": "view == azureFunctionsExplorer",
"group": "navigation@2"
},
{
"command": "azureFunctions.refresh",
"when": "view == azureFunctionsExplorer",
"group": "navigation@3"
}
],
"view/item/context": [

Просмотреть файл

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-action-green{fill:#89d185}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 1.414L11.414 6H16v1.414L7.414 16H5v-1.234L7.371 10H4V8.764L4.382 8H2.019V6H0V2.018h2.019V0H6v2.018h1.373L8.382 0H16v1.414z" id="outline" style="display: none;"/><path class="icon-vs-bg" d="M9 7h6l-8 8H6l2.984-6H5l.5-1H6V7l.5-1H8V3l1-2h6L9 7z" id="iconBg"/><path class="icon-vs-action-green" d="M7 3.018H5V1H3.019v2.018H1V5h2.019v2H5V5h2V3.018z" id="colorAction"/></svg>

После

Ширина:  |  Высота:  |  Размер: 684 B

Просмотреть файл

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-folder{fill:#c09553}.icon-vs-fg{fill:#2b282e}.icon-vs-bg{fill:#c5c5c5}</style><path class="icon-canvas-transparent" d="M0 0h16v16H0V0z" id="canvas"/><path class="icon-vs-out" d="M14.996 9.418V10H16v1.352l-1.004.96v.188c0 .827-.673 1.5-1.5 1.5h-.266l-2.092 2H9.441l.961-2H1.5C.673 14 0 13.327 0 12.5v-10C0 1.673.673 1 1.5 1h8.11l1 2h2.886c.827 0 1.5.673 1.5 1.5V7H16v1.414l-1.004 1.004z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M2 3h6.374l.5 1H2V3z" id="iconBg" style="display: none;"/><g id="iconFg"><path class="icon-vs-bg" d="M12 8l-2 4h2.5L11 15l4-4h-3l3-3z"/><path class="icon-folder" d="M13.996 7V4.5a.5.5 0 0 0-.5-.5H9.992l-1-2H1.5a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5h6.882l3-6h2.614zM2 4V3h6.374l.5 1H2z"/></g></svg>

После

Ширина:  |  Высота:  |  Размер: 894 B

Просмотреть файл

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-action-green{fill:#388a34}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 1.414L11.414 6H16v1.414L7.414 16H5v-1.234L7.371 10H4V8.764L4.382 8H2.019V6H0V2.018h2.019V0H6v2.018h1.373L8.382 0H16v1.414z" id="outline" style="display: none;"/><path class="icon-vs-bg" d="M9 7h6l-8 8H6l2.984-6H5l.5-1H6V7l.5-1H8V3l1-2h6L9 7z" id="iconBg"/><path class="icon-vs-action-green" d="M7 3.018H5V1H3.019v2.018H1V5h2.019v2H5V5h2V3.018z" id="colorAction"/></svg>

После

Ширина:  |  Высота:  |  Размер: 684 B

Просмотреть файл

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-folder{fill:#dcb67a}.icon-vs-fg{fill:#f0eff1}.icon-vs-bg{fill:#424242}</style><path class="icon-canvas-transparent" d="M0 0h16v16H0V0z" id="canvas"/><path class="icon-vs-out" d="M14.996 9.418V10H16v1.352l-1.004.96v.188c0 .827-.673 1.5-1.5 1.5h-.266l-2.092 2H9.441l.961-2H1.5C.673 14 0 13.327 0 12.5v-10C0 1.673.673 1 1.5 1h8.11l1 2h2.886c.827 0 1.5.673 1.5 1.5V7H16v1.414l-1.004 1.004z" id="outline" style="display: none;"/><path class="icon-vs-fg" d="M2 3h6.374l.5 1H2V3z" id="iconBg" style="display: none;"/><g id="iconFg"><path class="icon-vs-bg" d="M12 8l-2 4h2.5L11 15l4-4h-3l3-3z"/><path class="icon-folder" d="M13.996 7V4.5a.5.5 0 0 0-.5-.5H9.992l-1-2H1.5a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5h6.882l3-6h2.614zM2 4V3h6.374l.5 1H2z"/></g></svg>

После

Ширина:  |  Высота:  |  Размер: 894 B

Просмотреть файл

@ -5,12 +5,32 @@
import * as vscode from 'vscode';
import * as opn from 'opn';
import * as util from './util';
import { INode } from './nodes';
import { FunctionsCli } from './functions-cli';
import { QuickPickItemWithData } from './util';
export class AzureFunctionsCommands {
public static openInPortal(node?: INode) {
if (node && node.tenantId) {
opn(`https://portal.azure.com/${node.tenantId}/#resource${node.id}`);
}
export function openInPortal(node?: INode) {
if (node && node.tenantId) {
opn(`https://portal.azure.com/${node.tenantId}/#resource${node.id}`);
}
}
export async function createFunction(functionsCli: FunctionsCli) {
const templates = [
new QuickPickItemWithData("BlobTrigger"),
new QuickPickItemWithData("EventGridTrigger"),
new QuickPickItemWithData("HttpTrigger"),
new QuickPickItemWithData("QueueTrigger"),
new QuickPickItemWithData("TimerTrigger")
];
const template = await util.showQuickPick(templates, "Select a function template");
const name = await util.showInputBox("Function Name", "Provide a function name");
functionsCli.createFunction(template.label, name);
}
export async function initFunctionApp(functionsCli: FunctionsCli) {
functionsCli.initFunctionApp("TODO");
}

Просмотреть файл

@ -7,12 +7,13 @@
import * as vscode from 'vscode';
import * as util from "./util";
import * as commands from './commands';
import { AzureAccount } from './azure-account.api';
import { AzureFunctionsExplorer } from './explorer';
import { INode } from './nodes'
import { Reporter } from './telemetry';
import { AzureFunctionsCommands } from './commands';
import { FunctionsCli } from './functions-cli'
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(new Reporter(context));
@ -25,8 +26,14 @@ export function activate(context: vscode.ExtensionContext) {
const explorer = new AzureFunctionsExplorer(azureAccount);
context.subscriptions.push(vscode.window.registerTreeDataProvider('azureFunctionsExplorer', explorer));
const terminal: vscode.Terminal = vscode.window.createTerminal('Azure Functions');
context.subscriptions.push(terminal);
const functionsCli = new FunctionsCli(terminal);
initCommand(context, 'azureFunctions.refresh', (node?: INode) => explorer.refresh(node));
initCommand(context, 'azureFunctions.openInPortal', (node?: INode) => AzureFunctionsCommands.openInPortal(node));
initCommand(context, 'azureFunctions.openInPortal', (node?: INode) => commands.openInPortal(node));
initCommand(context, 'azureFunctions.createFunction', (node?: INode) => commands.createFunction(functionsCli));
initCommand(context, 'azureFunctions.initFunctionApp', (node?: INode) => commands.initFunctionApp(functionsCli));
} else {
vscode.window.showErrorMessage("The Azure Account Extension is required for the Azure Functions extension.");
}
@ -48,9 +55,14 @@ function initAsyncCommand(context: vscode.ExtensionContext, commandId: string, c
try {
await callback(...args);
} catch (error) {
result = 'Failed';
errorData = util.errorToString(error);
throw error;
if (error instanceof util.UserCancelledError) {
result = 'Canceled';
// Swallow the error so that it's not displayed to the user
} else {
result = 'Failed';
errorData = util.errorToString(error);
throw error;
}
} finally {
const end = Date.now();
const properties: { [key: string]: string; } = { result: result };

26
src/functions-cli.ts Normal file
Просмотреть файл

@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as util from './util';
export class FunctionsCli {
constructor(private readonly _terminal: vscode.Terminal) {
}
createFunction(templateName: string, name: string) {
this.executeCommand(`func new --language JavaScript --template ${templateName} --name ${name}`);
}
async initFunctionApp(name: string) {
this.executeCommand(`func init`);
}
private executeCommand(command: string) {
// TODO: Verify terminal is in current working folder
this._terminal.show();
this._terminal.sendText(command);
}
}

Просмотреть файл

@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { reporter } from './telemetry';
import * as vscode from 'vscode';
export function sendTelemetry(eventName: string, properties?: { [key: string]: string; }, measures?: { [key: string]: number; }) {
if (reporter) {
@ -28,4 +29,43 @@ export function errorToString(error: any): string | undefined {
return error.toString();
}
}
}
export async function showQuickPick<T>(items: QuickPickItemWithData<T>[] | Thenable<QuickPickItemWithData<T>[]>, placeHolder: string, token?: vscode.CancellationToken): Promise<QuickPickItemWithData<T>> {
const options: vscode.QuickPickOptions = {
placeHolder: placeHolder,
ignoreFocusOut: true
}
const result = await vscode.window.showQuickPick(items, options, token);
if (!result) {
throw new UserCancelledError();
}
return result;
}
export async function showInputBox(placeHolder: string, prompt: string): Promise<string> {
const options: vscode.InputBoxOptions = {
placeHolder: placeHolder,
prompt: prompt,
// TODO: validateInput
ignoreFocusOut: true
}
const result = await vscode.window.showInputBox(options);
if (!result) {
throw new UserCancelledError();
}
return result;
}
export class QuickPickItemWithData<T> implements vscode.QuickPickItem {
readonly description: string;
constructor(readonly label: string, description?: string, readonly data?: T) {
this.description = description ? description : '';
}
}
export class UserCancelledError extends Error { }