Updates from: 02/24/2023 02:28:40
Service Microsoft Docs article Related commit history on GitHub Change details
platform In Meeting Notification For Meeting https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/in-meeting-notification-for-meeting.md
For more information on `targetedMeetingNotification`, see [Targeted meeting not
## Code sample
-Sample name | Description | .NET | Node.js | Manifest
-|-|--|--|-|-|
-| In-meeting notification | Demonstrates how to implement in-meeting notification using bot. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/nodejs) |[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/csharp/demo-manifest/meetings-notification.zip) |
-| Targeted in-meeting notification | Demonstrates how to send notifications to specific participants in a meeting stage. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/csharp) |
+Sample name | Description | .NET | Node.js |
+|-|--|--|-|
+| In-meeting notification | Demonstrates how to implement in-meeting notification using bot. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/nodejs) |
## Step-by-step guide
platform Meeting Apps Apis https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/meeting-apps-apis.md
The following table includes the response codes:
## Targeted meeting notification API
-> [!NOTE]
-> Targeted meeting notification API is available only in [public developer preview](../resources/dev-preview/developer-preview-intro.md).
- The `targetedMeetingNotification` API allows apps to send targeted in-meeting notifications to specific participants in a meeting. Apps send targeted in-meeting notifications based on user action. The API is available through bot API. ### Prerequisite
The following table provides the response codes:
## Code sample
-|Sample name | Description | .NET | Node.js | Manifest
-|-|--|--|--|--|
-| Meetings extensibility | Teams meeting extensibility sample for passing tokens. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-token-app/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-token-app/nodejs) |[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-token-app/csharp/demo-manifest/meetings-token-app.zip)
-| Meeting content bubble bot | Teams meeting extensibility sample for interacting with content bubble bot in a meeting. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/csharp/demo-manifest/meetings-notification.zip) |
-| Meeting side panel | Teams meeting extensibility sample for interacting with the side panel in-meeting. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-sidepanel/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-sidepanel/nodejs)|
-| Details Tab in Meeting | Teams meeting extensibility sample for interacting with Details Tab in-meeting. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-details-tab/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-details-tab/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-details-tab/csharp/demo-manifest/meetings-details-tab.zip)
-| Meeting Events Sample | Sample app to show real-time Teams meeting events|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-events/csharp)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-events/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-events/csharp/demo-manifest/Meetings-Events.zip)
-| Meeting Recruitment Sample |Sample app to show meeting experience for recruitment scenario.|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meeting-recruitment-app/csharp)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meeting-recruitment-app/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meeting-recruitment-app/csharp/demo-manifest/Meeting-Recruitment-App.zip)
+|Sample name | Description | .NET | Node.js | Manifest|
+|-|--|--|--||
+| Meetings extensibility | Teams meeting extensibility sample for passing tokens. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-token-app/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-token-app/nodejs) ||
+| In-meeting notification | Demonstrates how to implement in-meeting notification using bot. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-notification/nodejs)||
+| Meeting side panel | Teams meeting extensibility sample for interacting with the side panel in-meeting. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-sidepanel/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-sidepanel/nodejs)||
+| Details Tab in Meeting | Teams meeting extensibility sample for interacting with Details Tab in-meeting. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-details-tab/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-details-tab/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-details-tab/csharp/demo-manifest/meetings-details-tab.zip)|
+| Meeting Events Sample | Sample app to show real-time Teams meeting events|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-events/csharp)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-events/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meetings-events/csharp/demo-manifest/Meetings-Events.zip)|
+| Meeting Recruitment Sample |Sample app to show meeting experience for recruitment scenario.|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meeting-recruitment-app/csharp)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meeting-recruitment-app/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/meeting-recruitment-app/csharp/demo-manifest/Meeting-Recruitment-App.zip)|
## See also
platform Share In Meeting https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/build-and-test/share-in-meeting.md
keywords: Share in Meeting
Share in meeting allows users to share documents or third-party web apps to the meeting stage. The meeting participants can collaborate and interact with the third-party web apps or edit the documents together.
-> [!NOTE]
-> Share in meeting is currently available in [public developer preview](~/resources/dev-preview/developer-preview-intro.md).
- The following image shows the **Share in meeting** button on the web app: :::image type="content" source="../../assets/images/share-in-teams-meeting/web-app.png" alt-text="Screenshot shows share in meeting button on the web app.":::
platform Overview App Growth https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/post-publish/app-growth/overview-app-growth.md
YouΓÇÖll probably not be surprised to hear that not all apps are equal on any ma
1. **Build a complementary, companion experience to your core web SaaS**: Build your Teams app serving as a point solution that can be called *add-in*, *plug-in*, or an *integration*. You can build them for select, frequent, isolated and lightweight use cases relevant to be achieved inside Teams.
-1. **Build a *collaborative app* product line**: Provide Teams users a unique, differentiated, rich, familiar, end to end and deeply immersive experience ΓÇô all contained in Teams and centered around collaboration versus individual productivity. [Collaborative apps](https://www.microsoft.com/microsoft-365/blog/2021/11/02/stay-in-the-flow-of-work-with-new-collaborative-apps-for-microsoft-teams/), a new app pattern, which is designed to bring people, processes, and data together to help users thrive in the hybrid workplace are positioned to transform how people in every organization do more together with the help of ubiquitous software in the flow of work. Collaborative apps offer an experience thatΓÇÖs preferred by the user over other channels where the SaaS app exists and often use one or more of Teams-only platform capabilities such as meeting extensions, Live Share, Graph APIs, message extensions, and so on, to deliver significant user value, on top of table stake scenarios.
+1. **Build a *collaborative app* product line**: Provide Teams users a unique, differentiated, rich, familiar, end to end and deeply immersive experience ΓÇô all contained in Teams and centered around collaboration versus individual productivity. [Collaborative apps](https://www.microsoft.com/en-us/microsoft-365/blog/2021/11/02/stay-in-the-flow-of-work-with-new-collaborative-apps-for-microsoft-teams/), a new app pattern, which is designed to bring people, processes, and data together to help users thrive in the hybrid workplace are positioned to transform how people in every organization do more together with the help of ubiquitous software in the flow of work. Collaborative apps offer an experience thatΓÇÖs preferred by the user over other channels where the SaaS app exists and often use one or more of Teams-only platform capabilities such as meeting extensions, Live Share, Graph APIs, message extensions, and so on, to deliver significant user value, on top of table stake scenarios.
Needless to say, the strategy you'll adopt among the options described above will determine:
platform Succeed https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/deploy-and-publish/appsource/post-publish/app-growth/succeed.md
Strategic developers, who are part of the invite-only Teams engineeringΓÇÖs buil
<details> <summary>Case Study on MicrosoftΓÇÖs public customers portal</summary>
-Impactful case studies of how investing in a collaborative app resulted in growth for your SaaS business and how customers using your app got impacted can be published on the following customer-facing sites: [Microsoft 365 ISV Benefits Program Success Stories](https://cloudpartners.transform.microsoft.com/practices/modernworkisv?tab=success-stories) and [Customer Stories](https://customers.microsoft.com/home?sq=&ff=&p=0) on Microsoft.com. Connect with your Teams engineering representatives or the [ISV Marketplace Success Rewards Program team](mailto:rewards@microsoft.com) to check eligibility, seek guidance, and execute this motion.
+Impactful case studies of how investing in a collaborative app resulted in growth for your SaaS business and how customers using your app got impacted can be published on the following customer-facing sites: [Microsoft 365 ISV Benefits Program Success Stories](https://cloudpartners.transform.microsoft.com/practices/modernworkisv?tab=success-stories) and [Customer Stories](https://customers.microsoft.com/en-us/home?sq=&ff=&p=0) on Microsoft.com. Connect with your Teams engineering representatives or the [ISV Marketplace Success Rewards Program team](mailto:rewards@microsoft.com) to check eligibility, seek guidance, and execute this motion.
</details> <br>
platform Personal Apps https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/design/personal-apps.md
With a private workspace, users can view app content that's meaningful to them i
#### **Configure and add multiple actions in NavBar**
-You can add multiple actions to the upper right NavBar and build an overflow menu for extra actions in an app.
-
->[!NOTE]
-> A maximum of five actions can be added in the NavBar, including the overflow menu.
+You can add multiple actions to the upper right NavBar and build an overflow menu for extra actions in an app. A maximum of five actions can be added in the NavBar, including the overflow menu.
:::image type="content" source="../../assets/images/overflow-menu-and-multiple-actionsoptions.png" alt-text="The screenshot is an example thats describes the NavBar and Overflow menu.":::
-To **Configure and add multiple actions in NavBar**, call [setNavBarMenu](/javascript/api/@microsoft/teams-js/microsoftteams.menus?view=msteams-client-js-1.12.1&preserve-view=true) API. and add the `displayMode enum` property to `MenuItem`. The `displayMode enum` defines how a menu appears in the NavBar. The default value of `displayMode enum` is set to `ifRoom`.
+To **Configure and add multiple actions in NavBar**, call [setNavBarMenu](/javascript/api/@microsoft/teams-js/microsoftteams.menus?view=msteams-client-js-1.12.1&preserve-view=true) API and add the `displayMode enum` property to `MenuItem`. The `displayMode enum` defines how a menu appears in the NavBar. The default value of `displayMode enum` is set to `ifRoom`.
Based on the requirements and space available in the NavBar, set `displayMode enum` considering one of the following.
platform Build A Dashboard Tab App https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/tabs/how-to/Build-a-dashboard-tab-app.md
+
+ Title: Build a dashboard tab app
+
+description: Describes Dashboard, widget and Graph API call in Teams toolkit
+
+ms.localizationpriority: medium
+ Last updated : 01/17/2023++
+# Build a dashboard tab app
+
+A dashboard is a tool to track, analyze, and display data to gain insight of an organization or a specific process. Dashboards in Teams allow you to monitor and view important metrics.
+
+The dashboard tab template from Teams Toolkit allows you to get started with integrating a canvas with multiple cards that provide an overview of content in Teams. You can:
+
+* Use widgets to display content from apps and services within your dashboard tab.
+* Integrate your app with Graph API to visualize details about the implementation of the selected data.
+* Create customizable dashboards that allow your business to set specific goals that help you track the information you need to view in multiple areas and across departments.
++
+Your team can get the latest updates from different sources in Teams using the Teams dashboard tab app. Use dashboard tab apps to connect numerous metrics, data sources, APIs, and services to help your business extract relevant information from the sources and present it to the users. For more information about creating a dashboard tab app and the source code directory structure, see [step-by-step guide](#step-by-step-guide).
+
+## Add a new dashboard
+
+After you've created a dashboard tab app, you can add a new dashboard.
+
+To add a new dashboard, follow these steps:
+
+1. [Create a dashboard class](#create-a-dashboard-class)
+1. [Override methods to customize dashboard tab app](#override-methods-to-customize-dashboard-tab-app)
+1. [Add a route for the new dashboard tab app](#add-a-route-for-the-new-dashboard-tab-app)
+1. [Modify manifest to add a new dashboard tab app](#modify-manifest-to-add-a-new-dashboard-tab-app)
+
+### Create a dashboard class
+
+Create a file with the .tsx extension for your dashboard in the tabs/src/views/dashboards directory, for example, YourDashboard.tsx. Then, create a class that extends the [Dashboard](https://github.com/OfficeDev/TeamsFx/wiki/) class:
+
+```typescript
+
+export default class YourDashboard extends Dashboard {}
+
+```
+
+> [!NOTE]
+> All methods are optional. If you don't override any method, the default dashboard layout is used.
+
+### Override methods to customize dashboard tab app
+
+The `dashboard` class provides few methods that you can override to customize the dashboard layout. The following table lists the methods that you can override:
+
+| **Methods** | **Function** |
+|||
+| `rowHeights()` | Customize the height of each row of the dashboard. |
+| `columnWidths()` | Customize how many columns the dashboard has at most and the width of each column. |
+| `dashboardLayout()` | Define widgets layout. |
+
+The following code is an example to customize the dashboard layout:
+
+```typescript
+export default class YourDashboard extends Dashboard {
+ protected rowHeights(): string | undefined {
+ return "500px";
+ }
+
+ protected columnWidths(): string | undefined {
+ return "4fr 6fr";
+ }
+
+ protected dashboardLayout(): JSX.Element | undefined {
+ return (
+ <>
+ <SampleWidget />
+ <div style={oneColumn("6fr 4fr")}>
+ <SampleWidget />
+ <SampleWidget />
+ </div>
+ </>
+ );
+ }
+}
+```
+
+### Add a route for the new dashboard tab app
+
+You must link your widget to a data source file. The widget picks up the data that's presented in the dashboard from the source file.
+
+Open tabs/src/App.tsx file and add a route for the new dashboard. Here's an example:
+
+```typescript
+import YourDashboard from "./views/dashboards/YourDashboard";
+
+export default function App() {
+ ...
+ <Route exact path="/yourdashboard" component={YourDashboard} />
+ ...
+}
+```
+
+### Modify manifest to add a new dashboard tab app
+
+Open templates/appPackage/manifest.template.json file and add a new dashboard tab under the `staticTabs`. Here's an example:
+
+```json
+{
+ "name": "Your Dashboard",
+ "entityId": "yourdashboard",
+ "contentUrl": "{{state.fx-resource-frontend-hosting.endpoint}}{{state.fx-resource-frontend-hosting.indexPath}}/yourdashboard",
+ "websiteUrl": "{{state.fx-resource-frontend-hosting.endpoint}}{{state.fx-resource-frontend-hosting.indexPath}}/yourdashboard",
+ "scopes": ["personal"]
+}
+```
+
+## Customize the dashboard layout
+
+Teamsfx provides convenient methods to define and modify the layout of the dashboard. The following are the methods:
+
+* Three widgets in a row with the height of 350 px occupying 20 percent, 60 percent, and 20 percent of the width, respectively.
+
+ ```typescript
+ export default class SampleDashboard extends Dashboard {
+ protected rowHeights(): string | undefined {
+ return "350px";
+ }
+
+ protected columnWidths(): string | undefined {
+ return "2fr 6fr 2fr";
+ }
+
+ protected dashboardLayout(): undefined | JSX.Element {
+ return (
+ <>
+ <ListWidget />
+ <ChartWidget />
+ <NewsWidget />
+ </>
+ );
+ }
+ }
+ ```
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/customize-dashboard-layout.png" alt-text="Screenshot shows the customized dashboard layout.":::
+
+* Two widgets in a row with a width of 600 px and 1100 px. The height of the first line is the maximum height of its content, and the height of the second line is 400 px.
+
+ ```typescript
+ export default class SampleDashboard extends Dashboard {
+ protected rowHeights(): string | undefined {
+ return "max-content 400px";
+ }
+
+ protected columnWidths(): string | undefined {
+ return "600px 1100px";
+ }
+
+ protected dashboardLayout(): undefined | JSX.Element {
+ return (
+ <>
+ <ListWidget />
+ <ChartWidget />
+ <NewsWidget />
+ </>
+ );
+ }
+ }
+ ```
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/customize-dashboard-layout2.png" alt-text="Screenshot shows the customization of height and width of the dashboard layout.":::
+
+* Arrange two widgets in a column.
+
+ ```typescript
+ import { oneColumn } from '../lib/Dashboard.styles';
+ export default class SampleDashboard extends Dashboard {
+ protected rowHeights(): string | undefined {
+ return "max-content";
+ }
+
+ protected columnWidths(): string | undefined {
+ return "4fr 6fr";
+ }
+
+ protected dashboardLayout(): undefined | JSX.Element {
+ return (
+ <>
+ <NewsWidget />
+ <div style={oneColumn()}>
+ <ListWidget />
+ <ChartWidget />
+
+ </div>
+ </>
+ );
+ }
+ }
+ ```
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/widget-customize.png" alt-text="Screenshot shows the two-widget customization.":::
+
+* Customize the height of widgets in a row.
+
+ The following code can achieve a height of 400 px for the `ListWidget` and a height of 350 px for the `ChartWidget`:
+
+ ```typescript
+ import { oneColumn } from '../lib/Dashboard.styles';
+ export default class SampleDashboard extends Dashboard {
+ protected rowHeights(): string | undefined {
+ return "max-content";
+ }
+
+ protected columnWidths(): string | undefined {
+ return "4fr 6fr";
+ }
+
+ protected dashboardLayout(): undefined | JSX.Element {
+ return (
+ <>
+ <NewsWidget />
+ <div style={oneColumn("400px 350px")}>
+ <ListWidget />
+ <ChartWidget />
+ </div>
+ </>
+ );
+ }
+ }
+ ```
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/chart-widget.png" alt-text="Screenshot shows the customization of a chart widget.":::
+
+### Dashboard tab app abstraction
+
+To adjust the layout of the dashboard, Teamsfx provides a `dashboard` class for the developers to implement a dashboard.
+
+The following code is an example of a dashboard class:
+
+```typescript
+interface IDashboardState {
+ isMobile?: boolean;
+ observer?: ResizeObserver;
+}
+
+/**
+ * The dashboard class which is the base class for all dashboard components.
+ */
+export class Dashboard extends Component<any, IDashboardState> {
+ private ref: React.RefObject<HTMLDivElement>;
+
+ /**
+ * Constructor for the dashboard class. Initializes the dashboard state.
+ * @param props The properties for the dashboard.
+ */
+ constructor(props: any) {
+ super(props);
+ this.state = {
+ isMobile: undefined,
+ observer: undefined,
+ };
+ this.ref = React.createRef<HTMLDivElement>();
+ }
+
+ /**
+ * This method is invoked immediately after a component is mounted. It's a good place to fetch data from server.
+ */
+ componentDidMount(): void {
+ // Observe the dashboard div for resize events
+ const observer = new ResizeObserver((entries) => {
+ for (let entry of entries) {
+ if (entry.target === this.ref.current) {
+ const { width } = entry.contentRect;
+ this.setState({ isMobile: width < 600 });
+ }
+ }
+ });
+ observer.observe(this.ref.current!);
+ }
+
+ /**
+ * This method is invoked immediately when a component is unmounted. It's a good place to clean up the resources.
+ */
+ componentWillUnmount(): void {
+ // Unobserve the dashboard div for resize events
+ if (this.state.observer && this.ref.current) {
+ this.state.observer.unobserve(this.ref.current);
+ }
+ }
+
+ /**
+ * Define the dashboard default layout, you can edit the code here to customize your dashboard layout.
+ */
+ render() {
+ return (
+ <>
+ <div
+ ref={this.ref}
+ style={dashboardStyles(
+ this.state.isMobile,
+ this.rowHeights(),
+ this.columnWidths()
+ )}
+ >
+ {this.dashboardLayout()}
+ </div>
+ </>
+ );
+ }
+
+ /**
+ * Implement this method to define the row heights of the dashboard.
+ * For example, if you want to have 3 rows, and the height of the first row is 100px, the height of the second row is 200px, and the height of the third row is 300px, you can return "100px 200px 300px".
+ * @returns The row heights of the dashboard.
+ */
+ protected rowHeights(): string | undefined {
+ return undefined;
+ }
+
+ /**
+ * Implement this method to define the column widths of the dashboard.
+ * For example, if you want to have 3 columns, and each column occupies 1/3 of the full width, you can return "1fr 1fr 1fr".
+ * @returns The column widths of the dashboard.
+ */
+ protected columnWidths(): string | undefined {
+ return undefined;
+ }
+
+ /**
+ * Implement this method to define the dashboard layout.
+ */
+ protected dashboardLayout(): JSX.Element | undefined {
+ return undefined;
+ }
+}
+```
+
+In the `dashboard` class, Teamsfx provides basic layouts with customizable methods. The dashboard is still a react component, and Teamsfx provides basic implementations of functions based on the lifecycle of react components, such as:
+
+* Implementing a basic render logic based on the grid layout.
+* Adding an observer to automatically adapt to mobile devices.
+
+The following are the customizable methods to override:
+
+| File | Content | Recommend to override |
+||||
+| **constructor()** | Initializes the dashboard state and variables. | No |
+| **componentDidMount()** | Invokes after a component is mounted. | No |
+| **componentWillUnmount()** | Invokes when a component is unmounted. | No |
+| **render()** | Invokes when there's an update. The dashboard default layout is defined in this method. | No |
+| **rowHeights()** | Customizes the height of each row of the dashboard. | Yes |
+| **columnWidths()** | Customizes the number of columns the dashboard has at most and the width of each column. | Yes |
+| **dashboardLayout()** | Defines the widget layout in dashboard. | Yes |
+
+## Use a widget in your dashboard
+
+Widgets display configurable information and charts on dashboards. They appear on the widget board where you can pin, unpin, arrange, resize, and customize widgets to reflect your interests. Your widget board is optimized to show relevant widgets and personalized content based on your usage.
+
+### Customize the widget
+
+You can customize the widget by overriding the following methods in the `widget` class:
+
+* Override `headerContent()`, `bodyContent()`, and `footerContent()` to customize the widget.
+
+ ```typescript
+ export class NewsWidget extends Widget<void> {
+
+ headerContent(): JSX.Element | undefined {
+ return (
+ <div style={headerContentStyle()}>
+ <News28Regular />
+ <Text style={headerTextStyle()}>Your News</Text>
+ <Button icon={<MoreHorizontal32Regular />} appearance="transparent" />
+ </div>
+ );
+ }
+
+ bodyContent(): JSX.Element | undefined {
+ return (
+ <div style={contentLayoutStyle()}>
+ <Image src="image.svg" style={imageStyle()} />
+ <Text style={titleStyle()}>Lorem Ipsum Dolor</Text>
+ <Text style={descStyle()}>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Enim, elementum sed</Text>
+ </div>
+ );
+ }
+
+ footerContent(): JSX.Element | undefined {
+ return (
+ <Button
+ appearance="transparent"
+ icon={<ArrowRight16Filled />}
+ iconPosition="after"
+ size="small"
+ style={footerButtonStyle()}
+ onClick={() => { }} // navigate to detailed page
+ >
+ View details
+ </Button>
+ );
+ }
+ }
+ ```
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/override-header-count.png" alt-text="Screenshot shows the example of header, body, and footer content in a widget.":::
+
+* Override `bodyContent()` and `footerContent()` to customize the widget.
+
+ ```typescript
+ export class NewsWidget extends Widget<void> {
+
+ bodyContent(): JSX.Element | undefined {
+ return (
+ <div style={contentLayoutStyle()}>
+ <Image src="image.svg" style={imageStyle()} />
+ <Text style={titleStyle()}>Lorem Ipsum Dolor</Text>
+ <Text style={descStyle()}>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Enim, elementum sed</Text>
+ </div>
+ );
+ }
+
+ footerContent(): JSX.Element | undefined {
+ return (
+ <Button
+ appearance="transparent"
+ icon={<ArrowRight16Filled />}
+ iconPosition="after"
+ size="small"
+ style={footerButtonStyle()}
+ onClick={() => { }} // navigate to detailed page
+ >
+ View details
+ </Button>
+ );
+ }
+ }
+ ```
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/override-body-content-footer-content.png" alt-text="Screenshot shows the body and footer content in a widget.":::
+
+* Override `bodyContent()` to customize the widget.
+
+ ```typescript
+ export class NewsWidget extends Widget<void> {
+
+ bodyContent(): JSX.Element | undefined {
+ return (
+ <div style={contentLayoutStyle()}>
+ <Image src="image.svg" style={imageStyle()} />
+ <Text style={titleStyle()}>Lorem Ipsum Dolor</Text>
+ <Text style={descStyle()}>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Enim, elementum sed</Text>
+ </div>
+ );
+ }
+
+ }
+ ```
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/override-body-content.png" alt-text="Screenshot shows body content in a widget.":::
+
+### Include a data loader
+
+If you want to include a data loader to your widget before the widget is loaded, you can add a property to the state of the widget to indicate that the data loader is loading. You can use this property to show a loading indicator to the user.
+
+The following steps show how to add a property to the state of `ListWidget` and how to use it to show a loading spinner while the data is loading.
+
+1. Define a state type: Define a state type including a property named `loading` that indicates whether the data is loading.
+
+ ```typescript
+ interface ListWidgetState {
+ data: ListModel[];
+ loading?: boolean;
+ }
+ ```
+
+1. Add a data loader: Modify the `bodyContent` method to show a loading spinner if data is loading.
+
+ ```tsx
+ bodyContent(): JSX.Element | undefined {
+ return (
+ <>
+ {this.state.loading !== false ? (
+ <div style={{ display: "grid", justifyContent: "center", height: "100%" }}>
+ <Spinner label="Loading..." labelPosition="below" />
+ </div>
+ ) : (
+ <div style={bodyContentStyle()}>
+ ...
+ </div>
+ )}
+ </>
+ );
+ }
+ ```
+
+1. Hide the footer button if the data is loading.
+
+ The following code is an example of footer button:
+
+ ```tsx
+ footerContent(): JSX.Element | undefined {
+ if (this.state.loading === false) {
+ return (
+ <Button
+ ...
+ </Button>
+ );
+ }
+ }
+ ```
+
+1. Update the state reference: Update the state reference in the widget file to use the new state type and update the state in the `getData` method to set the `loading` property to `false` after the data is loaded.
+
+ Now, the loading spinner is shown while the data is loading. When the data is loaded, the loading spinner is hidden and the list data, and footer button are shown.
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/spinner.gif" alt-text="Graphical representation shows the loading spinner while the data is loading.":::
+
+### Handle empty state
+
+You can display a specific content in your widget when the data is empty. To do so, you need to modify the `bodyContent` method in your widget file to adopt different states of the data.
+
+The following example shows how to display an empty image when the data of `ListWidget` is empty.
+
+```tsx
+bodyContent(): JSX.Element | undefined {
+ let hasData = this.state.data && this.state.data.length > 0;
+ return (
+ <div style={bodyContentStyle()}>
+ {hasData ? (
+ <>
+ {this.state.data?.map((t: ListModel) => {
+ ...
+ })}
+ </>
+ ) : (
+ <div
+ style={{
+ display: "grid",
+ gap: "1rem",
+ justifyContent: "center",
+ alignContent: "center",
+ }}
+ >
+ <Image src="empty-default.svg" height="150px" />
+ <Text align="center">No data</Text>
+ </div>
+ )}
+ </div>
+ );
+ }
+```
+
+You can use a similar approach to remove the footer content of your widget when the data is empty.
+
+```tsx
+footerContent(): JSX.Element | undefined {
+ let hasData = this.state.data && this.state.data.length > 0;
+ if (hasData) {
+ return (
+ <Button
+ ...
+ </Button>
+ );
+ }
+ }
+```
+
+ :::image type="content" source="../../assets/images/sbs-create-a-new-dashboard/no-data.png" alt-text="Screenshot showing no data in the list.":::
+
+### Refresh data as scheduled
+
+The following example shows how to display real-time data in a widget. The widget displays the current time and updates.
+
+```tsx
+import { Widget } from "../lib/Widget";
+
+interface IRefreshWidgetState {
+ data: string;
+}
+
+export class RefreshWidget extends Widget<IRefreshWidgetState> {
+ bodyContent(): JSX.Element | undefined {
+ return <>{this.state.data}</>;
+ }
+
+ async componentDidMount() {
+ setInterval(() => {
+ this.setState({ data: new Date().toLocaleTimeString() });
+ }, 1000);
+ }
+}
+```
+
+You can modify `setInterval` method to call your own function to refresh data like this `setInterval(() => yourGetDataFunction(), 1000)`.
+
+### Widget abstraction
+
+To simplify the development of a widget, Teamsfx provides a `widget` class for developers to inherit to implement a widget that meets their needs without paying much attention to implement the widget layout.
+
+The following code is an example of widget class:
+
+```typescript
+export abstract class Widget<T> extends Component<any, { data?: T | void }> {
+ constructor(props: any) {
+ super(props);
+ this.state = {
+ data: undefined,
+ };
+ }
+
+ /**
+ * This method is invoked immediately after a component is mounted.
+ * It's a good place to fetch data from server.
+ */
+ async componentDidMount() {
+ this.setState({ data: await this.getData() });
+ }
+
+ /**
+ * Define your widget layout, you can edit the code here to customize your widget.
+ */
+ render() {
+ return (
+ <div style={widgetStyles()}>
+ {this.headerContent() && (
+ <div style={headerStyles()}>{this.headerContent()}</div>
+ )}
+ {this.bodyContent() && <div>{this.bodyContent()}</div>}
+ {this.footerContent() && <div>{this.footerContent()}</div>}
+ </div>
+ );
+ }
+
+ /**
+ * Get data required by the widget, you can get data from a api call or static data stored in a file. Override this method according to your needs.
+ * @returns data for the widget
+ */
+ protected async getData(): Promise<T> {
+ return new Promise<T>(() => {});
+ }
+
+ /**
+ * Override this method to customize the widget header.
+ * @returns JSX component for the widget body
+ */
+ protected headerContent(): JSX.Element | undefined {
+ return undefined;
+ }
+
+ /**
+ * Override this method to customize the widget body.
+ * @returns JSX component for the widget body
+ */
+ protected bodyContent(): JSX.Element | undefined {
+ return undefined;
+ }
+
+ /**
+ * Override this method to customize the widget footer.
+ * @returns react node for the widget footer
+ */
+ protected footerContent(): JSX.Element | undefined {
+ return undefined;
+ }
+}
+```
+
+The following are the recommended methods to override:
+
+| Methods | Function | Recommend to override |
+||||
+| **constructor()** | Invokes the initial `this.state` and calls the constructor of the super class `React` component. | No |
+| **componentDidMount()** | Invokes after a component is mounted and assigns a value to the `data` property of the state by calling the `getData()` method. | No |
+| **render()** | Invokes whenever there's an update. The dashboard default layout is defined in this method. | No |
+| **getData()** | Invokes the data needed by the widget. The value returned by this method is set to `this.state.data`. |
+| **headerContent()** | Invokes what the widget header looks like. You can choose to override this method to customize a widget or not, if not, the widget won't have a header. | Yes |
+| **bodyContent()** | Invokes what the widget body looks like. You can choose to override this method to customize a widget or not, if not, the widget won't have a body. | Yes |
+| **footerContent()** | Invokes what the widget footer looks like. You can choose to override this method to customize a widget or not, if not, the widget won't have a footer. | Yes |
+
+### Microsoft Graph Toolkit as widget content
+
+Microsoft Graph Toolkit is a set of renewable, framework-agnostic web components, which helps accessing and working with Microsoft Graph. You can use the Microsoft Graph Toolkit with any web framework or without a framework.
+
+To use Microsoft Graph Toolkit as your widget content, follow these steps:
+
+1. Add SSO feature to your Teams app: Microsoft Teams provides single sign-on (SSO) function for an app to obtain signed in Teams user token to access Microsoft Graph. For more information, refer [SSO feature to your Teams app](../../toolkit/add-single-sign-on.md).
+
+1. Install required `npm` packages.
+
+ Run the following command in your project `tabs` folder to install the required `npm` packages:
+
+ ```bash
+ npm install @microsoft/mgt-react @microsoft/mgt-teamsfx-provider
+
+ ```
+
+1. Add a new Graph Toolkit widget: Create a new widget file in your project tabs/src/views/widgets folder, for example, GraphyWidget.tsx. In this widget, we'll guide users to consent our app to access Microsoft Graph and then show the user's `Todo` list by using Microsoft Graph Toolkit.
+
+ The following code is an example of using `Todo` component from Microsoft Graph Toolkit in widget:
+
+ ```tsx
+ import { Providers, ProviderState, Todo } from "@microsoft/mgt-react";
+ import { TeamsFxProvider } from "@microsoft/mgt-teamsfx-provider";
+
+ import { loginAction } from "../../internal/login";
+ import { TeamsUserCredentialContext } from "../../internal/singletonContext";
+ import { Widget } from "../lib/Widget";
+
+ interface IGraphWidgetState {
+ needLogin: boolean;
+ }
+
+ export class GraphWidget extends Widget<IGraphWidgetState> {
+ protected bodyContent(): JSX.Element | undefined {
+ return <div>{this.state.needLogin === false && <Todo />}</div>;
+ }
+
+ async componentDidMount() {
+ super.componentDidMount();
+
+ // Initialize TeamsFx provider
+ const provider = new TeamsFxProvider(TeamsUserCredentialContext.getInstance().getCredential(), [
+ "Tasks.ReadWrite",
+ ]);
+ Providers.globalProvider = provider;
+
+ // Check if user is signed in
+ if (await this.checkIsConsentNeeded()) {
+ await loginAction(["Tasks.ReadWrite"]);
+ }
+
+ // Update signed in state
+ Providers.globalProvider.setState(ProviderState.SignedIn);
+ this.setState({ needLogin: false });
+ }
+
+ /**
+ * Check if user needs to consent
+ * @returns true if user needs to consent
+ */
+ async checkIsConsentNeeded() {
+ let needConsent = false;
+ try {
+ await TeamsUserCredentialContext.getInstance().getCredential().getToken(["Tasks.ReadWrite"]);
+ } catch (error) {
+ needConsent = true;
+ }
+ return needConsent;
+ }
+ }
+
+ ```
+
+ For more information, refer [Microsoft Graph Toolkit](/graph/toolkit/overview).
+
+1. Add the widget to dashboard layout. Include the new widget in your dashboard file.
+
+ ```tsx
+ ...
+ export default class YourDashboard extends Dashboard {
+ ...
+ protected dashboardLayout(): undefined | JSX.Element {
+ return (
+ <>
+ <GraphWiget />
+ </>
+ );
+ }
+ ...
+ }
+ ```
+
+Now, launch or refresh your Teams app, you'll see the new widget using Microsoft Graph Toolkit.
+
+## Graph API call
+
+Microsoft Graph API is a web API that you can use to communicate with Microsoft cloud and other services. Custom applications can use the Microsoft Graph API to connect to data and use it in custom applications to enhance organizational productivity.
+
+To add a Graph API call:
+
+* [Call Graph API from the front-end (use delegated permissions)](#call-graph-api-from-the-front-end-use-delegated-permissions)
+* [Call Graph API from the back-end (use application permissions)](#call-graph-api-from-the-back-end-use-application-permissions)
+
+### Call Graph API from the front-end (use delegated permissions)
+
+If you want to call a Graph API from the front-end tab, follow these steps:
+
+1. Consent delegated permissions first: You can call `addNewPermissionScope(scopes: string[])` to consent the scopes of permissions you want to add. The consented status is preserved in a global context `FxContext`.
+
+1. Create a Graph client by adding the scope related to the Graph API you want to call.
+
+ ```typescript
+ let teamsfx;
+ teamsfx = FxContextInstance.getTeamsFx();
+ const graphClient = createMicrosoftGraphClient(teamsfx, scope);
+ ```
+
+1. Call the Graph API and parse the response into a certain model.
+
+ ```typescript
+ try {
+ const graphApiResult = await graphClient.api("<GRAPH_API_PATH>").get();
+ // Parse the graphApiResult into a Model you defined, used by the front-end.
+ } catch (e) {}
+ ```
+
+### Call Graph API from the back-end (use application permissions)
+
+If you want to call a Graph API from the back-end, follow these steps:
+
+1. [Consent application permissions](#consent-application-permissions)
+1. [Add an Azure function](#add-an-azure-function)
+1. [Add your logic in Azure function](#add-your-logic-in-azure-function)
+1. [Call the Azure function from the front-end](#call-the-azure-function-from-the-front-end)
+
+#### Consent application permissions
+
+To consent application permissions, follow these steps:
+
+1. Go to [Azure portal](https://ms.portal.azure.com/#home).
+1. Select **Azure Active Directory**.
+1. Select **App registrations** in the left pane.
+1. Select your dashboard app.
+1. Select **API permissions** in the left pane.
+1. Select **Add permission**.
+1. Select **Microsoft Graph**.
+1. Select **Application permissions**.
+1. Find the permissions you need.
+1. Select the **Add permissions** button at the bottom.
+1. Select **Γ£öGrant admin consent**.
+1. Select the **Yes** button to finish the admin consent.
+
+#### Add an Azure function
+
+In the left pane of the Visual Studio Code, select **Teams Toolkit** > **Adding features** > **Azure Functions** > and Enter the function name.
++
+#### Add your logic in Azure function
+
+In the `index.ts`/`index.ts` under the folder named Azure Function, you can add your logic that contains back-end Graph API calling with application permissions. Refer to the following code snippet:
+
+```typescript
+/**
+ * This function handles requests from teamsfx client.
+ * The HTTP request should contain an SSO token queried from Teams in the header.
+ * Before triggering this function, teamsfx binding would process the SSO token and generate teamsfx configuration.
+ *
+ * You should initializes the teamsfx SDK with the configuration and calls these APIs.
+ *
+ * The response contains multiple message blocks constructed into a JSON object, including:
+ * - An echo of the request body.
+ * - The display name encoded in the SSO token.
+ * - Current user's Microsoft 365 profile if the user has consented.
+ *
+ * @param {Context} context - The Azure Functions context object.
+ * @param {HttpRequest} req - The HTTP request.
+ * @param {teamsfxContext} TeamsfxContext - The context generated by teamsfx binding.
+ */
+export default async function run(
+ context: Context,
+ req: HttpRequest,
+ teamsfxContext: TeamsfxContext
+): Promise<Response> {
+ context.log("HTTP trigger function processed a request.");
+
+ // Initialize response.
+ const res: Response = {
+ status: 200,
+ body: {},
+ };
+
+ // Your logic here.
+
+ return res;
+}
+```
+
+#### Call the Azure function from the front-end
+
+Call the Azure function by function name. Refer to the following code snippet to call the Azure function:
+
+```typescript
+const functionName = process.env.REACT_APP_FUNC_NAME || "myFunc";
+async function callFunction(teamsfx) {
+ if (!teamsfx) {
+ throw new Error("TeamsFx SDK is not initialized.");
+ }
+ try {
+ const credential = teamsfx.getCredential();
+ const apiBaseUrl = teamsfx.getConfig("apiEndpoint") + "/api/";
+ // createApiClient(...) creates an Axios instance which uses BearerTokenAuthProvider to inject token to request header
+ const apiClient = createApiClient(
+ apiBaseUrl,
+ new BearerTokenAuthProvider(
+ async () => (await credential.getToken(""))!.token
+ )
+ );
+ const response = await apiClient.get(functionName);
+ return response.data;
+ } catch (e) {}
+}
+```
+
+For more information, see:
+
+* [sample](https://github.com/OfficeDev/TeamsFx-Samples/blob/dev/hello-world-tab-with-backend/tabs/src/components/sample/AzureFunctions.tsx)
+* [Developer guide](/azure/azure-functions/functions-reference?tabs=blob)
+
+## Embed Power BI to dashboard
+
+To embed Power BI to the dashboard, see [Power BI client react](/javascript/api/overview/powerbi/powerbi-client-react).
+
+## Step-by-step guide
+
+Follow the [step-by-step](~/sbs-create-dashboard-widget-graph-api-call-in-Teams-toolkit.yml) guide to build a dashboard, and learn to add a widget and Graph API call to the dashboard.
+
+## See also
+
+* [What are Teams tabs](../what-are-tabs.md)
+* [App design guidelines for tab](../design/tabs.md)
+* [Fluent UI library](https://react.fluentui.dev/?path=/docs/concepts-introduction--page)
+* [Fluent UI React charting examples](https://fluentuipr.z22.web.core.windows.net/heads/master/react-charting/demo/https://docsupdatetracker.net/index.html#/)
platform Authentication Flow In Universal Action For Adaptive Cards https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/authentication-flow-in-universal-action-for-adaptive-cards.md
+
+ Title: Add third party authentication to Adaptive Cards Universal Actions
+description: In this module, learn how to add third party authentication to your Adaptive Cards Universal Actions.
++
+ms.localizationpriority: medium
++
+# Add third party authentication to Adaptive Cards Universal Actions
+
+Adaptive Cards Universal Actions use the bot as the common backend for handling actions and introduce a new action type `Action.Execute`, which works across apps, such as Teams and Outlook.
+
+> [!NOTE]
+> Support for Adaptive Cards Universal Actions schema version v1.4 is only available for cards sent by bot.
+
+You can enable the following scenarios with `Action.Execute` on your Adaptive Cards Universal Action:
+
+* [Universal Actions](Overview.md#universal-actions)
+* [User Specific Views](Overview.md#user-specific-views)
+* [Sequential Workflows](Overview.md#sequential-workflow-support)
+* [Up to Date View](Overview.md#up-to-date-views)
+
+To learn more about Adaptive Cards Universal Actions, see [Adaptive Cards Universal Actions](Overview.md).
+
+If you want to add user-specific views in instances where an Adaptive Card with Universal Action is shared, in the context of a group chat or a channel, the user may need to be authenticated.
+
+In the past, users who were chatting one-on-one with the bot had to wait while you sent them a separate auth card to authenticate. To communicate with the bot, user would need to switch from the group chat or channel that would disturb the flow.
+
+## Authentication flow in Action.Execute protocol
+
+Authentication flow for OAuth, within the `Action.Execute` protocol, enables authentication within the context of the group chat or channel conversation where the Adaptive Card is shared.
+
+Bots can respond with sign-in request in response to `Action.Execute` for:
+
+* Adaptive Cards sent by bot in a one-on-one chat, group chat, or a channel.
+* Adaptive Cards sent by app user via message extension app (backed by bot) in one-on-one chat, group chat, or channel.
+* Adaptive Cards present in compose or preview area while the user is composing the message. In the compose area, refresh in Adaptive Card works and the bot may want to use a token to provide user-specific view to the app user before they send the card to the chat.
+
+## Getting started with OAuth or nominal sign-on flow
+
+The OAuth or nominal authentication steps for Adaptive Cards with Universal Actions are similar to bot in Teams.
+
+Ensure that you added authentication to your Teams bot. To learn more about how to create an authentication-enabled bot, how to deploy the bot to Azure and associate it with an identity provider, and how to integrate the bot within Microsoft Teams, see [add authentication to your Teams bot](../../../bots/how-to/authentication/add-authentication.md).
+
+For an OAuth or nominal sign-on experience in which the user is presented with a sign-in button or link, the following is the OAuth or nominal sign-on flow:
++
+1. Teams client sends an Adaptive Card or `actionInvokeActivity` request to the bot.
+1. The bot uses the Token Service protocol to check if there's already a cached token for the user specified in the `activity.from.id` field. The channel is specified in the `activity.channelId` field for the bot and connection that is configured.
+1. If there's a cached token, the bot can use this token. If there's no token, the bot creates an OAuthCard and places it in the response with the following values:
+
+ ```javascript
+ {
+ 'statusCode': 401,
+ 'type': 'application/vnd.microsoft.activity.loginRequest',
+ 'value': {
+ 'text': 'Please sign-in',
+ 'connectionName': '<configured-connection-name>',
+ 'buttons': [
+ {
+ 'title': 'Sign-In',
+ 'text': 'Sign-In',
+ 'type': 'signin',
+ 'value': '<sign-in-URL>'
+ }
+ ]
+ }
+ }
+ ```
+
+ * Senders must include a value that adheres to the OAuthCard format.
+ * Senders must include a `connectionName`. Receivers may ignore sign in requests with an empty or missing `connectionName`.
+ * Senders must include a `button` that has a non-empty buttons array.
+
+1. Upon receiving this response, Teams client shows a **Sign-In** button in the card footer where user can sign in.
+
+ :::image type="content" source="../../../assets/images/authentication/adaptive-card-universal-action/sign-in-button.png" alt-text="Screenshot shows the Sign-In button on the Adaptive card.":::
+
+1. When the user selects **Sign-In** button, the identity provider's sign-in page opens in a browser window opens. After the user signs in, the Token Service page appears with an authorization code value.
+1. Teams client creates and sends the `adaptiveCard/action` invoke activity with `name`. The value includes the `state` field containing the authorization code:
+
+ ```javascript
+ {
+ 'type': 'invoke',
+ 'name': 'adaptiveCard/action'
+ 'value': {
+ 'action': {
+ 'id': 'abc123',
+ 'type': 'Action.Execute',
+ 'verb': 'saveCommand',
+ 'data': {
+ 'firstName': 'Jeff',
+ 'lastName': 'Derstadt'
+ }
+ },
+ 'state': '123456'
+ },
+ ...
+ }
+
+ ```
+
+ Senders must include a `state` field.
+
+1. The channel delivers this invoke to the bot, which uses the authentication code to retrieve the token from the Token Service. The Token Service delivers the user's access token to the bot.
+
+ Receivers may ignore the `adaptiveCard/action` invoke or reply with an error if there's a missing or empty `state` field.
+
+ If the value in the `state` field is incorrect, the bot returns an error to the Teams client as follows:
+
+ ```javascript
+ {
+ 'statusCode': 401,
+ 'type': 'application/vnd.microsoft.error.invalidAuthCode',
+ }
+ ```
+
+ Teams client can again prompt the user for the correct authorization code or can send an `Action.Execute` request again.
+
+1. If the authorization code in the `state` field is correct, the bot uses the access token on behalf of the user to perform its actions.
+1. The bot responds with a card or message to the Teams client without an error.
+
+## See also
+
+* [Work with Adaptive Cards Universal Actions](Work-with-Universal-Actions-for-Adaptive-Cards.md)
+* [Enable SSO for Adaptive Cards Universal Actions](enable-sso-for-your-adaptive-cards-universal-action.md)
platform Enable Sso For Your Adaptive Cards Universal Action https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/enable-sso-for-your-adaptive-cards-universal-action.md
+
+ Title: Overview of SSO for Adaptive Cards Universal Actions in your bot
+description: Learn about Single sign-on (SSO) authentication in Teams and how to enable it in Adaptive Cards Universal Action in bots.
++
+ms.localizationpriority: medium
++
+# Enable SSO for Adaptive Cards Universal Actions in your bot
+
+With Single sign-on (SSO) in Teams, app users have the advantage of using Teams to access Adaptive Cards Universal Actions in a bot. After logging in to Teams using Microsoft or Microsoft 365 account, app users can use your app without the need to sign in again. Your app is available to app users on any device with access granted through Azure Active Directory (Azure AD).
+
+For more information about Universal Actions for Adaptive Cards, see [Universal Actions for Adaptive Cards](Overview.md).
+
+Adaptive Cards Universal Actions uses the bot as the common backend for handling actions and introduces a new action type. Bot uses Bot Framework to handle communication with the app users and to send and receive access token to the bot for SSO authentication. Similarly, Adaptive Cards Universal Actions also uses Bot Framework to enable SSO authentication.
+
+Before you enable SSO for your Adaptive Cards Universal Actions, ensure that you've enabled the SSO for your bot.
+
+> [!div class="nextstepaction"]
+> [Enable SSO for your bot](../../../bots/how-to/authentication/bot-sso-overview.md)
+
+## SSO in Teams at runtime
+
+SSO for Adaptive Cards Universal Actions in a bot can be enabled by obtaining access token for the Teams app user who's currently signed in. This process involves the bot app client and server, Teams client, Bot Framework, and Azure AD. During this interaction, the app user must give consent to obtain the access token in a multi-tenant environment.
+
+The following image shows how SSO works when a Teams app user attempts to access the Adaptive Cards Universal Actions in a bot:
++
+| # | Interaction | What's going on |
+| | | |
+| 1 | Teams client → Bot service | Teams sends an invoke `Action.Execute` request to the bot. <br> If the app user has previously signed in, a token is saved in the Bot Framework Token Store. The bot calls the Bot Framework Token Service that checks for an existing token for the app user in the Bot Framework Token Store. <br> • If the token exists, the app user is given access. <br> • If the token isn't available, the bot triggers the auth flow. |
+| 2 | Azure AD → Teams client | For the app user who's using the Adaptive Cards Universal Actions in a bot for the first time, the token exchange can occur only after the app user gives the consent. Teams client displays a message to the app user for giving consent. <br> In case the consent fails: <br> 1. The authentication falls back to the sign-in prompt and the app user must sign in to use the bot app. The sign-in button appears in Teams client and when the app user selects it, the Azure AD sign-in page appears. <br> 2. The app user signs in and grants access to the Bot service. |
+| 3 | Teams Client → Bot service | Teams client resends the invoke `Action.Execute` request to the bot along with the token. <br> Bot service sends an invoke response with an OAuth card in response to `adaptiveCard/action` invoke call. Teams client sends the original `adaptiveCard/action` again to the bot along with the token. |
+| 4 | Azure AD → Teams client | Azure AD sends invoke response with Adaptive Card to Teams client. Bot returns a non-error response to the Teams client using either a card or message. |
+
+For an Adaptive Cards Universal Actions in a bot, the bot app sends an OAuth card to Teams client. This card is used to get access token from Azure AD using `tokenExchangeResource`. Following app user's consent, Teams client sends the token received from Azure AD to the bot app using `tokenExchange`. The bot app can then parse the token to retrieve the app user's information, such as email address.
+
+## Use cases for enabling SSO
+
+Authentication for SSO, within the `Action.Execute`, enables authentication within the context of the group chat or channel conversation where the Adaptive Card is shared.
+
+Bots can respond with sign-in request in response to `Action.Execute` for:
+
+* Adaptive Cards sent by bot in a one-on-one chat, group chat, or a channel.
+* Adaptive Cards sent by app user via message extension app (backed by bot) in one-on-one chat, group chat, or channel.
+* Adaptive Cards present in compose or preview area while the app user is composing the message. In the compose area, refresh in Adaptive Card works and the bot may want to use a token to provide user-specific view to the app user before they send the card to the chat.
+
+## Next step
+
+> [!div class="nextstepaction"]
+> [Add code to enable SSO for Adaptive Cards Universal Actions](sso-adaptive-cards-universal-action.md)
+
+## See also
+
+* [Work with Universal Actions for Adaptive Cards](Work-with-Universal-Actions-for-Adaptive-Cards.md)
+* [Authentication flow in Adaptive Cards Universal Actions](authentication-flow-in-universal-action-for-adaptive-cards.md)
platform Sso Adaptive Cards Universal Action https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/sso-adaptive-cards-universal-action.md
+
+ Title: Add code to enable SSO for Adaptive Cards Universal Actions
+description: In this module, learn about how to enable SSO for your Adaptive Cards Universal Actions.
++
+ms.localizationpriority: medium
++
+# Add code to enable SSO for Adaptive Cards Universal Actions
+
+Authentication steps for single sign-on (SSO) are similar to that of a bot in Teams. Following are the steps to achieve SSO in Adaptive Cards Universal Action.
+
+> [!NOTE]
+> To implement SSO flow, you must have a one-on-one chat declared for your bot in the app manifest. When an app user invokes the SSO flow via the Adaptive Card `Action.Execute` protocol, a prompt appears to allow the app user to install the app in a personal scope if they haven't installed it.
+
+## Add code to handle an access token
+
+Ensure you've configured your bot in Azure Active Directory (Azure AD) for obtaining access token. You can update the code to handle the access token for Adaptive Cards Universal Actions in bot.
+
+If there's a cached token, the bot uses the same token. If there's no token available, the Adaptive Card sends an invoke response to the bot service, which sends an OAuth card with the following values that includes a `tokenExchangeResource` to designate an SSO operation:
+
+```JSON
+{
+"statusCode": 401,
+"type": "application/vnd.microsoft.activity.loginRequest",
+"value": {
+ "text": "Please sign-in",
+ "connectionName": "<configured-connection-name>",
+ "tokenExchangeResource": {
+ "id": "<unique-indentifier>",
+ "uri": "<application-or-resource-identifier>",
+ "providerId": "<optional-provider-identifier>"
+ },
+ "buttons": [
+ {
+ "title": "Sign-In",
+ "text": "Sign-In",
+ "type": "signin",
+ "value": "<sign-in-URL>"
+ }
+ ]
+}
+}
+```
+
+The bot service delivers the invoke response to the Teams client, which uses theΓÇ»`tokenExchangeResource` value and the Teams client token to obtain an on-behalf-of token or exchangeable token from Azure AD.
+
+The SSO fails when the Teams client ignores the `tokenExchangeResource` value for any reason, including invalid values, errors retrieving exchangeable tokens, or if Azure AD doesn't support the value. Then the Teams client triggers the nominal sign-in or OAuth flow. It's recommended that you provide a sign-in URL in the above response so that the OAuth flow works.
+
+## Consent dialog for getting access token
+
+If the app user is using an Adaptive Card for the first time, they must give consent for the app to use their identity. The following dialog appears:
+
+ :::image type="content" source="../../../assets/images/authentication/consent-sso-ac.png" alt-text="Screenshot shows you the consent dialog box.":::
+
+When the app user selects **View and accept**, the existing Azure AD permission consent view appears to show all the permissions. The app user can continue with the authentication flow.
+
+## Add code to receive the token
+
+1. Teams client sends the original `adaptiveCard/action` again to the bot along with the token as follows:
+
+ ```javascript
+ {
+ "type": "invoke",
+ "name": "adaptiveCard/action"
+ "value": {
+ "action": {
+ "id": "abc123",
+ "type": "Action.Execute",
+ "verb": "saveCommand",
+ "data": {
+ "firstName": "Jeff",
+ "lastName": "Derstadt"
+ }
+ },
+ "authentication": {
+ "id": "8769-xyz",
+ "connectionName": "oauthConnection",
+ "token": "...single sign-on token..."
+ }
+ }
+ }
+ ```
+
+ The following code snippet shows how to receive invoke activity in the bot service:
+
+ ```csharp
+ protected override async Task<InvokeResponse> OnInvokeActivityAsync(ITurnContext<IInvokeActivity> turnContext,
+ CancellationToken cancellationToken)
+         {
+           JObject value = JsonConvert.DeserializeObject<JObject>
+ (turnContext.Activity.Value.ToString());
+           JObject authentication = null;
+           if (value["authentication"] != null)
+           {
+           authentication = JsonConvert.DeserializeObject<JObject>(value["authentication"].ToString());
+           }
+ }
+ ```
+
+1. Teams client sends an invoke request to the bot. The bot receives the app users consent and uses their identity to help the token exchange process with the bot framework token service and Azure AD. The bot framework token service delivers the app users access token to the bot.
+ * Bot service ignores the access token if the value is incorrect.
+ * Bot service that experiences an error while performing token exchange must respond with an error or a second sign-in request that doesn't include SSO information. If the bot service responds with an error, the error must be:
+
+ ```javascript
+ {
+ "statusCode" = 412,
+ "type" = "application/vnd.microsoft.error.preconditionFailed",
+ "value" = {
+ "code" = "412",
+ "message" = "authentication token expired" }
+ }
+ ```
+
+ * When SSO fails, the Teams client shows a sign-in button in the card footer to initiate nominal sign-in flow.
+
+1. The bot uses the access token on behalf of the app user to perform its actions.
+1. The bot returns a non-error response to the Teams client using either a card or message.
+
+> [!NOTE]
+> To handle the access token in case the app user logs out, see [handle app user log out](../../../bots/how-to/authentication/bot-sso-code.md#handle-app-user-log-out).
+
+## Code sample
+
+| **Sample name** | **Description** | **.NET** | **Node.js** |
+| | | | | |
+| SSO for your Adaptive Cards Universal Actions | This sample code demonstrates how to enable SSO authentication for your Adaptive Cards Universal Actions in bot. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-sso-adaptivecard/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-sso-adaptivecard/nodejs) |
+
+## See also
+
+* [Work with Universal Actions for Adaptive Cards](Work-with-Universal-Actions-for-Adaptive-Cards.md)
+* [Enable SSO for your bot app](../../../bots/how-to/authentication/bot-sso-overview.md)
+* [Update app manifest for SSO and preview your app](../../../bots/how-to/authentication/bot-sso-manifest.md)
platform Teamsfx Multi Env https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/TeamsFx-multi-env.md
Title: TeamsFX multiple environments in Teams Toolkit description: In this module, learn about TeamsFX multi environment such as, create a new environment, select target environment and more-+ ms.localizationpriority: medium Last updated 11/29/2021
Last updated 11/29/2021
## Create new environment
-After you create a project, Teams Toolkit by default configures:
+Each project can have one **local** environment but multiple remote environments. After you create a project, Teams Toolkit by default configures:
* **local** environment to represent the local machine environment configuration. * **dev** environment to represent the remote or cloud environment configuration.
-> [!NOTE]
-> Each project can have one **local** environment but multiple remote environments.
- Perform the following steps to create a new environment: 1. Select the **Teams Toolkit** from the Visual Studio Code activity bar.
Perform the following steps to create a new environment:
:::image type="content" source="../assets/images/teams-toolkit-v2/teams toolkit fundamentals/create_new _env_1.PNG" alt-text="Create new environment":::
-> [!Note]
-> If you have more than one environment, you need to select an existing environment to create the new environment. The command copies the file contents of `config.<newEnv>.json` and `azure.parameters.<newEnv>.json` from the existing environment you've selected to the new environment created.
+ If you have more than one environment, you need to select an existing environment to create the new environment. The command copies the file contents of `config.<newEnv>.json` and `azure.parameters.<newEnv>.json` from the existing environment you've selected to the new environment created.
## Target environment
platform Create New Project https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/create-new-project.md
The steps to create a new Teams app are similar for all types of apps except not
:::image type="content" source="../assets/images/Tools-and-SDK-revamp/Create-new-app-VS/vs-ms-teams-app-type_3_1.png" alt-text="Select the teams app type":::
- > [!NOTE]
- > You can select any type of Teams app for your project.
+You can select any type of Teams app for your project.
The **GettingStarted .txt** window appears.
You can see Teams app templates already populated in Teams Toolkit for various T
|**Tab** |Tab app shows a webpage inside Teams, and it enables single sign-on (SSO) using Teams account. | |**Message Extension** |Message extension app implements simple features like creating an Adaptive Card, searching Nugget packages, unfurling links for the `dev.botframework.com` domain. |
-> [!NOTE]
-> After the project is created, Teams Toolkit automatically opens **GettingStarted** window. You can see the instructions in **GettingStarted** window and check out the different features in Teams Toolkit.
+After the project is created, Teams Toolkit automatically opens **GettingStarted** window. You can see the instructions in **GettingStarted** window and check out the different features in Teams Toolkit.
::: zone-end
platform Tools Prerequisites https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/tools-prerequisites.md
Ensure that the following tools are installed on the device where youΓÇÖll creat
| [Microsoft Graph Explorer](https://developer.microsoft.com/graph/graph-explorer) | The browser-based tool that lets you run a query from Microsoft Graph data. | JavaScript, TypeScript and SPFx | | [Developer Portal for Teams](https://dev.teams.microsoft.com/) | The web-based portal to configure, manage, and distribute your Teams app including to your organization or the Teams store.| JavaScript, TypeScript and SPFx. |
- > [!NOTE]
- >
- > * The document is tested with Teams Toolkit version 4.1.3 and Node.js version 16.
- > * Bookmark the Microsoft Graph Explorer to learn about Microsoft Graph services. This browser-based tool allows you to run a query and access the Microsoft Graph API.
+It's recommended that you bookmark the Microsoft Graph Explorer to learn about Microsoft Graph services. This browser-based tool allows you to run a query and access the Microsoft Graph API.
## Accounts to build your Teams app
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 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***: [Create a dashboard in Teams.](tabs/how-to/dashboard-teams-toolkit.md)
-
+* ***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:::
Teams platform features that are available to all app developers.
| **Date** | **Update** | **Find here** | | -- | | -|
-|31/01/2023| Introducing update and soft delete event notifications in bot | Build bots > Bot conversations > [Messages in bot conversations](bots/how-to/conversations/conversation-messages.md#update-message) |
+|31/01/2023| Introducing update and soft delete event notifications in bot | Build bots > Bot conversations > [Messages in bot conversations](bots/how-to/conversations/conversation-messages.md#update-message)
</details> </br>
Developer preview is a public program that provides early access to unreleased T
**2023 January**
-* ***January 31, 2023***: [Introducing Targeted in-meeting notification for apps in Teams](apps-in-teams-meetings/in-meeting-notification-for-meeting.md#targeted-in-meeting-notification).
* ***January 30, 2023***: [Enable app caching to improve subsequent launch time of the apps to the meeting side panel](apps-in-teams-meetings/build-tabs-for-meeting.md#app-caching). :::column-end:::