Author: Cristiano Goncalves

Multi-cloud certified architect (Microsoft, Amazon, and Google). More than two decades of experience in consulting delivery and technical sales. Currently a Technical Customer Success Manager in Microsoft HQ with the mission to partner with field CSM community to build platform capability and scale best practices.

Teams Speaker Queue now in 44 languages

A few weeks ago we released Speaker Queue Teams Speaker Queue | techpeanuts (tech-peanuts.com) a Teams meetings extensibility app template created to improve your meetings by defining and controlling time designated for each speaker/topic.

We are now releasing version 1.1 with bug fixes and support for 44 languages! Please try it, give your feedback and contribute to improve it.

Release Version 1.1 · OfficeDev/microsoft-teams-apps-speaker-queue (github.com)

Enjoy!

Disclaimer – The information contained in this blog post doesn’t represent the official Microsoft guidance or best practices. It is just the view of the author on current alternatives, implementations and workarounds for common issues and/or business needs. Please refer to official Microsoft documentation and evaluate carefully any steps, code or procedures documented herein. The author doesn’t offer any warranty. Use this information at your own risk.

Teams Company Communicator Improvements

What is Company Communicator?

Company Communicator or just CC is one of the most used Teams app templates. It enables corporate teams to create and send messages intended for multiple teams or large number of employees over chat, allowing organization to reach employees right where they collaborate. 

Thousands of customers use Company Communicator every day for scenarios like new initiative announcements, employee onboarding, modern learning and organization-wide broadcasts.

CC is backed by an Azure app service with a React app providing an interface for designated content users to create, preview, collaborate and send messages. It is a great example of how Azure can be used to extend teams, leveraging multiple cloud concepts and Azure services like functions, storage, bots and the service bus.

Being so widely used, Company Communicator is also the number one app in feature requests. Some of our smartest partners are currently working with multiple customers defining new scenarios, implementing extensions and other customizations. Those engagements generate CC variations and bring more and more customers to know and use the template.

Overview

Motivation

We all know that a diverse company is always better positioned to retain talent, and ultimately win on the competitive market.

A few weeks ago my colleague @Pradeep Bethi came up with the result of an effort to create a solution to congregate people around Employee Resource Groups (ERGs), have an efficient way to communicate messages and provide an intelligent way to clarify and ask questions, contributing to the overall company diversity.

The diverse team lead by Pradeep was able to combine Company Communicator, FAQ Plus and a brand new React application to create a new Teams app template with the major goal to foster diversity and inclusion in enterprises.

Customers loved that template, but some of the limitations of Company Communicator came to light. They were complaining of basically two things:

  1. The “feature” that basically mandate that images used in communications need to be posted in a public website. Authors in Company Communicator just reference, using an URL the image that is going to be used in the cards sent to users.
  2. Inability to schedule messages. Customers would like to schedule a few communication messages to be sent in the future. For example they could pre-configure the app to send customized messages on specific D&I dates of interest like the ones listed by the United Nations International Days and Weeks | United Nations or other websites like 2021 Workplace Diversity and Inclusivity D&I Calendar | Kazoo (kazoohr.com).

Great chance to engage and support!

New Features

Two new features were incorporated into a fork of Company Communicator 4.1 and also ported to the D&I Connect App template. Github repositories with both solutions are available for your reference:

Upload Image

The upload image feature is basically a button to allow authors to upload images to be used in Company Communicator communications. It is a front-end modification made in a single page of the CC React client application that uses a few react components and a custom function to convert an image on its base64 representation.

The same column used to store the image URL is used to store the base64 string. That allowed no changes in the Azure back-end components and a simple deployment. Azure storage tables have a limitation of 64kb and Teams can only support adaptive cards with 32kb in total. So the change we made controls the size of uploaded images to ensure we will not violate those limitations.

The result allows customers to use company communicator without the requirement to keep internal images in publicly accessible websites.

The new upload button when creating new company communicator messages

Message Scheduler

The message scheduler is a more complex change. New columns were incorporated to the Azure storage table to control the scheduled date and the status of the messages. A new background task was also implemented using IHostedService and the BackgroundService class.

The background service checks every 5 minutes if there are pending scheduled messages to send and execute the steps required to send the notifications appropriately.

We also made a few changes on the interface to allow authors to define when messages will be sent.

The new scheduler interface

When scheduled, messages become available in a third section created in the main messages interface. The Scheduled Message section allows authors to send notifications right away, make edits, copy the message, etc.

The new Scheduled messages section

Deployment

Sold to the new Company Communicator improvements? The deployment is super easy. If you already have Company Communicator 4.1 deployed, just open your Azure portal, select the App Service you are using to host the application and click Deployment Center.

Disconnect the source you are using and create a new External Git connection pointing to the repo where the changes were incorporated.

After disconnecting the previous GitHub source, under manual deployment (push), select External Git.

Then on Repository, type the https://github.com/cristianoag/microsoft-teams-apps-company-communicator.git, under Branch type master.

Now click Save and then Sync.

Wait until the deployment finish. You will have your Company Communicator with the new scheduler and the ability to upload files.

Comment if you have questions or need help! Have fun, Cristiano.

Disclaimer – The information contained in this blog post doesn’t represent the official Microsoft guidance or best practices. It is just the view of the author on current alternatives, implementations and workarounds for common issues and/or business needs. Please refer to official Microsoft documentation and evaluate carefully any steps, code or procedures documented herein. The author doesn’t offer any warranty. Use this information at your own risk.

Teams Speaker Queue

Hi there! We’re all participating in a ridiculous amount of online meetings lately. Some very organized, some fun, some rewarding, but some just disorganized and a waste of time. How can we help to improve your online meetings?

A few months ago I started playing with meetings extensibility and Power Apps. The very first example I created was just a clock application to kind of measure the amount of time spent by speakers during a meeting. That was subject of the Power Apps with Teams Meetings Extensibility | techpeanuts (tech-peanuts.com) article I posted here.

Since then a lot happened. We now have Power Apps design tools inside Teams, we have a Teams object in Power Apps to collect specific information about the various contexts and we have Microsoft Dataverse.

