Adaptive Cards

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“.

Screencast

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.