Skip to content

feat(clues): add filtered commander review queue - #133

Merged
cg8-5712 merged 5 commits into
mainfrom
feature/issue-78-clue-review-queue
Jul 27, 2026
Merged

cg8-5712 merged 5 commits into
mainfrom
feature/issue-78-clue-review-queue

Conversation

@cg8-5712

@cg8-5712 cg8-5712 commented Jul 27, 2026 •

Copy link
Copy Markdown
Collaborator
  • Add source_type filtering to clue timeline API, validation, and OpenAPI docs
  • Expose typed paginated clue timeline queries in the frontend API client
  • Build commander queue filters for status, source, time field, and sort order
  • Add loading, error retry, and pagination states for the review queue
  • Require explicit confirmation before submitting clue review decisions
  • Refresh queued clues after case mutations and completed reviews
  • Add frontend and API coverage for filtering, queue loading, and review confirmation
  • Add Testing Library DOM dependency and regenerate Yarn lockfile

Summary by CodeRabbit

  • 新功能
    • 指挥端新增线索审核队列,支持按审核状态、来源类型筛选并可按时间排序。
    • 队列支持分页;切换指挥端与审核后会自动刷新列表。
    • 审核提交新增确认弹窗,确认后才执行审核操作。
    • 线索查询接口新增按来源类型筛选能力(用于筛选“线索记录来源”)。
  • 改进
    • 不支持的来源类型会返回明确的校验错误。
    • 扩展前后端测试用例,覆盖来源类型筛选、分页以及确认提交流程。

- Add source_type filtering to clue timeline API, validation, and OpenAPI docs
- Expose typed paginated clue timeline queries in the frontend API client
- Build commander queue filters for status, source, time field, and sort order
- Add loading, error retry, and pagination states for the review queue
- Require explicit confirmation before submitting clue review decisions
- Refresh queued clues after case mutations and completed reviews
- Add frontend and API coverage for filtering, queue loading, and review confirmation
- Add Testing Library DOM dependency and regenerate Yarn lockfile
Copilot AI review requested due to automatic review settings July 27, 2026 01:48

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@cg8-5712, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4fbeee8d-962f-42f8-890f-01fb81a3f38e

📥 Commits

Reviewing files that changed from the base of the PR and between 78e4f20 and 9750c63.

📒 Files selected for processing (7)
  • .github/WORKFLOWS.md
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .github/workflows/security.yml
  • frontend/package.json
  • frontend/src/pages/CaseWorkspacePage.test.tsx
  • frontend/src/pages/CaseWorkspacePage.tsx
📝 Walkthrough

Walkthrough

新增 source_type 线索来源筛选,贯通后端校验、数据库查询和前端 API;指挥端新增可筛选、分页及审核确认后的线索队列刷新流程。

Changes

线索时间线来源筛选

Layer / File(s) Summary
后端来源筛选链路
docs/openapi.yaml, src/models.rs, src/services/case_service.rs, tests/api/case_clues_get.rs
线索时间线支持 source_type 参数,后端进行白名单校验并按来源过滤,接口测试覆盖分页、过滤和非法值。
前端线索时间线 API
frontend/src/api/cases.ts, frontend/src/api/cases.test.ts
新增查询与分页返回类型及 listCaseClues,序列化筛选参数并验证请求 URL。
指挥端审核队列与确认流程
frontend/src/pages/CaseWorkspacePage.tsx, frontend/src/pages/CaseWorkspacePage.test.tsx, frontend/package.json
指挥端增加线索筛选、排序、加载错误提示和分页;审核需确认后提交,并在成功后刷新队列。

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • AG-Angui/Angui#123:扩展同一线索时间线接口的查询参数及分页排序链路。
  • AG-Angui/Angui#127:提供 ClueSourceType 和 clues.source_type 等来源类型数据契约。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次变更的核心:为线索新增过滤后的指挥官审核队列。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-78-clue-review-queue

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
tests/api/case_clues_get.rs (1)

128-164: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

补充来源筛选与角色裁剪组合的覆盖。

当前正向断言只使用可查看全部线索的 commander,无法验证 source_type 不会泄露其他角色不可见的待审核线索。请增加 family 或 volunteer 查询 source_type=field_report 的断言,验证返回 total=0 且没有该线索。

As per path instructions, tests/** 必须覆盖有意义的正向、负向和边界场景。

🤖 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 `@tests/api/case_clues_get.rs` around lines 128 - 164, Extend the source_type
filtering coverage in the case clues test after the existing commander
assertions by issuing a field_report query with a family or volunteer token.
Assert that the response total is 0 and the items collection contains no
field_report clue, while preserving the existing commander positive assertions.

Source: Path instructions

🤖 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 `@frontend/src/pages/CaseWorkspacePage.tsx`:
- Around line 769-781: Update the isConfirming confirmation dialog in
CaseWorkspacePage to implement keyboard-modal behavior: move focus into the
dialog when opened, trap Tab navigation within it, restore focus to the
triggering control when closed, and close on Escape by reusing the existing
setIsConfirming(false) path. Preserve the current confirmation actions and
busy-state handling.
- Around line 322-346: Update loadClueQueue to isolate requests by case and
queueFilters, resetting the queue when either changes and ensuring only the
latest request can update clueQueue items, queueError, or isQueueLoading. Use a
request sequence or AbortController, and add a regression test covering
out-of-order responses so stale case/filter results are discarded.
- Line 348: Update the title/count rendering in CaseWorkspacePage to use
clueQueue.total and accurate “matching count” wording when isCommander is true,
keeping detail.clues.length and the existing wording for non-commander users.
Ensure the displayed count matches the visibleClues source selected for each
role.

---

Nitpick comments:
In `@tests/api/case_clues_get.rs`:
- Around line 128-164: Extend the source_type filtering coverage in the case
clues test after the existing commander assertions by issuing a field_report
query with a family or volunteer token. Assert that the response total is 0 and
the items collection contains no field_report clue, while preserving the
existing commander positive assertions.
🪄 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: CHILL

Plan: Pro Plus

Run ID: f77643cb-c35b-4d2a-a948-957f36dde42a

📥 Commits

Reviewing files that changed from the base of the PR and between 16dc232 and 9b0db94.

⛔ Files ignored due to path filters (2)
  • frontend/package-lock.json is excluded by !**/package-lock.json
  • frontend/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (9)
  • docs/openapi.yaml
  • frontend/package.json
  • frontend/src/api/cases.test.ts
  • frontend/src/api/cases.ts
  • frontend/src/pages/CaseWorkspacePage.test.tsx
  • frontend/src/pages/CaseWorkspacePage.tsx
  • src/models.rs
  • src/services/case_service.rs
  • tests/api/case_clues_get.rs

Comment thread frontend/src/pages/CaseWorkspacePage.tsx
}
}, [detail.id, isCommander, queueFilters, token])

const visibleClues = isCommander ? clueQueue.items : detail.clues

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

同步队列计数与当前渲染的数据源。

指挥端已改为渲染 clueQueue.items,但标题仍显示 detail.clues.length。例如队列返回 1 条、详情内线索为空时,页面会同时显示“0 条可见”和一条线索。指挥端应使用 clueQueue.total,并改为“匹配条数”等准确文案。

🤖 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 `@frontend/src/pages/CaseWorkspacePage.tsx` at line 348, Update the title/count
rendering in CaseWorkspacePage to use clueQueue.total and accurate “matching
count” wording when isCommander is true, keeping detail.clues.length and the
existing wording for non-commander users. Ensure the displayed count matches the
visibleClues source selected for each role.

Source: Path instructions

Comment thread frontend/src/pages/CaseWorkspacePage.tsx Outdated
- Track each commander queue request with a monotonically increasing version
- Clear queue data while loading a refreshed filtered result
- Apply queue results, errors, and loading state only for the latest request
- Invalidate pending queue requests when leaving commander mode
- Add coverage for stale responses resolving after newer filtered results

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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)
frontend/src/pages/CaseWorkspacePage.tsx (2)

527-533: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

请求失败时不要同时显示“暂无可见线索”。

加载开始时队列会被清空;请求失败后,页面既显示 ErrorState,又因为 visibleClues 为空显示“暂无可见线索”,会给用户造成矛盾的状态反馈。错误时应跳过空态。

As per path instructions,前端失败路径应提供一致的用户反馈。

