ThoughtSpot Everywhere(埋め込み)のチュートリアルをCodeSandboxでやってみた

ThoughtSpotの埋め込み機能であるEverywhere(TSE)のチュートリアルを Web上の開発環境のCodeSandboxを使ってやってみる
2021.05.27

データアナリティクス事業本部、池田です。
ThoughtSpot Everywhere というものがリリースされましたので、 まずはチュートリアルをやってみました。

検索とAIを活用した分析で対話型データアプリを構築するローコードプラットフォーム、ThoughtSpot Everywhereが登場

ThoughtSpot Everywhereは、デベロッパーやプロダクトリーダーが対話型のデータアプリを構築し、検索とAIを活用した分析などのモダンアナリティクスクラウドで利用できるサービスをアプリ、製品、サービスに統合可能な初のローコード埋め込み分析プラットフォームです。

WebアプリにThoughtSpotを埋め込むことができるようですね。

ThoughtSpot Everywhereのリリースと同時に、デベロッパーがThoughtSpotのサービスをテスト・実験するためのデベロッパープレイグラウンドも発表しました。

デベロッパープレイグラウンドについても使用したので、後述します。

デモ動画はいくつかありましたが、個人的には↓が分かりやすかったです。
Build interactive data apps with search-driven analytics

チュートリアル

ThoughtSpot for Developers で公開されている Tutorials がThoughtSpot Everywhere(以下TSE)のチュートリアルのようなのでやってみました。

以下、本章ではチュートリアルの章立てに沿って、ポイントだけコメントしていきます。 (なお、チュートリアルの内容やコードは執筆時点のものなので、必要に応じて適宜読み替えて下さい。)

1. Overview

TSEの埋め込みはVisual Embed SDKというSDKを使ってJavaScript+HTMLで実装します。

このチュートリアルでは使いませんが、 JSについては各種フレームワークが使えるようで、↓Reactを使ったサンプルが公開されています。
ThoughtSpot EverywhereでReactアプリに対話型分析を埋め込む

2. Getting started

このページでは、ThoughtSpotやWebサーバーといった実行環境について説明されています。

今回私は…

の組み合わせで行いました。(動かすだけなら登録なども一切ありませんでした。)
ローカルでなく、CodeSandboxを選んだ理由は最後の節に書きます。


ThoughtSpotをトライアル版でやってみる場合は以前のブログをご覧下さい。
ThoughtSpot Cloudのトライアルを始めてSearch Answersを使ってみた

3. Using the Developer Portal

Developer Portal(ThoughtSpotの「DEVELOP」タブ)について説明されています。 なお、Developer Portalは執筆時点では、ThoughtSpot Cloudのみ(インストール版は未対応)とのことです。

デベロッパープレイグラウンド(Playground)もこの機能の一部のようです。 検索画面や作成したピンボードなどを、 疑似的に埋め込んで見栄えを確認したり、 実際に埋め込みに使用するコードを生成できます。

4. Implementation Steps

ここがメインの工程で、実装を行っています。

GitHub上のコード のうち、 tse_tutorial フォルダだけ使うようです。

index.html

index.html

        <div id='embed'>
        </div>

Visual Embed SDKでは特定のdivタグ(チュートリアルであれば embed というidのdiv)に対して埋め込みを行ってくれるようです。

tse.js

tse.js

const {
  init,
  Action,
  AppEmbed,
  AuthType,
  EmbedEvent,
  Page,
  PinboardEmbed,
  SearchEmbed,
} = tsembed;

init で初期化した後、 検索であれば SearchEmbedピンボードやその一部であれば PinboardEmbedアプリケーションであれば AppEmbed といった部品でそれぞれ生成し、 .render() して描画する流れのようです。 ( ドキュメント

CodeSandbox上での作業

CodeSandbox上では以下のように作業しました。

  1. サンドボックス作成時に、フォルダまで指定してGitHubからインポート

    (↑Forkというのが気になったのですが、この時点ではGitHubにリポジトリが作成されるようなことはありませんでした。たぶん。)

    ↓サンドボックスが作成され、左側にインポートしたファイル群、右側にプレビューが表示されます。

    (↓ちなみに、この段階(GitHubのまま)のコードで画面操作していくと、実装がまだだと言われます。)

  2. チュートリアルの説明に沿って、 tse.js ファイルを編集

    この時、デベロッパープレイグラウンド(Developer Portal)を使って、 設定するデータソースやピンボードのIDなどを取得していきます。

    (↑画像は検索画面の埋め込み時に指定するデータソースのIDを取得しているところ。)

    実際の実装でも、プレイグラウンド上でIDを確認したり表示のオプションをいろいろ設定したりしながら、 アプリ開発していくのだろうなー、と想像しました。


チュートリアルのアプリケーションの埋め込みのところの説明によると…

Using the path attribute lets you go to any location. In particular, this can be good for embedding pinboards vs. the PinboardEmbed. When you use PinboardEmbed you get a limited number of options, for example, you can't make a copy. But if you give a path to the pinboard, you get all available options (that aren't disabled).

とのことで、同じピンボードでも、
PinboardEmbed でピンボード埋め込むと、↓オプションが制限されますが…

AppEmbed でピンボードのページを埋め込むと、↓選べるオプションなどが増えるようです。

(↑どうでも良いですが、 index.html をいじって左上のロゴを弊社のものにしてみました。)

この辺は使い分けが必要そうですね。


今回のチュートリアルで実装した tse.js コードが↓です。

クリックでコードを表示する/折りたたむ

(★のコメントしている部分が、GitHubからの変更箇所です。)

tse.js

/*
 * This is the script to update for the ThoughtSpot Everywhere tutorial.
 */
import { ActionData, tabularDataToHTML } from "./dataclasses.js";

const {
  init,
  Action,
  AppEmbed,
  AuthType,
  EmbedEvent,
  Page,
  PinboardEmbed,
  SearchEmbed
} = tsembed;

const tsURL = "https://try-everywhere.thoughtspot.cloud"; // ★

// functions to show and hide div sections.
const showDiv = (divId) => {
  const div = document.getElementById(divId);
  div.style.display = "flex";
};

const hideDiv = (divId) => {
  const div = document.getElementById(divId);
  div.style.display = "none";
};

const clearEmbed = () => {
  const div = document.getElementById("embed");
  div.innerHTML = "";
};

const closeModal = () => {
  const showDataElement = document.getElementById("show-data");
  showDataElement.style.display = "none"; // hide the box.
};

const showData = (payload) => {
  // TODO - add code to handle the custom action callback.
};

// Create and manage the login screen.

const onLogin = () => {
  // The following can be used if you want to use AuthType.Basic
  //const username = document.getElementById('username').value;
  //const password = document.getElementById('password').value;

  // ★~
  init({
    thoughtSpotHost: tsURL,
    authType: AuthType.None
  });
  // ~★

  hideDiv("login");
  showDiv("landing-page");
};

const showMainApp = () => {
  // Clears out the page and shows the main app.
  // This can be called from any page to make sure the state is correct.
  clearEmbed(); // just to be sure.
  hideDiv("landing-page");
  showDiv("main-app");
};

// Functions to embed the content based on user selection.

const onSearch = () => {
  showMainApp();

  // ★~
  const embed = new SearchEmbed("#embed", {
    frameParams: {},
    dataSources: ["cd252e5c-b552-49a8-821d-3eadaa049cca"],
    disabledActions: [Action.SpotIQAnalyze],
    disabledActionReason: "Enterprise feature.",
    hiddenActions: [Action.Download, Action.Share, Action.DownloadAsCsv]
  });

  embed.render();
  // ~★
};

const onVisualization = () => {
  showMainApp();

  // ★~
  const embed = new PinboardEmbed("#embed", {
    frameParams: {},
    pinboardId: "66f5bf76-b0a9-40b4-94b3-a93a7180c1da",
    vizId: "92e2a902-ec53-422a-83e1-9b125cc0cc5e",
    disabledActions: [Action.Download],
    disabledActionReason: "Enterprise feature.",
    hiddenActions: [Action.SpotIQAnalyze]
  });

  embed.render();
  // ~★
};

const onPinboard = () => {
  showMainApp();

  // ★~
  const embed = new PinboardEmbed("#embed", {
    frameParams: {},
    pinboardId: "543619d6-0015-4667-b257-eff547d13a12",
    disabledActions: [Action.DownloadAsPdf],
    disabledActionReason: "Enterprise feature.",
    hiddenActions: [Action.PinboardInfo]
  });

  embed.render();
  // ~★
};

// Embed the full application.
const onFull = () => {
  showMainApp();

  // ★~
  const embed = new AppEmbed("#embed", {
    frameParams: {},
    // pageId: Page.Home // loads the Home tab.  Others can be loaded.  See Page enum.
    path: "pinboard/543619d6-0015-4667-b257-eff547d13a12" // loads the Home tab.  Others can be loaded.  See Page enum.
  });

  embed.render();
  // ~★
};

export { onLogin, onFull, onSearch, onPinboard, onVisualization };

// Show the URL to connect to.
document.getElementById("ts-url").innerText = "ThoughtSpot Server: " + tsURL;

// Hook up the events to the buttons and links.
document.getElementById("login-button").addEventListener("click", onLogin);
document.getElementById("close-modal").addEventListener("click", closeModal);

// Events for buttons
document.getElementById("search-button").addEventListener("click", onSearch);
document
  .getElementById("pinboard-button")
  .addEventListener("click", onPinboard);
document
  .getElementById("viz-button")
  .addEventListener("click", onVisualization);
document.getElementById("full-app-button").addEventListener("click", onFull);

// Events for nav bar
document.getElementById("search-link").addEventListener("click", onSearch);
document.getElementById("pinboard-link").addEventListener("click", onPinboard);
document
  .getElementById("visualization-link")
  .addEventListener("click", onVisualization);
document
  .getElementById("full-application-link")
  .addEventListener("click", onFull);

↓CodeSandboxだとこんな感じ。
codesandbox.io 】 ※アプリ動かせます

5. Conclusion

細かいことは ドキュメント を読めとのこと。

6. Appendix A: Development Environment

ここではChromeのデバッグについて教えてくれています。親切!

7. Appendix B: Security Settings

ここでは、セキュリティ(CSP・CORS)設定について説明があります。

Developer Portal(「DEVELOP」タブ)で設定ができるみたいですね。

今回、CodeSandboxでやってみた理由ですが、 使用した公開されている環境の developers.thoughtspot.com/tryCSP の制限でlocalhostで使えなかったからです。 (ブログにCodeSandboxを埋め込むこともできませんでした…)
ローカル環境で試したい方はThoughtSpot Cloudのトライアルで試してみて下さい。

おわりに

TSEでThoughtSpotの活用の幅が広がりそうですね。 デベロッパープレイグラウンドも重要な機能そうです。

CodeSandboxも便利でした。 私はフレームワークをあまり使ったことが無いのですが、よく使う方はもっと嬉しいのですかね。

関連情報/参考にさせていただいたページ