top of page

Challenge 023 | Cards for Power Apps

Over a year ago, we discussed Adaptive Cards. These are micro-apps with a lightweight UI, which are great for quick user input or proper looking messages. Cards for Power Apps is based on the Adaptive Cards technology, but are part of the Power Platform ecosystem. That means Power Fx and connectors are available within the Card. This challenge we well learn how we can utilize these small, yet powerful Cards.

Challenge Objectives

🎯 Learn about Cards for Power Apps

🎯 Know the oros and cons of Card for Power Apps compared to Adaptive Cards

🎯 Understand that these micro-apps have a place in your solution

Introduction

What is Cards for Power Apps?

In Challenge 005 we explained what Adaptive Cards are. In a nutshell, an Adaptive Card is just a JSON object with a standardized structure. The JSON is fed to a host application that translated the data into a UI element. the host application can be Microsoft Teams, Outlook Actionable Messages, Viva Connections, and some more.

Card for Power Apps is a Canvas-like designer for these adaptive cards. The difference compared to Canvas is that it will only show controls that are supported by the Adaptive Cards framework and the layout also follows the Adaptive Cards framework. It is more a Canvas interpretation of the Adaptive Cards Designer.

When it became GA early this year I tried it, but it was still a bit buggy and for me not a great alternative for the original Adaptive Cards. Last month, Novermber 2023, Cards became solution-aware and got a Power Automate connector. There are still some limitations (see Additional Information section), but these updates do make it usable and for me the preferred method over the original Adaptive Cards in actual solutions (if the limitations are not an issue).

Build Cards

Power Apps blog Card

It's recommended for every organization that uses Power Platform, that they install the CoE Starter Kit to administer the platform. The product team envisioned three personas: admin, maker, and user. The maker group is an internal community of Power Platform makers. In this scenario we want to keep this group up-to-date with the Microsoft Power Apps blog. This is the same blog where I found the updates on Cards, As you can see on that website, there is an RSS feed available for this blog. We will use this as a trigger in a flow, and put information from this RSS feed into a Card and push that to a group chat.

RSS is an XML format to easily retrieve updates from websites. you can see the context of that XML by clicking the VIEW RSS FEED button on the blog site, or by clicking this. You will see that it has some information about the website, and a list of items. Each item has a link, a title, a description. This is the information that we want to show in Microsoft Teams.

  1. Create a new solution called Challenge 023

  2. Create a new Card called Power Apps Blog

  3. Notice that the "Canvas" section in the Designer is now identical to the Adaptive Cards Designer. We want a title, a description, and a button that will link us to the blogpost URL. The default card comes with two text labels (see image above). The first test label can be used for our title and the second for the description. We only need to add a button.

  4. Make the first text label Size extra large, and set the title of the button to Read blog.

  5. Add a variable for the title. We want to set this variable when we initiate the card. That's why we need to check both checkboxes under Customization. This will result in a required field when we send the card through Power Automate. You should also make the persistence permanent, as we don't want this variable to change when we reopen the card.

  6. Add two more variables with the same settings named varDescription and varUrl.

  7. Set the Text property of the first text label to varTitle. If you use the properties panel (the panel on the right) you need to start with an equal sign (=) to make it a Power Fx formula. Otherwise it will be just text. You can also use the Power Fx field above the preview screen. Note that this formula bar operates slightly different compared to the Canvas formula bar.

  8. Set the text of the second text label to varDescription.

  9. Set the type property of the button to Open Url and set the Url to varUrl.

  10. Save the Card.

The Card is now finished. We should now check what it looks like in Teams. We will be sending the cards using a Power Automate flow. We will start with a manually triggered flow to see how earlier post look. After that we can update it to an automated flow with the RSS trigger.

  1. Add a new instant flow to your solution

  2. Name the flow New Power Apps Blog

  3. Add an action called List all RSS feed items

  4. Enter the URL from the VIEW RSS FEED button as the RSS feed URL

  5. Add a Compose action. use an Expression as an input. you can type first(), and between the brackets you can enter the body from List all RSS feed items action. you expression should look like the snippet below.

first(outputs('List_all_RSS_feed_items')?['body'])

Up until here it is all stuff we already know. We want to post the card to a Teams channel. You could create a new team called Power Platform Makers to follow the scenario.

  1. Run your flow once. Make sure to copy the output of the compose action.

  2. Add a Parse JSON action. Give the outputs from the Compose action as content.

  3. For the schema, you can use the Generate from sample option. The Sample JSON is the output you copied when you ran the flow. Parse JSON isn't broadly known, but this way we tell Power Automate what the structure is from JSON it will receive. because we know what is coming in, we can use it in later actions as dynamic content.

  4. Add a new action and search for Cards for power apps. This is the brand new connector. Select the Create card instance action.

  5. You will get a dropdown where you can select the Card you want to use. This is probably empty. This has to do with permissions. All the Cards are stored in a Dataverse table called Cards. As for any Dataverse table, you will need permissions on that table to read, update, etc. You would expect that as a System Administrator for the environment (which you probably are if you use a developer tenant), you would be able to read the table. You can just create cards, but through Power Automate you will need a specific security role. you can go to aka.ms/ppac and select the environment you are working in, go to users, and select your own user profile. There are two predefined security roles. The Cards Role is used internally. This you should not use. The Cards Basic Role is the role you should grant users to work with Cards.

