Skip to content

better filters#817

Merged
goldflag merged 3 commits intomasterfrom
better-filters
Jan 21, 2026
Merged

better filters#817
goldflag merged 3 commits intomasterfrom
better-filters

Conversation

@goldflag
Copy link
Copy Markdown
Collaborator

@goldflag goldflag commented Jan 21, 2026

Summary by CodeRabbit

  • New Features

    • Added pathname as a filterable session-level parameter.
    • Redesigned session card for improved responsive layout (separate mobile/desktop views), with clearer duration, badges, icons and matching skeletons.
  • Refactor

    • Improved filtering infrastructure and URL parameter mapping for more consistent session-level filters and UTM handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown

vercel bot commented Jan 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
rybbit Ready Ready Preview, Comment Jan 21, 2026 7:20am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 21, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Extends client session filters by adding "pathname" and refactors server-side filter construction to support configurable session-level parameters and field mappings, replacing ad-hoc string replacements with composable mapping passed into getFilterStatement.

Changes

Cohort / File(s) Summary
Client Filter Configuration
client/src/lib/filterGroups.ts
Added "pathname" to SESSION_PAGE_FILTERS alongside existing entry_page, exit_page, and event_name.
Server: Filter Builder API
server/src/api/analytics/utils/getFilterStatement.ts
Added exported FilterStatementOptions (fields: sessionLevelParams?: FilterParameter[], fieldMappings?: Record<string,string>). Refactored getFilterStatement to accept options?: FilterStatementOptions, build session-level subqueries generically for configured params, and apply final field name remapping.
Server: Analytics Endpoints
server/src/api/analytics/getSessions.ts, server/src/api/analytics/funnels/getFunnelStepSessions.ts
Replaced inline string-replace logic for url_parameters['utm_*'] with a fieldMappings object (e.g., map CTE utm_sourceutm_source) passed into getFilterStatement. Declared SESSION_FIELD_MAPPINGS and included pathname/page_title/event_name in session-level param lists.
UI: Session Card Layout
client/src/components/Sessions/SessionCard.tsx
Responsive layout changes: two-row mobile layout and updated desktop layout; skeleton components updated to reflect new structure and duration display adjustments.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client UI
    participant API as Analytics API
    participant Filter as getFilterStatement
    participant DB as Database / ClickHouse

    rect rgba(200,200,255,0.5)
    Client->>API: Request sessions/funnel (filters, site, time)
    end

    rect rgba(200,255,200,0.5)
    API->>Filter: getFilterStatement(filters, site, time, { sessionLevelParams, fieldMappings })
    Filter->>Filter: Build session-level subqueries for configured params\nApply regex/numeric handling\nApply fieldMappings remap
    Filter-->>API: SQL filter fragment (CTE-aware)
    end

    rect rgba(255,200,200,0.5)
    API->>DB: Execute composed query with filter fragment and CTEs (including utm_* columns)
    DB-->>API: Rows
    API-->>Client: Results
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
I dug a pathname through the filter sod,
Mapped UTMs cleanly — no more string-rod,
Subqueries hop, fields find their name,
The rabbit rewired rules for the game. 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'better filters' is vague and generic, using non-descriptive language that doesn't convey meaningful information about the specific changes in the changeset. Consider a more specific title that describes the primary change, such as 'Add configurable session-level filtering with field mappings' or 'Refactor filter handling to support dynamic parameter mapping'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…ters and field mappings

- Introduced options for session-level parameters and field mappings in getFilterStatement, allowing for more flexible filter configurations.
- Updated getSessions and getFunnelStepSessions to utilize the new field mappings for UTM parameters, improving query efficiency.
- Enhanced unit tests for getFilterStatement to ensure correct handling of various filter types and conditions.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/src/api/analytics/funnels/getFunnelStepSessions.ts (1)

145-146: filterStatement with mapped field names fails at line 145 when applied to the events table in the SessionActions CTE.

The filterStatement is constructed once (line 68) with fieldMappings that replace url_parameters['utm_source'], etc., with utm_source column references. This mapping works correctly at line 251 where the final SELECT queries AggregatedSessions (which extracts UTM parameters as separate columns at lines 222-226). However, at line 145, the same filterStatement is applied to the SessionActions CTE, which selects directly from the events table without extracting UTM parameters. The events table stores UTM data in the url_parameters map, not as individual columns. When the mapped filter references utm_source, it will fail because that column does not exist in the events table.

Solution: Either build separate filter statements for each CTE context, or apply field mappings conditionally only for the aggregated query.

🧹 Nitpick comments (3)
server/src/api/analytics/utils/getFilterStatement.ts (2)

101-121: Session-level subquery uses raw param instead of getSqlParam(param).

