diff --git a/frontend/src/scenes/insights/EditorFilters/PathsTarget.tsx b/frontend/src/scenes/insights/EditorFilters/PathsTarget.tsx index a716b2a962d96..e864588381a45 100644 --- a/frontend/src/scenes/insights/EditorFilters/PathsTarget.tsx +++ b/frontend/src/scenes/insights/EditorFilters/PathsTarget.tsx @@ -7,7 +7,7 @@ import { LemonButton } from 'lib/lemon-ui/LemonButton' import { pathsDataLogic } from 'scenes/paths/pathsDataLogic' import { queryNodeToFilter } from '~/queries/nodes/InsightQuery/utils/queryNodeToFilter' -import { FunnelsQuery } from '~/queries/schema' +import { FunnelsQuery, PathsQuery } from '~/queries/schema' import { EditorFilterProps, FunnelPathType } from '~/types' export function PathsTargetStart(props: EditorFilterProps): JSX.Element { @@ -38,7 +38,10 @@ function PathsTarget({ position, insightProps }: PathTargetProps): JSX.Element { updateInsightFilter({ [key]: item }) } const onReset = (): void => { - updateQuerySource({ pathsFilter: { ...pathsFilter, [key]: undefined }, funnelPathsFilter: undefined }) + updateQuerySource({ + pathsFilter: { ...pathsFilter, [key]: undefined }, + funnelPathsFilter: undefined, + } as Partial) } function _getStepNameAtIndex(filters: Record, index: number): string { diff --git a/frontend/src/scenes/paths/PathNodeCard.tsx b/frontend/src/scenes/paths/PathNodeCard.tsx index de3becb0f4293..38baea7bee48d 100644 --- a/frontend/src/scenes/paths/PathNodeCard.tsx +++ b/frontend/src/scenes/paths/PathNodeCard.tsx @@ -2,6 +2,7 @@ import { Tooltip } from '@posthog/lemon-ui' import { Dropdown } from 'antd' import { useActions, useValues } from 'kea' +import { FunnelPathsFilter } from '~/queries/schema' import { InsightLogicProps } from '~/types' import { PATH_NODE_CARD_LEFT_OFFSET, PATH_NODE_CARD_TOP_OFFSET, PATH_NODE_CARD_WIDTH } from './constants' @@ -16,10 +17,11 @@ export type PathNodeCardProps = { } export function PathNodeCard({ insightProps, node }: PathNodeCardProps): JSX.Element | null { - const { pathsFilter } = useValues(pathsDataLogic(insightProps)) + const { pathsFilter: _pathsFilter, funnelPathsFilter: _funnelPathsFilter } = useValues(pathsDataLogic(insightProps)) const { updateInsightFilter, openPersonsModal, viewPathToFunnel } = useActions(pathsDataLogic(insightProps)) - const filter = pathsFilter || {} + const pathsFilter = _pathsFilter || {} + const funnelPathsFilter = _funnelPathsFilter || ({} as FunnelPathsFilter) if (!node.visible) { return null @@ -64,7 +66,9 @@ export function PathNodeCard({ insightProps, node }: PathNodeCardProps): JSX.Ele ? node.y0 + PATH_NODE_CARD_TOP_OFFSET : // use middle for end nodes node.y0 + (node.y1 - node.y0) / 2, - border: `1px solid ${isSelectedPathStartOrEnd(filter, node) ? 'purple' : 'var(--border)'}`, + border: `1px solid ${ + isSelectedPathStartOrEnd(pathsFilter, funnelPathsFilter, node) ? 'purple' : 'var(--border)' + }`, }} data-attr="path-node-card-button" > @@ -75,7 +79,7 @@ export function PathNodeCard({ insightProps, node }: PathNodeCardProps): JSX.Ele viewPathToFunnel={viewPathToFunnel} openPersonsModal={openPersonsModal} setFilter={updateInsightFilter} - filter={filter} + filter={pathsFilter} /> diff --git a/frontend/src/scenes/paths/Paths.tsx b/frontend/src/scenes/paths/Paths.tsx index e865923142e17..933f2825567f9 100644 --- a/frontend/src/scenes/paths/Paths.tsx +++ b/frontend/src/scenes/paths/Paths.tsx @@ -6,6 +6,8 @@ import { useEffect, useRef, useState } from 'react' import { InsightEmptyState, InsightErrorState } from 'scenes/insights/EmptyStates' import { insightLogic } from 'scenes/insights/insightLogic' +import { FunnelPathsFilter } from '~/queries/schema' + import { PathNodeCard } from './PathNodeCard' import { pathsDataLogic } from './pathsDataLogic' import type { PathNodeData } from './pathUtils' @@ -23,7 +25,9 @@ export function Paths(): JSX.Element { const [nodeCards, setNodeCards] = useState([]) const { insight, insightProps } = useValues(insightLogic) - const { paths, pathsFilter, insightDataLoading, insightDataError } = useValues(pathsDataLogic(insightProps)) + const { paths, pathsFilter, funnelPathsFilter, insightDataLoading, insightDataError } = useValues( + pathsDataLogic(insightProps) + ) const id = `'${insight?.short_id || DEFAULT_PATHS_ID}'` @@ -35,7 +39,15 @@ export function Paths(): JSX.Element { const elements = document?.getElementById(id)?.querySelectorAll(`.Paths__canvas`) elements?.forEach((node) => node?.parentNode?.removeChild(node)) - renderPaths(canvasRef, canvasWidth, canvasHeight, paths, pathsFilter || {}, setNodeCards) + renderPaths( + canvasRef, + canvasWidth, + canvasHeight, + paths, + pathsFilter || {}, + funnelPathsFilter || ({} as FunnelPathsFilter), + setNodeCards + ) }, [paths, !insightDataLoading, canvasWidth, canvasHeight]) if (insightDataError) { diff --git a/frontend/src/scenes/paths/pathUtils.ts b/frontend/src/scenes/paths/pathUtils.ts index fd0336483d3c7..16b82d61b2395 100644 --- a/frontend/src/scenes/paths/pathUtils.ts +++ b/frontend/src/scenes/paths/pathUtils.ts @@ -1,6 +1,6 @@ import { RGBColor } from 'd3' -import { PathsFilter } from '~/queries/schema' +import { FunnelPathsFilter, PathsFilter } from '~/queries/schema' import { FunnelPathType } from '~/types' export interface PathTargetLink { @@ -114,16 +114,22 @@ export function pageUrl(d: PathNodeData, display?: boolean): string { : name } -export const isSelectedPathStartOrEnd = (pathsFilter: PathsFilter, pathItemCard: PathNodeData): boolean => { +export const isSelectedPathStartOrEnd = ( + pathsFilter: PathsFilter, + funnelPathsFilter: FunnelPathsFilter, + pathItemCard: PathNodeData +): boolean => { const cardName = pageUrl(pathItemCard) const isPathStart = pathItemCard.targetLinks.length === 0 const isPathEnd = pathItemCard.sourceLinks.length === 0 - const { startPoint, endPoint, funnelPaths, funnelFilter } = pathsFilter + const { startPoint, endPoint } = pathsFilter + const { funnelPathType, funnelSource, funnelStep } = funnelPathsFilter || {} + return ( (startPoint === cardName && isPathStart) || (endPoint === cardName && isPathEnd) || - (funnelPaths === FunnelPathType.between && - ((cardName === funnelFilter?.events[funnelFilter.funnel_step - 1].name && isPathEnd) || - (cardName === funnelFilter?.events[funnelFilter.funnel_step - 2].name && isPathStart))) + (funnelPathType === FunnelPathType.between && + ((cardName === funnelSource?.series[funnelStep! - 1].name && isPathEnd) || + (cardName === funnelSource?.series[funnelStep! - 2].name && isPathStart))) ) } diff --git a/frontend/src/scenes/paths/renderPaths.ts b/frontend/src/scenes/paths/renderPaths.ts index f30a0c28346e1..2e8c6bbe6cafd 100644 --- a/frontend/src/scenes/paths/renderPaths.ts +++ b/frontend/src/scenes/paths/renderPaths.ts @@ -4,7 +4,7 @@ import { D3Selector } from 'lib/hooks/useD3' import { stripHTTP } from 'lib/utils' import { Dispatch, RefObject, SetStateAction } from 'react' -import { PathsFilter } from '~/queries/schema' +import { FunnelPathsFilter, PathsFilter } from '~/queries/schema' import { FALLBACK_CANVAS_WIDTH, HIDE_PATH_CARD_HEIGHT } from './Paths' import { PathNode } from './pathsDataLogic' @@ -34,6 +34,7 @@ const appendPathNodes = ( svg: any, nodes: PathNodeData[], pathsFilter: PathsFilter, + funnelPathsFilter: FunnelPathsFilter, setNodeCards: Dispatch> ): void => { svg.append('g') @@ -62,7 +63,7 @@ const appendPathNodes = ( } } } - if (isSelectedPathStartOrEnd(pathsFilter, d)) { + if (isSelectedPathStartOrEnd(pathsFilter, funnelPathsFilter, d)) { return d3.color('purple') } const startNodeColor = c && d3.color(c) ? d3.color(c) : d3.color('#5375ff') @@ -201,6 +202,7 @@ export function renderPaths( canvasHeight: number, paths: { links: PathNode[]; nodes: any[] }, pathsFilter: PathsFilter, + funnelPathsFilter: FunnelPathsFilter, setNodeCards: Dispatch> ): void { if (!paths || paths.nodes.length === 0) { @@ -227,7 +229,7 @@ export function renderPaths( setNodeCards(nodes.map((node: PathNodeData) => ({ ...node, visible: node.y1 - node.y0 > HIDE_PATH_CARD_HEIGHT }))) - appendPathNodes(svg, nodes, pathsFilter, setNodeCards) + appendPathNodes(svg, nodes, pathsFilter, funnelPathsFilter, setNodeCards) appendDropoffs(svg) appendPathLinks(svg, links, nodes, setNodeCards) addChartAxisLines(svg, height, nodes, maxLayer)