-
Notifications
You must be signed in to change notification settings - Fork 0
Quick Start Rendering Microapps
Welcome to our quick start guide on Rendering Microapps. This page will give you an introduction to how you can begin rendering Microapps in your client.
- The major structural components of a Microapp
- How to render a Microapp View
- You have completed Quick Start:Sending and Retrieving Smart Notifications
- You have a modern browser such as Chrome or Firefox available on your device
- You have familiarity with JavaScript and the HTML Document Object Model (DOM)
- You have access to a
git
client in which to clone a repository to your local device - You have access to a text editor to edit HTML and JavaScript
- A Workshop app has been installed in your Workgrid Space with the Microapp component enabled
In writing this quick start tutorial our goal is to focus on the Microapp concepts that are important to learn and not get bogged down on how we explicitly render the components. For this reason we're avoiding popular UI libraries and frameworks like Angular and React. Similarly, we're also avoiding using low-level JavaScript APIs (e.g. createElement and createTextNode) to facilitate element creation as that'll distract from the learning objective.
In this tutorial we'll be using a library called hyperscript to facilitate the creation of HTML DOM elements. It provides just enough abstraction to not create a distraction and keep our focus on learning Microapp concepts.
Now open a terminal on your device. Before we can proceed we need to make sure you still have your environment variables configured that were used in the prerequisite tutorial:
$ env | grep WORKGRID_
WORKGRID_USERNAME=<OMITTED
WORKGRID_COMPANY_CODE=<OMITTED
WORKGRID_APP_CLIENT_ACCESS_TOKEN=<OMITTED
WORKGRID_SPACE_ID=<OMITTED
WORKGRID_USER_CLIENT_ID=<OMITTED
WORKGRID_USER_CLIENT_SECRET=<OMITTED
If these variables are not set please revisit our Quick Start:Sending and Retrieving Smart Notifications to set them up.
The best way to understand the structural components of a Microapp is to fetch the list of installed Microapps for your user from our Unified Experience API.
Run the following curl
command in your terminal to retrieve your list of installed Microapps. Remember you may need to:
- refresh your OAuth 2 token if your credentials have expired.
curl --request GET \
--url "https://${WORKGRID_COMPANY_CODE}.workgrid.com/appbuilder/userapps" \
--header "Authorization: Bearer ${WORKGRID_USER_TOKEN}" \
--header "x-workgrid-space: ${WORKGRID_SPACE_ID}"
You should get a response like this:
[
{
"id": "270c3146-3ca4-47ef-b8d1-7d123983c94d",
"name": "Quick Links",
"description": "Allow users to favorite commonly used links",
"iconUrl": "https://cdn.dev.workgrid.com/templates/42b39c6e-11f4-4fc8-bac5-1489ddac6fb1/icon.png",
"featureName": "Find quick links",
"hasChatDiscoverability": true,
"chatDiscoverabilityPhrase": "Provides employees with quick access to URLs of the intranet pages and internet sites that are most likely to be requested by employees.",
"relatedFeatures": []
}
]
Take the value of the id
and store it in an environment variable named WORKGRID_APP_ENTRYPOINT
by running a command like the following:
export WORKGRID_APP_ENTRYPOINT="<REPLACE-WITH-ENTRYPOINT>"
Microapps have a couple of properties that are of particular importance when rendering. Not all are discussed here, but we will call a few out that will be part of the renderer in this tutorial. See the inline comments in the JSON sample below:
[
{
/* id is used to render the initial view of the app */
"id": "270c3146-3ca4-47ef-b8d1-7d123983c94d",
"name": "Quick Links",
"description": "Allow users to favorite commonly used links",
"iconUrl": "https://cdn.dev.workgrid.com/templates/42b39c6e-11f4-4fc8-bac5-1489ddac6fb1/icon.png",
"featureName": "Find quick links",
"hasChatDiscoverability": true,
"chatDiscoverabilityPhrase": "Provides employees with quick access to URLs of the intranet pages and internet sites that are most likely to be requested by employees.",
"relatedFeatures": []
}
]
Now that we have a list of microapps and their initial entrypoint views, we can take those entrypoints and use them to render the apps' content. This can be done by executing a query similar to the one seen below.
curl --request POST \
--url "https://${WORKGRID_COMPANY_CODE}.workgrid.com/appbuilder/userapps/${WORKGRID_APP_ENTRYPOINT}" \
--header "Authorization: Bearer ${WORKGRID_USER_TOKEN}" \
--header "x-workgrid-space: ${WORKGRID_SPACE_ID}"
You should get a response like this:
{
"appId": "2572a2a8-8b90-4872-b7d8-4c66d32d0260",
"featureId": "270c3146-3ca4-47ef-b8d1-7d123983c94d",
"featureExecutionId": "40ca475c-282b-453a-b92d-c2719edf6bfa",
"executionDate": "2023-06-28T16:27:54.642Z",
"response": {
"type": "AdaptiveCard",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "Image",
"url": "https://cdn.dev.workgrid.com/templates/42b39c6e-11f4-4fc8-bac5-1489ddac6fb1/icon.png",
"size": "Small",
"width": "20px",
"spacing": "None"
}
],
"verticalContentAlignment": "Center"
},
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "TextBlock",
"size": "Medium",
"weight": "Bolder",
"text": "Quick Links",
"wrap": true,
"style": "heading"
}
],
"verticalContentAlignment": "Center",
"horizontalAlignment": "Left"
},
{
"type": "Column",
"width": "stretch",
"horizontalAlignment": "Right",
"items": [
{
"type": "RichTextBlock",
"horizontalAlignment": "Right",
"inlines": [
{
"type": "TextRun",
"text": "Edit",
"selectAction": {
"type": "Action.Execute",
"id": "edit-view",
"associatedInputs": "none",
"data": {
"endpoint": "55b1100e-33ea-4c6f-b682-a2582044bbe7",
"adminLinks": [
{
"name": "Google",
"text": "[Google](https://www.google.com)",
"value": "https://www.google.com",
"isEnabled": true
},
{
"name": "Workgrid",
"text": "[Workgrid](https://www.workgrid.com/)",
"value": "https://www.workgrid.com/",
"isEnabled": true
}
]
}
}
}
]
}
],
"verticalContentAlignment": "Center"
}
]
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "15px"
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "TextBlock",
"text": "[Google](https://www.google.com)",
"wrap": true,
"size": "Default"
}
],
"verticalContentAlignment": "Center",
"spacing": "Small"
}
]
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "15px"
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "TextBlock",
"text": "[Workgrid](https://www.workgrid.com/)",
"wrap": true,
"size": "Default"
}
],
"verticalContentAlignment": "Center",
"spacing": "Small"
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5"
}
}
For the remainder of this tutorial we will be building our renderer. When we finish this section, our renderer will produce a view that looks similar to this (although the number and types of microapps may be different for you):
Using the terminal on your device clone
the repository we'll be using for this tutorial by running the command below:
git clone https://github.com/Workgrid/headless-documentation.git
You should see output like this:
$ git clone https://github.com/Workgrid/headless-documentation.git
Cloning into 'headless-documentation'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), 4.44 KiB | 4.44 MiB/s, done.
Then change to the directory where we will be working by running the command below:
cd headless-documentation/quick-start-microapp-renderer
There are two files in this folder: index-start.html
and index-complete.html
. We will be starting
with index-start.html
to build our renderer. If you have any trouble along the way refer to the index-complete.html
file as it represents the completed tutorial. Now open the index-start.html
file in your text editor as well as a
browser.
Before we get to building our renderer we will touch on a few items in this HTML file that will help set the stage for
the builder. First and foremost we have a few constants to set namely your WORKGRID_COMPANY_CODE
, WORKGRID_SPACE_ID
,
and WORKGRID_USER_TOKEN
. They are grouped together like this in the file:
const WORKGRID_COMPANY_CODE = '<company-code>';
const WORKGRID_SPACE_ID = '<space-id>';
const WORKGRID_USER_TOKEN = '<user-token>';
Due to CORS (Cross-Origin Resource Sharing) we cannot
dynamically fetch the user token so you will have to periodically resort to the curl
commands from
the Quick Start:Sending and Retrieving Smart Notifications
tutorial to get a token and update the WORKGRID_USER_TOKEN
constant.
Near the bottom of the file you will find a function named retrieveMicroapps
. This function will fetch the currently installed microapps for the user. Further up in the HTML file you will find two functions named renderMicroapp
and createAdaptiveCardInstance
as shown below:
async function renderMicroapp(microapp) {}
function createAdaptiveCardInstance() {
// Create an AdaptiveCard instance
let adaptiveCard = new AdaptiveCards.AdaptiveCard();
// Host Config defines the style and behavior of a card
adaptiveCard.hostConfig = new AdaptiveCards.HostConfig({
fontFamily: 'Segoe UI, Helvetica Neue, sans-serif',
actions: {
maxActions: 6,
actionsOrientation: 'vertical',
actionAlignment: 'stretch',
},
});
// Set the adaptive card's event handlers. onExecuteAction is invoked
// whenever an action is clicked in the card
adaptiveCard.onExecuteAction = async function (action) {};
return adaptiveCard;
}
This is where most of the code will go to create our renderer.
The renderMicroapp
is where we will accomplish two major tasks. The first will be to create a microapp
element and insert it into the DOM. The second will be to obtain the relevant microapp view and render the content
Here is the code of the renderMicroapp
function to implement these two tasks:
const container = h('div.microapp-container');
output.append(container);
// Load the applicable Microapp view
container.innerHTML = '...Loading Microapp view';
const microappView = await retrieveMicroappView(microapp.id);
let adaptiveCard = createAdaptiveCardInstance();
adaptiveCard.parse(microappView);
// Render the card to an HTML element:
const renderedCard = adaptiveCard.render();
container.innerHTML = '';
container.append(renderedCard);
Here we use the h
function to create an microapp
DOM element. We add the element to the output
DOM element using the append function. Next we can obtain the microapp view to be rendered and append the view to the microapp
DOM element.
Place this code inside the body of the renderMicroapp
function as shown below:
renderMicroapp({ node }) {
+ const container = h("div.microapp-container");
+
+ container.innerHTML = "...Loading Microapp view";
+ const microappView = await retrieveMicroappView(microapp.id);
+ let adaptiveCard = createAdaptiveCardInstance();
+ adaptiveCard.parse(microappView);
+ // Render the card to an HTML element:
+ const renderedCard = adaptiveCard.render();
+ container.innerHTML = "";
+ container.append(renderedCard);
}
Now if you go over to your browser you should see at least one Microapp view that is rendered. Remember you may need to refresh your OAuth 2 token if your credentials have expired.
Now that we have the rendering function in place we can proceed to handling microapp interactivity.
In order for Microapps in Workgrid to function properly they need to communicate with our api to carry out actions such as:
- Navigation to another Microapp View
- Submit content from a Microapp View
We now have to implement an event handler so a Microapp view will properly render based on an action undertaken. Here is the code of the createAdaptiveCardInstance
to implement the event handler:
adaptiveCard.onExecuteAction = async function (action) {
// Action.type is returning undefined. For now use direct path
if (
action._propertyBag.type === 'Action.Execute' ||
action._propertyBag.type === 'Action.Submit'
) {
// Obtain the closet microapp container
const container = action.parent.renderedElement.closest(
'.microapp-container'
);
// Load the applicable Microapp view
container.innerHTML = '...Loading Microapp view';
const view = await retrieveMicroappView(action.id, action.data);
adaptiveCard.parse(view);
// Render the card to an HTML element:
const renderedMicroappView = adaptiveCard.render();
container.innerHTML = '';
container.append(renderedMicroappView);
}
};
Here we obtain the microapp
DOM element based on the triggered action. We make a request to obtain the microapp view to be rendered based on the attributes associated to the action
Place this code inside the body of the adaptiveCard.onExecuteAction
function as shown below:
adaptiveCard.onExecuteAction = async function (action) {
+ // Action.type is returning undefined. For now use direct path
+ if ( action._propertyBag.type === "Action.Execute" ||
+ action._propertyBag.type === "Action.Submit" )
+ {
+ // Obtain the closet microapp container
+ const container = action.parent.renderedElement.closest(
+ ".microapp-container");
+
+ // Load the applicable Microapp view
+ container.innerHTML = "...Loading Microapp view";
+ const view = await retrieveMicroappView(action.id, action.data);
+ adaptiveCard.parse(view);
+
+ // Render the card to an HTML element:
+ const renderedMicroappView = adaptiveCard.render();
+ container.innerHTML = "";
+ container.append(renderedMicroappView);
}
Now if you go over to your browser, click on action button within the view, you should see a new Microapp view rendered. Remember you may need to refresh your OAuth 2 token if your credentials have expired.
Congratulations! You have just built your first Microapp renderer.