Skip to content

Commit

Permalink
feat(web-analytics): Add a DB field cookieless_server_hash_mode to a …
Browse files Browse the repository at this point in the history
…team, and setting to change it behind a flag (#27059)

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
robbie-c and github-actions[bot] authored Dec 20, 2024
1 parent f55dca1 commit f203ab5
Show file tree
Hide file tree
Showing 30 changed files with 414 additions and 7 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ export const FEATURE_FLAGS = {
EXPERIMENT_STATS_V2: 'experiment-stats-v2', // owner: @danielbachhuber #team-experiments
WEB_ANALYTICS_PERIOD_COMPARISON: 'web-analytics-period-comparison', // owner: @rafaeelaudibert #team-web-analytics
WEB_ANALYTICS_CONVERSION_GOAL_FILTERS: 'web-analytics-conversion-goal-filters', // owner: @rafaeelaudibert #team-web-analytics
COOKIELESS_SERVER_HASH_MODE_SETTING: 'cookieless-server-hash-mode-setting', // owner: @robbie-c #team-web-analytics
} as const
export type FeatureFlagKey = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS]

Expand Down
7 changes: 7 additions & 0 deletions frontend/src/scenes/settings/SettingsMap.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BounceRatePageViewModeSetting } from 'scenes/settings/environment/BounceRatePageViewMode'
import { CookielessServerHashModeSetting } from 'scenes/settings/environment/CookielessServerHashMode'
import { CustomChannelTypes } from 'scenes/settings/environment/CustomChannelTypes'
import { DeadClicksAutocaptureSettings } from 'scenes/settings/environment/DeadClicksAutocaptureSettings'
import { PersonsJoinMode } from 'scenes/settings/environment/PersonsJoinMode'
Expand Down Expand Up @@ -218,6 +219,12 @@ export const SETTINGS_MAP: SettingSection[] = [
title: 'Custom channel type',
component: <CustomChannelTypes />,
},
{
id: 'cookieless-server-hash-mode',
title: 'Cookieless server hash mode',
component: <CookielessServerHashModeSetting />,
flag: 'COOKIELESS_SERVER_HASH_MODE_SETTING',
},
],
},

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useActions, useValues } from 'kea'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { LemonRadio, LemonRadioOption } from 'lib/lemon-ui/LemonRadio'
import { useState } from 'react'
import { teamLogic } from 'scenes/teamLogic'

import { CookielessServerHashMode } from '~/types'

const options: LemonRadioOption<CookielessServerHashMode>[] = [
{
value: CookielessServerHashMode.Stateful,
label: (
<>
<div>Stateful</div>
</>
),
},
{
value: CookielessServerHashMode.Stateless,
label: (
<>
<div>Stateless</div>
</>
),
},
{
value: CookielessServerHashMode.Disabled,
label: (
<>
<div>Disabled</div>
</>
),
},
]

export function CookielessServerHashModeSetting(): JSX.Element {
const { updateCurrentTeam } = useActions(teamLogic)
const { currentTeam } = useValues(teamLogic)

const savedSetting = currentTeam?.cookieless_server_hash_mode ?? CookielessServerHashMode.Disabled
const [setting, setSetting] = useState<CookielessServerHashMode>(savedSetting)

const handleChange = (newSetting: CookielessServerHashMode): void => {
updateCurrentTeam({ cookieless_server_hash_mode: newSetting })
}

return (
<>
<p>
Use a cookieless server-side hash mode to hash user data. This is an experimental feature preview and
may result in dropped events.
</p>
<LemonRadio value={setting} onChange={setSetting} options={options} />
<div className="mt-4">
<LemonButton
type="primary"
onClick={() => handleChange(setting)}
disabledReason={setting === savedSetting ? 'No changes to save' : undefined}
>
Save
</LemonButton>
</div>
</>
)
}
1 change: 1 addition & 0 deletions frontend/src/scenes/settings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export type SettingId =
| 'web-vitals-autocapture'
| 'dead-clicks-autocapture'
| 'channel-type'
| 'cookieless-server-hash-mode'

type FeatureFlagKey = keyof typeof FEATURE_FLAGS

Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/teamActivityDescriber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ const teamActionsMapping: Record<
user_access_level: () => null,
live_events_token: () => null,
product_intents: () => null,
cookieless_server_hash_mode: () => null,
}

