diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeCohort.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeCohort.tsx index 310ec587c8d14..0aca9ceaaf8f1 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeCohort.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeCohort.tsx @@ -13,6 +13,7 @@ import { IconPeople, IconPerson, IconTrends } from '@posthog/icons' import { Query } from '~/queries/Query/Query' import { LemonDivider, LemonTag } from '@posthog/lemon-ui' import { DataTableNode, NodeKind } from '~/queries/schema' +import { INTEGER_REGEX_MATCH_GROUPS } from './utils' const Component = ({ attributes }: NotebookNodeProps): JSX.Element => { const { id } = attributes @@ -163,7 +164,7 @@ export const NotebookNodeCohort = createPostHogWidgetNode { return { id: parseInt(match[1]) } }, diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeEarlyAccessFeature.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeEarlyAccessFeature.tsx index b2d7ef4b0c527..922abebe0e682 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeEarlyAccessFeature.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeEarlyAccessFeature.tsx @@ -15,6 +15,7 @@ import { buildFlagContent } from './NotebookNodeFlag' import { useEffect } from 'react' import { NotFound } from 'lib/components/NotFound' import { IconFlag, IconRocket } from '@posthog/icons' +import { UUID_REGEX_MATCH_GROUPS } from './utils' const Component = ({ attributes }: NotebookNodeProps): JSX.Element => { const { id } = attributes @@ -129,7 +130,7 @@ export const NotebookNodeEarlyAccessFeature = createPostHogWidgetNode { return { id: match[1] } }, diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeExperiment.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeExperiment.tsx index b214da4480e16..240fbe54f6d91 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeExperiment.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeExperiment.tsx @@ -18,6 +18,7 @@ import { ExperimentResult } from 'scenes/experiments/ExperimentResult' import { NotFound } from 'lib/components/NotFound' import { IconFlag, IconFlask } from '@posthog/icons' import { ResultsTag, StatusTag } from 'scenes/experiments/ExperimentView/components' +import { INTEGER_REGEX_MATCH_GROUPS } from './utils' const Component = ({ attributes }: NotebookNodeProps): JSX.Element => { const { id } = attributes @@ -127,9 +128,9 @@ export const NotebookNodeExperiment = createPostHogWidgetNode { - return { id: match[1] as unknown as number } + return { id: parseInt(match[1]) } }, }, }) diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeFlag.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeFlag.tsx index 2dfc560a2883e..03a7b1d3b56d3 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeFlag.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeFlag.tsx @@ -18,6 +18,7 @@ import { buildSurveyContent } from './NotebookNodeSurvey' import { useEffect } from 'react' import { NotFound } from 'lib/components/NotFound' import { IconFlag, IconRocket } from '@posthog/icons' +import { INTEGER_REGEX_MATCH_GROUPS } from './utils' const Component = ({ attributes }: NotebookNodeProps): JSX.Element => { const { id } = attributes @@ -150,7 +151,7 @@ export const NotebookNodeFlag = createPostHogWidgetNode { return { id: match[1] as FeatureFlagLogicProps['id'] } }, diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx index 41c539cf05701..b2c2232704d41 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeQuery.tsx @@ -14,6 +14,7 @@ import { insightDataLogic } from 'scenes/insights/insightDataLogic' import { insightLogic } from 'scenes/insights/insightLogic' import { JSONContent } from '@tiptap/core' import { useSummarizeInsight } from 'scenes/insights/summarizeInsight' +import { SHORT_CODE_REGEX_MATCH_GROUPS } from './utils' const DEFAULT_QUERY: QuerySchema = { kind: NodeKind.DataTableNode, @@ -242,7 +243,7 @@ export const NotebookNodeQuery = createPostHogWidgetNode { return { query: { diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx index 501977b6e65dc..96c3644171f40 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeRecording.tsx @@ -24,6 +24,7 @@ import { asDisplay } from 'scenes/persons/person-utils' import { IconComment } from 'lib/lemon-ui/icons' import { NotFound } from 'lib/components/NotFound' import { IconPerson } from '@posthog/icons' +import { UUID_REGEX_MATCH_GROUPS } from './utils' const HEIGHT = 500 const MIN_HEIGHT = '20rem' @@ -158,7 +159,7 @@ export const NotebookNodeRecording = createPostHogWidgetNode { return { id: match[1], noInspector: false } }, diff --git a/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx b/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx index ec2ad6e2d0eee..d40c870fcf0d3 100644 --- a/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx +++ b/frontend/src/scenes/notebooks/Nodes/NotebookNodeSurvey.tsx @@ -15,6 +15,7 @@ import { SurveyDisplaySummary } from 'scenes/surveys/Survey' import { useEffect } from 'react' import { NotFound } from 'lib/components/NotFound' import { SurveyAppearancePreview } from 'scenes/surveys/SurveyAppearancePreview' +import { UUID_REGEX_MATCH_GROUPS } from './utils' const Component = ({ attributes }: NotebookNodeProps): JSX.Element => { const { id } = attributes @@ -115,7 +116,7 @@ export const NotebookNodeSurvey = createPostHogWidgetNode { return { id: match[1] } }, diff --git a/frontend/src/scenes/notebooks/Nodes/utils.test.tsx b/frontend/src/scenes/notebooks/Nodes/utils.test.tsx index 09cfe7c1ceebd..0b78bc6e9820b 100644 --- a/frontend/src/scenes/notebooks/Nodes/utils.test.tsx +++ b/frontend/src/scenes/notebooks/Nodes/utils.test.tsx @@ -1,6 +1,14 @@ import { NodeViewProps } from '@tiptap/core' -import { useSyncedAttributes } from './utils' +import { + createUrlRegex, + INTEGER_REGEX_MATCH_GROUPS, + SHORT_CODE_REGEX_MATCH_GROUPS, + useSyncedAttributes, + UUID_REGEX_MATCH_GROUPS, +} from './utils' import { renderHook, act } from '@testing-library/react' +import { urls } from 'scenes/urls' +import { InsightShortId } from '~/types' describe('notebook node utils', () => { jest.useFakeTimers() @@ -133,4 +141,34 @@ describe('notebook node utils', () => { expect(nodeViewProps.updateAttributes).not.toHaveBeenCalled() }) }) + + describe('paste matching handlers', () => { + it('matches the uuid regex', () => { + let url = urls.replaySingle(UUID_REGEX_MATCH_GROUPS) + let regex = createUrlRegex(url) + let matches = regex.exec('http://localhost/replay/0192c471-b890-7546-9eae-056d98b8c5a8') + expect(matches?.[1]).toEqual('0192c471-b890-7546-9eae-056d98b8c5a8') + + url = urls.experiment(INTEGER_REGEX_MATCH_GROUPS) + regex = createUrlRegex(url) + matches = regex.exec('http://localhost/experiments/12345') + expect(matches?.[1]).toEqual('12345') + + url = urls.insightView(SHORT_CODE_REGEX_MATCH_GROUPS as InsightShortId) + regex = createUrlRegex(url) + matches = regex.exec('http://localhost/insights/TAg12F') + expect(matches?.[1]).toEqual('TAg12F') + }) + it('ignores any query params', () => { + let url = urls.replaySingle(UUID_REGEX_MATCH_GROUPS) + let regex = createUrlRegex(url) + let matches = regex.exec('http://localhost/replay/0192c471-b890-7546-9eae-056d98b8c5a8?filters=false') + expect(matches?.[1]).toEqual('0192c471-b890-7546-9eae-056d98b8c5a8') + + url = urls.insightView(SHORT_CODE_REGEX_MATCH_GROUPS as InsightShortId) + regex = createUrlRegex(url) + matches = regex.exec('http://localhost/insights/TAg12F?dashboardId=1234') + expect(matches?.[1]).toEqual('TAg12F') + }) + }) }) diff --git a/frontend/src/scenes/notebooks/Nodes/utils.tsx b/frontend/src/scenes/notebooks/Nodes/utils.tsx index 114c52ec0fb69..91f1191e54188 100644 --- a/frontend/src/scenes/notebooks/Nodes/utils.tsx +++ b/frontend/src/scenes/notebooks/Nodes/utils.tsx @@ -6,6 +6,10 @@ import { CustomNotebookNodeAttributes, NotebookNodeAttributes } from '../Noteboo import { useCallback, useMemo, useRef } from 'react' import { tryJsonParse, uuid } from 'lib/utils' +export const INTEGER_REGEX_MATCH_GROUPS = '([0-9]*)(.*)' +export const SHORT_CODE_REGEX_MATCH_GROUPS = '([0-9a-zA-Z]*)(.*)' +export const UUID_REGEX_MATCH_GROUPS = '([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(.*)' + export function createUrlRegex(path: string | RegExp, origin?: string): RegExp { origin = (origin || window.location.origin).replace('.', '\\.') return new RegExp(origin + path, 'ig')