Skip to content

Commit

Permalink
Merge branch 'master' into playwright-wait-for-image-load
Browse files Browse the repository at this point in the history
  • Loading branch information
thmsobrmlr committed Jul 23, 2024
2 parents d3357a4 + 2fbb589 commit 461d355
Show file tree
Hide file tree
Showing 150 changed files with 2,334 additions and 1,762 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
"WORKER_CONCURRENCY": "2",
"OBJECT_STORAGE_ENABLED": "True",
"HOG_HOOK_URL": "http://localhost:3300/hoghook",
"CDP_ASYNC_FUNCTIONS_RUSTY_HOOK_TEAMS": "*"
"CDP_ASYNC_FUNCTIONS_RUSTY_HOOK_TEAMS": ""
},
"presentation": {
"group": "main"
Expand Down
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.
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.
15 changes: 15 additions & 0 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
ActionType,
ActivityScope,
AlertType,
AppMetricsTotalsV2Response,
AppMetricsV2RequestParams,
AppMetricsV2Response,
BatchExportConfiguration,
BatchExportRun,
CohortType,
Expand Down Expand Up @@ -1626,6 +1629,18 @@ const api = {
): Promise<PaginatedResponse<LogEntry>> {
return await new ApiRequest().hogFunction(id).withAction('logs').withQueryString(params).get()
},
async metrics(
id: HogFunctionType['id'],
params: AppMetricsV2RequestParams = {}
): Promise<AppMetricsV2Response> {
return await new ApiRequest().hogFunction(id).withAction('metrics').withQueryString(params).get()
},
async metricsTotals(
id: HogFunctionType['id'],
params: Partial<AppMetricsV2RequestParams> = {}
): Promise<AppMetricsTotalsV2Response> {
return await new ApiRequest().hogFunction(id).withAction('metrics/totals').withQueryString(params).get()
},

async listTemplates(): Promise<PaginatedResponse<HogFunctionTemplateType>> {
return await new ApiRequest().hogFunctionTemplates().get()
Expand Down
89 changes: 37 additions & 52 deletions frontend/src/lib/components/PayGateMini/PayGateButton.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,49 @@
import { LemonButton } from '@posthog/lemon-ui'
import { LemonButton, LemonButtonProps } from '@posthog/lemon-ui'
import { useValues } from 'kea'
import { useMemo } from 'react'
import { urls } from 'scenes/urls'

import { BillingFeatureType, BillingProductV2AddonType, BillingProductV2Type } from '~/types'
import { payGateMiniLogic, PayGateMiniLogicProps } from './payGateMiniLogic'

interface PayGateButtonProps {
gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null
productWithFeature: BillingProductV2AddonType | BillingProductV2Type
featureInfo: BillingFeatureType
onCtaClick: () => void
isAddonProduct?: boolean
scrollToProduct: boolean
}
type PayGateButtonProps = PayGateMiniLogicProps & Partial<LemonButtonProps>
export const PayGateButton = ({ feature, currentUsage, ...buttonProps }: PayGateButtonProps): JSX.Element | null => {
const { productWithFeature, featureInfo, gateVariant, isAddonProduct, scrollToProduct } = useValues(
payGateMiniLogic({ feature, currentUsage })
)

const ctaLink = useMemo(() => {
if (gateVariant === 'add-card' && !isAddonProduct) {
return `/api/billing/activate?products=all_products:&redirect_path=${urls.organizationBilling()}&intent_product=${
productWithFeature?.type
}`
} else if (gateVariant === 'add-card') {
return `/organization/billing${scrollToProduct ? `?products=${productWithFeature?.type}` : ''}`
} else if (gateVariant === 'contact-sales') {
return `mailto:[email protected]?subject=Inquiring about ${featureInfo?.name}`
} else if (gateVariant === 'move-to-cloud') {
return 'https://us.posthog.com/signup?utm_medium=in-product&utm_campaign=move-to-cloud'
}
return undefined
}, [gateVariant, isAddonProduct, productWithFeature, featureInfo, scrollToProduct])

const ctaLabel = useMemo(() => {
if (gateVariant === 'add-card') {
return 'Upgrade now'
} else if (gateVariant === 'contact-sales') {
return 'Contact sales'
}
return 'Move to PostHog Cloud'
}, [gateVariant])

export const PayGateButton = ({
gateVariant,
productWithFeature,
featureInfo,
onCtaClick,
isAddonProduct,
scrollToProduct = true,
}: PayGateButtonProps): JSX.Element => {
return (
<LemonButton
to={getCtaLink(gateVariant, productWithFeature, featureInfo, isAddonProduct, scrollToProduct)}
disableClientSideRouting={gateVariant === 'add-card' && !isAddonProduct}
type="primary"
center
onClick={onCtaClick}
{...buttonProps}
to={ctaLink}
disableClientSideRouting={gateVariant === 'add-card' && !isAddonProduct}
>
{getCtaLabel(gateVariant)}
{ctaLabel}
</LemonButton>
)
}

const getCtaLink = (
gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null,
productWithFeature: BillingProductV2AddonType | BillingProductV2Type,
featureInfo: BillingFeatureType,
isAddonProduct?: boolean,
scrollToProduct: boolean = true
): string | undefined => {
if (gateVariant === 'add-card' && !isAddonProduct) {
return `/api/billing/activate?products=all_products:&redirect_path=${urls.organizationBilling()}&intent_product=${
productWithFeature.type
}`
} else if (gateVariant === 'add-card') {
return `/organization/billing${scrollToProduct ? `?products=${productWithFeature.type}` : ''}`
} else if (gateVariant === 'contact-sales') {
return `mailto:[email protected]?subject=Inquiring about ${featureInfo.name}`
} else if (gateVariant === 'move-to-cloud') {
return 'https://us.posthog.com/signup?utm_medium=in-product&utm_campaign=move-to-cloud'
}
return undefined
}

const getCtaLabel = (gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null): string => {
if (gateVariant === 'add-card') {
return 'Upgrade now'
} else if (gateVariant === 'contact-sales') {
return 'Contact sales'
}
return 'Move to PostHog Cloud'
}
65 changes: 23 additions & 42 deletions frontend/src/lib/components/PayGateMini/PayGateMini.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ import { AvailableFeature, BillingFeatureType, BillingProductV2AddonType, Billin

import { upgradeModalLogic } from '../UpgradeModal/upgradeModalLogic'
import { PayGateButton } from './PayGateButton'
import { payGateMiniLogic } from './payGateMiniLogic'
import { payGateMiniLogic, PayGateMiniLogicProps } from './payGateMiniLogic'

export interface PayGateMiniProps {
feature: AvailableFeature
currentUsage?: number
export type PayGateMiniProps = PayGateMiniLogicProps & {
/**
* The content to show when the feature is available. Will show nothing if children is undefined.
*/
Expand All @@ -43,20 +41,11 @@ export function PayGateMini({
isGrandfathered,
docsLink,
}: PayGateMiniProps): JSX.Element | null {
const {
productWithFeature,
featureInfo,
featureAvailableOnOrg,
gateVariant,
isAddonProduct,
featureInfoOnNextPlan,
} = useValues(payGateMiniLogic({ featureKey: feature, currentUsage }))
const { productWithFeature, featureInfo, gateVariant } = useValues(payGateMiniLogic({ feature, currentUsage }))
const { preflight, isCloudOrDev } = useValues(preflightLogic)
const { billingLoading } = useValues(billingLogic)
const { hideUpgradeModal } = useActions(upgradeModalLogic)

const scrollToProduct = !(featureInfo?.key === AvailableFeature.ORGANIZATIONS_PROJECTS && !isAddonProduct)

useEffect(() => {
if (gateVariant) {
posthog.capture('pay gate shown', {
Expand Down Expand Up @@ -87,26 +76,15 @@ export function PayGateMini({
if (gateVariant && productWithFeature && featureInfo && !overrideShouldShowGate) {
return (
<PayGateContent
feature={feature}
currentUsage={currentUsage}
className={className}
background={background}
featureInfo={featureInfo}
featureAvailableOnOrg={featureAvailableOnOrg}
gateVariant={gateVariant}
productWithFeature={productWithFeature}
isGrandfathered={isGrandfathered}
isAddonProduct={isAddonProduct}
featureInfoOnNextPlan={featureInfoOnNextPlan}
handleCtaClick={handleCtaClick}
>
<div className="flex items-center justify-center space-x-3">
<PayGateButton
gateVariant={gateVariant}
productWithFeature={productWithFeature}
featureInfo={featureInfo}
onCtaClick={handleCtaClick}
scrollToProduct={scrollToProduct}
isAddonProduct={isAddonProduct}
/>
<PayGateButton feature={feature} currentUsage={currentUsage} onClick={handleCtaClick} />
{docsLink && isCloudOrDev && (
<LemonButton
type="secondary"
Expand All @@ -126,33 +104,36 @@ export function PayGateMini({
return <div className={className}>{children}</div>
}

interface PayGateContentProps {
interface PayGateContentProps extends PayGateMiniLogicProps {
className?: string
background: boolean
featureInfo: BillingFeatureType
featureAvailableOnOrg?: BillingFeatureType | null
gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null
productWithFeature: BillingProductV2AddonType | BillingProductV2Type
isGrandfathered?: boolean
isAddonProduct?: boolean
featureInfoOnNextPlan?: BillingFeatureType
children: React.ReactNode
handleCtaClick: () => void
}

function PayGateContent({
feature,
currentUsage,
className,
background,
featureInfo,
featureAvailableOnOrg,
gateVariant,
productWithFeature,
isGrandfathered,
isAddonProduct,
featureInfoOnNextPlan,
children,
handleCtaClick,
}: PayGateContentProps): JSX.Element {
}: PayGateContentProps): JSX.Element | null {
const {
productWithFeature,
featureInfo,
featureAvailableOnOrg,
gateVariant,
isAddonProduct,
featureInfoOnNextPlan,
} = useValues(payGateMiniLogic({ feature, currentUsage }))

if (!productWithFeature || !featureInfo) {
return null
}

return (
<div
className={clsx(
Expand Down
37 changes: 22 additions & 15 deletions frontend/src/lib/components/PayGateMini/payGateMiniLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { AvailableFeature, BillingProductV2AddonType, BillingProductV2Type } fro
import type { payGateMiniLogicType } from './payGateMiniLogicType'

export interface PayGateMiniLogicProps {
featureKey: AvailableFeature
feature: AvailableFeature
currentUsage?: number
}

Expand All @@ -17,7 +17,7 @@ export type GateVariantType = 'add-card' | 'contact-sales' | 'move-to-cloud' | n
export const payGateMiniLogic = kea<payGateMiniLogicType>([
props({} as PayGateMiniLogicProps),
path(['lib', 'components', 'payGateMini', 'payGateMiniLogic']),
key((props) => props.featureKey),
key((props) => props.feature),
connect(() => ({
values: [
billingLogic,
Expand All @@ -42,21 +42,21 @@ export const payGateMiniLogic = kea<payGateMiniLogicType>([

let foundProduct: BillingProductV2Type | BillingProductV2AddonType | undefined = undefined

if (checkProductFirst.includes(props.featureKey)) {
if (checkProductFirst.includes(props.feature)) {
foundProduct = billing?.products?.find((product) =>
product.features?.some((f) => f.key === props.featureKey)
product.features?.some((f) => f.key === props.feature)
)
}

// Check addons first (if not included in checkProductFirst) since their features are rolled up into the parent
const allAddons = billing?.products?.map((product) => product.addons).flat() || []
if (!foundProduct) {
foundProduct = allAddons.find((addon) => addon.features?.some((f) => f.key === props.featureKey))
foundProduct = allAddons.find((addon) => addon.features?.some((f) => f.key === props.feature))
}

if (!foundProduct) {
foundProduct = billing?.products?.find((product) =>
product.features?.some((f) => f.key === props.featureKey)
product.features?.some((f) => f.key === props.feature)
)
}
return foundProduct
Expand All @@ -71,18 +71,18 @@ export const payGateMiniLogic = kea<payGateMiniLogicType>([
],
featureInfo: [
(s) => [s.productWithFeature],
(productWithFeature) => productWithFeature?.features.find((f) => f.key === props.featureKey),
(productWithFeature) => productWithFeature?.features.find((f) => f.key === props.feature),
],
featureAvailableOnOrg: [
(s) => [s.user, (_, props) => props.featureKey],
(_user, featureKey) => {
return values.availableFeature(featureKey)
(s) => [s.user, (_, props) => props.feature],
(_user, feature) => {
return values.availableFeature(feature)
},
],
minimumPlanWithFeature: [
(s) => [s.productWithFeature],
(productWithFeature) =>
productWithFeature?.plans.find((plan) => plan.features?.some((f) => f.key === props.featureKey)),
productWithFeature?.plans.find((plan) => plan.features?.some((f) => f.key === props.feature)),
],
nextPlanWithFeature: [
(s) => [s.productWithFeature],
Expand All @@ -96,18 +96,18 @@ export const payGateMiniLogic = kea<payGateMiniLogicType>([
],
featureInfoOnNextPlan: [
(s) => [s.nextPlanWithFeature],
(nextPlanWithFeature) => nextPlanWithFeature?.features.find((f) => f.key === props.featureKey),
(nextPlanWithFeature) => nextPlanWithFeature?.features.find((f) => f.key === props.feature),
],
gateVariant: [
(s) => [
s.billingLoading,
s.hasAvailableFeature,
s.minimumPlanWithFeature,
(_, props) => props.featureKey,
(_, props) => props.feature,
(_, props) => props.currentUsage,
],
(billingLoading, hasAvailableFeature, minimumPlanWithFeature, featureKey, currentUsage) => {
if (hasAvailableFeature(featureKey, currentUsage)) {
(billingLoading, hasAvailableFeature, minimumPlanWithFeature, feature, currentUsage) => {
if (hasAvailableFeature(feature, currentUsage)) {
return null
}
if (billingLoading) {
Expand All @@ -122,5 +122,12 @@ export const payGateMiniLogic = kea<payGateMiniLogicType>([
return 'move-to-cloud'
},
],

scrollToProduct: [
(s) => [s.featureInfo, s.isAddonProduct],
(featureInfo, isAddonProduct) => {
return !(featureInfo?.key === AvailableFeature.ORGANIZATIONS_PROJECTS && !isAddonProduct)
},
],
})),
])
4 changes: 2 additions & 2 deletions frontend/src/lib/components/Playlist/Playlist.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@

.SessionRecordingPlaylistHeightWrapper {
// NOTE: Somewhat random way to offset the various headers and tabs above the playlist
height: calc(100vh - 15rem);
min-height: 41rem;
height: calc(100vh - 14rem);
min-height: 25rem;
}

.SessionRecordingPreview {
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ export const FEATURE_FLAGS = {
REPLAY_SIMILAR_RECORDINGS: 'session-replay-similar-recordings', // owner: #team-replay
SAVED_NOT_PINNED: 'saved-not-pinned', // owner: #team-replay
NEW_EXPERIMENTS_UI: 'new-experiments-ui', // owner: @jurajmajerik #team-feature-success
SESSION_REPLAY_FILTER_ORDERING: 'session-replay-filter-ordering', // owner: #team-replay
REPLAY_ERROR_CLUSTERING: 'session-replay-error-clustering', // owner: #team-replay
AUDIT_LOGS_ACCESS: 'audit-logs-access', // owner: #team-growth
SUBSCRIBE_FROM_PAYGATE: 'subscribe-from-paygate', // owner: #team-growth
Expand All @@ -202,7 +201,6 @@ export const FEATURE_FLAGS = {
HOG: 'hog', // owner: @mariusandra
HOG_FUNCTIONS: 'hog-functions', // owner: #team-cdp
PERSONLESS_EVENTS_NOT_SUPPORTED: 'personless-events-not-supported', // owner: @raquelmsmith
SESSION_REPLAY_UNIVERSAL_FILTERS: 'session-replay-universal-filters', // owner: #team-replay
ALERTS: 'alerts', // owner: github.com/nikitaevg
ERROR_TRACKING: 'error-tracking', // owner: #team-replay
SETTINGS_BOUNCE_RATE_PAGE_VIEW_MODE: 'settings-bounce-rate-page-view-mode', // owner: @robbie-c
Expand Down
Loading

0 comments on commit 461d355

Please sign in to comment.