Articles in this section
Category / Section

How to Embed Bold BI Dashboard Using React Native CLI with Node.js?

Published:

This article demonstrates how to integrate Bold BI dashboards within a React Native CLI application, using Node.js as the backend. The purpose of this application is to show how to render the dashboard available on your Bold BI server.

Requirements/Prerequisites

NOTE: Node.js versions 18.20 to 22.14 are supported.

How to Run the Sample

  • Please obtain the React Native CLI with Node.js sample from GitHub.

  • Ensure that you have enabled embedded authentication on the Embed Settings page. If it is not currently enabled, refer to the following image or the detailed instructions to enable it.

    Embed Settings

  • To download the embedConfig.json file, please follow this link for reference. Additionally, you can refer to the following image for visual guidance.

    Download Embed Settings

    image.png

  • Copy the downloaded embedConfig.json file and paste it into the designated location within the application. Please ensure that you have placed it in the correct location, as shown in the following image.

    Embed Config Location

  • Open the Nodejs sample in Visual Studio Code.

  • To install all dependent packages, use the command npm install.

  • Then, run the back-end Node.js sample using the command node embed.js.

  • Open the React Native CLI project in Android Studio.

  • To install all the required packages, use the command npm install.

  • Add a virtual device and run the Metro bundler in the terminal using the command npx react-native start.

  • Finally, run the sample in the Android emulator with the command npx react-native run-android.

NOTE: If the API host is already in use, modify the port number in embed.js according to your preference and update App.js in the React Native application accordingly.

How the Sample Works

  • The WebView component is used to render the dashboard.
const customHTML = `
    <html>
      <head>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </head>
      <body style="margin:0;padding:0;overflow:hidden;">
        <div id="dashboardContainer" style="width:100%;height:100vh;"></div>
      </body>
    </html>`;
return (
    <WebView
      source={{ html: customHTML }}
      mixedContentMode="always"
      injectedJavaScript={injectedJavaScript}
      javaScriptEnabled={true}
      originWhitelist={["*"]}
      onMessage={(event) => console.log("WebView message:", event.nativeEvent.data)}
    />
  );
  • The WebView loads a JavaScript snippet that dynamically injects the Bold BI embedding script and initializes the dashboard.
  const injectedJavaScript = `
    (function() {
      function loadScript(url, callback) {
        var script = document.createElement('script');
        script.src = url;
        script.onload = callback;
        script.onerror = function() {
          window.ReactNativeWebView.postMessage("Script loading failed.");
        };
        document.head.appendChild(script);
      }

      function renderDashboard() {
        try {
          const dashboard = BoldBI.create({
              serverUrl: "${ServerUrl + '/' + SiteIdentifier}",
              dashboardId: "${DashboardId}",
              embedContainerId: "dashboardContainer",
              authorizationServer: {
                  url: "${apiHost + authorizationServerAPI}"
              }
            });
          dashboard.loadDashboard();
        } catch (error) {
          console.error("Error loading dashboard:", error);
        }
      }

      loadScript('https://cdn.boldbi.com/embedded-sdk/v11.2.7/boldbi-embed.js', renderDashboard);
    })();
    true;
  `;
  • Before rendering, authorize the server URL by making a call to the AuthorizationServer API using the provided embedConfig values.
app.post('/authorizationserver',  async function (req, response){
var embedQuerString = req.body.embedQuerString;
var dashboardServerApiUrl = req.body.dashboardServerApiUrl;

embedQuerString += "&embed_user_email=" + userEmail;
embedQuerString += "&embed_server_timestamp=" + Math.round((new Date()).getTime() / 1000);
var embedSignature = "&embed_signature=" + GetSignatureUrl(embedQuerString);
var embedDetailsUrl = "/embed/authorize?" + embedQuerString+embedSignature;

var serverProtocol = url.parse(dashboardServerApiUrl).protocol == 'https:' ? https : http;
serverProtocol.get(dashboardServerApiUrl+embedDetailsUrl, function(res){
    var str = '';
    res.on('data', function (chunk) {
    str += chunk;
    });
    res.on('end', function () {
    response.send(str);
    });
});
})