Well… why not combine all those things and expand the clock idea into a Speaker Queue application for Teams? That happened!

With the awesome support, guidance, sample code, and extensive contribution from @Dajian Dong, @Aditya Challapally, @Shuo Chen, @Pawan Gulati and others, I have the pleasure to announce the pre-release of the Speaker Queue App template.

Speaker Queue is a Teams meetings extensibility app template created to improve your meetings. It can be used to define topics and control the time assigned to each speaker during online meetings.

Once deployed, Speaker Queue can be configured in meeting invites, offering experiences before and during online meetings. Before your meeting, you can use the app to define a person who will be responsible to control the list of topics/speakers and during meetings, the app offers a synchronized countdown view to all participants, so they can be aware of speaker turns.

The Speaker Queue app template is currently in pre-release and will be published in the official Teams App Templates page soon.

I would like to invite you to deploy the pre-release version and contribute to the project using our official GitHub project page. Please if you find any issues use GitHub to let us know and improve the application.

Check the following resources available today for you:

UPDATED ON 5/4/2021 – New version published Release Version 1.1 · OfficeDev/microsoft-teams-apps-speaker-queue (github.com)

Have fun! and improve your online meetings… 🙂

Cristiano

Disclaimer – The information contained in this blog post doesn’t represent the official Microsoft guidance or best practices. It is just the view of the author on current alternatives, implementations and workarounds for common issues and/or business needs. Please refer to official Microsoft documentation and evaluate carefully any steps, code or procedures documented herein. The author doesn’t offer any warranty. Use this information at your own risk.

A Simple Teams Meetings Extensibility App – Part 1

A few weeks ago I published an article here explaining how to use Power Apps to extend meetings in Teams. Power Apps is super easy and powerful, but so far it doesn’t provide access to all Teams meetings extensibility APIs. The only thing we can basically do with Power Apps currently is place the app in a panel that runs during meetings or work with the pre/post tabs to deliver experiences.

This time I want to provide a simple step by step approach to create meetings extensibility experiences on its full potential. For that we will need traditional web development. I’ll try to keep things simple and at the same time bring new cloud concepts so you can learn new things reading the article.

First a few concepts

If you search for meetings extensibility APIs documentation you will find that currently we can create apps to interact with teams meetings in many ways. We can call the Graph API and create meetings, we can get meeting information also using Graph API, and we can also create apps that interact with meetings in pre/during/post moments.

Meetings extensibility apps (the ones that run pre/during/post meetings) can basically call three APIs to get information about the meeting, its participants and to create pop-up notifications.

Pre and post meetings experiences are implemented by your app running in a tab configured in the meeting invite.

Pre-Meeting Application running in an invite tab

pre-meeting tab view

Post-Meeting Application running in an invite tab

post meeting view

During meetings, apps can run on a side panel or create pop-up notifications to interface with users.

In-Meeting Side Panel AppIn-meeting-dialog view

In-Meeting Pop-Up notification

in-meeting experience

How to create my first meetings extensibility app

As I said, let’s keep things simple. Let’s focus on creating a pre-meeting tab and learn how to call the APIs so we can get your first meeting extensibility app running inside teams.

Requirements

Uploading the Aample App

  • Create a folder where you will place all your app files. We will create three files:
    • main.css will have the styles that we will use in the html single page application we are creating.
    • index.html will have the single page application (html and JavaScript) that we will use for the main app.
    • config.html will have the configuration page for the app.
  • Open a command prompt, navigate to the folder you created and type “code .”
  • Click File, New File.
  • Paste the following code:
body {
    font-family: monospace;
}

ul {
    font-family: helvetica;
}

li {
    list-style: circle;
  }
  
.list {
    list-style: square;
  }
  
#msg {
    font-family: monospace;
}
  • Save the file as main.css.
  • Click File, New File.
  • Paste the following code:
<!DOCTYPE html>
<html>
<head>
    <script src= 'https://statics.teams.cdn.office.net/sdk/v1.6.0/js/MicrosoftTeams.min.js'></script>
    <meta charset="UTF-8">
    <title>Teams - Really Simple Meetings Extensibility SPA - Config Page</title>
    <link rel="stylesheet" href="main.css">
</head>

<body>
    <h1>Config Page</h1>
    <h2>Present some configuration options here and let the person who is configuring the app change settings.</h2>
    <h2>Icons, colors, differente content pages, etc</h2>

    <script>

    microsoftTeams.initialize();
    microsoftTeams.settings.setSettings({
        contentUrl: "https://m365x257948blogpost1.z22.web.core.windows.net/index.html",
        entityId: "123456",
        suggestedDisplayName: "Meeting Panel",
        websiteUrl: "https://m365x257948blogpost1.z22.web.core.windows.net/index.html"
    });
    microsoftTeams.settings.setValidityState(true);
    
    </script>
</html>
  • Save the file as config.html. Note that we will return to this file later to update the contentUrl and websiteUrl with the URL of the index.html file.
  • Click File, New File.
  • Paste the following code:
<!DOCTYPE html>
<html>
<head>
    <script src= 'https://statics.teams.cdn.office.net/sdk/v1.6.0/js/MicrosoftTeams.min.js'></script>
    <meta charset="UTF-8">
    <title>Teams - Really Simple Meetings Extensibility SPA</title>
    <link rel="stylesheet" href="main.css">
</head>

