Data-grid overhaul + session-replays / team-payments dashboard surfaces#1424
Data-grid overhaul + session-replays / team-payments dashboard surfaces#1424mantrakp04 wants to merge 18 commits into
Conversation
…ents surfaces - Rewrite data-grid with URL-synced state, new sizing logic, tests - Move analytics/replays → session-replays; add per-user session replays card - Add team-analytics and team-payments to team detail page - Add project_user.last_active_at index + permission-definitions pagination - Various editable-input / inline-save-discard / settings polish
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
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:
📝 WalkthroughWalkthroughAdds backend pagination/search and session-replays sorting, extends shared interfaces/SDK and template/server implementations for paginated listings, refactors DataGrid with URL-state and TanStack, converts tables to server-backed infinite sources, adds team analytics/payments and user session-replays UI, updates OpenAPI/docs/registry, adds a DB index, E2E tests, dependency, and AGENTS git-safety guidance. ChangesMain change DAG
UI / DataGrid and Tables
Pages / Features
Estimated code review effort: Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
…sion handling - Introduced pagination for teams in the dashboard, allowing for efficient data retrieval and display. - Updated permission definitions to include cursor-based pagination, improving user experience when navigating through permissions. - Refactored various components to utilize the new paginated API, ensuring consistency across the application. - Added error handling for pagination and improved loading states in user session replays and team member tables. - Enhanced the data grid to support URL-synced state for column widths and visibility, improving user customization options. This update significantly enhances the dashboard's performance and usability, particularly for users managing large teams and permissions.
23db822 to
cabcf19
Compare
- Updated the ProjectUser model to simplify indexing on lastActiveAt. - Refactored permission definitions pagination to utilize a unified schema, improving consistency across project and team permissions. - Enhanced error handling in pagination logic for better user feedback. - Improved loading states and data retrieval efficiency in various components, including session replays and team permissions. These changes streamline the permission management experience and optimize data handling in the dashboard.
…election logic - Renamed cursor comparator variable for clarity in session replay queries. - Enhanced search query handling to include escape character for better SQL compatibility. - Introduced error handling for asynchronous queries in the Team Analytics section, providing default values for failed queries. - Refactored data grid selection logic to support flexible row selection modes and improved column width distribution. These changes enhance the robustness and usability of the dashboard components, particularly in data retrieval and user interaction.
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)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/[userId]/user-analytics.tsx (1)
669-691:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winBase the chart empty state on the chart window, not the summary window.
When a day filter is active, the chart is built from the expanded
dailyrange (±15 days), buthasAnyEventstill comes fromsummary.total_events, which only counts the selected day. Filtering to a zero-event day will therefore hide surrounding activity and show the global “No events recorded” empty state instead.🤖 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 `@apps/dashboard/src/app/`(main)/(protected)/projects/[projectId]/users/[userId]/user-analytics.tsx around lines 669 - 691, The empty-state check currently uses data.summary.total_events which reflects only the summary window; change it to derive from the chart window data (the densified daily series) so the empty state matches the displayed chart. Move or recreate hasAnyEvent after the dense computation and set it to something like: hasAnyEvent = dense.some(d => (d.total_events ?? 0) > 0) (or sum dense totals > 0), ensuring the variable depends on dense (and dayFilter) rather than data.summary.total_events so the UI reflects densifyDaily/daily and dayFilter logic.
🤖 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
`@apps/dashboard/src/app/`(main)/(protected)/projects/[projectId]/users/[userId]/user-analytics.tsx:
- Around line 433-439: The page currently treats any non-empty dayFilter string
as a “filtered” state even when parseDayFilterRange(dayFilter) returns null; fix
by computing a single validated activeDayFilter/validatedFilterRange (call
parseDayFilterRange once, e.g. const activeDayFilter =
parseDayFilterRange(dayFilter)) and use that value everywhere you currently
check dayFilter or filterRange for rendering and querying (banner,
deltas/sparklines, description rewrite); if parseDayFilterRange returns null
clear/reset the URL param or treat the page as unfiltered so the UI and queries
stay consistent (update all usages of filterRange/dayFilter in
user-analytics.tsx including the sections around the parseDayFilterRange call
and the other affected blocks).
- Around line 753-755: The ActivityChart is being hidden at extra-large
viewports because it's wrapped in a div with the "xl:hidden" utility; to fix,
remove or change that responsive class so the chart remains visible on xl
screens—locate the wrapper around the ActivityChart (the div containing
<ActivityChart daily={dense} hasAnyEvent={hasAnyEvent}
description={chartDescription} />) and either delete the "xl:hidden" class or
replace it with the correct responsive utility (e.g., no hide or "hidden
xl:block" if you need it hidden on small screens but shown on xl).
---
Outside diff comments:
In
`@apps/dashboard/src/app/`(main)/(protected)/projects/[projectId]/users/[userId]/user-analytics.tsx:
- Around line 669-691: The empty-state check currently uses
data.summary.total_events which reflects only the summary window; change it to
derive from the chart window data (the densified daily series) so the empty
state matches the displayed chart. Move or recreate hasAnyEvent after the dense
computation and set it to something like: hasAnyEvent = dense.some(d =>
(d.total_events ?? 0) > 0) (or sum dense totals > 0), ensuring the variable
depends on dense (and dayFilter) rather than data.summary.total_events so the UI
reflects densifyDaily/daily and dayFilter logic.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0dfc9c9f-afbf-417c-9090-dab32256f568
📒 Files selected for processing (6)
apps/backend/src/app/api/latest/permission-definitions-pagination.tsapps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/[userId]/user-analytics.tsxapps/dashboard/src/components/data-table/team-member-table.tsxapps/dashboard/src/lib/apps-frontend.tsxdocs/content/docs/sdk/types/user.mdxpackages/template/src/dev-tool/index.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/backend/src/app/api/latest/permission-definitions-pagination.ts
- apps/dashboard/src/lib/apps-frontend.tsx
- packages/template/src/dev-tool/index.ts
- docs/content/docs/sdk/types/user.mdx
- apps/dashboard/src/components/data-table/team-member-table.tsx
| function parseDayFilterRange(dayFilter: string): { since: Date, until: Date } | null { | ||
| const parts = dayFilter.split("-").map(Number); | ||
| if (parts.length !== 3 || parts.some((p) => !Number.isFinite(p))) return null; | ||
| const since = new Date(Date.UTC(parts[0], parts[1] - 1, parts[2])); | ||
| const until = new Date(since); | ||
| until.setUTCDate(until.getUTCDate() + 1); | ||
| return { since, until }; |
There was a problem hiding this comment.
Validate dayFilter before treating the page as filtered.
Right now malformed values fall back to the unfiltered queries (filterRange === null), but the render path still shows the filter banner, disables deltas/sparklines, and rewrites descriptions whenever dayFilter is a non-empty string. A bad URL state will therefore show filtered UI around unfiltered analytics. Please derive one validated activeDayFilter and use that for both querying and rendering, or clear invalid values immediately.
Also applies to: 448-451, 586-599
🤖 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
`@apps/dashboard/src/app/`(main)/(protected)/projects/[projectId]/users/[userId]/user-analytics.tsx
around lines 433 - 439, The page currently treats any non-empty dayFilter string
as a “filtered” state even when parseDayFilterRange(dayFilter) returns null; fix
by computing a single validated activeDayFilter/validatedFilterRange (call
parseDayFilterRange once, e.g. const activeDayFilter =
parseDayFilterRange(dayFilter)) and use that value everywhere you currently
check dayFilter or filterRange for rendering and querying (banner,
deltas/sparklines, description rewrite); if parseDayFilterRange returns null
clear/reset the URL param or treat the page as unfiltered so the UI and queries
stay consistent (update all usages of filterRange/dayFilter in
user-analytics.tsx including the sections around the parseDayFilterRange call
and the other affected blocks).
| <div className="xl:hidden"> | ||
| <ActivityChart daily={dense} hasAnyEvent={hasAnyEvent} description={chartDescription} /> | ||
| </div> |
There was a problem hiding this comment.
The daily activity chart disappears on xl screens.
This is the only ActivityChart render in the component, so wrapping it in xl:hidden removes the chart entirely for extra-large viewports.
♻️ Minimal fix
- <div className="xl:hidden">
- <ActivityChart daily={dense} hasAnyEvent={hasAnyEvent} description={chartDescription} />
- </div>
+ <ActivityChart daily={dense} hasAnyEvent={hasAnyEvent} description={chartDescription} />🤖 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
`@apps/dashboard/src/app/`(main)/(protected)/projects/[projectId]/users/[userId]/user-analytics.tsx
around lines 753 - 755, The ActivityChart is being hidden at extra-large
viewports because it's wrapped in a div with the "xl:hidden" utility; to fix,
remove or change that responsive class so the chart remains visible on xl
screens—locate the wrapper around the ActivityChart (the div containing
<ActivityChart daily={dense} hasAnyEvent={hasAnyEvent}
description={chartDescription} />) and either delete the "xl:hidden" class or
replace it with the correct responsive utility (e.g., no hide or "hidden
xl:block" if you need it hidden on small screens but shown on xl).
- Replaced the use of `createDefaultDataGridState` with `useDataGridUrlState` across multiple components to improve state persistence and URL synchronization. - Updated pagination logic in various tables to ensure consistent handling of grid states and improve user experience during data retrieval. - Refactored components to utilize the new user picker table for better user selection functionality. These changes enhance the overall reliability and usability of the dashboard's data grid features.
- Removed unused parameters from session replay queries, specifically `sort_direction` and `q`, to simplify the API. - Updated user and team listing functions to utilize non-paginated APIs, enhancing data retrieval efficiency. - Refactored related components to support the new API structure, ensuring consistency across the application. - Improved error handling and response structures for better user feedback during data operations. These changes optimize the performance of session replay and user management features in the dashboard.
- Modified the `limit` parameter in the user query schema to remove the maximum cap description, simplifying the API documentation. - Updated corresponding OpenAPI specifications in both admin and server JSON files to reflect the change in the `limit` parameter description. These changes enhance the clarity of the API documentation and improve user understanding of the query parameters.
- Added a newline at the end of the `admin.json` and `server.json` files to comply with JSON formatting standards. This change ensures better compatibility with various parsers and tools that expect a newline at the end of files.
Summary
Refactors the dashboard data-grid into a smaller, URL-state-aware primitive and lands several new dashboard surfaces around it: per-user session replays, team-level analytics and payments, and pagination for permission definitions. Also moves session replays out from under
/analyticsto a top-level surface and adds aproject_user.last_active_atindex that the new weekly-active metrics depend on.Base:
dev→ Head:refactor/data-grid-and-dashboard-surfacesScope: 91 files, +5,644 / −1,858. Assets in this gist.
Screenshots
Captured from a local dev server (dashboard at
:8101, dummy project seeded with 26 users). Standard viewport 1920×1200, widescreen 2560×1440.Users list — data-grid overhaul in context
Widescreen:
User detail — new session-replays card + weekly metrics
Widescreen:
Session replays — moved out of
/analyticsWidescreen:
Project permissions — new pagination
Widescreen:
Other migrated surfaces
Scroll behaviour — new data-grid on the users list
What's new
packages/dashboard-ui-components/src/components/data-grid— rewritten. Trimmeddata-grid.tsxfrom ~1.7k LOC, split sizing logic intodata-grid-sizing.ts, addeduse-url-state.tsfor URL-synced state, and addeddata-grid.test.tsx.…/analytics/replaysto…/session-replays(top-level surface). Newuser-session-replays.tsxcard on the user detail page; new internalroute.tsxto feed it.team-analytics.tsxandteam-payments.tsx.permission-definitions-pagination.tsconsumed by both project and team permission CRUD routes.add_project_user_last_active_at_idx+ alastActiveAtindex that backs the new weekly-active metrics.editable-input,inline-save-discard,settings.tsx, walkthrough steps, and several data-table components touched in line with the data-grid rewrite.Notes for reviewers
apps/dashboard/src/components/data-table/*were updated to match — please scan those for any missed knobs.analytics/replays→session-replaysrename is git-tracked as renames; diffs should be small in those files.packages/template/src/lib/stack-app/session-replays/index.tsand additions inadmin-app-impl.ts/server-app-impl.tsmean OpenAPI specs (docs-mintlify/openapi/{admin,client}.json) regenerate; the diff is mostly mechanical.Test plan
pnpm typecheckcleanpnpm lintcleanpackages/dashboard-ui-components)lastActiveAtindex migration applied (i.e. on a fresh DB) and after applying it/analytics/replays/...URL path is no longer expected to be linked anywhereSummary by CodeRabbit
New Features
UX
Performance
Documentation
Tests