Repository navigation
fix(chat): focus + height polish; feat(admin): devpass margin% + chart - #2220
Conversation
Follow-up to #2215. Replaces autoFocus on the inline rename Input with a parent-controlled pendingFocusChatId so scroll-induced remounts no longer re-steal focus mid-edit, memoizes rowProps, hard-codes row heights through ROW_HEIGHT_* constants and stretches the row content to fill the slot, and drops the unused formatDate prop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds marginPct to /admin/devpass list and detail responses. Renders % margin in the Cycle margin KPI subtitle on /devpass. Introduces GET /admin/devpass/timeseries (revenue, cost, margin per day) wired into a new DevpassTimeseriesChart on /devpass with the existing DateRangePicker (30d, 90d, 365d, all time, custom). Adds an ID column with click-to-copy on the per-org subscription history and payment failure tables for easier debugging. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
WalkthroughThis PR adds DevPass margin percentage analytics and a new /devpass/timeseries API, integrates a date-range-filtered timeseries chart into admin pages, adds CopyableId UI and ID columns to DevPass detail tables, and refactors the playground chat sidebar edit/focus flow with memoized row props. ChangesDevPass Analytics and Timeseries
Chat Sidebar Edit Focus Refactoring
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 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: 4
🤖 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 `@ee/admin/src/app/devpass/page.tsx`:
- Around line 313-314: The parsed from/to query params used by
DevpassTimeseriesChart must be preserved when building any table interactions
(search, sort, filter, pagination): update the URL/query-string builders and
link/navigation functions that construct table requests (the functions that
currently build the search/sort/filter/pagination URLs) to include the existing
from and to values so they are forwarded on every interaction; ensure the
components that call those builders (the table controls and pagination handlers)
read from/to from the current router/query state and merge them into the new
query object so the chart retains the selected date range across actions.
In `@ee/admin/src/components/copyable-id.tsx`:
- Around line 18-27: The setTimeout in handleCopy (inside the CopyableId
component) can update state after unmount; fix by tracking the timeout ID and
clearing it on unmount: import and use useEffect (or useRef) in the CopyableId
component to store the timer id returned from setTimeout in handleCopy, call
clearTimeout(timerId) in a cleanup effect, and ensure you don't call
setCopied(false) after unmount; remove or guard the pending timeout when the
component unmounts to prevent state updates on an unmounted component.
In `@ee/admin/src/components/devpass-timeseries-chart.tsx`:
- Around line 89-97: The segmented-control buttons only indicate selection
visually; update the button element used inside the map (the one with key={key},
onClick={() => setActiveSeries(key)}, and data-active={activeSeries === key}) to
expose state to assistive tech by adding an aria-pressed attribute set to
{activeSeries === key}; ensure the attribute value reflects the same boolean
used for data-active so screen readers know which series is active (reference
activeSeries, setActiveSeries, and the button with key={key}).
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 8c393c26-ce05-4d35-9d57-52ee4e7d25cf
⛔ Files ignored due to path filters (1)
ee/admin/src/lib/api/v1.d.tsis excluded by!**/v1.d.ts
📒 Files selected for processing (6)
apps/api/src/routes/admin.tsapps/playground/src/components/playground/chat-sidebar.tsxee/admin/src/app/devpass/[orgId]/page.tsxee/admin/src/app/devpass/page.tsxee/admin/src/components/copyable-id.tsxee/admin/src/components/devpass-timeseries-chart.tsx
| query: z.object({ | ||
| from: z.string().optional(), | ||
| to: z.string().optional(), | ||
| }), |
There was a problem hiding this comment.
Validate from/to together on the new DevPass timeseries route.
The schema accepts arbitrary strings, but the handler only honors the range when both params are present. Right now a partial range silently falls back to all-time, and malformed values can flow into new Date(...)/SQL instead of returning a clean 4xx. Require valid YYYY-MM-DD values and either both params or neither.
Also applies to: 8308-8324
Forward `from`/`to` through the devpass table query-string and form action so chart range survives sort/filter/page interactions. Cancel the CopyableId reset timeout on unmount to avoid late state updates. Add aria-pressed to the timeseries chart's segmented control. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Two related changes bundled into one PR.
1. Chat sidebar virtualization follow-ups (#2215)
autoFocus. Parent statependingFocusChatIdflips on edit-start and is cleared once the input has actually delivered focus, so re-mounting the editing row on scroll never re-steals focus mid-edit.ROW_HEIGHT_HEADER/ROW_HEIGHT_SPACER/ROW_HEIGHT_CHATconstants used bygetChatHistoryRowHeight; row content stretches withh-full!andtop-1/2 -translate-y-1/2so the menu action stays vertically centered regardless of slot height.formatDateprop — already module-level, imported directly.!isChatsLoadingguard inside the empty-state branch (the early return already covers it).2. DevPass admin dashboard
/devpass. Formula:totalMargin / totalMrrCycle. Also surfaced per-subscriber on the detail response asmarginPct(currently only KPI subtitle uses it; per-row UI can come later)./devpass/[orgId], via a new tinyCopyableIdclient component (sonner toast on success, ✓ flicker confirmation)./devpass: newDevpassTimeseriesChartshows daily revenue, real provider cost, and margin. Uses the same<DateRangePicker />as the main admin dashboard (presets including30d,90d,365d,All time, plus custom).GET /admin/devpass/timeseries— acceptsfrom/to, defaults to all-time anchored on the earliestdev_plan_start. Revenue: completeddev_plan_*transactions. Cost:project_hourly_stats.costfor projects under orgs that are or were ever on a DevPass plan.Test plan
/(chat), rename a chat in a long history, scroll the sidebar so the editing row exits the viewport, scroll back — the input stays focused/active and does not re-steal focus./devpass, switch the date picker between 30d / 90d / 365d / All time — chart series and totals update; KPI strip reflects margin %./devpass/[orgId], click a row ID in either table — clipboard contains the full id, toast shown.pnpm formatclean;pnpm --filter admin tsc --noEmitclean;pnpm --filter admin buildsucceeds.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
New Metrics
Improvements