<body>

    <!-- html -->
    <h1 id='h1title'></h1>
    <table>
        <tr><td>User: </td><td><div id='userid'></div></td></tr>
        <tr><td>Theme: </td><td><div id='theme'></div></td></tr>
        <tr><td>MeetingId: </td><td><div id='meetingid'></div></td></tr>
        <tr><td>FrameContext: </td><td><div id='framecontext'></div></td></tr>
    </table>
    <!-- html -->

    <script>
    let h1 = document.getElementById('h1title');
    
    //initializes Teams SDK
    microsoftTeams.initialize();
    
    //gets the user context using Teams SDK
    microsoftTeams.getContext((context) =>{
        let userId = document.getElementById('userid');
        let theme = document.getElementById('theme');
        let meetingId = document.getElementById('meetingid');
        let frame = document.getElementById('framecontext');

        //updates the divs in the table with the context variables
        userId.innerHTML = context.userPrincipalName;
        theme.innerHTML = context.theme;
        meetingId.innerHTML = context.meetingId;
        frame.innerHTML = context.frameContext;

        //checks if the tab is running on the panel or in pre-meeting
        if (context.frameContext == 'content') {
            h1.innerHTML = 'This is the pre-meeting experience';
        } else {
            h1.innerHTML = 'This is the side panel content';
        }
    });
    </script>
</html>
  • Save the file as index.html.
  • Click the Azure icon on the left rail in VS Code. Expand Storage and then your Azure subscription. Right click the subscription and select Create Storage Account.
image_thumb.png
  • Provide a name for your storage and click Enter. Wait until the storage account is created in your subscription. When the storage account is created, right click it and select the “Configure Static Website…”.
image.png
  • Press Enter to confirm index.html as the index document name (you will need to upload the file as index.html). And press Enter to confirm the default value for the 404 error message. Wait until the storage is configured to host static websites.
  • Go back to the VS Code Explorer and right click the index.html file (the file you created/edited). Select “Upload to Azure Storage…”. Select your subscription and the storage account you created and configured. Select Blob Containers, then $Web, then /.
  • Your files will be uploaded to the Azure Storage.
  • Click the Azure icon on the left rail in VS Code. Expand Storage and then your Azure subscription. Right click the Storage you created and select Browse Static Website. In your browser, copy the URL of the website.
  • Now edit the config.html file and paste the value you copied on contentUrl and websiteUrl
  • Upload the config.html and the main.css files to the Azure Storage. You need to right click the files and select the option to Upload to Azure Storage. Select your subscription and the storage account you created and configured. Select Blob Containers, then $Web, then /.

Creating the Teams Manifest

Now that you have the sample application already uploaded to the Azure Storage, we need to configure a teams manifest to make it available inside Teams. 

  • Download the sample manifest file here. 
  • Unzip the file and edit the manifest.json file.
  • Change the value of configurationUrl to point to the URL of your config.html file. Remember that it is the base URL of your Azure Storage + /config.html.
  • Replace the value you will find in validDomain by the base URL you have for your Azure Storage. Please note that validDomain doesn’t need the https:// on the beginning of the value.
  • Save the json file. 
  • Zip the manifest.json file together with the two icons you have on the original zip package. Make sure all files are in the root of the zip file.
  • Now open your teams client and load the zip file as an app. You need to click apps, then Upload a Custom App.
  • Remember this is a meetings extensibility app, so it will be available to be included in calendar items when you invite someone for a meeting.

When creating the meeting, inviting someone and adding the app, you will get the configuration message and need to click Save. As soon as you do that, the application will be incorporated into the meeting invite and you will see the screen below.

Screenshot 2021-02-23 170858

Note that if you join the meeting, the app will be available to run as soon as you click on the icon that is available on the top right corner.

Screenshot 2021-02-23 171132

What I’ve Done?

Well. Now some context on what you just finished. Your app is a simple HTML page (a single page application) that uses JavaScript to call the Teams Client SDK. The latest version of the SDK has one of the APIs that we use for Teams meetings extensibility apps.

That is the API to get the user context. 

Screenshot 2021-02-23 171527

The user context provides some properties you use for your application. For example you know using the FrameContext property if the application is running in the pre/post meeting tab or in the in-meeting side panel. That is important so you can make your application behave appropriately depending on where your users are using it.

Another important property is the MeetingID. When you have the meeting identification you can call other APIs and get data about the invite or other properties of the meeting. You also have access to the theme used in Teams as well as the user name running your app.

The list of properties returned by the microsoftTeams.getContext API is available at Get context for your tab – Teams | Microsoft Docs

Now I invite you to check the code and discover where in the index.html we are calling the getContext API. You will see that it is a simple JavaScript call to the Teams Client SDK.

The other APIs available to get the role of the user in the meeting and to create notification popups will be object of the part 2 of this article.

Have fun and thanks for reading!

Cristiano

Disclaimer – The information contained in this blog post doesn’t represent the official Microsoft guidance or best practices. It is just the view of the author on current alternatives, implementations and workarounds for common issues and/or business needs. Please refer to official Microsoft documentation and evaluate carefully any steps, code or procedures documented herein. The author doesn’t offer any warranty. Use this information at your own risk.

How to run any website as a Teams app!

The Request and Initial Learnings

So you have been asked to make your company website or your company intranet website available in Teams… directly
from the left rail. That is, together with the Activity, Chat, Teams, Calendar, and other default Teams icons, you
want a button to allow your users access the Intranet directly from the main Teams window (figure below on the left).

image  image

You take the first step and research how to do it. You find out that using an app called App Studio you can create something called manifest and also a Teams App, that combines the manifest and the icons you want to display on Teams. Nice!

You go ahead and install App Studio. Run it and click on the Create a new app in the Manifest editor tab.

You fill out the basic information for the app and then click Tabs under capabilities. That is the place where you will add your Personal Tab. The personal tab is the entity that will be used to link your website to the button/icon that will be displayed on the Microsoft Teams interface.

You call the personal tab Intranet, use an unique entity id and use both Content URL and Website URL fields to point to the website you want to link. For the purpose of this article, let’s use the ubiquitous https://www.microsoft.com web site (figure above on the right).

Nice!!! We’re getting there. Now we need to install the app in Teams and test (before go through the whole process to publish the app to all company users). You save your tab, go to Test and Distribute under Finish and hit Install. Voilá… you now have the nice Intranet button on your Teams client. Ready to test!

But as any good feeling in IT is followed by a deception, it didn’t work.  You click your button and you just see a blank page. Nothing from the known microsoft.com website.

The Problem

So why https://www.microsoft.com website is not displaying on Teams (please replace www.microsoft.com by any website you are using and keep in mind that some websites work and some don’t).

But why am I getting a blank page? That is because www.microsoft.com and many other websites have a security feature that blocks them to be loaded inside an iFrame, and Teams personal tabs are implemented using an iFrame.

You can easily prove that is the issue with a simple html with an iFrame. Just save the content below as iframetest.html and open it in your browser.

Click here to download the iframetest.html file (code below).

image

You will see the following result:

image

Going a little further on the technical details, the reason behind is associated to a specific http header that is sent by the webserver hosting the website that doesn’t display ok. The header is called X-Frame-Options and with the value SAMEORIGIN, instructs your browser to block the display of the website in iFrames hosted outside websites with the same domain name of the website you want to display. So the iFrame would only work if hosted in any *.microsoft.com website.

If you are curious you can use POSTMAN or Fiddler to check on the returned headers and verify by your own means.

OK. Problem understood, how can we still run the intranet (or www.microsoft.com) inside Teams and have a button on the left rail pointing to the website?

Solution

First you need to understand that tabs in channels are not leveraging iFrames. Those tabs load websites just like your browser, so a site loaded by the Website app in a tab on a Teams channel is not subject to the X-Frame-Options restrictions.

Step 1 – Run your website on a tab in a channel inside a company wide team

So the first step in our solution is to create a company-wide team in Teams and create a tab in a channel using the Website app.

image image

You will end up with the www.microsoft.com (or your website that is unable to run inside an iFrame, running on a tab inside a channel of your Teams team). In the case below I have the microsoft.com website running in a tab of the General channel in my team.

image

Step 2 – Copy the link to your tab

Now that you have your tab running the “protected” website, click on the … on the upper right and select the Copy link to tab option. Save the value that was stored in your clipboard in a notepad, you will need it for the next step.

image

Step 3 – Create the Deeplink Execution html

Now we will create a html file with a javascript code that will instruct teams to execute a deeplink to the tab where you have your website running. It is a pretty simple html that loads the Teams client SDK and execute a single instruction to navigate to the tab. You need to get the content below, edit it and replace the value indicated as [LINK TO THE TAB]with the value you saved on step 2.

Click here to download the index.html file (code below)

image

Step 4 – Make the file accessible

Now you need to make your file accessible from Teams. You app will call the html file and you need a way to serve the https request for that. There are many options. You can host the file in an Azure Blob (free for the first 12 months and then USD 0.01 per month for 1GB – list price on 1/7/2021), you can use AWS S3, Google Cloud storage, a webserver that you have on-prem… you choose.

In this tutorial I’m using an Azure Blob Storage. I loaded my html file into Visual Studio Code and installed the Azure Storage extension. With the extension I can do everything from Visual Studio Code.

Click the Azure icon on the left rail in VS Code. Expand Storage and then your Azure subscription. Right click the subscription and select Create Storage Account.

image

Provide a name for your storage and click Enter. Wait until the storage account is created in your subscription. When the storage account is created, right click it and select the “Configure Static Website…”.

image

Press Enter to confirm index.html as the index document name (you will need to upload the file as index.html). And press Enter to confirm the default value for the 404 error message.

Now go back to the VS Code Explorer and right click the index.html file (the file you created/edited). Select “Upload to Azure Storage…”. Select your subscription and the storage account you created and configured. Select Blob Containers, then $Web, then /.

image

Click again on the Azure icon, expand storage, your subscription, right click the storage account and select Browse Static Website. You must see a blank page with the title “Teams Deep Link Example”.

image

Note that similar result can be achieved with any cloud storage service or even a on-premises web server that is capable to host a single static html page via HTTPS protocol.

Step 5 – Update your Teams App

Now you’re ready to go back to App Studio and replace the direct website URL you used by the one you browsed from Azure Blob storage.

Open the Teams client and run the App Studio. Click Manifest Editor and click the App you created previously. Click Tabs and edit the tab you created. In my case I’m replacing https://www.microsoft.com by https://teamstest1.z22.web.core.windows.net which is the URL that points to my static web website hosted on Azure Blob storage.

image

Click Save. Click Test and distribute under Finish and re-install the app for test purposes. Now every time you click on the Intranet icon available on the left rail, the Teams client will execute the code in your html page and navigate to the tab where the website is loaded.

Thanks for reading this!

Cristiano

Disclaimer – The information contained in this blog post doesn’t represent the official Microsoft guidance or best practices. It is just the view of the author on current alternatives, implementations and workarounds for common issues and/or business needs. Please refer to official Microsoft documentation and evaluate carefully any steps, code or procedures documented herein. The author doesn’t offer any warranty. Use this information at your own risk.

Power Apps with Teams Meetings Extensibility

Microsoft Teams has brand new extensibility points that will enable developers to expand the meeting experience. With this new capability, developers are able to build apps or integrate existing ones within the meeting surface and provide richer collaboration experiences for users across the entire meeting lifecycle – covering events and actions from before, during, and after a meeting.

The whole concept was created to have standard web solutions incorporating the ability to interface with Teams meetings through configurable tabs and the Teams client JavaScript SDK, but what about Power Apps?

What if we can combine Power Apps with the new meetings extensibility features and quickly create applications to interface with the meeting surface. It can be done, well… currently with some limitations, but what is currently available is at least enough to get our hands dirty and create some cool stuff.

Here is what I’m trying to achieve:

“I want to create a very simple application that can be incorporated and used by any meeting participant to track time  during a meeting. It will present a clock in stop watch mode (regressive timer) that can be adjusted and used to ensure you will use the meeting time in the most efficient way.”

Untitled

Step 1 – Create the Power App

The power app will have two screens. The first one will be presented just after the configuration of the app in the meeting, just to provide more information on the purpose of the application. The second one will have the stopwatch logic, as well as a time picker and a button to set/reset the regressive counter.

Screenshot 2020-12-10 180919

Screen Intro is the first app screen. It has just three labels to present a text message to all users configuring the application on the meeting invite.

