Embed using React Native mobile SDK

Embed using React Native mobile SDK

ThoughtSpot’s React Native Mobile Embed SDK Beta enables developers to embed ThoughtSpot Analytics in their mobile apps. This SDK is designed for the React Native framework to allow developers to build their mobile apps that operate on iOS and Android platforms, using native resources and a single codebase.

In its initial release, the React Native Embed SDK supports embedding a Liveboard component and customizing the embed view within the mobile app.

Before you beginπŸ”—

Before you get started, check the following:

Get started with embeddingπŸ”—

This section provides a set of steps to quickly embed a ThoughtSpot Liveboard in a mobile app.

Install the SDKπŸ”—

The latest version of the Mobile Embed SDK for React Native is available at https://www.npmjs.com/package/@thoughtspot/react-native-embed-sdk.

npm install @thoughtspot/react-native-embed-sdk

Import the SDK into your projectπŸ”—

 // NPM
 import { LiveboardEmbed, AuthType, init } from '@thoughtspot/react-native-embed-sdk';

After you import, you can define the ThoughtSpot host URL from which you want to embed a Liveboard, authentication type and attributes, and Liveboard ID.

File structure in the Expo go sandboxπŸ”—

In the Expo code sandbox, you’ll notice that your mobile embed project has the following files:

  • Auth.ts - Includes the code required to get authentication token from ThoughtSpot via REST API SDK.

  • App.tsx - Includes the code for expo app setup.

  • Home.tsx - Includes the code for the main screen and the form to populate embed view configuration, the init function with the tsHost and username, Liveboard ID, and custom style specification.

  • LiveboardView.tsx - Defines the interface configuration properties and event interaction settings for the Liveboard embed view.

You can use similar files in your project setup or an index file for the ThoughtSpot mobile embed code.

Initialize the SDK and set up authenticationπŸ”—

To initialize the SDK, the following information is required:

  • thoughtSpotHost
    The hostname of your ThoughtSpot application instance. For example, team2.thoughtspot.cloud. See FAQs to know how to find the hostname of your application instance.

  • authType
    Authentication type. In the current version, mobile embedding supports only the Cookieless Trusted authentication method (AuthType.TrustedAuthTokenCookieless).

init({
  thoughtSpotHost: 'ts-host-url',  // Replace with your ThoughtSpot host URL
  authType: AuthType.TrustedAuthTokenCookieless,
  getAuthToken: async () => "full-auth-token"
});

Add the Liveboard componentπŸ”—

const TsApp = () => {
  return (
    <View style={styles.container}>
    <LiveboardEmbed
        liveboardId="liveboard-id" // Replace it with your Liveboard ID
    />
    </View>
  );
};

Build your app and preview the embedded contentπŸ”—

  • Build your app:

    $ npm run build
  • If you are using an Expo project:

    1. Build your project locally

      expo start
    2. Scan the QR code with the Expo Go app to see the app with the embedded content.

Customize your embedπŸ”—

Just like the Visual Embed SDK for web application embed, the Mobile Embed SDK provides the following customization options:

Customize menu actionsπŸ”—

By default, the SDK includes a set of menu actions in the embedded view.

Default menu actions
  • Add filter (Action.AddFilter)
    Allows adding filters to the embedded Liveboard

  • Filter (Action.CrossFilter)
    Allows applying filters across all visualizations in a Liveboard.

  • Drill down (Action.DrillDown)
    Allows drilling down on a data point in the visualization to get granular details.

  • Personalized view (Action.PersonalisedViewsDropdown)
    The Liveboard personalized views drop-down.

  • Filter action (Action.AxisMenuFilter) in the chart axis or table column customization menu
    Allows adding, editing, or removing filters on a visualization.

  • Edit action (Action.AxisMenuEdit) in the axis customization menu.
    Allows editing the axis name, position, minimum and maximum values of a column.

  • Position action (Action.AxisMenuPosition) in the axis customization menu.
    Allows changing the position of the axis to the left or right side of the chart.

  • Sort action (Action.AxisMenuSort) - Sorts the data in ascending or descending order on a chart or table.

  • Aggregate (Action.AxisMenuAggregate) option in the chart axis or the table column customization menu.
    Provides aggregation options to analyze the data on a chart or table.

  • Conditional formatting menu option (Action.AxisMenuConditionalFormat)
    Allows adding rules for conditional formatting of data points on a chart or table.

  • The Group option (Action.AxisMenuGroup) in the chart axis or table column customization menu.
    Allows grouping data points if the axes use the same unit of measurement and a similar scale.

  • The Remove option (Action.AxisMenuRemove) in the chart axis or table column customization menu.
    Removes the data labels from a chart or the column of a table visualization.

  • The Rename option (Action.AxisMenuRename) in the chart axis or table column customization menu.
    Renames the axis label on a chart or the column header on a table

  • Time bucket option (Action.AxisMenuTimeBucket) in the chart axis or table column customization menu.
    Allows defining time metric for date comparison.

