From 4fc9141ec91fd44f7cd68dcaa0ac542da2e15947 Mon Sep 17 00:00:00 2001 From: Raquel Smith Date: Tue, 10 Sep 2024 14:00:52 -0700 Subject: [PATCH] make a url field function --- .../authorizedUrlListLogic.ts | 2 +- .../iframedToolbarBrowserLogic.ts | 16 ++++ .../components/IframedToolbarBrowser/utils.ts | 2 + .../LemonInputSelect/LemonInputSelect.tsx | 11 ++- .../DashboardTemplateConfigureStep.tsx | 74 ++++++++++++++++++- frontend/src/toolbar/bar/toolbarLogic.ts | 31 ++++++++ 6 files changed, 130 insertions(+), 6 deletions(-) diff --git a/frontend/src/lib/components/AuthorizedUrlList/authorizedUrlListLogic.ts b/frontend/src/lib/components/AuthorizedUrlList/authorizedUrlListLogic.ts index 20d0811578258..8cc977e20f2ae 100644 --- a/frontend/src/lib/components/AuthorizedUrlList/authorizedUrlListLogic.ts +++ b/frontend/src/lib/components/AuthorizedUrlList/authorizedUrlListLogic.ts @@ -241,7 +241,7 @@ export const authorizedUrlListLogic = kea([ [] as string[], { setAuthorizedUrls: (_, { authorizedUrls }) => authorizedUrls, - addUrl: (state, { url }) => state.concat([url]), + addUrl: (state, { url }) => (!state.includes(url) ? state.concat([url]) : state), updateUrl: (state, { index, url }) => Object.assign([...state], { [index]: url }), removeUrl: (state, { index }) => { const newUrls = [...state] diff --git a/frontend/src/lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic.ts b/frontend/src/lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic.ts index a2d74018d6aa8..71d1f657b1f5f 100644 --- a/frontend/src/lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic.ts +++ b/frontend/src/lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic.ts @@ -57,6 +57,7 @@ export const iframedToolbarBrowserLogic = kea([ disableElementSelector: true, setNewActionName: (name: string | null) => ({ name }), toolbarMessageReceived: (type: PostHogAppToolbarEvent, payload: Record) => ({ type, payload }), + setCurrentPath: (path: string, navigateIframe: boolean) => ({ path, navigateIframe }), }), reducers(({ props }) => ({ @@ -99,6 +100,12 @@ export const iframedToolbarBrowserLogic = kea([ setBrowserUrl: (_, { url }) => url, }, ], + currentPath: [ + '' as string, + { + setCurrentPath: (_, { path }) => path, + }, + ], loading: [ false as boolean, { @@ -255,6 +262,9 @@ export const iframedToolbarBrowserLogic = kea([ actions.setNewActionName(null) actions.disableElementSelector() return + case PostHogAppToolbarEvent.PH_TOOLBAR_NAVIGATED: + // remove leading / from path + return actions.setCurrentPath(payload.path.replace(/^\/+/, ''), false) default: console.warn(`[PostHog Heatmaps] Received unknown child window message: ${type}`) } @@ -271,6 +281,12 @@ export const iframedToolbarBrowserLogic = kea([ } }, + setCurrentPath: ({ path, navigateIframe }) => { + if (navigateIframe) { + actions.sendToolbarMessage(PostHogAppToolbarEvent.PH_NAVIGATE, { url: values.browserUrl + '/' + path }) + } + }, + startTrackingLoading: () => { actions.setIframeBanner(null) diff --git a/frontend/src/lib/components/IframedToolbarBrowser/utils.ts b/frontend/src/lib/components/IframedToolbarBrowser/utils.ts index 87d9cae13cf9f..5dd60eafa1093 100644 --- a/frontend/src/lib/components/IframedToolbarBrowser/utils.ts +++ b/frontend/src/lib/components/IframedToolbarBrowser/utils.ts @@ -17,6 +17,8 @@ export enum PostHogAppToolbarEvent { PH_ELEMENT_SELECTOR = 'ph-element-selector', PH_NEW_ACTION_NAME = 'ph-new-action-name', PH_NEW_ACTION_CREATED = 'ph-new-action-created', + PH_NAVIGATE = 'ph-navigate', + PH_TOOLBAR_NAVIGATED = 'ph-toolbar-navigated', } export const DEFAULT_HEATMAP_FILTERS: HeatmapFilters = { diff --git a/frontend/src/lib/lemon-ui/LemonInputSelect/LemonInputSelect.tsx b/frontend/src/lib/lemon-ui/LemonInputSelect/LemonInputSelect.tsx index 6187ea318f6b7..4e457ed8f01dc 100644 --- a/frontend/src/lib/lemon-ui/LemonInputSelect/LemonInputSelect.tsx +++ b/frontend/src/lib/lemon-ui/LemonInputSelect/LemonInputSelect.tsx @@ -46,6 +46,9 @@ export type LemonInputSelectProps = Pick< onInputChange?: (newValue: string) => void 'data-attr'?: string popoverClassName?: string + size?: 'xsmall' | 'small' | 'medium' | 'large' + borderless?: boolean + transparentBackground?: boolean } export function LemonInputSelect({ @@ -65,6 +68,9 @@ export function LemonInputSelect({ autoFocus = false, popoverClassName, 'data-attr': dataAttr, + size = 'medium', + borderless, + transparentBackground, }: LemonInputSelectProps): JSX.Element { const [showPopover, setShowPopover] = useState(false) const [inputValue, _setInputValue] = useState('') @@ -444,6 +450,7 @@ export function LemonInputSelect({ onKeyDown={_onKeyDown} disabled={disabled} autoFocus={autoFocus} + transparentBackground={transparentBackground} className={clsx( 'flex-wrap h-auto min-w-24', // Putting button-like text styling on the single-select unfocused placeholder @@ -451,9 +458,11 @@ export function LemonInputSelect({ mode === 'single' && values.length > 0 && !showPopover && - 'cursor-pointer placeholder:*:text-default' + 'cursor-pointer placeholder:*:text-default', + borderless && 'border-none' )} data-attr={dataAttr} + size={size} /> ) diff --git a/frontend/src/scenes/onboarding/productAnalyticsSteps/DashboardTemplateConfigureStep.tsx b/frontend/src/scenes/onboarding/productAnalyticsSteps/DashboardTemplateConfigureStep.tsx index 476cef6de6275..cc432139aad05 100644 --- a/frontend/src/scenes/onboarding/productAnalyticsSteps/DashboardTemplateConfigureStep.tsx +++ b/frontend/src/scenes/onboarding/productAnalyticsSteps/DashboardTemplateConfigureStep.tsx @@ -1,10 +1,10 @@ import { IconArrowRight } from '@posthog/icons' -import { LemonButton, LemonCard, LemonSkeleton, Link } from '@posthog/lemon-ui' +import { LemonButton, LemonCard, LemonInput, LemonInputSelect, LemonSkeleton, Link } from '@posthog/lemon-ui' import { useActions, useValues } from 'kea' import { authorizedUrlListLogic, AuthorizedUrlListType } from 'lib/components/AuthorizedUrlList/authorizedUrlListLogic' import { IframedToolbarBrowser } from 'lib/components/IframedToolbarBrowser/IframedToolbarBrowser' import { iframedToolbarBrowserLogic } from 'lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic' -import { useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { dashboardTemplateVariablesLogic } from 'scenes/dashboard/dashboardTemplateVariablesLogic' import { newDashboardLogic } from 'scenes/dashboard/newDashboardLogic' @@ -14,6 +14,69 @@ import { sdksLogic } from '../sdks/sdksLogic' import { DashboardTemplateVariables } from './DashboardTemplateVariables' import { onboardingTemplateConfigLogic } from './onboardingTemplateConfigLogic' +const UrlInput = ({ iframeRef }: { iframeRef: React.RefObject }): JSX.Element => { + const { setBrowserUrl, setCurrentPath } = useActions( + iframedToolbarBrowserLogic({ iframeRef, clearBrowserUrlOnUnmount: true }) + ) + const { browserUrl, currentPath } = useValues( + iframedToolbarBrowserLogic({ iframeRef, clearBrowserUrlOnUnmount: true }) + ) + const { snippetHosts } = useValues(sdksLogic) + const { addUrl } = useActions(authorizedUrlListLogic({ actionId: null, type: AuthorizedUrlListType.TOOLBAR_URLS })) + const [inputValue, setInputValue] = useState(currentPath) + + useEffect(() => { + setInputValue(currentPath) + }, [currentPath]) + + return ( +
+ setInputValue(v)} + onPressEnter={() => { + setCurrentPath(inputValue || '', true) + }} + prefix={ + +
+ ({ key: host, label: host }))} + allowCustomValues={false} + onChange={(v) => { + addUrl(v[0]) + setBrowserUrl(v[0]) + setCurrentPath('', false) + }} + size="xsmall" + transparentBackground + borderless + /> +
+ / +
+ } + /> + } + onClick={() => { + setCurrentPath(inputValue || '', true) + }} + /> + + Select pageview + +
+ ) +} + export const OnboardingDashboardTemplateConfigureStep = ({ stepKey = OnboardingStepKey.DASHBOARD_TEMPLATE, }: { @@ -50,8 +113,11 @@ export const OnboardingDashboardTemplateConfigureStep = ({
{browserUrl ? ( -
- +
+ +
+ +
) : ( <> diff --git a/frontend/src/toolbar/bar/toolbarLogic.ts b/frontend/src/toolbar/bar/toolbarLogic.ts index dd5a8dd6a2f2b..8546f2448cd39 100644 --- a/frontend/src/toolbar/bar/toolbarLogic.ts +++ b/frontend/src/toolbar/bar/toolbarLogic.ts @@ -72,6 +72,8 @@ export const toolbarLogic = kea([ setIsBlurred: (isBlurred: boolean) => ({ isBlurred }), setIsEmbeddedInApp: (isEmbedded: boolean) => ({ isEmbedded }), setFixedPosition: (position: ToolbarPositionType) => ({ position }), + setCurrentPathname: (pathname: string) => ({ pathname }), + maybeSendNavigationMessage: true, })), windowValues(() => ({ windowHeight: (window: Window) => window.innerHeight, @@ -164,6 +166,12 @@ export const toolbarLogic = kea([ setIsEmbeddedInApp: (_, { isEmbedded }) => isEmbedded, }, ], + currentPathname: [ + '', + { + setCurrentPathname: (_, { pathname }) => pathname, + }, + ], })), selectors({ position: [ @@ -403,6 +411,16 @@ export const toolbarLogic = kea([ // if embedded, we need to tell the parent window that a new action was created window.parent.postMessage({ type: PostHogAppToolbarEvent.PH_NEW_ACTION_CREATED, payload: action }, '*') }, + maybeSendNavigationMessage: () => { + const currentPath = window.location.pathname + if (currentPath !== values.currentPathname) { + actions.setCurrentPathname(currentPath) + window.parent.postMessage( + { type: PostHogAppToolbarEvent.PH_TOOLBAR_NAVIGATED, payload: { path: currentPath } }, + '*' + ) + } + }, })), afterMount(({ actions, values, cache }) => { cache.clickListener = (e: MouseEvent): void => { @@ -412,6 +430,16 @@ export const toolbarLogic = kea([ } } window.addEventListener('mousedown', cache.clickListener) + window.addEventListener('popstate', () => { + actions.maybeSendNavigationMessage() + }) + + // Use a setInterval to periodically check for URL changes + // We do this because we don't want to write over the history.pushState function in case other scripts rely on it + // And mutation observers don't seem to work :shrug: + setInterval(() => { + actions.maybeSendNavigationMessage() + }, 500) // the toolbar can be run within the posthog parent app // if it is then it listens to parent messages @@ -461,6 +489,9 @@ export const toolbarLogic = kea([ case PostHogAppToolbarEvent.PH_NEW_ACTION_NAME: actions.setAutomaticActionCreationEnabled(true, e.data.payload.name) return + case PostHogAppToolbarEvent.PH_NAVIGATE: + window.location.href = e.data.payload.url + return default: console.warn(`[PostHog Toolbar] Received unknown parent window message: ${type}`) }