Screen Timer has a group of components formed by TextInput2 and Icon1 to allow users to set the stopwatch. The icon was used just to create a good looking text box with a small watch. The Button1 is used to set the Timer1 object with the start value and the cmp_TimePicker_1 is a custom time picker that allows users to select hours, minutes and seconds that will be configured as the start value for the stopwatch.

The cmp_TimePicker component was created and documented by Matthew Devaney here (Make A Time Picker In Power Apps – Matthew Devaney) if you are interested.

As I’m using the component to select hours, minutes and seconds I made a few changes to remove the AM/PM selection and include the ability to select seconds. 

Here are the two screens in the initial state.

Screenshot 2020-12-10 181732

Screenshot 2020-12-10 181816

One important thing is the logic required to decide which screen present when. When the Power App is called from Teams, we need to detect if it is being executed from the tab pre-meeting or during the meeting. To create the detection logic I’m using a context variable that is incorporated by Teams when calling the Power App.

The logic was incorporated to the initial execution of the app and based on the context we decide if we will navigate to Intro or Timer screens. Here is the relevant code:

Set(varSubEntityId, Param(“subEntityId”));


If(
     varSubEntityId = “{subEntityId}”,
     Set(
         varInMeeting,
         true
         ),
     Set(
         varInMeeting,
         false
         )
);


If (varInMeeting, Navigate(‘Screen Timer’), Navigate(‘Screen Intro’));

If you are not familiar with Power Apps and just want to have access to the sample package with the clock, please click here and download the zip file with the app. You will need to import it in your Power Apps environment. After the import, please save and share the app with all the users that will use it… and remember, this is not a production ready app, it is a prototype just to prove a concept.

Step 2 – Teams App

Now that you have your Power App up and running, let’s work on the Teams App. A Teams app package is a.zip file containing the following: A manifest file named “manifest.json”, which specifies attributes of your app and points to required resources for your experience, a transparent “outline” icon and a full “color” icon.

The manifest file is the key file of the app and the one we need to dedicate time to configure the meeting experience based on the Power App.

Before we start, go to the Power Apps editor and get the URL of your Power App. You can do that opening powerapps.com, and selecting details on your app under Apps. The url will be listed under Web link.

Screenshot 2020-12-10 183521

We will need the value for App ID. Copy that value as you will need it to create your manifest file.

You will also need a random UUID for your Teams App. Please go to Online UUID Generator Tool and click “Generate a version 4 UUID”. Copy the value as you will need it in to create your manifest file.

Now you have the two values you need, go ahead and download the sample manifest from here. Unzip the file and open the manifest.json.

Replace <RANDOMUUID> with the value you generated for the random UUID.

Screenshot 2020-12-10 184319

Replace <APPID> with the value you copied from your Power App.

Screenshot 2020-12-10 184413

Save the manifest.json file and zip it again, together with the two icons. Make sure you are creating a file with all the files in the root of the zip file (very important).

Step 3 – Using your App

Now that you have your Teams App package (the zip file with the manifest and the two required icons) you will need to load it to Teams. You can load the app using the Teams Admin console (if you want to distribute the application in a more robust way) or you can just upload the file using your Teams client.

Here we will use the Teams client to upload the app. Open your Teams client and click in the Apps icon located in the lower left. Click on the Upload a custom app option and select Upload for <Your Company>.

Screenshot 2020-12-10 185004

Select the zip package and click Open. The app will be installed into Teams and will be available to be incorporated to meeting invites.

Now schedule a meeting with your colleagues, open the invite and click + on the top of the screen. You will see your app listed in the Optimized for meetings section. Click Meetings Timer and you will see a new tab in the invite.

Screenshot 2020-12-10 185233

Clicking on the Meetings Timer tab you will see the first Power App Screen (intro). Click join to enter the meeting. You will now see a new clock icon on the top of the screen. Click it and the second screen (timer) will be available on the right hand panel. You can select a time from the time picker, click set and start the stopwatch clicking on the big button.

Untitled

Limitations

I’m sure our dev team is still working to improve the experience with Power Apps in this new meetings extensibility scenario. Currently there are some limitations:

  • The meeting context (user role, meeting id, meeting members, etc) is only available via Teams Client SDK (based on JavaScript). As you may know, Power Apps doesn’t allow the use of custom JavaScript code in applications, so you’re unable to detect the user role, get the meeting id, and obtain other information from the context.
  • I also couldn’t find a way to use the application from the Teams web interface. The application is available, can be installed from the web interface but the button to activate it during the meeting is not presented.

If you followed those instructions and found additional limitations, please reach out. We will make sure to communicate to the right product groups and contribute to improve the product.

Have fun, Cristiano.

Disclaimer – The information contained in this blog post doesn’t represent the official Microsoft guidance or best practices. It is just the view of the author on current alternatives, implementations and workarounds for common issues and/or business needs. Please refer to official Microsoft documentation and evaluate carefully any steps, code or procedures documented herein. The author doesn’t offer any warranty. Use this information at your own risk.

COVID19 Building Access App: Community Led Improvements

Desk Reservations, Floor Maps, Impersonation,  Improved Notifications, and much more…

Hello there, since the launch of the BAR App (Building Access App) the community has been very active and we have many variations being created and shared. Our customers always have specific (sometimes crazy) requirements to unblock the app usage and it is unfortunate when I see the standard package not offering the ones required.

I have been dedicating some time lately to contribute and implement some of the most requested features.

In the spirit of the community I would like to share the latest enhancements with you all. I hope those can help your company during those difficult times. Remember, this application is free for any Office 365 subscriber.

Please reach out if you have questions.

Updated Package (v1.15)
http://aka.ms/bar115

20200909_195048000_iOS20200909_195123000_iOS20200909_195150000_iOS20200909_195211000_iOS

COVID19 Building Access App: Questions per Building

Part two of the Building Access App improvements article. This time I’m documenting steps to incorporate questions per building. With this new version you will not only be able to have different approvers per space but you will be able to configure different sets of questions per building.

You can use this version for scenarios where a specific building needs to have additional screening to make employees eligible to make reservations.