To disable or hide a menu action, you must specify the action ID in the disabledActions, visibleActions, or hiddenActions array. To show or hide menu actions, use either visibleActions or hiddenActions.

//Add the menu actions to show in the embed view. Removes all actions if the array is empty
visibleActions: [Action.AddFilter,Action.Share,Action.DrillDown,Action.AxisMenuFilter,Action.AxisMenuTimeBucket],
//disable actions
disabledActions: [Action.DrillDown, Action.Edit],
//specify the reason for disabling menu actions
disabledActionReason: "Contact your administrator to enable this feature",
//hiddenActions: [], /* Do not use if `visibleActions` is enabled */
//hide specific actions
hiddenActions: [Action.AddFilters],
//disable actions
disabledActions: [Action.DrillDown],
//specify the reason for disabling menu action
disabledActionReason: "Contact your administrator to enable this feature",
//visibleActions: [], /* Do not use if `hiddenActions` is enabled */

Customize app interactionsπŸ”—

To customize app interactions and enable custom workflows with Embed and Host events.

The following code adds an event listener for the authInit embed event and specifies how to handle the default load when it emits.

// Define a component that embeds a Liveboard and handles initial authentication state
const LiveboardEmbedView = () => {
  // Declare a loading state to control the loading UI
  const [loading, setLoading] = useState(true);

  // Create a ref to interact with the LiveboardEmbed component programmatically
  const webViewRef = useRef<any>(null);

  // Function to handle the AuthInit event from the LiveboardEmbed
  const handleAuthInit = () => {
    alert("Auth Init EmbedEvent"); // Show a simple alert when auth is initialized
    setLoading(false);  // Set loading to false once authentication is complete
  }

  return (
    <>
      {loading && <Text>Loading...</Text>}
      <LiveboardEmbed
        ref={webViewRef}
        liveboardId={liveboardId} // Pass the Liveboard ID
        onAuthInit={() => {handleAuthInit()}} // Callback when the AuthInit event is fired by the embed
      />
    </>
  );
};

Similarly, you can also add a host event to trigger an action or add custom workflow. The following example shows the host events registered to trigger reload and Liveboard Share actions.

// Define a component for embedding and interacting with a Liveboard
const LiveboardEmbedView = () => {
  // Create a reference to the LiveboardEmbed instance
  const webViewRef = useRef<any>(null);

  // Function to reload the embedded Liveboard
  const reloadView = () => {
    Alert.alert("Reloading") // Show an alert to inform the user
    if(webViewRef?.current) {
      // Trigger the Reload event on the Liveboard
      webViewRef?.current?.trigger(HostEvent.Reload)
    }
  }

  // Function to open the Share dialog for the Liveboard
  const shareView = () => {
    if(webViewRef?.current) {
      // Trigger the Share event on the Liveboard
      webViewRef.current.trigger(HostEvent.Share)
    }
  }

  // Render buttons for "Reload" and "Share", and the LiveboardEmbed component
  return (
    <>
      <View>
        <TouchableOpacity onPress={reloadView}>
          <Text>Reload</Text>
        </TouchableOpacity>
        <TouchableOpacity onPress={shareView}>
          <Text>Share</Text>
        </TouchableOpacity>
      </View>
      <LiveboardEmbed
        ref={webViewRef}  // Assign the ref to control this component
        liveboardId={liveboardId} // Pass the Liveboard ID
      />
    </>
  );
};

Customize stylesπŸ”—

You can use ThoughtSpot’s CSS customization framework to customize the text strings, icons, styles and the UI layout of the embedded view.

init({
    // Other attributes such as the host URL, authentication type and so on.
    customizations: {
        content: {
            strings: {
                // Custom label for the Filter menu action
                "Filter": "Select column",
            }
        },
        style: {
            customCSS: {
                variables: {
                    // Background color of the application
                    "--ts-var-root-background": "#fef4dd",
                    // Text color
                    "--ts-var-root-color": "#4a4a4a",
                    // Visualization title color
                    "--ts-var-viz-title-color": "#8e6b23",
                    // Font family for visualization title
                    "--ts-var-viz-title-font-family": "'Roboto', 'Helvetica', sans-serif",
                    // Title text capitalization
                    "--ts-var-viz-title-text-transform": "capitalize",
                    // Visualization description text color
                    "--ts-var-viz-description-color": "#6b705c",
                    // Font family for description text
                    "--ts-var-viz-description-font-family": "'Roboto', 'Helvetica', sans-serif",
                }
            }
        }
    }
});

