feat(requests): add time-range filter for proxy request search#596
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
📝 WalkthroughWalkthrough该 PR 在后端与前端全链路加入 startTime/endTime 过滤:后端新增解析与仓储时间范围约束并添加索引,前端扩展传输/Hook签名、实时缓存匹配与请求页时间筛选 UI 与文案。 Changes时间范围过滤功能完整实现
Sequence Diagram(s)sequenceDiagram
participant RequestsPage
participant AdminHandler
participant Repository
participant SQLite
RequestsPage->>AdminHandler: GET /requests or /requests/count (startTime,endTime,...)
AdminHandler->>AdminHandler: parseTimeQuery(startTime/endTime)
AdminHandler->>Repository: ListCursor/CountWithFilter(filter with StartTime/EndTime)
Repository->>SQLite: SELECT ... WHERE created_at >= ? AND created_at <= ?
SQLite-->>Repository: rows / count
Repository-->>AdminHandler: filtered results / count
AdminHandler-->>RequestsPage: 200 OK (JSON)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/pages/requests/index.tsx (1)
435-454:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win切换用户上下文时未重置时间筛选,存在跨账号残留。
这里重置了其它筛选项,但没有清理
startDateTime/endDateTime(及 debounced 状态)。切换账号后会继续沿用上一账号的时间窗口,和当前逻辑不一致。✅ 建议修复
setSelectedProjectId( readStoredNumberWithLegacy(projectFilterStorageKey, REQUEST_PROJECT_FILTER_STORAGE_KEY), ); setSelectedStatus(undefined); + setStartDateTime(''); + setEndDateTime(''); + setDebouncedStartDateTime(''); + setDebouncedEndDateTime(''); }, [ filterModeStorageKey, projectFilterStorageKey, providerFilterStorageKey, tokenFilterStorageKey, ]);🤖 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/requests/index.tsx` around lines 435 - 454, The useEffect that runs migrateLegacyRequestFilters and resets other filters must also clear the time filters to avoid cross-account retention; inside the same effect (the one calling migrateLegacyRequestFilters and setSelectedProviderId/... etc.) call the time-related setters to reset both the raw and debounced values — e.g. invoke setStartDateTime(undefined) and setEndDateTime(undefined) and also reset the debounced counterparts (setDebouncedStartDateTime and setDebouncedEndDateTime) so the previous account's time window is fully cleared when switching context.
🧹 Nitpick comments (1)
web/src/lib/transport/interface.ts (1)
132-139: ⚡ Quick win建议抽取统一的请求过滤类型,避免三处签名漂移。
这里和
web/src/lib/transport/http-transport.ts、web/src/hooks/queries/use-requests.ts都在重复声明同一组过滤字段。建议在web/src/lib/transport/types.ts导出一个共享类型并统一引用,减少后续新增筛选项时的漏改风险。♻️ 建议改法
// web/src/lib/transport/types.ts +export type RequestFilterParams = Pick< + CursorPaginationParams, + 'providerId' | 'status' | 'apiTokenId' | 'projectId' | 'startTime' | 'endTime' +>;// web/src/lib/transport/interface.ts +import type { RequestFilterParams } from './types'; ... - getProxyRequestsCount(filter?: { - providerId?: number; - status?: string; - apiTokenId?: number; - projectId?: number; - startTime?: string; - endTime?: string; - }): Promise<number>; + getProxyRequestsCount(filter?: RequestFilterParams): Promise<number>;🤖 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/lib/transport/interface.ts` around lines 132 - 139, Extract the repeated filter object into a shared type (e.g., ProxyRequestsFilter) exported from web/src/lib/transport/types.ts and update all signatures to use it: replace the inline filter in getProxyRequestsCount (interface in web/src/lib/transport/interface.ts), the corresponding parameter in web/src/lib/transport/http-transport.ts, and the filter type in web/src/hooks/queries/use-requests.ts to import and reference the new ProxyRequestsFilter type so all three sites share the same definition.
🤖 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 `@internal/handler/admin.go`:
- Around line 893-896: parseTimeQuery currently treats any integer string as a
millisecond timestamp (e.g., "1717488000" seconds becomes 1970), so modify
parseTimeQuery to strictly accept only millisecond-precision integers: before
calling strconv.ParseInt(...) or before accepting its result, validate the raw
string has millisecond precision (e.g., at least 13 digits for non-negative
timestamps or appropriate length for negatives) or check the parsed value is
within a reasonable ms-range (|value| >= 1e12) and reject/return an error
otherwise; update the branch that returns time.UnixMilli(millis) (the code
around parseTimeQuery) to perform this check and return a parse error for
second-precision integers.
In `@web/src/hooks/queries/use-requests.ts`:
- Around line 38-49: matchesRequestFilter currently parses
filter.startTime/filter.endTime using new Date(...).getTime(), which yields NaN
for pure-millisecond strings; update parsing so that in matchesRequestFilter you
first detect numeric-only strings for filter.startTime and filter.endTime (e.g.
/^\d+$/) and treat them as millisecond timestamps via Number(...) (or parseInt),
otherwise fall back to Date.parse(...) (or new Date(...).getTime()); then use
those parsed millisecond values for the existing comparisons against createdAtMs
(keep createdAtMs = new Date(request.createdAt).getTime() and guard with
Number.isFinite as before). Ensure you handle undefined startTime/endTime
exactly as current logic.
---
Outside diff comments:
In `@web/src/pages/requests/index.tsx`:
- Around line 435-454: The useEffect that runs migrateLegacyRequestFilters and
resets other filters must also clear the time filters to avoid cross-account
retention; inside the same effect (the one calling migrateLegacyRequestFilters
and setSelectedProviderId/... etc.) call the time-related setters to reset both
the raw and debounced values — e.g. invoke setStartDateTime(undefined) and
setEndDateTime(undefined) and also reset the debounced counterparts
(setDebouncedStartDateTime and setDebouncedEndDateTime) so the previous
account's time window is fully cleared when switching context.
---
Nitpick comments:
In `@web/src/lib/transport/interface.ts`:
- Around line 132-139: Extract the repeated filter object into a shared type
(e.g., ProxyRequestsFilter) exported from web/src/lib/transport/types.ts and
update all signatures to use it: replace the inline filter in
getProxyRequestsCount (interface in web/src/lib/transport/interface.ts), the
corresponding parameter in web/src/lib/transport/http-transport.ts, and the
filter type in web/src/hooks/queries/use-requests.ts to import and reference the
new ProxyRequestsFilter type so all three sites share the same definition.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0f3d35f7-7895-4aba-8da8-3ae17c68e83a
📒 Files selected for processing (12)
internal/handler/admin.gointernal/repository/interfaces.gointernal/repository/sqlite/migrations.gointernal/repository/sqlite/proxy_request.gointernal/repository/sqlite/proxy_request_test.goweb/src/hooks/queries/use-requests.tsweb/src/lib/transport/http-transport.tsweb/src/lib/transport/interface.tsweb/src/lib/transport/types.tsweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/requests/index.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: playwright
- GitHub Check: e2e
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
🔇 Additional comments (9)
internal/repository/interfaces.go (1)
125-139: LGTM!internal/handler/admin.go (1)
955-959: LGTM!Also applies to: 982-986
internal/repository/sqlite/proxy_request.go (1)
94-117: LGTM!Also applies to: 135-136, 177-178, 183-184
internal/repository/sqlite/proxy_request_test.go (1)
10-10: LGTM!Also applies to: 191-240
internal/repository/sqlite/migrations.go (1)
489-528: LGTM!web/src/lib/transport/types.ts (1)
376-379: LGTM!web/src/lib/transport/http-transport.ts (1)
414-443: LGTM!web/src/locales/en.json (1)
175-177: LGTM!web/src/locales/zh.json (1)
174-176: LGTM!
| function matchesRequestFilter(request: ProxyRequest, filter?: RequestFilterParams): boolean { | ||
| if (!filter) return true; | ||
| if (filter.providerId !== undefined && request.providerID !== filter.providerId) return false; | ||
| if (filter.status !== undefined && request.status !== filter.status) return false; | ||
| if (filter.apiTokenId !== undefined && request.apiTokenID !== filter.apiTokenId) return false; | ||
| if (filter.projectId !== undefined && request.projectID !== filter.projectId) return false; | ||
| const createdAtMs = new Date(request.createdAt).getTime(); | ||
| if (!Number.isFinite(createdAtMs)) return true; | ||
| if (filter.startTime !== undefined && createdAtMs < new Date(filter.startTime).getTime()) | ||
| return false; | ||
| if (filter.endTime !== undefined && createdAtMs > new Date(filter.endTime).getTime()) | ||
| return false; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 验证当前运行时对“毫秒时间戳字符串”的解析行为
node - <<'NODE'
const samples = ['2026-06-04T11:05:04Z', '1717488000000'];
for (const s of samples) {
const viaString = new Date(s).getTime();
const viaNumber = new Date(Number(s)).getTime();
console.log(`${s}\n new Date(string): ${Number.isFinite(viaString) ? viaString : 'NaN'}\n new Date(Number): ${Number.isFinite(viaNumber) ? viaNumber : 'NaN'}`);
}
NODERepository: awsl-project/maxx
Length of output: 212
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "RequestFilterParams|startTime|endTime|createdAt" web/src/hooks/queries/use-requests.ts
echo "----"
rg -n "startTime|endTime" web/src/lib/transport/types.ts
echo "----"
sed -n '1,120p' web/src/hooks/queries/use-requests.ts
echo "----"
sed -n '1,220p' web/src/lib/transport/types.tsRepository: awsl-project/maxx
Length of output: 11182
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "ISO|毫秒|timestamp|ms string|startTime|endTime" web/src/lib/transport/types.ts
echo "----"
rg -n "getProxyRequestsCount|getProxyRequests|getProxyRequests\\(" -S web/src/lib/transport
echo "----"
rg -n "startTime.*endTime|endTime.*startTime" -S web/src/lib/transportRepository: awsl-project/maxx
Length of output: 914
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '340,430p' web/src/lib/transport/types.ts
echo "---- interface.ts ----"
sed -n '90,170p' web/src/lib/transport/interface.ts
echo "---- http-transport.ts ----"
sed -n '360,480p' web/src/lib/transport/http-transport.tsRepository: awsl-project/maxx
Length of output: 9340
修复时间过滤解析以匹配后端契约(startTime/endTime 支持“毫秒时间戳字符串”)
web/src/hooks/queries/use-requests.ts 的 matchesRequestFilter 用 new Date(filter.startTime/endTime).getTime() 解析 startTime/endTime;但 web/src/lib/transport/types.ts 明确约定它们可以是“ISO 字符串或毫秒时间戳字符串”,且 http-transport.ts 会将该字符串原样透传到后端。运行时对纯数字毫秒串(如 1717488000000)new Date(str) 会得到 NaN,从而使起止时间比较退化为“不生效过滤”,导致实时列表/计数与后端结果不一致。
需要在前端将 startTime/endTime 按“纯数字 => 当作毫秒时间戳;否则 => ISO/Date.parse”解析成 ms 再比较。
🤖 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/hooks/queries/use-requests.ts` around lines 38 - 49,
matchesRequestFilter currently parses filter.startTime/filter.endTime using new
Date(...).getTime(), which yields NaN for pure-millisecond strings; update
parsing so that in matchesRequestFilter you first detect numeric-only strings
for filter.startTime and filter.endTime (e.g. /^\d+$/) and treat them as
millisecond timestamps via Number(...) (or parseInt), otherwise fall back to
Date.parse(...) (or new Date(...).getTime()); then use those parsed millisecond
values for the existing comparisons against createdAtMs (keep createdAtMs = new
Date(request.createdAt).getTime() and guard with Number.isFinite as before).
Ensure you handle undefined startTime/endTime exactly as current logic.
… + add 13-digit ms validation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
web/src/hooks/queries/use-requests.ts (1)
28-44:⚠️ Potential issue | 🟠 Major | ⚡ Quick win修复时间过滤解析以支持毫秒时间戳字符串
matchesRequestTimeRange使用new Date(startTime).getTime()和new Date(endTime).getTime()解析时间参数,但根据传输层契约(web/src/lib/transport/types.ts),startTime/endTime可以是"ISO 字符串或毫秒时间戳字符串"。当传入纯数字毫秒串(如
"1717488000000")时,new Date("1717488000000")会返回Invalid Date,导致getTime()得到NaN,使时间范围比较失效,从而导致实时缓存匹配逻辑与后端结果不一致。需要在解析前判断:如果是纯数字字符串(
/^\d+$/),则作为毫秒时间戳Number(startTime);否则使用new Date(startTime).getTime()。🛠️ 修复示例
function matchesRequestTimeRange( request: ProxyRequest, startTime?: string, endTime?: string, ): boolean { const createdAtMs = new Date(request.createdAt).getTime(); if (!Number.isFinite(createdAtMs)) { return true; } - if (startTime !== undefined && createdAtMs < new Date(startTime).getTime()) { + if (startTime !== undefined) { + const startMs = /^\d+$/.test(startTime) ? Number(startTime) : new Date(startTime).getTime(); + if (Number.isFinite(startMs) && createdAtMs < startMs) { + return false; + } + } + if (endTime !== undefined) { + const endMs = /^\d+$/.test(endTime) ? Number(endTime) : new Date(endTime).getTime(); + if (Number.isFinite(endMs) && createdAtMs > endMs) { + return false; + } - return false; } - if (endTime !== undefined && createdAtMs > new Date(endTime).getTime()) { - return false; - } return true; }🤖 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/hooks/queries/use-requests.ts` around lines 28 - 44, matchesRequestTimeRange currently uses new Date(...).getTime() for startTime/endTime which fails for pure-millisecond strings; update the function to parse startTime and endTime into startMs/endMs by first checking if the string matches /^\d+$/ and using Number(value) in that case, otherwise use Date.parse(value) (or new Date(value).getTime()), and only perform comparisons if the parsed ms is finite; reference the function matchesRequestTimeRange and the parameters startTime/endTime when making this change and ensure invalid parses are treated as "no bound" (skip that comparison) so behavior remains consistent with backend.
🧹 Nitpick comments (1)
internal/repository/sqlite/proxy_request.go (1)
110-130: 🏗️ Heavy lift过滤逻辑重复,建议提取为辅助函数
ListCursor(110-130 行)与CountWithFilter(178-198 行)中的过滤条件应用逻辑完全相同(ProviderID、Status、APITokenID、ProjectID、StartTime、EndTime 六个字段的if filter.X != nil判断与Where调用)。若后续新增过滤字段或调整过滤逻辑,需要同时修改两处,容易产生不一致。建议将过滤逻辑提取为辅助函数(如
applyProxyRequestFilter(query *gorm.DB, filter *repository.ProxyRequestFilter) *gorm.DB),在两处调用点统一使用,避免维护时遗漏。Also applies to: 178-198
🤖 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 `@internal/repository/sqlite/proxy_request.go` around lines 110 - 130, ListCursor and CountWithFilter duplicate the same filter-applying logic for repository.ProxyRequestFilter (checks for ProviderID, Status, APITokenID, ProjectID, StartTime, EndTime); extract this into a helper like applyProxyRequestFilter(query *gorm.DB, filter *repository.ProxyRequestFilter) *gorm.DB that encapsulates all the if filter.X != nil -> query.Where(...) and timestamp conversions (toTimestamp), then replace the inline blocks in ListCursor and CountWithFilter with calls to applyProxyRequestFilter to ensure a single source of truth for filtering.
🤖 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.
Duplicate comments:
In `@web/src/hooks/queries/use-requests.ts`:
- Around line 28-44: matchesRequestTimeRange currently uses new
Date(...).getTime() for startTime/endTime which fails for pure-millisecond
strings; update the function to parse startTime and endTime into startMs/endMs
by first checking if the string matches /^\d+$/ and using Number(value) in that
case, otherwise use Date.parse(value) (or new Date(value).getTime()), and only
perform comparisons if the parsed ms is finite; reference the function
matchesRequestTimeRange and the parameters startTime/endTime when making this
change and ensure invalid parses are treated as "no bound" (skip that
comparison) so behavior remains consistent with backend.
---
Nitpick comments:
In `@internal/repository/sqlite/proxy_request.go`:
- Around line 110-130: ListCursor and CountWithFilter duplicate the same
filter-applying logic for repository.ProxyRequestFilter (checks for ProviderID,
Status, APITokenID, ProjectID, StartTime, EndTime); extract this into a helper
like applyProxyRequestFilter(query *gorm.DB, filter
*repository.ProxyRequestFilter) *gorm.DB that encapsulates all the if filter.X
!= nil -> query.Where(...) and timestamp conversions (toTimestamp), then replace
the inline blocks in ListCursor and CountWithFilter with calls to
applyProxyRequestFilter to ensure a single source of truth for filtering.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e1ae0e98-9661-4ea4-8b18-07f80ca97c4f
📒 Files selected for processing (6)
internal/handler/admin.gointernal/repository/sqlite/proxy_request.goweb/src/hooks/queries/use-requests.tsweb/src/lib/transport/http-transport.tsweb/src/lib/transport/interface.tsweb/src/pages/requests/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- internal/handler/admin.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: multiinstance
- GitHub Check: playwright
- GitHub Check: e2e
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
📚 Learning: 2026-03-30T09:23:52.570Z
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
Applied to files:
web/src/hooks/queries/use-requests.ts
🔇 Additional comments (5)
internal/repository/sqlite/proxy_request.go (1)
172-172: LGTM!web/src/lib/transport/interface.ts (1)
132-139: LGTM!web/src/lib/transport/http-transport.ts (1)
414-443: LGTM!web/src/pages/requests/index.tsx (2)
75-84: LGTM!Also applies to: 252-256
1485-1534: LGTM!
…/endTime in both handlers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
internal/handler/admin.go (1)
901-955: ⚖️ Poor tradeoff考虑提取重复的过滤参数解析逻辑。
handleProxyRequests(lines 901-955) 和handleProxyRequestsCount(lines 978-1031) 中有约 55 行几乎完全相同的过滤参数解析代码。虽然 commit message 表明这是有意内联的(回退了之前的提取),但重复逻辑会增加维护成本:未来新增过滤参数或修改错误消息时需要在两处同步修改。♻️ 可选重构方案:提取为辅助函数
// parseProxyRequestFilter 从查询参数中解析代理请求过滤器 func parseProxyRequestFilter(query url.Values) (*repository.ProxyRequestFilter, error) { providerIDStr := query.Get("providerId") statusStr := query.Get("status") apiTokenIDStr := query.Get("apiTokenId") projectIDStr := query.Get("projectId") startTimeStr := query.Get("startTime") endTimeStr := query.Get("endTime") if providerIDStr == "" && statusStr == "" && apiTokenIDStr == "" && projectIDStr == "" && startTimeStr == "" && endTimeStr == "" { return nil, nil } filter := &repository.ProxyRequestFilter{} if providerIDStr != "" { providerID, err := strconv.ParseUint(providerIDStr, 10, 64) if err != nil { return nil, errors.New("invalid providerId") } filter.ProviderID = &providerID } if statusStr != "" { filter.Status = &statusStr } if apiTokenIDStr != "" { apiTokenID, err := strconv.ParseUint(apiTokenIDStr, 10, 64) if err != nil { return nil, errors.New("invalid apiTokenId") } filter.APITokenID = &apiTokenID } if projectIDStr != "" { projectID, err := strconv.ParseUint(projectIDStr, 10, 64) if err != nil { return nil, errors.New("invalid projectId") } filter.ProjectID = &projectID } if startTimeStr != "" { startTime, err := parseTimeQuery(startTimeStr, "startTime") if err != nil { return nil, err } filter.StartTime = startTime } if endTimeStr != "" { endTime, err := parseTimeQuery(endTimeStr, "endTime") if err != nil { return nil, err } filter.EndTime = endTime } return filter, nil }然后在两个 handler 中简化为:
// 在 handleProxyRequests 中 filter, err := parseProxyRequestFilter(r.URL.Query()) if err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } // 在 handleProxyRequestsCount 中 filter, err := parseProxyRequestFilter(r.URL.Query()) if err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return }Also applies to: 978-1031
🤖 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 `@internal/handler/admin.go` around lines 901 - 955, Duplicate query-parameter parsing for proxy request filters appears in handleProxyRequests and handleProxyRequestsCount; extract the logic into a helper like parseProxyRequestFilter(query url.Values) that returns (*repository.ProxyRequestFilter, error) and use it from both handlers, returning HTTP 400 on error (same behavior as current inline code). Ensure parseProxyRequestFilter implements the same parsing/validation for providerId, status, apiTokenId, projectId, startTime and endTime (using strconv.ParseUint and parseTimeQuery) and preserves nil when no filter params are present, then replace the inline blocks in handleProxyRequests and handleProxyRequestsCount with calls to this function and unified error handling.
🤖 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.
Nitpick comments:
In `@internal/handler/admin.go`:
- Around line 901-955: Duplicate query-parameter parsing for proxy request
filters appears in handleProxyRequests and handleProxyRequestsCount; extract the
logic into a helper like parseProxyRequestFilter(query url.Values) that returns
(*repository.ProxyRequestFilter, error) and use it from both handlers, returning
HTTP 400 on error (same behavior as current inline code). Ensure
parseProxyRequestFilter implements the same parsing/validation for providerId,
status, apiTokenId, projectId, startTime and endTime (using strconv.ParseUint
and parseTimeQuery) and preserves nil when no filter params are present, then
replace the inline blocks in handleProxyRequests and handleProxyRequestsCount
with calls to this function and unified error handling.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 49f703f6-ff0d-444e-9d2d-8d337410ade8
📒 Files selected for processing (1)
internal/handler/admin.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: multiinstance
- GitHub Check: playwright
- GitHub Check: e2e
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
📚 Learning: 2026-03-30T09:23:52.570Z
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
Applied to files:
internal/handler/admin.go
🔇 Additional comments (3)
internal/handler/admin.go (3)
828-848: LGTM!
901-955: LGTM!
978-1031: LGTM!
…ilter to Calendar popover - Add startTime <= endTime validation in both handlers - Replace raw datetime-local inputs with shadcn Popover + Calendar + time input - Install shadcn calendar and popover components Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/requests/index.tsx`:
- Line 50: 移除未使用的 Button 导入:在 web/src/pages/requests/index.tsx 中找到导入列表并删除未使用的标识符
Button(即从 import 列表中移除 "Button"),保存后重新运行 lint/build 以确认 ESLint/TS6133 错误已解决。
- Around line 1525-1530: The Calendar usage is passing a removed prop
initialFocus to DayPicker which causes TS2322; update the Calendar invocation
(the Calendar component that forwards DayPicker props) to remove initialFocus
and replace it with autoFocus (or drop it), i.e., change occurrences of
initialFocus on the Calendar component to autoFocus so the forwarded props match
react-day-picker@10's API and restore initial focus behavior.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a939b2f5-9edd-41b2-80ad-a0a4de24d147
⛔ Files ignored due to path filters (1)
web/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
internal/handler/admin.goweb/package.jsonweb/src/components/ui/button.tsxweb/src/components/ui/calendar.tsxweb/src/components/ui/popover.tsxweb/src/pages/requests/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- internal/handler/admin.go
📜 Review details
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
📚 Learning: 2026-03-14T03:21:15.610Z
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-14T03:21:15.610Z
Learning: In the awsl-project/maxx repository, `AlertDialogAction` in `web/src/components/ui/alert-dialog.tsx` is a custom wrapper around `<Button {...props}>` (not the standard shadcn/ui implementation). It accepts `React.ComponentProps<typeof Button>` and spreads all props including `variant` directly into `<Button>`, so variant styling is correctly forwarded at runtime.
Applied to files:
web/src/components/ui/calendar.tsxweb/src/components/ui/button.tsx
🪛 GitHub Actions: E2E Multi-instance / 0_multiinstance.txt
web/src/pages/requests/index.tsx
[error] 50-50: TypeScript (TS6133) failed during build: 'Button' is declared but its value is never read.
[error] 1529-1529: TypeScript (TS2322) failed during build: 'initialFocus' prop does not exist on type for DayPicker (Property 'initialFocus' does not exist in DayPickerProps).
web/src/components/ui/calendar.tsx
[error] 88-88: TypeScript (TS2353) failed during build: Object literal may only specify known properties, and 'table' does not exist in type 'Partial'.
🪛 GitHub Actions: E2E Multi-instance / multiinstance
web/src/pages/requests/index.tsx
[error] 50-50: TypeScript (tsc) TS6133: 'Button' is declared but its value is never read.
[error] 1529-1529: TypeScript (tsc) TS2322: Props type mismatch for DayPicker. Property 'initialFocus' does not exist on the expected DayPicker props type.
web/src/components/ui/calendar.tsx
[error] 88-88: TypeScript (tsc) TS2353: Object literal may only specify known properties, and 'table' does not exist in type 'Partial'.
🪛 GitHub Actions: E2E Playwright Tests / 0_playwright.txt
web/src/components/ui/calendar.tsx
[error] 88-88: Build failed: TypeScript error TS2353 — Object literal may only specify known properties, and 'table' does not exist in type 'Partial'.
🪛 GitHub Actions: E2E Playwright Tests / playwright
web/src/components/ui/calendar.tsx
[error] 88-88: TypeScript build failed (tsc). TS2353: Object literal may only specify known properties, and 'table' does not exist in type 'Partial'.
🪛 GitHub Actions: PR Checks / 1_Frontend Checks.txt
web/src/pages/requests/index.tsx
[error] 50-50: ESLint (@typescript-eslint/no-unused-vars): 'Button' is defined but never used.
🪛 GitHub Actions: PR Checks / Frontend Checks
web/src/pages/requests/index.tsx
[error] 50-50: ESLint (@typescript-eslint/no-unused-vars): 'Button' is defined but never used.
🪛 GitHub Check: Frontend Checks
web/src/pages/requests/index.tsx
[failure] 50-50:
'Button' is defined but never used
🔇 Additional comments (4)
web/src/components/ui/button.tsx (1)
1-59: LGTM!web/src/components/ui/popover.tsx (1)
1-89: LGTM!web/package.json (1)
49-49: LGTM!web/src/components/ui/calendar.tsx (1)
88-88: ⚡ Quick win
react-day-pickerv10 中classNames.table非法,需改用对应的网格样式键
Line 88的table: "w-full border-collapse"会触发 TS2353:table不在Partial<ClassNames>,构建阻塞;按 v10 的ClassNames类型把该键替换为类似month_grid的合法键。建议修复
- table: "w-full border-collapse", + month_grid: "w-full border-collapse",
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
b30cf0a to
eac51df
Compare





Summary
startTime/endTimefilter to proxy request list and count APIs, enabling users to search requests by creation time rangeidx_proxy_requests_created_at_idcomposite index with large-table skip safetyTimeRangeFiltercomponent with datetime-local inputs and 400ms debounceapplyProxyRequestFilterto eliminate duplicated filter logic in repository layeruseInfiniteProxyRequests/useProxyRequestsCount/getProxyRequestsCountfrom positional args to options object (RequestFilterParams)parseTimeQueryto only accept millisecond timestamps and RFC3339 formats (reject ambiguous timezone-less formats)Test plan
tsc --noEmit)TestProxyRequestListCursorAndCountFilterByCreatedAtRange🤖 Generated with Claude Code
Summary by CodeRabbit