Adaptive Cards

Adaptive Cards showcase

This post is related to a screencast I’ve made recently. It describes how the Flow, used by the solution, is built in details. Have fun watching and learning how it is made. This post is also part of the sequel I am writing about “Adaptive Cards“.


Adaptive Cards showcase screencast

The solution

The solution is built using PowerApps to give users their own entry point to the process. All data is being stored in two entities in Common Data Service (CDS). It is also using Microsoft Teams together with Adaptive Cards, as the medium for communication using the Digital Workplace approach (all information stored in a single environment, unified user experience) and Microsoft Flow that handles approvals and data processing.

In this post I will focus only on Microsoft Flow and how it works with Adaptive Cards, since this is the core of the solution.

How the Flow is built

Microsoft Flow posting Adaptive Cards
Microsoft Flow posting Adaptive Cards

Because I created the app with enough error handling logic, it doesn’t really have to wait, once a new request is submitted, for the Flow to be executed and therefore i decided to use another trigger, not the PowerApps one. Instead I used “When a record is created” (1) trigger from Common Data Service set of triggers (note it requires P1 license!).

Next (2) I am getting information about the related record, that holds quotas of available days for the user who triggered the Flow, for current year, using a “lookup” column in CDS building a relation between a single request and user’s quota information:

Getting related record in CDS using Lookup column
Getting related record in CDS using Lookup column

Next step (3) is to get requester details and their manager data. That is done using actions from “Office 365 Users” set of actions:

  • Get user profile (V2)
  • Get manager (V2)

Preparing and assigning a task

Now the magic starts 🙂 In the Scope (4) Flow is doing the following steps:

Assigning task, parsing Adaptive Card, posting the Card to Teams
Assigning task, parsing Adaptive Card, posting the Card to Teams

(A) I am assigning a task to manager using “Create an approval (V2)” action. It creates a task for the approver, but doesn’t pause workflow until task is completed. Simply assignes task and moves forward.

(B) One of the attributes being returned from the task action is “Adaptive Card” JSON code. Fully working! I then parsed it to be able to retrieve every property I want from it:

Getting Adaptive Card code from Microsoft Flow approval and parsing it
Getting Adaptive Card code from Microsoft Flow approval and parsing it

However I wanted to change it’s interface to replace it with my own:

Standard approval Adaptive Card vs. one I created
Standard approval Adaptive Card vs. one I created

Important! The Adaptive Card generated by Flow has the “Actions” property, that contains definition of “Approve” and “Reject” submit buttons. It contains a lot of values, that are required by the Flow Bot to properly parse the request and complete a related task:

Data send back to Flow Bot once button on Adaptive Card is clicked
Data send back to Flow Bot once button on Adaptive Card is clicked

Having that in mind I decided not to really build totally my own Adaptive Card, but just to prepare and use its “Body” property. Once I had the code prepared I pasted it into “Compose” (C) action in Flow and replaced values with properties from the flow and finally built new Adaptive Card code by joining together header information of the original card, with the customized body and Actions from original card (D):

Building new Adaptive Card code
Building new Adaptive Card code
  1. substring(body('Assign_approval_task_to_manager')?['adaptiveCard'], 0, indexOf(body('Assign_approval_task_to_manager')?['adaptiveCard'], '"body"'))
    To get header, so all information before the “body” property.
  2. outputs('New_Body_part_of_card')
    My new “Body” code.
  3. substring(body('Assign_approval_task_to_manager')?['adaptiveCard'], indexOf(body('Assign_approval_task_to_manager')?['adaptiveCard'], '"actions"'), sub(length(body('Assign_approval_task_to_manager')?['adaptiveCard']), indexOf(body('Assign_approval_task_to_manager')?['adaptiveCard'], '"actions"')))
    To get the “Actions”, so all information after the “Body” property.

Finally new code was sent using “Post your own adaptive card as the Flow bot to a user (Preview)” action to the approver (E).