Code samplesπŸ”—

The following example shows the minimum code required to embed a Liveboard successfully in a mobile app:

import React from 'react';
import { View, StyleSheet } from 'react-native';
// Import necessary ThoughtSpot SDK modules
import { AuthType, init, LiveboardEmbed } from '@thoughtspot/react-native-embed-sdk';

// Initialize the ThoughtSpot SDK
init({
    thoughtSpotHost: 'ts-host-url', // Replace with your ThoughtSpot host URL
    authType: AuthType.TrustedAuthTokenCookieless, //Using cookieless trusted token authentication
    getAuthToken: async () => "full-auth-token", //fetch a valid authentication token
});

// Add Liveboard component
const TsApp = () => {
    return (
    <View style={styles.container}>
      <LiveboardEmbed
        liveboardId="liveboard-id" // Pass the Liveboard ID
        onError={(error) => console.error('Embed error:', error)} // Log any embed errors
      />
    </View>
  );
};

// Define layout styles
const styles = StyleSheet.create({
    container: {
        flex: 1, // Takes up full screen height
        marginTop: 50, // Add some space from the top
        marginBottom: 30, // Add some space at the bottom
    },
});

export default TsApp; // Export the Liveboard component

In the following code sample, the embedded view is customized to show only Drill down (Action.DrillDown), Add filter (Action.AddFilter), and Share actions. This code also includes embed events that register event listeners or host events to trigger a response from the app.

import React, { useRef, useState } from 'react';
import { StyleSheet, View, Text, Alert, TouchableOpacity } from 'react-native';
// Import ThoughtSpot SDK components and helpers
import { Action, HostEvent, LiveboardEmbed, init, AuthType } from '@thoughtspot/react-native-embed-sdk';

// Initialize the ThoughtSpot SDK
init({
  thoughtSpotHost: 'ts-host-url', // Replace with your ThoughtSpot host URL
  authType: AuthType.TrustedAuthTokenCookieless, // Using cookieless trusted token authentication
  getAuthToken: async () => "full-auth-token", // Fetch authentication token
});

// Custom components to display and interact with the ThoughtSpot Liveboard
const LiveboardView = ({ liveboardId }) => {
  const [loading, setLoading] = useState(true); // State to track loading (optional)
  const webViewRef = useRef(null); // Ref to access the LiveboardEmbed instance

  // Reloads the liveboard when called
  const reloadView = () => {
    Alert.alert("Reloading")
    if (webViewRef?.current) {
      webViewRef.current.trigger(HostEvent.Reload);
    }
  };
  // Triggers the Liveboard sharing action
  const shareView = () => {
    if(webViewRef?.current) {
      webViewRef.current.trigger(HostEvent.Share)
    }
  };

  return (
    <View style={styles.embedContainer}>
      {/* The embedded ThoughtSpot Liveboard view */}
      <LiveboardEmbed
        ref={webViewRef}
        liveboardId={liveboardId}
        onAuthInit={() => setLoading(false)} // If authentication is successful
        onError={(error) => Alert.alert("Error", `Error: ${JSON.stringify(error)}`)} // Handle embed errors
        onLiveboardRendered={() => Alert.alert("Success", "Liveboard Rendered")} // Notify when Liveboard is rendered
        visibleActions={[Action.DrillDown, Action.AddFilter, Action.Share]} // Showm menu actions
        fullHeight={true}
      />
      {/* Optional control buttons */}
      <TouchableOpacity onPress={reloadView} style={styles.button}>
        <Text style={styles.buttonText}>Reload View</Text>
      </TouchableOpacity>
      <TouchableOpacity onPress={shareView}>
        <Text>Share</Text>
       </TouchableOpacity>
    </View>
  );
};

// Component that renders the LiveboardView
const TsApp = () => {
  return (
    <View style={styles.container}>
      <LiveboardView liveboardId="liveboard-id" /> // Pass the Liveboard ID
    </View>
  );
};

// Define layout styles
const styles = StyleSheet.create({
    container: {
        flex: 1, // Takes up full screen height
        marginTop: 50,
        marginBottom: 30,
    },
});

// Export the component
export default TsApp;

Test your appπŸ”—

  1. Connect your device to the app, authenticate, and load the Liveboard in your mobile app.

    Mobile embed view
    Mobile embed view
    Mobile embed view
  2. Select a data point to drill down on a visualization or apply filters.

  3. Verify the event interactions and workflows.

Known limitationsπŸ”—

The following Liveboard view configuration parameters are not supported in mobile embeds: