Wednesday, May 15, 2019

Approve a document in Teams using Adaptive Cards and Flow

Co-incidentally the same scenarios often appear simultaneously from different people at the same time, and this is one of them.

I’ve been assisting with random comments to a client who wants to start an approval on a document, and have that show up as a card with Approve/Decline buttons in Teams. And yesterday the good SharePoint/Flow man himself Chaks at Microsoft reached out with a similar scenario.

Chaks wanted to build a bot for this, and I asked if he had tried the Adaptive Card action in Flow, and have card buttons trigger an approval/decline action via a HTTP trigger. Turns out that adaptive cards via Flow in Teams does not support Action.Http. End of story.

Here I am, having told a client this should be easy, and Chaks telling me I can’t do it. Being me, that’s not acceptable, of course it can be done – and turns out my ego was right this time :D (it’s not always)

Start the approval Flow from SharePoint.

Adaptive card in Teams.


Important: Enable Major, minor versioning and approval on the document library. And I have not put any thoughts into licensing of actions in Flow if any for this scenario.

How??? Let me show you!
Let’s start with the approval part first. You don’t need to use a HTTP POST action to trigger a Flow. Flip open the advanced options and you can trigger by GET. And the good part, you can pass in routing information and pick out values from the calling URL.



In the above image I have specified Response/{Response}/Id/{Id} as my routing path which let’s me access Response and Id as variables in my Flow. In my case Response will be Approve/Decline, and Id is the item if of the file which should be approved.

Here’s an explanation of the complete approval flow:


  • Request is received
  • Load file properties based on the item id (using the id saves encoding issue)
  • Get file metadata to easily retrieve the ETAG value needed for approval (you can retrieve the ETAG value from the previous step as well, but that requires more work)
  • Check response for Appove or Decline
  • Approve or Decline the document approval
  • Output a simple web page to the approver
As an extra step you could send a message to the person asking for a document to be approved about the outcome, or any other logic needed.

Note: I had issues where Response and Id did not show up for all actions as dynamic variables in the Flow designer. This is solved by using them further down and copy/paste them where needed.

As for the asking for approval Flow, it’s a few simple steps:


  • For the selected file, load file properties
  • Create an adaptive card based on the file information
  • Post the card to a Teams channel
I used the card designer at https://adaptivecards.io/designer/ as a basis for my teams card. Note line 54 and 59 which are URL actions, where I have added Approve and Decline as part of the URL routing and also pass in the file item id. When a user clicks either of the buttons the URL will open in browser, triggering the approval Flow. And that’s all there is to it. No bots involved – pure Flow magic!
{
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "Container",
      "items": [
        {
          "type": "TextBlock",
          "size": "Medium",
          "weight": "Bolder",
          "text": "Please approve or decline the document"
        },
        {
          "type": "ColumnSet",
          "columns": [
            {
              "type": "Column",
              "items": [
                {
                  "type": "TextBlock",
                  "weight": "Bolder",
                  "text": "@{body('Get_file_properties')?['Editor']?['DisplayName']}",
                  "wrap": true
                },
                {
                  "type": "TextBlock",
                  "spacing": "None",
                  "text": "Modified {{DATE(@{body('Get_file_properties')?['Modified']},SHORT)}}",
                  "isSubtle": true,
                  "wrap": true
                }
              ],
              "width": "stretch"
            }
          ]
        }
      ]
    },
    {
      "type": "Container",
      "items": [
        {
          "type": "TextBlock",
          "text": "Someone wants you to approve the following document: ",
          "wrap": true
        }
      ]
    }
  ],
  "actions": [
    {
      "type": "Action.OpenUrl",
      "title": "Approve",
      "url": "https://.../invoke/Response/Approve/Id/@{body('Get_file_properties')?['ID']}?..."
    },
    {
      "type": "Action.OpenUrl",
      "title": "Decline",
      "url": "https://.../invoke/Response/Decline/Id/@{body('Get_file_properties')?['ID']}?..."
    }
  ],
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.0"
}

Happy flowing!