Sprucely title background

Integrasi

Anda dapat mengintegrasikan dasbor Sprucely.io yang interaktif ke situs web atau aplikasi web Anda sendiri dengan tiga cara: dengan menyematkannya menggunakan iframe HTML standar, dengan merendernya secara native menggunakan JavaScript runtime mandiri, atau dengan memasang komponen React mandiri. iframe adalah cara tercepat untuk disiapkan; runtime mandiri menggambar dasbor langsung di halaman Anda dan memungkinkan Anda mendorong data baru saat runtime. Bentuk JSON yang dibaca oleh runtime mandiri - dasbor, chart dan dataset - didokumentasikan dalam referensi format data. Untuk otomatisasi dasbor berbasis AI, lihat bagian MCP API.

Menyematkan Dasbor dalam HTML

Integrasi paling sederhana menggunakan elemen iframe HTML standar dan berfungsi di situs web mana pun, bahkan di halaman HTML lokal. Dasbor perlu dibagikan terlebih dahulu, baik di Cloud maupun On-premise, agar dapat berhasil dimuat. Perlu dicatat bahwa dasbor On-premise hanya akan dimuat ketika klien yang mengaksesnya berada di dalam jaringan korporat yang sama.

Instruksi:

1) Ambil tautan sematan dasbor - Di halaman Dasbor, pastikan dasbor Anda sudah dibagikan lalu klik ikon untuk dasbor ini. Sebuah banner popup hijau akan memberi tahu Anda bahwa tautan telah disalin ke clipboard. Anda akan menggunakan tautan ini untuk mengganti isi src iframe HTML di bawah.

2) Sematkan dasbor dengan ukuran tetap

<html>
  <head>
    <title>Sprucely.io Dashboard</title>
  </head>
  <body>
    <h1>Sprucely.io Dashboard</h1>
    <iframe src="https://www.sprucely.io/service/dashboards/embed/[userId]/[dashboardId]/"
            allow="clipboard-write"
            style="height: 500px; width: 700px;"
            title="Sprucely.io Dashboard"></iframe>
  </body>
</html>

(atau) Sematkan dasbor dengan lebar dinamis - Secara otomatis mengubah ukuran dasbor berdasarkan lebar dokumen induk

Anda dapat menggunakan parameter style aspect-ratio untuk menghitung ulang tinggi secara otomatis berdasarkan lebar.

<html>
  <head>
    <title>Sprucely.io Dashboard</title>
  </head>
  <body>
    <h1>Sprucely.io Dashboard</h1>
    <iframe src="https://www.sprucely.io/service/dashboards/embed/[userId]/[dashboardId]/"
            allow="clipboard-write"
            scrolling="no"
            style="width: 100%; aspect-ratio: 1.5; border: none;"
            title="Sprucely.io Dashboard"></iframe>
  </body>
</html>

3) Opsi sematan lainnya yang berguna

Anda dapat menambahkan modifikasi style kustom ke blok style elemen iframe, untuk menyesuaikan tampilan dan nuansa frame tersebut. Parameter ini mengikuti panduan HTML CSS standar. Contoh di bawah ini menambahkan border abu-abu di sekeliling dasbor:

<html>
  <head>
    <title>Sprucely.io Dashboard</title>
  </head>
  <body>
    <h1>Sprucely.io Dashboard</h1>
    <iframe src="https://www.sprucely.io/service/dashboards/embed/[userId]/[dashboardId]/"
            allow="clipboard-write"
            style="height: 100%; width: 100%; border: 2px solid grey;"
            title="Sprucely.io Dashboard"></iframe>
  </body>
</html>

Menyematkan dengan JavaScript Mandiri

Runtime mandiri merender dasbor langsung di dalam halaman Anda - tanpa iframe. Data Anda dimuat ke dalam database di dalam browser dan digambar sebagai chart yang sepenuhnya interaktif; runtime hanya menghubungi Sprucely.io untuk memvalidasi token akses Anda.

Instruksi:

1) Buat token akses - Di bagian Token Akses pada profil Anda, buat token akses untuk origin tempat halaman Anda disajikan (misalnya https://www.yourdomain.com). Runtime akan memvalidasi bahwa origin halaman yang menyematkan cocok dengan token sebelum merender.

2) Muat runtime dan render dasbor - Tambahkan script runtime ke halaman Anda, hubungkan database di dalam browser sekali dengan sprucely_db, lalu render setiap dasbor dengan sprucely_create. Halaman lengkap di bawah ini juga menghubungkan sebuah tombol yang menambahkan lebih banyak baris:

<html>
  <head>
    <title>Orders Dashboard</title>
  </head>
  <body>
    <div id="database"></div>
    <div id="orders_dashboard"></div>
    <button onclick="addRows()">Add rows</button>

    <script src="https://www.sprucely.io/cross-origin/sprucely-runtime.min.js"></script>
    <script>
      const data = {
        name:    "Orders",
        headers: ["region", "amount", "items"],
        types:   ["VARCHAR", "FLOAT", "INTEGER"],
        entries: [
          ["North", 120.50, 2],
          ["South",  89.95, 1],
          ["North", 432.00, 5],
          ["South",  74.50, 1]
        ]
      };

      const dashboard = {
        config: {
          type: "dashboard",
          style: {
            widget: {
              color: "#667FFF",
              backgroundColor: "#0C0B29",
              primaryColor: "#01EEAE",
              primaryColorSubtle: "#C70584",
              secondaryColor: "#2C2B49"
            }
          }
        },
        data: {
          type: "dash",
          children: [
            {
              type: "dash_stacker_hor",
              children: [
                { type: "dash_chart", datasetId: "Orders", x: "region", chartType: "bar", dataFunction: "count" },
                { type: "dash_chart", datasetId: "Orders", x: "amount", y: "items", chartType: "hexbin", dataFunction: "count" }
              ]
            }
          ]
        }
      };

      sprucely_db({
        id: "database",
        host: "https://www.yourdomain.com",
        accessToken: "YOUR_ACCESS_TOKEN"
      });
      sprucely_create({ id: "orders_dashboard", dashboard, data });

      function addRows() {
        sprucely_add({
          name:    "Orders",
          headers: ["region", "amount", "items"],
          types:   ["VARCHAR", "FLOAT", "INTEGER"],
          entries: [
            ["East", 310.40, 3],
            ["West", 129.95, 1]
          ]
        });
      }
    </script>
  </body>
</html>

3) Tambahkan data saat runtime - Panggil sprucely_add dengan baris tambahan kapan saja. Setiap dasbor yang menggunakan dataset tersebut akan menyegarkan diri secara otomatis:

sprucely_add({
  name:    "Orders",
  headers: ["region", "amount", "items"],
  types:   ["VARCHAR", "FLOAT", "INTEGER"],
  entries: [
    ["East", 310.40, 3],
    ["West", 129.95, 1]
  ]
});

Referensi Fungsi

  • sprucely_db({ id, host, accessToken }) - menghubungkan database di dalam browser dan memvalidasi token akses Anda terhadap origin halaman. Merender sebuah banner status ke dalam elemen yang diidentifikasi oleh id. Panggil sekali per halaman, sebelum membuat dasbor.
  • sprucely_create({ id, dashboard, data }) - merender satu dasbor ke dalam elemen yang diidentifikasi oleh id. Parameter dashboard mendefinisikan layout dan styling; data menyediakan dataset beserta nama, header, tipe kolom (VARCHAR, INTEGER, FLOAT atau TIMESTAMP) dan barisnya - lihat referensi format data.
  • sprucely_add(data) - menambahkan baris ke dataset yang namanya cocok dengan dataset yang sudah dimuat, lalu menyegarkan semua dasbor yang menggunakannya.

Menyematkan dengan React Mandiri

Jika situs Anda dibangun dengan React, Anda dapat merender dasbor sebagai komponen alih-alih memuat script secara manual. Komponen ini menggunakan token akses, definisi dasbor, dan format dataset yang sama seperti runtime JavaScript mandiri.

