Files
pulse/lib/filters.ts
Usman Baig 5677f30f3b feat: add dashboard dimension filtering and custom event properties
Dashboard filtering: FilterBar pills, AddFilterDropdown with dimension/
operator/value steps, URL-serialized filters, all SWR hooks filter-aware.

Custom event properties: pulse.track() accepts props object, EventProperties
panel with auto-discovered key tabs and value bar charts, clickable goal rows.

Updated changelog with both features under v0.13.0-alpha.
2026-03-06 21:02:14 +01:00

61 lines
1.8 KiB
TypeScript

// * Dimension filter types and utilities for dashboard filtering
export interface DimensionFilter {
dimension: string
operator: 'is' | 'is_not' | 'contains' | 'not_contains'
values: string[]
}
export const DIMENSION_LABELS: Record<string, string> = {
page: 'Page',
referrer: 'Referrer',
country: 'Country',
city: 'City',
region: 'Region',
browser: 'Browser',
os: 'OS',
device: 'Device',
utm_source: 'UTM Source',
utm_medium: 'UTM Medium',
utm_campaign: 'UTM Campaign',
}
export const OPERATOR_LABELS: Record<string, string> = {
is: 'is',
is_not: 'is not',
contains: 'contains',
not_contains: 'does not contain',
}
export const DIMENSIONS = Object.keys(DIMENSION_LABELS)
export const OPERATORS = Object.keys(OPERATOR_LABELS) as DimensionFilter['operator'][]
/** Serialize filters to query param format: "browser|is|Chrome,country|is|US" */
export function serializeFilters(filters: DimensionFilter[]): string {
if (!filters.length) return ''
return filters
.map(f => `${f.dimension}|${f.operator}|${f.values.join(';')}`)
.join(',')
}
/** Parse filters from URL search param string */
export function parseFiltersFromURL(raw: string): DimensionFilter[] {
if (!raw) return []
return raw.split(',').map(part => {
const [dimension, operator, valuesRaw] = part.split('|')
return {
dimension,
operator: operator as DimensionFilter['operator'],
values: valuesRaw?.split(';') ?? [],
}
}).filter(f => f.dimension && f.operator && f.values.length > 0)
}
/** Build display label for a filter pill */
export function filterLabel(f: DimensionFilter): string {
const dim = DIMENSION_LABELS[f.dimension] || f.dimension
const op = OPERATOR_LABELS[f.operator] || f.operator
const val = f.values.length > 1 ? `${f.values[0]} +${f.values.length - 1}` : f.values[0]
return `${dim} ${op} ${val}`
}