Once that's done, you should be ready to continue.

  1. Select the Power Apps Blog Card we created from the dropdown

  2. The variables we created earlier will show up because we checked the customization checkboxes for all variables. map varTitle to title, varDescription to summary, and varUrl to primarylink.

  3. Add a new action from the Microsoft Teams connection called Post card in a chat or channel.

  4. Select post in Channel.

  5. Search for the Power Platform Makers team and the General channel.

  6. Select post as Power Apps (Preview) and select post in Channel.

  7. The adaptive card to send can be the Card instance you created in the previous action.

  8. Save your flow and run it.

You should have received a Card in the channel. Pretty cool! The summary text is a bit long, but it gives some information, so we won't dive into that. This currently only works with a manual trigger. You could adjust the flow to use the RSS trigger and put those values in the Card variable. Your flow will then only have the RSS trigger, Create card instance action and the post card in channel action. I opted for the manual trigger option, as we can then directly see the output in the Teams channel.

Because of this challenge, I have created an RSS feed for my own blog. You could do the same for my blog if you want to. Some text manipulation will be required, as there is also an image in the summary. Some extra work, but you could add the image to the Card too. The RSS feed URL is in the snippet below if you want to give it a try.

https://rss.app/feeds/8HJhxSEE0WHM4Qdk.xml

Dataverse connected Card

The first card was a good use case, but the card itself was quite simple. just some labels with a button and some variables. For the second card we will make a bit more complex Card. You probably know that when you are using Approvals in Power Automate, that an Adaptive Card is sent in Microsoft Teams to Approve or Reject. But what if we see something that needs a small adjustment before it can be approved? In the standard scenario, we would either need to reject it and ask for a new submission, or approve it and make the adjustment where the data is stored. This is quite cumbersome, and we can make a Card that allows us to make this tiny adjustment ourselves.

Let's start with creating a simple Dataverse table. I am missing some inspiration, so my table is named Tea, as I am enjoying a nice cup of tea at the time of writing. Besides the standard columns, we will add the following:

  • Price (Currency)

  • Tea type (Choice with options Green, White, Black, and Oolong)

  • Approval stage (Choice with options Pending, Approved, and Rejected with Approved as default value)

I think that's enough to show the capabilities of Cards. Let's get to it.

  1. Create a new card named Tea Approval

  2. Add a variable named VarNewTea. We will map the name of the tea to this variable when we initiate the card, just like we did in the previous card. That means persistence is permanent, and both checkboxes should be checked.

  3. Go to the data tab and select add data. Just like we add data using connectors in Canvas Apps, we use connector(s) in Cards. At the moment only Dataverse is supported, but the team is working on adding support for other connectors. I heard them say SharePoint, Outlook, and SQL are high on their wishlist. Once a connection is set up you should select the Teas table.

  4. On the main card, make sure that the following labels are added

Name

Text

lblNewTea

New tea added

lblNewTeaName

Name

lblNewTeaNameValue

=VarNewTea

lblNewTeaPrice

Price

lblNewTeaPriceValue

=LookUp(Teas, Name = VarNewTea).Price

lblNewTeaType

Tea type

lblNewTeaTypeValue

=Text(LookUp(Teas, Name = VarNewTea).'Tea type')

As you can see, we are using Power Fx to retrieve information from the Dataverse to show it on the Card. Again, the equal sign (=) indicates Power Fx is being used. If you use the function bar, the equal sig isn't shown.

Add three buttons at the bottom, Approve, Adjust, and Reject. As described in the scenario, the first and last button will just do what we know from Approvals, but the Adjust button will allow us to change the properties before approving. With some text formatting the card will look like the image below.

Just like we know from Approvals, we want to show the end-user that an item is already been approved, or rejected. That means we need an extra screen.

  1. Make a new screen named Finished

  2. As we want to use just one screen for both Approved or Rejected, we want to store approved or rejected to a variable. With Cards, you cannot use Set() to create a variable. You should use the panel for that. I actually like the fact that creating and updating variables are done differently. Add a new variable called varApprovalStage. You can set the Default value to Pending. That means we won't have to give this as an input. This should not be reset, so Permanent is the persistence.

  3. Now we can Add two labels. lblFinished and lblNewTeaFinished. lblFinished can be set to ="This tea is " & varApprovalStage and lblNewTeaFinished can be set to VarNewTea. Format the labels a bit to make it look nice. This will result in a card that looks like something shown below.

Now let's make sure that when we press the Approve or Reject button, the record is updated and we will show this finished screen.

  1. The snippet below can be added to the OnSelect of the Approve button. These Power Fx functions are faily easy, but effective. We basically update the record by setting the Approval Stage to the choice Approved. Then we also set the variable used in the Finished screen to Approved (plain text), and navigate to that screen.

  2. Do exactly the same for the Rejected button, but adjust the Power Fx function accordingly.

