powershellpower-automateadaptive-cardspower-virtual-agents

Can't Dynamically Display PowerVA Data In Adaptive Card


I'm working on a Power Virtual Agent that will take some data from our ticketing system via Power Automate and display it to the user in a nice adaptive card. However, I'm having issues getting the card to actually put the tickets into the variables they should be linked to. I played around for a while in the Adaptive Card designer website, but couldn't get it to work.

Here is some example output from my Automate flow that I'm trying to put into a PVA adaptive card:

{
  "capitalName": "John",
  "returnString": "Success",
  "returnCode": true,
  "returnTickets": [
    {
      "id": 114762,
      "summary": "Example Ticket 1",
      "company": "Apple",
      "resources": "Michael, John"
    },
    {
      "id": 117572,
      "summary": "Example Ticket 2",
      "company": "Amazon",
      "resources": "John"
    },
    {
      "id": 121946,
      "summary": "Example Ticket 3",
      "company": "Microsoft",
      "resources": "Peter, Charles, Steven, John"
    },
    {
      "id": 122116,
      "summary": "Example Ticket 4",
      "company": "Facebook",
      "resources": "Steven, John"
    },
    {
      "id": 99336,
      "summary": "Example Ticket 5",
      "company": "Tesla",
      "resources": "Michael, John"
    },
    {
      "id": 119254,
      "summary": "Example Ticket 6",
      "company": "Gamestop",
      "resources": "Michael, John"
    }
  ]
}

And here is the adaptive card I JSON I have so far, which is pasted into Power Virtual Assistants:

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": [
    {
      "type": "TextBlock",
      "text": "Tickets",
      "weight": "Bolder",
      "size": "Medium"
    },
    {
      "type": "TextBlock",
      "text": "{{$root.returnTickets.length}} tickets found"
    },
    {
      "type": "FactSet",
      "facts": [
        {
          "title": "Ticket ID",
          "value": "{{id}}"
        },
        {
          "title": "Summary",
          "value": "{{summary}}"
        },
        {
          "title": "Company",
          "value": "{{company}}"
        },
        {
          "title": "Resources",
          "value": "{{resources}}"
        }
      ],
      "separator": true,
      "spacing": "Medium",
      "factsProperty": "returnTickets"
    }
  ]
}

Finally, here is what is what the adaptive card ends up looking like in the test bot: enter image description here

Thank you in advance!


Solution

  • A kind Microsoft employee, Henry, answered my question on the Power Virtual Agents forums. Here is a link to his original response to my question, along pictures and functional code you can copy and paste: https://powerusers.microsoft.com/t5/General/Display-Array-Items-in-Adaptive-Card/m-p/2366757/highlight/true#M6675

    I have since tweaked the code from what he provided as you will see below. I am using what I've learned here to connect to a Power Automate (PA) flow like I was try to do initially.

    There are two main takeaways for me: The way I was trying to call variables in the adaptive card was totally wrong. For those that don't already know, you can't call variables at all in the adaptive card JSON editor in PVA, but you can if you set the editor to Formula view. If you already have a card built in JSON, setting the editor to Formula mode will just update your card syntax to fit.

    More importantly, trying to call a variable with {{variable}}, or {${variable}} is not the right syntax at all. The whole thing is a confusing mess, since adaptive card syntax has changed completely in the last two years (it used to be Markdown), and ChatGPT, as smart as it is, recommends those same incorrect ways to format a variable. Some of the other guides online, textual or visual, are out of date and of little help. The correct way is to call the variables in relation to the topic you are in, for example Topic.testVariable. If you look closely when you deal with variables in certain contexts in PVA, you will actually see the variable's full name appear - Topic.something.

    Additionally, we need to use a parse function to format the array of ticket data into a table to dynamically load everything in our array. There actually is a way to iterate through data inside of an adaptive card - ForAll(). I may have stumbled upon this PowerFX function myself a while ago, however I couldn't get it to function as the other crucial pieces - the parse function with proper JSON schema for what I was trying to do - were not present, and as such, the adaptive card threw a bunch of errors before the topic was even run (which led me to think that approach was not correct.) I digress..

    Parse Value Screenshot

    I must note that it is important to make sure the schema is correct. I have tweaked the code to parse just the array I need rather than the entire JSON output, so I pasted in my own sample JSON for the schema to generate. Note for the eagle eyes, don't worry about the fact I am running the parsing on a variable called userTickets when my JSON references returnTickets - I'm just setting this name from my Power Automate flow when several values are returned.

    Here's my picture if you end up having problems parsing your sample JSON, and are using a table (Henry's original code uses a record):

    Schema for Parse Value

    Once we have the data in a table, we can call the pieces we need in the adaptive card. Note my use of a PowerFX function to count the number of tickets, and how all the variables are called with the Topic. syntax:

    {
      type: "AdaptiveCard",
      version: "1.4",
      body: [
        {
          type: "TextBlock",
          text: Topic.capitalName & "'s Tickets",
          weight: "bolder",
          size: "large"
        },
        {
          type: "TextBlock",
          text: CountRows(Topic.ticketTable) & " tickets found:",
          weight: "bolder",
          size: "medium",
          separator: true
        },
        {
          type: "Container",
          items: 
            ForAll(Topic.ticketTable,
              {
                type: "TextBlock",
                text: id & " / " & company & " / " & summary,
                wrap: true
              }
          )
        }
      ]
    }
    

    And boom! Our result!

    enter image description here