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: Add human friendly comparison periods toggle #27176

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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/api.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const MOCK_DEFAULT_TEAM: TeamType = {
person_on_events_querying_enabled: true,
live_events_token: '123',
capture_dead_clicks: false,
human_friendly_comparison_periods: false,
}

export const MOCK_DEFAULT_PROJECT: ProjectType = {
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/settings/SettingsMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { DataAttributes } from './environment/DataAttributes'
import { DataColorThemes } from './environment/DataColorThemes'
import { GroupAnalyticsConfig } from './environment/GroupAnalyticsConfig'
import { HeatmapsSettings } from './environment/HeatmapsSettings'
import { HumanFriendlyComparisonPeriodsSetting } from './environment/HumanFriendlyComparisonPeriodsSetting'
import { IPAllowListInfo } from './environment/IPAllowListInfo'
import { IPCapture } from './environment/IPCapture'
import { ManagedReverseProxy } from './environment/ManagedReverseProxy'
Expand Down Expand Up @@ -191,6 +192,11 @@ export const SETTINGS_MAP: SettingSection[] = [
title: 'IP data capture configuration',
component: <IPCapture />,
},
{
id: 'human-friendly-comparison-periods',
title: 'Human friendly comparison periods',
component: <HumanFriendlyComparisonPeriodsSetting />,
},
{
id: 'group-analytics',
title: 'Group analytics',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { LemonSwitch } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { teamLogic } from 'scenes/teamLogic'

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

return (
<>
<p>
When comparing against a previous month or year, PostHog will use the same start and end dates as the
current period by default. It might be desirable, however, to compare against the same day of the week
instead of the same day to account for weekend seasonality. If that's the case for your analysis, you
can enable this setting.
</p>
<p>
In practice, this means that an year comparison becomes a 52 week comparison, and a month comparison
becomes a 4 week comparison.
</p>
<LemonSwitch
onChange={(checked) => {
updateCurrentTeam({ human_friendly_comparison_periods: checked })
}}
checked={!!currentTeam?.human_friendly_comparison_periods}
disabled={currentTeamLoading}
label="Use human friendly comparison periods"
bordered
/>
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ exports[`verifiedDomainsLogic values has proper defaults 1`] = `
"effective_membership_level": 8,
"has_group_types": true,
"heatmaps_opt_in": true,
"human_friendly_comparison_periods": false,
"id": 997,
"ingested_event": true,
"is_demo": false,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/settings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export type SettingId =
| 'person-display-name'
| 'path-cleaning'
| 'datacapture'
| 'human-friendly-comparison-periods'
| 'group-analytics'
| 'persons-on-events'
| 'replay'
Expand Down
95 changes: 56 additions & 39 deletions frontend/src/scenes/teamActivityDescriber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -305,29 +305,6 @@ const teamActionsMapping: Record<
],
}
},
// TODO if I had to test and describe every single one of this I'd never release this
// we can add descriptions here as the need arises
access_control: () => null,
anonymize_ips: () => null,
app_urls: () => null,
completed_snippet_onboarding: () => null,
correlation_config: () => null,
data_attributes: () => null,
effective_membership_level: () => null,
has_group_types: () => null,
ingested_event: () => null,
is_demo: () => null,
live_events_columns: () => null,
organization: () => null,
project_id: () => null,
path_cleaning_filters: () => null,
person_display_name_properties: () => null,
person_on_events_querying_enabled: () => null,
primary_dashboard: () => null,
slack_incoming_webhook: () => null,
timezone: () => null,
surveys_opt_in: () => null,
week_start_day: () => null,
extra_settings: (change: ActivityChange | undefined): ChangeMapping | null => {
const after = change?.after
if (typeof after !== 'object') {
Expand All @@ -336,7 +313,9 @@ const teamActionsMapping: Record<
const descriptions = []
for (const key in after) {
if (key === 'poe_v2_enabled') {
descriptions.push(<>{after[key] ? 'enabled' : 'disabled'} Person on Events (v2)</>)
descriptions.push(
<>{after[key as keyof typeof after] ? 'enabled' : 'disabled'} Person on Events (v2)</>
)
}
}
return { description: descriptions }
Expand All @@ -350,24 +329,13 @@ const teamActionsMapping: Record<
for (const key in after) {
descriptions.push(
<>
set <em>{key}</em> to "{String(after[key])}"
set <em>{key}</em> to "{String(after[key as keyof typeof after])}"
</>
)
}
return { description: descriptions }
},
default_modifiers: () => null,
has_completed_onboarding_for: () => null,
// should never come from the backend
created_at: () => null,
api_token: () => null,
id: () => null,
updated_at: () => null,
uuid: () => null,
user_access_level: () => null,
live_events_token: () => null,
product_intents: () => null,
default_data_theme: (change) => {
default_data_theme: (change): ChangeMapping | null => {
return {
description: [
<>
Expand All @@ -385,6 +353,55 @@ const teamActionsMapping: Record<
],
}
},
human_friendly_comparison_periods: (change): ChangeMapping | null => {
if (!change) {
return null
}

return {
description: [
<>
<strong>{change?.after ? 'enabled' : 'disabled'}</strong> human friendly comparison periods
</>,
],
}
},

// TODO if I had to test and describe every single one of this I'd never release this
// we can add descriptions here as the need arises
access_control: () => null,
anonymize_ips: () => null,
app_urls: () => null,
completed_snippet_onboarding: () => null,
correlation_config: () => null,
data_attributes: () => null,
effective_membership_level: () => null,
has_group_types: () => null,
ingested_event: () => null,
is_demo: () => null,
live_events_columns: () => null,
organization: () => null,
project_id: () => null,
path_cleaning_filters: () => null,
person_display_name_properties: () => null,
person_on_events_querying_enabled: () => null,
primary_dashboard: () => null,
slack_incoming_webhook: () => null,
timezone: () => null,
surveys_opt_in: () => null,
week_start_day: () => null,
default_modifiers: () => null,
has_completed_onboarding_for: () => null,

// should never come from the backend
created_at: () => null,
api_token: () => null,
id: () => null,
updated_at: () => null,
uuid: () => null,
user_access_level: () => null,
live_events_token: () => null,
product_intents: () => null,
cookieless_server_hash_mode: () => null,
}

Expand All @@ -409,11 +426,11 @@ export function teamActivityDescriber(logItem: ActivityLogItem, asNotification?:
let changeSuffix: Description = <>on {nameAndLink(logItem)}</>

for (const change of logItem.detail.changes || []) {
if (!change?.field || !teamActionsMapping[change.field]) {
if (!change?.field || !(change.field in teamActionsMapping)) {
continue // not all notebook fields are describable
}

const actionHandler = teamActionsMapping[change.field]
const actionHandler = teamActionsMapping[change.field as keyof TeamType]
const processedChange = actionHandler(change, logItem)
if (processedChange === null) {
continue // // unexpected log from backend is indescribable
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ export interface TeamType extends TeamBasicType {
live_events_columns: string[] | null // Custom columns shown on the Live Events page
live_events_token: string
cookieless_server_hash_mode?: CookielessServerHashMode
human_friendly_comparison_periods: boolean

/** Effective access level of the user in this specific team. Null if user has no access. */
effective_membership_level: OrganizationMembershipLevel | null
Expand Down
1 change: 1 addition & 0 deletions posthog/api/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ class Meta:
"live_events_columns",
"recording_domains",
"cookieless_server_hash_mode",
"human_friendly_comparison_periods",
"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 @@ -83,6 +83,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."human_friendly_comparison_periods",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."default_data_theme",
Expand Down Expand Up @@ -390,6 +391,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."human_friendly_comparison_periods",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."default_data_theme",
Expand Down Expand Up @@ -906,6 +908,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."human_friendly_comparison_periods",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."default_data_theme",
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 @@ -83,6 +83,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."human_friendly_comparison_periods",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."default_data_theme",
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"."human_friendly_comparison_periods",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."default_data_theme",
Expand Down Expand Up @@ -833,6 +835,7 @@
"posthog_team"."person_display_name_properties",
"posthog_team"."live_events_columns",
"posthog_team"."recording_domains",
"posthog_team"."human_friendly_comparison_periods",
"posthog_team"."cookieless_server_hash_mode",
"posthog_team"."primary_dashboard_id",
"posthog_team"."default_data_theme",
Expand Down
Loading
Loading