Patch(Teas ,LookUp(Teas, Name = VarNewTea), {'Approval stage': 'Approval stage (Teas)'.Approved});

Set(varApprovalStage, "Approved");

Navigate(Finished)

You could save you Card and give it a try. You should obviously create a record in the Teas table first, but then you should be able to use it. You now already have created the same thing we know from approvals. Good job!

Now let's get to the part where we can adjust the record before approving, the most interesting part.

  1. Add a new screen called Adjust

  2. go back to the main screen to set the OnSelect of the Adjust button to =Navigate(Adjust). We now only have to worry about the Adjust screen.

  3. Add a label in the same title style as the other screens with the text Edit new tea

  4. add two text inputs and a dropdown. We will adjust these later.

  5. On the bottom of the card, add two buttons, Back and Save and approve. OnSelect of the first button can be set to Back().

  6. Name the first text input txtNameEdit, Make it required, set the label to Name and the Default value to =VarNewTea.

  7. The second text input can be named txtPriceEdit. Make this required too, set the label to Price and the Default value to =LookUp(Teas, Name = VarNewTea).Price

So far this is still quite straightforward, and something quite familiar to forms in Canvas. The labels are a property we don't know in Canvas from a text input, but these are Based on Adaptive Cards properties, and they are actually really helpful, as we don't need another label control to act as a label, as we have the label property. Are you following along?

There is actually a bit of a problem with the dropdown control. As you might know from Canvas, if we use a dropdown on a form, the items of that dropdown would look something like the snippet below for our tea types.

Choices('Tea type (Teas)')

The problem is, Choices() is not supported (yet) in Cards. This is a bit unfortunate, as this means we cannot get items for a dropdown in a dynamic manner. I intentionally let you use choices instead a related table for this reason, but the limitation is good to be aware of. I will show you how I work around this limitation in a not so neat way.

  1. Name the dropdown drpTypeEdit and make it required.

  2. Set the Value of the dropdown to =Text(LookUp(Teas, Name = VarNewTea).'Tea type'). Somehow I did not get to see the function bar, so I pasted it directly in the Value field on the Properties panel.

  3. Go to the Choices tab. Add the same values we've added to the Tea type choice field. That means Green, White, Black, and Oolong. Enter it for both the Title and Value.

  4. In the OnSelect of the Save and approve button, I added the function shown in the snippet below.

Patch(Teas ,LookUp(Teas, Name = VarNewTea), {Name: txtNameEdit, Price: Value(txtPriceEdit), 'Approval stage': 'Approval stage (Teas)'.Approved, 'Tea type': Switch(Text(drpTypeEdit), "Green", 'Tea type (Teas)'.Green, "White", 'Tea type (Teas)'.White, "Black",'Tea type (Teas)'.Black, "Oolong", 'Tea type (Teas)'.Oolong)});

Set(VarNewTea, txtNameEdit);

Set(varApprovalStage, "Approved");

Navigate(Finished)

What you can see it that I use a switch and for every option in the dropdown, I map it to a Choice option in Dataverse. Then the variables used in the card are updated and then we are routed to the Finished screen which we created earlier. The Card now looks like the image below.

You can save your card again and try the functionality by playing it. If it works fine, you can create a similar flow as we did for the first card to see it work in Microsoft Teams. I created a flow with a Dataverse trigger to send a card to Teams, which I assume I don't have to explain.

What this Card looks like in Teams is shown in the image below.

You now have created a multi-screen Card that interacts with Dataverse through a connector. You rock!

My findings

To be fully transparent, the switch option in the Patch() function is not a dynamic solution. This means that when we update the choices, we also need to update the Card, which must then be tested again. This is not ideal, but as far as I know, there is no alternative. I struggled a bit too long with it to be fair.

Another reason why I have been struggling is to get the Power Fx function to actually work in Cards for Power Apps. The suggestions in the function bar are just not what we are used in Canvas. In many cases I did not get any suggestions at all. I ended up creating a Canvas app for function bug fixing and moving it back into the Card, which needed some adjustment still.

Another issue I had was that not all environments worked for me. I have 4 environments in my developer tenant, and only one allowed me to create and use Cards properly. I am checking with the product team what this issue could be, but this is also not ideal for production solutions.

Additional Information

Currently we can only send these Cards through Microsoft Teams. The product team did mention they want to make it available for Outlook as well.

Another limitation is that only Dataverse is available as a connector. The product team mentioned that they want to bring more broadly used connectors in Canvas apps, like Office 365 User, SharePoint and SQL.

Triggering a Power Automate flow from a Card is on the roadmap and would be a welcome addition.

Although Cards can handle Power Fx, there are some limitations.

Key Takeaways

👉🏻 Micro-apps can bring business value in a quick and uniform way

👉🏻 Connectors for Cards have loads op potential

👉🏻 If the Choices() function is resolved and there is no issue with some environments not being able to use Cards, it is actually a great tool over Adaptive Cards.

© 2022 by Miguel Verweij

bottom of page