20200812_165218000_iOS20200812_165226000_iOS20200812_165239000_iOS20200812_165342000_iOS20200812_165349000_iOS

All the steps required to perform the required changes into the v1.1/v1.11 version are documented below. You can also access the modified package on GitHub using the link below:

https://github.com/cristianoag/BuildingAccess/releases/tag/v1.12

SharePoint

We will create two additional columns on the questions list stored SharePoint to create the relationship between buildings and questions. Additionally we will also create a column on the AppSettings list to store a flag that will control how if we will present questions per building or not.

  • Open SharePoint Online as administrator, access the site used to store data.
  • Include two additional columns (Building and Building:ID) in BAR_KeyQuestions.
    • Click Add Column, then select More…
    • In column name type Building. Select column type Lookup. Get information from the BAR_Buildings list and select Title from the “In this column” drop down. Select ID in “Add a column to show each of these additional fields”.
  • Include an additional Yes/No column (KeyQuestionsPerBuilding) in BAR_AppSettings. Select Yes/No Type. Default Value No.

Building Admin

The Building Admin app needs to be changed to include an additional configuration option to enable/disable the ability to present questions per building. We will also configure the forms to allow the relationship between buildings and questions.

  • Open PowerApps as administrator. Edit the Building Admin app.
  • Go to Data and refresh the BAR_KeyQuestions and BAR_AppSettings connections.
  • Go to Tree View and expand the Screen Key Questions Detail screen.
  • Click Edit fields and add the Building field.
  • Go to Tree View and expand the Screen App Settings screen. Select FormAppSettings. Click Edit fields and add the KeyQuestionsPerBuilding field.
  • Move the field up to be between Require Key Qestion completion before creating reservations and Key Questions failure message.
  • Select the field, select Advanced in properties. And Unlock it to change properties.
  • Change DisplayName to “Present Questions per Building”
  • Save and Publish the app

Building Access

Below are the steps to modify the Building Access app to change the screen flow. We need to perform those changes to ensure the building selection before present health questions. Users will need to pick a building so we can filter and present just questions for the specific building.

  • On Tree View, select App, go to OnStart event. Search for the colNav definition and change the first part of the JSON to navigate to the ScreenBuilding by default.

From:

Id: 0,
ScreenName: varString.NewRequest,
Description: varString.NewRequestDesc,
Screen: If(varAppSettings.KeyQuestions,’Screen Key Questions’ ,’Screen Building’),
Image: ic_fluent_building_24_regular

To:

Id: 0,
ScreenName: varString.NewRequest,
Description: varString.NewRequestDesc,
Screen: ‘Screen Building’,
Image: ic_fluent_building_24_regular
  • Expand Screen Building, select HeaderControlBuilding and change the NavigateScreen data field.

From:

If(varAppSettings.KeyQuestions,’Screen Key Questions’ ,’Screen Home’)

To:

‘Screen Home’
  • Still on Screen Building. Select ButtonCheckAvailability and change the OnSelect event to:
Set(varSelectedBuilding , First(colSelectedBuilding) );
If(varAppSettings.KeyQuestions,Navigate(‘Screen Key Questions’,ScreenTransition.None),
Navigate(‘Screen Availability’,ScreenTransition.None));
  • Expand Screen Key Questions, select ButtonSubmitKeyQuestions and change the OnSelect event as documented below.

From:

If( CountRows(Filter(colQuestionAnswersResponse,Answer =1)) >0, Set(varKeyQuestionsPass,false) , Set(varKeyQuestionsPass,true));
If(varKeyQuestionsPass,Navigate(‘Screen Building’),Navigate(‘Screen Key Question Confirmation’))

To:

If( CountRows(Filter(colQuestionAnswersResponse,Answer =1)) >0, Set(varKeyQuestionsPass,false) , Set(varKeyQuestionsPass,true));
If(varKeyQuestionsPass,Navigate(‘Screen Availability’),Navigate(‘Screen Key Question Confirmation’))
  • Still on Screen Key Questions, select the HeaderControl and change the NavigateScreen to:
If(varAppSettings.KeyQuestions,’Screen Key Questions’, ‘Screen Building’)
  • Click again in Screen Key Questions, on the OnVisible event, perform the changes below:

Replace:

If(IsEmpty(colKeyQuestions),ClearCollect(colKeyQuestions, Filter(BAR_KeyQuestions ,State.Value =”Published”)));

By:

If(varAppSettings.KeyQuestionsPerBuilding, ClearCollect(colKeyQuestions, Filter(BAR_KeyQuestions , State.Value =”Published” && Text(varSelectedBuilding.ID) = ‘Building:ID’.Value)), ClearCollect(colKeyQuestions, Filter(BAR_KeyQuestions ,State.Value =”Published”)));
  • Expand Screen Availability, change to the OnVisible event and paste the code below after the existent code:
Set(varBuildingControlsVisible,false);
// Get all floors/spaces for current buildind
ClearCollect(colFloors,Filter(BAR_Spaces,BuildingID = varSelectedBuilding.ID ));
Clear(colChosenRequests);
Set(varAvilabilityDatePickerDefault, Blank());
Set(varAvilabilityDatePickerDefault,Today());
Reset(DatePicker);

COVID19 Building Access App: Per Space Approval

This week I’ll start a series on incorporating changes into the COVID19 Building Access App. The first post will show how to change the 1.1 version to include per space approval.

By default the Building Access App includes an approval process that can be automatic, based on the manager configured on Active Directory or through a post into a specific Teams channel with adaptive cards for those users that don’t have a manager configured.

The number one request I get from customers deploying the app for the back to office scenario is to have the ability to have specific users responsible for specific spaces.

The following instructions can be used to learn about the application, power apps or even to incorporate the feature in your implementation. Please be aware that those changes only work in the 1.1 version of the app.

If you don’t want to follow the steps to change your setup and just need the feature in your environment, I published a new package on GitHub with the required changes already incorporated into the 1.1 package. I versioned it as 1.11.  

https://github.com/cristianoag/BuildingAccess/releases/tag/1.11

