feat(admin-ui): members panel, invite links, audit tab and role-aware console

- New MembersPanel: role switching, add/remove members, invite-link
  generation with copy/revoke, pending invite list
- New Audit tab (AuditLog.vue) with group filter
- Role-aware UI: viewer hides route/group edit actions (RouteCard readonly),
  owner-only controls, role badge + member count on group cards
- GroupEditor: members managed via panel, owners field super-admin only
- en/zh i18n and CSS for the new panels
This commit is contained in:
RhenCloud 2026-08-11 23:38:33 +08:00
parent 252f6f181a
commit 11b74aa82a
No known key found for this signature in database
GPG key ID: A574A617378C4E0B
11 changed files with 805 additions and 55 deletions

View file

@ -16,14 +16,45 @@ const en: Dict = {
"login.button": "Sign in with GitHub",
"tab.groups": "Groups",
"tab.logs": "Send Logs",
"tab.audit": "Audit Log",
"status.loading": "loading",
"status.connected": "connected",
"kpi.groups": "GROUPS",
"kpi.routes": "ROUTES",
"role.owner": "Owner",
"role.admin": "Admin",
"role.viewer": "Viewer",
"role.badge": "You: {role}",
"roles.owner": "Owner",
"roles.admin": "Admin",
"roles.viewer": "Viewer",
"members.title": "Members",
"members.note": "(role: owner = full control · admin = edit routes · viewer = read-only)",
"members.empty": "No members yet — add the first owner or share an invite link.",
"members.add": "Add member",
"members.addPlaceholder": "GitHub login",
"members.addBtn": "Add",
"members.role": "Role",
"members.you": "(you)",
"members.remove": "Remove",
"members.invites": "Invite links",
"members.inviteNote": "(single-use · expires in 7 days)",
"members.inviteRole": "Invite as",
"members.createInvite": "Create invite link",
"members.copyLink": "Copy",
"members.copied": "Copied!",
"members.revoke": "Revoke",
"members.noInvites": "No pending invites.",
"members.errSelfOwner": "You must remain an owner of this group.",
"members.errOwner": "A group needs at least one owner.",
"members.errLastOwner": "Cannot remove the last owner.",
"members.inviteOk": "Invite accepted — welcome!",
"members.inviteBad": "This invite is invalid or expired.",
"groups.empty": "No groups yet. Groups scope routes by org/user and delegate access.",
"groups.createFirst": "Create your first group",
"groups.admins": "ADMINS",
"groups.owners": "OWNERS",
"groups.members": "MEMBERS",
"groups.any": "any",
"groups.open": "Open →",
"group.back": "← Groups",
@ -123,9 +154,13 @@ const en: Dict = {
"groupEditor.adminsHint": "These users can view logs and edit this group's routes.",
"groupEditor.owners": "Owner scope",
"groupEditor.ownersNote": "(GitHub org / user logins, comma-separated)",
"groupEditor.ownersSuperOnly": "(only super admins may change)",
"groupEditor.ownersPlaceholder": "my-org, some-user",
"groupEditor.ownersHint":
"Only webhook events from these orgs/users enter this group's routes. Leave empty for no restriction.",
"groupEditor.membersNote": "Members",
"groupEditor.membersHint": "(owner / admin / viewer)",
"groupEditor.membersGoPanel": "Manage members and invite links from the group page.",
"groupEditor.providers": "Source platforms",
"groupEditor.providersNote": "(leave both unchecked = all)",
"groupEditor.providersHint":
@ -162,6 +197,17 @@ const en: Dict = {
"logs.detail": "Extra Info",
"logs.filterGroup": "Group",
"logs.allGroups": "All groups",
"audit.title": "AUDIT LOG",
"audit.empty": "No audit entries yet.",
"audit.time": "Time",
"audit.actor": "Actor",
"audit.action": "Action",
"audit.target": "Target",
"audit.group": "Group",
"audit.detail": "Detail",
"audit.filterGroup": "Group",
"audit.allGroups": "All groups",
"audit.refresh": "⟳ Refresh",
"toast.routesSaved": "Routes saved",
"toast.routeDeleted": "Route deleted",
"toast.groupSaved": "Groups saved",
@ -187,14 +233,43 @@ const zh: Dict = {
"login.button": "使用 GitHub 登录",
"tab.groups": "分组",
"tab.logs": "发送日志",
"tab.audit": "审计日志",
"status.loading": "加载中",
"status.connected": "已连接",
"kpi.groups": "分组",
"kpi.routes": "路由",
"groups.empty": "还没有分组。分组按组织/用户限定路由并委派访问权限。",
"groups.createFirst": "创建第一个分组",
"role.owner": "拥有者",
"role.admin": "管理员",
"role.viewer": "只读",
"role.badge": "我的角色:{role}",
"roles.owner": "拥有者",
"roles.admin": "管理员",
"roles.viewer": "只读",
"members.title": "成员",
"members.note": "角色owner = 完全控制 · admin = 编辑路由 · viewer = 只读)",
"members.empty": "还没有成员 —— 添加第一位 owner 或分享邀请链接。",
"members.add": "添加成员",
"members.addPlaceholder": "GitHub 登录名",
"members.addBtn": "添加",
"members.role": "角色",
"members.you": "(我)",
"members.remove": "移除",
"members.invites": "邀请链接",
"members.inviteNote": "(一次性 · 7 天内有效)",
"members.inviteRole": "邀请为",
"members.createInvite": "生成邀请链接",
"members.copyLink": "复制",
"members.copied": "已复制!",
"members.revoke": "撤销",
"members.noInvites": "暂无待接受的邀请。",
"members.errSelfOwner": "你必须保留本组的 owner 身份。",
"members.errOwner": "分组至少需要一位 owner。",
"members.errLastOwner": "不能移除最后一位 owner。",
"members.inviteOk": "邀请已接受 —— 欢迎!",
"members.inviteBad": "该邀请无效或已过期。",
"groups.admins": "管理员",
"groups.owners": "来源",
"groups.members": "成员",
"groups.any": "任意",
"groups.open": "进入 →",
"group.back": "← 返回分组",
@ -293,9 +368,13 @@ const zh: Dict = {
"groupEditor.adminsHint": "这些用户可以查看日志并编辑本分组的路由。",
"groupEditor.owners": "来源限定",
"groupEditor.ownersNote": "GitHub 组织 / 用户登录名,逗号分隔)",
"groupEditor.ownersSuperOnly": "(仅超级管理员可修改)",
"groupEditor.ownersPlaceholder": "my-org, some-user",
"groupEditor.ownersHint":
"只有来自这些组织/用户的 webhook 事件才会进入本分组的路由。留空表示不限制。",
"groupEditor.membersNote": "成员",
"groupEditor.membersHint": "owner / admin / viewer",
"groupEditor.membersGoPanel": "请在分组页面管理成员与邀请链接。",
"groupEditor.providers": "来源平台",
"groupEditor.providersNote": "(都不勾选 = 全部来源)",
"groupEditor.providersHint":
@ -332,6 +411,17 @@ const zh: Dict = {
"logs.detail": "附加信息",
"logs.filterGroup": "分组",
"logs.allGroups": "全部分组",
"audit.title": "审计日志",
"audit.empty": "暂无审计记录。",
"audit.time": "时间",
"audit.actor": "操作者",
"audit.action": "动作",
"audit.target": "对象",
"audit.group": "分组",
"audit.detail": "详情",
"audit.filterGroup": "分组",
"audit.allGroups": "全部分组",
"audit.refresh": "⟳ 刷新",
"toast.routesSaved": "路由已保存",
"toast.routeDeleted": "路由已删除",
"toast.groupSaved": "分组已保存",