change(ui): jump to specified url instead of fixed ts

This commit is contained in:
sylenien 2022-12-20 10:45:56 +01:00 committed by Shekar Siri
parent 55f33a6b02
commit 2a811102b2
11 changed files with 79 additions and 46 deletions

View file

@ -19,9 +19,16 @@ function ClickMapCard({ setCustomSession, visitedEvents }: any) {
if (!visitedEvents || !visitedEvents.length) {
return <div className="p-4">loading</div>
}
const searchUrl = metricStore.instance.series[0].filter.filters[0].value[0]
const jumpToEvent = metricStore.instance.data.events.find((evt: Record<string, any>) => {
if (searchUrl) return evt.path.includes(searchUrl)
return evt
})
const jumpTimestamp = (jumpToEvent.timestamp - metricStore.instance.data.startTs) + jumpToEvent.domBuildingTime
console.log(jumpTimestamp, jumpToEvent, searchUrl)
return (
<div>
<WebPlayer isClickmap customSession={metricStore.instance.data}/>
<WebPlayer isClickmap customSession={metricStore.instance.data} customTimestamp={jumpTimestamp} />
</div>
)
}

View file

@ -76,10 +76,6 @@ function WidgetForm(props: Props) {
}
if (value === CLICKMAP) {
obj['viewType'] = 'chart';
// @ts-ignore
const { start, end } = Period({ rangeName: LAST_30_DAYS })
obj["startTimestamp"] = start;
obj["endTimestamp"] = end;
if (metric.series[0].filter.filters.length < 1) {
metric.series[0].filter.addFilter({

View file

@ -112,7 +112,7 @@ function WidgetView(props: Props) {
<WidgetPreview className="mt-8" name={widget.name} />
{widget.metricOf !== FilterKey.SESSIONS && widget.metricOf !== FilterKey.ERRORS && (
<>
{(widget.metricType === 'table' || widget.metricType === 'timeseries') && <WidgetSessions className="mt-8" />}
{(widget.metricType === 'table' || widget.metricType === 'timeseries' || widget.metricType === 'clickMap') && <WidgetSessions className="mt-8" />}
{widget.metricType === 'funnel' && <FunnelIssues />}
</>
)}

View file

@ -36,6 +36,7 @@ function WebPlayer(props: any) {
visitedEvents,
insightsFilters,
insights,
jumpTimestamp,
} = props;
const { notesStore } = useStore();
const [activeTab, setActiveTab] = useState('');
@ -87,7 +88,7 @@ function WebPlayer(props: any) {
contextValue.player && contextValue.player.play()
if (isClickmap && isPlayerReady && insights.size > 0) {
setTimeout(() => {
contextValue.player.jump(500)
contextValue.player.jump(jumpTimestamp)
contextValue.player.pause()
contextValue.player.scaleFullPage()
setTimeout(() => { contextValue.player.showClickmap(insights) }, 250)
@ -96,7 +97,7 @@ function WebPlayer(props: any) {
return () => {
isPlayerReady && contextValue.player.showClickmap(null)
}
}, [insights, isPlayerReady])
}, [insights, isPlayerReady, jumpTimestamp])
// LAYOUT (TODO: local layout state - useContext or something..)
useEffect(

View file

@ -72,9 +72,9 @@ function Player(props) {
data-bottom-block={bottomBlockIsActive}
>
{fullscreen && <EscapeButton onClose={fullscreenOff} />}
<div className="relative flex-1 overflow-hidden">
<div className={cn("relative flex-1", isClickmap ? 'overflow-visible' : 'overflow-hidden')}>
<Overlay nextId={nextId} closedLive={closedLive} isClickmap={isClickmap} />
<div className={stl.screenWrapper} ref={screenWrapper} />
<div className={cn(stl.screenWrapper, isClickmap && '!overflow-y-scroll')} ref={screenWrapper} />
</div>
{!fullscreen && !!bottomBlock && (
<div style={{ maxWidth, width: '100%' }}>

View file

@ -18,7 +18,7 @@ export default class PlayerBlock extends React.PureComponent {
const shouldShowSubHeader = !fullscreen && !fullView && !isMultiview && !isClickmap
return (
<div className={cn(styles.playerBlock, 'flex flex-col overflow-x-hidden')} style={{ minWidth: isMultiview || isClickmap ? '100%' : undefined }}>
<div className={cn(styles.playerBlock, 'flex flex-col', !isClickmap ? 'overflow-x-hidden' : 'overflow-visible')} style={{ zIndex: isClickmap ? 1 : undefined, minWidth: isMultiview || isClickmap ? '100%' : undefined }}>
{shouldShowSubHeader ? (
<SubHeader sessionId={sessionId} disabled={disabled} jiraConfig={jiraConfig} />
) : null}

View file

@ -233,7 +233,7 @@ export default class MessageManager {
.finally(this.onFileReadFinally)
// load devtools
if (this.session.devtoolsURL.length) {
if (this.session.devtoolsURL?.length) {
this.state.update({ devtoolsLoading: true })
loadFiles(this.session.devtoolsURL, createNewParser())
.catch(() =>

View file

@ -117,6 +117,10 @@ export default class Screen {
return this.iframe.contentDocument;
}
get iframeStylesRef(): CSSStyleDeclaration {
return this.iframe.style
}
private boundingRect: DOMRect | null = null;
private getBoundingClientRect(): DOMRect {
if (this.boundingRect === null) {
@ -216,16 +220,25 @@ export default class Screen {
}
scaleFullPage() {
const { height, width } = this.document.body.getBoundingClientRect();
this.cursor.toggle(false)
const offsetHeight = this.parentElement.getBoundingClientRect().height
if (!this.parentElement) return;
const { height: boxHeight, width: boxWidth } = this.parentElement.getBoundingClientRect();
const { height, width } = this.document.body.getBoundingClientRect();
this.overlay.remove()
this.scaleRatio = 1
this.screen.style.transform = `scale(1) translate(-50%, -50%)`;
this.screen.style.overflow = 'scroll';
this.screen.style.height = `${offsetHeight - 50}px`;
this.scaleRatio = boxWidth/width;
if (this.scaleRatio > 1) {
this.scaleRatio = 1;
} else {
this.scaleRatio = Math.round(this.scaleRatio * 1e3) / 1e3;
}
this.screen.style.transform = `scale(${this.scaleRatio})`;
this.screen.style.width = width + 'px';
this.screen.style.height = height + 'px';
this.screen.style.top = '0';
this.screen.style.left = '0';
this.iframe.style.width = width + 'px';
this.iframe.style.height = height + 'px';
}
}

View file

@ -1,6 +1,6 @@
import { Log, LogLevel } from './types'
import type { Store } from '../common/types'
import type { Store } from 'App/player'
import Player, { State as PlayerState } from '../player/Player'
import MessageManager from './MessageManager'

View file

@ -66,12 +66,12 @@ export default class TargetMarker {
if (!parentEl) return {top:0, left:0, width:0,height:0} //TODO: can be initialized(?) on mounted screen only
const { top, left, width, height } = el.getBoundingClientRect()
const s = this.screen.getScale()
const scrinRect = this.screen.overlay.getBoundingClientRect() //this.screen.getBoundingClientRect() (now private)
const screenRect = this.screen.overlay.getBoundingClientRect() //this.screen.getBoundingClientRect() (now private)
const parentRect = parentEl.getBoundingClientRect()
return {
top: top*s + scrinRect.top - parentRect.top,
left: left*s + scrinRect.left - parentRect.left,
top: top*s + screenRect.top - parentRect.top,
left: left*s + screenRect.left - parentRect.left,
width: width*s,
height: height*s,
}
@ -142,17 +142,21 @@ export default class TargetMarker {
return a + b.count
}, 0);
this.clickMapOverlay?.remove()
const overlay = document.createElement("div")
Object.assign(overlay.style, clickmapStyles.overlayStyle)
const iframeSize = this.screen.iframeStylesRef
console.log(iframeSize)
const scaleRatio = this.screen.getScale()
Object.assign(overlay.style, clickmapStyles.overlayStyle({ height: iframeSize.height, width: iframeSize.width, scale: scaleRatio }))
this.clickMapOverlay = overlay
selections.forEach((s, i) => {
const el = this.screen.getElementBySelector(s.selector);
console.log(el, s.selector)
if (!el) return;
const bubbleContainer = document.createElement("div")
const {top, left, width, height} = el.getBoundingClientRect()
const totalClicks = document.createElement("div")
totalClicks.innerHTML = `${s.count} ${s.count !== 1 ? 'Clicks' : 'Click'}`
Object.assign(totalClicks.style, clickmapStyles.totalClicks)
@ -177,21 +181,32 @@ export default class TargetMarker {
smallClicksBubble.id = smallClicksId
this.smallClicks.push(smallClicksBubble)
border.onclick = () => {
this.clickContainers.forEach(container => {
if (container.id === containerId) {
container.style.visibility = "visible"
} else {
container.style.visibility = "hidden"
}
})
this.smallClicks.forEach(container => {
if (container.id !== smallClicksId) {
container.style.visibility = "visible"
} else {
container.style.visibility = "hidden"
}
})
border.onclick = (e) => {
e.stopPropagation()
this.clickContainers.forEach(container => {
if (container.id === containerId) {
container.style.visibility = "visible"
} else {
container.style.visibility = "hidden"
}
})
this.smallClicks.forEach(container => {
if (container.id !== smallClicksId) {
container.style.visibility = "visible"
} else {
container.style.visibility = "hidden"
}
})
}
overlay.onclick = (e) => {
e.stopPropagation()
this.clickContainers.forEach(container => {
container.style.visibility = "hidden"
})
this.smallClicks.forEach(container => {
container.style.visibility = "visible"
})
}
Object.assign(smallClicksBubble.style, clickmapStyles.clicks)
@ -201,8 +216,7 @@ export default class TargetMarker {
overlay.appendChild(border)
});
this.screen.document.body.appendChild(overlay)
// this.store.update({ markedTargets });
this.screen.getParentElement().appendChild(overlay)
} else {
this.store.update({ markedTargets: null });
this.clickMapOverlay?.remove()

View file

@ -1,14 +1,16 @@
export const clickmapStyles = {
overlayStyle: {
overlayStyle: ({ height, width, scale }: { height: string, width: string, scale: number }) => ({
transform: `scale(${scale})`,
position: 'absolute',
top: '0px',
left: '0px',
width: '100%',
height: '100%',
width: width,
height: height,
background: 'rgba(0,0,0, 0.15)',
zIndex: 9 * 10e3,
transformOrigin: 'left top',
// pointerEvents: 'none',
},
}),
totalClicks: {
fontSize: '16px',
fontWeight: '600',