20200811_113400000_iOS20200811_113313000_iOS20200811_113304000_iOS20200811_113320000_iOS20200811_113335000_iOS

Here are the changes that need to be implemented.

SharePoint Online

The first step consists on the creation of two additional columns on the BAR_Spaces SharePoint list to store space approvers and the flag to override the default approval flow.

  • Open SharePoint Online as administrator. Open the SPO site being used to store data for the BAR application.
  • Create an additional column of type person (Approver) in the BAR_Spaces SharePoint list.
  • Create an additional column of type Yes/No (HasApprover) in the BAR_Spaces SharePoint list. Select the default value No.

Building Admin

Now you need to update the Building Admin app to incorporate changes into the spaces detail form as well as in the gallery used to present spaces for configuration.

  • Open PowerApps as admin and edit the Building Admin app.
  • Go to Data and refresh the BAR_Spaces connection.
  • Go to Tree view and expand the Screen Space Detail page, click FormEditSpace, select Edit Fields and include the Approver and HasApprover additional fields. Change properties as required.
  • Select the DataCardValue in HasApprover (switch) and update the OnCheck event with:
Set(b_hasapprover,true);
  • Select the DataCardValue in HasApprover (switch) and update the OnUncheck event with:
Set(b_hasapprover,false);
  • Select the Approver Datacard and replace the value for Visible by b_hasapprover
  • Go to Tree view and expand the Screen Spaces page.
  • Edit GallerySpaces and include an additional label with the text “Approver:”. Make the font weight Samibold on properties.
  • Still on GallerySpaces, include an additional label connecting Text to the following formula:
If(ThisItem.HasApprover,ThisItem.Approver.DisplayName,”Default”)
  • Save and publish the app.

Building Access

The main app needs to be changed to pass the appropriate parameters to the request creation flow.

  • Open PowerApps as admin and edit the Building Access app.
  • Go to Data and refresh the BAR_Spaces connection.
  • Go to Tree view and expand Screen Availability. Expand GallerySpace and select imgAddRequest_1.
  • In the Action pane, go to OnSelect and change the content to include two additional parameters to the colChosenRequests collection. The content needs to be changed.
From this:

Collect(colChosenRequests,{FloorID:ThisItem.ID,BuldingID:ThisItem.BuildingID,DateValue:varSelectedDateString ,FloorTitle:ThisItem.Title,DatePickerValue: DatePicker.SelectedDate,BuldingName:varSelectedBuilding.Title, FloorName:ThisItem.Title,BuildingMaxOccupancy:Value( varSelectedBuilding.MaxOccupancy) ,RequestorName:varUser.displayName,RequestorEmail:varUser.mail,

OverCapacity:If( (CountRows( colDateRequests) >=varSelectedBuilding.MaxOccupancy) || varSelectedBuilding.MaxOccupancy = 0,true,false)

}) ;

UpdateContext({btnAddRequestInfoVisible:true});

//Notify(varString.RequestAddedPopupMsg,NotificationType.Success,3000)

To this:

Collect(colChosenRequests,{FloorID:ThisItem.ID,BuldingID:ThisItem.BuildingID,DateValue:varSelectedDateString ,FloorTitle:ThisItem.Title,

FloorApproverEmail: ThisItem.Approver.Email,

FloorHasApprover: ThisItem.HasApprover,

DatePickerValue: DatePicker.SelectedDate,BuldingName:varSelectedBuilding.Title, FloorName:ThisItem.Title,BuildingMaxOccupancy:Value( varSelectedBuilding.MaxOccupancy) ,RequestorName:varUser.displayName,RequestorEmail:varUser.mail,

OverCapacity:If( (CountRows( colDateRequests) >=varSelectedBuilding.MaxOccupancy) || varSelectedBuilding.MaxOccupancy = 0,true,false)

}) ;

UpdateContext({btnAddRequestInfoVisible:true});

//Notify(varString.RequestAddedPopupMsg,NotificationType.Success,3000)

  • Save and publish the app.

BARCreateRequests Flow

The BARCreateRequests flow needs to be changed to update the appropriate parameters in the request.

  • Open Power Automate as admin, click My Flows and edit the BARCreateRequests flow.
  • Expand InputRequests and change the schema to include FloorApprover (string) and FloorHasApprover (boolean) input parameters.

From:

{

“type”: “array”,

“items”: {

“type”: “object”,

“properties”: {

“BuildingMaxOccupancy”: {

“type”: “number”

            },

“BuldingID”: {

“type”: “integer”

            },

“BuldingName”: {

“type”: “string”

            },

“DatePickerValue”: {

“type”: “string”

            },

“DateValue”: {

“type”: “integer”

            },

“FloorID”: {

“type”: “integer”

            },

“FloorName”: {

“type”: “string”

            },

“FloorTitle”: {

“type”: “string”

            },

“OverCapacity”: {

“type”: “boolean”

            },

“RequestorEmail”: {

“type”: “string”

            },

“RequestorName”: {

“type”: “string”

            }

        },

“required”: [

“BuildingMaxOccupancy”,

“BuldingID”,

“BuldingName”,

“DatePickerValue”,

“DateValue”,

“FloorID”,

“FloorName”,

“FloorTitle”,

“OverCapacity”,

“RequestorEmail”,

“RequestorName”

        ]

    }

}

To:

{

“type”: “array”,

“items”: {

“type”: “object”,

“properties”: {

“BuildingMaxOccupancy”: {

“type”: “number”

            },

“BuldingID”: {

“type”: “integer”

            },

“BuldingName”: {

“type”: “string”

            },

“DatePickerValue”: {

“type”: “string”

            },

“DateValue”: {

“type”: “integer”

            },

“FloorID”: {

“type”: “integer”

            },

“FloorName”: {

“type”: “string”

            },

“FloorTitle”: {

“type”: “string”

            },

“FloorApproverEmail”: {

“type”: [“string”, “null”]

            },

“FloorHasApprover”: {

“type”: “boolean”

            },

“OverCapacity”: {

“type”: “boolean”

            },

“RequestorEmail”: {

“type”: “string”

            },

“RequestorName”: {

“type”: “string”

            }

        },

“required”: [

“BuildingMaxOccupancy”,

“BuldingID”,

“BuldingName”,

“DatePickerValue”,

“DateValue”,

“FloorID”,

“FloorName”,

“FloorTitle”,

“FloorHasApprover”,

“OverCapacity”,

“RequestorEmail”,

“RequestorName”

        ]

    }

}

  • Expand Scope-CreateRequest. Expand ForEachRequests and create a Get User Profile step just before the CreateRequests step. Use the formula below for the UPN value.

