Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web-analytics): Session filters 1 #21512

Merged
merged 32 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
fc7d420
Handle hogql session properties
robbie-c Apr 12, 2024
cd47348
Add test for two lazy joins in one query (session & person)
robbie-c Apr 12, 2024
394a309
Support passing session properties in web analytics queries
robbie-c Apr 12, 2024
1dec023
Fix typings
robbie-c Apr 12, 2024
7eadc34
Working session definition fetching
robbie-c Apr 15, 2024
d90274a
Working session property definitions
robbie-c Apr 15, 2024
4599849
Remove property allow list in web analytics
robbie-c Apr 16, 2024
6c2bced
Put session properties first
robbie-c Apr 16, 2024
a0a07aa
Add session values
robbie-c Apr 16, 2024
7ea52bc
Rename duration back to $session_duration
robbie-c Apr 16, 2024
e666f6f
Fix "keeps infiniteListCounts in sync"
robbie-c Apr 16, 2024
eba45b6
Fix "setting search query filters events"
robbie-c Apr 16, 2024
50afd65
Fix taxonomy tests
robbie-c Apr 16, 2024
6ceb302
Change session api to GenericViewSet
robbie-c Apr 16, 2024
200b09a
Add local properties back
robbie-c Apr 16, 2024
7f77e5f
Support datetime and boolean session properties
robbie-c Apr 16, 2024
68c1a88
Update mypy baseline
robbie-c Apr 16, 2024
0db6248
Hide duration as a property and asterisk field
robbie-c Apr 18, 2024
dbda731
Add AsyncReturnType
robbie-c Apr 18, 2024
cb2fb3b
Make taxonoicFilterLogic tests more reliable (maybe)
robbie-c Apr 18, 2024
870334a
Fix duplicates from bad rebase
robbie-c Apr 18, 2024
5658a57
Only show session table session properties if feature flag enabled
robbie-c Apr 18, 2024
888a1da
Improve error message for non-hogql non-duration session property
robbie-c Apr 18, 2024
085e150
Put session table properties behind FF
robbie-c Apr 18, 2024
c7c3a9a
Revert taxonomicFilterLogic tests
robbie-c Apr 18, 2024
f5ef830
Update query snapshots
github-actions[bot] Apr 18, 2024
350f046
Rename TaxonomicFilterGroupType.Sessions to TaxonomicFilterGroupType.…
robbie-c Apr 18, 2024
569b873
Use ViewSet instead of GenericViewSet
robbie-c Apr 24, 2024
0332190
Add tests for session properties and session property values api
robbie-c Apr 24, 2024
0ec3bf1
Formatting
robbie-c Apr 24, 2024
5ab36e1
New typing
robbie-c Apr 25, 2024
6cd2c85
Update query snapshots
github-actions[bot] Apr 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ class ApiRequest {
.withQueryString(queryParams)
}

public sessionPropertyDefinitions(teamId?: TeamType['id']): ApiRequest {
return this.projectsDetail(teamId).addPathComponent('sessions').addPathComponent('property_definitions')
}

public dataManagementActivity(teamId?: TeamType['id']): ApiRequest {
return this.projectsDetail(teamId).addPathComponent('data_management').addPathComponent('activity')
}
Expand Down Expand Up @@ -1212,6 +1216,23 @@ const api = {
},
},

sessions: {
async propertyDefinitions({
teamId = ApiConfig.getCurrentTeamId(),
search,
properties,
}: {
teamId?: TeamType['id']
search?: string
properties?: string[]
}): Promise<CountedPaginatedResponse<PropertyDefinition>> {
return new ApiRequest()
.sessionPropertyDefinitions(teamId)
.withQueryString(toParams({ search, ...(properties ? { properties: properties.join(',') } : {}) }))
.get()
},
},
Comment on lines +1219 to +1234
Copy link
Collaborator

Choose a reason for hiding this comment

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

No pagination?

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably no need to add it to the definitions endpoint, but I should add it to the values endpoint. I'll fix this in a future PR


cohorts: {
async get(cohortId: CohortType['id']): Promise<CohortType> {
return await new ApiRequest().cohortsDetail(cohortId).get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ function Example({ value }: { value?: string }): JSX.Element {
type === TaxonomicFilterGroupType.EventFeatureFlags ||
type === TaxonomicFilterGroupType.PersonProperties ||
type === TaxonomicFilterGroupType.GroupsPrefix ||
type === TaxonomicFilterGroupType.Metadata
type === TaxonomicFilterGroupType.Metadata ||
type === TaxonomicFilterGroupType.SessionProperties
) {
data = getCoreFilterDefinition(value, type)
} else if (type === TaxonomicFilterGroupType.Elements) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ function DefinitionView({ group }: { group: TaxonomicFilterGroup }): JSX.Element
isCohort,
isDataWarehouse,
isProperty,
hasSentAs,
} = useValues(definitionPopoverLogic)

const { setLocalDefinition } = useActions(definitionPopoverLogic)
Expand Down Expand Up @@ -142,13 +143,17 @@ function DefinitionView({ group }: { group: TaxonomicFilterGroup }): JSX.Element
/>
</DefinitionPopover.Grid>

<DefinitionPopover.HorizontalLine />
<DefinitionPopover.Section>
<DefinitionPopover.Card
title="Sent as"
value={<span className="font-mono text-xs">{_definition.name}</span>}
/>
</DefinitionPopover.Section>
{hasSentAs ? (
<>
<DefinitionPopover.HorizontalLine />
<DefinitionPopover.Section>
<DefinitionPopover.Card
title="Sent as"
value={<span className="font-mono text-xs">{_definition.name}</span>}
/>
</DefinitionPopover.Section>
</>
) : null}
</>
)
}
Expand Down Expand Up @@ -176,17 +181,21 @@ function DefinitionView({ group }: { group: TaxonomicFilterGroup }): JSX.Element
<DefinitionPopover.Grid cols={2}>
<DefinitionPopover.Card title="Property Type" value={_definition.property_type ?? '-'} />
</DefinitionPopover.Grid>
<DefinitionPopover.HorizontalLine />
<DefinitionPopover.Grid cols={2}>
<DefinitionPopover.Card
title="Sent as"
value={
<span className="truncate text-mono text-xs" title={_definition.name ?? undefined}>
{_definition.name !== '' ? _definition.name : <i>(empty string)</i>}
</span>
}
/>
</DefinitionPopover.Grid>
{hasSentAs ? (
<>
<DefinitionPopover.HorizontalLine />
<DefinitionPopover.Grid cols={2}>
<DefinitionPopover.Card
title="Sent as"
value={
<span className="truncate text-mono text-xs" title={_definition.name ?? undefined}>
{_definition.name !== '' ? _definition.name : <i>(empty string)</i>}
</span>
}
/>
</DefinitionPopover.Grid>
</>
) : null}
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,17 @@ export const definitionPopoverLogic = kea<definitionPopoverLogicType>([
[
TaxonomicFilterGroupType.PersonProperties,
TaxonomicFilterGroupType.EventProperties,
TaxonomicFilterGroupType.SessionProperties,
TaxonomicFilterGroupType.EventFeatureFlags,
TaxonomicFilterGroupType.NumericalEventProperties,
TaxonomicFilterGroupType.Metadata,
].includes(type) || type.startsWith(TaxonomicFilterGroupType.GroupsPrefix),
],
hasSentAs: [
(s) => [s.type, s.isProperty, s.isEvent],
(type, isProperty, isEvent) =>
isEvent || (isProperty && type !== TaxonomicFilterGroupType.SessionProperties),
],
isCohort: [(s) => [s.type], (type) => type === TaxonomicFilterGroupType.Cohorts],
isDataWarehouse: [(s) => [s.type], (type) => type === TaxonomicFilterGroupType.DataWarehouse],
viewFullDetailUrl: [
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/components/DefinitionPopover/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function getSingularType(type: TaxonomicFilterGroupType): string {
case TaxonomicFilterGroupType.EventProperties:
case TaxonomicFilterGroupType.PersonProperties:
case TaxonomicFilterGroupType.GroupsPrefix: // Group properties
case TaxonomicFilterGroupType.SessionProperties:
return 'property'
case TaxonomicFilterGroupType.EventFeatureFlags:
return 'feature'
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/PropertyFilters/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('propertyFilterTypeToTaxonomicFilterType()', () => {
...baseFilter,
type: PropertyFilterType.Session,
} as SessionPropertyFilter)
).toEqual(TaxonomicFilterGroupType.Sessions)
).toEqual(TaxonomicFilterGroupType.SessionProperties)
expect(propertyFilterTypeToTaxonomicFilterType({ ...baseFilter, type: PropertyFilterType.HogQL })).toEqual(
TaxonomicFilterGroupType.HogQLExpression
)
Expand Down Expand Up @@ -122,7 +122,7 @@ describe('breakdownFilterToTaxonomicFilterType()', () => {
TaxonomicFilterGroupType.EventProperties
)
expect(breakdownFilterToTaxonomicFilterType({ ...baseFilter, breakdown_type: 'session' })).toEqual(
TaxonomicFilterGroupType.Sessions
TaxonomicFilterGroupType.SessionProperties
)
expect(breakdownFilterToTaxonomicFilterType({ ...baseFilter, breakdown_type: 'hogql' })).toEqual(
TaxonomicFilterGroupType.HogQLExpression
Expand Down
16 changes: 11 additions & 5 deletions frontend/src/lib/components/PropertyFilters/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const PROPERTY_FILTER_TYPE_TO_TAXONOMIC_FILTER_GROUP_TYPE: Omit<
[PropertyFilterType.Feature]: TaxonomicFilterGroupType.EventFeatureFlags,
[PropertyFilterType.Cohort]: TaxonomicFilterGroupType.Cohorts,
[PropertyFilterType.Element]: TaxonomicFilterGroupType.Elements,
[PropertyFilterType.Session]: TaxonomicFilterGroupType.Sessions,
[PropertyFilterType.Session]: TaxonomicFilterGroupType.SessionProperties,
[PropertyFilterType.HogQL]: TaxonomicFilterGroupType.HogQLExpression,
[PropertyFilterType.Group]: TaxonomicFilterGroupType.GroupsPrefix,
[PropertyFilterType.DataWarehouse]: TaxonomicFilterGroupType.DataWarehouse,
Expand Down Expand Up @@ -183,10 +183,14 @@ export function isEventPropertyFilter(filter?: AnyFilterLike | null): filter is
export function isPersonPropertyFilter(filter?: AnyFilterLike | null): filter is PersonPropertyFilter {
return filter?.type === PropertyFilterType.Person
}
export function isEventPropertyOrPersonPropertyFilter(
export function isEventPersonOrSessionPropertyFilter(
filter?: AnyFilterLike | null
): filter is EventPropertyFilter | PersonPropertyFilter {
return filter?.type === PropertyFilterType.Event || filter?.type === PropertyFilterType.Person
): filter is EventPropertyFilter | PersonPropertyFilter | SessionPropertyFilter {
return (
filter?.type === PropertyFilterType.Event ||
filter?.type === PropertyFilterType.Person ||
filter?.type === PropertyFilterType.Session
)
}
export function isElementPropertyFilter(filter?: AnyFilterLike | null): filter is ElementPropertyFilter {
return filter?.type === PropertyFilterType.Element
Expand Down Expand Up @@ -264,7 +268,7 @@ const propertyFilterMapping: Partial<Record<PropertyFilterType, TaxonomicFilterG
[PropertyFilterType.Feature]: TaxonomicFilterGroupType.EventFeatureFlags,
[PropertyFilterType.Cohort]: TaxonomicFilterGroupType.Cohorts,
[PropertyFilterType.Element]: TaxonomicFilterGroupType.Elements,
[PropertyFilterType.Session]: TaxonomicFilterGroupType.Sessions,
[PropertyFilterType.Session]: TaxonomicFilterGroupType.SessionProperties,
[PropertyFilterType.HogQL]: TaxonomicFilterGroupType.HogQLExpression,
}

Expand Down Expand Up @@ -308,6 +312,8 @@ export function propertyFilterTypeToPropertyDefinitionType(
? PropertyDefinitionType.Person
: filterType === PropertyFilterType.Group
? PropertyDefinitionType.Group
: filterType === PropertyFilterType.Session
? PropertyDefinitionType.Session
: PropertyDefinitionType.Event
}

Expand Down
2 changes: 2 additions & 0 deletions frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const renderItemContents = ({
listGroupType === TaxonomicFilterGroupType.Events ||
listGroupType === TaxonomicFilterGroupType.CustomEvents ||
listGroupType === TaxonomicFilterGroupType.Metadata ||
listGroupType === TaxonomicFilterGroupType.SessionProperties ||
listGroupType.startsWith(TaxonomicFilterGroupType.GroupsPrefix) ? (
<>
<div className={clsx('taxonomic-list-row-contents', isStale && 'text-muted')}>
Expand Down Expand Up @@ -160,6 +161,7 @@ const selectedItemHasPopover = (
TaxonomicFilterGroupType.Cohorts,
TaxonomicFilterGroupType.CohortsWithAllUsers,
TaxonomicFilterGroupType.Metadata,
TaxonomicFilterGroupType.SessionProperties,
].includes(listGroupType) ||
listGroupType.startsWith(TaxonomicFilterGroupType.GroupsPrefix))
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('taxonomicFilterLogic', () => {
TaxonomicFilterGroupType.Events,
TaxonomicFilterGroupType.Actions,
TaxonomicFilterGroupType.Elements,
TaxonomicFilterGroupType.Sessions,
TaxonomicFilterGroupType.SessionProperties,
],
}
logic = taxonomicFilterLogic(logicProps)
Expand All @@ -62,7 +62,7 @@ describe('taxonomicFilterLogic', () => {
infiniteListLogic({ ...logic.props, listGroupType: TaxonomicFilterGroupType.Events }),
infiniteListLogic({ ...logic.props, listGroupType: TaxonomicFilterGroupType.Actions }),
infiniteListLogic({ ...logic.props, listGroupType: TaxonomicFilterGroupType.Elements }),
infiniteListLogic({ ...logic.props, listGroupType: TaxonomicFilterGroupType.Sessions }),
infiniteListLogic({ ...logic.props, listGroupType: TaxonomicFilterGroupType.SessionProperties }),
])
expect(
infiniteListLogic({ ...logic.props, listGroupType: TaxonomicFilterGroupType.Cohorts }).isMounted()
Expand All @@ -76,7 +76,7 @@ describe('taxonomicFilterLogic', () => {
[TaxonomicFilterGroupType.Events]: 1,
[TaxonomicFilterGroupType.Actions]: 0,
[TaxonomicFilterGroupType.Elements]: 4,
[TaxonomicFilterGroupType.Sessions]: 1,
[TaxonomicFilterGroupType.SessionProperties]: 1,
},
})
.toDispatchActions(['infiniteListResultsReceived'])
Expand All @@ -87,7 +87,7 @@ describe('taxonomicFilterLogic', () => {
[TaxonomicFilterGroupType.Events]: 157,
[TaxonomicFilterGroupType.Actions]: 0, // not mocked
[TaxonomicFilterGroupType.Elements]: 4,
[TaxonomicFilterGroupType.Sessions]: 1,
[TaxonomicFilterGroupType.SessionProperties]: 1,
},
})
})
Expand All @@ -110,7 +110,7 @@ describe('taxonomicFilterLogic', () => {
[TaxonomicFilterGroupType.Events]: 4,
[TaxonomicFilterGroupType.Actions]: 0,
[TaxonomicFilterGroupType.Elements]: 0,
[TaxonomicFilterGroupType.Sessions]: 0,
[TaxonomicFilterGroupType.SessionProperties]: 0,
},
})

Expand All @@ -127,7 +127,7 @@ describe('taxonomicFilterLogic', () => {
[TaxonomicFilterGroupType.Events]: 0,
[TaxonomicFilterGroupType.Actions]: 0,
[TaxonomicFilterGroupType.Elements]: 1,
[TaxonomicFilterGroupType.Sessions]: 0,
[TaxonomicFilterGroupType.SessionProperties]: 0,
},
})

Expand All @@ -144,7 +144,7 @@ describe('taxonomicFilterLogic', () => {
[TaxonomicFilterGroupType.Events]: 0,
[TaxonomicFilterGroupType.Actions]: 0,
[TaxonomicFilterGroupType.Elements]: 0,
[TaxonomicFilterGroupType.Sessions]: 0,
[TaxonomicFilterGroupType.SessionProperties]: 0,
},
})

