Skip to content

Commit

Permalink
feat(web-analytics): Add path cleaning (#20218)
Browse files Browse the repository at this point in the history
  • Loading branch information
robbie-c authored Feb 9, 2024
1 parent 76260bf commit 40ed638
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 24 deletions.
Binary file modified frontend/__snapshots__/exporter-exporter--dashboard--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions frontend/src/lib/lemon-ui/LemonTable/LemonTable.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
--lemon-table-background-color: var(--bg-light);
}

.WebAnalyticsDashboard &,
.WebAnalyticsModal & {
// Special override for scenes where the surroundings provide a border
border: none;
}

.posthog-3000 & {
--row-base-height: auto;

Expand Down
3 changes: 3 additions & 0 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -5073,6 +5073,9 @@
"dateRange": {
"$ref": "#/definitions/DateRange"
},
"doPathCleaning": {
"type": "boolean"
},
"includeBounceRate": {
"type": "boolean"
},
Expand Down
1 change: 1 addition & 0 deletions frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,7 @@ export interface WebStatsTableQuery extends WebAnalyticsQueryBase {
response?: WebStatsTableQueryResponse
includeScrollDepth?: boolean // automatically sets includeBounceRate to true
includeBounceRate?: boolean
doPathCleaning?: boolean
/** @asType integer */
limit?: number
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/scenes/web-analytics/WebAnalyticsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const WebAnalyticsModal = (): JSX.Element | null => {
fullScreen={false}
closable={true}
>
<div className="space-y-4">
<div className="WebAnalyticsModal space-y-4">
<div className="flex flex-row flex-wrap gap-2">
<WebPropertyFilters
setWebAnalyticsFilters={setWebAnalyticsFilters}
Expand All @@ -43,6 +43,7 @@ export const WebAnalyticsModal = (): JSX.Element | null => {
query={modal.query}
insightProps={modal.insightProps}
showIntervalSelect={modal.showIntervalSelect}
showPathCleaningControls={modal.showPathCleaningControls}
/>
</LemonModal.Content>
<div className="flex flex-row justify-end">
Expand Down
62 changes: 59 additions & 3 deletions frontend/src/scenes/web-analytics/WebAnalyticsTile.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { IconGear } from '@posthog/icons'
import { useActions, useValues } from 'kea'
import { IntervalFilterStandalone } from 'lib/components/IntervalFilter'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { LemonSwitch } from 'lib/lemon-ui/LemonSwitch'
import { UnexpectedNeverError } from 'lib/utils'
import { useCallback, useMemo } from 'react'
import { countryCodeToFlag, countryCodeToName } from 'scenes/insights/views/WorldMap'
import { urls } from 'scenes/urls'
import { DeviceTab, GeographyTab, webAnalyticsLogic } from 'scenes/web-analytics/webAnalyticsLogic'

import { Query } from '~/queries/Query/Query'
Expand Down Expand Up @@ -307,12 +311,16 @@ export const WebStatsTableTile = ({
query,
breakdownBy,
insightProps,
showPathCleaningControls,
}: {
query: DataTableNode
breakdownBy: WebStatsBreakdown
insightProps: InsightLogicProps
showPathCleaningControls?: boolean
}): JSX.Element => {
const { togglePropertyFilter } = useActions(webAnalyticsLogic)
const { togglePropertyFilter, setIsPathCleaningEnabled } = useActions(webAnalyticsLogic)
const { isPathCleaningEnabled } = useValues(webAnalyticsLogic)

const { key, type } = webStatsBreakdownToPropertyName(breakdownBy) || {}

const onClick = useCallback(
Expand All @@ -327,6 +335,15 @@ export const WebStatsTableTile = ({

const context = useMemo((): QueryContext => {
const rowProps: QueryContext['rowProps'] = (record: unknown) => {
if (
(breakdownBy === WebStatsBreakdown.InitialPage || breakdownBy === WebStatsBreakdown.Page) &&
isPathCleaningEnabled
) {
// if the path cleaning is enabled, don't allow toggling a path by clicking a row, as this wouldn't
// work due to the order that the regex and filters are applied
return {}
}

const breakdownValue = getBreakdownValue(record, breakdownBy)
if (breakdownValue === undefined) {
return {}
Expand All @@ -342,7 +359,37 @@ export const WebStatsTableTile = ({
}
}, [onClick, insightProps])

return <Query query={query} readOnly={true} context={context} />
const pathCleaningSettingsUrl = urls.settings('project-product-analytics', 'path-cleaning')
return (
<div className="border rounded bg-bg-light">
{showPathCleaningControls && (
<div className="flex flex-row items-center justify-end m-2 mr-4">
<div className="flex flex-row items-center space-x-2">
<LemonSwitch
label={
<div className="flex flex-row space-x-2">
<span>Enable path cleaning</span>
<LemonButton
icon={<IconGear />}
type="tertiary"
status="alt"
size="small"
noPadding={true}
tooltip="Edit path cleaning settings"
to={pathCleaningSettingsUrl}
/>
</div>
}
checked={isPathCleaningEnabled}
onChange={setIsPathCleaningEnabled}
className="h-full"
/>
</div>
</div>
)}
<Query query={query} readOnly={true} context={context} />
</div>
)
}

const getBreakdownValue = (record: unknown, breakdownBy: WebStatsBreakdown): string | undefined => {
Expand Down Expand Up @@ -383,14 +430,23 @@ const getBreakdownValue = (record: unknown, breakdownBy: WebStatsBreakdown): str
export const WebQuery = ({
query,
showIntervalSelect,
showPathCleaningControls,
insightProps,
}: {
query: QuerySchema
showIntervalSelect?: boolean
showPathCleaningControls?: boolean
insightProps: InsightLogicProps
}): JSX.Element => {
if (query.kind === NodeKind.DataTableNode && query.source.kind === NodeKind.WebStatsTableQuery) {
return <WebStatsTableTile query={query} breakdownBy={query.source.breakdownBy} insightProps={insightProps} />
return (
<WebStatsTableTile
query={query}
breakdownBy={query.source.breakdownBy}
insightProps={insightProps}
showPathCleaningControls={showPathCleaningControls}
/>
)
}
if (query.kind === NodeKind.InsightVizNode) {
return <WebStatsTrendTile query={query} showIntervalTile={showIntervalSelect} insightProps={insightProps} />
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/scenes/web-analytics/WebDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const Tiles = (): JSX.Element => {
}

const QueryTileItem = ({ tile }: { tile: QueryTile }): JSX.Element => {
const { query, title, layout, insightProps } = tile
const { query, title, layout, insightProps, showPathCleaningControls, showIntervalSelect } = tile

const { openModal } = useActions(webAnalyticsLogic)
const { getNewInsightUrl } = useValues(webAnalyticsLogic)
Expand Down Expand Up @@ -107,7 +107,12 @@ const QueryTileItem = ({ tile }: { tile: QueryTile }): JSX.Element => {
)}
>
{title && <h2 className="m-0 mb-3">{title}</h2>}
<WebQuery query={query} insightProps={insightProps} />
<WebQuery
query={query}
insightProps={insightProps}
showPathCleaningControls={showPathCleaningControls}
showIntervalSelect={showIntervalSelect}
/>
{buttonsRow.length > 0 ? <div className="flex justify-end my-2 space-x-2">{buttonsRow}</div> : null}
</div>
)
Expand Down Expand Up @@ -137,6 +142,7 @@ const TabsTileItem = ({ tile }: { tile: TabsTile }): JSX.Element => {
key={tab.id}
query={tab.query}
showIntervalSelect={tab.showIntervalSelect}
showPathCleaningControls={tab.showPathCleaningControls}
insightProps={tab.insightProps}
/>
),
Expand Down
40 changes: 39 additions & 1 deletion frontend/src/scenes/web-analytics/webAnalyticsLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ interface BaseTile {
export interface QueryTile extends BaseTile {
title?: string
query: QuerySchema
showIntervalSelect?: boolean
showPathCleaningControls?: boolean
insightProps: InsightLogicProps
canOpenModal: boolean
canOpenInsight?: boolean
Expand All @@ -85,6 +87,7 @@ export interface TabsTile extends BaseTile {
linkText: string
query: QuerySchema
showIntervalSelect?: boolean
showPathCleaningControls?: boolean
insightProps: InsightLogicProps
canOpenModal?: boolean
canOpenInsight?: boolean
Expand All @@ -100,6 +103,7 @@ export interface WebDashboardModalQuery {
query: QuerySchema
insightProps: InsightLogicProps
showIntervalSelect?: boolean
showPathCleaningControls?: boolean
canOpenInsight?: boolean
}

Expand Down Expand Up @@ -196,6 +200,7 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
setGeographyTab: (tab: string) => ({ tab }),
setDates: (dateFrom: string | null, dateTo: string | null) => ({ dateFrom, dateTo }),
setInterval: (interval: IntervalType) => ({ interval }),
setIsPathCleaningEnabled: (isPathCleaningEnabled: boolean) => ({ isPathCleaningEnabled }),
setStateFromUrl: (state: {
filters: WebAnalyticsPropertyFilters
dateFrom: string | null
Expand All @@ -206,6 +211,7 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
deviceTab: string | null
pathTab: string | null
geographyTab: string | null
isPathCleaningEnabled: boolean | null
}) => ({
state,
}),
Expand Down Expand Up @@ -308,6 +314,13 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
togglePropertyFilter: (oldTab, { tabChange }) => tabChange?.geographyTab || oldTab,
},
],
isPathCleaningEnabled: [
false as boolean,
{
setIsPathCleaningEnabled: (_, { isPathCleaningEnabled }) => isPathCleaningEnabled,
setStateFromUrl: (_, { state }) => state.isPathCleaningEnabled || false,
},
],
_modalTileAndTab: [
null as { tileId: TileId; tabId?: string } | null,
{
Expand Down Expand Up @@ -367,6 +380,7 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
s.pathTab,
s.geographyTab,
s.dateFilter,
s.isPathCleaningEnabled,
() => values.statusCheck,
() => values.isGreaterThanMd,
() => values.shouldShowGeographyTile,
Expand All @@ -379,6 +393,7 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
pathTab,
geographyTab,
{ dateFrom, dateTo, interval },
isPathCleaningEnabled: boolean,
statusCheck,
isGreaterThanMd: boolean,
shouldShowGeographyTile
Expand Down Expand Up @@ -552,12 +567,14 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
includeScrollDepth: statusCheck?.isSendingPageLeavesScroll,
includeBounceRate: true,
sampling,
doPathCleaning: isPathCleaningEnabled,
limit: 10,
},
embedded: false,
},
insightProps: createInsightProps(TileId.PATHS, PathTab.PATH),
canOpenModal: true,
showPathCleaningControls: true,
},
{
id: PathTab.INITIAL_PATH,
Expand All @@ -573,12 +590,14 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
dateRange,
includeScrollDepth: statusCheck?.isSendingPageLeavesScroll,
sampling,
doPathCleaning: isPathCleaningEnabled,
limit: 10,
},
embedded: false,
},
insightProps: createInsightProps(TileId.PATHS, PathTab.INITIAL_PATH),
canOpenModal: true,
showPathCleaningControls: true,
},
],
},
Expand Down Expand Up @@ -990,6 +1009,7 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
tabId,
title: tab.title,
showIntervalSelect: tab.showIntervalSelect,
showPathCleaningControls: tab.showPathCleaningControls,
insightProps: {
dashboardItemId: getDashboardItemId(tileId, tabId, true),
loadPriority: 0,
Expand All @@ -1004,6 +1024,8 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
return {
tileId,
title: tile.title,
showIntervalSelect: tile.showIntervalSelect,
showPathCleaningControls: tile.showPathCleaningControls,
insightProps: {
dashboardItemId: getDashboardItemId(tileId, undefined, true),
loadPriority: 0,
Expand Down Expand Up @@ -1188,6 +1210,7 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
pathTab,
geographyTab,
graphsTab,
isPathCleaningEnabled,
} = values

const urlParams = new URLSearchParams()
Expand All @@ -1214,6 +1237,9 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
if (geographyTab) {
urlParams.set('geography_tab', geographyTab)
}
if (isPathCleaningEnabled) {
urlParams.set('path_cleaning', isPathCleaningEnabled.toString())
}
return `/web?${urlParams.toString()}`
}

Expand All @@ -1233,7 +1259,18 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
urlToAction(({ actions }) => ({
'/web': (
_,
{ filters, date_from, date_to, interval, device_tab, source_tab, graphs_tab, path_tab, geography_tab }
{
filters,
date_from,
date_to,
interval,
device_tab,
source_tab,
graphs_tab,
path_tab,
geography_tab,
path_cleaning,
}
) => {
const parsedFilters = isWebAnalyticsPropertyFilters(filters) ? filters : initialWebAnalyticsFilter

Expand All @@ -1247,6 +1284,7 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
graphsTab: graphs_tab || null,
pathTab: path_tab || null,
geographyTab: geography_tab || null,
isPathCleaningEnabled: [true, 'true', 1, '1'].includes(path_cleaning),
})
},
})),
Expand Down
Loading

0 comments on commit 40ed638

Please sign in to comment.