if(items(‘ForEachRequests’)[‘FloorHasApprover’],items(‘ForEachRequests’)[‘FloorApproverEmail’], if(variables(‘varManagerExists’),body(‘Get_manager_(V2)’)?[‘mail’], variables(‘UserEmail’)))

  • Expand CreateRequests. Update the formula for ApproverNameText to:

if(items(‘ForEachRequests’)[‘FloorHasApprover’],body(‘Get_Space_Approver_Profile’)?[‘displayName’],

if(equals(variables(‘varManagerExists’),true),body(‘Get_manager_(V2)’)?[‘displayName’],”))

  • Update the formula for ApproverGuid to:

if(items(‘ForEachRequests’)[‘FloorHasApprover’],body(‘Get_Space_Approver_Profile’)?[‘id’],

if(equals(variables(‘varManagerExists’),true),body(‘Get_manager_(V2)’)?[‘id’],”))

  • In Approver, Update the formula for Claims to:

if(items(‘ForEachRequests’)[‘FloorHasApprover’],items(‘ForEachRequests’)[‘FloorApproverEmail’], if(equals(variables(‘varManagerExists’),true),body(‘Get_manager_(V2)’)?[‘mail’],null))

  • Save the flow and test the application. It should be able to deal with all approval cases, including approval per space.

New Stuff!

July marks the start of the new Microsoft fiscal year. Multiple announcements and news. In this post I’m aggregating some of the new stuff.

New Return to the Workplace App

You all remember the announcement we made a few weeks ago on the Building Access App (a return to Office scenario). Well, the idea got a lot of traction inside Microsoft and this week Satya announced the Return to the Workplace App during our Inspire/Ready event. (If you want to go directly to the announcement, please click here).

The Return to the Workplace App is a bit different from the Building Access App. The Building Access App has the feature to create booking requests for spaces inside the buildings and don’t require any additional licenses beyond the ones included with Office 365.

The app announced by Satya is super complete, offers Location Readiness, Health Safety Management, Workplace Care Management but still doesn’t support reservation of office spaces (location management). It also requires Power Apps and Power BI Premium/Pro licenses.

System at a Glance Welcome screen  Start survey

You can get more information about the new app at https://powerplatform.microsoft.com/en-us/return-to-the-workplace/

Instructions to setup it are available at https://docs.microsoft.com/en-us/powerapps/sample-apps/return-to-workplace/overview

Desk, Parking Spots and Granular Reservations

In multiple interactions with customers a common request is to have the ability to perform more granular reservations, including the ability to deal with multiple reservations in the same day, reserve tables, parking spots, etc.

Well, that’s why I love our community. I found multiple alternatives to complement what we are providing and expand. Few examples below:

  • April Dunnam created a desk booking and reservation template. She published it on GitHub and created a video demonstrating some of the app aspects. Video is available here and the app package on GitHub here.
  • Workspace Scheduler – This is a simple app that allows the management of buildings and book workspaces. It can be used to complement the other back to workplace apps and can be used inside teams in a channel or using a personal tab. The app is available here.

Great Ideas

Meet the new Teams App Template… Great Ideas. https://github.com/OfficeDev/microsoft-teams-apps-greatideas

Great Ideas app is an “innovation challenge” system that lets employees submit and share ideas and insights, with voting right within Microsoft Teams. Employees can submit an innovative idea in a selected category to be visible to all colleagues and leadership, ideas can be voted upon and a leader board of best idea contributors can be shared.

All Ideas

Begin with the Solution overview to read about what the app does and how it works.

When you’re ready to try out Great Ideas app, or to use it in your own organization, follow the steps in the Deployment guide.

Dataflex

This thing has the potential to change how we create Power Apps integrated to Teams.

Microsoft Dataflex delivers a built-in, low-code data platform for Teams, and provides relational data storage, rich data types, enterprise grade governance, and one-click solution deployment. Microsoft Dataflex enables everyone to easily build and deploy apps and intelligent chatbots in Teams with Microsoft Power Apps and Microsoft Power Virtual Agents.

Microsoft Dataflex is built on top of the Common Data Service, which reached general availability four years ago. Since that time, the Common Data Service added over 1,000 features and introduced support for Microsoft Dynamics 365 and Power Apps

Pllaceholder

Dataflex is being included with Teams licensing with additional capacity and features provided with a premium version called Dataflex Pro.

https://powerapps.microsoft.com/en-us/blog/introducing-microsoft-dataflex-a-new-low-code-data-platform-for-microsoft-teams/

Endpoint Data Loss Prevention

Data Loss Prevention is crucial in the overall application and business process automation for Teams. The ability to control and monitor how information is exchanged and block possible leaks is key for the security teams.

So far the Microsoft DLP strategy lacked the ability to manage the endpoint directly. Not anymore. We are announcing public preview of the Microsoft Endpoint Data Loss Prevention.

Microsoft 365 customers only need to create DLP policies once in the Microsoft 365 compliance center. They can then apply the policies to Exchange, Teams, SharePoint, OneDrive for Business, and now – to endpoints as well. All that is required is for the endpoint to be onboarded in your environment using your established device management onboarding process.

image.png

Disclaimer – The information contained in this blog post doesn’t represent the official Microsoft guidance or best practices. It is just the view of the author on current alternatives, implementations and workarounds for common issues and/or business needs. Please refer to official Microsoft documentation and evaluate carefully any steps, code or procedures documented herein. The author doesn’t offer any warranty. Use this information at your own risk.