Expand All @@ -161,13 +161,13 @@ describe('taxonomicFilterLogic', () => {
[TaxonomicFilterGroupType.Events]: 157,
[TaxonomicFilterGroupType.Actions]: 0,
[TaxonomicFilterGroupType.Elements]: 4,
[TaxonomicFilterGroupType.Sessions]: 1,
[TaxonomicFilterGroupType.SessionProperties]: 1,
},
})

// move right, skipping Actions
await expectLogic(logic, () => logic.actions.tabRight()).toMatchValues({
activeTab: TaxonomicFilterGroupType.Sessions,
activeTab: TaxonomicFilterGroupType.SessionProperties,
})
await expectLogic(logic, () => logic.actions.tabRight()).toMatchValues({
activeTab: TaxonomicFilterGroupType.Events,
Expand All @@ -181,7 +181,7 @@ describe('taxonomicFilterLogic', () => {
activeTab: TaxonomicFilterGroupType.Events,
})
await expectLogic(logic, () => logic.actions.tabLeft()).toMatchValues({
activeTab: TaxonomicFilterGroupType.Sessions,
activeTab: TaxonomicFilterGroupType.SessionProperties,
})
await expectLogic(logic, () => logic.actions.tabLeft()).toMatchValues({
activeTab: TaxonomicFilterGroupType.Elements,
Expand All @@ -201,7 +201,7 @@ describe('taxonomicFilterLogic', () => {
[TaxonomicFilterGroupType.Events]: 4,
[TaxonomicFilterGroupType.Actions]: 0,
[TaxonomicFilterGroupType.Elements]: 0,
[TaxonomicFilterGroupType.Sessions]: 0,
[TaxonomicFilterGroupType.SessionProperties]: 0,
},
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
TaxonomicFilterLogicProps,
TaxonomicFilterValue,
} from 'lib/components/TaxonomicFilter/types'
import { FEATURE_FLAGS } from 'lib/constants'
import { IconCohort } from 'lib/lemon-ui/icons'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { CORE_FILTER_DEFINITIONS_BY_GROUP } from 'lib/taxonomy'
import { capitalizeFirstLetter, pluralize, toParams } from 'lib/utils'
import { getEventDefinitionIcon, getPropertyDefinitionIcon } from 'scenes/data-management/events/DefinitionHeader'
Expand Down Expand Up @@ -168,6 +170,7 @@ export const taxonomicFilterLogic = kea<taxonomicFilterLogicType>([
s.metadataSource,
s.excludedProperties,
s.propertyAllowList,
featureFlagLogic.selectors.featureFlags,
],
(
teamId,
Expand All @@ -177,7 +180,8 @@ export const taxonomicFilterLogic = kea<taxonomicFilterLogicType>([
schemaColumns,
metadataSource,
excludedProperties,
propertyAllowList
propertyAllowList,
featureFlags
): TaxonomicFilterGroup[] => {
const groups: TaxonomicFilterGroup[] = [
{
Expand Down Expand Up @@ -486,18 +490,26 @@ export const taxonomicFilterLogic = kea<taxonomicFilterLogicType>([
getPopoverHeader: () => 'Notebooks',
},
{
name: 'Sessions',
name: 'Session Properties',
searchPlaceholder: 'sessions',
type: TaxonomicFilterGroupType.Sessions,
options: [
{
name: 'Session duration',
value: '$session_duration',
},
],
type: TaxonomicFilterGroupType.SessionProperties,
options: featureFlags[FEATURE_FLAGS.SESSION_TABLE_PROPERTY_FILTERS]
? undefined
: [
{
id: '$session_duration',
name: '$session_duration',
property_type: 'Duration',
is_numerical: true,
},
],
getName: (option: any) => option.name,
getValue: (option: any) => option.value,
getValue: (option) => option.name,
getPopoverHeader: () => 'Session',
endpoint: featureFlags[FEATURE_FLAGS.SESSION_TABLE_PROPERTY_FILTERS]
? `api/projects/${teamId}/sessions/property_definitions`
: undefined,
getIcon: getPropertyDefinitionIcon,
},
{
name: 'HogQL',
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/components/TaxonomicFilter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export enum TaxonomicFilterGroupType {
Plugins = 'plugins',
Dashboards = 'dashboards',
GroupNamesPrefix = 'name_groups',
Sessions = 'sessions',
SessionProperties = 'session_properties',
HogQLExpression = 'hogql_expression',
Notebooks = 'notebooks',
}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export const FEATURE_FLAGS = {
EMAIL_VERIFICATION_TICKET_SUBMISSION: 'email-verification-ticket-submission', // owner: #team-growth
TOOLBAR_HEATMAPS: 'toolbar-heatmaps', // owner: #team-replay
THEME: 'theme', // owner: @aprilfools
SESSION_TABLE_PROPERTY_FILTERS: 'session-table-property-filters', // owner: @robbie-c
} as const
export type FeatureFlagKey = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS]

Expand Down
Loading
Loading