Skip to content

feat: batch of small UX optimizations - #29

Merged
wyf9 merged 6 commits into
mainfrom
feat/ui-optimizations
Aug 30, 2026
Merged

feat: batch of small UX optimizations#29
wyf9 merged 6 commits into
mainfrom
feat/ui-optimizations

Conversation

@w9auto

@w9auto w9auto commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

一组小优化,合并为单个 commit。

变更内容

团队横幅

  • 站点管理员"以成员身份查看该团队"的信息横幅右侧新增关闭按钮;关闭后会话内不再显示(切换视图或刷新页面后恢复,与 normal view 本身一致)。

信息框

  • 信息框((i) MessageBar)在合适的地方支持 markdown:新增 MarkdownText 组件(走与用户内容相同的 marked + DOMPurify 管线)。作用域授权的提示(site:*site:team:* 等代码片段)现在正确渲染。
  • 信息框统一:横向 tab 下的提示性信息(团队域名、子团队、身份组,管理面板图片代理)统一改为信息框样式,并适当使用 markdown 增强表现;子团队页原"右侧按钮"移到信息框下方(仍右对齐)。整页标题下的描述不受影响。

管理面板

  • 用户批量选择栏:移除"清除"按钮,改由最左侧原 [i] 图标位置的 X 按钮清除选择。
  • 登录错误:用户代理列显示解析出的浏览器名(复用 parseClient),hover 显示完整 UA。
  • 图片代理:id 完整显示,仅在列宽不足时用 CSS 省略号截断(不再固定 slice(0,12))。

头像点击复制 ID

  • 我的应用(复制 client id)、团队(复制团队 id)、团队成员(复制用户 id,非用户名)、已授权应用(复制 client id)的头像/图标点击即复制,关联账号页除外。

团队应用卡片

  • 应用名称与描述之间换行;没有描述时不再用 client id 顶替。

关联账号

  • 被截断的用户名 / id 在 hover 时通过 Tooltip 显示完整值。

Webhook

  • 应用 webhook 被删除时,先向该 URL 推送一次 webhook.deleted 事件(不受订阅范围限制,停用状态除外),让接收端得知自己被删除。投递记录照常写入。

分页

  • "共 X 项 / 上一页 / 下一页 / 跳转"分页条无论项目多少统一固定在页面内容底部(仍在隐私政策 / 服务条款链接上方)。

验证

  • bun run build(tsc -b + vite build)✓
  • bun run lint
  • bunx tsc -p tsconfig.app.json --noEmit / bunx tsc -p tsconfig.worker.json --noEmit
  • 翻译键校验(zh/en 对齐)✓
  • bun run docs:build

Sourcery 总结

通过更清晰的信息指导、改进标识符处理、更一致的分页方式以及 Webhook 删除通知,优化管理和团队管理体验。

新功能:

  • 为应用、团队、团队成员和已授权应用的头像或图标添加点击复制标识符功能。
  • 在移除活跃 Webhook 之前,发送一条经过签名的最终 webhook.deleted 通知。
  • 支持在信息提示栏中渲染经过清理的 Markdown。
  • 允许管理员在当前会话中关闭普通视图下的团队横幅。

错误修复:

  • 在登录错误日志中显示解析后的浏览器名称,而不是原始用户代理字符串;悬停时仍保留完整值。
  • 使用响应式截断显示完整的图像代理和创建者标识符,而不是固定缩短。
  • 将团队应用描述与应用名称分开显示,并在没有描述时省略客户端 ID。
  • 在已连接账户的工具提示中显示被截断值的完整内容。

改进:

  • 将上下文标签页指导统一为信息提示栏,并将子团队操作重新定位到其指导信息下方。
  • 始终将分页控件固定在页面内容底部。
  • 通过内联关闭控件简化批量用户选择的清除操作。

文档:

  • 在英文和中文 Webhook 文档中记录最终 webhook.deleted 投递行为。
Original summary in English

Sourcery 摘要

通过更清晰的指导、更便捷的标识符处理、一致的分页方式和 Webhook 删除通知,改进团队、管理和集成工作流。

新功能:

  • 为应用、团队、团队成员以及已授权应用的头像或图标添加点击复制标识符操作。
  • 在移除活动 Webhook 前,发送带签名的最终 webhook.deleted 通知。
  • 在信息提示栏中渲染经过清理的 Markdown。
  • 允许管理员在当前会话中关闭普通视图下的团队横幅。

错误修复:

  • 在登录错误记录中显示解析后的浏览器名称,同时在工具提示中保留完整的用户代理信息。
  • 对图片代理和创建者标识符使用响应式截断,而不是固定长度缩短。
  • 将团队应用描述与名称分开显示,并在没有描述时省略客户端 ID。
  • 在已连接账户的工具提示中显示完整的截断值。

改进:

  • 将上下文相关的标签页指导统一为信息提示栏,并将子团队操作移至指导内容下方。
  • 让分页控件与列表页面底部保持对齐。
  • 将批量用户选择的清除按钮替换为行内关闭控件。

文档:

  • 在英文和中文 Webhook 文档中记录最终 webhook.deleted 交付行为。
Original summary in English

Sourcery 摘要

通过提供更清晰的指导、更便捷的标识符处理方式、统一的分页体验和 Webhook 删除通知,改进团队、管理和集成工作流。

新功能:

  • 为应用、团队、团队成员和已授权应用的头像或图标添加点击复制标识符的操作。
  • 在移除活动 Webhook 前,发送带签名的最终 webhook.deleted 通知。
  • 支持在信息提示栏中渲染经过清理的 Markdown。
  • 允许管理员在当前会话中关闭普通视图下的团队横幅。

错误修复:

  • 在登录错误日志中显示解析后的浏览器名称,同时在工具提示中保留完整的用户代理信息。
  • 对图像代理和创建者标识符使用响应式截断,而不是固定长度的缩短方式。
  • 分开显示团队应用描述;当不存在描述时,省略客户端 ID。
  • 在已连接账户的工具提示中显示被截断值的完整内容。

改进:

  • 将上下文相关的选项卡指导统一为信息提示栏,并将子团队操作移至指导内容下方。
  • 使分页控件始终与列表内容底部对齐。
  • 将批量用户选择的清除按钮替换为行内关闭控件。

文档:

  • 在英文和中文 Webhook 文档中记录最终 webhook.deleted 投递行为。
Original summary in English

Sourcery 总结

通过提供更清晰的指导、更便捷的标识符处理方式、统一的分页功能、可搜索的管理员列表以及 Webhook 删除通知,改进行政管理和团队管理工作流。

新功能:

  • 为应用、团队和团队成员添加点击复制标识符功能,并提供无障碍的成功和失败反馈。
  • 在移除活动 Webhook 前发送带签名的最终 webhook.deleted 事件,并记录该事件的投递情况。
  • 支持在信息提示栏中渲染经过清理的 Markdown。
  • 允许管理员在当前会话中关闭普通视图下的团队横幅。
  • 为应用和团队添加管理员搜索功能。

错误修复:

  • 在登录错误记录中显示解析后的浏览器名称,同时在工具提示中保留完整的用户代理信息。
  • 使用响应式截断方式显示图像代理和创建者标识符,替代固定长度的缩写。
  • 单独显示团队应用描述;当不存在描述时,省略客户端 ID。
  • 在已连接账户的工具提示中显示被截断值的完整内容。

改进:

  • 将上下文标签页指导统一为信息提示栏,并将子团队操作移至指导内容下方。
  • 让分页控件始终与列表内容底部对齐。
  • 将批量选择清除按钮替换为行内关闭控件。

文档:

  • 在英文和中文 Webhook 文档中说明带签名的最终 webhook.deleted 事件投递行为。
Original summary in English

Summary by Sourcery

