Adaptive Cards showcase
Table of contents:
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
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
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:
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:
(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:
However I wanted to change it’s interface to replace it with my own:
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:
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):
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.outputs('New_Body_part_of_card')
My new “Body” code.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'), '')
):
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:
Using the below 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:
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:
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.
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?
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 🙂
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
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?
Image: https://i.imgur.com/paCoH8H.png
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.