建议修改
-          ) : visibleClues.length === 0 ? (
+          ) : queueError ? null : visibleClues.length === 0 ? (
🤖 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 `@frontend/src/pages/CaseWorkspacePage.tsx` around lines 527 - 533, Update the
queue rendering logic in CaseWorkspacePage around queueError, isQueueLoading,
and visibleClues so a failed request does not render the “暂无可见线索” empty state
alongside ErrorState. Prioritize the loading and error states before the
empty-list branch, while preserving the existing clue list rendering for
successful responses.

Source: Path instructions


375-382: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

刷新队列时不要使用旧闭包中的筛选条件。

run 在异步操作完成后调用的是调用时捕获的 loadClueQueue。如果期间筛选从 A 改为 B,B 请求可能先发出,但这里会随后用旧筛选再次发起 A 请求;该请求会取得最新版本号并覆盖当前队列。请通过刷新状态触发依赖最新筛选条件的 effect,或读取最新 callback/ref,不要直接调用旧闭包。

建议的刷新方式
+  const [queueRefreshVersion, setQueueRefreshVersion] = useState(0)

   async function run(key: string, action: () => Promise<unknown>, message: string) {
     ...
     try {
       await action()
       await onChanged(message)
-      await loadClueQueue()
+      setQueueRefreshVersion((value) => value + 1)
       return true

并让队列 effect 依赖 queueRefreshVersion,由 effect 使用最新的 loadClueQueue。

🤖 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 `@frontend/src/pages/CaseWorkspacePage.tsx` around lines 375 - 382, 更新
CaseWorkspacePage 中的 run 函数及队列刷新流程,避免异步完成后直接调用捕获旧筛选条件的 loadClueQueue。改用
queueRefreshVersion 触发依赖最新 loadClueQueue 的 effect,并在操作完成后递增该刷新状态;保留
onChanged(message) 的现有行为。
🧹 Nitpick comments (1)
frontend/src/pages/CaseWorkspacePage.tsx (1)

757-771: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

收敛为唯一的审核提交入口。

submitReview 已包含完整提交逻辑,但按钮在 isConfirming 分支又复制了一份 reviewClue 调用。两条路径的收尾行为不一致:确认弹窗路径会关闭弹窗,重复路径成功后不会关闭。让触发按钮只负责打开确认框,统一由 submitReview 提交。

🤖 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 `@frontend/src/pages/CaseWorkspacePage.tsx` around lines 757 - 771, 让审核按钮的
onPress 仅负责在非确认状态下调用 setIsConfirming(true) 并返回;确认状态下改为调用已有的 submitReview,移除其中重复的
normalizedReason、reviewClue 和成功回调逻辑,确保所有审核提交统一经过 submitReview 并执行一致的收尾行为。
🤖 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 `@frontend/src/pages/CaseWorkspacePage.tsx`:
- Around line 323-329: Update loadClueQueue in the missing-token or unauthorized
path to clear clue queue data, reset queue errors, and set queue loading to
false before returning. Preserve request-version invalidation so earlier
responses remain ignored, and ensure stale queue state is not retained after
authentication is lost.

---

Outside diff comments:
In `@frontend/src/pages/CaseWorkspacePage.tsx`:
- Around line 527-533: Update the queue rendering logic in CaseWorkspacePage
around queueError, isQueueLoading, and visibleClues so a failed request does not
render the “暂无可见线索” empty state alongside ErrorState. Prioritize the loading and
error states before the empty-list branch, while preserving the existing clue
list rendering for successful responses.
- Around line 375-382: 更新 CaseWorkspacePage 中的 run 函数及队列刷新流程,避免异步完成后直接调用捕获旧筛选条件的
loadClueQueue。改用 queueRefreshVersion 触发依赖最新 loadClueQueue 的
effect,并在操作完成后递增该刷新状态;保留 onChanged(message) 的现有行为。

---

Nitpick comments:
In `@frontend/src/pages/CaseWorkspacePage.tsx`:
- Around line 757-771: 让审核按钮的 onPress 仅负责在非确认状态下调用 setIsConfirming(true)
并返回;确认状态下改为调用已有的 submitReview,移除其中重复的 normalizedReason、reviewClue
和成功回调逻辑,确保所有审核提交统一经过 submitReview 并执行一致的收尾行为。
🪄 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: CHILL

Plan: Pro Plus

Run ID: 090051ab-5f12-45fd-b123-1e1f5eb6bfda

📥 Commits

Reviewing files that changed from the base of the PR and between 9b0db94 and 78e4f20.

📒 Files selected for processing (2)
  • frontend/src/pages/CaseWorkspacePage.test.tsx
  • frontend/src/pages/CaseWorkspacePage.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/pages/CaseWorkspacePage.test.tsx

Comment thread frontend/src/pages/CaseWorkspacePage.tsx
@cg8-5712
cg8-5712 force-pushed the feature/issue-78-clue-review-queue branch from 3c2700d to 78e4f20 Compare July 27, 2026 02:18
cg8-5712 added 3 commits July 27, 2026 10:19
- enable Corepack before frontend dependency operations
- install, lint, and build frontend from its working directory with Yarn
- replace npm audit with Yarn audit against the public advisory registry
- declare Yarn 1.22.22 as the frontend package manager
- update workflow documentation and cache references for Yarn
- replace custom modal markup with HeroUI AlertDialog primitives
- trap focus within the confirmation dialog during keyboard navigation
- support Escape key dismissal and restore focus to the review trigger
- extend review tests for focus management and dialog dismissal
- Reset queued clues, pagination, loading state, and errors when no token exists
- Prevent sensitive commander review clues from remaining visible after logout
- Add coverage for clearing the commander queue on authentication loss
@cg8-5712
cg8-5712 merged commit 917b113 into main Jul 27, 2026
14 of 15 checks passed
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