Sprucely title background

Tích hợp

Bạn có thể tích hợp các dashboard Sprucely.io tương tác vào trang web hoặc ứng dụng web của riêng mình theo ba cách: nhúng bằng phần tử iframe HTML tiêu chuẩn, hiển thị trực tiếp bằng JavaScript runtime độc lập, hoặc gắn các component React độc lập. iframe là cách thiết lập nhanh nhất; các runtime độc lập vẽ dashboard trực tiếp trên trang của bạn và cho phép bạn nạp thêm dữ liệu mới vào runtime bất kỳ lúc nào. Cấu trúc JSON mà các runtime độc lập đọc - dashboard, biểu đồ và dataset - được trình bày trong tài liệu tham khảo định dạng dữ liệu. Để tự động hóa dashboard bằng AI, xem phần MCP API.

Nhúng Dashboard bằng HTML

Cách tích hợp đơn giản nhất sử dụng phần tử iframe HTML tiêu chuẩn và hoạt động trên bất kỳ trang web nào, kể cả các trang HTML cục bộ. Dashboard cần được chia sẻ, dù ở dạng Đám mây hay Tại chỗ, thì mới tải thành công. Lưu ý rằng dashboard Tại chỗ chỉ tải được khi thiết bị truy cập nằm trong cùng mạng nội bộ doanh nghiệp.

Hướng dẫn:

1) Lấy liên kết nhúng của dashboard - Trong trang Bảng điều khiển, đảm bảo dashboard của bạn đã được chia sẻ, sau đó nhấp vào biểu tượng của dashboard này. Một banner màu xanh sẽ hiện lên báo rằng liên kết đã được sao chép vào bộ nhớ tạm. Bạn sẽ dùng liên kết này để thay thế nội dung src của iframe HTML bên dưới.

2) Nhúng dashboard với kích thước cố định

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

(hoặc) Nhúng dashboard với chiều rộng động - Tự động thay đổi kích thước dashboard dựa trên chiều rộng của tài liệu cha

Bạn có thể dùng tham số style aspect-ratio để tự động tính lại chiều cao dựa trên chiều rộng.

<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) Các tùy chọn nhúng hữu ích khác

Bạn có thể thêm các chỉnh sửa style tùy chỉnh vào khối style của phần tử iframe, để tùy chỉnh giao diện và cảm nhận của khung. Các tham số này tuân theo hướng dẫn HTML CSS tiêu chuẩn. Ví dụ bên dưới thêm viền màu xám xung quanh dashboard:

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

Nhúng bằng JavaScript Độc Lập

Runtime độc lập hiển thị dashboard trực tiếp bên trong trang của bạn - không cần iframe. Dữ liệu của bạn được nạp vào một cơ sở dữ liệu trong trình duyệt và vẽ thành các biểu đồ tương tác hoàn chỉnh; runtime chỉ liên hệ với Sprucely.io để xác thực token truy cập của bạn.

Hướng dẫn:

1) Tạo token truy cập - Trong mục Token truy cập của trang hồ sơ, tạo một token truy cập cho origin nơi các trang của bạn được phục vụ (ví dụ https://www.yourdomain.com). Runtime xác thực rằng origin của trang nhúng khớp với token trước khi hiển thị.

2) Nạp runtime và hiển thị dashboard - Thêm script runtime vào trang của bạn, kết nối cơ sở dữ liệu trong trình duyệt một lần bằng sprucely_db, sau đó hiển thị từng dashboard bằng sprucely_create. Trang đầy đủ bên dưới còn gắn thêm một nút để thêm nhiều dòng dữ liệu hơn:

<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) Thêm dữ liệu tại runtime - Gọi sprucely_add với các dòng dữ liệu bổ sung vào bất kỳ lúc nào. Mọi dashboard sử dụng dataset đó sẽ tự động làm mới:

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

Tham chiếu hàm

  • sprucely_db({ id, host, accessToken }) - kết nối cơ sở dữ liệu trong trình duyệt và xác thực token truy cập của bạn theo origin của trang. Hiển thị một banner trạng thái vào phần tử được xác định bởi id. Gọi hàm này một lần cho mỗi trang, trước khi tạo dashboard.
  • sprucely_create({ id, dashboard, data }) - hiển thị một dashboard vào phần tử được xác định bởi id. Tham số dashboard định nghĩa bố cục và định dạng; data cung cấp dataset với tên, tiêu đề cột, kiểu cột (VARCHAR, INTEGER, FLOAT hoặc TIMESTAMP) và các dòng dữ liệu - xem tài liệu tham khảo định dạng dữ liệu.
  • sprucely_add(data) - thêm các dòng dữ liệu vào dataset có tên khớp với một dataset đã được nạp, sau đó làm mới tất cả các dashboard đang sử dụng dataset đó.

Nhúng bằng React Độc Lập

Nếu trang web của bạn được xây dựng bằng React, bạn có thể hiển thị dashboard dưới dạng component thay vì nạp script theo cách thủ công. Các component này dùng chung token truy cập, định nghĩa dashboard và định dạng dataset với runtime JavaScript độc lập.

Hướng dẫn:

1) Tạo token truy cập - Tương tự như với JavaScript độc lập, tạo một token truy cập cho origin của trang web bạn trong mục Token truy cập của trang hồ sơ.

2) Hiển thị các component dashboard - Lấy runtime từ https://www.sprucely.io/cross-origin/sprucely-runtime.min.cjs.js và đặt vào dự án của bạn. Gắn một component Sprucely.Database cho mỗi trang, và một component Sprucely.Dashboard cho mỗi dashboard. Dashboard sẽ hiện chỉ báo đang tải cho đến khi cơ sở dữ liệu xác thực xong token truy cập, rồi mới hiển thị. Ứng dụng đầy đủ bên dưới hiển thị hai dashboard từ hai dataset riêng biệt và thêm các dòng dữ liệu mới vào dashboard đầu tiên sau năm giây:

// 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 />);

Phục Vụ Token Ngắn Hạn

Token truy cập mà bạn tạo ở trên có thời hạn dài và được thiết kế để luôn là một bí mật ở phía server. Nếu chính backend của bạn phục vụ các trang nhúng - chứ không phải một trang không có backend riêng - thì bạn hoàn toàn không cần đưa token có thời hạn dài đó vào trang - backend của bạn có thể trao đổi nó, theo kiểu server-to-server, lấy một token render ngắn hạn (15 phút) ngay trước khi phục vụ mỗi trang, và chỉ token render đó mới đến được trình duyệt. Một token render mà khách truy cập trích xuất được từ trang chỉ hữu dụng trong vài phút, chứ không phải vô thời hạn.

Hướng dẫn:

1) Trao đổi token truy cập của bạn lấy một token render - từ backend của bạn, gọi POST https://www.sprucely.io/api/auth/render_token với token truy cập của bạn làm bearer credential. Phản hồi mang theo token mới, host mà nó bị ràng buộc, và thời hạn sống của nó tính bằng giây:

// 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) Phục vụ token render cho trình duyệt - sử dụng nó y hệt như một token truy cập khi gọi sprucely_db hoặc gắn Sprucely.Database. Lặp lại việc trao đổi trước khi phục vụ mỗi trang (hoặc theo một bộ đếm thời gian nếu bạn cache trang đã render), để trình duyệt không bao giờ nhận được một token có hiệu lực lâu hơn 15 phút.

Tham chiếu hàm

  • POST /api/auth/render_token - trao đổi một token truy cập hợp lệ, được gửi dưới dạng Authorization: Bearer <token>, để lấy một token render. Trả về { token, host, expires_in } với expires_in cố định ở mức 900 giây. Một token render không thể được trao đổi để lấy một token render khác - chỉ token truy cập có thời hạn dài mới có thể yêu cầu một token render.

Cài Đặt Bảo Mật

Nếu trang web của bạn áp dụng Chính sách Bảo mật Nội dung (CSP), các tích hợp JavaScript và React độc lập ở trên cần cho phép một số nguồn trước khi dashboard có thể tải được - runtime nạp script của nó từ Sprucely.io, mở một cơ sở dữ liệu trong trình duyệt chạy trên nền WebAssembly, và xác thực token truy cập của bạn với API của chúng tôi, và mỗi thao tác đó đều cần được cho phép rõ ràng trong CSP. Nếu trang web của bạn không dùng CSP, bạn có thể bỏ qua phần này.

Thêm các nguồn sau vào chính sách hiện có của bạn - đây là các chỉ thị cần hợp nhất vào, không phải một chính sách đầy đủ để thay thế những gì bạn đã có:

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;

Mục đích của từng chỉ thị:

  • script-src - https://www.sprucely.io nạp script runtime. 'wasm-unsafe-eval' là bắt buộc để biên dịch và chạy cơ sở dữ liệu trong trình duyệt, vốn được xây dựng trên nền WebAssembly.
  • connect-src - https://www.sprucely.io được liên hệ để xác thực token truy cập của bạn và để nạp các tệp WebAssembly và worker của cơ sở dữ liệu.
  • worker-src - cơ sở dữ liệu trong trình duyệt chạy các truy vấn của nó trên một luồng nền, được tạo từ một URL blob:.

Không có mục nào ở trên yêu cầu 'unsafe-inline' - bản thân runtime của Sprucely không bao giờ cần đến nó. Nếu bạn giữ định nghĩa dashboard và dataset của riêng mình trong một thẻ <script> nội tuyến, như trong ví dụ JavaScript độc lập ở trên, hoặc trang của bạn dùng inline style, hãy thêm 'unsafe-inline' vào script-src hoặc style-src hoặc cân nhắc dùng CSP nonce.