refactor(channel): 重构团队功能模块#770
Conversation
📝 WalkthroughWalkthrough本次变更扩展团队成员详情、任务与消息跳转、角色编辑、在线状态统计和 Host 关注展示;TeamTabs 收敛为两个页签,并更新弹层、完成项、文案、样式及测试隔离逻辑,同时移除 CLI 测试中的墙钟耗时断言。 Changes团队拓扑与任务工作流
页签、焦点与支持改动
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant ChannelPage
participant AgentBoardPanel
participant AgentDetailPanel
participant TaskOrMessageView
ChannelPage->>AgentBoardPanel: 渲染成员状态、任务和消息入口
AgentBoardPanel->>AgentDetailPanel: 打开成员详情
AgentDetailPanel->>ChannelPage: 请求打开任务或消息
ChannelPage->>TaskOrMessageView: 打开任务 ID 或消息 seq
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Explore these optional code suggestions:
|
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/components/ChannelFocusPanel.tsx`:
- Around line 63-68: 不要用 ChannelFocusPanel 中的 children == null
判断补充内容是否实际存在;改为由父组件传入并使用明确的 hasSupplementalContent 状态,或在没有 Host 内容时传入
null,同时保持现有空状态条件。同步更新 web/src/components/ChannelFocusPanel.test.tsx
第99-114行附近的测试,加入返回 null 的 supplemental 子组件并断言 focus.items 为空时仍显示空状态。
In `@web/src/i18n/strings/Channel.ts`:
- Line 545: Update the Chinese translation for Channel.tools.timeline from “消息”
to “时间线”, keeping the corresponding English Timeline meaning synchronized.
In `@web/src/i18n/strings/ChannelFocusBar.ts`:
- Line 24: Update the ChannelFocusBar.hostSummary translation to handle
attention counts correctly, displaying singular “alert” when attention is 1 and
plural “alerts” otherwise, using the project’s established i18n pluralization
pattern if available.
In `@web/src/pages/Channel.tsx`:
- Around line 2066-2080: 更新 Channel.tsx 中工作项和任务项的 aria-label,移除直接拼接的编号与标题,改为复用
AgentDetailModal 使用的 i18n 文案键 AgentDetailModal.openMessage 和
AgentDetailModal.openTask,并传入对应的 work.seq/work.summary 或 task.id/task.title
参数;同步确认英文和中文翻译键均已覆盖。
- Around line 946-950: Replace the aria-label translations in the role-live-dot
markup with member-specific keys, using Channel.team.member.online and
Channel.team.member.offline without a count parameter. Add both keys to the
English and Chinese Channel i18n strings in web/src/i18n/strings/Channel.ts,
preserving the existing team badge keys for aggregate counts.
In `@web/src/pages/CompletionPanel.test.tsx`:
- Around line 51-56: 在 CompletionPanel 测试的 afterEach 中补充清理被覆盖的全局
localStorage,使用与 AgentBoardPanel.test.tsx 一致的 Reflect.deleteProperty 方式,并保留现有
renderer 卸载逻辑,确保每个测试后全局属性均被还原。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b6808f30-2511-427c-b7d5-1a1f6113f632
📒 Files selected for processing (23)
cli/test/watch.test.tsweb/src/components/AgentDetailModal.test.tsxweb/src/components/AgentDetailModal.tsxweb/src/components/AgentJoin.test.tsxweb/src/components/AgentTokens.copypack.test.tsxweb/src/components/ChannelFocusBar.test.tsxweb/src/components/ChannelFocusBar.tsxweb/src/components/ChannelFocusPanel.test.tsxweb/src/components/ChannelFocusPanel.tsxweb/src/components/OrgTreePreview.tsxweb/src/components/TeamTabs.test.tsxweb/src/components/TeamTabs.tsxweb/src/i18n/strings/AgentDetailModal.tsweb/src/i18n/strings/Channel.i18n.source.test.tsweb/src/i18n/strings/Channel.tsweb/src/i18n/strings/ChannelFocusBar.tsweb/src/lib/divisionCharter.tsweb/src/pages/AgentBoardPanel.test.tsxweb/src/pages/Channel.tsxweb/src/pages/ChannelTeamRoute.test.tsxweb/src/pages/CompletionPanel.test.tsxweb/src/pages/DivisionBoard.test.tsxweb/src/styles/app.css
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
web/src/pages/DivisionBoard.test.tsx (1)
91-101: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win统一恢复测试期间修改的
IS_REACT_ACT_ENVIRONMENT。三个测试文件都在
beforeEach覆盖同一个全局属性,但只清理了localStorage;Bun 复用进程时会把该状态泄漏到后续测试。
web/src/pages/DivisionBoard.test.tsx#L91-L101:保存并恢复该属性的原始 descriptor。web/src/pages/AgentBoardPanel.test.tsx#L71-L79:保存并恢复该属性的原始 descriptor。web/src/pages/CompletionPanel.test.tsx#L46-L57:保存并恢复该属性的原始 descriptor。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/pages/DivisionBoard.test.tsx` around lines 91 - 101, 保存并恢复测试期间修改的 IS_REACT_ACT_ENVIRONMENT 原始 property descriptor。在 web/src/pages/DivisionBoard.test.tsx 的 91-101、web/src/pages/AgentBoardPanel.test.tsx 的 71-79,以及 web/src/pages/CompletionPanel.test.tsx 的 46-57 中,于 beforeEach 覆盖前记录 descriptor,并在对应 afterEach 中恢复它,同时保留现有 localStorage 清理和 renderer 卸载逻辑。web/src/pages/Channel.tsx (1)
469-483: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift让
teamRoleBuckets与 Team 统计共享完整 roster。
ChannelPage的authoritativeMemberNames/在线统计包含state.participants,但这里的投影只接收presence与identities。因此,仅存在于当前连接列表、尚未产生 presence/identity 记录的成员会被 Team 头部计数,却不会出现在 DivisionBoard 或未分工数量中。请把 participants(或已计算的 authoritative member set)纳入该投影,并补充 participant-only 回归测试;AgentBoardPanel.test.tsxLine 224-230 已证明该状态可达。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/pages/Channel.tsx` around lines 469 - 483, 扩展 teamRoleBuckets 及其调用链,接收并使用 state.participants 或已计算的 authoritative member set,确保仅存在于 participants、尚无 presence/identity 记录的成员也进入 selfReported/unassigned 投影及 Team 统计。保持现有 presence/identity 处理不变,并补充 participant-only 回归测试覆盖该成员出现在 DivisionBoard 或未分工数量中的行为。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/pages/Channel.tsx`:
- Around line 947-950: 在 Channel 组件中更新表示成员在线状态的 role-live-dot span,为其添加支持
aria-label 的可访问语义角色(优先使用 role="img"),同时保留现有 className 和在线/离线 aria-label 逻辑。
---
Outside diff comments:
In `@web/src/pages/Channel.tsx`:
- Around line 469-483: 扩展 teamRoleBuckets 及其调用链,接收并使用 state.participants 或已计算的
authoritative member set,确保仅存在于 participants、尚无 presence/identity 记录的成员也进入
selfReported/unassigned 投影及 Team 统计。保持现有 presence/identity 处理不变,并补充
participant-only 回归测试覆盖该成员出现在 DivisionBoard 或未分工数量中的行为。
In `@web/src/pages/DivisionBoard.test.tsx`:
- Around line 91-101: 保存并恢复测试期间修改的 IS_REACT_ACT_ENVIRONMENT 原始 property
descriptor。在 web/src/pages/DivisionBoard.test.tsx 的
91-101、web/src/pages/AgentBoardPanel.test.tsx 的 71-79,以及
web/src/pages/CompletionPanel.test.tsx 的 46-57 中,于 beforeEach 覆盖前记录
descriptor,并在对应 afterEach 中恢复它,同时保留现有 localStorage 清理和 renderer 卸载逻辑。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: f1786aaa-b6d5-453b-a2ae-829564e7e2e6
📒 Files selected for processing (6)
web/src/i18n/strings/Channel.tsweb/src/i18n/strings/ChannelFocusBar.tsweb/src/pages/AgentBoardPanel.test.tsxweb/src/pages/Channel.tsxweb/src/pages/CompletionPanel.test.tsxweb/src/pages/DivisionBoard.test.tsx
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
web/src/pages/Channel.tsx (2)
4995-5016: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
teamRoleSummary计算未做 memo,与同批新增的兄弟统计不一致。同一段落里新增的
memberOnlineNames/memberPresenceSummary都用useMemo包了,但紧邻的teamRoleBuckets(channelRoles, state.presence, channelIdentities, state.participants, t)(现在还多处理了participants)仍是每次渲染直接执行。ChannelPage在每个 websocket 帧到达时都会重渲染(dispatch({ type: "frame", frame })),而这里的结果pendingRoleClaimCount/unclaimedTeamCount只在 Team 面板展示的徽标里用到,值得和旁边两个统计一样做 memo,避免活跃频道里每条消息都重复做一遍 Map/Set 构建。♻️ 建议补 useMemo
- const teamRoleSummary = teamRoleBuckets( - channelRoles, - state.presence, - channelIdentities, - state.participants, - t, - ); + const teamRoleSummary = useMemo( + () => teamRoleBuckets(channelRoles, state.presence, channelIdentities, state.participants, t), + [channelRoles, state.presence, channelIdentities, state.participants, t], + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/pages/Channel.tsx` around lines 4995 - 5016, Wrap the teamRoleBuckets calculation in ChannelPage with useMemo, using channelRoles, state.presence, channelIdentities, state.participants, and t as dependencies. Keep pendingRoleClaimCount and unclaimedTeamCount derived from the memoized teamRoleSummary unchanged.
1033-1042: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
onSaveRole的 Promise 链未处理失败分支。
DivisionBoard里两处保存入口都是void onSaveRole(...).then((saved) => {...}),没有.catch。DivisionBoardProps.onSaveRole的类型是Promise<boolean>,并未在类型层面承诺“绝不 reject”;一旦某个调用方(现有的ChannelPage.saveRole内部已用 try/catch 兜底,但这是隐式契约,非类型强制)在未来实现中抛出异常,这里会产生未处理的 Promise rejection,且由于重置roleSaving的逻辑在调用方的finally块里,调用方来不及执行finally就已经抛出的话,roleSaving会永久卡在非 null,导致整块角色编辑 UI 一直被禁用。补一个.catch兜底可以避免这种放大故障。🛡️ 建议补充兜底
<button className="d-btn" type="button" disabled={roleSaving !== null} onClick={() => { - void onSaveRole(role.name, draftForRole).then((saved) => { - if (saved) finishRoleEdit(role.name); - }); + void onSaveRole(role.name, draftForRole) + .then((saved) => { + if (saved) finishRoleEdit(role.name); + }) + .catch(() => undefined); }} >- <button className="d-btn d-btn--primary" type="button" disabled={roleSaving !== null} onClick={() => { void onSaveRole(roleName, roleDraft); }}> + <button + className="d-btn d-btn--primary" + type="button" + disabled={roleSaving !== null} + onClick={() => { void onSaveRole(roleName, roleDraft).catch(() => undefined); }} + >Also applies to: 1165-1171
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/pages/Channel.tsx` around lines 1033 - 1042, 在 DivisionBoard 的两个角色保存入口中,更新围绕 onSaveRole 的 Promise 链,为 .then(...) 增加 .catch(...) 兜底处理未捕获的保存异常,避免产生未处理 rejection 并确保角色编辑状态不会永久保持禁用;保留现有成功分支 finishRoleEdit(role.name) 的行为。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@web/src/pages/Channel.tsx`:
- Around line 4995-5016: Wrap the teamRoleBuckets calculation in ChannelPage
with useMemo, using channelRoles, state.presence, channelIdentities,
state.participants, and t as dependencies. Keep pendingRoleClaimCount and
unclaimedTeamCount derived from the memoized teamRoleSummary unchanged.
- Around line 1033-1042: 在 DivisionBoard 的两个角色保存入口中,更新围绕 onSaveRole 的 Promise
链,为 .then(...) 增加 .catch(...) 兜底处理未捕获的保存异常,避免产生未处理 rejection
并确保角色编辑状态不会永久保持禁用;保留现有成功分支 finishRoleEdit(role.name) 的行为。
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 18d4541b-25b5-4e1d-ab65-13f3758f5788
📒 Files selected for processing (4)
web/src/pages/AgentBoardPanel.test.tsxweb/src/pages/Channel.tsxweb/src/pages/CompletionPanel.test.tsxweb/src/pages/DivisionBoard.test.tsx
|
review-ack: 已读最新实质 CodeRabbit(129a40c,两项有效 finding)与 PR Agent review;两项已在 5c69a97 修复,current head full check、Web 1207/1207、TypeScript 与生产构建均通过。current head CodeRabbit 因额度限流未执行,pr_agent synchronize 事件也被跳过;新增两文件 diff 已人工复核,无未解决阻断项。 |
改动说明
这次重构解决频道内功能模块边界与交互闭环,不是样式换皮。
合并前检查(review-ack 强制闸——不留结论合不了)
审查说明:最新实质 CodeRabbit review 在
129a40c提出两项有效问题,均已于5c69a97修复;current head 的自动增量复审因额度限流未执行。current head 的pr_agentcheck 成功,但synchronize事件被跳过且未产生新 review,新增 diff 已人工复核,并以 rejected save、participant-only roster、元数据优先级和显式公告同步测试覆盖。验证
full check:SUCCESS(current head5c69a97)pr_agent:SUCCESSgit diff --checkpassed官方测试站基线证据
在
https://agentparty.pwtk-dev.work/c/agentparty的v0.2.152 / fd7954d上用 chrome-use 复现:charter updated to rev 21。该测试站只在
v*tag 的 xdream Worker 部署后更新,因此合并后会发布v0.2.153,等待deploy (xdream)与verify-dual成功,再在同一站做发布后回归。