function nameAndLink(logItem?: ActivityLogItem): JSX.Element {
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ export interface TeamType extends TeamBasicType {
primary_dashboard: number // Dashboard shown on the project homepage
live_events_columns: string[] | null // Custom columns shown on the Live Events page
live_events_token: string
cookieless_server_hash_mode?: CookielessServerHashMode

/** Effective access level of the user in this specific team. Null if user has no access. */
effective_membership_level: OrganizationMembershipLevel | null
Expand Down Expand Up @@ -4829,6 +4830,12 @@ export type ReplayTemplateVariableType = {
noTouch?: boolean
}

export enum CookielessServerHashMode {
Disabled = 0,
Stateless = 1,
Stateful = 2,
}

/**
* Assistant Conversation
*/
Expand Down
10 changes: 9 additions & 1 deletion plugin-server/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,12 @@ export enum PluginLogLevel {
Critical = 4, // only error type and system source
}

export enum CookielessServerHashMode {
Disabled = 0,
Stateless = 1,
Stateful = 2,
}

export interface PluginLogEntry {
id: string
team_id: number
Expand Down Expand Up @@ -633,13 +639,15 @@ export interface Team {
api_token: string
slack_incoming_webhook: string | null
session_recording_opt_in: boolean
person_processing_opt_out?: boolean
person_processing_opt_out: boolean | null
heatmaps_opt_in: boolean | null
ingested_event: boolean
person_display_name_properties: string[] | null
test_account_filters:
| (EventPropertyFilter | PersonPropertyFilter | ElementPropertyFilter | CohortPropertyFilter)[]
| null
cookieless_server_hash_mode: CookielessServerHashMode | null
timezone: string
}

/** Properties shared by RawEventMessage and EventMessage. */
Expand Down
9 changes: 7 additions & 2 deletions plugin-server/src/worker/ingestion/team-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,9 @@ export async function fetchTeam(client: PostgresRouter, teamId: Team['id']): Pro
heatmaps_opt_in,
ingested_event,
person_display_name_properties,
test_account_filters
test_account_filters,
cookieless_server_hash_mode,
timezone
FROM posthog_team
WHERE id = $1
`,
Expand Down Expand Up @@ -203,7 +205,10 @@ export async function fetchTeamByToken(client: PostgresRouter, token: string): P
person_processing_opt_out,
heatmaps_opt_in,
ingested_event,
test_account_filters
person_display_name_properties,
test_account_filters,
cookieless_server_hash_mode,
timezone
FROM posthog_team
WHERE api_token = $1
LIMIT 1
Expand Down
11 changes: 8 additions & 3 deletions plugin-server/tests/main/db.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,7 @@ describe('DB', () => {
anonymize_ips: false,
api_token: 'token1',
id: teamId,
project_id: teamId,
project_id: teamId as Team['project_id'],
ingested_event: true,
name: 'TEST PROJECT',
organization_id: organizationId,
Expand All @@ -866,6 +866,8 @@ describe('DB', () => {
uuid: expect.any(String),
person_display_name_properties: [],
test_account_filters: {} as any, // NOTE: Test insertion data gets set as an object weirdly
cookieless_server_hash_mode: null,
timezone: 'UTC',
} as Team)
})

Expand All @@ -885,17 +887,20 @@ describe('DB', () => {
anonymize_ips: false,
api_token: 'token2',
id: teamId,
project_id: teamId,
project_id: teamId as Team['project_id'],
ingested_event: true,
name: 'TEST PROJECT',
organization_id: organizationId,
session_recording_opt_in: true,
person_processing_opt_out: null,
person_display_name_properties: [],
heatmaps_opt_in: null,
slack_incoming_webhook: null,
uuid: expect.any(String),
test_account_filters: {} as any, // NOTE: Test insertion data gets set as an object weirdly
})
cookieless_server_hash_mode: null,
timezone: 'UTC',
} as Team)
})

it('returns null if the team does not exist', async () => {
Expand Down
1 change: 1 addition & 0 deletions posthog/api/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class Meta:
"primary_dashboard",
"live_events_columns",
"recording_domains",
"cookieless_server_hash_mode",
"person_on_events_querying_enabled",
"inject_web_apps",
"extra_settings",
Expand Down
3 changes: 3 additions & 0 deletions posthog/api/test/__snapshots__/test_action.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."extra_settings",
"posthog_team"."modifiers",
Expand Down Expand Up @@ -385,6 +386,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."extra_settings",
"posthog_team"."modifiers",
Expand Down Expand Up @@ -896,6 +898,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."extra_settings",
"posthog_team"."modifiers",
Expand Down
3 changes: 3 additions & 0 deletions posthog/api/test/__snapshots__/test_annotation.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."extra_settings",
"posthog_team"."modifiers",
Expand Down Expand Up @@ -380,6 +381,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."extra_settings",
"posthog_team"."modifiers",
Expand Down Expand Up @@ -824,6 +826,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."extra_settings",
"posthog_team"."modifiers",
Expand Down
Loading

0 comments on commit f203ab5

Please sign in to comment.