Service | Microsoft Docs article | Related commit history on GitHub | Change details |
---|---|---|---|
platform | Teams Live Share Canvas | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-canvas.md | document.getElementById("line-tip-size").onclick = () => { You can clear all strokes in the canvas by calling `inkingManager.clear()`. This deletes all strokes from the canvas. +#### Import and export raw strokes ++Live Share Canvas supports importing and exporting raw strokes from `InkingManager`, which enables you to export them to your back-end for later use in a future session. ++```javascript +// Export raw strokes +const strokes = inkingManager.exportRaw(); ++// Optionally clear out existing strokes, and import strokes +inkingManager.clear(); +inkingManager.importRaw(strokes); +``` ++#### Export strokes as an SVG ++You can export your entire drawing within the `InkingManager` to a scalable vector graphic (SVG). The SVG contents are returned as a string, which you can then store in your server as an .svg file extension. ++```javascript +// Export raw strokes +const svgText = inkingManager.exportSVG(); +``` + ### Cursors :::image type="content" source="../assets/images/teams-live-share/canvas-cursors.gif" alt-text="GIF shows an example of users sharing a cursor on a canvas."::: |
platform | Teams Live Share Capabilities | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/teams-live-share-capabilities.md | timer.play(); :::image type="content" source="../assets/images/teams-live-share/live-share-state.png" alt-text="Screenshot shows an example of Live Share state to synchronize what planet in the solar system is actively presented to the meeting."::: -The `LiveState` class enables synchronizing simple application state for everyone in a meeting. `LiveState` synchronizes two values: a `state` string and a corresponding `data` object, which allows you to build an ephemeral distributed-state machine. +The `LiveState` class enables synchronizing simple application state for everyone in a meeting. `LiveState` synchronizes a single `state` value, allowing you to synchronize any JSON serializable value, such as a `string`, `number`, or `object`. The following are a few examples in which `LiveState` can be used in your application: The following are a few examples in which `LiveState` can be used in your applic - Synchronizing the current step in a multi-round group activity. For example, the guessing phase during the Agile Poker game. > [!NOTE]-> Unlike `SharedMap`, the `state` and `data` values in `LiveState` will be reset after all the users disconnect from a session. +> Unlike `SharedMap`, the `state` value in `LiveState` will be reset after all the users disconnect from a session. Example: const schema = { const { container } = await liveShare.joinContainer(schema); const { appState } = container.initialObjects; -// Register listener for changes to state and corresponding custom data -appState.on("stateChanged", (state, data, local) => { - if (state === "planet-viewer") { - const planetName = data?.planetName; - // Update app to display an image of the selected planet for the selected solar system - } else { - // No planet is yet selected - } +// Register listener for changes to state +appState.on("stateChanged", (planetName, local) => { + // Update app with newly selected planet }); -// Set roles who can change state and start listening for changes -appState.initialize(); +// Set a default value and start listening for changes +await appState.initialize("Mercury"); function onSelectPlanet(planetName) {- appState.changeState("planet-viewer", { - planetName, - }); + appState.set(planetName); } ``` enum PlanetName { NEPTUNE = "Neptune", } -// Declare interface for type of custom data for user -interface ICustomState { - planetName: PlanetName; -} - // Join the Fluid container const host = LiveShareHost.create(); const liveShare = new LiveShareClient(host); const schema = { initialObjects: {- appState: LiveState<ICustomState>, + appState: LiveState<PlanetName>, }, }; const { container } = await liveShare.joinContainer(schema);-const appState = container.initialObjects.appState as LiveState<ICustomState>; +const appState = container.initialObjects.appState as LiveState<PlanetName>; -// Register listener for changes to state and corresponding custom data -appState.on("stateChanged", (state: string, data: ICustomState | undefined, local: boolean) => { - if (state === "planet-viewer") { - const planetName = data?.planetName; - // Update app to display an image of the selected planet for the selected solar system - } else { - // No planet is yet selected - } +// Register listener for changes to state +appState.on("stateChanged", (planetName: PlanetName, local: boolean) => { + // Update app to display an image of the selected planet for the selected solar system }); -// Set roles who can change state and start listening for changes -appState.initialize(); +// Set a default value and start listening for changes +await appState.initialize(PlanetName.MERCURY); function onSelectPlanet(planetName: PlanetName) {- appState.changeState("planet-viewer", { - planetName, - }); + appState.set(planetName); } ``` const schema = { const { container } = await liveShare.joinContainer(schema); const { appState } = container.initialObjects; -// Register listener for changes to state and corresponding custom data -appState.on("stateChanged", (state, data, local) => { +// Register listener for changes to state +appState.on("stateChanged", (state, local) => { // Update local app state }); // Set roles who can change state and start listening for changes+const initialState = { + documentId: "INITIAL_DOCUMENT_ID", +}; const allowedRoles = [UserMeetingRole.organizer, UserMeetingRole.presenter];-appState.initialize(allowedRoles); +await appState.initialize(initialState, allowedRoles); function onSelectEditMode(documentId) {- appState.changeState("editing", { + appState.set({ documentId, }); } function onSelectPresentMode(documentId) {- appState.changeState("presenting", { + appState.set({ documentId, presentingUserId: "LOCAL_USER_ID", }); const schema = { const { container } = await liveShare.joinContainer(schema); const appState = container.initialObjects.appState as LiveState<ICustomState>; -// Register listener for changes to state and corresponding custom data -appState.on("stateChanged", (state: string, data: ICustomState | undefined, local: boolean) => { +// Register listener for changes to state +appState.on("stateChanged", (state: ICustomState, local: boolean) => { // Update local app state }); // Set roles who can change state and start listening for changes+const initialState: ICustomState = { + documentId: "INITIAL_DOCUMENT_ID", +}; const allowedRoles: UserMeetingRole[] = [UserMeetingRole.organizer, UserMeetingRole.presenter];-appState.initialize(allowedRoles); +await appState.initialize(initialState, allowedRoles); function onSelectEditMode(documentId: string) {- appState.changeState("editing", { + appState.set({ documentId, }); } function onSelectPresentMode(documentId: string) {- appState.changeState("presenting", { + appState.set({ documentId, presentingUserId: "LOCAL_USER_ID", }); |
platform | Locally With An Ide | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/debug/locally-with-an-ide.md | If you're hosting your bot locally during development, you need to use a tunneli ngrok http <port> --host-header=localhost:<port> ``` -Use the https endpoint provided by ngrok in your app manifest. +Use the https endpoint provided by ngrok in your [app manifest](../../../resources/schem). > [!NOTE] > If you close your command window and restart, a new URL is generated and you need to update your bot endpoint address to use it. |
platform | Get Teams Context | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/get-teams-context.md | public class MyBot : TeamsActivityHandler * [SDK reference](/javascript/api/botbuilder/teamsinfo?view=botbuilder-ts-latest#botbuilder-teamsinfo-getmember&preserve-view=true) -* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L157) +* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L186) ```typescript export class MyBot extends TeamsActivityHandler { |
platform | Manifest Schema | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/resources/schema/manifest-schema.md | The following is the sample manifest schema: { "name": "keyword", "title": "Search keywords",- "inputType": "text", + "inputType": "choiceset", "description": "Enter the keywords to search for", "value": "Initial value for the parameter", "choices": [ |
platform | Using Teams Client Library | https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/tabs/how-to/using-teams-client-library.md | For more info, see [Extend Teams apps across Microsoft 365](../../m365-apps/over ### Callbacks converted to promises +> [!NOTE] +> The `getTabInstances` API isn't implemented on Teams mobile. + Teams APIs that previously took a callback parameter have been updated to return a JavaScript [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) object. These include the following APIs: ```js |