Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insights table - New UI #4700

Merged
merged 17 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions frontend/src/lib/components/DateDisplay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import './DateDisplay.scss'
interface DateDisplayProps {
date: string
interval: IntervalType
hideWeekRange?: boolean
}

const DISPLAY_DATE_FORMAT: Record<IntervalType, string> = {
Expand All @@ -29,21 +30,21 @@ const dateHighlight = (parsedDate: dayjs.Dayjs, interval: IntervalType): string
case 'month':
return parsedDate.format('YYYY')
default:
return ''
return parsedDate.format('dd')
}
}

/* Returns a single line standardized component to display the date depending on context.
For example, a single date in a graph will be shown as: `Th` Apr 22.
*/
export function DateDisplay({ date, interval }: DateDisplayProps): JSX.Element {
export function DateDisplay({ date, interval, hideWeekRange }: DateDisplayProps): JSX.Element {
const parsedDate = dayjs(date)

return (
<>
<span className="dated-highlight">{dateHighlight(parsedDate, interval)}</span>
{parsedDate.format(DISPLAY_DATE_FORMAT[interval])}
{interval === 'week' && (
{interval === 'week' && !hideWeekRange && (
<>
{/* TODO: @EDsCODE will help validate; this should probably come from the backend */}
{' - '}
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/lib/components/InsightLabel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ interface InsightsLabelProps {
action?: ActionFilter
value?: string
breakdownValue?: string
hideBreakdown?: boolean // Whether to hide the breakdown detail in the label
hideIcon?: boolean // Whether to hide the icon that showcases the color of the series
seriesStatus?: string // Used by lifecycle chart to display the series name
fallbackName?: string // Name to display for the series if it can be determined from `action`
hasMultipleSeries?: boolean // Whether the graph has multiple discrete series (not breakdown values)
Expand Down Expand Up @@ -47,6 +49,8 @@ export function InsightLabel({
action,
value,
breakdownValue,
hideBreakdown,
hideIcon,
seriesStatus,
fallbackName,
hasMultipleSeries,
Expand All @@ -58,7 +62,7 @@ export function InsightLabel({
return (
<Row className="insights-label" wrap={false}>
<Col style={{ display: 'flex', alignItems: 'center' }} flex="auto">
{!(hasMultipleSeries && !breakdownValue) && (
{!(hasMultipleSeries && !breakdownValue) && !hideIcon && (
<div
className="color-icon"
style={{
Expand All @@ -75,13 +79,13 @@ export function InsightLabel({
/>
)}
<div className="protect-width">
{showEventName && <PropertyKeyInfo disableIcon value={eventName} />}
{showEventName && <PropertyKeyInfo disableIcon disablePopover value={eventName} />}

{hasMultipleSeries && ((action?.math && action.math !== 'total') || showCountedByTag) && (
<MathTag math={action?.math} mathProperty={action?.math_property} />
)}

{breakdownValue && (
{breakdownValue && !hideBreakdown && (
<>
{hasMultipleSeries && <span style={{ padding: '0 2px' }}>-</span>}
{breakdownValue === 'total' ? <i>Total</i> : breakdownValue}
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/lib/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
endWithPunctation,
dateFilterToText,
hexToRGBA,
average,
median,
} from './utils'

describe('capitalizeFirstLetter()', () => {
Expand Down Expand Up @@ -168,3 +170,20 @@ describe('hexToRGBA()', () => {
expect(hexToRGBA('#5375ff', 1)).toEqual('rgba(83,117,255,1)')
})
})

describe('average()', () => {
it('calculates average correctly', () => {
expect(average([9, 4, 1, 3, 5, 7])).toEqual(4.8)
expect(average([72, 35, 68, 66, 70, 9, 81])).toEqual(57.3) // Tests rounding too
expect(average([86.4, 46.321, 45.304, 34.1, 147])).toEqual(71.8) // Tests rounding too
})
})

describe('median()', () => {
it('returns middle number if array length is odd', () => {
expect(median([9, 4, 1, 3, 5, 7, 3, 6, 14])).toEqual(5)
})
it('returns avg of middle numbers if array length is even', () => {
expect(median([9, 4, 0, 5, 7, 3, 6, 14])).toEqual(5.5)
})
})
22 changes: 22 additions & 0 deletions frontend/src/lib/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -908,3 +908,25 @@ export function lightenDarkenColor(hex: string, pct: number): string {
export function toString(input?: any | null): string {
return input?.toString() || ''
}

export function average(input: number[]): number {
/**
* Returns the average of an array
* @param input e.g. [100,50, 75]
*/
return Math.round((input.reduce((acc, val) => acc + val, 0) / input.length) * 10) / 10
}

export function median(input: number[]): number {
/**
* Returns the median of an array
* @param input e.g. [3,7,10]
*/
const sorted = [...input].sort((a, b) => a - b)
const half = Math.floor(sorted.length / 2)

if (sorted.length % 2) {
return sorted[half]
}
return average([sorted[half - 1], sorted[half]])
}
8 changes: 6 additions & 2 deletions frontend/src/lib/utils/eventUsageLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export const eventUsageLogic = kea<
reportSavedInsightToDashboard: true,
reportInsightsTabReset: true,
reportInsightsControlsCollapseToggle: (collapsed: boolean) => ({ collapsed }),
reportInsightsTableCalcToggled: (mode: string) => ({ mode }),
},
listeners: {
reportAnnotationViewed: async ({ annotations }, breakpoint) => {
Expand Down Expand Up @@ -430,8 +431,11 @@ export const eventUsageLogic = kea<
reportInsightsTabReset: async () => {
posthog.capture('insights tab reset')
},
reportInsightsControlsCollapseToggle: async ({ collapsed }) => {
posthog.capture('insight controls collapse toggled', { collapsed })
reportInsightsControlsCollapseToggle: async (payload) => {
posthog.capture('insight controls collapse toggled', payload)
},
reportInsightsTableCalcToggled: async (payload) => {
posthog.capture('insights table calc toggled', payload)
},
},
})
18 changes: 12 additions & 6 deletions frontend/src/scenes/insights/Insights.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'

import { Tabs, Row, Col, Card, Button, Tooltip } from 'antd'
import { ACTIONS_LINE_GRAPH_LINEAR, ACTIONS_LINE_GRAPH_CUMULATIVE, FUNNEL_VIZ, FEATURE_FLAGS } from 'lib/constants'
import { FUNNEL_VIZ, FEATURE_FLAGS, ACTIONS_TABLE, ACTIONS_BAR_CHART_VALUE } from 'lib/constants'
import { annotationsLogic } from '~/lib/components/Annotations'
import { router } from 'kea-router'

Expand Down Expand Up @@ -363,20 +363,26 @@ export function Insights(): JSX.Element {
!showTimeoutMessage &&
activeView === ViewType.FUNNELS &&
allFilters.display === FUNNEL_VIZ && (
<Card style={{ marginTop: 16 }}>
<Card style={{ marginTop: 8 }}>
<FunnelPeople />
</Card>
)}
{(!allFilters.display ||
allFilters.display === ACTIONS_LINE_GRAPH_LINEAR ||
allFilters.display === ACTIONS_LINE_GRAPH_CUMULATIVE) &&
(allFilters.display !== ACTIONS_TABLE &&
allFilters.display !== ACTIONS_BAR_CHART_VALUE)) &&
(activeView === ViewType.TRENDS || activeView === ViewType.SESSIONS) && (
<Card style={{ marginTop: 16 }}>
/* InsightsTable is loaded for all trend views (except below), plus the sessions view.
Exclusions:
1. Table view. Because table is already loaded anyways in `Trends.tsx` as the main component.
2. Bar value chart. Because this view displays data in completely different dimensions.
*/
<Card style={{ marginTop: 8 }}>
<BindLogic
logic={trendsLogic}
props={{ dashboardItemId: null, view: activeView }}
>
<InsightsTable />
<h3 className="l3">Details table</h3>
<InsightsTable showTotalCount={activeView !== ViewType.SESSIONS} />
</BindLogic>
</Card>
)}
Expand Down
Loading