Skip to content

Commit

Permalink
fix(insights): use results from data node for retention (#15913)
Browse files Browse the repository at this point in the history
  • Loading branch information
thmsobrmlr authored Jun 7, 2023
1 parent babafc5 commit 4992bba
Show file tree
Hide file tree
Showing 11 changed files with 390 additions and 356 deletions.
8 changes: 6 additions & 2 deletions frontend/src/exporter/ExportedInsight/ExportedInsight.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChartDisplayType, InsightLogicProps, InsightModel } from '~/types'
import { BindLogic } from 'kea'
import { insightLogic } from 'scenes/insights/insightLogic'
import { InsightViz } from 'lib/components/Cards/InsightCard/InsightCard'
import { FilterBasedCardContent } from 'lib/components/Cards/InsightCard/InsightCard'
import './ExportedInsight.scss'
import { FriendlyLogo } from '~/toolbar/assets/FriendlyLogo'
import { InsightLegend } from 'lib/components/InsightLegend/InsightLegend'
Expand Down Expand Up @@ -91,7 +91,11 @@ export function ExportedInsight({
<QueriesUnsupportedHere />
)
) : (
<InsightViz insight={insight as any} style={{ top: 0, left: 0 }} />
<FilterBasedCardContent
insight={insight as any}
insightProps={insightLogicProps}
style={{ top: 0, left: 0 }}
/>
)}
{showLegend ? (
<div className="p-4">
Expand Down
353 changes: 53 additions & 300 deletions frontend/src/lib/components/Cards/InsightCard/InsightCard.tsx

Large diffs are not rendered by default.

267 changes: 267 additions & 0 deletions frontend/src/lib/components/Cards/InsightCard/InsightMeta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
import { useActions, useValues } from 'kea'
import { capitalizeFirstLetter } from 'lib/utils'
import React from 'react'
import { insightLogic } from 'scenes/insights/insightLogic'
import { urls } from 'scenes/urls'
import { dashboardsModel } from '~/models/dashboardsModel'
import { ExporterFormat, InsightColor } from '~/types'
import { Splotch, SplotchColor } from 'lib/lemon-ui/Splotch'
import { LemonButton, LemonButtonWithDropdown } from 'lib/lemon-ui/LemonButton'
import { LemonDivider } from 'lib/lemon-ui/LemonDivider'
import { Link } from 'lib/lemon-ui/Link'
import { ObjectTags } from 'lib/components/ObjectTags/ObjectTags'
import { InsightDetails } from './InsightDetails'
import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import { groupsModel } from '~/models/groupsModel'
import { cohortsModel } from '~/models/cohortsModel'
import { mathsLogic } from 'scenes/trends/mathsLogic'
import { UserActivityIndicator } from '../../UserActivityIndicator/UserActivityIndicator'
import { ExportButton } from 'lib/components/ExportButton/ExportButton'
import { CardMeta } from 'lib/components/Cards/CardMeta'
import { DashboardPrivilegeLevel, FEATURE_FLAGS } from 'lib/constants'
import { PieChartFilled } from '@ant-design/icons'
import { Tooltip } from 'lib/lemon-ui/Tooltip'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { TopHeading } from 'lib/components/Cards/InsightCard/TopHeading'
import { summarizeInsight } from 'scenes/insights/summarizeInsight'
import { InsightCardProps } from './InsightCard'

interface InsightMetaProps
extends Pick<
InsightCardProps,
| 'insight'
| 'ribbonColor'
| 'updateColor'
| 'removeFromDashboard'
| 'deleteWithUndo'
| 'refresh'
| 'rename'
| 'duplicate'
| 'dashboardId'
| 'moveToDashboard'
| 'showEditingControls'
| 'showDetailsControls'
| 'moreButtons'
> {
/**
* Optional callback to update height of the primary InsightMeta div. Allow for coordinating InsightViz height
* with InsightMeta in a way that makes it possible for meta to overlay viz in expanded (InsightDetails) state.
*/
setPrimaryHeight?: (primaryHeight: number | undefined) => void
areDetailsShown?: boolean
setAreDetailsShown?: React.Dispatch<React.SetStateAction<boolean>>
}

export function InsightMeta({
insight,
ribbonColor,
dashboardId,
updateColor,
removeFromDashboard,
deleteWithUndo,
refresh,
rename,
duplicate,
moveToDashboard,
setPrimaryHeight,
areDetailsShown,
setAreDetailsShown,
showEditingControls = true,
showDetailsControls = true,
moreButtons,
}: InsightMetaProps): JSX.Element {
const { short_id, name, dashboards } = insight
const { exporterResourceParams, insightProps } = useValues(insightLogic)
const { reportDashboardItemRefreshed } = useActions(eventUsageLogic)
const { aggregationLabel } = useValues(groupsModel)
const { cohortsById } = useValues(cohortsModel)
const { nameSortedDashboards } = useValues(dashboardsModel)
const { mathDefinitions } = useValues(mathsLogic)
const { featureFlags } = useValues(featureFlagLogic)

const otherDashboards = nameSortedDashboards.filter((d) => !dashboards?.includes(d.id))
const editable = insight.effective_privilege_level >= DashboardPrivilegeLevel.CanEdit

// not all interactions are currently implemented for queries
const allInteractionsAllowed = !insight.query

const summary = summarizeInsight(insight.query, insight.filters, {
aggregationLabel,
cohortsById,
mathDefinitions,
isUsingDashboardQueries: !!featureFlags[FEATURE_FLAGS.HOGQL],
})

return (
<CardMeta
setPrimaryHeight={setPrimaryHeight}
ribbonColor={ribbonColor}
showEditingControls={showEditingControls}
showDetailsControls={showDetailsControls}
setAreDetailsShown={setAreDetailsShown}
areDetailsShown={areDetailsShown}
className={'border-b'}
topHeading={<TopHeading insight={insight} />}
meta={
<>
<Link to={urls.insightView(short_id)}>
<h4 title={name} data-attr="insight-card-title">
{name || <i>{summary}</i>}
</h4>
</Link>

{!!insight.description && <div className="CardMeta__description">{insight.description}</div>}
{insight.tags && insight.tags.length > 0 && <ObjectTags tags={insight.tags} staticOnly />}
<UserActivityIndicator at={insight.last_modified_at} by={insight.last_modified_by} />
</>
}
metaDetails={<InsightDetails insight={insight} />}
samplingNotice={
insight.filters.sampling_factor && insight.filters.sampling_factor < 1 ? (
<Tooltip title={`Results calculated from ${100 * insight.filters.sampling_factor}% of users`}>
<PieChartFilled className="mr-2" style={{ color: 'var(--primary-light)' }} />
</Tooltip>
) : null
}
moreButtons={
<>
{allInteractionsAllowed && (
<>
<LemonButton status="stealth" to={urls.insightView(short_id)} fullWidth>
View
</LemonButton>
{refresh && (
<LemonButton
status="stealth"
onClick={() => {
refresh()
reportDashboardItemRefreshed(insight)
}}
fullWidth
>
Refresh
</LemonButton>
)}
</>
)}
{editable && updateColor && (
<LemonButtonWithDropdown
status="stealth"
dropdown={{
overlay: Object.values(InsightColor).map((availableColor) => (
<LemonButton
key={availableColor}
active={availableColor === (ribbonColor || InsightColor.White)}
status="stealth"
onClick={() => updateColor(availableColor)}
icon={
availableColor !== InsightColor.White ? (
<Splotch color={availableColor as string as SplotchColor} />
) : null
}
fullWidth
>
{availableColor !== InsightColor.White
? capitalizeFirstLetter(availableColor)
: 'No color'}
</LemonButton>
)),
placement: 'right-start',
fallbackPlacements: ['left-start'],
actionable: true,
closeParentPopoverOnClickInside: true,
}}
fullWidth
>
Set color
</LemonButtonWithDropdown>
)}
{editable && moveToDashboard && otherDashboards.length > 0 && (
<LemonButtonWithDropdown
status="stealth"
dropdown={{
overlay: otherDashboards.map((otherDashboard) => (
<LemonButton
key={otherDashboard.id}
status="stealth"
onClick={() => {
moveToDashboard(otherDashboard)
}}
fullWidth
>
{otherDashboard.name || <i>Untitled</i>}
</LemonButton>
)),
placement: 'right-start',
fallbackPlacements: ['left-start'],
actionable: true,
closeParentPopoverOnClickInside: true,
}}
fullWidth
>
Move to
</LemonButtonWithDropdown>
)}
<LemonDivider />
{editable && allInteractionsAllowed && (
<LemonButton status="stealth" to={urls.insightEdit(short_id)} fullWidth>
Edit
</LemonButton>
)}
{editable && (
<LemonButton status="stealth" onClick={rename} fullWidth>
Rename
</LemonButton>
)}
<LemonButton
status="stealth"
onClick={duplicate}
fullWidth
data-attr={
dashboardId ? 'duplicate-insight-from-dashboard' : 'duplicate-insight-from-card-list-view'
}
>
Duplicate
</LemonButton>
<LemonDivider />
{exporterResourceParams ? (
<ExportButton
fullWidth
items={[
{
export_format: ExporterFormat.PNG,
insight: insight.id,
dashboard: insightProps.dashboardId,
},
{
export_format: ExporterFormat.CSV,
export_context: exporterResourceParams,
},
]}
/>
) : null}
{moreButtons && (
<>
<LemonDivider />
{moreButtons}
</>
)}
{editable && (
<>
<LemonDivider />
{removeFromDashboard ? (
<LemonButton status="danger" onClick={removeFromDashboard} fullWidth>
Remove from dashboard
</LemonButton>
) : allInteractionsAllowed ? (
<LemonButton status="danger" onClick={deleteWithUndo} fullWidth>
Delete insight
</LemonButton>
) : null}
</>
)}
</>
}
/>
)
}
8 changes: 6 additions & 2 deletions frontend/src/queries/nodes/DataNode/dataNodeLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { removeExpressionComment } from '~/queries/nodes/DataTable/utils'
import { userLogic } from 'scenes/userLogic'
import { UNSAVED_INSIGHT_MIN_REFRESH_INTERVAL_MINUTES } from 'scenes/insights/insightLogic'
import { teamLogic } from 'scenes/teamLogic'
import equal from 'fast-deep-equal'

export interface DataNodeLogicProps {
key: string
Expand All @@ -44,14 +45,17 @@ export const dataNodeLogic = kea<dataNodeLogicType>([
}),
props({} as DataNodeLogicProps),
key((props) => props.key),
propsChanged(({ actions, props }, oldProps) => {
propsChanged(({ actions, props, values }, oldProps) => {
if (props.query?.kind && oldProps.query?.kind && props.query.kind !== oldProps.query.kind) {
actions.clearResponse()
}
if (props.query?.kind && !objectsEqual(props.query, oldProps.query) && !props.cachedResults) {
actions.loadData()
}
if (props.cachedResults && oldProps.cachedResults == null) {
if (
props.cachedResults &&
(!values.response || (oldProps.cachedResults && !equal(props.cachedResults, oldProps.cachedResults)))
) {
actions.setResponse(props.cachedResults)
}
}),
Expand Down
27 changes: 2 additions & 25 deletions frontend/src/queries/nodes/InsightViz/InsightViz.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { BindLogic, useValues } from 'kea'
import clsx from 'clsx'
import equal from 'fast-deep-equal'

import { insightLogic } from 'scenes/insights/insightLogic'
import { insightSceneLogic } from 'scenes/insights/insightSceneLogic'
Expand All @@ -11,31 +10,9 @@ import { InsightQueryNode, InsightVizNode, QueryContext } from '../../schema'

import { InsightContainer } from './InsightContainer'
import { EditorFilters } from './EditorFilters'
import { InsightLogicProps, InsightModel, ItemMode } from '~/types'
import { InsightLogicProps, ItemMode } from '~/types'
import { keyForInsightLogicProps } from 'scenes/insights/sharedUtils'
import { filtersToQueryNode } from '../InsightQuery/utils/filtersToQueryNode'

const getCachedResults = (
cachedInsight: Partial<InsightModel> | undefined | null,
query: InsightQueryNode
): Partial<InsightModel> | undefined => {
if (
!cachedInsight ||
cachedInsight.result === null ||
cachedInsight.result === undefined ||
cachedInsight.filters === undefined
) {
return undefined
}

// only set the cached result when the filters match the currently set ones
const cachedQueryNode = filtersToQueryNode(cachedInsight.filters)
if (!equal(cachedQueryNode, query)) {
return undefined
}

return cachedInsight
}
import { getCachedResults } from './utils'

/** The key for the dataNodeLogic mounted by an InsightViz for insight of insightProps */
export const insightVizDataNodeKey = (insightProps: InsightLogicProps): string => {
Expand Down
Loading

0 comments on commit 4992bba

Please sign in to comment.