Improve administrative and team-management workflows with clearer guidance, easier identifier handling, consistent pagination, searchable admin lists, and webhook deletion notifications.

New Features:

  • Add click-to-copy identifiers for applications, teams, and team members, with accessible success and failure feedback.
  • Send a signed final webhook.deleted event before removing active webhooks and record the delivery.
  • Support sanitized Markdown rendering in informational message bars.
  • Allow administrators to dismiss the normal-view team banner for the current session.
  • Add administrator search for applications and teams.

Bug Fixes:

  • Show parsed browser names in login error records while retaining the complete user agent in a tooltip.
  • Display image proxy and creator identifiers with responsive truncation instead of fixed shortening.
  • Show team application descriptions separately and omit the client ID when no description exists.
  • Show complete truncated values in connected-account tooltips.

Enhancements:

  • Standardize contextual tab guidance as informational message bars and reposition sub-team actions beneath the guidance.
  • Keep pagination controls aligned to the bottom of list content.
  • Replace the bulk-selection clear button with an inline dismiss control.

Documentation:

  • Document final signed webhook.deleted delivery behavior in English and Chinese webhook documentation.

- The site-admin "viewing as a member" team banner gains a dismiss
  button; dismissal is session-only and resets when the view toggles
- Info bars render markdown (new MarkdownText component): scope grants
  notice, image proxy subtitle, and the team domains / sub-teams /
  groups hints are unified to the info-bar style under horizontal tabs,
  with the sub-teams "create" button moved below the bar (still
  right-aligned)
- Admin users bulk bar: the clear button is replaced by an X taking the
  intent icon's place on the left
- Avatars in My Apps / Teams / Team members / Authorized apps copy the
  app client id / team id / user id on click (new CopyIdTrigger)
- Team app cards: name and description on separate lines; an empty
  description no longer falls back to the client id
- Linked accounts: truncated username / id rows show the full value in
  a tooltip on hover
- App webhooks receive one final `webhook.deleted` delivery before the
  row is removed, so endpoints can learn they were deleted
- Admin login errors: the user-agent column shows the parsed browser
  label; the full UA stays available on hover
- Admin image proxy: ids render in full and truncate with a CSS
  ellipsis only when the column is too narrow
- Pagination bars pin to the bottom of the page content (still above
  the legal footer) regardless of how few items the list holds
@sourcery-ai

sourcery-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

审查者指南

此 PR 汇集了通知、管理表格、标识符交互、团队视图和分页方面的小幅 UX 改进,同时新增了一个删除前的签名 webhook 生命周期事件及相应文档。UI 改动主要引入了可复用的文案/Markdown 组件和基于 flex 的页面布局;后端则会在删除活动 webhook 记录之前发送并记录 webhook.deleted

webhook 删除告别事件投递时序图

sequenceDiagram
    participant Client
    participant API
    participant WebhookEndpoint
    participant Database

    Client->>API: DELETE /api/apps/:appId/webhooks/:webhookId
    API->>Database: SELECT app_webhooks row
    alt webhook is active
        API->>WebhookEndpoint: POST webhook.deleted with signature
        WebhookEndpoint-->>API: HTTP response
        API->>Database: INSERT app_webhook_deliveries
    end
    API->>Database: DELETE app_webhooks row
    API-->>Client: Deletion response
Loading

点击复制标识符交互时序图

sequenceDiagram
    actor User
    participant CopyIdTrigger
    participant Clipboard
    participant UI

    User->>CopyIdTrigger: Click or press Enter/Space on avatar
    CopyIdTrigger->>Clipboard: navigator.clipboard.writeText(id)
    Clipboard-->>CopyIdTrigger: Copy completed
    CopyIdTrigger->>UI: Show copied tooltip
    CopyIdTrigger-->>User: Keep surrounding navigation from firing
Loading

文件级变更

变更 详细信息 文件
统一信息类 UI,并为包含格式或代码片段的通知添加经过清理的 Markdown 渲染。
  • 添加由现有 marked/DOMPurify 流程支持的异步 MarkdownText 组件。
  • 将团队选项卡以及管理页面的图像代理/范围授权描述转换为信息类 MessageBar,同时保留页面标题副标题。
  • 更新修订后通知所使用的本地化字符串。
src/components/MarkdownText.tsx
src/pages/admin/AdminImageProxy.tsx
src/pages/admin/AdminScopeGrants.tsx
src/pages/teams/GroupsTab.tsx
src/pages/teams/TeamDetail.tsx
src/i18n/en.json
src/i18n/zh.json
改进列表页和详情页中复制标识符及查看截断值的交互提示。
  • 将应用、团队、团队成员和已授权应用的头像/图标包装在支持无障碍访问的点击/键盘复制触发器中;该触发器会阻止父级导航,并显示复制成功反馈。
  • 当视觉文本被截断时,通过 Fluent UI 工具提示显示完整的连接标识符和用户名。
  • 将应用描述显示在单独的行中;当描述缺失时,不再显示客户端 ID 作为备用内容。
src/components/CopyIdTrigger.tsx
src/pages/apps/AppList.tsx
src/pages/ConnectedApps.tsx
src/pages/Connections.tsx
src/pages/teams/AppsGrid.tsx
src/pages/teams/MembersTable.tsx
src/pages/teams/TeamList.tsx
将受影响的布局转换为 flex 列布局,使分页始终位于内容区域底部。
  • 让共享布局内容及相关页面/选项卡根元素填充可用的垂直空间。
  • 在 Pagination 上使用自动顶部边距和内边距,使其无论行数多少都保持在页脚链接上方。
src/components/Layout.tsx
src/components/Pagination.tsx
src/components/AuditLog.tsx
src/pages/AuditLogPage.tsx
src/pages/ConnectedApps.tsx
src/pages/Domains.tsx
src/pages/Tokens.tsx
src/pages/admin/AdminApps.tsx
src/pages/admin/AdminConnections.tsx
src/pages/admin/AdminDomains.tsx
src/pages/admin/AdminImageProxy.tsx
src/pages/admin/AdminInvites.tsx
src/pages/admin/AdminLayout.tsx
src/pages/admin/AdminLoginErrors.tsx
src/pages/admin/AdminLogs.tsx
src/pages/admin/AdminNotices.tsx
src/pages/admin/AdminScopeGrants.tsx
src/pages/admin/AdminTeamInvites.tsx
src/pages/admin/AdminTeams.tsx
src/pages/admin/AdminUsers.tsx
src/pages/teams/MembersTable.tsx
src/pages/teams/TeamDetail.tsx
src/pages/apps/AppList.tsx
src/pages/teams/TeamList.tsx
为管理页面普通视图横幅添加会话范围内的关闭状态,并简化批量选择清除操作。
  • 在内存中的管理视图 Zustand store 中记录横幅关闭状态,并在切换普通视图时重置该状态。
  • 为团队普通视图的 MessageBar 添加关闭按钮。
  • 将管理用户页面的清除选择操作移至 MessageBar 图标中,并移除单独的 Clear 按钮。
src/store/adminView.ts
src/pages/teams/TeamDetail.tsx
src/pages/admin/AdminUsers.tsx
通过使用解析后的浏览器名称和响应式标识符截断来优化管理表格展示。
  • 复用 parseClient 来渲染浏览器名称,同时在工具提示中保留完整的用户代理字符串。
  • 将固定的图像代理 ID 截取替换为 CSS 省略号,并通过响应式截断保留完整的创建者 ID。
src/pages/admin/AdminLoginErrors.tsx
src/pages/admin/AdminImageProxy.tsx
在移除活动 webhook 之前发送带签名的最终 webhook.deleted 事件,并记录其生命周期行为。
  • 加载完整的 webhook 记录,解密其密钥,并对活动 hook 投递告别事件,不受订阅情况影响。
  • 在删除 webhook 行之前,将投递结果写入常规投递历史表。
  • 以英文和中文记录端点、载荷、签名行为以及非活动 hook 例外情况。
worker/routes/apps.ts
docs/app-notifications.md
docs/zh/app-notifications.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

This PR packages small UX improvements across notices, admin tables, identifier interactions, team views, and pagination, while also adding a pre-deletion signed webhook lifecycle event with matching documentation. The UI changes primarily introduce reusable copy/Markdown components and flex-based page layouts, and the backend sends and records webhook.deleted before deleting active webhook records.

Sequence diagram for webhook deletion farewell delivery

sequenceDiagram
    participant Client
    participant API
    participant WebhookEndpoint
    participant Database

    Client->>API: DELETE /api/apps/:appId/webhooks/:webhookId
    API->>Database: SELECT app_webhooks row
    alt webhook is active
        API->>WebhookEndpoint: POST webhook.deleted with signature
        WebhookEndpoint-->>API: HTTP response
        API->>Database: INSERT app_webhook_deliveries
    end
    API->>Database: DELETE app_webhooks row
    API-->>Client: Deletion response
Loading

Sequence diagram for click-to-copy identifier interaction

sequenceDiagram
    actor User
    participant CopyIdTrigger
    participant Clipboard
    participant UI

    User->>CopyIdTrigger: Click or press Enter/Space on avatar
    CopyIdTrigger->>Clipboard: navigator.clipboard.writeText(id)
    Clipboard-->>CopyIdTrigger: Copy completed
    CopyIdTrigger->>UI: Show copied tooltip
    CopyIdTrigger-->>User: Keep surrounding navigation from firing
Loading

File-Level Changes

Change Details Files
Standardize informational UI and add sanitized Markdown rendering for notices that contain formatting or code snippets.
  • Add an asynchronous MarkdownText component backed by the existing marked/DOMPurify pipeline.
  • Convert team-tab and admin image-proxy/scope-grant descriptions to informational MessageBars while preserving page-header subtitles.
  • Update localized strings for the revised notices.
src/components/MarkdownText.tsx
src/pages/admin/AdminImageProxy.tsx
src/pages/admin/AdminScopeGrants.tsx
src/pages/teams/GroupsTab.tsx
src/pages/teams/TeamDetail.tsx
src/i18n/en.json
src/i18n/zh.json
Improve list and detail-page interaction affordances for copying identifiers and inspecting truncated values.
  • Wrap app, team, team-member, and authorized-app avatars/icons in an accessible click/keyboard copy trigger that stops parent navigation and shows copied feedback.
  • Show full connection identifiers and usernames in Fluent UI tooltips when visual text is truncated.
  • Display application descriptions on separate lines and omit the client ID fallback when descriptions are absent.
src/components/CopyIdTrigger.tsx
src/pages/apps/AppList.tsx
src/pages/ConnectedApps.tsx
src/pages/Connections.tsx
src/pages/teams/AppsGrid.tsx
src/pages/teams/MembersTable.tsx
src/pages/teams/TeamList.tsx
Keep pagination consistently at the bottom of the content area by converting affected layouts to flex columns.
  • Make the shared layout content and relevant page/tab roots fill available vertical space.
  • Use auto top margins and padding on Pagination so the bar remains above footer links regardless of row count.
src/components/Layout.tsx
src/components/Pagination.tsx
src/components/AuditLog.tsx
src/pages/AuditLogPage.tsx
src/pages/ConnectedApps.tsx
src/pages/Domains.tsx
src/pages/Tokens.tsx
src/pages/admin/AdminApps.tsx
src/pages/admin/AdminConnections.tsx
src/pages/admin/AdminDomains.tsx
src/pages/admin/AdminImageProxy.tsx
src/pages/admin/AdminInvites.tsx
src/pages/admin/AdminLayout.tsx
src/pages/admin/AdminLoginErrors.tsx
src/pages/admin/AdminLogs.tsx
src/pages/admin/AdminNotices.tsx
src/pages/admin/AdminScopeGrants.tsx
src/pages/admin/AdminTeamInvites.tsx
src/pages/admin/AdminTeams.tsx
src/pages/admin/AdminUsers.tsx
src/pages/teams/MembersTable.tsx
src/pages/teams/TeamDetail.tsx
src/pages/apps/AppList.tsx
src/pages/teams/TeamList.tsx
Add session-scoped dismissal for the admin normal-view banner and streamline bulk-selection clearing.
  • Track banner dismissal in the in-memory admin-view Zustand store and reset it when normal view is toggled.
  • Add a dismiss button to the team normal-view MessageBar.
  • Move the admin users clear-selection action into the MessageBar icon and remove the separate Clear button.
src/store/adminView.ts
src/pages/teams/TeamDetail.tsx
src/pages/admin/AdminUsers.tsx
Refine admin table presentation by using parsed browser names and responsive identifier truncation.
  • Reuse parseClient to render browser names while retaining the full user agent in a tooltip.
  • Replace fixed image-proxy ID slicing with CSS ellipsis and preserve full creator IDs with responsive truncation.
src/pages/admin/AdminLoginErrors.tsx
src/pages/admin/AdminImageProxy.tsx
Deliver a signed final webhook.deleted event before removing active webhooks and document the lifecycle behavior.
  • Load the complete webhook record, decrypt its secret, and deliver the farewell event regardless of subscriptions for active hooks.
  • Write the delivery result to the normal delivery-history table before deleting the webhook row.
  • Document the endpoint, payload, signing behavior, and inactive-hook exception in English and Chinese.
worker/routes/apps.ts
docs/app-notifications.md
docs/zh/app-notifications.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 30, 2026

Copy link
Copy Markdown

Deploying prism-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: a157e84
Status: ✅  Deploy successful!
Preview URL: https://e7e68221.siiway-prism.pages.dev
Branch Preview URL: https://feat-ui-optimizations.siiway-prism.pages.dev

View logs

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

嗨——我发现了 3 个问题

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

## 个别评论

### 评论 1
<location path="src/components/MarkdownText.tsx" line_range="45-49" />
<code_context>
+  },
+});
+
+export function MarkdownText({ source }: { source: string }) {
+  const styles = useStyles();
+  const [html, setHtml] = useState("");
+
+  useEffect(() => {
+    let cancelled = false;
+    // renderMarkdown registers any <img> with the image proxy, so it is async.
+    void renderMarkdown(source).then((out) => {
+      if (!cancelled) setHtml(out);
+    });
+    return () => {
+      cancelled = true;
+    };
+  }, [source]);
+
+  return (
+    <span
+      className={styles.body}
+      // Sanitized by renderMarkdown (DOMPurify, conservative allowlist).
+      dangerouslySetInnerHTML={{ __html: html }}
+    />
+  );
</code_context>
<issue_to_address>
**问题 (bug_risk):** MarkdownText 将 `p``ul``pre` 等块级 Markdown 元素渲染在 `<span>` 内部,这属于无效的短语内容标记;浏览器会重新解析或移动这些元素,导致 MessageBar 的布局和样式无法可靠地与渲染后的 Markdown 保持一致。

**触发条件:** 翻译后的信息栏字符串包含段落、列表或其他块级 Markdown 时。

**建议修复:** 将经过清理的 HTML 渲染在 `div` 等块级容器中,或者将 Markdown 输出限制为行内元素。

```suggestion
    <div
      className={styles.body}
      // Sanitized by renderMarkdown (DOMPurify, conservative allowlist).
      dangerouslySetInnerHTML={{ __html: html }}
    />
```
</issue_to_address>

### 评论 2
<location path="src/components/CopyIdTrigger.tsx" line_range="47-50" />
<code_context>
+  const [copied, setCopied] = useState(false);
+
+  const copy = () => {
+    void navigator.clipboard.writeText(id).then(() => {
+      setCopied(true);
+      setTimeout(() => setCopied(false), 1500);
+    });
+  };
+
</code_context>
<issue_to_address>
**问题 (bug_risk):** `navigator.clipboard.writeText(id)` 被拒绝时,其 Promise 会被丢弃,因此剪贴板权限失败或不安全上下文导致的失败会产生未处理的 Promise 拒绝,并使触发器无提示地继续显示未复制成功的状态。

**触发条件:** 浏览器拒绝剪贴板访问,或页面不处于安全的剪贴板上下文中时。

**建议修复:** 捕获拒绝,并显示现有的错误/Toast 反馈,而不是丢弃该错误。
</issue_to_address>

### 评论 3
<location path="src/components/Pagination.tsx" line_range="24-25" />
<code_context>
+    // Pin the bar to the bottom of the page's flex column regardless of how
+    // few rows the list holds; paddingTop keeps the gap when there is no
+    // free space to absorb.
+    marginTop: "auto",
+    paddingTop: "16px",
   },
   pageCount: {
</code_context>
<issue_to_address>
**问题 (bug_risk):** 向分页元素添加 `marginTop: "auto"`,并不能在其父级不是垂直 flex 容器的布局中将分页固定到底部;例如,AdminDatabase 的 `pane``resultMeta` 父级仍是普通布局/行方向的 flex 布局,因此当页面行数较少时,分页仍会紧接在表格之后。

**触发条件:** 在页面或嵌套面板中使用分页,而其父级没有能够垂直扩展的 flex-column 容器时。

**建议修复:** 将所有包含分页的页面/面板设为填满可用内容高度的 flex column,或者将底部固定布局应用在页面容器上,而不仅仅应用于 Pagination。
</issue_to_address>

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

Hey - I've found 3 issues

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

## Individual Comments

### Comment 1
<location path="src/components/MarkdownText.tsx" line_range="45-49" />
<code_context>
+  },
+});
+
+export function MarkdownText({ source }: { source: string }) {
+  const styles = useStyles();
+  const [html, setHtml] = useState("");
+
+  useEffect(() => {
+    let cancelled = false;
+    // renderMarkdown registers any <img> with the image proxy, so it is async.
+    void renderMarkdown(source).then((out) => {
+      if (!cancelled) setHtml(out);
+    });
+    return () => {
+      cancelled = true;
+    };
+  }, [source]);
+
+  return (
+    <span
+      className={styles.body}
+      // Sanitized by renderMarkdown (DOMPurify, conservative allowlist).
+      dangerouslySetInnerHTML={{ __html: html }}
+    />
+  );
</code_context>
<issue_to_address>
**issue (bug_risk):** MarkdownText renders block-level markdown elements such as `p`, `ul`, and `pre` inside a `<span>`, which is invalid phrasing-content markup; the browser reparses or relocates those elements and the MessageBar layout and styles do not reliably match the rendered markdown.

**Triggers:** When a translated info-bar string contains a paragraph, list, or other block-level markdown.

**Suggested fix:** Render the sanitized HTML inside a block container such as a `div`, or restrict the markdown output to inline elements.

```suggestion
    <div
      className={styles.body}
      // Sanitized by renderMarkdown (DOMPurify, conservative allowlist).
      dangerouslySetInnerHTML={{ __html: html }}
    />
```
</issue_to_address>

### Comment 2
<location path="src/components/CopyIdTrigger.tsx" line_range="47-50" />
<code_context>
+  const [copied, setCopied] = useState(false);
+
+  const copy = () => {
+    void navigator.clipboard.writeText(id).then(() => {
+      setCopied(true);
+      setTimeout(() => setCopied(false), 1500);
+    });
+  };
+
</code_context>
<issue_to_address>
**issue (bug_risk):** A rejected `navigator.clipboard.writeText(id)` promise is discarded, so clipboard permission failures or insecure-context failures produce an unhandled promise rejection and leave the trigger silently showing that nothing was copied.

**Triggers:** When the browser denies clipboard access or the page is not in a secure clipboard context.

**Suggested fix:** Catch the rejection and show the existing error/toast feedback instead of discarding it.
</issue_to_address>

### Comment 3
<location path="src/components/Pagination.tsx" line_range="24-25" />
<code_context>
+    // Pin the bar to the bottom of the page's flex column regardless of how
+    // few rows the list holds; paddingTop keeps the gap when there is no
+    // free space to absorb.
+    marginTop: "auto",
+    paddingTop: "16px",
   },
   pageCount: {
</code_context>
<issue_to_address>
**issue (bug_risk):** Adding `marginTop: "auto"` to the pagination element does not pin it to the bottom for layouts whose parent is not a vertical flex container; for example, the AdminDatabase `pane` and `resultMeta` parents remain ordinary/row flex layouts, so pagination still sits immediately after the table when a page has few rows.

**Triggers:** When using pagination in a page or nested pane that has no vertically growing flex-column parent.

**Suggested fix:** Make every pagination-containing page/pane a flex column that fills the available content height, or apply the bottom-pinning layout at the page container rather than only on Pagination.
</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/components/MarkdownText.tsx Outdated
Comment thread src/components/CopyIdTrigger.tsx Outdated
Comment thread src/components/Pagination.tsx
@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).

…db pagination pinning

- MarkdownText renders sanitized markdown in a <div> instead of a <span>;
  block-level output (<p>/<ul>/<pre>) is no longer invalid phrasing content
- CopyIdTrigger catches navigator.clipboard rejections and surfaces a
  "Copy failed" tooltip instead of an unhandled rejection / silent no-op
- AdminDatabase browse pane now fills the content height (flex chain +
  1fr grid row, pane alignSelf:stretch) and pins the row-count/pagination
  bar to the bottom like the other list pages; sidebar stays top-aligned
Same unhandled-rejection / silent-failure pattern as CopyIdTrigger: catch
navigator.clipboard rejections and show a "Copy failed" tooltip (and a
dismiss icon) instead of dropping the error.
w9auto added 3 commits August 30, 2026 20:06
…tros

- MarkdownText forces white-space:normal and overflow-wrap:anywhere so the
  MessageBar body wraps instead of overflowing the viewport (the reflow
  auto-detection ran against the initial empty markup and never re-fired)
- Admin → OAuth Sources: drop the "OAuth Sources" heading and render the
  hint as an info bar to match the rest of the admin surface
- Admin → Notices: intro hint moved into an info bar; the "New notice"
  button moves below it (still right-aligned), following the sub-teams
  pattern from the earlier commit
Matches the pattern already used by Admin → Users: an Input + Search
button toolbar filters the list server-side, resetting to page 1 on
submit. Enter in the input triggers the search.

- worker /admin/apps: accepts ?search=…, LIKE-matches on app name,
  client id, owner username, and team name
- worker /admin/teams: accepts ?search=…, LIKE-matches on team name
  and description
- adminListApps / adminListTeams API clients grow a `search` argument
- Admin → Teams merges the search toolbar with the existing "Create
  team" button so they share the row
- CopyIdTrigger takes an optional `copiedLabel` that flashes on success;
  the four avatar-copy call sites (My Apps, Teams, Team members,
  Authorized apps) each pass a role-specific string, so the confirmation
  says *what* was copied ("Copied team ID") instead of a generic "Copied!"
- Pagination jump input's placeholder becomes "Page" / "页数" — the
  previous "Go to page" / "跳转到页" was truncated inside the narrow
  64-px input, leaving the visible hint identical to the Go button next
  to it. The Go button label and the input's aria-label are unchanged.
@wyf9
wyf9 merged commit ee3e65c into main Aug 30, 2026
4 checks passed
@wyf9
wyf9 deleted the feat/ui-optimizations branch August 31, 2026 02:09
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