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(onboarding): add product config screen #18720

Merged
merged 21 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f203a46
stub out config screen
raquelmsmith Nov 17, 2023
8600f48
saave the configuration
raquelmsmith Nov 17, 2023
090ba08
fix
raquelmsmith Nov 17, 2023
d619a6b
Merge branch 'master' into feat/onboarding-product-config-screen
raquelmsmith Nov 30, 2023
3571c68
add existing replay controls to config
raquelmsmith Nov 30, 2023
e04fc64
dont show any toasts in onboarding
raquelmsmith Nov 30, 2023
565213d
add minimum duration option
raquelmsmith Nov 30, 2023
bf2906d
move dropdown
raquelmsmith Dec 1, 2023
4c1e931
flag the control
raquelmsmith Dec 1, 2023
a20f212
Merge branch 'master' into feat/onboarding-product-config-screen
raquelmsmith Dec 1, 2023
25dd07f
Merge branch 'master' into feat/onboarding-product-config-screen
raquelmsmith Dec 4, 2023
ec4649b
Update frontend/src/scenes/onboarding/Onboarding.tsx
raquelmsmith Dec 5, 2023
be01f8c
Update UI snapshots for `chromium` (1)
github-actions[bot] Dec 5, 2023
b54ff44
Merge branch 'feat/onboarding-product-config-screen' of https://githu…
raquelmsmith Dec 5, 2023
d18c625
Merge branch 'master' into feat/onboarding-product-config-screen
raquelmsmith Dec 5, 2023
8f22d3c
Update UI snapshots for `chromium` (1)
github-actions[bot] Dec 5, 2023
bc63fe8
Update UI snapshots for `chromium` (1)
github-actions[bot] Dec 5, 2023
1174790
Update UI snapshots for `chromium` (1)
github-actions[bot] Dec 5, 2023
b763148
Update UI snapshots for `chromium` (2)
github-actions[bot] Dec 5, 2023
29ce3e8
Update UI snapshots for `chromium` (1)
github-actions[bot] Dec 5, 2023
cd62dfe
Update UI snapshots for `chromium` (2)
github-actions[bot] Dec 5, 2023
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
29 changes: 29 additions & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { LemonSelectOptions } from '@posthog/lemon-ui'

import { AvailableFeature, ChartDisplayType, LicensePlan, Region, SSOProvider } from '../types'

/** Display types which don't allow grouping by unit of time. Sync with backend NON_TIME_SERIES_DISPLAY_TYPES. */
Expand Down Expand Up @@ -263,3 +265,30 @@ export const EVENT_DEFINITIONS_PER_PAGE = 50
export const PROPERTY_DEFINITIONS_PER_EVENT = 5
export const EVENT_PROPERTY_DEFINITIONS_PER_PAGE = 50
export const LOGS_PORTION_LIMIT = 50

export const SESSION_REPLAY_MINIMUM_DURATION_OPTIONS: LemonSelectOptions<number | null> = [
{
label: 'no minimum',
value: null,
},
{
label: '1',
value: 1000,
},
{
label: '2',
value: 2000,
},
{
label: '5',
value: 5000,
},
{
label: '10',
value: 10000,
},
{
label: '15',
value: 15000,
},
]
55 changes: 55 additions & 0 deletions frontend/src/scenes/onboarding/Onboarding.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { useActions, useValues } from 'kea'
import { FEATURE_FLAGS, SESSION_REPLAY_MINIMUM_DURATION_OPTIONS } from 'lib/constants'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { useEffect, useState } from 'react'
import { SceneExport } from 'scenes/sceneTypes'
import { teamLogic } from 'scenes/teamLogic'

import { ProductKey } from '~/types'

import { OnboardingBillingStep } from './OnboardingBillingStep'
import { onboardingLogic, OnboardingStepKey } from './onboardingLogic'
import { OnboardingOtherProductsStep } from './OnboardingOtherProductsStep'
import { OnboardingProductConfiguration } from './OnboardingProductConfiguration'
import { ProductConfigOption } from './onboardingProductConfigurationLogic'
import { OnboardingVerificationStep } from './OnboardingVerificationStep'
import { FeatureFlagsSDKInstructions } from './sdks/feature-flags/FeatureFlagsSDKInstructions'
import { ProductAnalyticsSDKInstructions } from './sdks/product-analytics/ProductAnalyticsSDKInstructions'
Expand Down Expand Up @@ -65,6 +70,8 @@ const OnboardingWrapper = ({ children }: { children: React.ReactNode }): JSX.Ele
}

