基于 fx 与用户组(Groups)在 ToolJet 中条件显示组件
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
本文为技术文章,基于仓库文档 conditionally-display-components.md 编写,并结合仓库源码进行深度扩充。
ToolJet 条件显示组件实战:利用 fx 表达式与用户组(Groups)实现按角色动态渲染 UI
当同一个 ToolJet 应用需要被多个用户组(如 Manager、普通员工)同时访问时,往往需要"同一份应用、不同的人看到不同的界面"——例如审批按钮只对管理者可见、编辑入口只对管理员开放。本文基于 ToolJet 的Visibility 属性 + fx 表达式 + 用户组(Groups)机制,完整演示如何让组件按登录用户的所属组条件显示。读完本文,你将掌握globals.currentUser全局对象的用法、组判断表达式的写法,并能用同样的逻辑实现多组判断、角色判断以及整块区域的条件渲染。
场景背景:为什么需要按组控制组件可见性
ToolJet 应用默认对同一工作区内的成员可见,但不同成员的角色与职责可能差异巨大。以文档示例中的"员工请假管理"应用为例:
- 普通员工:只能查看自己的请假记录、提交请求;
- Manager 组:除了查看,还需要看到
Approve Selected(批量审批)按钮来执行审批操作。
如果让所有人看到审批按钮,普通员工会看到无法使用的功能;如果隐藏按钮,Manager 又无法操作。此时就需要根据当前登录用户的所属用户组来动态决定组件是否渲染。
文档中给出的目标非常明确:
在这个应用中,
Approve Selected按钮只应在Manager组的成员访问应用时显示。
下面这张图展示了应用未加任何条件时的初始界面(表格列出了多条请假记录,右下角有Approve Selected按钮):
前置知识:ToolJet 中的用户组(Groups)与全局变量
在动手之前,先建立两个关键概念。
1. 用户组(Groups)
ToolJet 中的"组"是工作区层面的权限集合。从后端源码看,每个组织(Organization)维护一组GroupPermissions实体,getAllGroupByOrganization会按organizationId查询全部组(见 server/src/modules/group-permissions/util.service.ts);邀请新用户时,后端会把用户加入指定组,并将组名汇总为groupsArray(见 server/src/modules/organization-users/util.service.ts)。
这意味着"当前用户属于哪些组"是登录会话中就已确定的运行时数据,前端应用可以直接读取,无需额外查询接口。
2.globals全局对象与currentUser
ToolJet 在前端维护一个名为globals的全局运行时对象,应用中的所有表达式(fx)都可以通过{{ }}语法访问它。其中currentUser是当前登录用户信息的集合。
从源码可以确认currentUser的结构与填充逻辑。在 frontend/src/AppBuilder/_hooks/useAppData.js 中,前端通过setResolvedGlobals('currentUser', {...})注入用户数据:
setResolvedGlobals( 'currentUser', { ...user, groups: currentSession?.groups, role: currentSession?.role?.name, ssoUserInfo: currentSession?.ssoUserInfo, ...(currentSession?.currentUser?.metadata && !isEmpty(currentSession?.currentUser?.metadata) ? { metadata: currentSession?.currentUser?.metadata } : {}), }, moduleId );由此可以确认globals.currentUser至少包含以下字段:
| 字段 | 说明 |
|---|---|
groups | 当前用户所属的全部组名数组,如["@allusers", "@admin", "Managers"] |
role | 当前用户在当前工作区的角色名称 |
ssoUserInfo | 通过 SSO 登录时返回的用户信息(如 OIDC 用户属性) |
metadata | 用户元数据(若存在) |
| 其他用户基础字段 | 用户名、邮箱、头像等 |
关键点:groups是一个字符串数组,因此可以直接调用 JavaScript 数组的.includes()方法判断用户是否属于某个组——这正是本文核心表达式的原理基础。
实操步骤:为按钮设置基于用户组的 Visibility
下面按文档步骤,为一个具体按钮(Approve Selected)配置条件可见性。
第 1 步:选中目标组件
在应用编辑器中,点击画布上的Approve Selected按钮组件,使其被选中。选中后右侧属性面板会显示该组件(如button1)的所有可配置属性。
第 2 步:定位 Visibility 属性
在右侧属性面板中,找到Visibility(可见性)属性。这是 ToolJet 所有组件通用的内置属性之一。从组件定义源码可以看到,Button 组件的visibility是一个布尔类型的校验字段(validation: { schema: { type: 'boolean' } }),并且默认值为{{true}},即默认总是可见(见 frontend/src/AppBuilder/WidgetManager/widgets/button.js)。
第 3 步:打开 fx 表达式编辑器
Visibility 输入框右侧有一个fx切换按钮。点击它,输入框会从"静态开关"切换为"表达式模式",允许你输入一段以{{ }}包裹的 JavaScript 表达式。fx 表达式在应用运行时求值,其结果(布尔值)决定组件是否渲染。
第 4 步:输入组判断表达式
在 fx 输入框中粘贴以下代码:
{{globals.currentUser.groups.includes('Manager')}}下图展示了该表达式在 Button 组件 Visibility 属性中的实际填写效果:
表达式解读:
globals.currentUser.groups:当前登录用户的组名数组;.includes('Manager'):判断数组中是否包含字符串'Manager';- 整体结果:用户属于 Manager 组时返回
true(显示按钮),否则返回false(隐藏按钮)。
注意:表达式中的组名必须与工作区中实际创建的组名完全一致(区分大小写)。文档正文中写法为
'Manager',而配套截图中出现的是'Managers',实际使用时请以你在工作区中创建的组名为准。
效果验证:不同组用户看到不同界面
保存并发布应用后,分别用不同组的账号登录预览,验证条件渲染效果。
非 Manager 用户的视角
普通员工登录后,globals.currentUser.groups中不包含Manager组,表达式求值为false,因此Approve Selected按钮被隐藏。从预览界面的 Inspector 面板可以看到,该用户groups中只有@allusers、@admin等默认组:
Manager 用户的视角
Manager 组成员登录后,表达式求值为true,Approve Selected按钮正常显示,可以进行批量审批操作:
对比两张截图可以直观看到:表格、查看按钮等公共组件对所有人可见,而审批按钮仅对 Manager 组可见——这就是"同一应用、按组差异化渲染"的效果。
进阶扩展:更多条件显示场景
文档明确指出,这套逻辑可以轻松迁移到更多场景。以下是在仓库能力范围内可直接套用的几种写法。
1. 整块区域的条件显示:使用 Container 组件
如果需要对"一组组件"(表单、卡片、操作栏等)统一控制可见性,不必给每个组件单独配置表达式。将相关组件全部拖入一个Container容器组件中,然后只对容器设置 Visibility 表达式即可——容器内所有组件会跟随容器一起显示或隐藏。
{{globals.currentUser.groups.includes('Managers')}}2. 多组判断:任一组成员可见
使用 JavaScript 的||运算符组合多个组判断:
{{globals.currentUser.groups.includes('Managers') || globals.currentUser.groups.includes('Admins')}}3. 基于角色的判断
如果不需要精确到组,也可以基于role字段判断:
{{globals.currentUser.role === 'admin'}}4. 反选:排除某些组
使用!取反,例如"非 HR 组的用户隐藏离职办理入口":
{{!globals.currentUser.groups.includes('HR')}}5. 与业务数据联动
fx 表达式的求值环境是完整的运行时,可以结合组件值、查询结果等。例如"只有选择了行记录时审批按钮才可见":
{{globals.currentUser.groups.includes('Managers') && table1.selectedRow !== undefined}}原理深挖:Visibility 条件在 ToolJet 中如何工作
理解底层机制有助于写出更可靠的表达式。
1. 求值引擎:{{ }}表达式
ToolJet 的属性值支持静态值与动态表达式两种形态,{{ }}包裹的内容会被解析为 JavaScript 表达式在运行时求值。Visibility 属性要求布尔值,因此表达式的最终结果必须是true/false。
2.globals.currentUser的来源
前面已经看到,currentUser由前端在应用数据加载阶段通过setResolvedGlobals('currentUser', {...})注入全局状态(见 frontend/src/AppBuilder/_hooks/useAppData.js)。其中groups直接取自currentSession?.groups,即后端在用户会话中返回的组列表——会话建立时已确定,因此同一登录用户在应用内各处的组判断结果是一致的。
此外,在 frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js 中可以看到,代码提示(hint)机制对globals.currentUser开头的表达式有专门处理(自动映射到服务端用户上下文),说明globals.currentUser是框架层一等公民级别的全局变量,可放心在任意组件的 fx 表达式中使用。
3. 组件默认可见性
绝大多数组件的visibility默认值都是{{true}}(如 Button、TagsInput、Accordion、AudioRecorder 等,见 frontend/src/AppBuilder/WidgetManager/widgets/button.js 等组件定义)。这意味着不配置 Visibility 的组件对所有登录用户可见;只有当你显式写入条件表达式时,才产生差异化显示。
4. 组数据由后端维护
组本身由工作区管理员在用户管理中创建和维护。后端在邀请用户、管理组织成员时都会维护用户与组的关系(见 server/src/modules/group-permissions/util.service.ts 与 server/src/modules/organization-users/util.service.ts)。因此本文方案本质上是"后端会话中的组信息 → 前端全局对象 → 组件属性表达式"的完整链路,无需自行存储权限状态。
注意事项与最佳实践
- 组名大小写敏感:
includes('Manager')与组内实际名称必须逐字符一致,建议先在用户管理页面确认组名; - 未登录/公开访问场景:如果应用以公开链接访问,
currentUser的groups可能为空或不包含业务组,条件表达式会自然返回false(组件隐藏),请在设计公开页面时留意; - 优先用 Container 批量控制:涉及多个组件的组级可见性需求,优先容器方案,避免在多个组件上重复维护同一表达式;
- 可见性 ≠ 安全权限:Visibility 控制的是"显示/隐藏",属于 UI 层体验优化;对审批、删除等敏感操作,仍应在服务端通过查询权限、组件权限(如 server/src/modules/app-permissions/repositories/component-users.repository.ts 所管理的组件级权限)等机制做真正的访问控制;
- 表达式保持简洁:复杂逻辑建议拆解为多个布尔表达式或借助查询/变量预处理,便于维护与调试。
总结
本文从 ToolJet 文档中的经典场景出发,完整实现了"按用户组条件显示组件":
- 在组件属性面板中找到Visibility属性;
- 点击fx切换到表达式模式;
- 输入
{{globals.currentUser.groups.includes('Manager')}}; - 保存发布后,不同组的用户看到差异化界面。
其底层依赖的是前端全局对象globals.currentUser(含groups、role等会话数据)与全组件通用的布尔型visibility属性(默认{{true}})。同样的思路可以扩展到多组判断、角色判断、Container 整块区域控制以及与业务数据联动的组合条件,让一份应用在多个用户群体之间优雅地"千人千面"。
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考