diff --git a/.gitignore b/.gitignore index a2c073ee71..6018c77067 100644 --- a/.gitignore +++ b/.gitignore @@ -333,6 +333,7 @@ ASALocalRun/ .mfractor/ # Ignore compiled files from the extension +**/extension/logs/ **/out/ !src/extension/locales/**/out/ src/extension/package.nls.*.json diff --git a/build b/build index ac8edafe23..d7fdebd5c1 100755 --- a/build +++ b/build @@ -3,7 +3,6 @@ yarn --cwd ./src/client build yarn --cwd ./src/extension install yarn --cwd ./src/extension build - dotnet publish src/CoreTemplateStudio/code/src/CoreTemplateStudio/CoreTemplateStudio.Cli/CoreTemplateStudio.Cli.csproj -c debug -r win-x64 --self-contained true -o src/extension/src/corets-cli/win32/ dotnet publish src/CoreTemplateStudio/code/src/CoreTemplateStudio/CoreTemplateStudio.Cli/CoreTemplateStudio.Cli.csproj -c debug -r linux-x64 --self-contained true -o src/extension/src/corets-cli/linux/ dotnet publish src/CoreTemplateStudio/code/src/CoreTemplateStudio/CoreTemplateStudio.Cli/CoreTemplateStudio.Cli.csproj -c debug -r osx-x64 --self-contained true -o src/extension/src/corets-cli/darwin/ \ No newline at end of file diff --git a/docs/application-architecture.md b/docs/application-architecture.md deleted file mode 100644 index 03298d2c63..0000000000 --- a/docs/application-architecture.md +++ /dev/null @@ -1,69 +0,0 @@ -Web Template Studio is a [Visual Studio Code Extension](https://code.visualstudio.com/api) built in [Typescript](https://www.typescriptlang.org/)/[React.js](https://reactjs.org/). It leverages the templating engine ([Core Template Studio](https://github.com/Microsoft/CoreTemplateStudio)) used by [Windows Template Studio](https://github.com/Microsoft/WindowsTemplateStudio). For more info on the terminology, please refer to the [terminology document](./terminology.md). - -[Core Template Studio](https://github.com/Microsoft/CoreTemplateStudio) serves both Web and Windows Template Studios in merging the templates selected by the user. For more information on Core Template Studio, refer to its [documentation](https://github.com/Microsoft/CoreTemplateStudio/blob/dev/docs/getting-started-developers.md). - -[Web Template Studio](https://github.com/Microsoft/WebTemplateStudio) has two major components. The extension's backend (referred to as the [extension](https://github.com/Microsoft/WebTemplateStudio/tree/dev/src/extension)), which is written in [Typescript](https://www.typescriptlang.org/) and the front-end wizard (referred to as the [client](https://github.com/Microsoft/WebTemplateStudio/tree/dev/src/client)), written in [React.tsx](https://www.typescriptlang.org/docs/handbook/jsx.html). - -Here is a diagram that illustrates the high level functionality of each of the components: - -![Architecture Diagram](./arch-diagram.png) - -Before the extension is ready to run, the build script compiles the wizard's React code into JavaScript that gets injected into html, which then gets served using [VSCode's Webview API](https://code.visualstudio.com/api/extension-guides/webview). Visit [this page](https://github.com/Microsoft/WebTemplateStudio/blob/dev/docs/install.md) to know more about how to run the extension. As the extension is launching, it starts up the Engine (which will by default run on PORT 9502) and updates the cache with the updated templates (if any were added). The Engine will keep listening to the extension's requests such as generation, etc. - -The two components will be discussed separately later. There are a few important concepts that will help you get started on development quickly: - -## **Communication** - -The wizard runs in an isolated environment, and mimics how applications run on a browser. For example, the wizard does not have access to the local storage of the user, or any of the OS's resources/actions. For this reason, most of the logic is done in the extension. The wizard communicates with the extension using the WebView API, with a command defined for each function (look at the extension's constants file and the wizard's constants file to see the currently defined commands). -For example, if we want to send the email of a user from the extension to the wizard, you can use the VSCode object to do so: - -```js -vscode.postMessage({ - command: "sendEmailCommand", - payload: { - email: "example@email.com" - } -}); -``` - - This sends the email using the WebView API and - -```js -panel.webview.onDidReceiveMessage( - message => { - switch (message.command) { - case "sendEmailCommand": - // message.payload.email = example@email.com - return; - // other commands - } - }, - undefined, - undefined -); -``` - - receives the email. - -We receive all the commands from the extension in [App.tsx](https://github.com/Microsoft/WebTemplateStudio/blob/dev/src/client/src/App.tsx) and receive all the commands from the wizard in the [controller.ts](https://github.com/Microsoft/WebTemplateStudio/blob/dev/src/extension/src/controller.ts). You will find the documentation very helpful if you need more info on the Webview API. - -## **Separating the UI from the Logic**: - -One of our main concerns is increasing the speed of the wizard and making it as light as possible. Therefore, the wizard does not perform any expensive computations, and does not make any API requests. Most of these actions are done in the extension. So as the user navigates through the wizard, the selections are validated in the wizard and stored. When the user clicks generate, these selections will then be sent to the extension, which will deal with them synchronously. The extension starts with the templates (if any were selected), which will get sent to the Engine (Core Template Studio). After their successful generation, the extension uses Azure SDK to deploy the resources if the user selects any. - -We will briefly discuss the architecture of the extension and the wizard: - -## **Client**: - -As previously mentioned, the client is written in React.js. It keeps track of the state using Redux. If you are not familiar with Redux, we suggest familiarizing yourself with it before you start development on the wizard. - -## **Extension**: - -TODO: Explain the architecture of the extension and the key concepts to contribute. -The extension back-end is responsible for running all services pertaining to the core experience. This includes launching the VS Code WebView React Panel, hosting the core template generation engine and enabling functionality with the Azure Cloud Computing Platform. - -To communicate with the user-facing React Wizard, VS Code extension API exposes the `PostMessage()` function to communicate with the extension and vice versa. The behavior of a received message from the wizard is defined in a function delegate that gets passed to the ReactPanel from the controller. - -The controller acts as a router to and for behavior. The flow of command from client starts when the `postMessage()` gets called in the client and the reactpanel object in the extension receives it. With the argument payload `message: any` from the client, there is a property specified within message called `module`. This tells the controller which service module the message payload should be routed to. - -For more details about how to make specific contributions to the project (adding templates, services, etc.) please refer to the [FAQ](./faq.md) section. diff --git a/docs/arch-diagram.png b/docs/arch-diagram.png deleted file mode 100644 index bf774f7a26..0000000000 Binary files a/docs/arch-diagram.png and /dev/null differ diff --git a/docs/contributing/application-architecture.md b/docs/contributing/application-architecture.md new file mode 100644 index 0000000000..9467f97d7c --- /dev/null +++ b/docs/contributing/application-architecture.md @@ -0,0 +1,145 @@ +Web Template Studio is a [Visual Studio Code Extension](https://code.visualstudio.com/api) that has three major components: + + - The extension's backend (referred to as the [extension](https://github.com/Microsoft/WebTemplateStudio/tree/dev/src/extension)), which is written in [Typescript](https://www.typescriptlang.org/). + - The front-end wizard (referred to as the [client](https://github.com/Microsoft/WebTemplateStudio/tree/dev/src/client)), written in [React](https://reactjs.org/) and [Typescript](https://www.typescriptlang.org/). + - Generation engine (referred to as [Core Template Studio](https://github.com/Microsoft/CoreTemplateStudio)) written in [.NET Core](https://dotnet.microsoft.com/download). + +![Architecture Diagram](../resources/webts-architecture-diagram.png) + +All three components are included in Web Template Studio vsix. + +## Extension + +The extension is the main part of Web Template Studio. It has been built using the [Visual Studio Code Extensibility API](https://code.visualstudio.com/api) to build extensions. It is responsible for launching the client in a Visual Studio Code tab and for communication between the wizard client and the Core Template Studio CLI. It is also responsible for creating the Azure Services (App Service and CosmosDB Service) and the deployment the generated applications. + +It contains two commands that can be called from Visual Studio Code: + +- [webTemplateStudioExtension.wizardLaunch](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/extension.ts#L7-L11): This command is executed when we launch the "Web Template Studio: Launch" command from Visual Studio Code. It is responsible to start the Core Template Studio CLI in a `child_process`, synchronizing the templates and opening the wizard in a Visual Studio Code tab. While the wizard is open, it is also responsible for maintaining communication between the wizard client and the Core Template Studio CLI to obtain templates and generate projects. + +- [webTemplateStudioExtension.deployApp](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/extension.ts#L13-L18): This command is executed when we launch the "Web Template Studio: Deploy App" command from Visual Studio Code. It is responsible for deploying a generated application in Azure. Note: For this command to work properly, we need a web application generated with Web Template Studio opened and configured with an App Service. + + +## Client + +The wizard client is the visual component of the extension. It is a [React](https://reactjs.org/) app that is compiled into JavaScript that gets injected into html, which then gets served using [VSCode's Webview API](https://code.visualstudio.com/api/extension-guides/webview). It is shown in a Visual Studio Code tab when the user executes the "Web Template Studio: Launch" extension command. + +It is responsible for the interaction with the user and is responsible for collecting the name and route of the project, the selected frameworks, pages and services and sending them to the extension for processing with Core Template Studio. + +The wizard client keeps track of the state using [Redux](https://react-redux.js.org/). + +## Generation Engine (Core Template Studio) + +The Generation Engine is responsible for template synchronisation, get frameworks, get templates and generating projects. It consists of a [CLI](https://github.com/microsoft/CoreTemplateStudio/blob/dev/docs/getting-started-developers.md#cli-project) that receives requests from the extension and get processed by [Core Template Studio](https://github.com/microsoft/CoreTemplateStudio/). Once the request is processed, it returns the response in json format to the extension. + +For more Info see [Core Template Studio Docs](https://github.com/microsoft/CoreTemplateStudio/blob/dev/docs/getting-started-developers.md). + + +## Extension and CLI Core Template Studio communication + +The communication between the extension and the Core Template Studio CLI is defined in the [coreTemplateStudio.ts](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/coreTemplateStudio.ts) file. This static class is responsible for starting/stopping the Core Template Studio CLI in a `child_process`, and managing the Core Template Studio CLI requests and responses (including notifications and errors). + +It also exposes public functions to call the Core Template Studio CLI commands. Currently the functions offered by the [coreTemplateStudio](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/coreTemplateStudio.ts) class are: + +```js +- sync(payload: ICommandPayload): Promise +- getProjectTypes(): Promise +- getFrameworks(projectType: string): Promise +- getPages(projectType: string, frontendFramework: string, backendFramework: string): Promise +- getFeatures(projectType: string, frontendFramework: string, backendFramework: string): Promise +- generate(payload: ICommandPayload): Promise +``` + +To execute a Core Template Studio CLI command from the extension we have to instantiate the [coreTemplateStudio](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/coreTemplateStudio.ts) class and execute the function that has the command we want to execute. + + Example: + +```js +async getPages(): Promise { + const coreTS = CoreTemplateStudio.GetExistingInstance(); + const pages = await coreTS.getPages("projectType", "frontendFramework", "backendFramework"); + console.log(pages); + }; + } +``` + +To see the Core Template Studio CLI available commands visit [Core Template Studio Docs](https://github.com/microsoft/CoreTemplateStudio/blob/dev/docs/getting-started-developers.md#cli-project). + +## Extension and client communication + +### Client send to extension + +When the client wants to execute an extension command, it will call `vscode.postMessage()` function, passing through parameters an object with the following properties: + +- module: extension module that should process this request. +- command: extension command that should process the request. +- payload: data that we send in the request. + + Example: + +```js +vscode.postMessage({ + module: "extension-module", + command: "get-pages", + payload: { + projectType: "project type", + frontendFramework: "frontend framework", + backendFramework: "backend framework" + } + }); +``` + +When the extension create the webview (that includes the client), the `routingMessageReceieverDelegate()` function found in [controller.ts](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/controller.ts) is passed by parameters. This function is responsible for receiving client requests and locating the module that processes the request. All modules that can process customer requests are registered in [Controller.extensionModuleMap](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/controller.ts#L50-L61). + +The modules inherit from [WizardServant](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/wizardServant.ts) which is the class responsible for executing the function associated with each command, controlling errors and recording telemetry if necessary. + +NOTE: In the development environment (running the app in the browser), the Visual Studio Code extension is not available for the client to interact with. The communication is mocked using the [mockVsCodeAPI.ts](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/client/src/mockData/mockVsCodeApi.ts), which uses the native `window.postMessage()` command to send messages to the application. + +### Client receive from extension + +Messages sent from the extension are received in the `messageEventsFromExtension()` function in [App.tsx](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/client/src/App.tsx). This function configures an `addEventListener` to listen all messages sent from the extension and through a switch executes the necessary instructions according to the command received. + +Example: + +```js + function messageEventsFromExtension(){ + window.addEventListener("message", event => { + const message = event.data; + switch (message.command) { + ... + case "get-pages": + // set pages in redux store + break; + ... + } + } + } +``` + +NOTE: currently, we are developing [extensionService.ts](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/client/src/utils/extensionService/extensionService.ts) that will handle communication between client and extension through promises and will offer a simple and centralized way to call extension commands and receive responses. + +### Extension to client + +When the extension needs to send a request to the client, it will call `postMessageWebview()` function in [reactPanel.ts](https://github.com/microsoft/WebTemplateStudio/blob/dev/src/extension/src/reactPanel.ts). This function communicates with the webview (that contains the client), passing through parameters an object with the following properties: + +- command: extension command that processed the request. +- payload: data that we send in the request. + +Example: + +```js +reactPanelContext.postMessageWebview({ + command: "get-template-info", + payload: { + templatesVersion:"1.0.0.0", + wizardVersion: "1.0.0.0", + itemNameValidationConfig: [], + projectNameValidationConfig: [] + } +``` + + + + +## Separating the UI from the Logic: + +One of our main concerns is increasing the speed of the wizard and making it as light as possible. Therefore, the wizard does not perform any expensive computations, and does not make any API requests. Most of these actions are done in the extension. So as the user navigates through the wizard, the selections are validated in the wizard and stored. When the user clicks generate, these selections will then be sent to the extension, which will deal with them synchronously. The extension starts with the templates (if any were selected), which will get sent to the Engine (Core Template Studio). After their successful generation, the extension uses Azure SDK to deploy the resources if the user selects any. diff --git a/docs/generated-apps/services/azure-appservice.md b/docs/generated-apps/services/azure-appservice.md new file mode 100644 index 0000000000..8166a20e34 --- /dev/null +++ b/docs/generated-apps/services/azure-appservice.md @@ -0,0 +1,39 @@ +# Azure App Service + +Azure App Service is an HTTP-based service for hosting web applications, REST APIs, and mobile back ends. You can develop in your favorite language, be it .NET, .NET Core, Java, Ruby, Node.js, PHP, or Python. Applications run and scale with ease on both Windows and Linux-based environments. For more info about Azure App Service click [here](https://docs.microsoft.com/azure/app-service/overview). + +Web Template Studio offers you the functionality to create and deploy your application to Azure App Service from the wizard quickly and easly. + +## Getting started + +To create an Azure App Service using Web Template Studio: + +- Navigate to the "Add Optional Cloud Services" step. Click the "Add to my project" button in App Service card. + +![azure-appservice-card](../../resources/azure-appservice-card.png) + +- Select a _Subscription_ from the _Create App Service_ tab that just opened. Use the _Create New_ + option if you want to create a new _Subscription_. _**Note:**_ Create new will take you to Azure portal to create a subscription. + +- Enter a _Name_ for your azure web app. Enter a unique app name that includes only the valid characters, those are a-z, A-Z, 0-9, and -. Alternatively, you can accept the automatically generated unique name. The URL of the web app is `http://.azurewebsites.net`, where `` is your app name. + +_**Note:**_ by default, Web Template Studio creates a Resource Group with the same name as the web app. It will also create the free BASIC App Service Plan that hosts the web app. [More info for App Service Plans](https://azure.microsoft.com/en-us/pricing/details/app-service/plans/). + +![azure-appservice-card](../../resources/azure-appservice-createappservice.png) + +Once you hit generate on the summary page, Web Template Studio will create an Azure App Service that will be accessible from `http://.azurewebsites.net`. + +Web Template Studio uses an arm-template for Azure App Services (generated under the arm-templates directory). This template contains the definitions and parameters for all resources that need to deploy. Once Azure receives your template, it takes about 2-3 minutes to create the App Service and the App Service Plan. The app service initially contains an empty web app. + +_**Note:**_ For advanced users, the _arm templates_ +used to deploy your application are also available under the _arm-templates_ directory (in your generated project). + +## How to deploy + +When we create a Azure App Service, it initially contains an empty web app. To learn how to deploy your generated application to the created Azure App Service, read the [Web Template Studio deployment documentation](../../deployment.md). + +## VSCode Extension for Azure App Service + +To manage Azure App Service you can use the [Azure App Service extension for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureappservice), which is automatically installed with Web Template Studio. + +This extension helps you create, manage, and deploy your websites quickly. diff --git a/docs/services/azure-cosmos.md b/docs/generated-apps/services/azure-cosmos.md similarity index 82% rename from docs/services/azure-cosmos.md rename to docs/generated-apps/services/azure-cosmos.md index 024404a3d4..f9171413de 100644 --- a/docs/services/azure-cosmos.md +++ b/docs/generated-apps/services/azure-cosmos.md @@ -11,20 +11,19 @@ generates to your database instance. To deploy Cosmos DB using Web Template Studio: -![azure-cosmos-modal](../resources/azure-cosmos-modal.png) +- Navigate to the "Add Optional Cloud Services" step. Click the "Add to my project" button in CosmosDB card. -- Click _Add Resource_ on Cosmos DB under _Services_ tab +![azure-cosmos-card](../../resources/azure-cosmos-services-card.png) -- Select a _Subscription_ and _Resource Group_ from the _Create Cosmos DB Account_ tab that just opened. Use _Create New_ - option if you want to create a new _Subscription_ or _Resource Group. _**Note:**\_ New subscription will take you to Azure portal to create a subscription. +- Select a _Subscription_ from the _Create Cosmos DB Account_ tab that just opened. Use _Create New_ + option if you want to create a new _Subscription_. _**Note:**_ Create new will take you to Azure portal to create a subscription. - Enter a _Name_ for your cosmos account. This name is globally unique since your database will be available as `.documents.azure.com`. -- Select a _Location_ where your Cosmos DB instance will be deployed initially. You can scale it to multiple locations - through the Azure portal after! - -- Select an API for your database (Mongo/Core (SQL)/Azure Table/Cassandra/Gremlin (GraphQL) etc). +- Select an API for your database. _**Note:**_ Web Template Studio only supports MongoDB API and SQL API. + +![azure-cosmos-modal](../../resources/azure-cosmos-modal.png) Once you hit generate on the summary page, Web Template Studio will deploy your database and display a popup with your database connection string once it's available (usually within 5-6 minutes). This will prompt you to replace the @@ -50,7 +49,7 @@ file! ## Cosmos DB in Azure Portal -![azure-cosmos-portal](../resources/azure-cosmos-portal.png) +![azure-cosmos-portal](../../resources/azure-cosmos-portal.png) You can access and modify your database instance through the [Azure portal](https://portal.azure.com). Once you login to the portal, select Azure Cosmos DB from the menu bar on the left side. This will list different database @@ -60,7 +59,7 @@ collections, setting up firewalls, viewing metrics for your deployment etc. ## VSCode Extension for Azure Cosmos DB -![azure-cosmos-extension](../resources/azure-cosmos-extension.png) +![azure-cosmos-extension](../../resources/azure-cosmos-extension.png) If you would like to manage your Cosmos DB environment from VSCode itself, we recommend you install the [Azure Cosmos](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-cosmosdb) extension for VSCode. diff --git a/docs/resources/azure-appservice-card.png b/docs/resources/azure-appservice-card.png new file mode 100644 index 0000000000..136c35a6b0 Binary files /dev/null and b/docs/resources/azure-appservice-card.png differ diff --git a/docs/resources/azure-appservice-createappservice.png b/docs/resources/azure-appservice-createappservice.png new file mode 100644 index 0000000000..489022ab6c Binary files /dev/null and b/docs/resources/azure-appservice-createappservice.png differ diff --git a/docs/resources/azure-cosmos-modal.png b/docs/resources/azure-cosmos-modal.png index 2b8db59d24..00b1a59a68 100644 Binary files a/docs/resources/azure-cosmos-modal.png and b/docs/resources/azure-cosmos-modal.png differ diff --git a/docs/resources/azure-cosmos-services-card.png b/docs/resources/azure-cosmos-services-card.png new file mode 100644 index 0000000000..0ba9e6371c Binary files /dev/null and b/docs/resources/azure-cosmos-services-card.png differ diff --git a/docs/resources/webts-architecture-diagram.png b/docs/resources/webts-architecture-diagram.png new file mode 100644 index 0000000000..39c4516bd9 Binary files /dev/null and b/docs/resources/webts-architecture-diagram.png differ diff --git a/docs/services/azure-functions.md b/docs/services/azure-functions.md deleted file mode 100644 index e2486c96a2..0000000000 --- a/docs/services/azure-functions.md +++ /dev/null @@ -1,123 +0,0 @@ -# Azure Functions - -Azure Functions is a serverless compute service that enables you to run code on-demand without having to explicitly -provision or manage infrastructure. Think of it as deploying functions that executes on pre-defined triggers instead of -having to write and manage a full-fledged server yourself. One of the most commonly used triggers is an HTTPTrigger which -is a function that runs whenever it receives an HTTP request. This is essentially the same as an API endpoint. Web -Template Studio allows you to deploy a function app with multiple 'hello world' HTTPTrigger functions (maximum of 10) so -you can get to writing your business logic as soon as possible! - -## Getting started - -Deploying an Azure Function application using Web Template Studio: - -![azure-functions-modal](../resources/azure-functions-modal.png) - -- Click _Add Resource_ on Azure Functions under _Services_ tab - -- Select a _Subscription_ and _Resource Group_ from the _Create Functions Application_ tab that just opened. Use _Create - New_ if you want to create a new subscription or resource group. _**Note:**_ New subscription will take you to the Azure - portal to create a subscription. - -- Enter an _App Name_ for your function app. This name has to be globally unique since your app will be available as - `.azurewebsites.net`. - -- Select a _Location_ where your function app will be deployed. You want it to be closer to your users (or servers if it's - running as a back-end service helper). - -- Select a _Runtime_ for your functions. This is the programming language/framework you want to write your - functions in. - -- Select the _Number of Functions_ needed for your application. This number can be thought of as the number of endpoints - your application would need. You can rename your functions from the summary bar on the right side of the - application. These would be available as `.azurewebsites.net/api/`. - -The _hello world_ functions deployed are pretty basic and just return _"Hello, ``"_ on a query/header with the -variable 'name'. For example: `.azurewebsites.net/api/?name=John+Doe` will return -_"Hello, John Doe"_. - -## How this works - -Once you hit generate, Web Template Studio creates a directory with the same name as your Function's _App Name_ under your -generated project. This is compressed to a _.zip_ and deployed (using kudu zip deploy) to your newly created function -application. _**Note:**_ For advanced users, the _arm templates_ used to deploy your application are also available -under the _arm-templates_ directory (inside your generated project). - -## Calling your function - -Since all functions deployed through Web Template Studio are HTTP Triggers, you can invoke a function with an HTTP request. -You can use your favorite HTTP Client library (for example Axios, Fetch, Request etc.) to hit the endpoints exposed -by your function application. An individual function (assume it's called `function1`) under an application with _appName_ -`my-functions-app` is available at `my-functions-app.azurewebsites.net/api/function1`. - -### Examples - -Let's assume we have a Hello World function application with appName `my-functions-app` and a function `function1` that returns _"Hello, -``"_ on a query/header with the variable 'name' - -- Using Fetch with Javascript: - -```js -fetch( - "https://`my-functions-app.azurewebsites.net/api/function1?name=John+Doe", - { - method: "GET" - } -) - .then(res => { - // this would print `Hello John Doe` - console.log(res); - }) - .catch(err => { - console.error(err); - }); -``` - -- Using Axios with Javascript - -```js -axios - .get( - "https://`my-functions-app.azurewebsites.net/api/function1?name=John+Doe" - ) - .then(res => { - // this would print `Hello John Doe` - console.log(res); - }) - .catch(err => { - console.error(err); - }); -``` - -## Functions app in Azure Portal - -![azure-functions-portal](../resources/azure-functions-portal.png) - -You can configure your Function Application's advanced settings (like configuring a domain, storage accounts, -delete your application etc.) from the [azure portal](https://portal.azure.com). Once you login to the portal, select -**Function Apps** from the menu bar on the left side and select your application. Your individual functions are listed -under _Functions_ and you can monitor/integrate them here. Everything you need to manage/configure about your Function -Application can be done through the portal. - -## Editing your functions and deploying the changes - -We strongly encourage you to install the [Azure Functions](https://marketplace.visualstudio.com/items? -itemName=ms-azuretools.vscode-azurefunctions) extension for VSCode by **Microsoft** to manage your application. This -enables you to deploy your changes with a single click and test them out immediately instead of manually deploying the -new changes. Once you have installed this extension, here's what you need to do to deploy your changes: - -![azure-functions-extension](../resources/azure-functions-extension.png) - -- Open your Function Application's directory in a new VSCode window. Edit your function file(s). - -- Select Azure from the activity bar on VSCode and in the _Functions_ tab bar, click the `Deploy to function app...` - button and select your function application from the menu. - -- You can also add new functions using the `Create function...` button. - -- To remove a function, simply delete the corresponding files and all references to it and deploy again. - -### Deploying manually - -If you do not want to install the extension (it is _recommended_ that you install it to make your workflow easier), follow -one of the methods in the [Azure app service zip deploy tutorial](https://docs.microsoft.com/en-us/azure/app-service/deploy-zip) to manually deploy your updated functions! diff --git a/docs/telemetry.md b/docs/telemetry.md index 0218a66e4b..8db0ec16e8 100644 --- a/docs/telemetry.md +++ b/docs/telemetry.md @@ -2,6 +2,14 @@ Web Template Studio logs usage data and diagnostics telemetry through [Application Insights](https://azure.microsoft.com/en-us/services/monitor/). +The class [TelemetryService](../src/extension/src/telemetry/telemetryService.ts), within the extension code, isolates the telemetry service implementation details and offers a smooth and easy way to invoke telemetry events. + +Apart from the data logged in Web Template Studio, Core Template Studio tracks telemetry data on generation. For more info see [Core Template Studio Telemetry](https://github.com/microsoft/CoreTemplateStudio/blob/dev/docs/telemetry.md) + +## Trends + +Please head to our [Telemetry Data](telemetryData.md) where we show trends from the gathered telemetry. + ## Telemetry Gathered The wizard for Web Template Studio collects basic diagnostics telemetry and usage data: @@ -14,16 +22,69 @@ The wizard for Web Template Studio collects basic diagnostics telemetry and usag Through the Application Insights API, telemetry events are collected to gather basic information regarding Web Template Studio extension usage. The following table describes the Telemetry Events we collect: -| **Property** | **Note** | -| :-------------------: | ---------------------------------------------------------------------------------------------------- | -| **Event Time** | Timestamp for when the event occurred | -| **Event Name** | Unique event name/descriptor for the event. For ex: WebTemplateStudioVsix/Azure-Functions-Deployment | -| **VSCode Session ID** | A unique identifier for the current session. Changes each time the editor is started. | -| **VSCode Machine ID** | A unique identifier for the computer | -| **VSCode Version** | VSCode version being used by the user | -| **Extension Version** | Web Template Studio extension version being used | -| **OS** | User's operating system | -| **Error** | Error description if an error occurs | -| **Stack** | Error stack trace if an error occurs | -| **Result** | If the event succeeded or not | +|Event Name Tracked |Notes | +|:-------------:|:-----| +|**Extension-Launch**|Track when the extension starts running.| +|**Extension-closed**|Track when the extension is closed. Save the template synchronization status| +|**Sync-Engine**|Track the time it takes to synchronize the templates in the extension| +|**Create-New-Project**|Track the start of creating a new project. Save the entry-point of this action (Launch wizard or Create New Project button).| +|**Wizard-To-Generate-Session-Time**|Track the time that elapses since the extension is launched until the start generation a new project.| +|**Wizard-Page-Change**|Track the total time the user views a Web Template Studio extension page.| +|**login**|Track the time it takes for a user to log in to Azure.| +|**logout**|Track the time it takes for a user to log out of their Azure account.| +|**get-user-status**|Track the time it takes for the extension to obtain the data of a user logged in to Azure.| +|**subscription-data-for-cosmos**|Track the time that elapses when obtaining Azure CosmosDB data when selecting an Azure subscription.| +|**subscription-data-for-app-service**|Track the time that elapses when obtaining Azure App Service data when selecting an Azure subscription.| +|**Azure-App-Service-Deployment**|Track the time it takes to create an App Service in Azure.| +|**Azure-Cosmos-Deployment**|Track the time it takes to create a CosmosDB Service in Azure.| +|**Azure-Resource-Group-Deployment**|Track the time it takes to create a resource group in Azure is created.| +|**Connection-String-Replaced**|Track the time it takes for the extension to replace the connection strings when we add a Azure CosmosDB service.| +|**Press-Quickstart**|Track the event that occurs when you press the Quickstart button when you start the application.| +|**Open-Add-Pages-Modal**|Track the event that occurs when you press the Add Pages button on the right side of the extension.| +|**Open-AppService-Modal-From-Services-List**|Track the event that occurs when you press the Edit App Service button on the right side of the extension.| +|**Open-CosmosDBService-Modal-From-Services-List**|Track the event that occurs when you press the Edit CosmosDB Service button on the right side of the extension.| +|**open-project-vscode**|Track the time it takes to open the project generated in a new instance of Visual Studio Code.| +|**reset-pages**|Track the time it takes to clean the added pages while we are creating a project.| + +For events related to session and project generation see [Core Template Studio - Usage telemetry collected](https://github.com/microsoft/CoreTemplateStudio/blob/dev/docs/telemetry.md#usage-telemetry-collected). + +## Telemetry Configuration + +The TelemetryService class use [vscode-extension-telemetry](https://www.npmjs.com/package/vscode-extension-telemetry) module. The Application Insights telemetry requires a telemetry instrumentation key to be able to track telemetry. If you want to track your own telemetry, you will need your own instrumentation key, obtain one by creating an [Application Insights](https://docs.microsoft.com/azure/application-insights/app-insights-asp-net) instance in your Azure account, if you don't have an Azure account there are different options to [create one for free](https://azure.microsoft.com/en-us/free/). + +The instrumentation key is setup through in the `package.json` file from extension code: + +``` json +//package.json +{ + ... + "aiKey": "__AIKEY__", + ... +} +``` +## Send Telemetry from Extension Code + +To send telemetry from the extension code we must use the `telemetryService` class. This class defines several methods that will help us to register custom events in Application Insight. Currently the only instance of `telemetryService` is statically initialized in the` Controller` class. The methods that help us to track telemetry events are: + +- `trackEvent`: Track the event and the custom properties passed by the function parameters. +- `trackEventWithDuration`: Track the event, the custom properties and the duration calculated between the start date and the end date in seconds passed by the function parameters. +- `callWithTelemetryAndCatchHandleErrors`: Use the `callWithTelemetryAndErrorHandling` class to track the duration when executing a callback function passed by parameters. It also tracks if there has been any error or exception during the execution of the callback function. + + +## Send Telemetry from Client Code + +Communication between the client and the extension is done using sending requests with the method `vscode.postmessage` ([more info](https://code.visualstudio.com/api/extension-guides/webview#passing-messages-from-an-extension-to-a-webview)), passing through parameters the module and the extension command that have to process this request. If we want to track the client request, send the property `track: true`. + +Example: + +```javascript +vscode.postMessage({ + module: EXTENSION_MODULES.AZURE, + command: EXTENSION_COMMANDS.SUBSCRIPTION_DATA_APP_SERVICE, + track: true +}); +``` + +In extension code, the abstract class `wizardServant` (which is extended by all the modules of the extension with commands that can be called from the client code) is responsible for processing these requests and tracking the duration of the execution of the command or if an error occurred during its execution. +There is also an exclusive telemetry module in the extension, which we can call from the client to track simple events. You send this command with the `track: false` property so that the wizardServant class does not re-trace the event. diff --git a/sha256-staging-weekly.md b/sha256-staging-weekly.md index 7ea849b35d..4ebd834f71 100644 --- a/sha256-staging-weekly.md +++ b/sha256-staging-weekly.md @@ -1,3 +1,3 @@ -Version: 0.0.1929801 +Version: 0.1.1934601 -sha256: F741ED84B0FBFA12A4996A9150054D47FA7A1A7B4A30DB5ACECDBF457AD7B447 +sha256: DF6AE6F0BAB4A47A681F57D135C1127CCD320028527CB2DA8E20FCFE5E1A52AB diff --git a/src/CoreTemplateStudio b/src/CoreTemplateStudio index 7ee1292e8b..8e0d4f60eb 160000 --- a/src/CoreTemplateStudio +++ b/src/CoreTemplateStudio @@ -1 +1 @@ -Subproject commit 7ee1292e8b00a582088efe37f0a5534c4de44a74 +Subproject commit 8e0d4f60ebc19054c859e4f6f38566681266a998 diff --git a/src/client/.eslintrc.js b/src/client/.eslintrc.js new file mode 100644 index 0000000000..ae9e66e4f9 --- /dev/null +++ b/src/client/.eslintrc.js @@ -0,0 +1,50 @@ +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + extends: [ + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + parserOptions: { + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + ignorePatterns: [ + ".vscode/", + ".vscode-test/", + "logs/", + "node_modules/", + "src/assets/", + "src/translations/" + ], + "plugins": [ + "react-hooks" + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + // e.g. "@typescript-eslint/explicit-function-return-type": "off", + + //temporarily disabled until we decide which rules to enable + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/no-var-requires": "off", + "react/display-name" : "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-use-before-define": "off", + "react-hooks/exhaustive-deps": "off", + "eqeqeq": "warn", + + //React Hooks + "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks + //"react-hooks/exhaustive-deps": "warn" // Checks effect dependencies + }, + settings: { + react: { + version: "detect" // Tells eslint-plugin-react to automatically detect the version of React to use + } + } + }; \ No newline at end of file diff --git a/src/client/package.json b/src/client/package.json index 302e6954e0..c11a4a414e 100644 --- a/src/client/package.json +++ b/src/client/package.json @@ -3,6 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { + "@testing-library/react": "^9.4.0", + "@testing-library/react-hooks": "^3.2.1", "@types/classnames": "^2.2.7", "@types/jest": "23.3.13", "@types/lodash": "^4.14.121", @@ -22,8 +24,10 @@ "classnames": "^2.2.6", "focus-visible": "^5.0.2", "global": "^4.3.2", + "latest-version": "^5.1.0", "lodash": "^4.17.14", "node-fetch": "^2.3.0", + "npm": "^6.13.6", "react": "^16.7.0", "react-dom": "^16.7.0", "react-intl": "^2.8.0", @@ -36,12 +40,10 @@ "react-select": "^2.3.0", "react-sortable-hoc": "^1.7.1", "redux": "^4.0.1", + "redux-mock-store": "^1.5.4", "redux-thunk": "^2.3.0", "reselect": "^4.0.0", "rewire": "^4.0.1", - "tslint": "^5.12.1", - "tslint-microsoft-contrib": "^6.1.0", - "tslint-react": "^3.6.0", "typescript": "3.2.4", "typescript-react-intl": "^0.3.0" }, @@ -53,9 +55,8 @@ "manage:translations": "node scripts/manageTranslations.js", "test": "react-scripts test --coverage", "eject": "react-scripts eject", - "lint": "tslint -c tslint.json src/**/*.{ts,tsx}", "format": "prettier --write src/**/*.{ts,tsx}", - "tslint-check": "tslint-config-prettier-check ./tslint.json" + "lint": "eslint ./src/**/*.{ts,tsx}" }, "eslintConfig": { "extends": "react-app" @@ -69,12 +70,15 @@ "devDependencies": { "@types/enzyme": "^3.9.3", "@types/enzyme-adapter-react-16": "^1.0.5", + "@typescript-eslint/eslint-plugin": "^2.20.0", + "@typescript-eslint/parser": "^2.20.0", "enzyme": "^3.9.0", "enzyme-adapter-react-16": "^1.13.2", + "eslint": "^6.8.0", + "eslint-plugin-react": "^7.18.3", + "eslint-plugin-react-hooks": "^2.4.0", "react-intl-translations-manager": "^5.0.3", - "tslint-config-prettier": "^1.18.0", - "tslint-microsoft-contrib": "^6.1.0", - "tslint-react-hooks": "^2.0.0" + "redux-mock-store": "^1.5.4" }, "proxy": "http://localhost:9052" } diff --git a/src/client/src/App.tsx b/src/client/src/App.tsx index 548fcad1f3..0abc8e6d7a 100644 --- a/src/client/src/App.tsx +++ b/src/client/src/App.tsx @@ -2,22 +2,18 @@ import classnames from "classnames"; import * as React from "react"; import { connect } from "react-redux"; import { withRouter } from "react-router"; -import { Route, RouteComponentProps, Link } from "react-router-dom"; +import { Route, RouteComponentProps } from "react-router-dom"; import PageDetails from "./containers/PageDetails"; -import SelectFrameworks from "./containers/SelectFrameworks"; -import SelectPages from "./containers/SelectPages"; -import NewProject from "./containers/NewProject"; +import PageAddPages from "./containers/PageAddPages"; +import PageNewProject from "./containers/PageNewProject"; import CosmosResourceModal from "./containers/CosmosResourceModal"; import Footer from "./containers/Footer"; import Header from "./containers/Header"; -import ReviewAndGenerate from "./containers/ReviewAndGenerate"; +import PageReviewAndGenerate from "./containers/PageReviewAndGenerate"; import RightSidebar from "./containers/RightSidebar"; -import PostGenerationModal from "./containers/PostGenerationModal"; import RedirectModal from "./containers/RedirectModal"; import ViewLicensesModal from "./containers/ViewLicensesModal"; -import AppServiceModal from "./containers/AppServiceModal"; -import AddPagesModal from "./containers/AddPagesModal"; import { ReactComponent as HomeSplashSVG } from "./assets/homeSplash.svg"; import { ReactComponent as SummarySplashSVG } from "./assets/summarySplash.svg"; @@ -27,15 +23,14 @@ import { EXTENSION_MODULES, ROUTES, DEVELOPMENT, - FRAMEWORK_TYPE, - BOOTSTRAP_LICENSE + BOOTSTRAP_LICENSE, + FRAMEWORK_TYPE } from "./utils/constants"; import { getVSCodeApi } from "./actions/vscodeApiActions/getVSCodeApi"; import { logIntoAzureAction } from "./actions/azureActions/logIntoAzure"; import { - updateOutputPathAction, - updateProjectNameAction + updateOutputPathAction } from "./actions/wizardSelectionActions/updateProjectNameAndPath"; import { setAccountAvailability, @@ -43,17 +38,15 @@ import { setSiteNameAvailabilityAction, IAvailabilityFromExtension } from "./actions/azureActions/setAccountAvailability"; -import AzureLogin from "./containers/AzureLogin"; +import PageAzureLogin from "./containers/PageAzureLogin"; import { getSubscriptionData } from "./actions/azureActions/subscriptionData"; -import AzureFunctionsModal from "./containers/AzureFunctionsModal"; -import { setProjectPathValidation } from "./actions/wizardSelectionActions/setProjectPathValidation"; +import { setValidations } from "./actions/wizardSelectionActions/setValidations"; import { updateTemplateGenerationStatusMessageAction, updateTemplateGenerationStatusAction } from "./actions/wizardInfoActions/updateGenStatusActions"; import { - selectPagesAction, - updatePageCountAction + selectPagesAction } from "./actions/wizardSelectionActions/selectPages"; import { getVersionsDataAction } from "./actions/wizardInfoActions/getVersionData"; import { @@ -65,12 +58,10 @@ import appStyles from "./appStyles.module.css"; import { startLogOutAzure } from "./actions/azureActions/logOutAzure"; import { IVersions } from "./types/version"; import { getVSCodeApiSelector } from "./selectors/vscodeApiSelector"; -import { IPageCount } from "./reducers/wizardSelectionReducers/pageCountReducer"; import { IVSCodeObject } from "./reducers/vscodeApiReducer"; import { setAzureValidationStatusAction } from "./actions/azureActions/setAzureValidationStatusAction"; import { IServiceStatus } from "./reducers/generationStatus/genStatus"; import { resetPagesAction } from "./actions/wizardSelectionActions/selectPages"; -import { selectFrontendFramework } from "./actions/wizardSelectionActions/selectFrontEndFramework"; import { ISelected } from "./types/selected"; import { AppState } from "./reducers"; import { IOption } from "./types/option"; @@ -79,12 +70,14 @@ import { setPortAction } from "./actions/wizardContentActions/setPort"; import { ThunkDispatch } from "redux-thunk"; import RootAction from "./actions/ActionType"; import TopNavBar from "./components/TopNavBar"; -import { parseFrameworksPayload } from "./utils/parseFrameworksPayload"; -import { getBackendFrameworksSuccess } from "./actions/wizardContentActions/getBackendFrameworks"; -import { getFrontendFrameworksSuccess } from "./actions/wizardContentActions/getFrontendFrameworks"; import { getPagesOptionsAction } from "./actions/wizardContentActions/getPagesOptions"; -import frontendFramework from "./reducers/wizardSelectionReducers/selectFrontendFrameworkReducer"; -import AzureLoginModal from "./containers/AzureLoginModal"; +import PageSelectFrameworks from './containers/PageSelectFrameworks'; +import { getPages, getFrameworks } from "./utils/extensionService/extensionService"; +import AppServiceModal from "./containers/AppServiceModal"; +import PostGenerationModal from "./containers/PostGenerationModal"; +import { setBackendFrameworksAction } from "./actions/wizardContentActions/setBackendFrameworks"; +import { setFrontendFrameworksAction } from "./actions/wizardContentActions/setFrontendFrameworks"; +import { parseFrameworksPayload } from "./utils/parseFrameworksPayload"; if (process.env.NODE_ENV === DEVELOPMENT) { require("./css/themes.css"); @@ -92,7 +85,6 @@ if (process.env.NODE_ENV === DEVELOPMENT) { interface IDispatchProps { updateOutputPath: (outputPath: string) => any; - updateProjectName: (projectName: string) => any; getVSCodeApi: () => void; logIntoAzure: (email: string, subscriptions: []) => void; startLogOutToAzure: () => any; @@ -106,97 +98,104 @@ interface IDispatchProps { setSiteNameAvailability: ( isAvailableObject: IAvailabilityFromExtension ) => any; - setProjectPathValidation: (validation: any) => void; + setValidations: (validations: any) => void; setAzureValidationStatus: (status: boolean) => void; updateTemplateGenStatusMessage: (status: string) => any; updateTemplateGenStatus: (isGenerated: IServiceStatus) => any; getVersionsData: (versions: IVersions) => any; updateDependencyInfo: (dependencyInfo: IDependencyInfo) => any; - getBackendFrameworksSuccess: (frameworks: IOption[]) => any; - getFrontendFrameworksSuccess: (frameworks: IOption[]) => any; getPages: (pages: IOption[]) => any; selectPages: (pages: ISelected[]) => void; - updatePageCount: (pageCount: IPageCount) => any; resetPageSelection: () => any; - selectFrontend: (frontendFramework: ISelected) => any; setPreviewStatus: (isPreview: boolean) => void; setPort: (port: number) => void; + setPages: (pages: ISelected[]) => void; + setBackendFrameworks: (frameworks: IOption[]) => any; + setFrontendFrameworks: (frameworks: IOption[]) => any; } interface IStateProps { vscode: IVSCodeObject; frontendOptions: IOption[]; selectedFrontend: ISelected; + selectedBackend: ISelected; + selectedPages: ISelected[]; + isPreview: boolean; } type Props = IDispatchProps & IStateProps & RouteComponentProps; -class App extends React.Component { - public static defaultProps = { - getVSCodeApi: () => {}, - loadWizardContent: () => {}, - logIntoAzure: () => {}, - startLogOutToAzure: () => {}, - saveSubscriptionData: () => {}, - updateOutputPath: () => {}, - setCosmosResourceAccountNameAvailability: () => {}, - setAppNameAvailability: () => {}, - setProjectPathValidation: () => {}, - setAzureValidationStatus: () => {}, - updateDependencyInfo: () => {}, - getBackendFrameworksSuccess: () => {}, - getFrontendFrameworksSuccess: () => {}, - updateTemplateGenStatusMessage: () => {}, - updateTemplateGenStatus: () => {}, - getVersionsData: () => {}, - setPreviewStatus: () => {}, - setPort: () => {} - }; +const App = (props: Props) => { + const { selectedFrontend, selectedBackend, vscode, selectedPages, setPages, frontendOptions,isPreview, setFrontendFrameworks, setBackendFrameworks } = props; + if (frontendOptions.length === 0){ + messageEventsFromExtension(); + getFrameworksListAndSetToStore(); + } + + React.useEffect(()=>{ + props.getVSCodeApi(); + },[]); + + React.useEffect(()=>{ + const { vscode } = props; + vscode.postMessage({ + module: EXTENSION_MODULES.AZURE, + command: EXTENSION_COMMANDS.GET_USER_STATUS, + track: true + }); + },[props.vscode]); + + React.useEffect(()=>{ + loadPages(); + },[selectedFrontend, selectedBackend]); - public componentDidMount() { - this.props.getVSCodeApi(); - // listens for a login event from VSCode + function getFrameworksListAndSetToStore(){ + getFrameworks(vscode, isPreview).then((event: any)=>{ + const message = event.data; + setFrontendFrameworks( + parseFrameworksPayload( + message.payload.frameworks, + FRAMEWORK_TYPE.FRONTEND, + message.payload.isPreview + ) + ); + setBackendFrameworks( + parseFrameworksPayload( + message.payload.frameworks, + FRAMEWORK_TYPE.BACKEND, + message.payload.isPreview + ) + ); + }); + } + + const loadPages = () => { + getPages(vscode, selectedFrontend.internalName, selectedBackend.internalName).then((event)=>{ + props.getPages(event.data.payload.pages); + selectedPages.map((selectedPage)=>{ + selectedPage.internalName = `wts.Page.${selectedFrontend.internalName}.${selectedPage.defaultName ? selectedPage.defaultName.replace(" ",""):""}`; + }); + setPages(selectedPages); + }); + } + + function messageEventsFromExtension(){ window.addEventListener("message", event => { const message = event.data; switch (message.command) { - // get frameworks from extension message - case EXTENSION_COMMANDS.GET_FRAMEWORKS: - this.props.getFrontendFrameworksSuccess( - parseFrameworksPayload( - message.payload.frameworks, - FRAMEWORK_TYPE.FRONTEND, - message.payload.isPreview - ) - ); - this.props.getBackendFrameworksSuccess( - parseFrameworksPayload( - message.payload.frameworks, - FRAMEWORK_TYPE.BACKEND, - message.payload.isPreview - ) - ); - break; - case EXTENSION_COMMANDS.GET_PAGES: - this.props.getPages(message.payload.pages); - break; case EXTENSION_COMMANDS.GET_DEPENDENCY_INFO: - this.props.updateDependencyInfo(message.payload); + props.updateDependencyInfo(message.payload); break; case EXTENSION_COMMANDS.GET_OUTPUT_PATH: - if (message.payload != null && message.payload.outputPath != null) { - this.props.updateOutputPath(message.payload.outputPath); - } - break; - case EXTENSION_COMMANDS.GET_PROJECT_NAME: - if (message.payload != null && message.payload.projectName != null) { - this.props.updateProjectName(message.payload.projectName); + if (message.payload !== null && message.payload.outputPath !== undefined) { + props.updateOutputPath(message.payload.outputPath); } break; case EXTENSION_COMMANDS.GET_USER_STATUS: case EXTENSION_COMMANDS.AZURE_LOGIN: // email will be null or undefined if login didn't work correctly - if (message.payload != null) { - this.props.logIntoAzure( + if (message.payload !== null) { + props.logIntoAzure( message.payload.email, message.payload.subscriptions ); @@ -205,7 +204,7 @@ class App extends React.Component { case EXTENSION_COMMANDS.AZURE_LOGOUT: // Update UI only if user sign out is confirmed by the extension if (message.payload) { - this.props.startLogOutToAzure(); + props.startLogOutToAzure(); } break; case EXTENSION_COMMANDS.SUBSCRIPTION_DATA_FUNCTIONS: @@ -214,8 +213,8 @@ class App extends React.Component { // Expect resource groups and locations on this request // Receive resource groups and locations // and update redux (resourceGroups, locations) - if (message.payload != null) { - this.props.saveSubscriptionData({ + if (message.payload !== null) { + props.saveSubscriptionData({ locations: message.payload.locations, resourceGroups: message.payload.resourceGroups, validName: message.payload.validName @@ -225,56 +224,52 @@ class App extends React.Component { case EXTENSION_COMMANDS.NAME_COSMOS: // Receive input validation // and update redux (boolean, string) - this.props.setCosmosResourceAccountNameAvailability({ + props.setCosmosResourceAccountNameAvailability({ isAvailable: message.payload.isAvailable, message: message.payload.reason }); - this.props.setAzureValidationStatus(false); + props.setAzureValidationStatus(false); break; case EXTENSION_COMMANDS.NAME_FUNCTIONS: - this.props.setAppNameAvailability({ + props.setAppNameAvailability({ isAvailable: message.payload.isAvailable, message: message.payload.reason }); - this.props.setAzureValidationStatus(false); + props.setAzureValidationStatus(false); break; case EXTENSION_COMMANDS.NAME_APP_SERVICE: - this.props.setSiteNameAvailability({ + props.setSiteNameAvailability({ isAvailable: message.payload.isAvailable, message: message.payload.reason }); - this.props.setAzureValidationStatus(false); - break; - case EXTENSION_COMMANDS.PROJECT_PATH_VALIDATION: - this.props.setProjectPathValidation( - message.payload.projectPathValidation - ); + props.setAzureValidationStatus(false); break; case EXTENSION_COMMANDS.GEN_STATUS_MESSAGE: - this.props.updateTemplateGenStatusMessage(message.payload.status); + props.updateTemplateGenStatusMessage(message.payload.status); break; case EXTENSION_COMMANDS.GEN_STATUS: - this.props.updateTemplateGenStatus(message.payload); + props.updateTemplateGenStatus(message.payload); break; - case EXTENSION_COMMANDS.GET_VERSIONS: - this.props.getVersionsData(message.payload); + case EXTENSION_COMMANDS.GET_TEMPLATE_INFO: + const versionData: IVersions = { + templatesVersion:message.payload.templatesVersion, + wizardVersion: message.payload.wizardVersion + }; + props.getVersionsData(versionData); + props.setValidations({ + itemNameValidationConfig:message.payload.itemNameValidationConfig, + projectNameValidationConfig:message.payload.projectNameValidationConfig + }); break; case EXTENSION_COMMANDS.RESET_PAGES: if (message.payload.resetPages) { - this.props.resetPageSelection(); - const { selectedFrontend } = this.props; - - // reset page count - const key = `wts.Page.${selectedFrontend.internalName}.Blank`; - const PAGE_TYPE_COUNT: IPageCount = {}; - PAGE_TYPE_COUNT[key] = 1; - this.props.updatePageCount(PAGE_TYPE_COUNT); - + props.resetPageSelection(); + // select default blank page const PAGES_SELECTION: ISelected[] = [ { title: "Blank", - internalName: `wts.Page.${selectedFrontend.internalName}.Blank`, + internalName: `wts.Page.${message.payload.internalName}.Blank`, id: "Blank", defaultName: "Blank", isValidTitle: true, @@ -287,89 +282,73 @@ class App extends React.Component { author: "Microsoft" } ]; - this.props.selectPages(PAGES_SELECTION); + props.selectPages(PAGES_SELECTION); } break; case EXTENSION_COMMANDS.GET_PREVIEW_STATUS: - this.props.setPreviewStatus(message.payload.preview); + props.setPreviewStatus(message.payload.preview); break; } }); } - public componentDidUpdate(prevProps: Props) { - const { vscode } = this.props; - if (vscode !== prevProps.vscode) { - vscode.postMessage({ - module: EXTENSION_MODULES.AZURE, - command: EXTENSION_COMMANDS.GET_USER_STATUS, - track: true - }); - } - } - - public render() { - const { pathname } = this.props.location; - return ( - -
- - -
- - - - - - - - + const { pathname } = props.location; + return ( + +
+ -
- {pathname === ROUTES.NEW_PROJECT ? ( - - ) : null} +
+ + + + + - {pathname === ROUTES.REVIEW_AND_GENERATE ? ( - - ) : null} - - - + {pathname === ROUTES.NEW_PROJECT ? ( + - - - -
- -
-