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

feat: Heatmaps toolbar code #21630

Merged
merged 24 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9dee6e7
Heatmaps toolbar code
benjackwhite Apr 18, 2024
273c18e
Fix
benjackwhite Apr 18, 2024
9cbec05
Update UI snapshots for `chromium` (2)
github-actions[bot] Apr 18, 2024
397c5a3
fix
benjackwhite Apr 18, 2024
51ceb6a
fix types?
benjackwhite Apr 18, 2024
d06d11f
Enforce types
benjackwhite Apr 18, 2024
0b68674
Update UI snapshots for `chromium` (1)
github-actions[bot] Apr 18, 2024
7e01389
Update UI snapshots for `chromium` (1)
github-actions[bot] Apr 18, 2024
5b731a2
Update UI snapshots for `chromium` (1)
github-actions[bot] Apr 18, 2024
d7d061a
Fixes
benjackwhite Apr 18, 2024
7b80ccf
fix
benjackwhite Apr 18, 2024
8304c8b
fix
benjackwhite Apr 18, 2024
d3b131a
Update UI snapshots for `chromium` (1)
github-actions[bot] Apr 18, 2024
c483955
Update UI snapshots for `chromium` (1)
github-actions[bot] Apr 18, 2024
952a97d
Update UI snapshots for `chromium` (2)
github-actions[bot] Apr 18, 2024
93c87bf
Update UI snapshots for `chromium` (1)
github-actions[bot] Apr 18, 2024
51cdc29
Update UI snapshots for `chromium` (2)
github-actions[bot] Apr 18, 2024
d1810d2
Merge branch 'master' into feat/heatmaps-toolbar
benjackwhite Apr 18, 2024
366cb91
Update UI snapshots for `chromium` (1)
github-actions[bot] Apr 18, 2024
df15ff5
Added preview
benjackwhite Apr 18, 2024
2c43861
Merge branch 'master' into feat/heatmaps-toolbar
benjackwhite Apr 22, 2024
d890d48
Fix
benjackwhite Apr 22, 2024
e2aec8d
Merge branch 'master' into feat/heatmaps-toolbar
benjackwhite Apr 22, 2024
71550e0
merge
benjackwhite Apr 23, 2024
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-other-toolbar--heatmap--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-other-toolbar--heatmap--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export const FEATURE_FLAGS = {
SESSION_REPLAY_MOBILE_ONBOARDING: 'session-replay-mobile-onboarding', // owner: #team-replay
IP_ALLOWLIST_SETTING: 'ip-allowlist-setting', // owner: @benjackwhite
EMAIL_VERIFICATION_TICKET_SUBMISSION: 'email-verification-ticket-submission', // owner: #team-growth
TOOLBAR_HEATMAPS: 'toolbar-heatmaps', // owner: #team-replay
THEME: 'theme', // owner: @aprilfools
} as const
export type FeatureFlagKey = (typeof FEATURE_FLAGS)[keyof typeof FEATURE_FLAGS]
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/loadPostHogJS.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export function loadPostHogJS(): void {
capture_copied_text: true,
},
process_person: 'identified_only',

__preview_heatmaps: true,

// Helper to capture events for assertions in Cypress
_onCapture: (window as any)._cypress_posthog_captures
? (_, event) => (window as any)._cypress_posthog_captures.push(event)
Expand Down
44 changes: 25 additions & 19 deletions frontend/src/toolbar/actions/ActionsEditingToolbarMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IconPencil, IconPlus, IconSearch, IconTrash, IconX } from '@posthog/icons'
import { IconPencil, IconPlus, IconSearch, IconTrash } from '@posthog/icons'
import { LemonDivider, LemonTag } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { Field, Form, Group } from 'kea-forms'
Expand All @@ -9,7 +9,7 @@ import { actionsTabLogic } from '~/toolbar/actions/actionsTabLogic'
import { SelectorEditingModal } from '~/toolbar/actions/SelectorEditingModal'
import { StepField } from '~/toolbar/actions/StepField'
import { ToolbarMenu } from '~/toolbar/bar/ToolbarMenu'
import { posthog } from '~/toolbar/posthog'
import { toolbarPosthogJS } from '~/toolbar/toolbarPosthogJS'