function GetSignatureUrl(queryString)
{
var keyBytes = Buffer.from(embedSecret);
var hmac = crypto.createHmac('sha256', keyBytes);
data = hmac.update(queryString);
gen_hmac= data.digest().toString('base64');

return gen_hmac;
}

Steps to Create a New React and Node.js Application to Embed a Dashboard

  1. Create a folder in your desired location and open it in Visual Studio Code.

  2. Open the terminal in Visual Studio Code. Please refer to the image below.

    image.png

  3. Ensure that you have enabled embed authentication on the Embed Settings page. If it is not currently enabled, refer to the following image or detailed instructions to enable it.
    embed-settings.png

  4. To download the embedConfig.json file, please follow this link for reference. Additionally, you can refer to the following image for visual guidance.

    embed-settings-download.png

    embedconfig-properties.jpg

  • Copy the downloaded embedConfig.json file and paste it into the designated location within the application. Please ensure that it is placed in the correct location, as shown in the image below.

    image.png

  • Next, create a JavaScript file named embed.js. Within this file, create an API endpoint called /authorizationserver/get that utilizes the GetSignatureUrl() method to generate the required algorithm. In this API, append the embedQueryString, userEmail, and the value obtained from the GetSignatureUrl() method as query parameters in the URL to retrieve the details of a specific dashboard.

        var fs = require("fs");
        var http = require("http");
        var https = require("https");
        var url = require("url");
        var express = require('express');
        var cors = require('cors');
        var app = express();
        var crypto = require('crypto');
        const path = require('path');
        
        app.use(cors());
        //Parse JSON bodies (as sent by API clients).
        app.use(express.json());
        
        //Assign a port number for an API to run.
        const port = 8080;
        
        let appconfig;
        try {
            appconfig = JSON.parse(fs.readFileSync('embedConfig.json'));
        } catch (error) {
            console.error('Error: embedConfig.json file not found.');
            process.exit(1);
        }
        
        var embedSecret = appconfig.EmbedSecret;
        var userEmail = appconfig.UserEmail;
        
        app.post('/authorizationserver',  async function (req, response){
            var embedQuerString = req.body.embedQuerString;
            var dashboardServerApiUrl = req.body.dashboardServerApiUrl;
            
            embedQuerString += "&embed_user_email=" + userEmail;
            embedQuerString += "&embed_server_timestamp=" + Math.round((new Date()).getTime() / 1000);
            var embedSignature = "&embed_signature=" + GetSignatureUrl(embedQuerString);
            var embedDetailsUrl = "/embed/authorize?" + embedQuerString+embedSignature;
            
            var serverProtocol = url.parse(dashboardServerApiUrl).protocol == 'https:' ? https : http;
            serverProtocol.get(dashboardServerApiUrl+embedDetailsUrl, function(res){
                var str = '';
                res.on('data', function (chunk) {
                str += chunk;
                });
                res.on('end', function () {
                response.send(str);
                });
            });
        })
        
        function GetSignatureUrl(queryString)
        {
            var keyBytes = Buffer.from(embedSecret);
            var hmac = crypto.createHmac('sha256', keyBytes);
            data = hmac.update(queryString);
            gen_hmac= data.digest().toString('base64');
            
            return gen_hmac;
        }
        app.get('/getdetails', (req, res) => {
            const serverEmbedConfigData = path.join(__dirname, 'embedConfig.json');
            const jsonData = fs.readFileSync(serverEmbedConfigData, 'utf8');
            const parsedData = JSON.parse(jsonData);
        
            const clientEmbedConfigData = {
                DashboardId: parsedData.DashboardId,
                ServerUrl: parsedData.ServerUrl, 
                SiteIdentifier: parsedData.SiteIdentifier, 
                EmbedType: parsedData.EmbedType, 
                Environment: parsedData.Environment
            };
            res.send(clientEmbedConfigData);
        });
        
        app.listen(port, () => {
            console.log(`Server is running on port ${port}`);
        }); 
    

    NOTE: If the API host is already in use, modify the port number in embed.js according to your preference, and update App.js in the React Native application accordingly.

  • Create a new file and name it package.json. Installing the packages listed in the following dependencies section is essential.

        {
             "version": "1.0.0",
             "description": "",
             "main": "embed.js",
             "dependencies": {
                 "cors": "^2.8.5",
                 "express": "^4.17.3"
             },
             "devDependencies": {},
             "scripts": {
                 "test": "echo \"Error: no test specified\" && exit 1"
             },
             "keywords": [],
             "author": "",
             "license": "ISC"
         }
    
  • Run the following command in the terminal: npm install.

  • To run the Node.js sample, use the following command in Visual Studio Code: npm start.

  • Create a new React Native project called ReactNativeCLI using the following command:

        npx @react-native-community/cli init ReactNativeCLI
    
  • After creating the React Native CLI sample, open the project in Android Studio.

  • Within the React Native CLI sample, create a new file named App.js. In the App.js file, add the following code to import the required modules, define the HomeScreen component, and use a useEffect hook to fetch the dashboard details when the component loads.

        import React, { useEffect, useState } from "react";
        import { WebView } from "react-native-webview";
        
        export default function HomeScreen() {
          const [embedConfig, setEmbedConfig] = useState(null);
        
          const apiHost = "http://10.0.2.2:8080";  // Use emulator IP instead of localhost
          const authorizationServerAPI='/authorizationserver';
          const getDetailsUrl='/getdetails';
        
          useEffect(() => {
            fetch(apiHost+getDetailsUrl)
              .then((response) => response.json())
              .then((data) => setEmbedConfig(data))
              .catch((error) => console.error("Error fetching embed config:", error));
          }, []);
        
          if (!embedConfig) return null;
        
          const { ServerUrl, DashboardId, SiteIdentifier } = embedConfig;
    
  • Inside the App.js file, add the following code: create a DOM element with the ID dashboardContainer. This element will be used in the renderDashboard() method to display the dashboard within it.

        const customHTML = `
            <html>
              <head>
                <meta name="viewport" content="width=device-width, initial-scale=1" />
              </head>
              <body style="margin:0;padding:0;overflow:hidden;">
                <div id="dashboardContainer" style="width:100%;height:100vh;"></div>
              </body>
            </html>`;
        
         const injectedJavaScript = `
            (function() {
              function loadScript(url, callback) {
                var script = document.createElement('script');
                script.src = url;
                script.onload = callback;
                script.onerror = function() {
                  window.ReactNativeWebView.postMessage("Script loading failed.");
                };
                document.head.appendChild(script);
              }
        
              function renderDashboard() {
                try {
                  const dashboard = BoldBI.create({
                      serverUrl: "${ServerUrl + '/' + SiteIdentifier}",
                      dashboardId: "${DashboardId}",
                      embedContainerId: "dashboardContainer",
                      authorizationServer: {
                          url: "${apiHost+authorizationServerAPI}"
                      }
                    });
                  dashboard.loadDashboard();
                } catch (error) {
                  console.error("Error loading dashboard:", error);
                }
              }
        
              loadScript('https://cdn.boldbi.com/embedded-sdk/v11.2.7/boldbi-embed.js', renderDashboard);
            })();
            true;
          `;
        
          return (
            <WebView
              source={{ html: customHTML }}
              mixedContentMode="always"
              injectedJavaScript={injectedJavaScript}
              javaScriptEnabled={true}
              originWhitelist={["*"]}
              onMessage={(event) => console.log("WebView message:", event.nativeEvent.data)}
            />
          );
        }
    
  • After that, add a virtual device and run the Metro bundler in the terminal using the command npx react-native start.

  • Finally, run the sample in the Android emulator using the command npx react-native run-android.

Was this article useful?
Like
Dislike
Help us improve this page
Please provide feedback or comments
SP
Written by Santhoshkumar Palpandiyan
Updated
Comments (0)
Please  to leave a comment
Access denied
Access denied