From f403b175005f2330aa485e58861e47f03b76640f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Oberm=C3=BCller?= Date: Tue, 13 Aug 2024 08:09:52 +0200 Subject: [PATCH] refactor(insights): move to queries in new insight urls (#24193) Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- cypress/e2e/insights-navigation.cy.ts | 1 - ...alendar-select--with-time-toggle--dark.png | Bin 26387 -> 23892 bytes ...lendar-select--with-time-toggle--light.png | Bin 26034 -> 23425 bytes .../navigation-3000/sidebars/featureFlags.tsx | 31 ++++-- .../CommandPalette/commandPaletteLogic.tsx | 12 +- frontend/src/lib/utils/eventUsageLogic.ts | 12 +- .../queries/nodes/DataTable/BackToSource.tsx | 4 +- .../nodes/DataTable/DataTableOpenEditor.tsx | 20 ++-- .../queries/nodes/Node/EditHogQLButton.tsx | 17 ++- .../queries/nodes/Node/OpenEditorButton.tsx | 2 +- .../data-management/actions/ActionsTable.tsx | 52 ++++----- .../database/DatabaseTables.tsx | 2 +- .../external/forms/SyncProgressStep.tsx | 2 +- .../experiments/ExperimentView/components.tsx | 34 +++--- .../src/scenes/feature-flags/FeatureFlags.tsx | 34 ++++-- .../RecentFeatureFlagInsightsCard.tsx | 22 +++- .../src/scenes/funnels/FunnelStepMore.tsx | 80 +++++-------- .../insights/InsightNav/insightNavLogic.tsx | 61 ++-------- .../src/scenes/insights/InsightPageHeader.tsx | 20 ++-- .../src/scenes/insights/insightDataLogic.tsx | 41 ++++++- .../scenes/insights/insightSceneLogic.test.ts | 30 ++++- .../src/scenes/insights/insightSceneLogic.tsx | 94 ++++++++++++---- frontend/src/scenes/insights/utils.tsx | 105 ++++++++++-------- .../scenes/insights/utils/compareFilters.ts | 2 +- frontend/src/scenes/paths/pathsDataLogic.ts | 25 +++-- .../scenes/retention/retentionModalLogic.ts | 2 +- .../saved-insights/savedInsightsLogic.test.ts | 15 +-- .../saved-insights/savedInsightsLogic.ts | 4 - .../project/PathCleaningFiltersConfig.tsx | 4 +- frontend/src/scenes/surveys/SurveyView.tsx | 29 +---- frontend/src/scenes/surveys/surveyLogic.tsx | 44 +++++++- .../trends/persons-modal/personsModalLogic.ts | 2 +- frontend/src/scenes/urls.ts | 12 +- .../web-analytics/WebAnalyticsModal.tsx | 6 +- .../web-analytics/webAnalyticsLogic.tsx | 20 ++-- 35 files changed, 462 insertions(+), 379 deletions(-) diff --git a/cypress/e2e/insights-navigation.cy.ts b/cypress/e2e/insights-navigation.cy.ts index 1cb88f0c2b93f..eccb3f86cbf58 100644 --- a/cypress/e2e/insights-navigation.cy.ts +++ b/cypress/e2e/insights-navigation.cy.ts @@ -71,7 +71,6 @@ describe('Insights', () => { it('can open event explorer as an insight', () => { cy.clickNavMenu('activity') - cy.get('[data-attr="data-table-export-menu"]').click() cy.get('[data-attr="open-json-editor-button"]').click() cy.get('[data-attr="insight-json-tab"]').should('exist') }) diff --git a/frontend/__snapshots__/lemon-ui-lemon-calendar-lemon-calendar-select--with-time-toggle--dark.png b/frontend/__snapshots__/lemon-ui-lemon-calendar-lemon-calendar-select--with-time-toggle--dark.png index 966ad47ae71b02513c1533085a4600ff5bdbc3dc..818a792142337504575b48ef89fdf3ab6c931b0c 100644 GIT binary patch literal 23892 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 literal 26034 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 diff --git a/frontend/src/layout/navigation-3000/sidebars/featureFlags.tsx b/frontend/src/layout/navigation-3000/sidebars/featureFlags.tsx index 16acfa8f807e5..9f022d067003e 100644 --- a/frontend/src/layout/navigation-3000/sidebars/featureFlags.tsx +++ b/frontend/src/layout/navigation-3000/sidebars/featureFlags.tsx @@ -13,7 +13,8 @@ import { teamLogic } from 'scenes/teamLogic' import { urls } from 'scenes/urls' import { groupsModel } from '~/models/groupsModel' -import { FeatureFlagType } from '~/types' +import { InsightVizNode, NodeKind } from '~/queries/schema' +import { BaseMathType, FeatureFlagType } from '~/types' import { navigation3000Logic } from '../navigationLogic' import { ExtendedListItem, SidebarCategory } from '../types' @@ -56,6 +57,26 @@ export const featureFlagsSidebarLogic = kea([ if (!featureFlag.id) { throw new Error('Feature flag ID should never be missing in the sidebar') } + + const query: InsightVizNode = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.TrendsQuery, + series: [ + { + event: '$pageview', + name: '$pageview', + kind: NodeKind.EventsNode, + math: BaseMathType.UniqueUsers, + }, + ], + breakdownFilter: { + breakdown: `$feature/${featureFlag.key}`, + breakdown_type: 'event', + }, + }, + } + return { key: featureFlag.id, name: featureFlag.key, @@ -115,13 +136,7 @@ export const featureFlagsSidebarLogic = kea([ }, { label: 'Try out in Insights', - to: urls.insightNew({ - events: [ - { id: '$pageview', name: '$pageview', type: 'events', math: 'dau' }, - ], - breakdown_type: 'event', - breakdown: `$feature/${featureFlag.key}`, - }), + to: urls.insightNew(undefined, undefined, query), 'data-attr': 'usage', }, ], diff --git a/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx b/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx index 6b94e11224320..9f1f2d5cfda9d 100644 --- a/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx +++ b/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx @@ -431,7 +431,7 @@ export const commandPaletteLogic = kea([ display: 'Create a new Trend insight', executor: () => { // TODO: Don't reset insight on change - push(urls.insightNew({ insight: InsightType.TRENDS })) + push(urls.insightNew(InsightType.TRENDS)) }, }, { @@ -439,7 +439,7 @@ export const commandPaletteLogic = kea([ display: 'Create a new Funnel insight', executor: () => { // TODO: Don't reset insight on change - push(urls.insightNew({ insight: InsightType.FUNNELS })) + push(urls.insightNew(InsightType.FUNNELS)) }, }, { @@ -447,7 +447,7 @@ export const commandPaletteLogic = kea([ display: 'Create a new Retention insight', executor: () => { // TODO: Don't reset insight on change - push(urls.insightNew({ insight: InsightType.RETENTION })) + push(urls.insightNew(InsightType.RETENTION)) }, }, { @@ -455,7 +455,7 @@ export const commandPaletteLogic = kea([ display: 'Create a new Paths insight', executor: () => { // TODO: Don't reset insight on change - push(urls.insightNew({ insight: InsightType.PATHS })) + push(urls.insightNew(InsightType.PATHS)) }, }, { @@ -463,7 +463,7 @@ export const commandPaletteLogic = kea([ display: 'Create a new Stickiness insight', executor: () => { // TODO: Don't reset insight on change - push(urls.insightNew({ insight: InsightType.STICKINESS })) + push(urls.insightNew(InsightType.STICKINESS)) }, }, { @@ -471,7 +471,7 @@ export const commandPaletteLogic = kea([ display: 'Create a new Lifecycle insight', executor: () => { // TODO: Don't reset insight on change - push(urls.insightNew({ insight: InsightType.LIFECYCLE })) + push(urls.insightNew(InsightType.LIFECYCLE)) }, }, { diff --git a/frontend/src/lib/utils/eventUsageLogic.ts b/frontend/src/lib/utils/eventUsageLogic.ts index 8aef510145114..30140759c4e2a 100644 --- a/frontend/src/lib/utils/eventUsageLogic.ts +++ b/frontend/src/lib/utils/eventUsageLogic.ts @@ -34,6 +34,7 @@ import { isFunnelsQuery, isInsightQueryNode, isInsightVizNode, + isNodeWithSource, } from '~/queries/utils' import { AccessLevel, @@ -235,6 +236,7 @@ function sanitizeFilterParams(filters: AnyPartialFilterType): Record { const payload: Record = { query_kind: query?.kind, + query_source_kind: isNodeWithSource(query) ? query.source.kind : undefined, } if (isInsightVizNode(query) || isInsightQueryNode(query)) { @@ -290,7 +292,7 @@ export const eventUsageLogic = kea([ params, }), // insights - reportInsightCreated: (insightType: InsightType | null) => ({ insightType }), + reportInsightCreated: (query: Node | null) => ({ query }), reportInsightSaved: (query: Node | null, isNewInsight: boolean) => ({ query, isNewInsight }), reportInsightViewed: ( insightModel: Partial, @@ -630,10 +632,14 @@ export const eventUsageLogic = kea([ } posthog.capture('person viewed', properties) }, - reportInsightCreated: async ({ insightType }, breakpoint) => { + reportInsightCreated: async ({ query }, breakpoint) => { // "insight created" essentially means that the user clicked "New insight" await breakpoint(500) // Debounce to avoid multiple quick "New insight" clicks being reported - posthog.capture('insight created', { insight: insightType }) + + posthog.capture('insight created', { + query_kind: query?.kind, + query_source_kind: isNodeWithSource(query) ? query.source.kind : undefined, + }) }, reportInsightSaved: async ({ query, isNewInsight }) => { // "insight saved" is a proxy for the new insight's results being valuable to the user diff --git a/frontend/src/queries/nodes/DataTable/BackToSource.tsx b/frontend/src/queries/nodes/DataTable/BackToSource.tsx index c56c1b94b158f..9b47d4fa0b358 100644 --- a/frontend/src/queries/nodes/DataTable/BackToSource.tsx +++ b/frontend/src/queries/nodes/DataTable/BackToSource.tsx @@ -30,9 +30,7 @@ export function BackToSource(): JSX.Element | null { - router.actions.push(urls.insightNew(undefined, undefined, JSON.stringify(backToSourceQuery))) - } + onClick={() => router.actions.push(urls.insightNew(undefined, undefined, backToSourceQuery))} > « Back to {backToSourceQuery.source.kind?.replace('Query', '') ?? 'Insight'} diff --git a/frontend/src/queries/nodes/DataTable/DataTableOpenEditor.tsx b/frontend/src/queries/nodes/DataTable/DataTableOpenEditor.tsx index 71eb46a0e7652..6b445ca6ed491 100644 --- a/frontend/src/queries/nodes/DataTable/DataTableOpenEditor.tsx +++ b/frontend/src/queries/nodes/DataTable/DataTableOpenEditor.tsx @@ -16,11 +16,19 @@ interface DataTableOpenEditorProps { export function DataTableOpenEditor({ query }: DataTableOpenEditorProps): JSX.Element | null { const { response } = useValues(dataTableLogic) + const tableInsightQuery: DataTableNode | null = response?.hogql + ? { + kind: NodeKind.DataTableNode, + full: true, + source: { kind: NodeKind.HogQLQuery, query: response.hogql }, + } + : null + return ( } - to={urls.insightNew(undefined, undefined, JSON.stringify(query))} + to={urls.insightNew(undefined, undefined, query)} sideAction={ response?.hogql ? { @@ -30,15 +38,7 @@ export function DataTableOpenEditor({ query }: DataTableOpenEditorProps): JSX.El items={[ { label: 'Open as direct SQL insight', - to: urls.insightNew( - undefined, - undefined, - JSON.stringify({ - kind: NodeKind.DataTableNode, - full: true, - source: { kind: NodeKind.HogQLQuery, query: response.hogql }, - }) - ), + to: urls.insightNew(undefined, undefined, tableInsightQuery!), 'data-attr': 'open-sql-editor-button', }, ]} diff --git a/frontend/src/queries/nodes/Node/EditHogQLButton.tsx b/frontend/src/queries/nodes/Node/EditHogQLButton.tsx index b079d09840141..e116b98bb8e99 100644 --- a/frontend/src/queries/nodes/Node/EditHogQLButton.tsx +++ b/frontend/src/queries/nodes/Node/EditHogQLButton.tsx @@ -2,26 +2,23 @@ import { IconQueryEditor } from 'lib/lemon-ui/icons' import { LemonButton, LemonButtonWithoutSideActionProps } from 'lib/lemon-ui/LemonButton' import { urls } from 'scenes/urls' -import { NodeKind } from '~/queries/schema' +import { DataTableNode, NodeKind } from '~/queries/schema' export interface EditHogQLButtonProps extends LemonButtonWithoutSideActionProps { hogql: string } export function EditHogQLButton({ hogql, ...props }: EditHogQLButtonProps): JSX.Element { + const query: DataTableNode = { + kind: NodeKind.DataTableNode, + full: true, + source: { kind: NodeKind.HogQLQuery, query: hogql }, + } return ( } tooltip="Edit SQL directly" {...props} diff --git a/frontend/src/queries/nodes/Node/OpenEditorButton.tsx b/frontend/src/queries/nodes/Node/OpenEditorButton.tsx index 43c50ad820946..7e29aa6188ddd 100644 --- a/frontend/src/queries/nodes/Node/OpenEditorButton.tsx +++ b/frontend/src/queries/nodes/Node/OpenEditorButton.tsx @@ -13,7 +13,7 @@ export function OpenEditorButton({ query, ...props }: OpenEditorButtonProps): JS } tooltip="Open as a new insight" {...props} diff --git a/frontend/src/scenes/data-management/actions/ActionsTable.tsx b/frontend/src/scenes/data-management/actions/ActionsTable.tsx index a0164fad09672..9bb24e85a09a6 100644 --- a/frontend/src/scenes/data-management/actions/ActionsTable.tsx +++ b/frontend/src/scenes/data-management/actions/ActionsTable.tsx @@ -1,7 +1,6 @@ import { IconCheckCircle } from '@posthog/icons' import { LemonInput, LemonSegmentedButton } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' -import { combineUrl } from 'kea-router' import api from 'lib/api' import { ObjectTags } from 'lib/components/ObjectTags/ObjectTags' import { ProductIntroduction } from 'lib/components/ProductIntroduction/ProductIntroduction' @@ -19,15 +18,8 @@ import { actionsLogic } from 'scenes/actions/actionsLogic' import { userLogic } from 'scenes/userLogic' import { actionsModel } from '~/models/actionsModel' -import { - ActionType, - AvailableFeature, - ChartDisplayType, - FilterLogicalOperator, - InsightType, - ProductKey, - ReplayTabs, -} from '~/types' +import { InsightVizNode, NodeKind } from '~/queries/schema' +import { ActionType, AvailableFeature, ChartDisplayType, FilterLogicalOperator, ProductKey, ReplayTabs } from '~/types' import { NewActionButton } from '../../actions/NewActionButton' import { teamLogic } from '../../teamLogic' @@ -44,6 +36,25 @@ export function ActionsTable(): JSX.Element { const { hasAvailableFeature } = useValues(userLogic) const { updateHasSeenProductIntroFor } = useActions(userLogic) + const tryInInsightsUrl = (action: ActionType): string => { + const query: InsightVizNode = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.TrendsQuery, + series: [ + { + id: action.id, + name: action.name || undefined, + kind: NodeKind.ActionsNode, + }, + ], + interval: 'day', + trendsFilter: { display: ChartDisplayType.ActionsLineGraph }, + }, + } + return urls.insightNew(undefined, undefined, query) + } + const columns: LemonTableColumns = [ { title: 'Name', @@ -183,26 +194,7 @@ export function ActionsTable(): JSX.Element { > View recordings - + Try out in Insights diff --git a/frontend/src/scenes/data-management/database/DatabaseTables.tsx b/frontend/src/scenes/data-management/database/DatabaseTables.tsx index da69f2ff923b0..4304507754161 100644 --- a/frontend/src/scenes/data-management/database/DatabaseTables.tsx +++ b/frontend/src/scenes/data-management/database/DatabaseTables.tsx @@ -80,7 +80,7 @@ export function DatabaseTables({ const query = defaultQuery(table as string, Object.values(obj.fields)) return (
- + {table}
diff --git a/frontend/src/scenes/data-warehouse/external/forms/SyncProgressStep.tsx b/frontend/src/scenes/data-warehouse/external/forms/SyncProgressStep.tsx index e38cad0634274..03579c9a1cd44 100644 --- a/frontend/src/scenes/data-warehouse/external/forms/SyncProgressStep.tsx +++ b/frontend/src/scenes/data-warehouse/external/forms/SyncProgressStep.tsx @@ -74,7 +74,7 @@ export const SyncProgressStep = (): JSX.Element => { className="my-1" type="primary" onClick={() => cancelWizard()} - to={urls.insightNew(undefined, undefined, JSON.stringify(query))} + to={urls.insightNew(undefined, undefined, query)} > Query
diff --git a/frontend/src/scenes/experiments/ExperimentView/components.tsx b/frontend/src/scenes/experiments/ExperimentView/components.tsx index 0e808fb60a18a..73544888ab671 100644 --- a/frontend/src/scenes/experiments/ExperimentView/components.tsx +++ b/frontend/src/scenes/experiments/ExperimentView/components.tsx @@ -24,7 +24,7 @@ import { urls } from 'scenes/urls' import { filtersToQueryNode } from '~/queries/nodes/InsightQuery/utils/filtersToQueryNode' import { Query } from '~/queries/Query/Query' -import { NodeKind } from '~/queries/schema' +import { InsightVizNode, NodeKind } from '~/queries/schema' import { Experiment as ExperimentType, ExperimentResults, FilterType, InsightShortId, InsightType } from '~/types' import { experimentLogic } from '../experimentLogic' @@ -121,29 +121,27 @@ export function ExploreButton({ icon = }: { icon?: JSX.Element properties: [], } + const query: InsightVizNode = { + kind: NodeKind.InsightVizNode, + source: filtersToQueryNode( + transformResultFilters( + experimentResults?.filters + ? { ...experimentResults.filters, explicit_date: true } + : filtersFromExperiment + ) + ), + showTable: true, + showLastComputation: true, + showLastComputationRefresh: false, + } + return ( Explore results diff --git a/frontend/src/scenes/feature-flags/FeatureFlags.tsx b/frontend/src/scenes/feature-flags/FeatureFlags.tsx index 4824530c97dc7..bb935951ca995 100644 --- a/frontend/src/scenes/feature-flags/FeatureFlags.tsx +++ b/frontend/src/scenes/feature-flags/FeatureFlags.tsx @@ -25,10 +25,12 @@ import { urls } from 'scenes/urls' import { userLogic } from 'scenes/userLogic' import { groupsModel, Noun } from '~/models/groupsModel' +import { InsightVizNode, NodeKind } from '~/queries/schema' import { ActivityScope, AnyPropertyFilter, AvailableFeature, + BaseMathType, FeatureFlagFilters, FeatureFlagType, ProductKey, @@ -60,6 +62,28 @@ export function OverViewTab({ const { updateFeatureFlag, loadFeatureFlags, setSearchTerm, setFeatureFlagsFilters } = useActions(flagLogic) const { hasAvailableFeature } = useValues(userLogic) + const tryInInsightsUrl = (featureFlag: FeatureFlagType): string => { + const query: InsightVizNode = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.TrendsQuery, + series: [ + { + event: '$pageview', + name: '$pageview', + kind: NodeKind.EventsNode, + math: BaseMathType.UniqueUsers, + }, + ], + breakdownFilter: { + breakdown_type: 'event', + breakdown: `$feature/${featureFlag.key}`, + }, + }, + } + return urls.insightNew(undefined, undefined, query) + } + const columns: LemonTableColumns = [ { title: 'Key', @@ -203,15 +227,7 @@ export function OverViewTab({ Edit
)} - + Try out in Insights diff --git a/frontend/src/scenes/feature-flags/RecentFeatureFlagInsightsCard.tsx b/frontend/src/scenes/feature-flags/RecentFeatureFlagInsightsCard.tsx index 225a69bdbf761..4cfaec0046a92 100644 --- a/frontend/src/scenes/feature-flags/RecentFeatureFlagInsightsCard.tsx +++ b/frontend/src/scenes/feature-flags/RecentFeatureFlagInsightsCard.tsx @@ -3,12 +3,26 @@ import { CompactList } from 'lib/components/CompactList/CompactList' import { InsightRow } from 'scenes/project-homepage/RecentInsights' import { urls } from 'scenes/urls' -import { InsightModel } from '~/types' +import { InsightVizNode, NodeKind } from '~/queries/schema' +import { BaseMathType, InsightModel } from '~/types' import { featureFlagLogic } from './featureFlagLogic' export function RecentFeatureFlagInsights(): JSX.Element { const { relatedInsights, relatedInsightsLoading, featureFlag } = useValues(featureFlagLogic) + const query: InsightVizNode = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.TrendsQuery, + series: [ + { event: '$pageview', name: '$pageview', kind: NodeKind.EventsNode, math: BaseMathType.UniqueUsers }, + ], + breakdownFilter: { + breakdown_type: 'event', + breakdown: `$feature/${featureFlag.key}`, + }, + }, + } return ( } diff --git a/frontend/src/scenes/funnels/FunnelStepMore.tsx b/frontend/src/scenes/funnels/FunnelStepMore.tsx index e083a06aba36f..80d5b88b5935a 100644 --- a/frontend/src/scenes/funnels/FunnelStepMore.tsx +++ b/frontend/src/scenes/funnels/FunnelStepMore.tsx @@ -6,7 +6,8 @@ import { cleanFilters } from 'scenes/insights/utils/cleanFilters' import { urls } from 'scenes/urls' import { queryNodeToFilter } from '~/queries/nodes/InsightQuery/utils/queryNodeToFilter' -import { FunnelPathType, InsightType, PathType } from '~/types' +import { InsightVizNode, NodeKind } from '~/queries/schema' +import { FunnelPathType, PathType } from '~/types' import { funnelDataLogic } from './funnelDataLogic' @@ -28,6 +29,28 @@ export function FunnelStepMore({ stepIndex }: FunnelStepMoreProps): JSX.Element } const stepNumber = stepIndex + 1 + const getPathUrl = (funnelPathType: FunnelPathType, dropOff = false): string => { + const query: InsightVizNode = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.PathsQuery, + funnelPathsFilter: { + funnelStep: dropOff ? stepNumber * -1 : stepNumber, + funnelSource: querySource!, + funnelPathType, + }, + pathsFilter: { + includeEventTypes: [PathType.PageView, PathType.CustomEvent], + }, + dateRange: { + date_from: filterProps.date_from, + }, + }, + } + + return urls.insightNew(undefined, undefined, query) + } + return ( {stepNumber > 1 && ( - + Show user paths leading to step )} {stepNumber > 1 && ( - + Show user paths between previous step and this step )} - + Show user paths after step {stepNumber > 1 && ( - + Show user paths after dropoff )} {stepNumber > 1 && ( - + Show user paths before dropoff )} diff --git a/frontend/src/scenes/insights/InsightNav/insightNavLogic.tsx b/frontend/src/scenes/insights/InsightNav/insightNavLogic.tsx index c4ac869a1ec34..a245432b3a3a8 100644 --- a/frontend/src/scenes/insights/InsightNav/insightNavLogic.tsx +++ b/frontend/src/scenes/insights/InsightNav/insightNavLogic.tsx @@ -1,14 +1,12 @@ import { actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' -import { urlToAction } from 'kea-router' import { FEATURE_FLAGS } from 'lib/constants' import { LemonTag } from 'lib/lemon-ui/LemonTag/LemonTag' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { identifierToHuman } from 'lib/utils' -import { insightDataLogic, queryFromKind } from 'scenes/insights/insightDataLogic' +import { getDefaultQuery, insightDataLogic } from 'scenes/insights/insightDataLogic' import { keyForInsightLogicProps } from 'scenes/insights/sharedUtils' import { filterTestAccountsDefaultsLogic } from 'scenes/settings/project/filterTestAccountDefaultsLogic' -import { examples, TotalEventsTable } from '~/queries/examples' import { insightMap } from '~/queries/nodes/InsightQuery/utils/queryNodeToFilter' import { ActionsNode, @@ -20,7 +18,6 @@ import { InsightVizNode, LifecycleFilter, LifecycleQuery, - NodeKind, PathsFilter, PathsQuery, RetentionFilter, @@ -47,9 +44,10 @@ import { isStickinessQuery, isTrendsQuery, } from '~/queries/utils' -import { BaseMathType, FilterType, InsightLogicProps, InsightType } from '~/types' +import { BaseMathType, InsightLogicProps, InsightType } from '~/types' import { MathAvailability } from '../filters/ActionFilter/ActionFilterRow/ActionFilterRow' +import { insightSceneLogic } from '../insightSceneLogic' import type { insightNavLogicType } from './insightNavLogicType' export interface Tab { @@ -116,7 +114,7 @@ export const insightNavLogic = kea([ filterTestAccountsDefaultsLogic, ['filterTestAccountsDefault'], ], - actions: [insightDataLogic(props), ['setQuery']], + actions: [insightDataLogic(props), ['setQuery'], insightSceneLogic, ['setOpenedWithQuery']], })), actions({ setActiveView: (view: InsightType) => ({ view }), @@ -224,41 +222,19 @@ export const insightNavLogic = kea([ }), listeners(({ values, actions }) => ({ setActiveView: ({ view }) => { - if ([InsightType.SQL, InsightType.JSON, InsightType.HOG].includes(view as InsightType)) { - // if the selected view is SQL or JSON then we must have the "allow queries" flag on, - // so no need to check it - if (view === InsightType.JSON) { - actions.setQuery(TotalEventsTable) - } else if (view === InsightType.SQL) { - actions.setQuery(examples.DataVisualization) - } else if (view === InsightType.HOG) { - actions.setQuery(examples.Hoggonacci) - } - } else { - let query: InsightVizNode - - if (view === InsightType.TRENDS) { - query = queryFromKind(NodeKind.TrendsQuery, values.filterTestAccountsDefault) - } else if (view === InsightType.FUNNELS) { - query = queryFromKind(NodeKind.FunnelsQuery, values.filterTestAccountsDefault) - } else if (view === InsightType.RETENTION) { - query = queryFromKind(NodeKind.RetentionQuery, values.filterTestAccountsDefault) - } else if (view === InsightType.PATHS) { - query = queryFromKind(NodeKind.PathsQuery, values.filterTestAccountsDefault) - } else if (view === InsightType.STICKINESS) { - query = queryFromKind(NodeKind.StickinessQuery, values.filterTestAccountsDefault) - } else if (view === InsightType.LIFECYCLE) { - query = queryFromKind(NodeKind.LifecycleQuery, values.filterTestAccountsDefault) - } else { - throw new Error('encountered unexpected type for view') - } + const query = getDefaultQuery(view, values.filterTestAccountsDefault) + if (isInsightVizNode(query)) { actions.setQuery({ ...query, source: values.queryPropertyCache ? mergeCachedProperties(query.source, values.queryPropertyCache) : query.source, } as InsightVizNode) + actions.setOpenedWithQuery(query) + } else { + actions.setQuery(query) + actions.setOpenedWithQuery(query) } }, setQuery: ({ query }) => { @@ -267,23 +243,6 @@ export const insightNavLogic = kea([ } }, })), - urlToAction(({ actions }) => ({ - '/insights/:shortId(/:mode)(/:subscriptionId)': ( - _, // url params - { dashboard, ...searchParams }, // search params - { filters: _filters } // hash params - ) => { - // capture any filters from the URL, either #filters={} or ?insight=X&bla=foo&bar=baz - const filters: Partial | null = - Object.keys(_filters || {}).length > 0 ? _filters : searchParams.insight ? searchParams : null - - if (!filters?.insight) { - return - } - - actions.setActiveView(filters?.insight) - }, - })), afterMount(({ values, actions }) => { if (values.query && isInsightVizNode(values.query)) { actions.updateQueryPropertyCache(cachePropertiesFromQuery(values.query.source, values.queryPropertyCache)) diff --git a/frontend/src/scenes/insights/InsightPageHeader.tsx b/frontend/src/scenes/insights/InsightPageHeader.tsx index 708152a4ede69..c5bd094f6c86f 100644 --- a/frontend/src/scenes/insights/InsightPageHeader.tsx +++ b/frontend/src/scenes/insights/InsightPageHeader.tsx @@ -210,18 +210,14 @@ export function InsightPageHeader({ insightLogicProps }: { insightLogicProps: In data-attr="edit-insight-sql" onClick={() => { router.actions.push( - urls.insightNew( - undefined, - undefined, - JSON.stringify({ - kind: NodeKind.DataTableNode, - source: { - kind: NodeKind.HogQLQuery, - query: hogQL, - }, - full: true, - } as DataTableNode) - ) + urls.insightNew(undefined, undefined, { + kind: NodeKind.DataTableNode, + source: { + kind: NodeKind.HogQLQuery, + query: hogQL, + }, + full: true, + } as DataTableNode) ) }} fullWidth diff --git a/frontend/src/scenes/insights/insightDataLogic.tsx b/frontend/src/scenes/insights/insightDataLogic.tsx index b1075ba7c321d..bca93a4cf03b4 100644 --- a/frontend/src/scenes/insights/insightDataLogic.tsx +++ b/frontend/src/scenes/insights/insightDataLogic.tsx @@ -14,7 +14,15 @@ import { filtersToQueryNode } from '~/queries/nodes/InsightQuery/utils/filtersTo import { queryNodeToFilter } from '~/queries/nodes/InsightQuery/utils/queryNodeToFilter' import { insightVizDataNodeKey } from '~/queries/nodes/InsightViz/InsightViz' import { queryExportContext } from '~/queries/query' -import { InsightNodeKind, InsightVizNode, Node, NodeKind } from '~/queries/schema' +import { + DataTableNode, + DataVisualizationNode, + HogQuery, + InsightNodeKind, + InsightVizNode, + Node, + NodeKind, +} from '~/queries/schema' import { isInsightVizNode } from '~/queries/utils' import { ExportContext, FilterType, InsightLogicProps, InsightType } from '~/types' @@ -30,6 +38,37 @@ export const queryFromFilters = (filters: Partial): InsightVizNode = source: filtersToQueryNode(filters), }) +export const getDefaultQuery = ( + insightType: InsightType, + filterTestAccountsDefault: boolean +): DataTableNode | DataVisualizationNode | HogQuery | InsightVizNode => { + if ([InsightType.SQL, InsightType.JSON, InsightType.HOG].includes(insightType)) { + if (insightType === InsightType.JSON) { + return examples.TotalEventsTable as DataTableNode + } else if (insightType === InsightType.SQL) { + return examples.DataVisualization as DataVisualizationNode + } else if (insightType === InsightType.HOG) { + return examples.Hoggonacci as HogQuery + } + } else { + if (insightType === InsightType.TRENDS) { + return queryFromKind(NodeKind.TrendsQuery, filterTestAccountsDefault) + } else if (insightType === InsightType.FUNNELS) { + return queryFromKind(NodeKind.FunnelsQuery, filterTestAccountsDefault) + } else if (insightType === InsightType.RETENTION) { + return queryFromKind(NodeKind.RetentionQuery, filterTestAccountsDefault) + } else if (insightType === InsightType.PATHS) { + return queryFromKind(NodeKind.PathsQuery, filterTestAccountsDefault) + } else if (insightType === InsightType.STICKINESS) { + return queryFromKind(NodeKind.StickinessQuery, filterTestAccountsDefault) + } else if (insightType === InsightType.LIFECYCLE) { + return queryFromKind(NodeKind.LifecycleQuery, filterTestAccountsDefault) + } + } + + throw new Error('encountered unexpected type for view') +} + export const queryFromKind = (kind: InsightNodeKind, filterTestAccountsDefault: boolean): InsightVizNode => ({ kind: NodeKind.InsightVizNode, source: { ...nodeKindToDefaultQuery[kind], ...(filterTestAccountsDefault ? { filterTestAccounts: true } : {}) }, diff --git a/frontend/src/scenes/insights/insightSceneLogic.test.ts b/frontend/src/scenes/insights/insightSceneLogic.test.ts index c2a45b334145d..8ba30590bbf75 100644 --- a/frontend/src/scenes/insights/insightSceneLogic.test.ts +++ b/frontend/src/scenes/insights/insightSceneLogic.test.ts @@ -6,7 +6,8 @@ import { insightSceneLogic } from 'scenes/insights/insightSceneLogic' import { urls } from 'scenes/urls' import { useMocks } from '~/mocks/jest' -import { InsightVizNode } from '~/queries/schema' +import { examples } from '~/queries/examples' +import { InsightVizNode, NodeKind } from '~/queries/schema' import { initKeaTests } from '~/test/init' import { InsightShortId, InsightType, ItemMode } from '~/types' @@ -43,8 +44,8 @@ describe('insightSceneLogic', () => { }) }) - it('redirects when opening /insight/new with filters', async () => { - router.actions.push(urls.insightNew({ insight: InsightType.FUNNELS })) + it('redirects when opening /insight/new with insight type in theurl', async () => { + router.actions.push(urls.insightNew(InsightType.FUNNELS)) await expectLogic(logic).toFinishAllListeners() await expectLogic(router) .delay(1) @@ -61,6 +62,29 @@ describe('insightSceneLogic', () => { ).toEqual('FunnelsQuery') }) + it('redirects when opening /insight/new with query in the url', async () => { + router.actions.push( + urls.insightNew(undefined, undefined, { + kind: NodeKind.InsightVizNode, + source: examples.InsightPathsQuery, + } as InsightVizNode) + ) + await expectLogic(logic).toFinishAllListeners() + await expectLogic(router) + .delay(1) + .toMatchValues({ + location: partial({ + pathname: addProjectIdIfMissing(urls.insightNew(), MOCK_TEAM_ID), + search: '', + hash: '', + }), + }) + + expect( + (logic.values.insightLogicRef?.logic.values.queryBasedInsight.query as InsightVizNode).source?.kind + ).toEqual('PathsQuery') + }) + it('persists edit mode in the url', async () => { const viewUrl = combineUrl(urls.insightView(Insight42)) const editUrl = combineUrl(urls.insightEdit(Insight42)) diff --git a/frontend/src/scenes/insights/insightSceneLogic.tsx b/frontend/src/scenes/insights/insightSceneLogic.tsx index ad5eff574651d..2e1220067564f 100644 --- a/frontend/src/scenes/insights/insightSceneLogic.tsx +++ b/frontend/src/scenes/insights/insightSceneLogic.tsx @@ -1,14 +1,14 @@ import { actions, BuiltLogic, connect, kea, listeners, path, reducers, selectors, sharedListeners } from 'kea' import { actionToUrl, beforeUnload, router, urlToAction } from 'kea-router' import { CombinedLocation } from 'kea-router/lib/utils' -import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast' +import { objectsEqual } from 'lib/utils' import { eventUsageLogic, InsightEventSource } from 'lib/utils/eventUsageLogic' import { createEmptyInsight, insightLogic } from 'scenes/insights/insightLogic' import { insightLogicType } from 'scenes/insights/insightLogicType' -import { cleanFilters } from 'scenes/insights/utils/cleanFilters' import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' import { sceneLogic } from 'scenes/sceneLogic' import { Scene } from 'scenes/sceneTypes' +import { filterTestAccountsDefaultsLogic } from 'scenes/settings/project/filterTestAccountDefaultsLogic' import { teamLogic } from 'scenes/teamLogic' import { mathsLogic } from 'scenes/trends/mathsLogic' import { urls } from 'scenes/urls' @@ -16,18 +16,31 @@ import { urls } from 'scenes/urls' import { ActivityFilters } from '~/layout/navigation-3000/sidepanel/panels/activity/activityForSceneLogic' import { cohortsModel } from '~/models/cohortsModel' import { groupsModel } from '~/models/groupsModel' -import { ActivityScope, Breadcrumb, FilterType, InsightShortId, InsightType, ItemMode } from '~/types' +import { queryNodeToFilter } from '~/queries/nodes/InsightQuery/utils/queryNodeToFilter' +import { Node } from '~/queries/schema' +import { isInsightVizNode } from '~/queries/utils' +import { ActivityScope, Breadcrumb, InsightShortId, InsightType, ItemMode } from '~/types' -import { insightDataLogic } from './insightDataLogic' +import { getDefaultQuery, insightDataLogic } from './insightDataLogic' import { insightDataLogicType } from './insightDataLogicType' import type { insightSceneLogicType } from './insightSceneLogicType' import { summarizeInsight } from './summarizeInsight' +import { compareFilters } from './utils/compareFilters' export const insightSceneLogic = kea([ path(['scenes', 'insights', 'insightSceneLogic']), connect(() => ({ logic: [eventUsageLogic], - values: [teamLogic, ['currentTeam'], sceneLogic, ['activeScene'], preflightLogic, ['disableNavigationHooks']], + values: [ + teamLogic, + ['currentTeam'], + sceneLogic, + ['activeScene'], + preflightLogic, + ['disableNavigationHooks'], + filterTestAccountsDefaultsLogic, + ['filterTestAccountsDefault'], + ], })), actions({ setInsightId: (insightId: InsightShortId) => ({ insightId }), @@ -45,6 +58,7 @@ export const insightSceneLogic = kea([ logic, unmount, }), + setOpenedWithQuery: (query: Node | null) => ({ query }), }), reducers({ insightId: [ @@ -88,6 +102,7 @@ export const insightSceneLogic = kea([ setInsightDataLogicRef: (_, { logic, unmount }) => (logic && unmount ? { logic, unmount } : null), }, ], + openedWithQuery: [null as Node | null, { setOpenedWithQuery: (_, { query }) => query }], }), selectors(() => ({ legacyInsightSelector: [ @@ -190,7 +205,7 @@ export const insightSceneLogic = kea([ '/insights/:shortId(/:mode)(/:subscriptionId)': ( { shortId, mode, subscriptionId }, // url params { dashboard, ...searchParams }, // search params - { filters: _filters, q }, // hash params + { insight: insightType, q }, // hash params { method, initial }, // "location changed" event payload { searchParams: previousSearchParams } // previous location ) => { @@ -230,12 +245,15 @@ export const insightSceneLogic = kea([ actions.setSceneState(insightId, insightMode, subscriptionId) } - // capture any filters from the URL, either #filters={} or ?insight=X&bla=foo&bar=baz - const filters: Partial | null = - Object.keys(_filters || {}).length > 0 ? _filters : searchParams.insight ? searchParams : null + let query: Node | null = null + if (q) { + query = JSON.parse(q) + } else if (insightType && Object.values(InsightType).includes(insightType)) { + query = getDefaultQuery(insightType, values.filterTestAccountsDefault) + } - // Redirect to a simple URL if we had filters in the URL - if (filters || q) { + // Redirect to a simple URL if we had a query in the URL + if (q || insightType) { router.actions.replace( insightId === 'new' ? urls.insightNew(undefined, dashboard) @@ -246,15 +264,14 @@ export const insightSceneLogic = kea([ } // reset the insight's state if we have to - if (initial || method === 'PUSH' || filters || q) { + if (initial || method === 'PUSH' || query) { if (insightId === 'new') { const teamFilterTestAccounts = values.currentTeam?.test_account_filters_default_checked || false values.insightLogicRef?.logic.actions.setInsight( { ...createEmptyInsight('new', teamFilterTestAccounts), - ...(filters ? { filters: cleanFilters(filters || {}, teamFilterTestAccounts) } : {}), ...(dashboard ? { dashboards: [dashboard] } : {}), - ...(q ? { query: JSON.parse(q) } : {}), + ...(query ? { query } : {}), }, { fromPersistentApi: false, @@ -262,13 +279,10 @@ export const insightSceneLogic = kea([ } ) - eventUsageLogic.actions.reportInsightCreated(filters?.insight || InsightType.TRENDS) - } - } + actions.setOpenedWithQuery(query || null) - // show a warning toast if opened `/edit#filters={...}` - if (filters && insightMode === ItemMode.Edit && insightId !== 'new') { - lemonToast.info(`This insight has unsaved changes! Click "Save" to not lose them.`) + eventUsageLogic.actions.reportInsightCreated(query) + } } }, })), @@ -292,7 +306,7 @@ export const insightSceneLogic = kea([ setInsightMode: actionToUrl, } }), - beforeUnload(({ values }) => ({ + beforeUnload(({ values, props }) => ({ enabled: (newLocation?: CombinedLocation) => { // safeguard against running this check on other scenes if (values.activeScene !== Scene.Insight) { @@ -310,10 +324,44 @@ export const insightSceneLogic = kea([ return false } + let newInsightEdited = false + if (props.dashboardItemId === 'new') { + const startingQuery = + values.openedWithQuery || getDefaultQuery(InsightType.TRENDS, values.filterTestAccountsDefault) + const currentQuery = values.insightDataLogicRef?.logic.values.query + + if (isInsightVizNode(startingQuery) && isInsightVizNode(currentQuery)) { + // TODO: This shouldn't be necessary after we have removed the `cleanFilters` function. + // Currently this causes "default" properties to be set on the query. + const startingFilters = queryNodeToFilter(startingQuery.source) + const currentFilters = queryNodeToFilter(currentQuery.source) + + if ( + currentFilters.filter_test_accounts === false && + currentFilters.filter_test_accounts === values.filterTestAccountsDefault + ) { + delete currentFilters.filter_test_accounts + } + + newInsightEdited = !compareFilters( + startingFilters, + currentFilters, + values.filterTestAccountsDefault + ) + } else if (!isInsightVizNode(startingQuery) && !isInsightVizNode(currentQuery)) { + newInsightEdited = !objectsEqual(startingQuery, currentQuery) + } else { + newInsightEdited = true + } + } + + const insightMetadataEdited = !!values.insightLogicRef?.logic.values.insightChanged + const savedInsightEdited = + props.dashboardItemId !== 'new' && !!values.insightDataLogicRef?.logic.values.queryChanged + return ( values.insightMode === ItemMode.Edit && - (!!values.insightLogicRef?.logic.values.insightChanged || - !!values.insightDataLogicRef?.logic.values.queryChanged) + (insightMetadataEdited || savedInsightEdited || newInsightEdited) ) }, message: 'Leave insight?\nChanges you made will be discarded.', diff --git a/frontend/src/scenes/insights/utils.tsx b/frontend/src/scenes/insights/utils.tsx index f413e548c6805..c28c841647165 100644 --- a/frontend/src/scenes/insights/utils.tsx +++ b/frontend/src/scenes/insights/utils.tsx @@ -9,7 +9,15 @@ import { urls } from 'scenes/urls' import { propertyFilterTypeToPropertyDefinitionType } from '~/lib/components/PropertyFilters/utils' import { FormatPropertyValueForDisplayFunction } from '~/models/propertyDefinitionsModel' import { examples } from '~/queries/examples' -import { ActionsNode, BreakdownFilter, DataWarehouseNode, EventsNode, PathsFilter } from '~/queries/schema' +import { + ActionsNode, + BreakdownFilter, + DataWarehouseNode, + EventsNode, + InsightVizNode, + NodeKind, + PathsFilter, +} from '~/queries/schema' import { isDataWarehouseNode, isEventsNode } from '~/queries/utils' import { ActionFilter, @@ -24,7 +32,8 @@ import { InsightShortId, InsightType, PathType, - TrendsFilterType, + PropertyFilterType, + PropertyOperator, } from '~/types' import { insightLogic } from './insightLogic' @@ -355,15 +364,15 @@ export function getResponseBytes(apiResponse: Response): number { } export const insightTypeURL = { - TRENDS: urls.insightNew({ insight: InsightType.TRENDS }), - STICKINESS: urls.insightNew({ insight: InsightType.STICKINESS }), - LIFECYCLE: urls.insightNew({ insight: InsightType.LIFECYCLE }), - FUNNELS: urls.insightNew({ insight: InsightType.FUNNELS }), - RETENTION: urls.insightNew({ insight: InsightType.RETENTION }), - PATHS: urls.insightNew({ insight: InsightType.PATHS }), - JSON: urls.insightNew(undefined, undefined, JSON.stringify(examples.EventsTableFull)), - HOG: urls.insightNew(undefined, undefined, JSON.stringify(examples.Hoggonacci)), - SQL: urls.insightNew(undefined, undefined, JSON.stringify(examples.DataVisualization)), + TRENDS: urls.insightNew(InsightType.TRENDS), + STICKINESS: urls.insightNew(InsightType.STICKINESS), + LIFECYCLE: urls.insightNew(InsightType.LIFECYCLE), + FUNNELS: urls.insightNew(InsightType.FUNNELS), + RETENTION: urls.insightNew(InsightType.RETENTION), + PATHS: urls.insightNew(InsightType.PATHS), + JSON: urls.insightNew(undefined, undefined, examples.EventsTableFull), + HOG: urls.insightNew(undefined, undefined, examples.Hoggonacci), + SQL: urls.insightNew(undefined, undefined, examples.DataVisualization), } /** Combines a list of words, separating with the correct punctuation. For example: [a, b, c, d] -> "a, b, c, and d" */ @@ -379,46 +388,48 @@ export function concatWithPunctuation(phrases: string[]): string { } export function insightUrlForEvent(event: Pick): string | undefined { - let insightParams: Partial | undefined + let query: InsightVizNode | undefined if (event.event === '$pageview') { - insightParams = { - insight: InsightType.TRENDS, - interval: 'day', - display: ChartDisplayType.ActionsLineGraph, - actions: [], - events: [ - { - id: '$pageview', - name: '$pageview', - type: 'events', - order: 0, - properties: [ - { - key: '$current_url', - value: event.properties.$current_url, - type: 'event', - }, - ], - }, - ], + query = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.TrendsQuery, + interval: 'day', + series: [ + { + event: '$pageview', + name: '$pageview', + kind: NodeKind.EventsNode, + properties: [ + { + key: '$current_url', + value: event.properties.$current_url, + type: PropertyFilterType.Event, + operator: PropertyOperator.Exact, + }, + ], + }, + ], + trendsFilter: { display: ChartDisplayType.ActionsLineGraph }, + }, } } else if (event.event !== '$autocapture') { - insightParams = { - insight: InsightType.TRENDS, - interval: 'day', - display: ChartDisplayType.ActionsLineGraph, - actions: [], - events: [ - { - id: event.event, - name: event.event, - type: 'events', - order: 0, - properties: [], - }, - ], + query = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.TrendsQuery, + interval: 'day', + series: [ + { + event: event.event, + name: event.event, + kind: NodeKind.EventsNode, + }, + ], + trendsFilter: { display: ChartDisplayType.ActionsLineGraph }, + }, } } - return insightParams ? urls.insightNew(insightParams) : undefined + return query ? urls.insightNew(undefined, undefined, query) : undefined } diff --git a/frontend/src/scenes/insights/utils/compareFilters.ts b/frontend/src/scenes/insights/utils/compareFilters.ts index 93afde2296b6b..79d6562eb8a60 100644 --- a/frontend/src/scenes/insights/utils/compareFilters.ts +++ b/frontend/src/scenes/insights/utils/compareFilters.ts @@ -46,7 +46,7 @@ export const cleanFilter = ( export function compareFilters( a: Partial, b: Partial, - test_account_filters_default_checked: boolean | undefined + test_account_filters_default_checked?: boolean | undefined ): boolean { // this is not optimized for speed and does not work for many cases yet // e.g. falsy values are not treated the same as undefined values, unset filters are not handled, ordering of series isn't checked diff --git a/frontend/src/scenes/paths/pathsDataLogic.ts b/frontend/src/scenes/paths/pathsDataLogic.ts index 2c2f08223bf88..454ed411158ee 100644 --- a/frontend/src/scenes/paths/pathsDataLogic.ts +++ b/frontend/src/scenes/paths/pathsDataLogic.ts @@ -2,15 +2,17 @@ import { actions, connect, kea, key, listeners, path, props, selectors } from 'k import { router } from 'kea-router' import { TaxonomicFilterGroupType } from 'lib/components/TaxonomicFilter/types' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' +import { MathAvailability } from 'scenes/insights/filters/ActionFilter/ActionFilterRow/ActionFilterRow' import { insightVizDataLogic } from 'scenes/insights/insightVizDataLogic' import { keyForInsightLogicProps } from 'scenes/insights/sharedUtils' import { pathsTitle } from 'scenes/trends/persons-modal/persons-modal-utils' import { openPersonsModal, OpenPersonsModalProps } from 'scenes/trends/persons-modal/PersonsModal' import { urls } from 'scenes/urls' -import { InsightActorsQuery, NodeKind, PathsQuery } from '~/queries/schema' +import { actionsAndEventsToSeries } from '~/queries/nodes/InsightQuery/utils/filtersToQueryNode' +import { InsightActorsQuery, InsightVizNode, NodeKind, PathsQuery } from '~/queries/schema' import { isPathsQuery } from '~/queries/utils' -import { ActionFilter, InsightLogicProps, InsightType, PathType, PropertyFilterType, PropertyOperator } from '~/types' +import { ActionFilter, InsightLogicProps, PathType, PropertyFilterType, PropertyOperator } from '~/types' import type { pathsDataLogicType } from './pathsDataLogicType' import { PathNodeData } from './pathUtils' @@ -157,14 +159,19 @@ export const pathsDataLogic = kea([ } events.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)) - if (events.length > 0) { - router.actions.push( - urls.insightNew({ - insight: InsightType.FUNNELS, - events: events.reverse(), + const query: InsightVizNode = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.FunnelsQuery, + series: actionsAndEventsToSeries({ events: events.reverse() }, true, MathAvailability.None), + dateRange: { date_from: values.dateRange?.date_from, - }) - ) + }, + }, + } + + if (events.length > 0) { + router.actions.push(urls.insightNew(undefined, undefined, query)) } }, })), diff --git a/frontend/src/scenes/retention/retentionModalLogic.ts b/frontend/src/scenes/retention/retentionModalLogic.ts index e8e583298b178..7fbb821c7cef0 100644 --- a/frontend/src/scenes/retention/retentionModalLogic.ts +++ b/frontend/src/scenes/retention/retentionModalLogic.ts @@ -81,7 +81,7 @@ export const retentionModalLogic = kea([ ) { query.showPropertyFilter = false } - return urls.insightNew(undefined, undefined, JSON.stringify(query)) + return urls.insightNew(undefined, undefined, query) }, ], }), diff --git a/frontend/src/scenes/saved-insights/savedInsightsLogic.test.ts b/frontend/src/scenes/saved-insights/savedInsightsLogic.test.ts index 4cc1d84fb8cd8..6a61b7c05d675 100644 --- a/frontend/src/scenes/saved-insights/savedInsightsLogic.test.ts +++ b/frontend/src/scenes/saved-insights/savedInsightsLogic.test.ts @@ -1,10 +1,9 @@ -import { combineUrl, router } from 'kea-router' +import { router } from 'kea-router' import { expectLogic, partial } from 'kea-test-utils' import api from 'lib/api' import { MOCK_TEAM_ID } from 'lib/api.mock' import { DeleteDashboardForm, deleteDashboardLogic } from 'scenes/dashboard/deleteDashboardLogic' import { DuplicateDashboardForm, duplicateDashboardLogic } from 'scenes/dashboard/duplicateDashboardLogic' -import { cleanFilters } from 'scenes/insights/utils/cleanFilters' import { sceneLogic } from 'scenes/sceneLogic' import { Scene } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' @@ -12,7 +11,7 @@ import { urls } from 'scenes/urls' import { useMocks } from '~/mocks/jest' import { dashboardsModel } from '~/models/dashboardsModel' import { initKeaTests } from '~/test/init' -import { InsightModel, InsightType, QueryBasedInsightModel } from '~/types' +import { InsightModel, QueryBasedInsightModel } from '~/types' import { INSIGHTS_PER_PAGE, InsightsResult, savedInsightsLogic } from './savedInsightsLogic' @@ -187,16 +186,6 @@ describe('savedInsightsLogic', () => { }) }) - describe('redirects old /insights urls to the real URL', () => { - it('new mode with ?insight= and no hash params', async () => { - router.actions.push(combineUrl('/insights', cleanFilters({ insight: InsightType.FUNNELS })).url) - await expectLogic(router).toMatchValues({ - location: partial({ pathname: urls.project(MOCK_TEAM_ID, urls.insightNew()) }), - hashParams: { filters: partial({ insight: InsightType.FUNNELS }) }, - }) - }) - }) - it('can duplicate and does not use derived name for name', async () => { const sourceInsight = createInsight(123, 'hello') as QueryBasedInsightModel sourceInsight.name = '' diff --git a/frontend/src/scenes/saved-insights/savedInsightsLogic.ts b/frontend/src/scenes/saved-insights/savedInsightsLogic.ts index a9b86424902fe..a2cdb3a1ef993 100644 --- a/frontend/src/scenes/saved-insights/savedInsightsLogic.ts +++ b/frontend/src/scenes/saved-insights/savedInsightsLogic.ts @@ -358,10 +358,6 @@ export const savedInsightsLogic = kea([ router.actions.push(urls.savedInsights()) } return - } else if (searchParams.insight) { - // old URL with `?insight=TRENDS` in query - router.actions.replace(urls.insightNew(searchParams)) - return } const currentFilters = cleanFilters(values.filters) diff --git a/frontend/src/scenes/settings/project/PathCleaningFiltersConfig.tsx b/frontend/src/scenes/settings/project/PathCleaningFiltersConfig.tsx index f1803e750b7ac..9ef7c81c18fca 100644 --- a/frontend/src/scenes/settings/project/PathCleaningFiltersConfig.tsx +++ b/frontend/src/scenes/settings/project/PathCleaningFiltersConfig.tsx @@ -24,8 +24,8 @@ export function PathCleaningFiltersConfig(): JSX.Element | null { return ( <>

- Make your Paths clearer by aliasing - one or multiple URLs.{' '} + Make your Paths clearer by aliasing one or multiple + URLs.{' '} Example: http://tenant-one.mydomain.com/accounts and{' '} http://tenant-two.mydomain.com/accounts can become a single /accounts{' '} diff --git a/frontend/src/scenes/surveys/SurveyView.tsx b/frontend/src/scenes/surveys/SurveyView.tsx index 8672ea7070b68..bb5f4e79280c1 100644 --- a/frontend/src/scenes/surveys/SurveyView.tsx +++ b/frontend/src/scenes/surveys/SurveyView.tsx @@ -13,19 +13,10 @@ import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton' import { LemonTabs } from 'lib/lemon-ui/LemonTabs' import { capitalizeFirstLetter, pluralize } from 'lib/utils' import { useEffect, useState } from 'react' -import { urls } from 'scenes/urls' import { Query } from '~/queries/Query/Query' import { NodeKind } from '~/queries/schema' -import { - ActivityScope, - InsightType, - PropertyFilterType, - PropertyOperator, - Survey, - SurveyQuestionType, - SurveyType, -} from '~/types' +import { ActivityScope, PropertyFilterType, PropertyOperator, Survey, SurveyQuestionType, SurveyType } from '~/types' import { SURVEY_EVENT_NAME, SurveyQuestionLabel } from './constants' import { SurveyDisplaySummary } from './Survey' @@ -432,6 +423,7 @@ export function SurveyResult({ disableEventsTable }: { disableEventsTable?: bool surveyOpenTextResults, surveyOpenTextResultsReady, surveyNPSScore, + surveyAsInsightURL, } = useValues(surveyLogic) return ( @@ -510,22 +502,7 @@ export function SurveyResult({ disableEventsTable }: { disableEventsTable?: bool type="primary" data-attr="survey-results-explore" icon={} - to={urls.insightNew({ - insight: InsightType.TRENDS, - events: [ - { id: 'survey sent', name: 'survey sent', type: 'events' }, - { id: 'survey shown', name: 'survey shown', type: 'events' }, - { id: 'survey dismissed', name: 'survey dismissed', type: 'events' }, - ], - properties: [ - { - key: '$survey_id', - value: survey.id, - operator: PropertyOperator.Exact, - type: PropertyFilterType.Event, - }, - ], - })} + to={surveyAsInsightURL} > Explore results diff --git a/frontend/src/scenes/surveys/surveyLogic.tsx b/frontend/src/scenes/surveys/surveyLogic.tsx index 9659305b0580c..90df9b1bcf8bc 100644 --- a/frontend/src/scenes/surveys/surveyLogic.tsx +++ b/frontend/src/scenes/surveys/surveyLogic.tsx @@ -11,9 +11,10 @@ import { eventUsageLogic } from 'lib/utils/eventUsageLogic' import { Scene } from 'scenes/sceneTypes' import { urls } from 'scenes/urls' -import { DataTableNode, HogQLQuery, NodeKind } from '~/queries/schema' +import { DataTableNode, HogQLQuery, InsightVizNode, NodeKind } from '~/queries/schema' import { hogql } from '~/queries/utils' import { + BaseMathType, Breadcrumb, FeatureFlagFilters, MultipleSurveyQuestion, @@ -1115,6 +1116,47 @@ export const surveyLogic = kea([ (survey) => survey.questions.some((question) => question.branching && Object.keys(question.branching).length > 0), ], + surveyAsInsightURL: [ + (s) => [s.survey], + (survey) => { + const query: InsightVizNode = { + kind: NodeKind.InsightVizNode, + source: { + kind: NodeKind.TrendsQuery, + properties: [ + { + key: '$survey_id', + value: survey.id, + operator: PropertyOperator.Exact, + type: PropertyFilterType.Event, + }, + ], + series: [ + { + kind: NodeKind.EventsNode, + event: 'survey sent', + name: 'survey sent', + math: BaseMathType.TotalCount, + }, + { + kind: NodeKind.EventsNode, + event: 'survey shown', + name: 'survey shown', + math: BaseMathType.TotalCount, + }, + { + kind: NodeKind.EventsNode, + event: 'survey dismissed', + name: 'survey dismissed', + math: BaseMathType.TotalCount, + }, + ], + }, + } + + return urls.insightNew(undefined, undefined, query) + }, + ], }), forms(({ actions, props, values }) => ({ survey: { diff --git a/frontend/src/scenes/trends/persons-modal/personsModalLogic.ts b/frontend/src/scenes/trends/persons-modal/personsModalLogic.ts index 224464a866831..55514365774c9 100644 --- a/frontend/src/scenes/trends/persons-modal/personsModalLogic.ts +++ b/frontend/src/scenes/trends/persons-modal/personsModalLogic.ts @@ -361,7 +361,7 @@ export const personsModalLogic = kea([ source, full: true, } - return urls.insightNew(undefined, undefined, JSON.stringify(query)) + return urls.insightNew(undefined, undefined, query) }, ], }), diff --git a/frontend/src/scenes/urls.ts b/frontend/src/scenes/urls.ts index 42659a914800c..2bdaea9722e90 100644 --- a/frontend/src/scenes/urls.ts +++ b/frontend/src/scenes/urls.ts @@ -2,14 +2,14 @@ import { combineUrl } from 'kea-router' import { getCurrentTeamId } from 'lib/utils/getAppContext' import { ExportOptions } from '~/exporter/types' -import { HogQLFilters } from '~/queries/schema' +import { HogQLFilters, Node } from '~/queries/schema' import { ActionType, ActivityTab, AnnotationType, - AnyPartialFilterType, DashboardType, InsightShortId, + InsightType, PipelineNodeTab, PipelineStage, PipelineTab, @@ -71,13 +71,9 @@ export const urls = { `/events/${encodeURIComponent(id)}/${encodeURIComponent(timestamp)}`, ingestionWarnings: (): string => '/data-management/ingestion-warnings', insights: (): string => '/insights', - insightNew: ( - filters?: AnyPartialFilterType, - dashboardId?: DashboardType['id'] | null, - query?: string | Record - ): string => + insightNew: (type?: InsightType, dashboardId?: DashboardType['id'] | null, query?: Node): string => combineUrl('/insights/new', dashboardId ? { dashboard: dashboardId } : {}, { - ...(filters ? { filters } : {}), + ...(type ? { insight: type } : {}), ...(query ? { q: typeof query === 'string' ? query : JSON.stringify(query) } : {}), }).url, insightNewHogQL: (query: string, filters?: HogQLFilters): string => diff --git a/frontend/src/scenes/web-analytics/WebAnalyticsModal.tsx b/frontend/src/scenes/web-analytics/WebAnalyticsModal.tsx index 63bbf2d441f4f..19aa3535d690b 100644 --- a/frontend/src/scenes/web-analytics/WebAnalyticsModal.tsx +++ b/frontend/src/scenes/web-analytics/WebAnalyticsModal.tsx @@ -49,11 +49,7 @@ export const WebAnalyticsModal = (): JSX.Element | null => {

{modal.canOpenInsight ? ( } size="small" type="secondary" diff --git a/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx b/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx index 8b7f2309c3648..7349db8cb1051 100644 --- a/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx +++ b/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx @@ -533,7 +533,7 @@ export const webAnalyticsLogic = kea([ event: '$pageview', kind: NodeKind.EventsNode, math: BaseMathType.UniqueUsers, - name: '$pageview', + name: 'Pageview', custom_name: 'Unique visitors', }, ], @@ -927,6 +927,7 @@ export const webAnalyticsLogic = kea([ series: [ { event: '$pageview', + name: 'Pageview', kind: NodeKind.EventsNode, math: BaseMathType.UniqueUsers, }, @@ -1020,6 +1021,7 @@ export const webAnalyticsLogic = kea([ series: [ { event: '$pageview', + name: 'Pageview', kind: NodeKind.EventsNode, math: BaseMathType.UniqueUsers, }, @@ -1282,8 +1284,8 @@ export const webAnalyticsLogic = kea([ }, ], getNewInsightUrl: [ - (s) => [s.webAnalyticsFilters, s.dateFilter, s.tiles], - (webAnalyticsFilters: WebAnalyticsPropertyFilters, { dateTo, dateFrom }, tiles) => { + (s) => [s.tiles], + (tiles) => { return function getNewInsightUrl(tileId: TileId, tabId?: string): string | undefined { const formatQueryForNewInsight = (query: QuerySchema): QuerySchema => { if (query.kind === NodeKind.InsightVizNode) { @@ -1305,17 +1307,9 @@ export const webAnalyticsLogic = kea([ if (!tab) { throw new Error('Developer Error, tab not found') } - return urls.insightNew( - { properties: webAnalyticsFilters, date_from: dateFrom, date_to: dateTo }, - null, - formatQueryForNewInsight(tab.query) - ) + return urls.insightNew(undefined, undefined, formatQueryForNewInsight(tab.query)) } else if (tile.kind === 'query') { - return urls.insightNew( - { properties: webAnalyticsFilters, date_from: dateFrom, date_to: dateTo }, - null, - formatQueryForNewInsight(tile.query) - ) + return urls.insightNew(undefined, undefined, formatQueryForNewInsight(tile.query)) } else if (tile.kind === 'replay') { return urls.replay() }