export const ActionsEditingToolbarMenu = (): JSX.Element => {
const {
Expand Down Expand Up @@ -38,7 +38,7 @@ export const ActionsEditingToolbarMenu = (): JSX.Element => {
startingSelector={editingSelectorValue}
onChange={(selector) => {
if (selector && editingSelector !== null) {
posthog.capture('toolbar_manual_selector_applied', {
toolbarPosthogJS.capture('toolbar_manual_selector_applied', {
chosenSelector: selector,
})
setElementSelector(selector, editingSelector)
Expand All @@ -52,7 +52,7 @@ export const ActionsEditingToolbarMenu = (): JSX.Element => {
enableFormOnSubmit
className="flex flex-col overflow-hidden flex-1"
>
<ToolbarMenu.Header>
<ToolbarMenu.Header className="border-b">
<h1 className="p-1 font-bold text-sm mb-0">
{selectedActionId === 'new' ? 'New ' : 'Edit '}
action
Expand Down Expand Up @@ -124,9 +124,12 @@ export const ActionsEditingToolbarMenu = (): JSX.Element => {
icon={<IconPencil />}
onClick={(e) => {
e.stopPropagation()
posthog.capture('toolbar_manual_selector_modal_opened', {
selector: step?.selector,
})
toolbarPosthogJS.capture(
'toolbar_manual_selector_modal_opened',
{
selector: step?.selector,
}
)
editSelectorWithIndex(index)
}}
>
Expand Down Expand Up @@ -198,22 +201,25 @@ export const ActionsEditingToolbarMenu = (): JSX.Element => {
</ToolbarMenu.Body>
<ToolbarMenu.Footer>
<span className="flex-1">
<LemonButton
type="secondary"
size="small"
onClick={() => selectAction(null)}
sideIcon={<IconX />}
>
Cancel
</LemonButton>
{selectedActionId !== 'new' ? (
<LemonButton
type="secondary"
status="danger"
onClick={deleteAction}
icon={<IconTrash />}
size="small"
>
Delete
</LemonButton>
) : null}
</span>
<LemonButton type="primary" htmlType="submit">
<LemonButton type="secondary" size="small" onClick={() => selectAction(null)}>
Cancel
</LemonButton>
<LemonButton type="primary" htmlType="submit" size="small">
{selectedActionId === 'new' ? 'Create ' : 'Save '}
action
</LemonButton>
{selectedActionId !== 'new' ? (
<LemonButton type="secondary" status="danger" onClick={deleteAction} icon={<IconTrash />} />
) : null}
</ToolbarMenu.Footer>
</Form>
</ToolbarMenu>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/toolbar/actions/ActionsListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function ActionsListView({ actions }: ActionsListViewProps): JSX.Element
subtle
key={action.id}
onClick={() => selectAction(action.id || null)}
className="font-medium my-1"
className="font-medium my-1 w-full"
>
<span className="min-w-[2rem] inline-block text-left">{index + 1}.</span>
<span className="flex-grow">
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/toolbar/actions/actionsTabLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { urls } from 'scenes/urls'

import { actionsLogic } from '~/toolbar/actions/actionsLogic'
import { toolbarLogic } from '~/toolbar/bar/toolbarLogic'
import { posthog } from '~/toolbar/posthog'
import { toolbarConfigLogic } from '~/toolbar/toolbarConfigLogic'
import { toolbarPosthogJS } from '~/toolbar/toolbarPosthogJS'
import { ActionDraftType, ActionForm } from '~/toolbar/types'
import { actionStepToActionStepFormItem, elementToActionStep, stepToDatabaseFormat } from '~/toolbar/utils'
import { ActionType, ElementType } from '~/types'
Expand Down Expand Up @@ -292,11 +292,11 @@ export const actionsTabLogic = kea<actionsTabLogicType>([
}
},
showButtonActions: () => {
posthog.capture('toolbar mode triggered', { mode: 'actions', enabled: true })
toolbarPosthogJS.capture('toolbar mode triggered', { mode: 'actions', enabled: true })
},
hideButtonActions: () => {
actions.setShowActionsTooltip(false)
posthog.capture('toolbar mode triggered', { mode: 'actions', enabled: false })
toolbarPosthogJS.capture('toolbar mode triggered', { mode: 'actions', enabled: false })
},
[actionsLogic.actionTypes.getActionsSuccess]: () => {
const { userIntent, actionId } = values
Expand Down
25 changes: 17 additions & 8 deletions frontend/src/toolbar/bar/ToolbarMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
export function ToolbarMenu({ children }: { children: React.ReactNode }): JSX.Element {
return <div className="w-full h-full flex flex-col overflow-hidden">{children}</div>
import clsx from 'clsx'

export type ToolbarMenuProps = {
children: React.ReactNode
className?: string
}

export function ToolbarMenu({ children, className }: ToolbarMenuProps): JSX.Element {
return <div className={clsx('w-full h-full flex flex-col overflow-hidden', className)}>{children}</div>
}

ToolbarMenu.Header = function ToolbarMenuHeader({ children }: { children: React.ReactNode }): JSX.Element {
return <div className="pt-1 px-1">{children}</div>
ToolbarMenu.Header = function ToolbarMenuHeader({ children, className }: ToolbarMenuProps): JSX.Element {
return <div className={clsx('pt-1 px-1', className)}>{children}</div>
}

ToolbarMenu.Body = function ToolbarMenuBody({ children }: { children: React.ReactNode }): JSX.Element {
return <div className="flex flex-col flex-1 h-full overflow-y-auto px-1 min-h-20">{children}</div>
ToolbarMenu.Body = function ToolbarMenuBody({ children, className }: ToolbarMenuProps): JSX.Element {
return (
<div className={clsx('flex flex-col flex-1 h-full overflow-y-auto px-1 min-h-20', className)}>{children}</div>
)
}

ToolbarMenu.Footer = function ToolbarMenufooter({ children }: { children: React.ReactNode }): JSX.Element {
return <div className="flex flex-row items-center p-2 border-t">{children}</div>
ToolbarMenu.Footer = function ToolbarMenufooter({ children, className }: ToolbarMenuProps): JSX.Element {
return <div className={clsx('flex flex-row items-center p-2 border-t gap-2', className)}>{children}</div>
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { ElementRect } from '~/toolbar/types'

interface HeatmapElementProps {
interface AutocaptureElementProps {
rect?: ElementRect
style: Record<string, any>
onClick: (event: React.MouseEvent) => void
onMouseOver: (event: React.MouseEvent) => void
onMouseOut: (event: React.MouseEvent) => void
}

export function HeatmapElement({
export function AutocaptureElement({
rect,
style = {},
onClick,
onMouseOver,
onMouseOut,
}: HeatmapElementProps): JSX.Element | null {
}: AutocaptureElementProps): JSX.Element | null {
if (!rect) {
return null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ const heatmapLabelStyle = {
fontFamily: 'monospace',
}

interface HeatmapLabelProps extends React.PropsWithoutRef<JSX.IntrinsicElements['div']> {
interface AutocaptureElementLabelProps extends React.PropsWithoutRef<JSX.IntrinsicElements['div']> {
rect?: ElementRect
align?: 'left' | 'right'
}

export function HeatmapLabel({
export function AutocaptureElementLabel({
rect,
style = {},
align = 'right',
children,
...props
}: HeatmapLabelProps): JSX.Element | null {
}: AutocaptureElementLabelProps): JSX.Element | null {
if (!rect) {
return null
}
Expand Down
13 changes: 10 additions & 3 deletions frontend/src/toolbar/elements/ElementInfoWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ export function ElementInfoWindow(): JSX.Element | null {
transition: 'opacity 0.2s, box-shadow 0.2s',
backgroundBlendMode: 'multiply',
background: 'white',
boxShadow: `hsla(4, 30%, 27%, 0.6) 0px 3px 10px 2px`,
}}
>
{onClose ? (
Expand Down Expand Up @@ -111,8 +110,16 @@ export function ElementInfoWindow(): JSX.Element | null {
<IconX />
</div>
) : null}
{/* eslint-disable-next-line react/forbid-dom-props */}
<div style={{ minHeight, maxHeight, overflow: 'auto' }}>
<div
// eslint-disable-next-line react/forbid-dom-props
style={{
minHeight,
maxHeight,
overflow: 'auto',
boxShadow: `hsla(4, 30%, 27%, 0.6) 0px 3px 10px 2px`,
borderRadius: '8px',
}}
>
<ElementInfo />
</div>
</div>
Expand Down
31 changes: 19 additions & 12 deletions frontend/src/toolbar/elements/Elements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import { useActions, useValues } from 'kea'
import { compactNumber } from 'lib/utils'
import { Fragment } from 'react'

import { AutocaptureElement } from '~/toolbar/elements/AutocaptureElement'
import { AutocaptureElementLabel } from '~/toolbar/elements/AutocaptureElementLabel'
import { ElementInfoWindow } from '~/toolbar/elements/ElementInfoWindow'
import { elementsLogic } from '~/toolbar/elements/elementsLogic'
import { FocusRect } from '~/toolbar/elements/FocusRect'
import { HeatmapElement } from '~/toolbar/elements/HeatmapElement'
import { HeatmapLabel } from '~/toolbar/elements/HeatmapLabel'
import { heatmapLogic } from '~/toolbar/elements/heatmapLogic'
import { getBoxColors, getHeatMapHue } from '~/toolbar/utils'

import { Heatmap } from './Heatmap'
import { ScrollDepth } from './ScrollDepth'

export function Elements(): JSX.Element {
const {
heatmapElements,
Expand Down Expand Up @@ -48,23 +51,26 @@ export function Elements(): JSX.Element {
zIndex: 2147483010,
}}
>
<ScrollDepth />
<Heatmap />
{highlightElementMeta?.rect ? <FocusRect rect={highlightElementMeta.rect} /> : null}

{elementsToDisplay.map(({ rect, element }, index) => (
<HeatmapElement
<AutocaptureElement
key={`inspect-${index}`}
rect={rect}
style={{
pointerEvents: heatmapPointerEvents,
cursor: 'pointer',
zIndex: 0,
zIndex: hoverElement === element ? 2 : 1,
opacity:
(!hoverElement && !selectedElement) ||
selectedElement === element ||
hoverElement === element
? 1
: 0.4,
transition: 'opacity 0.2s, box-shadow 0.2s',
borderRadius: 5,
...getBoxColors('blue', hoverElement === element || selectedElement === element),
}}
onClick={() => selectElement(element)}
Expand All @@ -76,14 +82,15 @@ export function Elements(): JSX.Element {
{heatmapElements.map(({ rect, count, clickCount, rageclickCount, element }, index) => {
return (
<Fragment key={`heatmap-${index}`}>
<HeatmapElement
<AutocaptureElement
rect={rect}
style={{
pointerEvents: inspectEnabled ? 'none' : heatmapPointerEvents,
zIndex: 1,
zIndex: hoverElement === element ? 4 : 3,
opacity: !hoverElement || hoverElement === element ? 1 : 0.4,
transition: 'opacity 0.2s, box-shadow 0.2s',
cursor: 'pointer',
borderRadius: 5,
...getBoxColors(
'red',
hoverElement === element,
Expand All @@ -95,7 +102,7 @@ export function Elements(): JSX.Element {
onMouseOut={() => selectedElement === null && setHoverElement(null)}
/>
{!!clickCount && (
<HeatmapLabel
<AutocaptureElementLabel
rect={rect}
style={{
pointerEvents: heatmapPointerEvents,
Expand All @@ -122,10 +129,10 @@ export function Elements(): JSX.Element {
onMouseOut={() => selectedElement === null && setHoverElement(null)}
>
{compactNumber(clickCount || 0)}
</HeatmapLabel>
</AutocaptureElementLabel>
)}
{!!rageclickCount && (
<HeatmapLabel
<AutocaptureElementLabel
rect={rect}
style={{
pointerEvents: heatmapPointerEvents,
Expand Down Expand Up @@ -153,7 +160,7 @@ export function Elements(): JSX.Element {
onMouseOut={() => selectedElement === null && setHoverElement(null)}
>
{compactNumber(rageclickCount)}&#128545;
</HeatmapLabel>
</AutocaptureElementLabel>
)}
</Fragment>
)
Expand All @@ -162,7 +169,7 @@ export function Elements(): JSX.Element {
{labelsToDisplay.map(({ element, rect, index }, loopIndex) => {
if (rect) {
return (
<HeatmapLabel
<AutocaptureElementLabel
key={`label-${loopIndex}`}
rect={rect}
align="left"
Expand All @@ -182,7 +189,7 @@ export function Elements(): JSX.Element {
onMouseOut={() => selectedElement === null && setHoverElement(null)}
>
{(index || loopIndex) + 1}
</HeatmapLabel>
</AutocaptureElementLabel>
)
}
})}
Expand Down
Loading
Loading