Preserve request log filters on detail navigation#1723
Conversation
Greptile SummaryThis PR moves request log filter state from component
Confidence Score: 5/5Safe to merge — this is a pure frontend state-lifting change with no backend contract changes, no schema mutations, and the core URL read/write logic is atomic and correctly resets pagination on every filter change. The filter state migration to URL params is well-structured: a single No files require special attention — Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Toolbar as DataTableToolbar
participant Table as RequestsTable
participant Content as RequestsContent
participant Router as TanStack Router (URL)
participant Detail as RequestDetailPage
User->>Toolbar: Change filter (e.g. status)
Toolbar->>Table: onColumnFiltersChange(updater)
Table->>Table: handleColumnFiltersChange → extract values
Table->>Content: onFiltersChange(filters)
Content->>Router: "navigate({ search: draft+clearCursors, replace:true })"
Router-->>Content: useRouterState update (currentSearch)
Content->>Content: useMemo → parseRequestSearchFilters
Content->>Table: new columnFilters props
Table->>Table: useMemo recomputes columnFilters
Table-->>User: Table re-renders with filtered data
User->>Table: Click View Detail
Table->>Content: onViewDetail(requestId)
Content->>Router: "navigate({ to: $requestId, search: currentSearch })"
Router-->>Detail: currentSearch (filters + cursors in URL)
User->>Detail: Click Back
Detail->>Router: "navigate({ to: /project/requests, search: currentSearch })"
Router-->>Content: Filter params restored from URL
Content->>Content: useMemo → parseRequestSearchFilters
Content-->>User: List rendered with original filters preserved
Reviews (2): Last reviewed commit: "Address request log filter review feedba..." | Re-trigger Greptile |
…ge title config, request filter preservation, structured response items Upstream commits merged: - fix: model settings dialog overflow (looplj#1716) - chore: custom page title config after login (looplj#1720) - feat: preserve request log filters on detail navigation (looplj#1723) - feat(llm): support responses websocket sessions (looplj#1730) - chore: add claude-opus-4-7 to claudecode DefaultModels (looplj#1733) - fix(channels): show real i18n label for single-variant types (looplj#1734) - fix(llm): accept structured response item arguments (looplj#1728) Resolved 4 import-path conflicts (looplj -> ldm2060) and adapted session scope integration in auth middleware. Fixed Windows flaky WebSocket test for platform-specific socket error messages. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Preserve request log filters on detail navigation * Address request log filter review feedback --------- Co-authored-by: userZ <spare.nets-0y@icloud.com>
背景
请求日志页面支持按状态、来源、渠道、API Key、模型 ID 和日期范围过滤请求记录。当前这些过滤条件主要保存在请求日志列表组件的 React state 中。
这会导致一个用户可见的问题:用户设置过滤条件后,打开某条请求详情页,再从详情页返回列表时,列表组件已经卸载并重新挂载,原来的过滤状态会恢复为空。用户需要重新设置过滤条件,排查请求时的上下文会丢失。
Fixes #1722
修改内容
1. 将请求日志过滤状态迁移到 URL search params
frontend/src/features/requests/index.tsx新增了请求日志过滤参数的解析和写入逻辑,将以下过滤条件从组件内存状态迁移到 TanStack Router 的 search params:statussourcechannelapiKeymodelIDcreatedAtFrom、createdAtTocreatedAtStartTime、createdAtEndTime列表页现在会从当前 URL search 中解析过滤条件,并据此生成 GraphQL 查询的
where条件。2. 过滤变化时同步更新 URL,并重置分页游标
过滤条件变化后,现在会写回当前路由的 search params,同时清理分页游标相关参数:
startCursorendCursorcursorDirectioncursorHistory这样可以避免一个旧分页游标继续作用在新的过滤条件上,导致列表位置或查询结果不符合用户预期。
3. 将请求日志表格过滤状态改为受控状态
frontend/src/features/requests/components/requests-table.tsx现在由父级传入 URL 派生出的过滤状态,并用这些状态控制 TanStack Table 的columnFilters。表格过滤变化时,通过统一的
onFiltersChange回传完整过滤状态,而不是分别调用多个单独的过滤更新回调。这样可以减少多个过滤器连续更新时互相覆盖或状态不同步的风险。4. 详情跳转保留完整 search params
请求日志列表中的“查看详情”按钮,以及抽屉中的“查看详情”入口,现在会使用列表页传入的详情跳转回调。
跳转到详情页时会保留当前完整 search params,因此详情页 URL 中包含进入详情前的列表过滤状态。
5. 详情页返回保留过滤状态
frontend/src/features/requests/components/request-detail-page.tsx的返回按钮现在会读取详情页当前的 search params,并带着这些参数返回/project/requests。因此无论用户使用详情页返回按钮,还是使用浏览器后退,只要进入详情页时携带了过滤 search params,返回列表后都能恢复原来的过滤状态。
6. 重置过滤改为一次性清理请求日志过滤参数
工具栏的重置过滤按钮现在通过父级传入的
onResetFilters一次性清理所有请求日志过滤 search params。这样可以避免先清表格过滤、再清日期范围带来的多次路由更新竞态,保证表格过滤状态和日期范围状态一起恢复为空。
7. 明确请求日志路由的 search 类型
frontend/src/routes/_authenticated/project/requests/index.tsx和frontend/src/routes/_authenticated/project/requests/$requestId.tsx新增validateSearch,显式声明请求日志列表页和详情页接受Record<string, unknown>search params。这样可以移除请求日志列表页和详情页导航中的
as any,保留 TanStack Router 的类型检查能力。8. 优化日期范围时间参数序列化
日期范围的时间参数现在只会在存在对应日期时写入 URL:
createdAtFrom时才可能写入createdAtStartTimecreatedAtTo时才可能写入createdAtEndTime同时,默认时间会从 URL 中省略:
00:00:0023:59:59这样可以避免孤立的 time 参数,也能减少默认日期范围场景下的 URL 噪音。
对外表现
修改后,请求日志页面的用户可见行为如下:
作用
这个修改让请求日志页面的过滤状态从“组件生命周期内有效”变成“路由状态可恢复”。它改善了请求排查流程中的上下文保持能力,用户可以在列表和详情之间切换而不丢失筛选条件。
同时,过滤状态进入 URL 后,也便于复制当前过滤后的页面地址进行复现或协作排查。
关于分页游标的说明
详情页 URL 仍然保留完整列表 search,其中可能包含分页游标。这样做是为了保留既有行为:用户从请求日志第 2 页或更后面的页面打开详情页后,返回时仍能回到原来的列表位置。
如果只携带过滤 key,详情页 URL 会更短,但会改变现有分页恢复行为,用户可能从非第一页打开详情后返回到过滤后的第一页。因此本 PR 只在过滤条件变化时清理旧游标,详情导航仍保留完整列表上下文。
风险与兼容性
验证
./node_modules/.bin/tsc --noEmit --pretty false./node_modules/.bin/prettier --check src/features/requests/index.tsx src/features/requests/components/index.ts src/features/requests/components/requests-table.tsx src/features/requests/components/data-table-toolbar.tsx src/features/requests/components/requests-columns.tsx src/features/requests/components/request-detail-page.tsx src/routes/_authenticated/project/requests/index.tsx 'src/routes/_authenticated/project/requests/$requestId.tsx'git diff --check