一个开源的嵌入式分析后台:把 Tableau Cloud / Tableau Server 的工作簿与视图嵌进你自己的产品,同时把多团队、页面级权限、站点用户与计划管理这些「后台该有的东西」一并给你。它是纯前端、可自托管的源码起点,不是带后端的企业平台。

MIT 许可 · v0.13.0 · 纯前端(无后端 / 无数据库) · React 19 + TypeScript 7 + shadcn/ui + TanStack Router

Tableau Embed Plus 的工作区首页:左侧侧边栏包含工作区、Tableau 站点管理、AI 与系统配置,右侧是团队 Dashboard
开箱即用的工作区首页:团队作用域 URL(/t/{slug}/…)、按岗位区分的侧边栏、以及跑在真实 REST 数据上的页面。什么都不配也能跑(内置演示站点)。

一、为什么要做它

把 Tableau 嵌进自己的产品,难点从来不在"放一个 iframe":认证要签 Connected App JWT、REST 接口不给你 CORS、
站点角色和计划任务散在一堆端点里、再加上团队隔离与权限控制——这些东西每个项目都要重写一遍,而且每一条都有坑。

1.1 认证这一步最容易翻车

Connected App 的 JWT 要在浏览器里签发、按分钟级过期刷新、还要按能力域申请最小 scope。

1.2 REST 不支持 CORS

Tableau Cloud 的 REST 没有 ACAO 头、预检直接 405,必须同源反代 —— 但嵌入用的 iframe 又直连 Tableau,两条链路要分清。

1.3 后台该有的都得有

多团队、页面级权限、系统配置、帮助页、组件规范……嵌入式分析只是其中一块。

这个项目就是把这些一次性做掉,并且把"为什么这么做"写在代码注释和文档里。它不是别人的模板 fork,是从零搭的。

二、它是什么样的应用

一个纯前端的 SPA(pnpm build 出来就是静态资源),按"跨团队的管理面"和"团队内的工作区"分两层:

页面

路由

说明

工作区

/t/{slug}/…

Dashboard / Favorites / Recents / Workbooks / Views,数据全部来自你连接的 Tableau 站点

Tableau 站点用户与角色

/t/{slug}/tableau/users

读站点用户(自动翻页)、按关键词/角色筛选、改站点角色(本应用唯一的写操作,二次确认)

定时计划运行情况

/t/{slug}/tableau/schedules

提取刷新任务、后台作业、订阅计划,只读

用户 / 团队 / 权限

/users · /teams · /permissions

角色 × 路由的页面级权限矩阵,一处登记全站生效

系统配置

/config/smtp · /config/login

SMTP 预检、登录页样式与第三方入口的公开参数

组件总览

/components

公共件清单 + 实时预览,新页面照它搭就不会走样

帮助 / 关于

/help

环境自检(当前连的是谁的站点)、版本、第三方版权与商标声明

三、核心能力

3.1 Tableau 嵌入

官方 Embedding API v3,Connected App JWT 在浏览器内签发并定时热更新,不重建视图、不闪烁。

3.2 按能力域拆 scope

内容 / 站点用户 / 计划任务各自一条认证链路,而不是一张全权限令牌;某域 401 或限流不拖累其它页面。

3.3 多团队工作区

团队身份进 URL(/t/{slug}/…),收藏与最近浏览按团队分区,两个标签页可以同时停在两个团队。

3.4 页面级权限

一份路由目录驱动侧边栏、路由守卫与权限矩阵;新页面默认 fail-closed,未登记直接报错拦住。

3.5 站点用户与角色

直接读站点用户表;改角色走同一套 REST,失败按 Tableau 错误码给专属文案(席位不足 / 组内最低角色 / 无效角色)。

3.6 计划运行监控

提取刷新频率说人话、连续失败次数成徽章、后台作业按需展开取对象名(避免逐行 N+1)。

3.7 部署即配

站点绑定全部走 .env,附 nginx 反代样例与 /help 的环境自检卡。

3.8 AI 起点

/ai 是能跑的对话页,provider 一处可换;零配置走内置演示 provider,不配 Key 也不空白。

3.9 i18n 与主题

i18next 词典(当前 en-US)+ 亮/暗/跟随系统三种主题,都在页头可切。

3.10 行为有脚本钉住

类型检查 + 一批真实 Chrome 用例,把类型系统证明不了的行为(路由、权限、落盘)钉死。

四、看看真实界面

在应用内嵌的 Tableau 视图:Executive Overview 仪表板,含地图、KPI 与小型序列图
嵌入真实视图:视图标题、工作簿与收藏都在应用外壳里,嵌入区是官方 tableau-viz 组件直连 Tableau,不经过反代。
Workbooks 页:按工作簿分组的视图卡片列表
Workbooks:工作簿与视图列表走 REST(自动翻页 + 项目过滤),点进去就是嵌入页。
Tableau 站点用户与角色页,含筛选栏与改角色操作
站点用户与角色:这是页面里唯一会写数据的操作。改的是站点级许可证属性,所以不做乐观更新——服务端可能因席位拒绝。图中账号信息已作模糊处理。
定时计划运行情况页:提取刷新任务与后台作业列表
计划运行情况:Tableau Cloud 没有 /schedules 端点(返回 403),所以计划信息从刷新任务内联的 schedule 读——这类"官方接口没承诺"的坑都写在页面说明里。
页面权限矩阵:角色 × 路由的勾选表
页面权限:角色 × 页面的矩阵,侧边栏入口过滤与 URL 直达拦截同时生效。
组件总览页:公共件清单与实时预览
组件总览:每个可复用零件都有 import 路径、用途与可交互预览,新页面照着搭就不会各写各的版面。
帮助页:环境自检卡与第三方版权说明
帮助页:clone 之后第一个问题"我现在连的是谁的站点"由环境自检卡回答;底部是随发行物一起走的第三方版权与商标说明。
登录页模板
登录页模板:三种样式可切、第三方入口参数可配。注意:它是 UI 模板,不拦截页面、不创建会话。

五、技术栈

React 19 · TypeScript 7(原生编译器,next 通道)

Vite 8 · pnpm 12 · Node 24

Tailwind CSS v4 + shadcn/ui(radix-nova 预设)+ Radix UI

TanStack Router(文件路由)· TanStack Query 5 · zustand

i18next 26(当前仅 en-US,词典已为多语言准备好)

官方 Embedding API v3 + REST API 3.23 + Connected App JWT

六、快速开始

git clone https://github.com/tableau-China/Tableau-Embed-Hub.git
cd Tableau-Embed-Hub
pnpm install
pnpm dev

什么都不配也能跑:应用内置演示站点与演示凭据,每个页面都是活的。换自己的站点时只改 .env,不用改代码。

6.1 接上你自己的 Tableau 站点

cp .env.example .env
# 填「站点绑定」三项 + 「Connected App 凭据」三项,然后重新构建

你想改

改哪里

站点(地址 / Site name / 站点内容 URL / 嵌入用户)

VITE_TABLEAU_SERVER_URL · _SITE_NAME · _SITE_CONTENT_URL · _EMBED_USER

Connected App 凭据

VITE_TABLEAU_CLIENT_ID · _SECRET_ID · _SECRET_VALUE

只显示某个项目

VITE_TABLEAU_PROJECT(留空 = 不过滤)

REST 反代路径(要和生产网关一致)

VITE_TABLEAU_API_BASE(默认 /tableau-proxy)

6.2 部署三步

  1. pnpm build,把 dist/ 丢给任意静态托管(CDN / nginx / S3+CDN 均可);
  2. 按仓库里的 nginx 样例,把 /tableau-proxy 反代到你的 Tableau 站点(路径必须和 VITE_TABLEAU_API_BASE 一致);
  3. 在 Connected App 里把生产域名加进 Trusted Sites。

前端是 history 路由,静态托管要配"未命中回退到 index.html"。嵌入用的 iframe 直连 Tableau,不经过反代。

七、工程化:靠脚本而不是靠自觉

类型系统证明不了的行为,这个项目用真实 Chrome 用例钉住——改坏了会当场报错,而不是等上线后被人发现:

命令

它保证什么

pnpm typecheck

类型检查(TS 7 原生编译器)

pnpm test

纯函数用例:权限语义、目录不变量、SMTP 规则、存储迁移

pnpm check:routes

路由文件 ↔ 权限目录一致性(路由守卫是 fail-open 的,漏登记 = 权限盲区)

pnpm check:i18n · check:i18n:keys

词典 key 对齐 + 代码里用到的 key 无遗漏

pnpm check:team-routes

团队 slug 路由与作用域数据分区(16 项浏览器用例)

pnpm check:permissions

权限矩阵与侧边栏顺序(15 项浏览器用例)

pnpm check:smtp · check:login

配置页的校验、落盘与"密码不落盘"(6 + 7 项浏览器用例)

八、许可、合规与边界

这不是官方项目。 与 Salesforce, Inc. 没有隶属、授权或赞助关系;Tableau、Tableau Cloud、Tableau Server 是 Salesforce, Inc. 的商标。 项目名里的 "Tableau" 只是用来说明它集成的是什么产品。
  • 许可:本项目自身代码是 MIT。
  • 第三方:@tableau/embedding-api 适用 Salesforce 的二进制代码许可(不是开源许可);使用者需要自行接受并遵守其条款。其余依赖均为 MIT / ISC / Apache-2.0 一类宽松许可。仓库里的 THIRD-PARTY.md 与 /help 页都列了完整说明。
  • 凭据边界:这是纯前端应用,.env 与内置演示凭据都会被打进构建产物,混淆不构成加密。真正的访问控制依赖 Tableau 后台的 Connected App 域名白名单、访问级别与密钥轮换;要彻底隐藏密钥,必须把 JWT 签发迁到后端。
  • 权限不是安全边界:页面权限控制的是可见性与直达,接入后端后必须由接口再校验一次。

九、和 Vizwise Hub 是什么关系

同一个作者还在 vizwise.cn 上维护着一个商业产品
Vizwise Hub(企业级内容管理与 AI 分析门户)。两者不是「开源版 / 付费版」的关系,
也不是彼此的简化版——架构与交付形态本就不同,只是恰好都在解决"让 Tableau 的内容被更多人真正用起来"这一件事。

维度

Tableau Embed Plus(本仓库)

Vizwise Hub(商业产品)

性质与许可

开源项目,MIT,社区支持(GitHub Issues)

商业产品,付费,官方支持

交付形态

源码 + 静态产物,自己构建、部署与运维

部署即可用的成品平台

架构

纯前端 SPA:无后端、无数据库

前后端 + PostgreSQL 数据仓库 + 服务端任务

安全模型

凭据会进构建产物;页面权限只控制可见性,不作安全边界

接口双重校验;三级角色,数据按团队隔离

能力终点

浏览、嵌入、站点用户与计划只读运行情况

订阅推送、数据仓库元数据与数据字典、AI 自然语言操作、平台运营分析

国际化

词典已就绪,当前仅 en-US

简体 / 繁体 / English 完整翻译

适合谁

单个或少量 Tableau 站点、有前端能力、想自己做外壳或二次开发

中大型企业、多团队治理、要让非 Tableau 用户也能看数与问数

入口

本页 · GitHub 仓库

vizwise.cn/pages/vizwise-hub-overview

十、路线图

  • Phase 0–4 已完成:脚手架与工具链、多团队工作区、Tableau 嵌入与站点管理页、页面级权限、系统配置、AI 起点、部署样例。
  • 进行中:把嵌入 API 改为运行时从使用者自己的 Tableau 站点加载,让仓库与构建产物不再分发 Salesforce 代码。
  • 计划中:TypeScript 7.1 正式版发布后切到稳定版;等上游支持 TS 7 后合并掉现在为 lint 保留的第二份 TypeScript。
  • 可选:SQLite 后端(Drizzle)+ JWT 签发下沉。

Tableau Embed Plus · MIT 许可 ·
仓库:github.com/tableau-China/Tableau-Embed-Hub ·
作者:xilejun

本文配图取自项目实际运行界面(v0.13.0)。其中站点用户页的账号信息已作模糊处理。