Service | Microsoft Docs article | Related commit history on GitHub | Change details |
---|---|---|---|
platform | Bot Sso Code | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/authentication/bot-sso-code.md | To update your app's code: - >[!NOTE] + > [!NOTE] > You might receive multiple responses for a given request if the user has multiple active endpoints. You must eliminate all duplicate or redundant responses with the token. For more information about signin/tokenExchange, see [TeamsSSOTokenExchangeMiddleware Class](/python/api/botbuilder-core/botbuilder.core.teams.teams_sso_token_exchange_middleware.teamsssotokenexchangemiddleware?view=botbuilder-py-latest#remarks&preserve-view=true). 1. Use the following code snippet for requesting a token. - # [csharp](#tab/cs2) + # [csharp](#tab/cs2) After you add the `AdapterWithErrorHandler.cs`, your code should be as shown below: To update your app's code: } ``` - # [JavaScript](#tab/js2) + # [JavaScript](#tab/js2) After you add the code snippet for `TeamsSSOTokenExchangeMiddleware`, your code should be as shown below: |
platform | Analyze Your Apps Usage In Developer Portal | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/build-and-test/analyze-your-apps-usage-in-developer-portal.md | You can view your app's usage and other insights from the **Analytics** page. To 1. Select the required app from the **Apps** page. 1. Select **Analytics** under the **Overview** or select **View details** under the **Active Users (Preview)** card. - :::image type="content" source="../../assets/images/tdp/dev-app-portal.png" alt-text="The screenshots shows you the analytics page of your app in Developer Portal."lightbox="../../assets/images/tdp/dev-app-portal.png"::: + :::image type="content" source="../../assets/images/tdp/dev-app-portal.png" alt-text="Screenshot shows you the analytics page of your app in Developer Portal."lightbox="../../assets/images/tdp/dev-app-portal.png"::: As you explore individual metrics on this page, you can use **Filter** button to analyze your app's usage from the following filter options: As you explore individual metrics on this page, you can use **Filter** button to * **Operating system** * **Area** - :::image type="content" source="../../assets/images/tdp/dev-analytics-filter.png" alt-text="The screenshots shows you the analytics page filter in Developer Portal."::: + :::image type="content" source="../../assets/images/tdp/dev-analytics-filter.png" alt-text="Screenshot shows you the analytics page filter in Developer Portal."::: After you have selected your desired filters, you can explore the following individual widgets: After you have selected your desired filters, you can explore the following indi The **Usage by time period** chart shows you the number of active users or tenants who opened and used your app across different time periods. - :::image type="content" source="../../assets/images/tdp/usage-by-time-period.png" alt-text="The screenshots shows you the usage by time period chart for your published app."::: + :::image type="content" source="../../assets/images/tdp/usage-by-time-period.png" alt-text="Screenshot shows you the usage by time period chart for your published app."::: | Metric | Definition | | :--| :| The **Usage by time period** chart shows you the number of active users or tenan The **Usage by platform and OS** chart shows your app's active usage across various endpoints, such as **Windows**, **Mac**, **iOS**, **Android**, and **Web**. The same user or tenant can use an app on multiple endpoints. Each data point represents a given R30 (Rolling 30 days) period. - :::image type="content" source="../../assets/images/tdp/usage-by-platform-OS.png" alt-text="The screenshots shows you the usage by platform and OS chart for your published app."::: + :::image type="content" source="../../assets/images/tdp/usage-by-platform-OS.png" alt-text="Screenshot shows you the usage by platform and OS chart for your published app."::: ## Usage by retention state The **Usage by retention state** chart lets you track four key retention or churn metrics for your app over time. | Metric | Definition | | :--| :| The **Usage by retention state** chart lets you track four key retention or chur The **Usage intensity** chart shows the key usage intensity metrics for your app. - :::image type="content" source="../../assets/images/tdp/usage-intensity.png" alt-text="The screenshots shows you the usage intensity chart for your published app."::: + :::image type="content" source="../../assets/images/tdp/usage-intensity.png" alt-text="Screenshot shows you the usage intensity chart for your published app."::: | Metric | Definition | | :--| :| The **My App dashboard** table shows you the latest R30 (Rolling 30 days) data f You can select each of these **Metric name** to see trends over time. - :::image type="content" source="../../assets/images/tdp/app-dashboard.png" alt-text="The screenshots shows you App dashboard chart for your published app."::: + :::image type="content" source="../../assets/images/tdp/app-dashboard.png" alt-text="Screenshots shows you app dashboard chart for your published app in Developer Portal."::: ## See also |
platform | Teams Developer Portal | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/build-and-test/teams-developer-portal.md | Title: Developer Portal for Teams -description: In this article, learn how to create a brand new app and import an existing app in Teams Developer Portal. +description: In this article, learn how to create a brand new app and import an existing app in Teams Developer Portal. Also, learn about the Changelog for Developer Portal. ms.localizationpriority: medium -> * Currently, Developer Portal is not available for Government Community Cloud (GCC)-High or Department of Defense (DOD) tenants. +> * Developer Portal isn't available for Government Community Cloud (GCC)-High or Department of Defense (DOD) tenants. > * However, you can use a regular tenant to build an app in Developer Portal, download the app, and upload the app using [Microsoft Graph](/graph/api/teamsapp-publish?view=graph-rest-1.0&tabs=http&preserve-view=true) to a national cloud. For more information, see [National cloud deployments](/graph/deployments). ## Register an app Developer Portal provides the following ways to register a Teams app: ### Create and register a brand new app -Developer portal allows you to create a brand new app: +Developer Portal allows you to create a brand new app: -1. Log into Developer Portal, select **Apps** from the left pane. +1. Sign in to [Developer Portal](https://dev.teams.microsoft.com) and select **Apps** from the left pane. - :::image type="content" source="../../assets/images/tdp/home-page.png" alt-text="The screenshot is an example that shows the Developer Portal for Teams home page." lightbox="../../assets/images/tdp/home-page.png"::: + :::image type="content" source="../../assets/images/tdp/home-page.png" alt-text="Screenshot shows the home page of Developer Portal for Teams with the Apps option highlighted in red." lightbox="../../assets/images/tdp/home-page.png"::: 1. Select **+ New app**. - :::image type="content" source="../../assets/images/tdp/new-app.png" alt-text="Create new from developer portal"::: + :::image type="content" source="../../assets/images/tdp/enter-app-name-tdp.png" alt-text="Screenshot shows how to create a brand new app in Developer Portal for Teams." lightbox="../../assets/images/tdp/create-new-app-in-tdp.png"::: 1. Enter app name and select **Add**. Developer portal allows you to create a brand new app: Now you've successfully created a brand new app and you can see all the basic information of the new app. ### Import an existing app Follow the steps to import and manage your existing app in Developer Portal: -1. Select **Apps** from the left pane of the Developer Portal. -1. Select **Import App**. +1. In Developer Portal, select **Apps** from the left pane. +1. Select **Import app**. - :::image type="content" source="../../assets/images/tdp/import-app.png" alt-text="The screenshot show how to import your existing app in Developer Portal for Teams to manage your apps." lightbox="../../assets/images/tdp/import-app.png"::: + :::image type="content" source="../../assets/images/tdp/import-app.png" alt-text="Screenshot shows how to import your existing app in Developer Portal for Teams to manage your apps." lightbox="../../assets/images/tdp/import-app.png"::: 1. Select the app manifest file, and then select **Open**. Follow the steps to import and manage your existing app in Developer Portal: * If you create an app using the Microsoft Teams Toolkit for Visual Studio Code, you can manage your app in Developer Portal. * You can import an existing app which you created on App Studio to Developer Portal. To import an already published app to Developer Portal, the [app owner](~/concepts/build-and-test/manage-your-apps-in-developer-portal.md#advanced) needs to raise a service request through [admin portal](https://admin.microsoft.com/Adminportal/Home?#/support) to transfer the ownership over the app ID. +## Changelog for Developer Portal ++Changelog for Developer Portal allows you to stay engaged with the latest updates in Teams. You can view the updates about features, recent changes in APIs, and important bug fixes. ++To view **Changelog**, sign in to [Developer Portal](https://dev.teams.microsoft.com) and select **Changelog** from the left pane. +++The updates for Changelog in Developer Portal are categorized based on the following: ++* **Added**: Updates on a service or feature that's a new feature or capability. +* **Changed**: Updates on a service or API that's modified. +* **Removed**: Updates on a service or API that's removed and may be replaced with a new and updated service. +* **Fixed**: Updates on a service or API that was previously identified as a high-priority or breaking-change issue that's fixed or mitigated. +* **Deprecated**: Updates on a service or API at the end of its life and deprecated. +* **Security**: Updates on important and critical security patch. + ## Next step > [!div class="nextstepaction"] |
platform | Launch App | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/post-publish/app-growth/launch-app.md | Contact the field, account, or engineering representatives from Microsoft to dis </details> <br> <details>-<summary>Features placements in AppSource and the Teams in-product app store</summary> +<summary>Featured placements in AppSource and the Teams in-product app store</summary> Contact your Microsoft field, account or engineering representatives or connect with the [ISV Marketplace Success Rewards Program team](mailto:rewards@microsoft.com) to feature your app in AppSource and the Teams in-client app store merchandising sections. Ensure your app experience is free of bugs to boost your chances of getting promoted on the store. |
platform | Msgex Sso Code | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/includes/messaging-extensions/msgex-sso-code.md | To update your app's code: 1. Add code snippet for `TeamsSSOTokenExchangeMiddleware`. -# [csharp](#tab/cs1) + # [csharp](#tab/cs1) -Add the following code snippet to `AdapterWithErrorHandler.cs` (or the equivalent class in your app's code): + Add the following code snippet to `AdapterWithErrorHandler.cs` (or the equivalent class in your app's code): -```csharp + ```csharp base.Use(new TeamsSSOTokenExchangeMiddleware(storage, configuration["ConnectionName"])); ``` -# [JavaScript](#tab/js1) + # [JavaScript](#tab/js1) -Add the following code snippet to `index.js` (or the equivalent class in your app's code): + Add the following code snippet to `index.js` (or the equivalent class in your app's code): -```JavaScript - const {TeamsSSOTokenExchangeMiddleware} = require('botbuilder'); - const tokenExchangeMiddleware = new TeamsSSOTokenExchangeMiddleware(memoryStorage, env.connectionName); - adapter.use(tokenExchangeMiddleware); + ```JavaScript + const {TeamsSSOTokenExchangeMiddleware} = require('botbuilder'); + const tokenExchangeMiddleware = new TeamsSSOTokenExchangeMiddleware(memoryStorage, env.connectionName); + adapter.use(tokenExchangeMiddleware); ``` Add the following code snippet to `index.js` (or the equivalent class in your ap 1. Use the following code snippet for requesting a token. -# [csharp](#tab/cs2) --After you add the `AdapterWithErrorHandler.cs`, your code should be as shown below: --```csharp - public class AdapterWithErrorHandler : CloudAdapter - { - public AdapterWithErrorHandler( - IConfiguration configuration, - IHttpClientFactory httpClientFactory, - ILogger<IBotFrameworkHttpAdapter> logger, - IStorage storage, - ConversationState conversationState) - : base(configuration, httpClientFactory, logger) - { - base.Use(new TeamsSSOTokenExchangeMiddleware(storage, configuration["ConnectionName"])); -- OnTurnError = async (turnContext, exception) => - { - // Log any leaked exception from the application. - // NOTE: In production environment, you should consider logging this to - // Azure Application Insights. Visit https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-telemetry?view=azure-bot-service-4.0&tabs=csharp to see how - // to add telemetry capture to your bot. - logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); -- // Send a message to the user. - await turnContext.SendActivityAsync("The bot encountered an error or bug."); - await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code."); -- if (conversationState != null) - { - try - { - // Delete the conversationState for the current conversation to prevent the - // bot from getting stuck in an error-loop caused by being in a bad state. - // ConversationState should be thought of as similar to "cookie-state" in a Web pages. - await conversationState.DeleteAsync(turnContext); - } - catch (Exception e) - { - logger.LogError(e, $"Exception caught on attempting to Delete ConversationState : {e.Message}"); - } - } -- // Send a trace activity, which will be displayed in the Bot Framework Emulator. - await turnContext.TraceActivityAsync( - "OnTurnError Trace", - exception.Message, - "https://www.botframework.com/schemas/error", - "TurnError"); - }; - } - } - ``` --# [JavaScript](#tab/js2) --After you add the code to `index.js`, your code should be as shown below: --```JavaScript - // index.js is used to setup and configure your bot. -- // Import required packages. - const path = require('path'); + # [csharp](#tab/cs2) ++ After you add the `AdapterWithErrorHandler.cs`, your code should be as shown below: ++ ```csharp + public class AdapterWithErrorHandler : CloudAdapter + { + public AdapterWithErrorHandler( + IConfiguration configuration, + IHttpClientFactory httpClientFactory, + ILogger<IBotFrameworkHttpAdapter> logger, + IStorage storage, + ConversationState conversationState) + : base(configuration, httpClientFactory, logger) + { + base.Use(new TeamsSSOTokenExchangeMiddleware(storage, configuration["ConnectionName"])); ++ OnTurnError = async (turnContext, exception) => + { + // Log any leaked exception from the application. + // NOTE: In production environment, you should consider logging this to + // Azure Application Insights. Visit https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-telemetry?view=azure-bot-service-4.0&tabs=csharp to see how + // to add telemetry capture to your bot. + logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); ++ // Send a message to the user. + await turnContext.SendActivityAsync("The bot encountered an error or bug."); + await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code."); ++ if (conversationState != null) + { + try + { + // Delete the conversationState for the current conversation to prevent the + // bot from getting stuck in an error-loop caused by being in a bad state. + // ConversationState should be thought of as similar to "cookie-state" in a Web pages. + await conversationState.DeleteAsync(turnContext); + } + catch (Exception e) + { + logger.LogError(e, $"Exception caught on attempting to Delete ConversationState : {e.Message}"); + } + } ++ // Send a trace activity, which will be displayed in the Bot Framework Emulator. + await turnContext.TraceActivityAsync( + "OnTurnError Trace", + exception.Message, + "https://www.botframework.com/schemas/error", + "TurnError"); + }; + } + } + ``` ++ # [JavaScript](#tab/js2) ++ After you add the code to `index.js`, your code should be as shown below: ++ ```JavaScript + // index.js is used to setup and configure your bot. ++ // Import required packages. + const path = require('path'); - // Read botFilePath and botFileSecret from .env file. - const ENV_FILE = path.join(__dirname, '.env'); - require('dotenv').config({ path: ENV_FILE }); + // Read botFilePath and botFileSecret from .env file. + const ENV_FILE = path.join(__dirname, '.env'); + require('dotenv').config({ path: ENV_FILE }); - const restify = require('restify'); + const restify = require('restify'); - // Import required bot services. - // See https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0 to learn more about the different parts of a bot. - const { - CloudAdapter, - ConversationState, - MemoryStorage, - UserState, - ConfigurationBotFrameworkAuthentication, - TeamsSSOTokenExchangeMiddleware - } = require('botbuilder'); + // Import required bot services. + // See https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0 to learn more about the different parts of a bot. + const { + CloudAdapter, + ConversationState, + MemoryStorage, + UserState, + ConfigurationBotFrameworkAuthentication, + TeamsSSOTokenExchangeMiddleware + } = require('botbuilder'); - const { TeamsBot } = require('./bots/teamsBot'); - const { MainDialog } = require('./dialogs/mainDialog'); - const { env } = require('process'); + const { TeamsBot } = require('./bots/teamsBot'); + const { MainDialog } = require('./dialogs/mainDialog'); + const { env } = require('process'); - const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(process.env); + const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(process.env); - var conname = env.connectionName; + var conname = env.connectionName; - console.log(`\n${ conname } is the con name`); + console.log(`\n${ conname } is the con name`); - // Create adapter. - // See https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0 to learn more about how bots work. - const adapter = new CloudAdapter(botFrameworkAuthentication); - const memoryStorage = new MemoryStorage(); - const tokenExchangeMiddleware = new TeamsSSOTokenExchangeMiddleware(memoryStorage, env.connectionName); + // Create adapter. + // See https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0 to learn more about how bots work. + const adapter = new CloudAdapter(botFrameworkAuthentication); + const memoryStorage = new MemoryStorage(); + const tokenExchangeMiddleware = new TeamsSSOTokenExchangeMiddleware(memoryStorage, env.connectionName); - adapter.use(tokenExchangeMiddleware); - adapter.onTurnError = async (context, error) => { - // This check writes out errors to console log .vs. app insights. - // NOTE: In production environment, you should consider logging this to Azure application insights. See https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-telemetry?view=azure-bot-service-4.0&tabs=csharp for telemetry configuration instructions. - console.error(`\n [onTurnError] unhandled error: ${ error }`); + adapter.use(tokenExchangeMiddleware); + adapter.onTurnError = async (context, error) => { + // This check writes out errors to console log .vs. app insights. + // NOTE: In production environment, you should consider logging this to Azure application insights. See https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-telemetry?view=azure-bot-service-4.0&tabs=csharp for telemetry configuration instructions. + console.error(`\n [onTurnError] unhandled error: ${ error }`); - // Send a trace activity, which will be displayed in Bot Framework Emulator. - await context.sendTraceActivity( - 'OnTurnError Trace', - `${ error }`, - 'https://www.botframework.com/schemas/error', - 'TurnError' - ); + // Send a trace activity, which will be displayed in Bot Framework Emulator. + await context.sendTraceActivity( + 'OnTurnError Trace', + `${ error }`, + 'https://www.botframework.com/schemas/error', + 'TurnError' + ); - // Send a message to the user. - await context.sendActivity('The bot encountered an error or bug.'); - await context.sendActivity('To continue to run this bot, please fix the bot source code.'); - // Clear out state. - await conversationState.delete(context); - }; + // Send a message to the user. + await context.sendActivity('The bot encountered an error or bug.'); + await context.sendActivity('To continue to run this bot, please fix the bot source code.'); + // Clear out state. + await conversationState.delete(context); + }; - // Define the state store for your bot. - // See https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-state?view=azure-bot-service-4.0&branch=live&tabs=csharp to learn more about using MemoryStorage. - // A bot requires a state storage system to persist the dialog and user state between messages. + // Define the state store for your bot. + // See https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-state?view=azure-bot-service-4.0&branch=live&tabs=csharp to learn more about using MemoryStorage. + // A bot requires a state storage system to persist the dialog and user state between messages. //const memoryStorage = new MemoryStorage(); - // Create conversation and user state with in-memory storage provider. - const conversationState = new ConversationState(memoryStorage); - const userState = new UserState(memoryStorage); + // Create conversation and user state with in-memory storage provider. + const conversationState = new ConversationState(memoryStorage); + const userState = new UserState(memoryStorage); - // Create the main dialog. - const dialog = new MainDialog(); - // Create the bot that will handle incoming messages. - const bot = new TeamsBot(conversationState, userState, dialog); + // Create the main dialog. + const dialog = new MainDialog(); + // Create the bot that will handle incoming messages. + const bot = new TeamsBot(conversationState, userState, dialog); - // Create HTTP server. - const server = restify.createServer(); - server.use(restify.plugins.bodyParser()); + // Create HTTP server. + const server = restify.createServer(); + server.use(restify.plugins.bodyParser()); - server.listen(process.env.port || process.env.PORT || 3978, function() { - console.log(`\n${ server.name } listening to ${ server.url }`); - console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator'); - console.log('\nTo talk to your bot, open the emulator select "Open Bot"'); - }); + server.listen(process.env.port || process.env.PORT || 3978, function() { + console.log(`\n${ server.name } listening to ${ server.url }`); + console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator'); + console.log('\nTo talk to your bot, open the emulator select "Open Bot"'); + }); - // Listen for incoming requests. - server.post('/api/messages', async (req, res) => { - // Route received a request to adapter for processing. - await adapter.process(req, res, (context) => bot.run(context)); - }); + // Listen for incoming requests. + server.post('/api/messages', async (req, res) => { + // Route received a request to adapter for processing. + await adapter.process(req, res, (context) => bot.run(context)); + }); - ``` + ``` -+ ### Consent dialog for getting access token private async Task<DialogTurnResult> LoginStepAsync(WaterfallStepContext stepCon # [JavaScript](#tab/js3) -```JavaScript -class MainDailog { - - this.addDialog(new OAuthPrompt(OAUTH_PROMPT, { - connectionName: process.env.connectionName, - text: 'Please Sign In', - Title: 'Sign In', - timeout: 300000 - })); -- this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT)); -- this.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [ - this.promptStep.bind(this), - this.loginStep.bind(this), - ])); -- this.initialDialogId = MAIN_WATERFALL_DIALOG; -- } --async promptStep(stepContext) { - try { - return await stepContext.beginDialog(OAUTH_PROMPT); - } catch (err) { - console.error(err); + ```JavaScript + class MainDailog { + + this.addDialog(new OAuthPrompt(OAUTH_PROMPT, { + connectionName: process.env.connectionName, + text: 'Please Sign In', + Title: 'Sign In', + timeout: 300000 + })); + + this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT)); + + this.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [ + this.promptStep.bind(this), + this.loginStep.bind(this), + ])); + + this.initialDialogId = MAIN_WATERFALL_DIALOG; + }- } --async loginStep(stepContext) { - // Get the token from the previous step. Note that we could also have gotten the - // token directly from the prompt itself. There is an example of this in the next method. - const tokenResponse = stepContext.result; - if (!tokenResponse || !tokenResponse.token) { - await stepContext.context.sendActivity('Login was not successful please try again.'); - } else { - const token = tokenResponse.token; - // On successful login, the token contains sign in token. + + async promptStep(stepContext) { + try { + return await stepContext.beginDialog(OAUTH_PROMPT); + } catch (err) { + console.error(err); + } }- return await stepContext.endDialog(); - } -``` + + async loginStep(stepContext) { + // Get the token from the previous step. Note that we could also have gotten the + // token directly from the prompt itself. There is an example of this in the next method. + const tokenResponse = stepContext.result; + if (!tokenResponse || !tokenResponse.token) { + await stepContext.context.sendActivity('Login was not successful please try again.'); + } else { + const token = tokenResponse.token; + // On successful login, the token contains sign in token. + } + return await stepContext.endDialog(); + } + ``` -+ > [!NOTE] > The code snippets use the Waterfall Dialog bot. For more information about Waterfall Dialog, see [About component and waterfall dialogs](/azure/bot-service/bot-builder-concept-waterfall-dialogs?view=azure-bot-service-4.0&preserve-view=true). |
platform | Whats New | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/whats-new.md | Teams platform features that are available to all app developers. **2023 February** +* ***February 27, 2022***: [Changelog for Developer Portal.](concepts/build-and-test/teams-developer-portal.md#changelog-for-developer-portal) * ***February 23, 2022***: [SSO authentication for your Adaptive Cards Universal Actions.](task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/enable-sso-for-your-adaptive-cards-universal-action.md) * ***February 23, 2022***: [Third party authentication for Adaptive Cards Universal Actions.](task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/authentication-flow-in-universal-action-for-adaptive-cards.md) * ***February 21, 2023***: [Targeted in-meeting notification for apps in Teams](apps-in-teams-meetings/in-meeting-notification-for-meeting.md#targeted-in-meeting-notification). * ***February 20, 2023***: [Plan your app growth in Teams.](concepts/deploy-and-publish/appsource/post-publish/app-growth/overview-app-growth.md) -* ***February 17, 2023***: [Build a dashboard tab app](tabs/how-to/build-a-dashboard-tab-app.md#build-a-dashboard-tab-app) +* ***February 17, 2023***: [Build a dashboard tab app.](tabs/how-to/build-a-dashboard-tab-app.md#build-a-dashboard-tab-app) * ***February 09, 2023***: [Apps for Teams meetings support anonymous users.](apps-in-teams-meetings/build-apps-for-anonymous-user.md) :::column-end::: |