Skip to content

Commit

Permalink
Add WebTabs UI which is similar to LemonTabs but has a changable title
Browse files Browse the repository at this point in the history
  • Loading branch information
robbie-c committed Oct 27, 2023
1 parent 2ccc204 commit 5d565bf
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 223 deletions.
152 changes: 152 additions & 0 deletions frontend/src/scenes/web-analytics/WebAnalyticsDataTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { QueryContext, QueryContextColumnComponent, QueryContextColumnTitleComponent } from '~/queries/types'
import { DataTableNode, NodeKind, WebStatsBreakdown } from '~/queries/schema'
import { UnexpectedNeverError } from 'lib/utils'
import { useActions } from 'kea'
import { webAnalyticsLogic } from 'scenes/web-analytics/webAnalyticsLogic'
import { useCallback } from 'react'
import { Query } from '~/queries/Query/Query'

const PercentageCell: QueryContextColumnComponent = ({ value }) => {
if (typeof value === 'number') {
return <span>{`${(value * 100).toFixed(1)}%`}</span>
} else {
return null
}
}

const NumericCell: QueryContextColumnComponent = ({ value }) => {
return <span>{typeof value === 'number' ? value.toLocaleString() : String(value)}</span>
}

const BreakdownValueTitle: QueryContextColumnTitleComponent = (props) => {
const { query } = props
const { source } = query
if (source.kind !== NodeKind.WebStatsTableQuery) {
return null
}
const { breakdownBy } = source
switch (breakdownBy) {
case WebStatsBreakdown.Page:
return <>Path</>
case WebStatsBreakdown.InitialPage:
return <>Initial Path</>
case WebStatsBreakdown.InitialReferringDomain:
return <>Referring Domain</>
case WebStatsBreakdown.InitialUTMSource:
return <>UTM Source</>
case WebStatsBreakdown.InitialUTMCampaign:
return <>UTM Campaign</>
case WebStatsBreakdown.Browser:
return <>Browser</>
case WebStatsBreakdown.OS:
return <>OS</>
case WebStatsBreakdown.DeviceType:
return <>Device Type</>
default:
throw new UnexpectedNeverError(breakdownBy)
}
}

const BreakdownValueCell: QueryContextColumnComponent = (props) => {
const { value, query } = props
const { source } = query
if (source.kind !== NodeKind.WebStatsTableQuery) {
return null
}
if (typeof value !== 'string') {
return null
}

return <BreakdownValueCellInner value={value} />
}

export const webStatsBreakdownToPropertyName = (breakdownBy: WebStatsBreakdown): string => {
switch (breakdownBy) {
case WebStatsBreakdown.Page:
return '$pathname'
case WebStatsBreakdown.InitialPage:
return '$initial_pathname'
case WebStatsBreakdown.InitialReferringDomain:
return '$initial_referrer'
case WebStatsBreakdown.InitialUTMSource:
return '$initial_utm_source'
case WebStatsBreakdown.InitialUTMCampaign:
return '$initial_utm_campaign'
case WebStatsBreakdown.Browser:
return '$browser'
case WebStatsBreakdown.OS:
return '$os'
case WebStatsBreakdown.DeviceType:
return '$device_type'
default:
throw new UnexpectedNeverError(breakdownBy)
}
}

const BreakdownValueCellInner = ({ value }: { value: string }): JSX.Element => {
return <span>{value}</span>
}

export const webAnalyticsDataTableQueryContext: QueryContext = {
columns: {
breakdown_value: {
renderTitle: BreakdownValueTitle,
render: BreakdownValueCell,
},
bounce_rate: {
title: 'Bounce Rate',
render: PercentageCell,
align: 'right',
},
views: {
title: 'Views',
render: NumericCell,
align: 'right',
},
visitors: {
title: 'Visitors',
render: NumericCell,
align: 'right',
},
},
}

export const WebStatsTableTile = ({
query,
breakdownBy,
}: {
query: DataTableNode
breakdownBy: WebStatsBreakdown
}): JSX.Element => {
const { togglePropertyFilter } = useActions(webAnalyticsLogic)
const propertyName = webStatsBreakdownToPropertyName(breakdownBy)

const onClick = useCallback(
(record: unknown) => {
if (typeof record !== 'object' || !record || !('result' in record)) {
return
}
const result = record.result
if (!Array.isArray(result)) {
return
}
// assume that the first element is the value
togglePropertyFilter(propertyName, result[0])
},
[togglePropertyFilter, propertyName]
)

return (
<Query
query={query}
readOnly={true}
context={{
...webAnalyticsDataTableQueryContext,
rowProps: (record) => ({
onClick: () => onClick(record),
className: 'hover:underline cursor-pointer hover:bg-mark',
}),
}}
/>
)
}
34 changes: 34 additions & 0 deletions frontend/src/scenes/web-analytics/WebAnalyticsNotice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useActions, useValues } from 'kea'
import { supportLogic } from 'lib/components/Support/supportLogic'
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
import { LemonBanner } from 'lib/lemon-ui/LemonBanner'
import { Link } from 'lib/lemon-ui/Link'
import { IconBugReport, IconFeedback, IconGithub } from 'lib/lemon-ui/icons'

export const WebAnalyticsNotice = (): JSX.Element => {
const { openSupportForm } = useActions(supportLogic)
const { preflight } = useValues(preflightLogic)

const showSupportOptions = preflight?.cloud

return (
<LemonBanner type={'info'}>
<p>PostHog Web Analytics is in closed Alpha. Thanks for taking part! We'd love to hear what you think.</p>
{showSupportOptions ? (
<p>
<Link onClick={() => openSupportForm('bug')}>
<IconBugReport /> Report a bug
</Link>{' '}
-{' '}
<Link onClick={() => openSupportForm('feedback')}>
<IconFeedback /> Give feedback
</Link>{' '}
-{' '}
<Link to={'https://github.com/PostHog/posthog/issues/18177'}>
<IconGithub /> View GitHub issue
</Link>
</p>
) : null}
</LemonBanner>
)
}
Loading

0 comments on commit 5d565bf

Please sign in to comment.