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