From ecec4d8fd7e2fff8c8fb9d4b8dfc16cd8c4fbda7 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Tue, 2 Jul 2024 16:10:52 +0200 Subject: [PATCH] change(ui): cards menu --- .../ResponseTimeDistribution.tsx | 21 +- .../NewDashModal/ExampleCards.tsx | 22 +- .../NewDashModal/Examples/HeatmapsExample.tsx | 60 ++++ .../PageResponseTimeDistributionExample.tsx | 26 ++ .../DashboardWidgetGrid.tsx | 2 +- .../WidgetWrapper/WidgetWrapperNew.tsx | 286 +++++++++--------- .../Funnels/FunnelWidget/FunnelBar.tsx | 4 +- .../Funnels/FunnelWidget/FunnelWidget.tsx | 2 +- 8 files changed, 265 insertions(+), 158 deletions(-) create mode 100644 frontend/app/components/Dashboard/components/DashboardList/NewDashModal/Examples/HeatmapsExample.tsx create mode 100644 frontend/app/components/Dashboard/components/DashboardList/NewDashModal/Examples/PageResponseTimeDistributionExample.tsx diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResponseTimeDistribution/ResponseTimeDistribution.tsx b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResponseTimeDistribution/ResponseTimeDistribution.tsx index 687778b5f..6386748d4 100644 --- a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResponseTimeDistribution/ResponseTimeDistribution.tsx +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResponseTimeDistribution/ResponseTimeDistribution.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { NoContent } from 'UI'; import { Styles, AvgLabel } from '../../common'; -import { - ComposedChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, +import { + ComposedChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, XAxis, YAxis, ReferenceLine, Tooltip } from 'recharts'; import { NO_METRIC_DATA } from 'App/constants/messages' @@ -41,26 +41,25 @@ const PercentileLine = props => { interface Props { data: any - metric?: any } function ResponseTimeDistribution(props: Props) { - const { data, metric } = props; + const { data } = props; const colors = Styles.colors; return (
- +
@@ -68,7 +67,7 @@ function ResponseTimeDistribution(props: Props) { 'Page Response Time: ' + val} /> - { metric.data.percentiles && metric.data.percentiles.map((item: any, i: number) => ( + { data.percentiles && data.percentiles.map((item: any, i: number) => ( - + diff --git a/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/ExampleCards.tsx b/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/ExampleCards.tsx index 777f02175..3ede58409 100644 --- a/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/ExampleCards.tsx +++ b/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/ExampleCards.tsx @@ -7,7 +7,17 @@ import ByBrowser from './Examples/SessionsBy/ByBrowser'; import BySystem from './Examples/SessionsBy/BySystem'; import ByCountry from './Examples/SessionsBy/ByCountry'; import ByUrl from './Examples/SessionsBy/ByUrl'; -import { ERRORS, FUNNEL, INSIGHTS, PERFORMANCE, TABLE, TIMESERIES, USER_PATH, WEB_VITALS } from 'App/constants/card'; +import { + CLICKMAP, + ERRORS, + FUNNEL, + INSIGHTS, + PERFORMANCE, + TABLE, + TIMESERIES, + USER_PATH, + WEB_VITALS +} from 'App/constants/card'; import { FilterKey } from 'Types/filter/filterType'; import { Activity, BarChart, TableCellsMerge, TrendingUp } from 'lucide-react'; import WebVital from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/WebVital'; @@ -25,6 +35,7 @@ import SlowestDomains from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/SessionsBy/SlowestDomains'; import SpeedIndexByLocationExample from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/SpeedIndexByLocationExample'; +import HeatmapsExample from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/HeatmapsExample'; export const CARD_CATEGORY = { PRODUCT_ANALYTICS: 'product-analytics', @@ -90,6 +101,14 @@ export const CARD_LIST: CardType[] = [ totalDropDueToIssues: 294 } }, + { + title: 'Heatmaps', + key: CLICKMAP, + cardType: CLICKMAP, + metricOf: 'sessionCount', + category: CARD_CATEGORIES[0].key, + example: HeatmapsExample + }, { title: 'Path Finder', key: USER_PATH, @@ -122,6 +141,7 @@ export const CARD_LIST: CardType[] = [ example: ByIssues }, + { title: 'Insights', key: INSIGHTS, diff --git a/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/Examples/HeatmapsExample.tsx b/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/Examples/HeatmapsExample.tsx new file mode 100644 index 000000000..625d109df --- /dev/null +++ b/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/Examples/HeatmapsExample.tsx @@ -0,0 +1,60 @@ +import React, { useEffect } from 'react'; +import ExCard from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/ExCard'; +import heatmapRenderer from 'Player/web/addons/simpleHeatmap'; + +interface Props { + title: string; + type: string; + onCard: (card: string) => void; +} + +function HeatmapsExample(props: Props) { + const canvasRef = React.useRef(null); + + useEffect(() => { + const pointMap: Record = {}; + let maxIntensity = 0; + + for (let i = 0; i < 20; i++) { + const x = Math.floor(Math.random() * 300); + const y = Math.floor(Math.random() * 180); + const key = `${x}-${y}`; + if (!pointMap[key]) { + pointMap[key] = { + times: Math.floor(Math.random() * 100), + data: [x, y], + original: { x, y } + }; + } + + maxIntensity = Math.max(maxIntensity, pointMap[key].times); + } + + const heatmapData: number[][] = []; + for (const key in pointMap) { + const { data, times } = pointMap[key]; + heatmapData.push([...data, times]); + } + + heatmapRenderer + .setCanvas(canvasRef?.current!) + .setData(heatmapData) + .setRadius(15, 10) + .setMax(maxIntensity) + .resize() + .draw(); + }, []); + + + // const data = {}; + return ( + + + + ); +} + +export default HeatmapsExample; diff --git a/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/Examples/PageResponseTimeDistributionExample.tsx b/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/Examples/PageResponseTimeDistributionExample.tsx new file mode 100644 index 000000000..e0feafe0a --- /dev/null +++ b/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/Examples/PageResponseTimeDistributionExample.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import ExCard from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/ExCard'; +import CustomMetricOverviewChart from 'Components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricOverviewChart'; +import ResponseTimeDistribution from 'Components/Dashboard/Widgets/PredefinedWidgets/ResponseTimeDistribution'; + + +interface Props { + title: string; + type: string; + onCard: (card: string) => void; +} + +function PageResponseTimeDistributionExample(props: Props) { + const data = { + chart: [] + } + return ( + + + + ); +} + +export default PageResponseTimeDistributionExample; diff --git a/frontend/app/components/Dashboard/components/DashboardWidgetGrid/DashboardWidgetGrid.tsx b/frontend/app/components/Dashboard/components/DashboardWidgetGrid/DashboardWidgetGrid.tsx index 33f472da2..7d96b7a90 100644 --- a/frontend/app/components/Dashboard/components/DashboardWidgetGrid/DashboardWidgetGrid.tsx +++ b/frontend/app/components/Dashboard/components/DashboardWidgetGrid/DashboardWidgetGrid.tsx @@ -54,8 +54,8 @@ function DashboardWidgetGrid(props: Props) { } dashboardId={dashboardId} siteId={siteId} - isWidget={false} grid="other" + showMenu={true} /> )) diff --git a/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapperNew.tsx b/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapperNew.tsx index 126e347b1..03c712db2 100644 --- a/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapperNew.tsx +++ b/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapperNew.tsx @@ -1,159 +1,161 @@ -import React, {useRef} from 'react'; +import React, { useRef } from 'react'; import cn from 'classnames'; -import {Card, Tooltip, Button} from 'antd'; -import {useDrag, useDrop} from 'react-dnd'; +import { Card, Tooltip, Button } from 'antd'; +import { useDrag, useDrop } from 'react-dnd'; import WidgetChart from '../WidgetChart'; -import {observer} from 'mobx-react-lite'; -import {useStore} from 'App/mstore'; -import {withRouter, RouteComponentProps} from 'react-router-dom'; -import {withSiteId, dashboardMetricDetails} from 'App/routes'; +import { observer } from 'mobx-react-lite'; +import { useStore } from 'App/mstore'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; +import { withSiteId, dashboardMetricDetails } from 'App/routes'; import TemplateOverlay from './TemplateOverlay'; import stl from './widgetWrapper.module.css'; -import {FilterKey} from 'App/types/filter/filterType'; +import { FilterKey } from 'App/types/filter/filterType'; import LazyLoad from 'react-lazyload'; -import {TIMESERIES} from "App/constants/card"; -import CardMenu from "Components/Dashboard/components/WidgetWrapper/CardMenu"; -import AlertButton from "Components/Dashboard/components/WidgetWrapper/AlertButton"; +import { TIMESERIES } from 'App/constants/card'; +import CardMenu from 'Components/Dashboard/components/WidgetWrapper/CardMenu'; +import AlertButton from 'Components/Dashboard/components/WidgetWrapper/AlertButton'; interface Props { - className?: string; - widget?: any; - index?: number; - moveListItem?: any; - isPreview?: boolean; - isTemplate?: boolean; - dashboardId?: string; - siteId?: string; - active?: boolean; - history?: any; - onClick?: () => void; - isWidget?: boolean; - hideName?: boolean; - grid?: string; - isGridView?: boolean; + className?: string; + widget?: any; + index?: number; + moveListItem?: any; + isPreview?: boolean; + isTemplate?: boolean; + dashboardId?: string; + siteId?: string; + active?: boolean; + history?: any; + onClick?: () => void; + isWidget?: boolean; + hideName?: boolean; + grid?: string; + isGridView?: boolean; + showMenu?: boolean; } function WidgetWrapperNew(props: Props & RouteComponentProps) { - const {dashboardStore} = useStore(); - const { - isWidget = false, - active = false, - index = 0, - moveListItem = null, - isPreview = false, - isTemplate = false, - siteId, - grid = '', - isGridView = false, - } = props; - const widget: any = props.widget; - const isTimeSeries = widget.metricType === TIMESERIES; - const isPredefined = widget.metricType === 'predefined'; - const dashboard = dashboardStore.selectedDashboard; + const { dashboardStore } = useStore(); + const { + isWidget = false, + active = false, + index = 0, + moveListItem = null, + isPreview = false, + isTemplate = false, + siteId, + grid = '', + isGridView = false, + showMenu = false + } = props; + const widget: any = props.widget; + const isTimeSeries = widget.metricType === TIMESERIES; + const isPredefined = widget.metricType === 'predefined'; + const dashboard = dashboardStore.selectedDashboard; - const [{isDragging}, dragRef] = useDrag({ - type: 'item', - item: {index, grid}, - collect: (monitor) => ({ - isDragging: monitor.isDragging(), - }), - }); + const [{ isDragging }, dragRef] = useDrag({ + type: 'item', + item: { index, grid }, + collect: (monitor) => ({ + isDragging: monitor.isDragging() + }) + }); - const [{isOver, canDrop}, dropRef] = useDrop({ - accept: 'item', - drop: (item: any) => { - if (item.index === index || item.grid !== grid) return; - moveListItem(item.index, index); - }, - canDrop(item) { - return item.grid === grid; - }, - collect: (monitor: any) => ({ - isOver: monitor.isOver(), - canDrop: monitor.canDrop(), - }), - }); + const [{ isOver, canDrop }, dropRef] = useDrop({ + accept: 'item', + drop: (item: any) => { + if (item.index === index || item.grid !== grid) return; + moveListItem(item.index, index); + }, + canDrop(item) { + return item.grid === grid; + }, + collect: (monitor: any) => ({ + isOver: monitor.isOver(), + canDrop: monitor.canDrop() + }) + }); - const onChartClick = () => { - // if (!isWidget || isPredefined) return; - props.history.push( - withSiteId(dashboardMetricDetails(dashboard?.dashboardId, widget.metricId), siteId) - ); - }; - - const ref: any = useRef(null); - const dragDropRef: any = dragRef(dropRef(ref)); - const addOverlay = - isTemplate || - (!isPredefined && - isWidget && - widget.metricOf !== FilterKey.ERRORS && - widget.metricOf !== FilterKey.SESSIONS); - - return ( - null} - id={`widget-${widget.widgetId}`} - title={!props.hideName ? widget.name : null} - extra={isWidget ? [ -
- {!isPredefined && isTimeSeries && !isGridView && ( - - )} - - {!isTemplate && !isGridView && ( - - )} -
- ] : []} - styles={{ - header: { - padding: '0 14px', - borderBottom: 'none', - minHeight: 44, - fontWeight: 500, - fontSize: 14, - }, - body: { - padding: 0, - }, - }} - > - {!isTemplate && isWidget && isPredefined && ( - -
- {'Cannot drill down system provided metrics'} -
-
- )} - - {addOverlay && } - - -
- -
-
-
+ const onChartClick = () => { + // if (!isWidget || isPredefined) return; + props.history.push( + withSiteId(dashboardMetricDetails(dashboard?.dashboardId, widget.metricId), siteId) ); + }; + + const ref: any = useRef(null); + const dragDropRef: any = dragRef(dropRef(ref)); + const addOverlay = + isTemplate || + (!isPredefined && + isWidget && + widget.metricOf !== FilterKey.ERRORS && + widget.metricOf !== FilterKey.SESSIONS); + + return ( + null} + id={`widget-${widget.widgetId}`} + title={!props.hideName ? widget.name : null} + extra={[ +
+ {!isPredefined && isTimeSeries && !isGridView && ( + + )} + + {showMenu && ( + + )} +
+ ]} + styles={{ + header: { + padding: '0 14px', + borderBottom: 'none', + minHeight: 44, + fontWeight: 500, + fontSize: 14 + }, + body: { + padding: 0 + } + }} + > + {!isTemplate && isWidget && isPredefined && ( + +
+ {'Cannot drill down system provided metrics'} +
+
+ )} + + {addOverlay && } + + +
+ +
+
+
+ ); } export default withRouter(observer(WidgetWrapperNew)); diff --git a/frontend/app/components/Funnels/FunnelWidget/FunnelBar.tsx b/frontend/app/components/Funnels/FunnelWidget/FunnelBar.tsx index 4006b7c32..f365ce4b7 100644 --- a/frontend/app/components/Funnels/FunnelWidget/FunnelBar.tsx +++ b/frontend/app/components/Funnels/FunnelWidget/FunnelBar.tsx @@ -62,7 +62,7 @@ function FunnelBar(props: Props) { {/* @ts-ignore */}
- {filter.sessionsCount} Sessions + {filter.sessionsCount} Sessions ({filter.completedPercentage}%) Completed @@ -70,7 +70,7 @@ function FunnelBar(props: Props) { 0 ? 'red' : 'gray-light'} size={16} /> 0 ? 'color-red' : 'disabled')}>{filter.droppedCount} Sessions + className={'mx-1 ' + (filter.droppedCount > 0 ? 'color-red' : 'disabled')}>{filter.droppedCount} Sessions 0 ? 'color-red' : 'disabled')}>({filter.droppedPercentage}%) Dropped diff --git a/frontend/app/components/Funnels/FunnelWidget/FunnelWidget.tsx b/frontend/app/components/Funnels/FunnelWidget/FunnelWidget.tsx index 82a6e7e4b..7866bcbd3 100644 --- a/frontend/app/components/Funnels/FunnelWidget/FunnelWidget.tsx +++ b/frontend/app/components/Funnels/FunnelWidget/FunnelWidget.tsx @@ -132,7 +132,7 @@ export const Stage = observer(({ stage, index, isWidget, uxt, focusStage, focuse > {!uxt ? : } - {!isWidget && !uxt && } + {/*{!isWidget && !uxt && }*/}
) : ( <>