const ProductAnalyticsOnboarding = (): JSX.Element => {
const { currentTeam } = useValues(teamLogic)

return (
<OnboardingWrapper>
<SDKs
Expand All @@ -77,10 +84,57 @@ const ProductAnalyticsOnboarding = (): JSX.Element => {
teamPropertyToVerify="ingested_event"
stepKey={OnboardingStepKey.VERIFY}
/>
<OnboardingProductConfiguration
stepKey={OnboardingStepKey.PRODUCT_CONFIGURATION}
options={[
{
title: 'Autocapture frontend interactions',
description: `If you use our JavaScript or React Native libraries, we'll automagically
capture frontend interactions like pageviews, clicks, and more. Fine-tune what you
capture directly in your code snippet.`,
teamProperty: 'autocapture_opt_out',
value: !currentTeam?.autocapture_opt_out,
type: 'toggle',
inverseToggle: true,
},
]}
/>
</OnboardingWrapper>
)
Copy link
Member

Choose a reason for hiding this comment

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

Ha, github won't let me comment on the replay lines because they've not changed 🙈

Would be cool to have the basic settings here
Screenshot 2023-11-30 at 10 08 05

Ultimately we'll want the cost controls here too

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep! Planning on picking this up again today 👍

}
const SessionReplayOnboarding = (): JSX.Element => {
const { featureFlags } = useValues(featureFlagLogic)
const configOptions: ProductConfigOption[] = [
{
type: 'toggle',
title: 'Capture console logs',
description: `Capture console logs as a part of user session recordings.
Use the console logs alongside recordings to debug any issues with your app.`,
teamProperty: 'capture_console_log_opt_in',
value: true,
},
{
type: 'toggle',
title: 'Capture network performance',
description: `Capture performance and network information alongside recordings. Use the
network requests and timings in the recording player to help you debug issues with your app.`,
teamProperty: 'capture_performance_opt_in',
value: true,
},
]

if (featureFlags[FEATURE_FLAGS.SESSION_RECORDING_SAMPLING] === true) {
configOptions.push({
type: 'select',
title: 'Minimum session duration (seconds)',
description: `Only record sessions that are longer than the specified duration.
Start with it low and increase it later if you're getting too many short sessions.`,
teamProperty: 'session_recording_minimum_duration_milliseconds',
value: null,
selectOptions: SESSION_REPLAY_MINIMUM_DURATION_OPTIONS,
})
}

return (
<OnboardingWrapper>
<SDKs
Expand All @@ -89,6 +143,7 @@ const SessionReplayOnboarding = (): JSX.Element => {
subtitle="Choose the framework your frontend is built on, or use our all-purpose JavaScript library. If you already have the snippet installed, you can skip this step!"
stepKey={OnboardingStepKey.SDKS}
/>
<OnboardingProductConfiguration stepKey={OnboardingStepKey.PRODUCT_CONFIGURATION} options={configOptions} />
</OnboardingWrapper>
)
}
Expand Down
68 changes: 68 additions & 0 deletions frontend/src/scenes/onboarding/OnboardingProductConfiguration.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { LemonSelect, LemonSwitch } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { useEffect } from 'react'

import { OnboardingStepKey } from './onboardingLogic'
import { onboardingProductConfigurationLogic, ProductConfigOption } from './onboardingProductConfigurationLogic'
import { OnboardingStep } from './OnboardingStep'

export const OnboardingProductConfiguration = ({
stepKey = OnboardingStepKey.PRODUCT_CONFIGURATION,
options,
}: {
stepKey?: OnboardingStepKey
options: ProductConfigOption[]
}): JSX.Element | null => {
const { configOptions } = useValues(onboardingProductConfigurationLogic)
const { setConfigOptions, saveConfiguration } = useActions(onboardingProductConfigurationLogic)
useEffect(() => {
setConfigOptions(options)
}, [])

return configOptions ? (
<OnboardingStep title={`Set up your configuration`} stepKey={stepKey} continueAction={saveConfiguration}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a bit more clear to say "Configure ${product.name}"?

{configOptions?.map((option: ProductConfigOption) => (
<div className="my-8" key={option.teamProperty}>
{option.type == 'toggle' ? (
<>
<LemonSwitch
data-attr="opt-in-session-recording-switch"
onChange={(checked) => {
setConfigOptions(
configOptions.map((o) =>
o.teamProperty === option.teamProperty ? { ...o, value: checked } : o
)
)
}}
label={option.title}
fullWidth={true}
labelClassName={'text-base font-semibold'}
checked={option.value || false}
/>
<p className="prompt-text ml-0">{option.description}</p>
</>
) : (
<>
<label className="text-base font-semibold">{option.title}</label>
<div className="flex justify-between items-center mb-1 gap-x-4">
<p className="prompt-text m-0">{option.description}</p>
<LemonSelect
dropdownMatchSelectWidth={false}
onChange={(v) => {
setConfigOptions(
configOptions.map((o) =>
o.teamProperty === option.teamProperty ? { ...o, value: v } : o
)
)
}}
options={option.selectOptions || []}
value={option.value}
/>
</div>
</>
)}
</div>
))}
</OnboardingStep>
) : null
}
7 changes: 6 additions & 1 deletion frontend/src/scenes/onboarding/OnboardingStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const OnboardingStep = ({
children,
showSkip = false,
onSkip,
continueAction,
continueOverride,
backActionOverride,
}: {
Expand All @@ -23,6 +24,7 @@ export const OnboardingStep = ({
children: React.ReactNode
showSkip?: boolean
onSkip?: () => void
continueAction?: () => void
continueOverride?: JSX.Element
backActionOverride?: () => void
}): JSX.Element => {
Expand Down Expand Up @@ -77,7 +79,10 @@ export const OnboardingStep = ({
) : (
<LemonButton
type="primary"
onClick={() => (!hasNextStep ? completeOnboarding() : goToNextStep())}
onClick={() => {
continueAction && continueAction()
!hasNextStep ? completeOnboarding() : goToNextStep()
}}
sideIcon={hasNextStep ? <IconArrowRight /> : null}
>
{!hasNextStep ? 'Finish' : 'Continue'}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/onboarding/onboardingLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export enum OnboardingStepKey {
BILLING = 'billing',
OTHER_PRODUCTS = 'other_products',
VERIFY = 'verify',
PRODUCT_CONFIGURATION = 'configure',
}

// These types have to be set like this, so that kea typegen is happy
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { LemonSelectOptions } from '@posthog/lemon-ui'
import { actions, connect, kea, listeners, path, reducers } from 'kea'
import { teamLogic } from 'scenes/teamLogic'

import type { onboardingProductConfigurationLogicType } from './onboardingProductConfigurationLogicType'

export interface ProductConfigOptionBase {
title: string
description: string
teamProperty: string
}

export interface ProductConfigurationToggle extends ProductConfigOptionBase {
type: 'toggle'
/** Sets the initial value. Use a team setting to reflect current state, or a static value to set a default. */
value: boolean
/** If true, the value is inverted when saving, used for 'opt_out' type settings */
inverseToggle?: boolean
}

export interface ProductConfigurationSelect extends ProductConfigOptionBase {
type: 'select'
/** Sets the initial value. Use a team setting to reflect current state, or a static value to set a default. */
value: string | number | null
selectOptions: LemonSelectOptions<any>
}

export type ProductConfigOption = ProductConfigurationToggle | ProductConfigurationSelect

export const onboardingProductConfigurationLogic = kea<onboardingProductConfigurationLogicType>([
path(() => ['scenes', 'onboarding', 'onboardingProductConfigurationLogic']),
connect({
actions: [teamLogic, ['updateCurrentTeam']],
}),
actions({
setConfigOptions: (configOptions: ProductConfigOption[]) => ({ configOptions }),
saveConfiguration: true,
}),
reducers(() => ({
configOptions: [
[],
{
setConfigOptions: (_, { configOptions }) => configOptions,
},
],
})),
listeners(({ values, actions }) => ({
saveConfiguration: async () => {
const updateConfig = {}
values.configOptions.forEach((configOption) => {
updateConfig[configOption.teamProperty] = configOption.inverseToggle
? !configOption.value
: configOption.value
})
actions.updateCurrentTeam(updateConfig)
},
})),
])
29 changes: 2 additions & 27 deletions frontend/src/scenes/settings/project/SessionRecordingSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AuthorizedUrlList } from 'lib/components/AuthorizedUrlList/AuthorizedUr
import { AuthorizedUrlListType } from 'lib/components/AuthorizedUrlList/authorizedUrlListLogic'
import { FlaggedFeature } from 'lib/components/FlaggedFeature'
import { FlagSelector } from 'lib/components/FlagSelector'
import { FEATURE_FLAGS } from 'lib/constants'
import { FEATURE_FLAGS, SESSION_REPLAY_MINIMUM_DURATION_OPTIONS } from 'lib/constants'
import { IconCancel } from 'lib/lemon-ui/icons'
import { LemonLabel } from 'lib/lemon-ui/LemonLabel/LemonLabel'
import { teamLogic } from 'scenes/teamLogic'
Expand Down Expand Up @@ -305,32 +305,7 @@ export function ReplayCostControl(): JSX.Element {
onChange={(v) => {
updateCurrentTeam({ session_recording_minimum_duration_milliseconds: v })
}}
options={[
{
label: 'no minimum',
value: null,
},
{
label: '1',
value: 1000,
},
{
label: '2',
value: 2000,
},
{
label: '5',
value: 5000,
},
{
label: '10',
value: 10000,
},
{
label: '15',
value: 15000,
},
]}
options={SESSION_REPLAY_MINIMUM_DURATION_OPTIONS}
value={currentTeam?.session_recording_minimum_duration_milliseconds}
/>
</div>
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/scenes/teamLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ export const teamLogic = kea<teamLogicType>([
eventUsageLogic.findMounted()?.actions?.reportTeamSettingChange(property, payload[property])
})

lemonToast.success(message)
if (!window.location.pathname.match(/\/(onboarding|products)/)) {
lemonToast.success(message)
}

return patchedTeam
},
Expand Down
Loading