Next (5) Flow is pausing waiting for the task is completed. Once approver completes task (using either Approval Card in Teams, or buttons in e-mail, or mobile app) Flow is able to move on. Then I am initiating variable to store approval comments (6). Since this is not a required field in task, it is possible that it was empty, what made Flow to fail, when I was then trying to save null “Comments” back in CDS. Therefore I decided to use “Run after” in “Set variable” action and concatenate comment with empty string, what solved the issue (concat(outputs('Get_approval_comments'), '')):

Using "Run after" to join null string with empty one
Using “Run after” to join null string with empty one

Handling approval outcome

Now the final scope starts (7).

It is first updating (A) request record in CDS entity storing information about approval: who, when, what the outcome is and comments are. Next (B), based on the outcome it is sending another Adaptive Card to the requester with either confirmation or rejection message:

Handling approval outcome
Handling approval outcome

Using the below cards:

Approval and Rejection Adaptive Cards
Approval and Rejection Adaptive Cards

Then (C) is adding an entry to calendars of the Requester and Manager for the leave period. Next it is generating the ICS file, using data from the leave and the proper format. Finally is saving the file to the Aure Blob Storage:

Preparing and generating ICS file
Preparing and generating ICS file

Important! If you want that your ICS file will be downloaded when calling its URL, rather than displayed in a browser as a plain text, use the “application/octet-stream” content type.

Lastly (E) it is updating left days quota and is sending Adaptive Card to a channel in Microsoft Teams, so that other members of a team will know when their colleague is going to be absent. Also, it allows them to download generated previously ICS file, so that they can add this fact to their calendars as well:

Different Adaptive Cards sent to Microsoft Teams channel
Different Adaptive Cards sent to Microsoft Teams channel

And that’s it! Hope you liked it.

If you have any questions or would you like me to help you with your Adaptive Cards journey leave me comment or reach me out using contact form.

Tomasz Poszytek

Hi, I am Tomasz. I am expert in the field of process automation and business solutions' building using Power Platform. I am Microsoft MVP and Nintex vTE.

  • Javier

    Hi Tomasz
    Amazing technique for customizing approvals adaptive cards… thanks for sharing!
    One question, is it possible to send the customized adaptive card via email instead of posting it to a teams user?

    November 1, 2019 at 10:51 pm Reply
    • Tomasz Poszytek

      Yes, this is called Actionable Message and is nearly the same as adaptive card, just small, but still significant differences.
      I will also share it on my blog one day 🙂

      November 2, 2019 at 7:49 am Reply
  • Javier

    Good to know!
    I am following your technique to customize my own approval emails by using Office 365 Outlook “Send an email (v2)” after “Create an approval”. In order to let the Flow work as I expected:
    – first realized ‘Create an approval’ ‘Enable notifications’ property shall be set to ‘No’ in order to avoid email approval duplication (i.e. the standard plus the customized one).
    – then realized that in Office 365 Outlook “Send an email (v2)” body I need to concat the adaptive card json obtained from “Create an approval” surrounded by ANGLE BRACKET script type=”application/adaptivecard+json” ANGLE BRACKET and ANGLE BRACKET /script ANGLE BRACKET
    – finally struggling with the fact “submit” button not displayed on email body sent via “Send an email (v2”). No matter I try with the original adaptive card obtained from “Create an approval” without modifying it

    If I find the workaround, I will let you know

    November 2, 2019 at 10:02 am Reply
  • Kurtis

    I put into flow Create an Approval, after it I put Parse JSON
    I put “Adaptive Card” into Content field, but Schema doesn’t populate like in your video. Is there something I am missing?

    December 20, 2019 at 1:33 am Reply
    • Tomasz Poszytek

      You actually don’t need that “Parse JSON” action. I used it only because I wanted to manipulate the contents of Adaptive Card. I think what you just want to do is to submit this card to Teams and therefore simply put AdaptiveCard contents directly to the proper action.

      December 20, 2019 at 8:24 am Reply

Post a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.