Skip to content

Commit

Permalink
Release new tooltips #4156 (#5267)
Browse files Browse the repository at this point in the history
* release InsightsTableV2

* release graphs new UI
  • Loading branch information
paolodamico authored Jul 21, 2021
1 parent 3264539 commit 75d50e3
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 199 deletions.
1 change: 0 additions & 1 deletion frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ export const FEATURE_FLAGS = {
EVENT_COLUMN_CONFIG: '4141-event-columns',
NPS_PROMPT: '4562-nps',
INGESTION_TAXONOMY: '4267-event-property-taxonomy',
NEW_TOOLTIPS: '4156-tooltips-legends',
ENGAGEMENT_COHORTS: 'engagement-cohorts-4349',
PLUGIN_METRICS: '4871-plugin-metrics',
FUNNEL_BAR_VIZ: '4535-funnel-bar-viz', // Nail Funnels #4785
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const CALC_COLUMN_LABELS: Record<CalcColumnState, string> = {
median: 'Median',
}

export function InsightsTableV2({ isLegend = true, showTotalCount = false }: InsightsTableProps): JSX.Element | null {
export function InsightsTable({ isLegend = true, showTotalCount = false }: InsightsTableProps): JSX.Element | null {
const { indexedResults, visibilityMap, filters } = useValues(trendsLogic)
const { toggleVisibility } = useActions(trendsLogic)
const { cohorts } = useValues(cohortsModel)
Expand Down
137 changes: 2 additions & 135 deletions frontend/src/scenes/insights/InsightsTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,135 +1,2 @@
import React from 'react'
import { Table } from 'antd'
import { useActions, useValues } from 'kea'
import { IndexedTrendResult, trendsLogic } from 'scenes/trends/trendsLogic'
import { PHCheckbox } from 'lib/components/PHCheckbox'
import { getChartColors } from 'lib/colors'
import { FEATURE_FLAGS, MATHS } from 'lib/constants'
import { cohortsModel } from '~/models/cohortsModel'
import { CohortType } from '~/types'
import { ColumnsType } from 'antd/lib/table'
import { maybeAddCommasToInteger } from 'lib/utils'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { InsightsTableV2 } from './InsightsTableV2'

export function InsightsTable(props: InsightsTableProps): JSX.Element {
const { featureFlags } = useValues(featureFlagLogic)
return featureFlags[FEATURE_FLAGS.NEW_TOOLTIPS] ? <InsightsTableV2 {...props} /> : <InsightsTableV1 {...props} />
}

function formatLabel(item: IndexedTrendResult): string {
const name = item.action?.name || item.label
const math = item.action?.math
const mathLabel = math ? MATHS[math].name : ''
const propNum = item.action?.properties.length
const propLabel = propNum ? propNum + (propNum === 1 ? ' property' : ' properties') : ''
return name + (mathLabel ? ' — ' + mathLabel : '') + (propLabel ? ' — ' + propLabel : '')
}

function formatBreakdownLabel(breakdown_value: string | number | undefined, cohorts: CohortType[]): string {
if (breakdown_value && typeof breakdown_value == 'number') {
return cohorts.filter((c) => c.id == breakdown_value)[0]?.name || breakdown_value.toString()
} else if (typeof breakdown_value == 'string') {
return breakdown_value === 'nan' ? 'Other' : breakdown_value
} else {
return ''
}
}

interface InsightsTableProps {
isLegend?: boolean // `true` -> Used as a supporting legend at the bottom of another graph; `false` -> used as it's own display
showTotalCount?: boolean
}

function InsightsTableV1({ isLegend = true, showTotalCount = false }: InsightsTableProps): JSX.Element | null {
const { indexedResults, visibilityMap, filters } = useValues(trendsLogic)
const { toggleVisibility } = useActions(trendsLogic)
const { cohorts } = useValues(cohortsModel)
const isSingleEntity = indexedResults.length === 1

if (indexedResults.length === 0 || !indexedResults?.[0]?.data) {
return null
}

// Build up columns to include. Order matters.
const columns: ColumnsType<IndexedTrendResult> = []

if (isLegend) {
columns.push({
title: '',
render: function RenderCheckbox({}, item: IndexedTrendResult, index: number) {
// legend will always be on insight page where the background is white
return (
<PHCheckbox
color={getChartColors('white')[index]}
checked={visibilityMap[item.id]}
onChange={() => toggleVisibility(item.id)}
disabled={isSingleEntity}
/>
)
},
fixed: 'left',
width: 60,
})
}

columns.push({
title: 'Label',
render: function RenderLabel({}, item: IndexedTrendResult) {
return (
<span
style={{ cursor: isSingleEntity ? undefined : 'pointer' }}
onClick={() => !isSingleEntity && toggleVisibility(item.id)}
>
{formatLabel(item)}
</span>
)
},
fixed: 'left',
width: 150,
})

if (showTotalCount) {
columns.push({
title: 'Total',
dataIndex: 'count',
fixed: 'left',
width: 100,
})
}

if (filters.breakdown) {
columns.push({
title: 'Breakdown Value',
render: function RenderBreakdownValue({}, item: IndexedTrendResult) {
return formatBreakdownLabel(item.breakdown_value, cohorts)
},
fixed: 'left',
width: 150,
})
}

if (indexedResults && indexedResults.length > 0) {
const valueColumns = indexedResults[0].data.map(({}, index: number) => ({
title: (indexedResults[0].labels || indexedResults[0].dates || indexedResults[0].days)[index],
render: function RenderPeriod({}, item: IndexedTrendResult) {
return maybeAddCommasToInteger(item.data[index])
},
}))

columns.push(...valueColumns)
}

return (
<Table
dataSource={indexedResults}
columns={columns}
size="small"
rowKey="id"
pagination={{ pageSize: 100, hideOnSinglePage: true }}
style={{ marginTop: '1rem' }}
scroll={indexedResults && indexedResults.length > 0 ? { x: indexedResults[0].data.length * 160 } : {}}
data-attr="insights-table-graph"
/>
)
}
import { InsightsTable } from './InsightsTable'
export { InsightsTable }
70 changes: 8 additions & 62 deletions frontend/src/scenes/insights/LineGraph/LineGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,18 @@ import { useActions, useValues } from 'kea'
import Chart from '@posthog/chart.js'
import 'chartjs-adapter-dayjs'
import PropTypes from 'prop-types'
import { formatLabel, compactNumber, lightenDarkenColor } from '~/lib/utils'
import { compactNumber, lightenDarkenColor } from '~/lib/utils'
import { getBarColorFromStatus, getChartColors } from 'lib/colors'
import { useWindowSize } from 'lib/hooks/useWindowSize'
import { toast } from 'react-toastify'
import { Annotations, annotationsLogic, AnnotationMarker } from 'lib/components/Annotations'
import { useEscapeKey } from 'lib/hooks/useEscapeKey'
import dayjs from 'dayjs'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import './LineGraph.scss'
import { InsightLabel } from 'lib/components/InsightLabel'
import { FEATURE_FLAGS } from 'lib/constants'
import { InsightTooltip } from '../InsightTooltip'

//--Chart Style Options--//
// Chart.defaults.global.defaultFontFamily = "'PT Sans', sans-serif"
Chart.defaults.global.legend.display = false
Chart.defaults.global.animation.duration = 0
Chart.defaults.global.elements.line.tension = 0
Expand All @@ -43,8 +40,6 @@ export function LineGraph({
}) {
const chartRef = useRef()
const myLineChart = useRef()
const { featureFlags } = useValues(featureFlagLogic)
const newUI = featureFlags[FEATURE_FLAGS.NEW_TOOLTIPS]
const annotationsRoot = useRef()
const [left, setLeft] = useState(-1)
const [holdLeft, setHoldLeft] = useState(0)
Expand Down Expand Up @@ -156,9 +151,9 @@ export function LineGraph({
: undefined,
backgroundColor: BACKGROUND_BASED_CHARTS.includes(type) ? mainColor : undefined,
fill: false,
borderWidth: newUI ? 2 : 1,
pointRadius: newUI ? 0 : undefined,
pointHoverBorderWidth: newUI ? 2 : undefined,
borderWidth: 2,
pointRadius: 0,
pointHoverBorderWidth: 2,
pointHitRadius: 8,
...dataset,
}
Expand Down Expand Up @@ -224,7 +219,7 @@ export function LineGraph({

const inspectUsersLabel = !dashboardItemId && onClick && showPersonsModal

const newUITooltipOptions = {
const tooltipOptions = {
enabled: false, // disable builtin tooltip (use custom markup)
mode: 'nearest',
// If bar, we want to only show the tooltip for what we're hovering over
Expand Down Expand Up @@ -349,62 +344,13 @@ export function LineGraph({
},
}

const tooltipOptions = newUI
? newUITooltipOptions
: {
enabled: true,
intersect: false,
mode: 'nearest',
// If bar, we want to only show the tooltip for what we're hovering over
// to avoid confusion
axis: { bar: 'x', horizontalBar: 'y' }[type],
bodySpacing: 5,
position: 'nearest',
yPadding: 10,
xPadding: 10,
caretPadding: 0,
displayColors: false,
backgroundColor: colors.tooltipBackground,
titleFontColor: colors.tooltipTitle,
bodyFontColor: colors.tooltipBody,
footerFontColor: colors.tooltipBody,
borderColor: colors.tooltipBorder,
labelFontSize: 23,
cornerRadius: 4,
fontSize: 12,
footerSpacing: 0,
titleSpacing: 0,
footerFontStyle: 'italic',
callbacks: {
label: function (tooltipItem, data) {
let entityData = data.datasets[tooltipItem.datasetIndex]
if (entityData.dotted && !(tooltipItem.index === entityData.data.length - 1)) {
return null
}
const label = entityData.chartLabel || entityData.label || tooltipItem.label || ''
const action =
entityData.action || (entityData.actions && entityData.actions[tooltipItem.index])
const formattedLabel = action ? formatLabel(label, action) : label

let value = tooltipItem.yLabel.toLocaleString()
if (type === 'horizontalBar') {
const perc = Math.round((tooltipItem.xLabel / totalValue) * 100, 2)
value = `${tooltipItem.xLabel.toLocaleString()} (${perc}%)`
}
return (formattedLabel ? formattedLabel + ' — ' : '') + value + (percentage ? '%' : '')
},
footer: () => (inspectUsersLabel ? 'Click to see users related to the datapoint' : ''),
},
itemSort: (a, b) => b.yLabel - a.yLabel,
}

let options = {
responsive: true,
maintainAspectRatio: false,
scaleShowHorizontalLines: false,
tooltips: tooltipOptions,
plugins:
newUI && type !== 'horizontalBar' && !datasets[0].status
type !== 'horizontalBar' && !datasets[0].status
? {
crosshair: {
snap: {
Expand All @@ -426,9 +372,9 @@ export function LineGraph({
crosshair: false,
},
hover: {
mode: newUI ? 'nearestX' : 'nearest',
mode: 'nearestX',
axis: 'xy',
intersect: !newUI,
intersect: false,
onHover(evt) {
if (onClick) {
const point = this.getElementAtEvent(evt)
Expand Down

0 comments on commit 75d50e3

Please sign in to comment.