Multi-card Interfaces with Adaptive Cards

You can now return a new Adaptive Card definition from an Action.WebRequest! In this tutorial, we'll review how to build even more complex, interactive, and multi-card user experiences with Adaptive Cards. Instead of returning a toast message from an Action.Webrequest action, you can now return an entirely new Adaptive Card definition!

Adaptive Cards can define “actions,” which are typically rendered as buttons within the card. The Adaptive Card Host SPA supports a variety of actions, including the ability to navigate the browser, show a toast message, or show a modal dialog. It also supports an action type of Action.Webrequest which provides the ability to send a web request to a server. This allows the card author to capture input from the user and send that input to a server where additional interesting business logic can take place.

For example, the following Adaptive Card definition could be used to add a constituent record in Blackbaud Raiser’s Edge NXT.

JSON
    {
      "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.4",
      "body": [
        {
          "type": "TextBlock",
          "text": "Use this card to add a new individual constituent."
        },
        {
          "type": "Input.Text",
          "id": "first",
          "label": "First name",
          "maxLength": 50
        },
        {
          "type": "Input.Text",
          "id": "last",
          "label": "Last name",
          "maxLength": 50,
          "isRequired": true,
          "errorMessage": "Last name is required."
        }
      ],
      "actions": [
        {
          "type": "Action.Webrequest",
          "title": "Save",
          "url": "https://someWebRequestURL...",
        }
      ]
    }
  
{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": [
    {
      "type": "TextBlock",
      "text": "Use this card to add a new individual constituent."
    },
    {
      "type": "Input.Text",
      "id": "first",
      "label": "First name",
      "maxLength": 50
    },
    {
      "type": "Input.Text",
      "id": "last",
      "label": "Last name",
      "maxLength": 50,
      "isRequired": true,
      "errorMessage": "Last name is required."
    }
  ],
  "actions": [
    {
      "type": "Action.Webrequest",
      "title": "Save",
      "url": "https://someWebRequestURL...",
    }
  ]
}

The card defines two input fields, first and last name, and a save button. When the save button is selected, the first/last name are packaged into a request and sent to the specified URL.

Using techniques demonstrated in previous tutorials, you can register a SKY Add-in for the Home page tile dashboard in Raiser’s Edge NXT and use the Adaptive Card Host SPA to render this card in a tile.

Register a SKY Add-in for the Home page tile dashboard.

Previously, the response from the request sent by the save action could only show a toast message, such as “A new constituent record was added!” Now with the new capability of the Adaptive Card Host SPA, the response can define a completely new Adaptive Card that replaces the initial data entry card and provides richer feedback to the user. This new card can even contain its own actions that send requests and return different cards.

To do this, you'll use Power Automate to implement a flow that triggers when the Save button is selected.

This flow accepts some input values, such as first/last name, that are provided by the Adaptive Card. It then performs the logic for adding a constituent and returns a new card definition containing a confirmation message that the constituent was added along with a link to open the newly created constituent page.

Follow the same process as the Data entry with Adaptive Cards tutorial and create a new flow using the Trigger a flow from a SKY Add-in Adaptive Card action template. The flow is triggered by an add-in on the Home page. The Home page add-in provides no additional context, so remove the context element from the schema and update the placeholder fields in the schema to use the “first” and “last” field identifiers from the initial card.

JSON
    {
      "type": "object",
      "properties": {
        "uit": {
          "type": "string"
        },
        "data": {
          "type": "object",
          "properties": {
            "first": {
               "type": "string"
            },
             "last": {
               "type": "string"
            }
          }
        }
      }
    }
{
  "type": "object",
  "properties": {
    "uit": {
      "type": "string"
    },
    "data": {
      "type": "object",
      "properties": {
        "first": {
           "type": "string"
        },
         "last": {
           "type": "string"
        }
      }
    }
  }
}

After validating the user identity token, use the Create an individual constituent action to create a new constituent record using the values supplied in the flow trigger.

Create an individual constituent.

Next, build a new Adaptive Card with details about the newly added constituent that replaces the initial card. To do this, use the Adaptive Card designer with a few placeholder values that we'll update later in Microsoft Power Automate.

Adaptive card designer.

The card payload shown above contains the following.

JSON
    {
      "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.4",
      "body": [
        {
          "type": "TextBlock",
          "text": "Success!",
          "size": "Large",
          "weight": "Bolder",
          "color": "Good"
        },
        {
          "type": "TextBlock",
          "text": "Constituent **xxxxx** was successfully added!"
        },
        {
          "type": "TextBlock",
          "text": "[View the new constituent record](https://host.nxt.blackbaud.com/constituent/records/xxxxx?&svcid=renxt&envid=xxxxx)"
        }
      ]
    }
{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": [
    {
      "type": "TextBlock",
      "text": "Success!",
      "size": "Large",
      "weight": "Bolder",
      "color": "Good"
    },
    {
      "type": "TextBlock",
      "text": "Constituent **xxxxx** was successfully added!"
    },
    {
      "type": "TextBlock",
      "text": "[View the new constituent record](https://host.nxt.blackbaud.com/constituent/records/xxxxx?&svcid=renxt&envid=xxxxx)"
    }
  ]
}

Back in Power Automate, paste the card payload from the designer into a Compose action, and replace the xxxxx placeholders with the appropriate values. You'll have the first/last name from the flow trigger. The system record ID of the newly added constituent will come from the output of the Create new individual constituent action.

Build new Adaptive Card response.

Now, it’s just a matter of returning the output from the compose action as the response.

Return the output from the compose action as the response.

Here is an overview of the flow.

Flow overview.

After saving this flow, Power Automate generates the URL that can be used to trigger the flow. Use that to update the url property of the Webrequest action in the card.

JSON
    {
      "type": "Action.Webrequest",
      "title": "Save",
      "url": https://prod-116.westus.logic.azure.com:443/workflows/3aed...
    }
{
  "type": "Action.Webrequest",
  "title": "Save",
  "url": https://prod-116.westus.logic.azure.com:443/workflows/3aed...
}

When you select the Save button, the second flow triggers. It adds the constituent record and returns a new Adaptive Card, which replaces the original one.

The new Adaptive Card returns.

In this tutorial, we showed how a new Adaptive Card can be returned from an Action.Webrequest action. The new card completely replaces the original card and enables users to build even more complex, interactive, and multi-card users experiences.