Skip to content

feat(teams): always show site-admin banner, add "normal view" toggle - #28

Merged
l5z12 merged 2 commits into
mainfrom
feat/site-admin-team-normal-view
Aug 29, 2026
Merged

feat(teams): always show site-admin banner, add "normal view" toggle#28
l5z12 merged 2 commits into
mainfrom
feat/site-admin-team-normal-view

Conversation

@l5z12

@l5z12 l5z12 commented Aug 29, 2026

Copy link
Copy Markdown
Member

Summary

Two related changes to how site administrators access teams:

  1. Site admins are always elevated on every team — including ones they own by membership. Previously an admin who was the owner-by-membership of a team acted as themselves (no banner, no site_admin audit stamp). Now the override applies uniformly: the team page always shows the "You're here as a site administrator…" banner and every action is stamped site_admin: true.

  2. "Switch to normal view" — the opt-out. A site admin can drop the override for the session and act as their own team membership instead.

How it works

  • Backend (worker/routes/teams.ts): actorFor now honors an X-Prism-Team-View: member request header, suppressing the site-admin override exactly the way a PAT already does. getTeamAuthority no longer special-cases owner-by-membership admins, and gained member_role (the role you'd hold without the override), surfaced as my_member_role on the team-detail response.
  • Client: a session-only Zustand store (src/store/adminView.ts, deliberately not persisted) drives the header through the single request() chokepoint. A page reload returns to the default admin view, so nobody gets locked out of a team they don't belong to.
  • UI (TeamDetail.tsx):
    • The site-admin banner carries a Switch to normal view button — only when my_member_role is set (a real membership to fall back to).
    • A mirror info banner ("viewing as a member…") offers Switch to site admin view.
    • In normal view, opening a team you're not a member of shows a friendly "switch back" prompt instead of a bare 404.

Notes

  • Normal view is a session-wide mode (resets on reload), not per-team — the simplest race-free way to thread the signal through the global client. Every team page shows a banner indicating the current mode, so it's never silent.
  • Docs updated (docs/admin.md, docs/teams.md + docs/zh/ counterparts); en/zh i18n keys added and parity-checked.

Testing

  • `bun run tsc -b` — clean
  • `bun run lint` — clean
  • translation parity check — all keys present across locales

Sourcery 摘要

确保站点管理员的团队访问始终限定在相应站点范围内,同时提供一种清晰且仅限当前会话的方式,以普通团队成员身份进行操作。

新功能:

  • 添加仅限当前会话的普通视图切换功能,使站点管理员能够通过其实际团队成员身份进行操作,并可切换回站点管理员访问权限。
  • 当普通视图隐藏了管理员不属于的团队时,显示明确的团队视图横幅和恢复指引。

错误修复:

  • 对每个团队中的站点管理员统一应用站点管理员权限和审计归因,包括管理员通过成员身份拥有的团队。

增强功能:

  • 显示管理员底层成员身份的角色,以便 UI 仅在适用时提供普通视图。
  • 在 API 请求中传递所选团队视图,并在页面重新加载时重置该视图。

文档:

  • 更新英文和中文的管理员及团队文档,说明统一的站点管理员访问权限和仅限当前会话的普通视图。

杂项:

  • 为新的团队视图消息添加对应的英文和中文翻译。
Original summary in English

Sourcery 总结

统一所有团队中的站点管理员访问权限,同时提供一种明确标示的、仅限当前会话的方式,让管理员以普通团队成员身份进行操作。

新功能:

  • 添加仅限当前会话的普通视图切换功能,使站点管理员能够以其实际团队成员身份进行操作,并切换回站点管理员访问权限。
  • 当普通视图隐藏管理员不属于的团队时,在团队页面显示清晰的操作指引。

错误修复:

  • 统一应用站点管理员权限和审计归属,包括管理员通过成员身份拥有的团队。

增强功能:

  • 显示管理员底层成员身份的角色,以便 UI 仅在适用时提供普通视图。
  • 在 API 请求中传递所选团队视图,并在页面重新加载时重置该视图。

文档:

  • 更新英文和中文的管理员及团队文档,说明统一的站点管理员访问权限和普通视图。

杂项:

  • 添加团队视图相关消息的英文和中文翻译。
Original summary in English

Summary by Sourcery

Unify site-administrator access across all teams while providing a clearly indicated, session-only way to operate as a normal team member.

New Features:

  • Add a session-only normal-view toggle that lets site administrators act through their actual team membership and switch back to site-admin access.
  • Show clear team-page guidance when normal view hides teams the administrator does not belong to.

Bug Fixes:

  • Apply site-admin authority and audit attribution consistently, including on teams the administrator owns through membership.

Enhancements:

  • Expose the administrator’s underlying membership role so the UI can offer normal view only when applicable.
  • Propagate the selected team view with API requests and reset it on page reload.

Documentation:

  • Update English and Chinese administrator and team documentation for unified site-admin access and normal view.

Chores:

  • Add English and Chinese translations for team-view messaging.

…" toggle

A site administrator now holds owner-level authority as the site on every
team, including one they own by membership — previously an owner-by-membership
admin acted as themselves with no banner. The team page always shows the
site-admin banner and every action is stamped `site_admin: true`.

Add "switch to normal view": an opt-out that drops the override for the
session (an `X-Prism-Team-View: member` header suppressed in actorFor the same
way a PAT is), letting an admin act as their own membership instead. It is
session-only and resets on reload, so an admin can't get locked out of a team
they don't belong to. The banner offers the switch only when the admin has a
real membership to fall back to; the mirror banner offers the way back, and a
non-member admin in normal view gets a friendly "switch back" prompt instead
of a bare 404.

Docs (en + zh) and i18n updated.
@sourcery-ai

sourcery-ai Bot commented Aug 29, 2026

Copy link
Copy Markdown

审查者指南

该 PR 统一了所有团队的网站管理员权限提升行为,新增了一个不持久化的会话切换开关,通过发送成员视图请求头来恢复真实的成员权限,并更新团队 UI、翻译和文档,以解释和控制这两种模式。

Sequence diagram for switching site-admin team view

sequenceDiagram
    actor Admin
    participant TeamDetail
    participant AdminViewStore
    participant Request as API_request
    participant TeamsWorker

    Admin->>TeamDetail: Click Switch to normal view
    TeamDetail->>AdminViewStore: setNormalView(true)
    TeamDetail->>Request: invalidateQueries()
    Request->>AdminViewStore: isNormalView()
    Request->>TeamsWorker: Request with X-Prism-Team-View: member
    TeamsWorker->>TeamsWorker: wantsNormalView()
    TeamsWorker->>TeamsWorker: actorFor()
    TeamsWorker-->>Request: Apply real membership authority
    Request-->>TeamDetail: Team detail with my_member_role
Loading

Flow diagram for site-admin and normal team views

flowchart TD
    A[Session-authenticated site admin opens a team] --> B[Default site-admin view]
    B --> C[actorFor grants site-admin authority]
    C --> D[Team response sets site_admin_access and my_member_role]
    D --> E[Show site-admin banner]
    E --> F{Real membership exists?}
    F -- Yes --> G[Switch to normal view]
    G --> H[Send X-Prism-Team-View: member]
    H --> I[Use real membership role and audit identity]
    I --> J[Show member-view banner]
    F -- No --> K[Remain in site-admin view]
    J --> L[Switch to site admin view]
    L --> B
    I --> M{Team membership exists?}
    M -- No --> N[Show switch-back prompt]
    M -- Yes --> J
Loading

文件级变更

变更 详情 文件
使网站管理员权限始终一致地覆盖成员所有权,同时公开底层成员角色以支持回退决策。
  • 解析当前操作主体时,遵循退出请求头。
  • 移除基于成员身份判断所有者的例外情况,确保提升权限的操作始终带有网站管理员标记。
  • 在团队权限和团队详情响应中返回查看者的非提升成员角色。
worker/routes/teams.ts
src/lib/api.ts
添加仅限会话的普通视图模式,并将其传播到所有 API 请求。
  • 添加一个不持久化的 Zustand store,并提供非 hook 访问器。
  • 启用后,由集中式请求客户端附加 X-Prism-Team-View: member。
  • 切换后使查询失效,以刷新权限和团队数据。
src/store/adminView.ts
src/lib/api.ts
src/pages/teams/TeamDetail.tsx
更新团队详情 UI,清晰传达当前权限模式并提供恢复路径。
  • 当存在真实成员身份时,在网站管理员视图和普通视图之间添加切换按钮。
  • 对于普通视图中的非成员管理员,显示切换回去的提示,而不是直接显示 404。
  • 避免在普通视图中重试符合预期的 404 响应。
src/pages/teams/TeamDetail.tsx
src/i18n/en.json
src/i18n/zh.json
使用英文和中文记录统一的网站管理员覆盖行为,以及会话范围内的普通视图行为。
  • 解释成员拥有团队时的网站管理员横幅和审计标记。
  • 记录请求头机制、重新加载后的重置行为以及非成员回退行为。
  • 统一两种语言环境下的团队访问指南。
docs/admin.md
docs/teams.md
docs/zh/admin.md
docs/zh/teams.md

提示和命令

与 Sourcery 交互

  • 触发新的审查: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 根据审查评论生成 GitHub issue: 回复审查评论,请 Sourcery 根据该评论创建 issue。你也可以使用 @sourcery-ai issue 回复审查评论,以根据该评论创建 issue。
  • 生成拉取请求标题: 在拉取请求标题中的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title,以随时生成或重新生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中的任意位置写入 @sourcery-ai summary,即可在你指定的位置随时生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary,以随时生成或重新生成摘要。
  • 生成审查者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时生成或重新生成审查者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这项功能会很有用。
  • 忽略所有 Sourcery 审查: 在拉取请求中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你想从新的审查开始,这项功能尤其有用——别忘了评论 @sourcery-ai review 以触发新的审查!

自定义你的体验

访问你的控制面板以:

  • 启用或停用审查功能,例如 Sourcery 生成的拉取请求摘要、审查者指南等。
  • 更改审查语言。
  • 添加、移除或编辑自定义审查指令。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

The PR makes site-admin elevation uniform across all teams, adds a non-persisted session toggle that sends a member-view header to revert to real membership authority, and updates the team UI, translations, and documentation to explain and control both modes.

Sequence diagram for switching site-admin team view

sequenceDiagram
    actor Admin
    participant TeamDetail
    participant AdminViewStore
    participant Request as API_request
    participant TeamsWorker

    Admin->>TeamDetail: Click Switch to normal view
    TeamDetail->>AdminViewStore: setNormalView(true)
    TeamDetail->>Request: invalidateQueries()
    Request->>AdminViewStore: isNormalView()
    Request->>TeamsWorker: Request with X-Prism-Team-View: member
    TeamsWorker->>TeamsWorker: wantsNormalView()
    TeamsWorker->>TeamsWorker: actorFor()
    TeamsWorker-->>Request: Apply real membership authority
    Request-->>TeamDetail: Team detail with my_member_role
Loading

Flow diagram for site-admin and normal team views

flowchart TD
    A[Session-authenticated site admin opens a team] --> B[Default site-admin view]
    B --> C[actorFor grants site-admin authority]
    C --> D[Team response sets site_admin_access and my_member_role]
    D --> E[Show site-admin banner]
    E --> F{Real membership exists?}
    F -- Yes --> G[Switch to normal view]
    G --> H[Send X-Prism-Team-View: member]
    H --> I[Use real membership role and audit identity]
    I --> J[Show member-view banner]
    F -- No --> K[Remain in site-admin view]
    J --> L[Switch to site admin view]
    L --> B
    I --> M{Team membership exists?}
    M -- No --> N[Show switch-back prompt]
    M -- Yes --> J
Loading

File-Level Changes

Change Details Files
Make site-admin authority consistently override membership ownership, while exposing the underlying membership role for fallback decisions.
  • Honor the opt-out request header when resolving the acting principal.
  • Remove the owner-by-membership exception so elevated actions are always site-stamped.
  • Return the viewer’s non-elevated membership role in team authority and team-detail responses.
worker/routes/teams.ts
src/lib/api.ts
Add a session-only normal-view mode and propagate it through all API requests.
  • Add a non-persisted Zustand store with a non-hook accessor.
  • Attach X-Prism-Team-View: member from the centralized request client when enabled.
  • Invalidate queries after toggling to refresh permissions and team data.
src/store/adminView.ts
src/lib/api.ts
src/pages/teams/TeamDetail.tsx
Update team detail UI to clearly communicate the active authority mode and provide recovery paths.
  • Add switch buttons between site-admin and normal views when a real membership exists.
  • Show a switch-back prompt instead of a bare 404 for non-member admins in normal view.
  • Avoid retrying legitimate 404 responses in normal view.
src/pages/teams/TeamDetail.tsx
src/i18n/en.json
src/i18n/zh.json
Document the uniform site-admin override and session-scoped normal-view behavior in English and Chinese.
  • Explain site-admin banners and audit stamping on member-owned teams.
  • Document the request-header mechanism, reload reset, and non-member fallback behavior.
  • Align team-access guidance across both locales.
docs/admin.md
docs/teams.md
docs/zh/admin.md
docs/zh/teams.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 29, 2026

Copy link
Copy Markdown

Deploying prism-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 611770a
Status: ✅  Deploy successful!
Preview URL: https://56d4baa4.siiway-prism.pages.dev
Branch Preview URL: https://feat-site-admin-team-normal.siiway-prism.pages.dev

View logs

@l5z12
l5z12 deployed to preview August 29, 2026 20:28 — with GitHub Actions Active

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好——我发现了 1 个问题

面向 AI Agent 的提示
请处理本次代码审查中的评论:

## 单条评论

### 评论 1
<location path="src/pages/teams/TeamDetail.tsx" line_range="252" />
<code_context>

-  const { data, isLoading } = useQuery({
+  const { data, isLoading, isError } = useQuery({
     queryKey: ["team", id],
     queryFn: () => api.getTeam(id!),
     enabled: !!id,
+    // In normal view a non-member admin legitimately gets a 404 — don't retry
</code_context>
<issue_to_address>
**issue (broader_impact):** React Query 的缓存键不包含 `normalView`,因此站点管理员模式和成员模式会复用同一个缓存的团队条目。切换模式会使当前查询失效,但在重新获取期间进行导航或渲染时,仍可能显示之前模式下的角色、横幅和管理控件,直到请求完成。

**触发条件:** 管理员切换视图,或在之前模式的团队响应已缓存时在不同团队之间导航。

**建议修复:**`normalView` 包含在团队作用域的查询键中,或者在渲染新模式之前清除/移除相关的缓存条目。

```suggestion
    queryKey: ["team", id, normalView],
```
</issue_to_address>

Sourcery 对开源项目免费——如果你喜欢我们的审查,请考虑分享给他人 ✨
帮助我变得更有用!请对每条评论点击 👍 或 👎,我会利用这些反馈来改进审查结果。
Original comment in English

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/pages/teams/TeamDetail.tsx" line_range="252" />
<code_context>

-  const { data, isLoading } = useQuery({
+  const { data, isLoading, isError } = useQuery({
     queryKey: ["team", id],
     queryFn: () => api.getTeam(id!),
     enabled: !!id,
+    // In normal view a non-member admin legitimately gets a 404 — don't retry
</code_context>
<issue_to_address>
**issue (broader_impact):** The React Query cache key does not include `normalView`, so the same cached team entry is reused for both site-admin and member modes. Switching modes invalidates the active query, but navigation or rendering during the refetch can still display the previous mode's role, banner, and management controls until the request completes.

**Triggers:** When an admin switches views or navigates between teams while a prior-mode team response is cached.

**Suggested fix:** Include `normalView` in the team-scoped query keys, or clear/remove the relevant cached entries before rendering the new mode.

```suggestion
    queryKey: ["team", id, normalView],
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/pages/teams/TeamDetail.tsx Outdated
@github-actions

Copy link
Copy Markdown

Preview deployed: https://prism-preview.siiway.workers.dev (shared preview Worker + database, so the newest PR deploy is what is live there).

…stale UI

Address Sourcery review: the team query cache entry was shared between
site-admin and normal view, so toggling modes (or landing on a team cached in
the other mode) briefly showed the previous mode's role, banner and management
controls until the refetch completed. Include `normalView` in the query key so
each mode has its own entry. Existing `["team", id]` invalidations still match
by prefix, and the server stays authoritative via the request header — this was
a transient display issue only.
@l5z12
l5z12 deployed to preview August 29, 2026 20:33 — with GitHub Actions Active
@l5z12
l5z12 merged commit a65bea6 into main Aug 29, 2026
4 checks passed
@l5z12
l5z12 deleted the feat/site-admin-team-normal-view branch August 29, 2026 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants