From 2c58a9014db418b1c7ce48a5098c4c324ab1604b Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Thu, 26 Oct 2023 16:11:55 +0100 Subject: [PATCH] Improve clickability discovery of table rows --- .../src/queries/nodes/DataTable/DataTable.tsx | 1 + frontend/src/queries/types.ts | 3 +- .../src/scenes/web-analytics/WebDashboard.tsx | 116 ++++++++++++------ 3 files changed, 80 insertions(+), 40 deletions(-) diff --git a/frontend/src/queries/nodes/DataTable/DataTable.tsx b/frontend/src/queries/nodes/DataTable/DataTable.tsx index 47f10de575e5b9..8154d03fd04aaf 100644 --- a/frontend/src/queries/nodes/DataTable/DataTable.tsx +++ b/frontend/src/queries/nodes/DataTable/DataTable.tsx @@ -559,6 +559,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults } (response as any).result.length > 0 || !responseLoading) && } + onRow={context?.rowProps} /> )} {/* TODO: this doesn't seem like the right solution... */} diff --git a/frontend/src/queries/types.ts b/frontend/src/queries/types.ts index 03e80d7490fe6d..1a77b7536d1e0f 100644 --- a/frontend/src/queries/types.ts +++ b/frontend/src/queries/types.ts @@ -1,5 +1,5 @@ import { InsightLogicProps } from '~/types' -import { ComponentType } from 'react' +import { ComponentType, HTMLProps } from 'react' import { DataTableNode } from '~/queries/schema' /** Pass custom metadata to queries. Used for e.g. custom columns in the DataTable. */ @@ -14,6 +14,7 @@ export interface QueryContext { insightProps?: InsightLogicProps emptyStateHeading?: string emptyStateDetail?: string + rowProps?: (record: unknown) => Omit, 'key'> } export type QueryContextColumnTitleComponent = ComponentType<{ diff --git a/frontend/src/scenes/web-analytics/WebDashboard.tsx b/frontend/src/scenes/web-analytics/WebDashboard.tsx index 1d07f69b5d61e0..36b456ce6ec1a8 100644 --- a/frontend/src/scenes/web-analytics/WebDashboard.tsx +++ b/frontend/src/scenes/web-analytics/WebDashboard.tsx @@ -4,15 +4,16 @@ import { webAnalyticsLogic } from 'scenes/web-analytics/webAnalyticsLogic' import { PropertyFilters } from 'lib/components/PropertyFilters/PropertyFilters' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' import { isEventPropertyFilter } from 'lib/components/PropertyFilters/utils' -import { NodeKind, WebStatsBreakdown } from '~/queries/schema' +import { DataTableNode, NodeKind, QuerySchema, WebStatsBreakdown } from '~/queries/schema' import { QueryContext, QueryContextColumnComponent, QueryContextColumnTitleComponent } from '~/queries/types' -import { useCallback } from 'react' import { UnexpectedNeverError } from 'lib/utils' import { DateFilter } from 'lib/components/DateFilter/DateFilter' import { LemonBanner } from 'lib/lemon-ui/LemonBanner' import { supportLogic } from 'lib/components/Support/supportLogic' import { IconBugReport, IconFeedback, IconGithub } from 'lib/lemon-ui/icons' import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' +import { Link } from 'lib/lemon-ui/Link' +import { useCallback } from 'react' const PercentageCell: QueryContextColumnComponent = ({ value }) => { if (typeof value === 'number') { @@ -64,47 +65,35 @@ const BreakdownValueCell: QueryContextColumnComponent = (props) => { if (typeof value !== 'string') { return null } - const { breakdownBy } = source - let propertyName: string + + return +} + +const webStatsBreakdownToPropertyName = (breakdownBy: WebStatsBreakdown): string => { switch (breakdownBy) { case WebStatsBreakdown.Page: - propertyName = '$pathname' - break + return '$pathname' case WebStatsBreakdown.InitialPage: - propertyName = '$initial_pathname' - break + return '$initial_pathname' case WebStatsBreakdown.InitialReferringDomain: - propertyName = '$initial_referrer' - break + return '$initial_referrer' case WebStatsBreakdown.InitialUTMSource: - propertyName = '$initial_utm_source' - break + return '$initial_utm_source' case WebStatsBreakdown.InitialUTMCampaign: - propertyName = '$initial_utm_campaign' - break + return '$initial_utm_campaign' case WebStatsBreakdown.Browser: - propertyName = '$browser' - break + return '$browser' case WebStatsBreakdown.OS: - propertyName = '$os' - break + return '$os' case WebStatsBreakdown.DeviceType: - propertyName = '$device_type' - break + return '$device_type' default: throw new UnexpectedNeverError(breakdownBy) } - - return } -const BreakdownValueCellInner = ({ value, propertyName }: { value: string; propertyName: string }): JSX.Element => { - const { togglePropertyFilter } = useActions(webAnalyticsLogic) - - const onClick = useCallback(() => { - togglePropertyFilter(propertyName, value) - }, [togglePropertyFilter, propertyName, value]) - return {value} +const BreakdownValueCellInner = ({ value }: { value: string }): JSX.Element => { + return {value} } const queryContext: QueryContext = { @@ -152,6 +141,7 @@ const Filters = (): JSX.Element => { const Tiles = (): JSX.Element => { const { tiles } = useValues(webAnalyticsLogic) + return (
{tiles.map((tile, i) => { @@ -165,7 +155,7 @@ const Tiles = (): JSX.Element => { } flex flex-col`} > {title &&

{title}

} - +
) } else if ('tabs' in tile) { @@ -188,7 +178,7 @@ const Tiles = (): JSX.Element => {
{/* TODO switch to a select if more than 3 */} {tabs.map(({ id, linkText }) => ( - { onClick={() => setTabId(id)} > {linkText} - + ))}
)} {/* Setting key forces the component to be recreated when the tab changes */} - + ) } else { @@ -213,6 +203,54 @@ const Tiles = (): JSX.Element => { ) } +const QueryTile = ({ query }: { query: QuerySchema }): JSX.Element => { + if (query.kind === NodeKind.DataTableNode && query.source.kind === NodeKind.WebStatsTableQuery) { + return + } + + return +} + +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 ( + ({ + onClick: () => onClick(record), + className: 'hover:underline cursor-pointer hover:bg-mark', + }), + }} + /> + ) +} + export const Notice = (): JSX.Element => { const { openSupportForm } = useActions(supportLogic) const { preflight } = useValues(preflightLogic) @@ -224,17 +262,17 @@ export const Notice = (): JSX.Element => {

PostHog Web Analytics is in closed Alpha. Thanks for taking part! We'd love to hear what you think.

{showSupportOptions ? (

- openSupportForm('bug')}> + openSupportForm('bug')}> Report a bug - {' '} + {' '} -{' '} - openSupportForm('feedback')}> + openSupportForm('feedback')}> Give feedback - {' '} + {' '} -{' '} - + View GitHub issue - +

) : null}