When buildSessionLevelSubquery is called with a parameter from sessionLevelParams, it uses the raw param directly in the SQL condition (line 111). However, parameters like pathname don't need transformation, but if someone adds a parameter like referrer (which maps to domainWithoutWWW(referrer)) to sessionLevelParams, the SQL would be incorrect.

Consider using getSqlParam(param) for consistency, or document that sessionLevelParams must only contain parameters that don't require SQL transformation.

♻️ Suggested fix
   const buildSessionLevelSubquery = (
     param: FilterParameter,
     filterType: FilterType,
     values: (string | number)[],
     wildcardPrefix: string
   ): string => {
     const whereClause = [siteIdFilter, timeFilter].filter(Boolean).join(" AND ");
+    const sqlParam = getSqlParam(param);
     const condition =
       values.length === 1
-        ? `${param} ${filterTypeToOperator(filterType)} ${SqlString.escape(wildcardPrefix + values[0] + wildcardPrefix)}`
-        : `(${values.map(value => `${param} ${filterTypeToOperator(filterType)} ${SqlString.escape(wildcardPrefix + value + wildcardPrefix)}`).join(" OR ")})`;
+        ? `${sqlParam} ${filterTypeToOperator(filterType)} ${SqlString.escape(wildcardPrefix + values[0] + wildcardPrefix)}`
+        : `(${values.map(value => `${sqlParam} ${filterTypeToOperator(filterType)} ${SqlString.escape(wildcardPrefix + value + wildcardPrefix)}`).join(" OR ")})`;

304-311: Consider using replaceAll() instead of regex to avoid static analysis warnings.

The static analysis tool flagged a potential ReDoS vulnerability on line 308. While this is likely a false positive (since fieldMappings are developer-controlled constants, not user input), you can silence the warning and simplify the code by using String.prototype.replaceAll():

♻️ Suggested fix using replaceAll
   // Apply field mappings if provided (for CTEs that extract fields to different column names)
   if (options?.fieldMappings) {
     for (const [from, to] of Object.entries(options.fieldMappings)) {
-      // Escape special regex characters in the 'from' string
-      const escapedFrom = from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
-      result = result.replace(new RegExp(escapedFrom, "g"), to);
+      result = result.replaceAll(from, to);
     }
   }
server/src/api/analytics/getSessions.ts (1)

60-67: Consider extracting shared SESSION_FIELD_MAPPINGS to avoid duplication.

This constant is identical to the one defined inline in getFunnelStepSessions.ts (lines 69-75). Consider extracting it to a shared location (e.g., utils/getFilterStatement.ts or a constants file) to maintain consistency and reduce duplication.

♻️ Example shared constant in getFilterStatement.ts
// In server/src/api/analytics/utils/getFilterStatement.ts
export const UTM_FIELD_MAPPINGS: Record<string, string> = {
  "url_parameters['utm_source']": "utm_source",
  "url_parameters['utm_medium']": "utm_medium",
  "url_parameters['utm_campaign']": "utm_campaign",
  "url_parameters['utm_term']": "utm_term",
  "url_parameters['utm_content']": "utm_content",
};

Then import and use in both getSessions.ts and getFunnelStepSessions.ts.

…ile display

- Redesigned the SessionCard component to support a mobile-first layout, featuring a two-row design for better usability on smaller screens.
- Added tooltips and badges for session details, including country, browser, and device type, enhancing the information presented to users.
- Updated the SessionCardSkeleton to match the new layout, ensuring a consistent loading experience across devices.
- Simplified the desktop layout while maintaining essential session information visibility.
@goldflag goldflag merged commit 7bba659 into master Jan 21, 2026
6 of 7 checks passed
jonathan-tw-fenz pushed a commit to jonathan-tw-fenz/rybbit that referenced this pull request Jan 26, 2026
* better filters

* Refactor getFilterStatement to support customizable session-level filters and field mappings

- Introduced options for session-level parameters and field mappings in getFilterStatement, allowing for more flexible filter configurations.
- Updated getSessions and getFunnelStepSessions to utilize the new field mappings for UTM parameters, improving query efficiency.
- Enhanced unit tests for getFilterStatement to ensure correct handling of various filter types and conditions.

* Enhance SessionCard component with responsive layout and improved mobile display

- Redesigned the SessionCard component to support a mobile-first layout, featuring a two-row design for better usability on smaller screens.
- Added tooltips and badges for session details, including country, browser, and device type, enhancing the information presented to users.
- Updated the SessionCardSkeleton to match the new layout, ensuring a consistent loading experience across devices.
- Simplified the desktop layout while maintaining essential session information visibility.
@coderabbitai coderabbitai bot mentioned this pull request Feb 6, 2026
@coderabbitai coderabbitai bot mentioned this pull request Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant