Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

Quick Start Rendering Microapps

Steven Harrington edited this page Jun 29, 2023 · 4 revisions

Quick Start

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.

You will learn

  • The major structural components of a Microapp
  • How to render a Microapp View

Prerequisites

  • 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

Before We Start

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.

Environment Setup

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.

Structural Components of a Microapp

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:

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>"

Microapp properties

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": []
  }
]

Obtain a specific Microapp view

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"
  }
}

Rendering a Microapp

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):

Microapp View

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.

Microapp Rendering function

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.

Microapp Interactivity Handling

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.