feat(web): time range filter dropdown with URL state#7
Conversation
|
@xingkaixin 这个想先问下方向再决定要不要 rebase—— 几种都能干:
主要不想盲目 rebase 642 行结果方向不对。 |
可以的,这个我一直想,但没有去做,感谢 PR。 |
Per maintainer feedback on PR xingkaixin#7 (option 1): consume the backend `from`/ `to` scan-window plumbing introduced in fc59d37 instead of doing client-side in-memory filtering. The previous PR also re-implemented `filterSessionsByActivityWindow` in handlers.ts; that has been dropped since upstream main carries an identical helper now. What this adds: - `useTimeRange` hook (apps/web/src/lib/useTimeRange.ts): URL-search- param-backed time range with CLI flag fallback. Encoding: ?range=7d|30d|90d|all|yesterday preset / all-time / yesterday ?from=YYYY-MM-DD[&to=YYYY-MM-DD] custom window Falls back to `rangeFromAppConfig(appConfig)` (whatever the CLI was launched with) when neither URL param is present. - `TimeRangeMenu` component: header dropdown with presets (Yesterday, Last 1d/3d/7d/14d/30d/90d, All time) plus a custom from/to date pair. - `windowFromTimeRange` helper in api.ts: maps a UI-side TimeRange union back into the existing `{from?, to?, days?}` window shape that the backend / fetch helpers already accept. Closed-inclusive semantics: yesterday and custom-with-`to` round `to` to end-of-day (-1ms). - Extended `fetchAgents` and `fetchSearchResults` to also accept the window so the dropdown drives every list/dashboard/search refetch consistently. fetchSessions / fetchDashboard already accepted it. - App.tsx: split the original mount-time effect into a config+bookmarks load and a window-driven reload effect that re-runs whenever the active range changes. syncLiveUpdate, search-results effect, and every fetch call site now use `activeWindow = windowFromTimeRange( timeRange)` as the single source of truth. Dropdown rendered next to the header subtitle, hidden in session-detail mode. Tests: - 7 unit tests for windowFromTimeRange covering null/undefined, all, preset days, yesterday with pinned system time, custom from-only, custom from+to closed-inclusive same-day, malformed dates degrading safely. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f2fe344 to
b244750
Compare
…eview)
Codex flagged 6 issues, all conf >= 75. Fixes:
P1 (api.ts windowFromTimeRange) — preset { days } only returned `{ days }`,
but /api/sessions, /api/search and /api/agents do not parse `days`. Result:
selecting "Last 7d" narrowed only the dashboard while sessions, search,
and agent counts still showed everything. Now returns days AND a concrete
from/to derived from local-day arithmetic so every endpoint filters
consistently.
P1 (windowFromTimeRange) — `all` returned `{}`, which let CLI defaults
re-assert themselves on /sessions and the 30-day default fire on
/dashboard. The "All time" label thus contradicted the data. Now emits
explicit `from=0 (epoch), to=now` so the wide window overrides any
backend default.
P1 (handlers.ts handleGetAgents) — only read CLI defaults, not query.
Dropdown moved sessions list but agent counts stayed pinned to CLI
window. Now parses ?from/?to with defaults as fallback (one-line
parity with handleGetSessions / handleGetSearch).
P2 (windowFromTimeRange yesterday) — used `from + 86400000 - 1` for `to`,
which on DST transition days lands on the wrong calendar boundary
(spring-forward day overshoots into next day, fall-back day stops at 23:00).
Now uses setDate(+1) + setMilliseconds(-1) — DST-safe and correct on
month/year boundaries. Added a regression test pinning system time to
2026-03-09 (one day after US spring DST start).
P2 (useTimeRange.isValidIsoDate) — accepted "2026-02-31" because
new Date("2026-02-31") silently normalizes to 2026-03-03 and getTime()
is finite. URL ?from=2026-02-31 would query the wrong day. Added
round-trip check: parsed components must match the input.
P2 (TimeRangeMenu) — popover marked role="menu" but contains a custom
date-range form with inputs. ARIA menu semantics expect menuitem-style
descendants. Switched to role="dialog" with aria-label; preset list
becomes a role="radiogroup" with role="radio" buttons.
Tests: expanded windowFromTimeRange suite to 12 cases (preset days+from/to,
all=epoch+now, DST-safe yesterday, custom inclusive end-of-day, malformed
degrade) + 4 isValidIsoDate cases (round-trip, format, calendar-impossible).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@xingkaixin 按你说的方案 1 重写了 ( 整个 PR 现在 scope 缩成纯前端 dropdown 消费后端 from/to API。Drop 了原 PR 里 handlers.ts 的
跑 codex review 发现 6 个 conf >=75 issue,都 fix 了:
测试:windowFromTimeRange 12 case (preset/all/DST-safe yesterday/custom inclusive/malformed degrade) + isValidIsoDate 4 case (format/round-trip/leap year/impossible date), CDP 验证暂没跑 (我这边 server 还跑着旧 dist),你方便起 dev 验证下:
PR 缩到 +152/-53,handlers.ts 只动了 6 行 (handleGetAgents query parse 对齐 sessions/search),前端是核心。 |
我这边测下来,当前实现还差两个关键点。 第一,TimeRangeMenu 更适合放在最顶层 app header,和 search / version / CLI window chip 同一层。这个筛选语义是全局展示窗口,会影响 dashboard、agent counts、session list、search results。放在 Dashboard/内容 header 里,切到 agent 或 session 时语义会变局部,使用上会觉得筛选状态消失。 第二,当前后端 query 我建议按这个方向改:
这样启动时仍然可以默认 7d,页面里切 30d / all time 时服务端会补齐数据。这个路线能实现“无需重启 CLI 改时间范围”。 |
|
收到 review,先转 draft。 两个改动 (TimeRangeMenu 上提到顶层 header + LiveScanStore expandable scan 的后端架构改造) 都比较深,尤其后端那个涉及 in-flight scan de-dupe / window 缓存边界,我这边需要时间想清楚再动手。想好了 ready for review 再 @ 你。 |
Summary
Adds a dropdown in the toolbar to switch the active time window (7d / 30d / 90d / all, plus a custom from→to picker) without restarting the CLI. The selection is encoded in the URL so it survives reload and is shareable; existing
--days/--from/--toCLI flags still seed the initial value.Changes
Frontend (
apps/web)useTimeRangehook: parses?range=7d|30d|90d|allor?from=YYYY-MM-DD[&to=...]from URL search params, falls back to CLI flags from/api/config, exposes asetRangethat writes back to the URL.TimeRangeMenucomponent: native dropdown with preset radio items + custom<input type=\"date\">from/to fields and Apply / Reset actions. Closes on outside click / Esc.App.tsx: replaces the read-only "Last 7d · …" chip in the header with the new menu. Splits the mount-time fetch (config + bookmarks) from a range-driven effect that refetches/api/agents,/api/sessions,/api/dashboardwhenever the active range changes. Live-update sync and search refetches now also carry the range.lib/api.ts:fetchAgents/fetchSessions/fetchDashboard/fetchSearchResultsaccept an optionalTimeRangeand serialize it consistently.Backend (
packages/cli)resolveListWindowhelper centralizes the "explicit query > CLI default" precedence and adds?days=Nsupport (and?days=0= all-time) to the agents/sessions/search handlers, matching the dashboard handler's existing behavior. Existing?from=&to=semantics are unchanged.days=Nfiltering anddays=0overriding a configured CLI default.Test plan
pnpm --filter codesesh test— 24/24 vitest pass (incl. 2 new cases).pnpm lint— 0 warnings across all packages.pnpm --filter codesesh build— CLI bundle + web dist OK.localhost:4321):Last 7d ·CLI(CLI fallback).?range=30d, label switches toLast 30d.?range=all→ label =All time.?from=2026-01-01&to=2026-02-01→ label shows the range.curl /api/sessions?days={3,30,0}→ 362 / 1008 / 1322 sessions;curl /api/agents?days=0shows full counts;?days=3filters cursor to 0.🤖 Generated with Claude Code