Adaptive Card SKY Add-ins
Published
In this post, I'll describe a new feature we've introduced - implementing "Adaptive Cards" within SKY Add-ins! This capability (in "Preview" now) will allow you to inject an Adaptive Card into the Blackbaud user interface using the SKY Add-ins framework.
What are "Adaptive Cards"?
Adaptive Cards are an interesting way of delivering lightweight UI to a host application. It is a platform-agnostic and purely declarative framework where you author a "card" in JSON, and the card gets sent to and rendered by a host application. When sent to Microsoft Teams, the card looks like the Teams UI...when sent to Outlook, it renders as an actionable message embedded in the email...and when sent to an iOS device, it renders using native iOS elements. The card "adapts" to its host application - same card JSON, just different rendering for each host app. There is an official schema that is well-documented, and there are SDKs for many popular platforms, including Android, iOS, ASP.NET, ReactNative...even a JavaScript SDK for rendering Adaptive Cards on web pages!
For example, here's the JSON for a very basic "Hello world" Adaptive Card:
When sent to a host application, the card might render like this:
You can view a gallery of sample cards (and see the underlying JSON definitions) here:
https://adaptivecards.io/samples
From the gallery, you can see a variety of interesting (and rich) UX examples - you've probably even seen some of these cards in action in your day-to-day life:
The phrase "lightweight UI" is emphasized above to convey that, while you can achieve a very rich, interactive, and responsive UX, this framework isn't meant to solve every use case. It isn't meant to produce complex and highly interactive SPAs - instead, it's intended for more narrowly scoped and focused user interactions.
There is even a nice drag/drop WYSIWYG designer where you can build a card from scratch or from a template right in the browser, no coding required! As you build out a card, you can see a visual of how it will render as well as the underlying JSON that defines the card:
And just in case it isn't obvious, all of this is free and open-sourced, with no login/account creation required! Right now, anyone on the planet can visit the designer and create a great looking Adaptive Card with very little effort and at no cost!
To illustrate, I used the drag/drop designer and re-created the "Giving" tile on the constituent page within Raiser's Edge NXT:
The Adaptive Card Host SPA
So using the online designer, it's easy to craft an interesting and visually appealing Adaptive Card. But a card needs a "host application" to render it, and there are several hosts available - the above card JSON could be sent to Microsoft Teams, Outlook, or a number of other hosts. Imagine sending a "major donor summary profile" Adaptive Card to a Fundraisers channel in Microsoft Teams!
As mentioned earlier, there is a JavaScript SDK for rendering Adaptive Cards which makes it possible to show cards on web pages. What if you could leverage Adaptive Cards to inject some scoped and narrowly focused UI into Blackbaud solutions? Well, that is exactly the goal of our SKY Add-ins framework!
Similar to how we implemented the Power App Host SPA and the Power BI Host SPA, we created an Adaptive Card Host SPA! This SPA acts as a SKY Add-in and can be used to inject an Adaptive Card into a Blackbaud solution contextually bound to the "current record". Here's the above card showing on the actual constituent page within Raiser's Edge NXT:
Note some attractive aspects to this approach:
How does this work?
The Adaptive Card Host SPA is parameterized by a "card service URL" that will be called when the SPA is loaded to fetch the JSON for the card to be displayed. As described in the documentation, a developer could define a SKY Add-in for the Constituent Tile Dashboard extension point using a URL like this:
https://app.blackbaud.com/addin-adaptivecard-host/tile?cardServiceUrl=someURL
At runtime, when the add-in is loaded the SPA will send a POST request to the specified URL with the user identity token (UIT) and current "context" object (as defined by the extension point) in the body. This is exactly the same pattern used in the Web Request Action SPA, and the expectation is that the service called will validate the user identity token and then use the context values provided to build and return the JSON for the Adaptive Card to be shown. The SPA will in turn use the Adaptive Card JavaScript SDK to render the card in the UI.
Using Power Automate to craft the JSON
The card service URL parameter can actually refer to any web service, but to reinforce the low-code/no-code theme I decided to leverage Power Automate and the new Trigger a flow from a SKY Add-in button template (we'll be publishing a new template to make this even easier). I created a flow that will accept the UIT and a context object as part of the trigger body and returns the JSON for a card. So my flow is actually acting like a web service - it's triggered by a request, and it returns a response!
Here's an overview of the flow:
After validating the user identity token, the "Build the Adaptive Card JSON" block uses a few of the Raiser's Edge NXT connectors to fetch details about the constituent along with the first/latest/greatest/lifetime giving:
I did some minor formatting of amounts using the built-in Format number action:
...and used a few additional steps and expressions to aggregate and compose some values so they'll display nicely (ex: showing the gift splits as a semi-colon separated string):
I copied the card JSON payload from the WYSIWYG designer, pasted it into a Compose action, and then updated the placeholders in my card with actual values from the connectors:
My flow returns the JSON to the Adaptive Card Host SPA using the Response action:
And that is it!
To summarize:
Actions
As described in the documentation, the Adaptive Card UX can even be interactive with Markdown support for formatting text and rendering links. You can use expressions to dynamically show/hide content based on declarative logic, and you can add "actions" to the card that can trigger additional business logic.
More information
We're excited to make this functionality available as an easy-to-use option for creating SKY Add-ins. Using the online WYSIWYG designer to compose the card interface, and using Power Automate to incorporate live data from Blackbaud (or any) solution makes this a very compelling low-code/no-code option!
For more information, make sure to check out the Adaptive Card Host SPA documentation and the Adaptive Card Add-ins tutorial using Power Automate.
Adaptive Cards are an interesting way of delivering lightweight UI to a host application. It is a platform-agnostic and purely declarative framework where you author a "card" in JSON, and the card gets sent to and rendered by a host application. When sent to Microsoft Teams, the card looks like the Teams UI...when sent to Outlook, it renders as an actionable message embedded in the email...and when sent to an iOS device, it renders using native iOS elements. The card "adapts" to its host application - same card JSON, just different rendering for each host app. There is an official schema that is well-documented, and there are SDKs for many popular platforms, including Android, iOS, ASP.NET, ReactNative...even a JavaScript SDK for rendering Adaptive Cards on web pages!
For example, here's the JSON for a very basic "Hello world" Adaptive Card:
When sent to a host application, the card might render like this:
You can view a gallery of sample cards (and see the underlying JSON definitions) here:
https://adaptivecards.io/samples
From the gallery, you can see a variety of interesting (and rich) UX examples - you've probably even seen some of these cards in action in your day-to-day life:
The phrase "lightweight UI" is emphasized above to convey that, while you can achieve a very rich, interactive, and responsive UX, this framework isn't meant to solve every use case. It isn't meant to produce complex and highly interactive SPAs - instead, it's intended for more narrowly scoped and focused user interactions.
There is even a nice drag/drop WYSIWYG designer where you can build a card from scratch or from a template right in the browser, no coding required! As you build out a card, you can see a visual of how it will render as well as the underlying JSON that defines the card:
And just in case it isn't obvious, all of this is free and open-sourced, with no login/account creation required! Right now, anyone on the planet can visit the designer and create a great looking Adaptive Card with very little effort and at no cost!
To illustrate, I used the drag/drop designer and re-created the "Giving" tile on the constituent page within Raiser's Edge NXT:
The Adaptive Card Host SPA
So using the online designer, it's easy to craft an interesting and visually appealing Adaptive Card. But a card needs a "host application" to render it, and there are several hosts available - the above card JSON could be sent to Microsoft Teams, Outlook, or a number of other hosts. Imagine sending a "major donor summary profile" Adaptive Card to a Fundraisers channel in Microsoft Teams!
As mentioned earlier, there is a JavaScript SDK for rendering Adaptive Cards which makes it possible to show cards on web pages. What if you could leverage Adaptive Cards to inject some scoped and narrowly focused UI into Blackbaud solutions? Well, that is exactly the goal of our SKY Add-ins framework!
Similar to how we implemented the Power App Host SPA and the Power BI Host SPA, we created an Adaptive Card Host SPA! This SPA acts as a SKY Add-in and can be used to inject an Adaptive Card into a Blackbaud solution contextually bound to the "current record". Here's the above card showing on the actual constituent page within Raiser's Edge NXT:
Note some attractive aspects to this approach:
- Adaptive Cards are simple to create using the designer (drag/drop + set a few properties)
- Cards are purely declarative, so no JavaScript/coding required
- Unlike the Power Apps and Power BI Host SPAs, this technique doesn't require the end-user to have a license for anything! End users experience the card just as if it were a native part of the Blackbaud application.
How does this work?
The Adaptive Card Host SPA is parameterized by a "card service URL" that will be called when the SPA is loaded to fetch the JSON for the card to be displayed. As described in the documentation, a developer could define a SKY Add-in for the Constituent Tile Dashboard extension point using a URL like this:
https://app.blackbaud.com/addin-adaptivecard-host/tile?cardServiceUrl=someURL
At runtime, when the add-in is loaded the SPA will send a POST request to the specified URL with the user identity token (UIT) and current "context" object (as defined by the extension point) in the body. This is exactly the same pattern used in the Web Request Action SPA, and the expectation is that the service called will validate the user identity token and then use the context values provided to build and return the JSON for the Adaptive Card to be shown. The SPA will in turn use the Adaptive Card JavaScript SDK to render the card in the UI.
Using Power Automate to craft the JSON
The card service URL parameter can actually refer to any web service, but to reinforce the low-code/no-code theme I decided to leverage Power Automate and the new Trigger a flow from a SKY Add-in button template (we'll be publishing a new template to make this even easier). I created a flow that will accept the UIT and a context object as part of the trigger body and returns the JSON for a card. So my flow is actually acting like a web service - it's triggered by a request, and it returns a response!
Here's an overview of the flow:
After validating the user identity token, the "Build the Adaptive Card JSON" block uses a few of the Raiser's Edge NXT connectors to fetch details about the constituent along with the first/latest/greatest/lifetime giving:
I did some minor formatting of amounts using the built-in Format number action:
...and used a few additional steps and expressions to aggregate and compose some values so they'll display nicely (ex: showing the gift splits as a semi-colon separated string):
I copied the card JSON payload from the WYSIWYG designer, pasted it into a Compose action, and then updated the placeholders in my card with actual values from the connectors:
My flow returns the JSON to the Adaptive Card Host SPA using the Response action:
And that is it!
To summarize:
- I created an attractive Adaptive Card using the WYSIWYG designer to get the basic JSON for the card.
- I created a Power Automate flow to build the card with data from the Raiser's Edge NXT connectors (using the JSON from the designer and replacing the placeholder values with actual values form the connectors).
- I registered a SKY Add-in that uses the Adaptive Card Host SPA, and specified the URL of my flow as the source of the card JSON.
Actions
As described in the documentation, the Adaptive Card UX can even be interactive with Markdown support for formatting text and rendering links. You can use expressions to dynamically show/hide content based on declarative logic, and you can add "actions" to the card that can trigger additional business logic.
More information
We're excited to make this functionality available as an easy-to-use option for creating SKY Add-ins. Using the online WYSIWYG designer to compose the card interface, and using Power Automate to incorporate live data from Blackbaud (or any) solution makes this a very compelling low-code/no-code option!
For more information, make sure to check out the Adaptive Card Host SPA documentation and the Adaptive Card Add-ins tutorial using Power Automate.
News SKY Developer Announcements
11/16/2022 11:49am EST
Leave a Comment