From 2a811102b236bc431b29507ffd48a81ec957f83c Mon Sep 17 00:00:00 2001 From: sylenien Date: Tue, 20 Dec 2022 10:45:56 +0100 Subject: [PATCH] change(ui): jump to specified url instead of fixed ts --- .../ClickMapCard/ClickMapCard.tsx | 9 ++- .../components/WidgetForm/WidgetForm.tsx | 4 -- .../components/WidgetView/WidgetView.tsx | 2 +- frontend/app/components/Session/WebPlayer.tsx | 5 +- .../app/components/Session_/Player/Player.js | 4 +- .../app/components/Session_/PlayerBlock.js | 2 +- frontend/app/player/web/MessageManager.ts | 2 +- frontend/app/player/web/Screen/Screen.ts | 27 ++++++--- frontend/app/player/web/WebPlayer.ts | 2 +- .../app/player/web/addons/TargetMarker.ts | 58 ++++++++++++------- .../app/player/web/addons/clickmapStyles.ts | 10 ++-- 11 files changed, 79 insertions(+), 46 deletions(-) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx index 8535880cd..bf61ec0c8 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx @@ -19,9 +19,16 @@ function ClickMapCard({ setCustomSession, visitedEvents }: any) { if (!visitedEvents || !visitedEvents.length) { return
loading
} + const searchUrl = metricStore.instance.series[0].filter.filters[0].value[0] + const jumpToEvent = metricStore.instance.data.events.find((evt: Record) => { + 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 (
- +
) } diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx index a081cdbc5..cf77dc872 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx @@ -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({ diff --git a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx index 3492e89c7..93228b342 100644 --- a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx +++ b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx @@ -112,7 +112,7 @@ function WidgetView(props: Props) { {widget.metricOf !== FilterKey.SESSIONS && widget.metricOf !== FilterKey.ERRORS && ( <> - {(widget.metricType === 'table' || widget.metricType === 'timeseries') && } + {(widget.metricType === 'table' || widget.metricType === 'timeseries' || widget.metricType === 'clickMap') && } {widget.metricType === 'funnel' && } )} diff --git a/frontend/app/components/Session/WebPlayer.tsx b/frontend/app/components/Session/WebPlayer.tsx index 3f61ed6ae..36e663a37 100644 --- a/frontend/app/components/Session/WebPlayer.tsx +++ b/frontend/app/components/Session/WebPlayer.tsx @@ -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( diff --git a/frontend/app/components/Session_/Player/Player.js b/frontend/app/components/Session_/Player/Player.js index 98d671ed7..6fa429eed 100644 --- a/frontend/app/components/Session_/Player/Player.js +++ b/frontend/app/components/Session_/Player/Player.js @@ -72,9 +72,9 @@ function Player(props) { data-bottom-block={bottomBlockIsActive} > {fullscreen && } -
+
-
+
{!fullscreen && !!bottomBlock && (
diff --git a/frontend/app/components/Session_/PlayerBlock.js b/frontend/app/components/Session_/PlayerBlock.js index 879d3c024..314e3383c 100644 --- a/frontend/app/components/Session_/PlayerBlock.js +++ b/frontend/app/components/Session_/PlayerBlock.js @@ -18,7 +18,7 @@ export default class PlayerBlock extends React.PureComponent { const shouldShowSubHeader = !fullscreen && !fullView && !isMultiview && !isClickmap return ( -
+
{shouldShowSubHeader ? ( ) : null} diff --git a/frontend/app/player/web/MessageManager.ts b/frontend/app/player/web/MessageManager.ts index fda25702b..46b694329 100644 --- a/frontend/app/player/web/MessageManager.ts +++ b/frontend/app/player/web/MessageManager.ts @@ -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(() => diff --git a/frontend/app/player/web/Screen/Screen.ts b/frontend/app/player/web/Screen/Screen.ts index f10a3bd35..4e6e768bb 100644 --- a/frontend/app/player/web/Screen/Screen.ts +++ b/frontend/app/player/web/Screen/Screen.ts @@ -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'; } + } diff --git a/frontend/app/player/web/WebPlayer.ts b/frontend/app/player/web/WebPlayer.ts index bdf4c0c15..267dfdd4d 100644 --- a/frontend/app/player/web/WebPlayer.ts +++ b/frontend/app/player/web/WebPlayer.ts @@ -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' diff --git a/frontend/app/player/web/addons/TargetMarker.ts b/frontend/app/player/web/addons/TargetMarker.ts index 028858f6d..0066243b5 100644 --- a/frontend/app/player/web/addons/TargetMarker.ts +++ b/frontend/app/player/web/addons/TargetMarker.ts @@ -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() diff --git a/frontend/app/player/web/addons/clickmapStyles.ts b/frontend/app/player/web/addons/clickmapStyles.ts index 086260089..d69c5f7fa 100644 --- a/frontend/app/player/web/addons/clickmapStyles.ts +++ b/frontend/app/player/web/addons/clickmapStyles.ts @@ -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',