Updates from: 04/26/2023 01:25:24
Service Microsoft Docs article Related commit history on GitHub Change details
platform Teams Live Share Capabilities https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-capabilities.md
Last updated 04/07/2022
:::image type="content" source="../assets/images/teams-live-share/Teams-live-share-core-capabilities-hero.png" alt-text="Screenshot shows an example of users playing agile poker game in a Teams meeting, which showcases the Live share capability.":::
-The Live Share SDK can be added to your meeting extension's `sidePanel` and `meetingStage` contexts with minimal effort.
+The Live Share SDK can be added to your meeting extension's `sidePanel` and `meetingStage` contexts with minimal effort.
> [!NOTE] > The Live Share SDK isn't supported for anonymous users.
platform Teams Live Share Overview https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-overview.md
Last updated 04/07/2022
> [!VIDEO https://www.youtube.com/embed/971YIvosuUk]
-Live Share is an SDK designed to transform Teams apps into collaborative multi-user experiences without writing any dedicated back-end code. With Live Share, your users can co-watch, co-create, and co-edit during meetings.
+Live Share is an SDK designed to transform Teams apps into collaborative multiuser experiences without writing any dedicated back-end code. With Live Share, your users can co-watch, co-create, and co-edit during meetings.
Sometimes screen sharing just isn't enough, which is why Microsoft built tools like PowerPoint Live and Whiteboard directly into Teams. By bringing your web application directly to center stage in the meeting interface, your users can seamlessly collaborate during meetings and calls.
platform Teams Together Mode https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-together-mode.md
Custom Together Mode scenes in Microsoft Teams provide an immersive and engaging
* Bring people together and encourage them to turn on their video. * Combine participants digitally into a single virtual scene.
-* Place the participants' video streams in pre-determined seats designed and fixed by the scene creator.
+* Place the participants' video streams in predetermined seats designed and fixed by the scene creator.
In custom Together Mode scenes, the scene is an artifact. The scene is created by the scene developer using the Microsoft Scene studio. In a conceived scene setting, participants have seats with video streams. The videos are rendered in those seats. Scene only apps are recommended as the experience for such apps is clear.
You must have a basic understanding of the following to use custom Together Mode
Consider the following practices for a scene building experience: * Ensure that all images are in PNG format.
-* Ensure that the final package with all the images put together must not exceed 1920x1080 resolution. The resolution is an even number. This resolution is a requirement for scenes to be shown successfully.
+* Ensure that the final package with all the images put together must not exceed 1920 x 1080 resolution. The resolution is an even number. This resolution is a requirement for scenes to be shown successfully.
* Ensure that the maximum scene size is 10 MB. * Ensure that the maximum size of each image is 5 MB. A scene is a collection of multiple images. The limit is for each individual image. * Ensure to select **Transparent** as required. This checkbox is available on the right panel when an image is selected. The overlapping images must be marked as **Transparent** to indicate that they're overlapping images in the scene.
platform Manage Your Apps In Developer Portal https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/build-and-test/manage-your-apps-in-developer-portal.md
In the **Advanced** section, you can see the following components to manage your
1. In the **Advanced** section, select **Owners**. 1. Select **Add owners**.
- 1. Enter a name and select a user ID from the drop-down list.
+ 1. Enter a name and select a user ID from the dropdown list.
1. Under **Role**, select **Operative** or **Administrator**. 1. Select **Add**.
platform Browser Device Permissions https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/device-capabilities/browser-device-permissions.md
Teams app that requires device permissions in the browser must show instructions
|Sample name | Description | Node.js | Manifest |-|--|--|--|
-| Tab device permissions for browser | The sample shows how to show the device permissions using Teans JS SDK and browser api's. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/tab-device-permissions/nodejs) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/tab-device-permissions/nodejs/demo-manifest/tab-device-permissions.zip)
+| Tab device permissions for browser | The sample shows how to show the device permissions using TeamsJS SDK and browser api's. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/tab-device-permissions/nodejs) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/tab-device-permissions/nodejs/demo-manifest/tab-device-permissions.zip)
## Step-by-step guide
platform Native Device Permissions https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/concepts/device-capabilities/native-device-permissions.md
You can enrich your Teams app with native device capabilities, such as camera, m
> [!NOTE] >
-> * To integrate media capabilities within your Teams web client, desktop, and mobile see [Integrate media capabilities](media-capabilities.md).
+> * To integrate media capabilities within your Teams web client, desktop, and mobile, see [Integrate media capabilities](media-capabilities.md).
> * To integrate QR or barcode scanner capability within your Microsoft Teams mobile app, see [Integrate QR or barcode scanner capability in Teams](qr-barcode-scanner-capability.md). > * To integrate location capabilities within your Teams web client, desktop, and mobile, see [Integrate location capabilities](location-capability.md).
Device permissions are stored for every sign in session. It means that if you si
| Sample name | Description | Node.js | Manifest ||--|||
-|Device permissions | The sample shows how to use the device permissions using teams js sdk and browser api's. |[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/tab-device-permissions/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/tab-device-permissions/nodejs/demo-manifest/tab-device-permissions.zip)
+|Device permissions | The sample shows how to use the device permissions using TeamsJS SDK and browser api's. |[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/tab-device-permissions/nodejs)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/tab-device-permissions/nodejs/demo-manifest/tab-device-permissions.zip)
## Next step
platform Bots Conv Proactive https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/resources/bot-v3/bot-conversations/bots-conv-proactive.md
A proactive message is a message that is sent by a bot to start a conversation.
* Poll responses. * External event notifications.
-Sending a message to start a new conversation thread is different than sending a message in response to an existing conversation. When your bot starts a new conversation, there's no pre-existing conversation to post the message to. To send a proactive message, you need to:
+Sending a message to start a new conversation thread is different than sending a message in response to an existing conversation. When your bot starts a new conversation, there's no preexisting conversation to post the message to. To send a proactive message, you need to:
1. [Decide what you're going to say](#best-practices-for-proactive-messaging) 1. [Obtain the user's unique ID and tenant ID](#obtain-necessary-user-information)
platform Bots Create https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/resources/bot-v3/bots-create.md
For more information, see [Bot Framework Documentation](/azure/bot-service/?view
**Teams Developer Portal for Teams** is a tool that can help create your bot, and an app package that references your bot. It also contains a React control library and configurable samples for cards. For more information, see [Getting started with Teams Developer Portal for Teams](~/concepts/build-and-test/teams-developer-portal.md). The steps that follow assume that you are hand configuring your bot and not using **Teams Developer Portal for Teams**:
-1. Create the bot using [Bot Framework](https://dev.botframework.com/bots/new). **Be sure to add Microsoft Teams as a channel from the featured channels list after creating your bot.** Feel free to re-use any Microsoft App ID you generated if you've already created your app package/manifest.
+1. Create the bot using [Bot Framework](https://dev.botframework.com/bots/new). **Be sure to add Microsoft Teams as a channel from the featured channels list after creating your bot.** Feel free to reuse any Microsoft App ID you generated if you've already created your app package/manifest.
![Bot Framework registration page](~/assets/images/bots/bfregister.png)
platform Bots With Tabs https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/resources/bot-v3/bots-with-tabs.md
Bots and tabs work together, and are often combined into a single back-end servi
For example: Suppose your tab application uses a proprietary ID system to secure its content. Suppose you also have a bot that can interact with the user. Typically, youΓÇÖll want to show content in the tab that is specific to the viewing user. The challenge is that the user ID in your system is likely different from the Microsoft Teams user ID. So how do you associate these two identities?
-In general, the recommended approach is to sign the user in with the bot using the same identity system used to provide authentication for the tab content. You can implement via the sign-in action, which typically logs in the user via an OAuth flow.
+In general, the recommended approach is to sign the user in with the bot using the same identity system used to provide authentication for the tab content. You can implement via the sign in action, which typically signs in the user via an OAuth flow.
This flow works best if your identity provider implements the OAuth 2.0 protocol. You can then associate the Teams user ID with the userΓÇÖs credentials from your own identity service.
platform Search Extensions https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/resources/messaging-extension-v3/search-extensions.md
The sequence is as follows:
4. The Microsoft Teams client launches a pop-up window hosting your webpage using the given authentication URL. 5. After the user signs in, you should close your window and send an "authentication code" to the Teams client. 6. The Teams client then reissues the query to your service, which includes the authentication code passed in step 5.-
-Your service should verify that the authentication code received in step 6 matches the one from step 5, which ensures that a malicious user doesn't try to spoof or compromise the sign-in flow. This effectively "closes the loop" to finish the secure authentication sequence.
+Your service must verify that the authentication code received in step 6 matches the one from step 5, which ensures that a malicious user doesn't try to spoof or compromise the sign in flow. This effectively "closes the loop" to finish the secure authentication sequence.
### Respond with a sign-in action
To prompt an unauthenticated user to sign in, respond with a suggested action of
``` > [!NOTE]
-> For the sign-in experience to be hosted in a Teams pop-up, the domain portion of the URL must be in your appΓÇÖs list of valid domains. For more information, see [validDomains](~/resources/schem#validdomains) in the manifest schema.
+> For the sign in experience to be hosted in a Teams pop-up, the domain portion of the URL must be in your appΓÇÖs list of valid domains. For more information, see [validDomains](~/resources/schem#validdomains) in the manifest schema.
### Start the sign-in flow
-Your sign-in experience should be responsive and fit within a pop-up window. It should integrate with the [Microsoft Teams JavaScript client SDK](/javascript/api/overview/msteams-client), which uses message passing.
+Your sign in must be responsive and fit within a pop-up window. It should integrate with the [Microsoft Teams JavaScript client SDK](/javascript/api/overview/msteams-client), which uses message passing.
-As with other embedded experiences running inside Teams, your code inside the window needs to first call `microsoftTeams.initialize()`. If your code performs an OAuth flow, you can pass the Teams user ID into your window, which then can pass it to the OAuth sign-in URL.
+As with other embedded experiences running inside Teams, your code inside the window needs to first call `microsoftTeams.initialize()`. If your code performs an OAuth flow, you can pass the Teams user ID into your window, which then can pass it to the URL of OAuth sign in URL.
### Complete the sign-in flow
-When the sign-in request completes and redirects back to your page, it should perform the following steps:
+When the sign in request completes and redirects back to your page, it should perform the following steps:
-1. Generate a security code. (This can be a random number.) You need to cache this code on your service, along with the credentials obtained through the sign-in flow such as, OAuth 2.0 tokens.
+1. Generate a security code. (This can be a random number.) You need to cache this code on your service, along with the credentials obtained through sign in such as, OAuth 2.0 tokens.
2. Call `microsoftTeams.authentication.notifySuccess` and pass the security code. At this point, the window closes and control is passed to the Teams client. The client can now reissue the original user query, along with the security code in the `state` property. Your code can use the security code to look up the credentials stored earlier to complete the authentication sequence and then complete the user request.
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
The following code is an example to customize the dashboard layout:
```typescript export default class YourDashboard extends Dashboard {
- protected rowHeights(): string | undefined {
+ override rowHeights(): string | undefined {
return "500px"; }
- protected columnWidths(): string | undefined {
+ override columnWidths(): string | undefined {
return "4fr 6fr"; }
- protected dashboardLayout(): JSX.Element | undefined {
+ override dashboardLayout(): JSX.Element | undefined {
return ( <> <SampleWidget />
- <div style={oneColumn("6fr 4fr")}>
- <SampleWidget />
- <SampleWidget />
- </div>
</> ); }
export default class YourDashboard extends Dashboard {
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:
+Open **tabs/src/App.tsx** and add a route for the new dashboard. Here's an example:
```typescript import YourDashboard from "./views/dashboards/YourDashboard";
export default function App() {
### 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:
+Open **templates/appPackage/manifest.template.json** and add a new dashboard tab under **staticTabs**. Here's an example:
```json {
Teamsfx provides convenient methods to define and modify the layout of the dashb
```typescript export default class SampleDashboard extends Dashboard {
- protected rowHeights(): string | undefined {
+ override rowHeights(): string | undefined {
return "350px"; }
- protected columnWidths(): string | undefined {
+ override columnWidths(): string | undefined {
return "2fr 6fr 2fr"; }
- protected dashboardLayout(): undefined | JSX.Element {
+ override dashboardLayout(): undefined | JSX.Element {
return ( <> <ListWidget />
Teamsfx provides convenient methods to define and modify the layout of the dashb
```typescript export default class SampleDashboard extends Dashboard {
- protected rowHeights(): string | undefined {
+ override rowHeights(): string | undefined {
return "max-content 400px"; }
- protected columnWidths(): string | undefined {
+ override columnWidths(): string | undefined {
return "600px 1100px"; }
- protected dashboardLayout(): undefined | JSX.Element {
+ override dashboardLayout(): undefined | JSX.Element {
return ( <> <ListWidget />
Teamsfx provides convenient methods to define and modify the layout of the dashb
* Arrange two widgets in a column.
+ ```css
+ .one-column {
+ display: grid;
+ gap: 20px;
+ grid-template-rows: 1fr 1fr;
+ }
+ ```
+ ```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>
- </>
- );
- }
+ override dashboardLayout(): JSX.Element | undefined {
+ return (
+ <>
+ <NewsWidget />
+ <div className="one-column">
+ <ListWidget />
+ <ChartWidget />
+ </div>
+ </>
+ );
} ```
Teamsfx provides convenient methods to define and modify the layout of the dashb
The following code can achieve a height of 400 px for the `ListWidget` and a height of 350 px for the `ChartWidget`:
+ ```css
+ .one-column {
+ display: grid;
+ gap: 20px;
+ grid-template-rows: 400px 350px;
+ }
+ ```
+ ```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>
- </>
- );
- }
- }
+ override dashboardLayout(): JSX.Element | undefined {
+ return (
+ <>
+ <NewsWidget />
+ <div className="one-column">
+ <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.":::
To adjust the layout of the dashboard, Teamsfx provides a `dashboard` class for
The following code is an example of a dashboard class: ```typescript
+import React, { Component } from "react";
+
+import { mergeStyles } from "@fluentui/react";
+ 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> {
+export class Dashboard extends Component<{}, 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 = {
export class Dashboard extends Component<any, IDashboardState> {
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) => {
export class Dashboard extends Component<any, IDashboardState> {
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) {
export class Dashboard extends Component<any, IDashboardState> {
} }
- /**
- * Define the dashboard default layout, you can edit the code here to customize your dashboard layout.
- */
render() {
+ const styling = mergeStyles({
+ display: "grid",
+ gap: "20px",
+ padding: "1rem",
+ gridTemplateColumns: "4fr 6fr",
+ gridTemplateRows: "1fr",
+ ...(this.state.isMobile && { gridTemplateColumns: "1fr" }),
+ ...(this.columnWidths() && { gridTemplateColumns: this.columnWidths() }),
+ ...(this.rowHeights() && { gridTemplateRows: this.rowHeights() }),
+ });
+ return ( <>
- <div
- ref={this.ref}
- style={dashboardStyles(
- this.state.isMobile,
- this.rowHeights(),
- this.columnWidths()
- )}
- >
+ <div ref={this.ref} className={styling}>
{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; }
You can customize the widget by overriding the following methods in the `widget`
* Override `headerContent()`, `bodyContent()`, and `footerContent()` to customize the widget. ```typescript
- export class NewsWidget extends Widget<void> {
+ export class NewsWidget extends Widget<any, any> {
- headerContent(): JSX.Element | undefined {
- return (
- <div style={headerContentStyle()}>
- <News28Regular />
- <Text style={headerTextStyle()}>Your News</Text>
- <Button icon={<MoreHorizontal32Regular />} appearance="transparent" />
- </div>
- );
- }
+ headerContent(): JSX.Element | undefined {
+ return (
+ <div>
+ <News28Regular />
+ <Text>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>
- );
- }
+ bodyContent(): JSX.Element | undefined {
+ return (
+ <div className="content-layout">
+ <Image src="image.svg" className="img" />
+ <Text className="title">Lorem Ipsum Dolor</Text>
+ <Text className="desc">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>
- );
- }
+ footerContent(): JSX.Element | undefined {
+ return (
+ <Button
+ appearance="transparent"
+ icon={<ArrowRight16Filled />}
+ iconPosition="after"
+ size="small"
+ className="footer-button"
+ onClick={() => { }} // navigate to detailed page
+ >
+ View details
+ </Button>
+ );
+ }
} ```
You can customize the widget by overriding the following methods in the `widget`
* Override `bodyContent()` and `footerContent()` to customize the widget. ```typescript
- export class NewsWidget extends Widget<void> {
+ export class NewsWidget extends Widget<any, any> {
- 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>
- );
- }
+ bodyContent(): JSX.Element | undefined {
+ return (
+ <div className="content-layout">
+ <Image src="image.svg" className="img" />
+ <Text className="title">Lorem Ipsum Dolor</Text>
+ <Text className="desc">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>
- );
- }
+ footerContent(): JSX.Element | undefined {
+ return (
+ <Button
+ appearance="transparent"
+ icon={<ArrowRight16Filled />}
+ iconPosition="after"
+ size="small"
+ className="footer-button"
+ onClick={() => { }} // navigate to detailed page
+ >
+ View details
+ </Button>
+ );
+ }
} ```
You can customize the widget by overriding the following methods in the `widget`
* Override `bodyContent()` to customize the widget. ```typescript
- export class NewsWidget extends Widget<void> {
+ export class NewsWidget extends Widget<any, any> {
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>
- );
- }
+ return (
+ <div className="content-layout">
+ <Image src="image.svg" className="img" />
+ <Text className="title">Lorem Ipsum Dolor</Text>
+ <Text className="desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Enim, elementum sed</Text>
+ </div>
+ );
+ }
} ```
The following steps show how to add a property to the state of `ListWidget` and
1. Add a data loader: Modify the `bodyContent` method to show a loading spinner if data is loading.
- ```tsx
+ ```typescript
bodyContent(): JSX.Element | undefined { return ( <> {this.state.loading !== false ? (
- <div style={{ display: "grid", justifyContent: "center", height: "100%" }}>
+ <div className="loading-class-name">
<Spinner label="Loading..." labelPosition="below" /> </div> ) : (
- <div style={bodyContentStyle()}>
+ <div className="list-body">
... </div> )}
The following steps show how to add a property to the state of `ListWidget` and
The following code is an example of footer button:
- ```tsx
+ ```typescript
footerContent(): JSX.Element | undefined { if (this.state.loading === false) { return (
You can display a specific content in your widget when the data is empty. To do
The following example shows how to display an empty image when the data of `ListWidget` is empty.
-```tsx
+```css
+.empty-layout {
+ display: grid;
+ gap: 1rem
+ justify-content: center;
+ align-content: center;
+}
+```
+
+```typescript
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>
- );
- }
+ let hasData = this.state.data && this.state.data.length > 0;
+ return (
+ <div className="list-body">
+ {hasData ? (
+ <>
+ {this.state.data?.map((t: ListModel) => {
+ ...
+ })}
+ </>
+ ) : (
+ <div className="empty-layout">
+ <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
+```typescript
footerContent(): JSX.Element | undefined {
- let hasData = this.state.data && this.state.data.length > 0;
- if (hasData) {
- return (
- <Button
- ...
- </Button>
- );
- }
+ 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.":::
footerContent(): JSX.Element | undefined {
The following example shows how to display real-time data in a widget. The widget displays the current time and updates.
-```tsx
+```typescript
import { Widget } from "../lib/Widget"; interface IRefreshWidgetState { data: string; }
-export class RefreshWidget extends Widget<IRefreshWidgetState> {
+export class RefreshWidget extends Widget<any, IRefreshWidgetState> {
bodyContent(): JSX.Element | undefined { return <>{this.state.data}</>; }
To simplify the development of a widget, Teamsfx provides a `widget` class for d
The following code is an example of widget class: ```typescript
-export abstract class Widget<T> extends Component<any, { data?: T | void }> {
+import "./Widget.css";
+
+import { Component } from "react";
+
+export abstract class Widget<P, T> extends Component<P, T> {
constructor(props: any) { super(props);
- this.state = {
- data: undefined,
- };
+ this.state = {} as T;
}
- /**
- * 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() });
+ this.setState({ ...(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>
- )}
+ <div className="widget-root">
+ {this.headerContent() && <div className="widget-header">{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; }
To use Microsoft Graph Toolkit as your widget content, follow these steps:
```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.
To use Microsoft Graph Toolkit as your widget content, follow these steps:
needLogin: boolean; }
- export class GraphWidget extends Widget<IGraphWidgetState> {
- protected bodyContent(): JSX.Element | undefined {
+ export class GraphWidget extends Widget<any, IGraphWidgetState> {
+ override bodyContent(): JSX.Element | undefined {
return <div>{this.state.needLogin === false && <Todo />}</div>; }
To use Microsoft Graph Toolkit as your widget content, follow these steps:
... export default class YourDashboard extends Dashboard { ...
- protected dashboardLayout(): undefined | JSX.Element {
+ override dashboardLayout(): undefined | JSX.Element {
return ( <> <GraphWiget />
platform Overview https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Overview.md
Now, you can understand how Adaptive Cards can be transformed with the new Unive
Adaptive Cards are a combination of content, such as text and graphics, and actions that can be performed by a user. For more information, see [Adaptive Cards](https://adaptivecards.io/). The new Universal Actions for Adaptive Cards enable a common handling of the Adaptive Card actions across platforms and applications. For more information, see [Universal Action Model](/adaptive-cards/authoring-cards/universal-action-model).
-You can get started by updating scenarios using the [quick start guide].(Work-with-universal-actions-for-adaptive-cards.md) and leverage Universal Actions.
+You can get started by updating scenarios using the [quick start guide](Work-with-universal-actions-for-adaptive-cards.md) and leverage Universal Actions.
## Next step
platform Cards Actions https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/cards/cards-actions.md
The following code shows an example of Adaptive Cards with `invoke` action with
|3|Adaptive cards|Demonstrates how the multi-turn dialog can use a card to get user input for name and age.|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/csharp_dotnetcore/07.using-adaptive-cards)|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/javascript_nodejs/07.using-adaptive-cards)|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/python/07.using-adaptive-cards)|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/java_springboot/07.using-adaptive-cards)| > [!NOTE]
-> Media elements are not supported for adaptive card in Teams
+> Media elements are not supported for Adaptive Card in Teams.
## Next step
platform Cards Reference https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/cards/cards-reference.md
The card can contain an inline image by including a link to the publicly availab
Images are scaled up or down in size to maintain the aspect ratio for covering the image area. Images are then cropped from center to achieve the appropriate aspect ratio for the card.
-Images must be at most 1024×1024 and in PNG, JPEG, or GIF format. Animated GIF isn't supported.
+Images must be at most 1024 × 1024 and in PNG, JPEG, or GIF format. Animated GIF isn't supported.
The following table provides the properties of inline card images:
Bot Framework reference:
## Sign in card
-The sign in card in Teams is similar to the signin card in the Bot Framework except that the signin card in Teams only supports two actions `signin` and `openUrl`.
+The sign in card in Teams is similar to the sign in card in the Bot Framework except that the sign in card in Teams only supports two actions `signin` and `openUrl`.
The sign in action can be used from any card in Teams, not just the sign in card. For more information, see [Teams authentication flow for bots](~/bots/how-to/authentication/auth-flow-bot.md). ### Support for login cards
-The following table provides the features that support sign-in cards:
+The following table provides the features that support sign in cards:
| Bots in Teams | Message extensions | Connectors | Bot Framework | | | | | |
platform Design Effective Cards https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/cards/design-effective-cards.md
A `Container` allows you to group a set of related elements together.
Follow these guidelines when including images in your cards.
-* **Do**: Design images for high DPI screens to avoid pixelation. It's better to display a 100x100-pixel image at 50x50 pixels than the other way around.
+* **Do**: Design images for high DPI screens to avoid pixelation. It's better to display a 100 x 100 pixel image at 50 x 50 pixels than the other way around.
* **Do**: If you need to control the exact size of your images, use the `width` and `height` properties. * **Don't**: Include padding with your images. This typically introduces undesirable spacing and layout issues. * Regarding background color:
platform Design Teams Task Modules https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/task-modules/design-teams-task-modules.md
Task modules are a great place to surface forms with sequential user inputs and
### Sign in
-Create a focused sign in or sign-up flow with a series of task modules, letting users move easily through sequential steps.
+Create a focused sign in or sign up flow with a series of task modules, letting users move easily through sequential steps.
#### Mobile
platform What Are Cards https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/task-modules-and-cards/what-are-cards.md
The bots for Teams support the following types of cards:
- List card - Connector card for Microsoft 365 Groups - Receipt card-- Sign-in card
+- Sign in card
- Thumbnail card - Card collections - Overflow menu on Adaptive Cards
platform AAD Manifest Customization https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/AAD-manifest-customization.md
You need to interact with Azure AD application during various stages of your Tea
1. **To create Project**
- You can create a project with Teams Toolkit that comes with single-sign-on (SSO) support by default such as `SSO-enabled tab`. For more information on how to create a new app, see [create new Teams application using Teams Toolkit](create-new-project.md). An Azure AD manifest file is automatically created for you in `templates\appPackage\aad.template.json`. Teams Toolkit creates or updates the Azure AD application during local development or while you move the application to the cloud.
+ You can create a project with Teams Toolkit that comes with single sign-on (SSO) support by default such as `SSO-enabled tab`. For more information on how to create a new app, see [create new Teams application using Teams Toolkit](create-new-project.md). An Azure AD manifest file is automatically created for you in `templates\appPackage\aad.template.json`. Teams Toolkit creates or updates the Azure AD application during local development or while you move the application to the cloud.
2. **To add SSO to your Bot or Tab**
platform Teamsfx Collaboration https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/TeamsFx-collaboration.md
Title: Collaborate on TeamsFx Project using Teams Toolkit description: In this article, learn how to collaborate on TeamsFx Project using Teams Toolkit and collaborate with other developers.-+ ms.localizationpriority: medium Last updated 11/29/2021
platform Add Single Sign On https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/add-single-sign-on.md
Title: Add single sign-on to your Teams apps description: In this module, learn how to add single sign-on (SSO) of Teams Toolkit, enable SSO support, update your application to use SSO-+ ms.localizationpriority: medium Last updated 05/20/2022
To make this work in your app:
</details>
-<br>
- ## Debug your app Press **F5** to debug your application. Teams Toolkit uses the Azure AD manifest file to register an Azure AD app for SSO. For Teams Toolkit local debug functionalities, see [how to debug your Teams app locally](debug-local.md).
You can perform the following steps to add SSO using Teams Toolkit in Visual Stu
1. Select the required application type under **Create a new Teams application**, clear the **Configure with single sign-on** check box.
-1. Select **create**.
+1. Select **Create**.
:::image type="content" source="../assets/images/teams-toolkit-v2/add-sso-vs/vs-2022-preview-create-teamsapp-sso-uncheck_1.png" alt-text="select the teams app to be created and uncheck sso check box" lightbox="../assets/images/teams-toolkit-v2/add-sso-vs/vs-2022-preview-create-teamsapp-sso-uncheck.png":::
platform Debug Background Process https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/debug-background-process.md
Teams Toolkit checks the following prerequisites during the debug process:
For more information, see [Node.js version compatibility table for project type](tools-prerequisites.md#nodejs-version-compatibility-table-for-project-type).
-* Teams Toolkit prompts you to sign-in to Microsoft 365 account, if you haven't signed in with your valid credentials.
+* Teams Toolkit prompts you to sign in to Microsoft 365 account, if you haven't signed in with your valid credentials.
* Custom app uploading or sideloading for your developer tenant is turned on, to prevent local debug termination. * Teams Toolkit installs Ngrok npm package `ngrok@4.2.2` in `~/.fx/bin/ngrok`, if Ngrok isn't installed or the version doesn't match the requirement. Ngrok binary version 2.3 is applicable for bot and message extension. The Ngrok binary is managed by Ngrok npm package in `/.fx/bin/ngrok/node modules/ngrok/bin`. * Teams Toolkit installs Azure Functions Core Tools npm package. `azure-functions-core-tools@3` for **Windows** and **MacOs** in `~/.fx/bin/func`, if Azure Functions Core Tools version 4 isn't installed or the version doesn't match the requirement. The Azure Functions Core Tools npm package in `~/.fx/bin/func/node_modules/azure-functions-core-tools/bin` manages Azure Functions Core Tools binary. For Linux, the local debug terminates.
platform Debug Local https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/debug-local.md
Perform the following steps using the Teams Toolkit to debug your app after you
:::image type="content" source="../assets/images/debug-teams-app/vs-localdebug-teamsappdependencies.png" alt-text="Teams app dependencies for local debug" lightbox="../assets/images/debug-teams-app/vs-localdebug-teamsappdependencies.png"::: > [!NOTE]
- > In this scenario the project name is MyTeamsApp1
+ > In this scenario the project name is MyTeamsApp1.
Your Microsoft 365 account needs to have the side loading permission before you sign in. Ensure your Teams app can be uploaded to the tenant, otherwise your Teams app can fail to run in Teams Client.
platform Faq https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/faq.md
Before provision, the tool asks you if you want to create a new resource group o
<details>
-<summary><b>How can I provision sharepoint-based app?</b></summary>
+<summary><b>How can I provision SharePoint-based app?</b></summary>
You can follow [provision SharePoint-based app](/microsoftteams/platform/sbs-gs-spfx?tabs=vscode%2Cviscode&tutorial-step=4). > [!NOTE]
-> Currently, the building Teams app with sharepoint framework with Teams Toolkit doesn't have direct integration with Azure, the contents in the doc doesn't apply to SPFx based apps.
+> Currently, the building Teams app with SharePoint framework with Teams Toolkit doesn't have direct integration with Azure, the contents in the doc doesn't apply to SPFx based apps.
<br>
platform Publish https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/publish.md
The following steps help you to publish the app from Teams Toolkit:
1. You can publish your Teams app in one of the following ways: * Select **Publish to Teams** under **DEPLOYMENT**.
- * Select **View > Command Palette... > Teams: Publish to Teams**.
+ * Select **View** > **Command Palette...** > **Teams: Publish to Teams**.
:::image type="content" source="../assets/images/teams-toolkit-v2/teams toolkit fundamentals/select-publish_1.png" alt-text="Select Publish":::
platform Test App Behavior https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/test-app-behavior.md
Title: Test app behavior in different environment description: In this module, learn how to test app behavior in different environment-+ ms.localizationpriority: high Last updated 03/03/2022
You can test your Teams app after integrating with Microsoft Teams. To test your
* **Locally hosted in Teams**: Teams Toolkit locally hosts your Teams app by sideloading it into Teams for testing in local environment.
-* **Cloud-hosted in Teams**: For testing your Teams app remotely, you need to Cloud-host it using provisioning and deploying on Microsoft Azure Active Directory(Azure AD). It involves uploading your solution to the Azure AD and then upload into Teams.
+* **Cloud-hosted in Teams**: For testing your Teams app remotely, you need to Cloud-host it using provisioning and deploying on Microsoft Azure Active Directory (Azure AD). It involves uploading your solution to the Azure AD and then upload into Teams.
> [!NOTE] > For production-scale debugging and testing, we recommend that you follow your own company guidelines to ensure you are able to support testing, staging, and deployment through your own processes.
You can test your Teams app after integrating with Microsoft Teams. To test your
Teams is a cloud-based product that requires all services it accesses, to be available publicly using HTTPS endpoints. Local hosting is about sideloading into Teams for testing in local environment. > [!NOTE]
-> Although you can use any tool of your choice for testing, we recommend you to use [ngrok](https://ngrok.com/download)
+> Although you can use any tool of your choice for testing, we recommend you to use [ngrok](https://ngrok.com/download).
## Cloud-hosted environment
platform Use CICD Template https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/use-CICD-template.md
If there are any changes related to Teams app's manifest file, you can update th
Perform the following steps to publish your app:
-1. Sign-in to [Developer portal for Teams](https://dev.teams.microsoft.com) using the corresponding account.
-2. Import your app package in zip, select `App -> Import app -> Replace`.
+1. Sign in to [Developer portal for Teams](https://dev.teams.microsoft.com) using the corresponding account.
+2. Import your app package in zip, select **App** > **Import app** > **Replace**.
3. Select the target app in app list. 4. Publish your app, select `Publish -> Publish to your org`.