Instruksi:

1) Buat token akses - Seperti pada JavaScript mandiri, buat token akses untuk origin situs Anda di bagian Token Akses pada profil Anda.

2) Render komponen dasbor - Ambil runtime dari https://www.sprucely.io/cross-origin/sprucely-runtime.min.cjs.js dan tempatkan di proyek Anda. Pasang satu komponen Sprucely.Database per halaman, dan satu komponen Sprucely.Dashboard per dasbor. Dasbor akan menampilkan indikator loading sampai database berhasil memvalidasi token akses, lalu dirender. Aplikasi lengkap di bawah ini merender dua dasbor dari dataset yang terpisah dan menambahkan baris baru ke dasbor pertama setelah lima detik:

// Get https://www.sprucely.io/cross-origin/sprucely-runtime.min.cjs.js
// and place it in your project, next to this file.

import React, { useEffect } from "react";
import { createRoot } from "react-dom/client";
import Sprucely, { sprucely_add } from "./sprucely-runtime.min.cjs.js";

const style = {
  widget: {
    color: "#667FFF",
    backgroundColor: "#0C0B29",
    primaryColor: "#01EEAE",
    primaryColorSubtle: "#C70584",
    secondaryColor: "#2C2B49"
  }
};

const orders = {
  name:    "Orders",
  headers: ["region", "amount", "items"],
  types:   ["VARCHAR", "FLOAT", "INTEGER"],
  entries: [
    ["North", 120.50, 2],
    ["South",  89.95, 1],
    ["North", 432.00, 5],
    ["South",  74.50, 1]
  ]
};

const returns = {
  name:    "Returns",
  headers: ["reason", "amount", "days"],
  types:   ["VARCHAR", "FLOAT", "INTEGER"],
  entries: [
    ["Damaged", 45.00, 3],
    ["Late",    12.50, 8],
    ["Changed", 99.90, 2]
  ]
};

const moreOrders = {
  name:    "Orders",
  headers: ["region", "amount", "items"],
  types:   ["VARCHAR", "FLOAT", "INTEGER"],
  entries: [
    ["East", 310.40, 3],
    ["West", 129.95, 1]
  ]
};

const ordersDashboard = {
  config: { type: "dashboard", style },
  data: {
    type: "dash",
    children: [
      {
        type: "dash_stacker_hor",
        children: [
          { type: "dash_chart", datasetId: "Orders", x: "region", chartType: "bar", dataFunction: "count" },
          { type: "dash_chart", datasetId: "Orders", x: "amount", y: "items", chartType: "hexbin", dataFunction: "count" }
        ]
      }
    ]
  }
};

const returnsDashboard = {
  config: { type: "dashboard", style },
  data: {
    type: "dash",
    children: [
      {
        type: "dash_stacker_hor",
        children: [
          { type: "dash_chart", datasetId: "Returns", x: "amount", y: "days", d: "amount", r: "days", chartType: "dot", dataFunction: "average" }
        ]
      }
    ]
  }
};

const App = () => {
  useEffect(() => {
    const timer = setTimeout(() => { sprucely_add(moreOrders); }, 5000);
    return () => clearTimeout(timer);
  }, []);

  return (
    <>
      <Sprucely.Database host="https://www.yourdomain.com" accessToken="YOUR_ACCESS_TOKEN" />
      <Sprucely.Dashboard id="orders_dashboard" dashboard={ordersDashboard} data={orders} />
      <Sprucely.Dashboard id="returns_dashboard" dashboard={returnsDashboard} data={returns} />
    </>
  );
};

createRoot(document.getElementById("root")).render(<App />);

Menyajikan Token Berumur Pendek

