Skip to content

Commit

Permalink
Merge branch 'master' into taxonomy-project
Browse files Browse the repository at this point in the history
  • Loading branch information
Twixes authored Dec 2, 2024
2 parents b54cb8e + 7ec7356 commit bbb6a2d
Show file tree
Hide file tree
Showing 8 changed files with 295 additions and 135 deletions.
4 changes: 4 additions & 0 deletions frontend/src/lib/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ export function percentage(
maximumFractionDigits: number = 2,
fixedPrecision: boolean = false
): string {
if (division === Infinity) {
return '∞%'
}

return division.toLocaleString('en-US', {
style: 'percent',
maximumFractionDigits,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/queries/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export type QueryContextColumnComponent = ComponentType<{
}>

interface QueryContextColumn {
title?: string
title?: JSX.Element | string
renderTitle?: QueryContextColumnTitleComponent
render?: QueryContextColumnComponent
align?: 'left' | 'right' | 'center' // default is left
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { actions, connect, kea, listeners, path, reducers } from 'kea'
import { loaders } from 'kea-loaders'
import api from 'lib/api'
import { dayjs } from 'lib/dayjs'
import { CORE_FILTER_DEFINITIONS_BY_GROUP } from 'lib/taxonomy'
import { eventUsageLogic } from 'lib/utils/eventUsageLogic'

import { HogQLQuery, NodeKind } from '~/queries/schema'
Expand Down Expand Up @@ -40,7 +41,7 @@ export const sessionRecordingsListPropertiesLogic = kea<sessionRecordingsListPro
kind: NodeKind.HogQLQuery,
query: hogql`SELECT properties.$session_id as session_id, any(properties) as properties
FROM events
WHERE event IN ['$pageview', '$autocapture']
WHERE event IN ${Object.keys(CORE_FILTER_DEFINITIONS_BY_GROUP['events'])}
AND session_id IN ${sessionIds}
-- the timestamp range here is only to avoid querying too much of the events table
-- we don't really care about the absolute value,
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/settings/environment/TeamDangerZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ export function TeamDangerZone(): JSX.Element {
return <ProjectDangerZone />
}

// We don't yet allow deleting individual environments, as we still use `team` fields with `on_delete=CASCADE`
// on many models that conceptually are project-level (such as insights or feature flags). That `on_delete=CASCADE`
// means currently deleting an environment would also delete resources a user wouldn't expect to disappear.
// TODO: Remove once point 15 ("Denormalize models") of https://github.com/PostHog/posthog/issues/13418#issuecomment-2180883524 is resolved
return <i>Deletion of individual environments is coming soon.</i>

return (
<>
<div className="text-danger">
Expand Down
118 changes: 89 additions & 29 deletions frontend/src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { IconGear } from '@posthog/icons'
import { IconGear, IconTrending } from '@posthog/icons'
import { Tooltip } from '@posthog/lemon-ui'
import clsx from 'clsx'
import { useActions, useValues } from 'kea'
import { getColorVar } from 'lib/colors'
import { IntervalFilterStandalone } from 'lib/components/IntervalFilter'
import { ProductIntroduction } from 'lib/components/ProductIntroduction/ProductIntroduction'
import { IconOpenInNew } from 'lib/lemon-ui/icons'
import { IconOpenInNew, IconTrendingDown, IconTrendingFlat } from 'lib/lemon-ui/icons'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { LemonSwitch } from 'lib/lemon-ui/LemonSwitch'
import { UnexpectedNeverError } from 'lib/utils'
import { percentage, UnexpectedNeverError } from 'lib/utils'
import { useCallback, useMemo } from 'react'
import { NewActionButton } from 'scenes/actions/NewActionButton'
import { countryCodeToFlag, countryCodeToName } from 'scenes/insights/views/WorldMap'
Expand Down Expand Up @@ -37,15 +40,72 @@ const toUtcOffsetFormat = (value: number): string => {
return `UTC${sign}${integerPart}${formattedMinutes}`
}

const PercentageCell: QueryContextColumnComponent = ({ value }) => {
if (typeof value === 'number') {
return <span>{`${(value * 100).toFixed(1)}%`}</span>
}
return null
}
type VariationCellProps = { isPercentage?: boolean; reverseColors?: boolean }
const VariationCell = (
{ isPercentage, reverseColors }: VariationCellProps = { isPercentage: false, reverseColors: false }
): QueryContextColumnComponent => {
const formatNumber = (value: number): string =>
isPercentage ? `${(value * 100).toFixed(1)}%` : value.toLocaleString()

return function Cell({ value }) {
if (!value) {
return null
}

if (!Array.isArray(value)) {
return <span>{String(value)}</span>
}

const [current, previous] = value as [number, number]
const pctChangeFromPrevious =
previous === 0 && current === 0 // Special case, render as flatline
? 0
: current === null
? null
: previous === null || previous === 0
? Infinity
: current / previous - 1

const trend =
pctChangeFromPrevious === null
? null
: pctChangeFromPrevious === 0
? { Icon: IconTrendingFlat, color: getColorVar('muted') }
: pctChangeFromPrevious > 0
? {
Icon: IconTrending,
color: reverseColors ? getColorVar('danger') : getColorVar('success'),
}
: {
Icon: IconTrendingDown,
color: reverseColors ? getColorVar('success') : getColorVar('danger'),
}

// If current === previous, say "increased by 0%"
const tooltip =
pctChangeFromPrevious !== null
? `${current >= previous ? 'Increased' : 'Decreased'} by ${percentage(
Math.abs(pctChangeFromPrevious),
0
)} since last period (from ${formatNumber(previous)} to ${formatNumber(current)})`
: null

const NumericCell: QueryContextColumnComponent = ({ value }) => {
return <span>{typeof value === 'number' ? value.toLocaleString() : String(value)}</span>
return (
<div className={clsx({ 'pr-4': !trend })}>
<Tooltip title={tooltip}>
<span>
{formatNumber(current)}&nbsp;
{trend && (
// eslint-disable-next-line react/forbid-dom-props
<span style={{ color: trend.color }}>
<trend.Icon color={trend.color} className="ml-1" />
</span>
)}
</span>
</Tooltip>
</div>
)
}
}

const BreakdownValueTitle: QueryContextColumnTitleComponent = (props) => {
Expand Down Expand Up @@ -227,48 +287,48 @@ export const webAnalyticsDataTableQueryContext: QueryContext = {
render: BreakdownValueCell,
},
bounce_rate: {
title: 'Bounce Rate',
render: PercentageCell,
title: <span className="pr-5">Bounce Rate</span>,
render: VariationCell({ isPercentage: true, reverseColors: true }),
align: 'right',
},
views: {
title: 'Views',
render: NumericCell,
title: <span className="pr-5">Views</span>,
render: VariationCell(),
align: 'right',
},
clicks: {
title: 'Clicks',
render: NumericCell,
title: <span className="pr-5">Clicks</span>,
render: VariationCell(),
align: 'right',
},
visitors: {
title: 'Visitors',
render: NumericCell,
title: <span className="pr-5">Visitors</span>,
render: VariationCell(),
align: 'right',
},
average_scroll_percentage: {
title: 'Average Scroll',
render: PercentageCell,
title: <span className="pr-5">Average Scroll</span>,
render: VariationCell({ isPercentage: true }),
align: 'right',
},
scroll_gt80_percentage: {
title: 'Deep Scroll Rate',
render: PercentageCell,
title: <span className="pr-5">Deep Scroll Rate</span>,
render: VariationCell({ isPercentage: true }),
align: 'right',
},
total_conversions: {
title: 'Total Conversions',
render: NumericCell,
title: <span className="pr-5">Total Conversions</span>,
render: VariationCell(),
align: 'right',
},
conversion_rate: {
title: 'Conversion Rate',
render: PercentageCell,
title: <span className="pr-5">Conversion Rate</span>,
render: VariationCell({ isPercentage: true }),
align: 'right',
},
converting_users: {
title: 'Converting Users',
render: NumericCell,
title: <span className="pr-5">Converting Users</span>,
render: VariationCell(),
align: 'right',
},
action_name: {
Expand Down
1 change: 1 addition & 0 deletions posthog/hogql/functions/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,7 @@ def compare_types(arg_types: list[ConstantType], sig_arg_types: tuple[ConstantTy
"argMaxMerge": HogQLFunctionMeta("argMaxMerge", 1, 1, aggregate=True),
"avgState": HogQLFunctionMeta("avgState", 1, 1, aggregate=True),
"avgMerge": HogQLFunctionMeta("avgMerge", 1, 1, aggregate=True),
"avgMergeIf": HogQLFunctionMeta("avgMergeIf", 2, 2, aggregate=True),
"avgWeighted": HogQLFunctionMeta("avgWeighted", 2, 2, aggregate=True),
"avgWeightedIf": HogQLFunctionMeta("avgWeightedIf", 3, 3, aggregate=True),
"avgArray": HogQLFunctionMeta("avgArrayOrNull", 1, 1, aggregate=True),
Expand Down
Loading

0 comments on commit bbb6a2d

Please sign in to comment.