Token akses yang Anda buat di atas berumur panjang dan dimaksudkan untuk tetap menjadi rahasia sisi server. Jika backend Anda sendiri yang menyajikan halaman penyematan - alih-alih halaman yang tidak memiliki backend sendiri - Anda sama sekali tidak perlu menempatkan token berumur panjang tersebut ke dalam halaman - backend Anda dapat menukarnya, dari server ke server, dengan token render berumur pendek (15 menit) tepat sebelum menyajikan setiap halaman, sehingga hanya token render itu yang pernah sampai ke browser. Token render yang diekstrak pengunjung dari halaman hanya berguna selama beberapa menit, bukan untuk selamanya.

Instruksi:

1) Tukar token akses Anda dengan token render - dari backend Anda, panggil POST https://www.sprucely.io/api/auth/render_token dengan token akses Anda sebagai kredensial bearer. Respons membawa token baru, host yang terikat dengannya, dan masa berlakunya dalam detik:

// On your server, immediately before serving each embedding page:
const response = await fetch("https://www.sprucely.io/api/auth/render_token", {
  method:  "POST",
  headers: { Authorization: "Bearer " + process.env.SPRUCELY_ACCESS_TOKEN }
});
const { token, expires_in } = await response.json(); // expires_in: 900 (15 minutes)

// Send only the render token to the browser - never the long-lived access
// token itself:
res.send(`
  <script src="https://www.sprucely.io/cross-origin/sprucely-runtime.min.js"></script>
  <script>
    sprucely_db({
      id: "database",
      host: "https://www.yourdomain.com",
      accessToken: "${token}"
    });
  </script>
`);

2) Sajikan token render ke browser - gunakan persis seperti token akses saat memanggil sprucely_db atau memasang Sprucely.Database. Ulangi pertukaran ini sebelum menyajikan setiap halaman (atau berdasarkan timer jika Anda meng-cache halaman yang dirender), sehingga browser tidak pernah menerima token yang berlaku lebih dari 15 menit.

Referensi Fungsi

  • POST /api/auth/render_token - menukar token akses yang valid, dikirim sebagai Authorization: Bearer <token>, dengan sebuah token render. Mengembalikan { token, host, expires_in } dengan expires_in tetap pada 900 detik. Token render tidak dapat ditukar dengan token render lainnya - hanya token akses berumur panjang yang dapat memintanya.

Pengaturan Keamanan

Jika situs Anda menerapkan Content Security Policy (CSP), integrasi JavaScript dan React mandiri di atas memerlukan beberapa sumber yang diizinkan agar dasbor dapat dimuat - runtime memuat script-nya dari Sprucely.io, membuka database di dalam browser yang didukung oleh WebAssembly, dan memvalidasi token akses Anda terhadap API kami, dan masing-masing itu memerlukan izin CSP yang eksplisit. Jika situs Anda tidak menggunakan CSP, Anda dapat melewati bagian ini.

Tambahkan sumber-sumber berikut ke policy Anda yang sudah ada - ini adalah directive yang perlu digabungkan, bukan policy lengkap untuk menggantikan yang sudah Anda miliki:

script-src   'self' https://www.sprucely.io 'wasm-unsafe-eval';
connect-src  'self' https://www.sprucely.io;
worker-src   'self' blob: https://www.sprucely.io;

Kegunaan masing-masing directive:

  • script-src - https://www.sprucely.io memuat script runtime. 'wasm-unsafe-eval' diperlukan untuk mengompilasi dan menjalankan database di dalam browser, yang dibangun di atas WebAssembly.
  • connect-src - https://www.sprucely.io dihubungi untuk memvalidasi token akses Anda dan untuk memuat file WebAssembly dan worker milik database.
  • worker-src - database di dalam browser menjalankan query-nya pada thread latar belakang, yang dibuat dari URL blob:.

Tidak satu pun di atas memerlukan 'unsafe-inline' - runtime Sprucely sendiri tidak pernah membutuhkannya. Jika Anda menyimpan definisi dasbor dan dataset Anda sendiri dalam tag <script> inline, seperti pada contoh JavaScript mandiri di atas, atau halaman Anda sendiri menggunakan style inline, tambahkan 'unsafe-inline' ke script-src atau style-src atau pertimbangkan CSP nonce.