From 2d1f32a1cf5cdeffd5bf386505b3489747a062c3 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 7 Dec 2022 14:37:34 +0530 Subject: [PATCH] feat(ui) - dashboard improvements - wip --- .../components/AddCardModal/AddCardModal.tsx | 8 +- .../DashboardHeader/DashboardHeader.tsx | 8 +- .../DashboardSideMenu/DashboardSideMenu.tsx | 2 +- .../DashboardWidgetGrid.tsx | 2 +- .../MetricTypeItem/MetricTypeItem.tsx | 2 +- .../MetricTypeList/MetricTypeList.tsx | 93 ++------ .../MetricsLibraryModal.tsx | 58 ++++- .../components/MetricsList/MetricsList.tsx | 29 ++- .../components/MetricsView/MetricsView.tsx | 9 +- .../components/WidgetForm/WidgetForm.tsx | 24 +- .../MetricSubtypeDropdown.tsx | 59 +++++ .../components/MetricSubtypeDropdown/index.ts | 1 + .../MetricTypeDropdown.stories.tsx | 11 + .../MetricTypeDropdown/MetricTypeDropdown.tsx | 54 +++++ .../components/MetricTypeDropdown/index.ts | 1 + .../components/WidgetView/WidgetView.tsx | 2 +- frontend/app/components/Modal/Modal.tsx | 2 +- .../CustomDropdownOption.tsx | 38 ++++ .../shared/CustomDropdownOption/index.ts | 1 + .../SankeyChart/SankeyChart.stories.tsx | 18 +- .../Insights/SankeyChart/SankeyChart.tsx | 31 ++- frontend/app/constants/card.ts | 213 ++++++++++++++++++ frontend/app/mstore/dashboardStore.ts | 4 +- frontend/app/types/filter/filterType.ts | 54 +++++ 24 files changed, 591 insertions(+), 133 deletions(-) create mode 100644 frontend/app/components/Dashboard/components/WidgetForm/components/MetricSubtypeDropdown/MetricSubtypeDropdown.tsx create mode 100644 frontend/app/components/Dashboard/components/WidgetForm/components/MetricSubtypeDropdown/index.ts create mode 100644 frontend/app/components/Dashboard/components/WidgetForm/components/MetricTypeDropdown/MetricTypeDropdown.stories.tsx create mode 100644 frontend/app/components/Dashboard/components/WidgetForm/components/MetricTypeDropdown/MetricTypeDropdown.tsx create mode 100644 frontend/app/components/Dashboard/components/WidgetForm/components/MetricTypeDropdown/index.ts create mode 100644 frontend/app/components/shared/CustomDropdownOption/CustomDropdownOption.tsx create mode 100644 frontend/app/components/shared/CustomDropdownOption/index.ts create mode 100644 frontend/app/constants/card.ts diff --git a/frontend/app/components/Dashboard/components/AddCardModal/AddCardModal.tsx b/frontend/app/components/Dashboard/components/AddCardModal/AddCardModal.tsx index 582e5b2f3..0558a99f6 100644 --- a/frontend/app/components/Dashboard/components/AddCardModal/AddCardModal.tsx +++ b/frontend/app/components/Dashboard/components/AddCardModal/AddCardModal.tsx @@ -2,12 +2,16 @@ import Modal from 'App/components/Modal/Modal'; import React from 'react'; import MetricTypeList from '../MetricTypeList'; -function AddCardModal() { +interface Props { + siteId: string; + dashboardId: string; +} +function AddCardModal(props: Props) { return ( <> - + ); diff --git a/frontend/app/components/Dashboard/components/DashboardHeader/DashboardHeader.tsx b/frontend/app/components/Dashboard/components/DashboardHeader/DashboardHeader.tsx index 0ce2103eb..25ff80e81 100644 --- a/frontend/app/components/Dashboard/components/DashboardHeader/DashboardHeader.tsx +++ b/frontend/app/components/Dashboard/components/DashboardHeader/DashboardHeader.tsx @@ -14,6 +14,7 @@ import DashboardEditModal from '../DashboardEditModal'; import AddCardModal from '../AddCardModal'; interface IProps { + dashboardId: string; siteId: string; renderReport?: any; } @@ -21,10 +22,9 @@ interface IProps { type Props = IProps & RouteComponentProps; function DashboardHeader(props: Props) { - const { siteId } = props; + const { siteId, dashboardId } = props; const { dashboardStore } = useStore(); const { showModal } = useModal(); - // const [showTooltip, setShowTooltip] = React.useState(false); const [focusTitle, setFocusedInput] = React.useState(true); const [showEditModal, setShowEditModal] = React.useState(false); const period = dashboardStore.period; @@ -82,7 +82,9 @@ function DashboardHeader(props: Props) {
- +
} diff --git a/frontend/app/components/Dashboard/components/MetricTypeItem/MetricTypeItem.tsx b/frontend/app/components/Dashboard/components/MetricTypeItem/MetricTypeItem.tsx index 380472bde..8b77fc18e 100644 --- a/frontend/app/components/Dashboard/components/MetricTypeItem/MetricTypeItem.tsx +++ b/frontend/app/components/Dashboard/components/MetricTypeItem/MetricTypeItem.tsx @@ -4,7 +4,7 @@ import { Icon } from 'UI'; export interface MetricType { title: string; - icon: IconNames; + icon?: IconNames; description: string; slug: string; } diff --git a/frontend/app/components/Dashboard/components/MetricTypeList/MetricTypeList.tsx b/frontend/app/components/Dashboard/components/MetricTypeList/MetricTypeList.tsx index d5cea3be5..e0d6e846b 100644 --- a/frontend/app/components/Dashboard/components/MetricTypeList/MetricTypeList.tsx +++ b/frontend/app/components/Dashboard/components/MetricTypeList/MetricTypeList.tsx @@ -2,90 +2,37 @@ import { useModal } from 'App/components/Modal'; import React from 'react'; import MetricsLibraryModal from '../MetricsLibraryModal'; import MetricTypeItem, { MetricType } from '../MetricTypeItem/MetricTypeItem'; +import { TYPES, LIBRARY } from 'App/constants/card'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; +import { dashboardMetricCreate, withSiteId } from 'App/routes'; -const METRIC_TYPES: MetricType[] = [ - { - title: 'Add From Library', - icon: 'grid', - description: 'Select a pre existing card from card library', - slug: 'library', - }, - { - title: 'Timeseries', - icon: 'graph-up', - description: 'Trend of sessions count in over the time.', - slug: 'timeseries', - }, - { - title: 'Table', - icon: 'list-alt', - description: 'See list of Users, Sessions, Errors, Issues, etc.,', - slug: 'table', - }, - { - title: 'Funnel', - icon: 'funnel', - description: 'Uncover the issues impacting user journeys.', - slug: 'funnel', - }, - { - title: 'Errors Tracking', - icon: 'exclamation-circle', - description: 'Discover user journeys between 2 points.', - slug: 'errors', - }, - { - title: 'Performance Monitoring', - icon: 'speedometer2', - description: 'Retention graph of users / features over a period of time.', - slug: 'performance', - }, - { - title: 'Resource Monitoring', - icon: 'files', - description: 'Find the adoption of your all features in your app.', - slug: 'resource-monitoring', - }, - { - title: 'Web Vitals', - icon: 'activity', - description: 'Find the adoption of your all features in your app.', - slug: 'web-vitals', - }, - { - title: 'User Path', - icon: 'signpost-split', - description: 'Discover user journeys between 2 points.', - slug: 'user-path', - }, - { - title: 'Retention', - icon: 'arrow-repeat', - description: 'Retension graph of users / features over a period of time.', - slug: 'retention', - }, - { - title: 'Feature Adoption', - icon: 'card-checklist', - description: 'Find the adoption of your all features in your app.', - slug: 'feature-adoption', - }, -]; +interface Props extends RouteComponentProps { + dashboardId: number; + siteId: string; +} +function MetricTypeList(props: Props) { + const { dashboardId, siteId, history } = props; + const { hideModal } = useModal(); -function MetricTypeList() { const { showModal } = useModal(); const onClick = ({ slug }: MetricType) => { - if (slug === 'library') { - showModal(, { right: true, width: 700 }); + hideModal(); + if (slug === LIBRARY) { + return showModal(, { right: true, width: 800 }); } + + // TODO redirect to card builder with metricType query param + const path = withSiteId(dashboardMetricCreate(dashboardId + ''), siteId); + history.push(path); }; + return ( <> - {METRIC_TYPES.map((metric: MetricType) => ( + {TYPES.map((metric: MetricType) => ( onClick(metric)} /> ))} ); } -export default MetricTypeList; +export default withRouter(MetricTypeList); diff --git a/frontend/app/components/Dashboard/components/MetricsLibraryModal/MetricsLibraryModal.tsx b/frontend/app/components/Dashboard/components/MetricsLibraryModal/MetricsLibraryModal.tsx index f6df7a81f..308924a12 100644 --- a/frontend/app/components/Dashboard/components/MetricsLibraryModal/MetricsLibraryModal.tsx +++ b/frontend/app/components/Dashboard/components/MetricsLibraryModal/MetricsLibraryModal.tsx @@ -1,13 +1,65 @@ import Modal from 'App/components/Modal/Modal'; -import React from 'react'; +import React, { useMemo, useState } from 'react'; +import MetricsList from '../MetricsList'; +import { Button } from 'UI'; +import { useModal } from 'App/components/Modal'; +import { useStore } from 'App/mstore'; +import { useObserver } from 'mobx-react-lite'; + +interface Props { + dashboardId: number; + siteId: string; +} +function MetricsLibraryModal(props: Props) { + const { siteId, dashboardId } = props; + const [selectedList, setSelectedList] = useState([]); + + console.log('dashboardId', dashboardId); + + const onSelectionChange = (list: any) => { + setSelectedList(list); + }; -function MetricsLibraryModal() { return ( <> - Hello + +
+ +
+ {/* TODO should show the dynamic values */} + +
); } export default MetricsLibraryModal; + +function SelectedContent({ dashboardId, selected }: any) { + const { hideModal } = useModal(); + const { metricStore, dashboardStore } = useStore(); + const total = useObserver(() => metricStore.sortedWidgets.length); + const dashboard = useMemo(() => dashboardStore.getDashboard(dashboardId), [dashboardId]); + + const addSelectedToDashboard = () => { + dashboardStore.addWidgetToDashboard(dashboard, selected).then(hideModal); + }; + + return ( +
+
+ Selected {selected.length} of{' '} + {total} +
+
+ + +
+
+ ); +} diff --git a/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx b/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx index b3880dbe2..3f2ca9c3c 100644 --- a/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx +++ b/frontend/app/components/Dashboard/components/MetricsList/MetricsList.tsx @@ -7,18 +7,31 @@ import MetricListItem from '../MetricListItem'; import { sliceListPerPage } from 'App/utils'; import Widget from 'App/mstore/types/widget'; -function MetricsList({ siteId }: { siteId: string }) { +function MetricsList({ + siteId, + onSelectionChange = () => {}, +}: { + siteId: string; + onSelectionChange?: (selected: any[]) => void; +}) { const { metricStore } = useStore(); const metrics = metricStore.sortedWidgets; const metricsSearch = metricStore.metricsSearch; - const [selectedMetrics, setSelectedMetrics] = useState([]); + const [selectedMetrics, setSelectedMetrics] = useState([]); + + useEffect(() => { + metricStore.fetchList(); + }, []); + + useEffect(() => { + onSelectionChange(selectedMetrics); + }, [selectedMetrics]); const toggleMetricSelection = (id: any) => { - console.log('id', id); if (selectedMetrics.includes(id)) { - selectedMetrics.splice(selectedMetrics.indexOf(id), 1); + setSelectedMetrics(selectedMetrics.filter((i: number) => i !== id)); } else { - selectedMetrics.push(id); + setSelectedMetrics([...selectedMetrics, id]); } }; @@ -48,7 +61,7 @@ function MetricsList({ siteId }: { siteId: string }) { } > -
+
{ e.stopPropagation(); toggleMetricSelection(parseInt(metric.metricId)); @@ -80,7 +93,7 @@ function MetricsList({ siteId }: { siteId: string }) { ))}
-
+
Showing{' '} {Math.min(list.length, metricStore.pageSize)} out diff --git a/frontend/app/components/Dashboard/components/MetricsView/MetricsView.tsx b/frontend/app/components/Dashboard/components/MetricsView/MetricsView.tsx index 929868550..a3621291b 100644 --- a/frontend/app/components/Dashboard/components/MetricsView/MetricsView.tsx +++ b/frontend/app/components/Dashboard/components/MetricsView/MetricsView.tsx @@ -1,7 +1,6 @@ import React from 'react'; import withPageTitle from 'HOCs/withPageTitle'; import MetricsList from '../MetricsList'; -import { useStore } from 'App/mstore'; import { useObserver } from 'mobx-react-lite'; import MetricViewHeader from '../MetricViewHeader'; @@ -9,14 +8,8 @@ interface Props { siteId: string; } function MetricsView({ siteId }: Props) { - const { metricStore } = useStore(); - - React.useEffect(() => { - metricStore.fetchList(); - }, []); - return useObserver(() => ( -
+
diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx index bf0ccda20..be1d80eef 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx @@ -8,6 +8,8 @@ import FilterSeries from '../FilterSeries'; import { confirm, Tooltip } from 'UI'; import Select from 'Shared/Select' import { withSiteId, dashboardMetricDetails, metricDetails } from 'App/routes' +import MetricTypeDropdown from './components/MetricTypeDropdown'; +import MetricSubtypeDropdown from './components/MetricSubtypeDropdown'; interface Props { history: any; @@ -103,18 +105,10 @@ function WidgetForm(props: Props) {
- i.value === metric.metricType) || metricTypes[0]} - // @ts-ignore - list={metricTypes.map((i) => ({ value: i.value, name: i.label, icon: metricIcons[i.value] }))} - /> + + - {metric.metricType === 'timeseries' && ( + {/* {metric.metricType === 'timeseries' && ( <> of - )} + )} */} {metric.metricOf === FilterKey.ISSUE && ( <> @@ -177,7 +171,7 @@ function WidgetForm(props: Props) { variant="text-primary" onClick={() => metric.addSeries()} disabled={!canAddSeries} - >Add Series + >ADD )}
diff --git a/frontend/app/components/Dashboard/components/WidgetForm/components/MetricSubtypeDropdown/MetricSubtypeDropdown.tsx b/frontend/app/components/Dashboard/components/WidgetForm/components/MetricSubtypeDropdown/MetricSubtypeDropdown.tsx new file mode 100644 index 000000000..4e76c47de --- /dev/null +++ b/frontend/app/components/Dashboard/components/WidgetForm/components/MetricSubtypeDropdown/MetricSubtypeDropdown.tsx @@ -0,0 +1,59 @@ +import { useStore } from 'App/mstore'; +import { useObserver } from 'mobx-react-lite'; +import { TYPES } from 'App/constants/card'; +import { MetricType } from 'App/components/Dashboard/components/MetricTypeItem/MetricTypeItem'; +import React from 'react'; +import Select from 'Shared/Select'; +import { components } from 'react-select'; +import CustomDropdownOption from 'Shared/CustomDropdownOption'; + +interface Props { + onSelect: any; +} +function MetricSubtypeDropdown(props: Props) { + const { metricStore } = useStore(); + const metric: any = useObserver(() => metricStore.instance); + + const options = React.useMemo(() => { + const type = TYPES.find((i: MetricType) => i.slug === metric.metricType); + if (type && type.subTypes) { + const options = type.subTypes.map((i: MetricType) => ({ + label: i.title, + icon: i.icon, + value: i.slug, + description: i.description, + })); + return options; + } + return false; + }, [metric.metricType]); + + return options ? ( + <> +
of
+ i.value === metric.metricType) || options[0]} + onChange={props.onSelect} + // onSelect={onSelect} + components={{ + MenuList: ({ children, ...props }: any) => { + return ( + + {children} + + ); + }, + Option: ({ children, ...props }: any) => { + const { data } = props; + return ; + }, + }} + /> + ); +} + +export default MetricTypeDropdown; diff --git a/frontend/app/components/Dashboard/components/WidgetForm/components/MetricTypeDropdown/index.ts b/frontend/app/components/Dashboard/components/WidgetForm/components/MetricTypeDropdown/index.ts new file mode 100644 index 000000000..ae7bd4cb1 --- /dev/null +++ b/frontend/app/components/Dashboard/components/WidgetForm/components/MetricTypeDropdown/index.ts @@ -0,0 +1 @@ +export { default } from './MetricTypeDropdown'; diff --git a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx index 3b8d8f246..3492e89c7 100644 --- a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx +++ b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx @@ -100,7 +100,7 @@ function WidgetView(props: Props) {
setExpanded(!expanded)}>
- {expanded ? 'Close' : 'Edit'} + {expanded ? 'Collapse' : 'Edit'}
diff --git a/frontend/app/components/Modal/Modal.tsx b/frontend/app/components/Modal/Modal.tsx index 52f3d3cfe..ab4a5fa23 100644 --- a/frontend/app/components/Modal/Modal.tsx +++ b/frontend/app/components/Modal/Modal.tsx @@ -47,7 +47,7 @@ Modal.Header = ({ title }: { title: string }) => { }; Modal.Content = ({ children, className = 'p-4' }: { children: any; className?: string }) => { - return
{children}
; + return
{children}
; }; export default Modal; diff --git a/frontend/app/components/shared/CustomDropdownOption/CustomDropdownOption.tsx b/frontend/app/components/shared/CustomDropdownOption/CustomDropdownOption.tsx new file mode 100644 index 000000000..4d8c6d2ad --- /dev/null +++ b/frontend/app/components/shared/CustomDropdownOption/CustomDropdownOption.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { components, OptionProps } from 'react-select'; +import { Icon } from 'UI'; +import cn from 'classnames'; + +export interface Props extends OptionProps { + icon?: string; + label: string; + description: string; +} +function CustomDropdownOption(props: Props) { + const { icon = '', label, description, isSelected, isFocused } = props; + return ( + +
+ {icon && ( + + )} +
+
{label}
+
{description}
+
+
+
+ ); +} + +export default CustomDropdownOption; diff --git a/frontend/app/components/shared/CustomDropdownOption/index.ts b/frontend/app/components/shared/CustomDropdownOption/index.ts new file mode 100644 index 000000000..240e1246d --- /dev/null +++ b/frontend/app/components/shared/CustomDropdownOption/index.ts @@ -0,0 +1 @@ +export { default } from './CustomDropdownOption'; diff --git a/frontend/app/components/shared/Insights/SankeyChart/SankeyChart.stories.tsx b/frontend/app/components/shared/Insights/SankeyChart/SankeyChart.stories.tsx index f0e3ed21e..dfb9949f8 100644 --- a/frontend/app/components/shared/Insights/SankeyChart/SankeyChart.stories.tsx +++ b/frontend/app/components/shared/Insights/SankeyChart/SankeyChart.stories.tsx @@ -1,13 +1,13 @@ -import { storiesOf } from '@storybook/react'; -import SankeyChart from './SankeyChart'; +import SankeyChart, { SankeyChartData } from './SankeyChart'; +import React from 'react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; -const data = { +const data: SankeyChartData = { nodes: [ { name: 'Home Page' }, { name: 'Dashboard' }, { name: 'Preferences' }, { name: 'Billing' }, - ], links: [ { source: 0, target: 1, value: 100 }, @@ -17,4 +17,12 @@ const data = { ], }; -storiesOf('SankeyChart', module).add('Pure', () => ); +export default { + title: 'Dashboad/Cards/SankeyChart', + component: SankeyChart, +} as ComponentMeta; + +const Template: ComponentStory = (args: any) => ; + +export const Simple = Template.bind({}); +Simple.args = { data }; diff --git a/frontend/app/components/shared/Insights/SankeyChart/SankeyChart.tsx b/frontend/app/components/shared/Insights/SankeyChart/SankeyChart.tsx index c09888102..511ca12e8 100644 --- a/frontend/app/components/shared/Insights/SankeyChart/SankeyChart.tsx +++ b/frontend/app/components/shared/Insights/SankeyChart/SankeyChart.tsx @@ -1,11 +1,27 @@ import React from 'react'; import { Sankey, Tooltip, Rectangle, Layer, ResponsiveContainer } from 'recharts'; +type Node = { + name: string; +} + +type Link = { + source: number; + target: number; + value: number; +} + +export interface SankeyChartData { + links: Link[]; + nodes: Node[]; +} interface Props { - data: any; + data: SankeyChartData; + nodePadding?: number; + nodeWidth?: number; } function SankeyChart(props: Props) { - const { data } = props; + const { data, nodePadding = 50, nodeWidth = 10 } = props; return (
Sankey Chart
@@ -17,8 +33,8 @@ function SankeyChart(props: Props) { data={data} // node={{ stroke: '#77c878', strokeWidth: 0 }} node={} - nodePadding={50} - nodeWidth={10} + nodePadding={nodePadding} + nodeWidth={nodeWidth} margin={{ left: 10, right: 100, @@ -33,7 +49,7 @@ function SankeyChart(props: Props) { - }/> + } />
@@ -44,10 +60,7 @@ function SankeyChart(props: Props) { export default SankeyChart; const CustomTooltip = (props: any) => { - console.log('props', props); - return ( -
test
- ) + return
test
; // if (active && payload && payload.length) { // return ( //
diff --git a/frontend/app/constants/card.ts b/frontend/app/constants/card.ts new file mode 100644 index 000000000..1c95f66ea --- /dev/null +++ b/frontend/app/constants/card.ts @@ -0,0 +1,213 @@ +import { IconNames } from 'App/components/ui/SVG'; +import { FilterKey, IssueType } from 'Types/filter/filterType'; + +export interface CardType { + title: string; + icon?: IconNames; + description: string; + slug: string; + subTypes?: CardType[]; +} + +export const LIBRARY = 'library'; +export const TIMESERIES = 'timeseries'; +export const TABLE = 'table'; + +export const TYPES: CardType[] = [ + { + title: 'Add From Library', + icon: 'grid', + description: 'Select a pre existing card from card library', + slug: LIBRARY, + }, + { + title: 'Timeseries', + icon: 'graph-up', + description: 'Trend of sessions count in over the time.', + slug: TIMESERIES, + subTypes: [{ title: 'Session Count', slug: 'sessionCount', description: '' }], + }, + { + title: 'Table', + icon: 'list-alt', + description: 'See list of Users, Sessions, Errors, Issues, etc.,', + slug: TABLE, + subTypes: [ + { title: 'Users', slug: FilterKey.USERID, description: '' }, + { title: 'Sessions', slug: FilterKey.SESSIONS, description: '' }, + { title: 'JS Errors', slug: FilterKey.ERRORS, description: '' }, + { title: 'Issues', slug: FilterKey.ISSUE, description: '' }, + { title: 'Browser', slug: FilterKey.USER_BROWSER, description: '' }, + { title: 'Devices', slug: FilterKey.USER_DEVICE, description: '' }, + { title: 'Countries', slug: FilterKey.USER_COUNTRY, description: '' }, + { title: 'URLs', slug: FilterKey.LOCATION, description: '' }, + ], + }, + { + title: 'Funnel', + icon: 'funnel', + description: 'Uncover the issues impacting user journeys.', + slug: 'funnel', + }, + { + title: 'Errors Tracking', + icon: 'exclamation-circle', + description: 'Discover user journeys between 2 points.', + slug: 'errors', + subTypes: [ + { title: 'Resources by Party', slug: FilterKey.RESOURCES_BY_PARTY, description: '' }, + { title: 'Errors per Domains', slug: FilterKey.ERRORS_PER_DOMAINS, description: '' }, + { title: 'Errors per type', slug: FilterKey.ERRORS_PER_TYPE, description: '' }, + { title: 'Calls_Errors', slug: FilterKey.CALLS_ERRORS, description: '' }, + { title: 'Domains_Errors_4xx', slug: FilterKey.DOMAINS_ERRORS_4XX, description: '' }, + { title: 'Domains_Errors_5xx', slug: FilterKey.DOMAINS_ERRORS_5XX, description: '' }, + { + title: 'Impacted_Sessions_By_Js_Errors', + slug: FilterKey.IMPACTED_SESSIONS_BY_JS_ERRORS, + description: '', + }, + ], + }, + { + title: 'Performance Monitoring', + icon: 'speedometer2', + description: 'Retention graph of users / features over a period of time.', + slug: 'performance', + subTypes: [ + { title: 'Cpu', slug: FilterKey.CPU, description: '' }, + { title: 'Crashes', slug: FilterKey.CRASHES, description: '' }, + { title: 'Fps', slug: FilterKey.FPS, description: '' }, + { title: 'Pages_Dom_Build_Time', slug: FilterKey.PAGES_DOM_BUILD_TIME, description: '' }, + { title: 'Memory_Consumption', slug: FilterKey.MEMORY_CONSUMPTION, description: '' }, + { title: 'Pages_Response_Time', slug: FilterKey.PAGES_RESPONSE_TIME, description: '' }, + { + title: 'Pages_Response_Time_Distribution', + slug: FilterKey.PAGES_RESPONSE_TIME_DISTRIBUTION, + description: '', + }, + { + title: 'Resources_Vs_Visually_Complete', + slug: FilterKey.RESOURCES_VS_VISUALLY_COMPLETE, + description: '', + }, + { title: 'Sessions_Per_Browser', slug: FilterKey.SESSIONS_PER_BROWSER, description: '' }, + { title: 'Slowest_Domains', slug: FilterKey.SLOWEST_DOMAINS, description: '' }, + { title: 'Speed_Location', slug: FilterKey.SPEED_LOCATION, description: '' }, + { title: 'Time_To_Render', slug: FilterKey.TIME_TO_RENDER, description: '' }, + { + title: 'Impacted_Sessions_By_Slow_Pages', + slug: FilterKey.IMPACTED_SESSIONS_BY_SLOW_PAGES, + description: '', + }, + ], + }, + { + title: 'Resource Monitoring', + icon: 'files', + description: 'Find the adoption of your all features in your app.', + slug: 'resource-monitoring', + subTypes: [ + { + title: 'Breakdown_Of_Loaded_Resources', + slug: FilterKey.BREAKDOWN_OF_LOADED_RESOURCES, + description: '', + }, + { title: 'Missing_Resources', slug: FilterKey.MISSING_RESOURCES, description: '' }, + { + title: 'Resource_Type_Vs_Response_End', + slug: FilterKey.RESOURCE_TYPE_VS_RESPONSE_END, + description: '', + }, + { title: 'Resource_Fetch_Time', slug: FilterKey.RESOURCE_FETCH_TIME, description: '' }, + { title: 'Slowest_Resources', slug: FilterKey.SLOWEST_RESOURCES, description: '' }, + ], + }, + { + title: 'Web Vitals', + icon: 'activity', + description: 'Find the adoption of your all features in your app.', + slug: 'web-vitals', + subTypes: [ + { + title: 'Resources_Count_By_Type', + slug: FilterKey.RESOURCES_COUNT_BY_TYPE, + description: '', + }, + { title: 'Resources_Loading_Time', slug: FilterKey.RESOURCES_LOADING_TIME, description: '' }, + { + title: 'CPU Load', + slug: FilterKey.AVG_CPU, + description: 'Uncover the issues impacting user journeys', + }, + { + title: 'DOM Build Time', + slug: FilterKey.AVG_DOM_CONTENT_LOADED, + description: 'Keep a close eye on errors and track their type, origin and domain.', + }, + { + title: 'DOM Content Loaded Start', + slug: FilterKey.AVG_DOM_CONTENT_LOAD_START, + description: + 'FInd out which resources are missing and those that may be slowign your web app.', + }, + { + title: 'DOM Content Loaded', + slug: FilterKey.AVG_FIRST_CONTENTFUL_PIXEL, + description: + "Optimize your app's performance by tracking slow domains, page resposne times, memory consumption, CPU usage and more.", + }, + { + title: 'First Paint', + slug: FilterKey.AVG_FIRST_PAINT, + description: + 'Find out which resources are missing and those that may be slowing your web app.', + }, + { title: 'Frame Rate', slug: FilterKey.AVG_FPS, description: '' }, + { + title: 'Image Load Time', + slug: FilterKey.AVG_IMAGE_LOAD_TIME, + description: + 'Find out which resources are missing and those that may be slowing your web app.', + }, + { title: 'Page Load Time', slug: FilterKey.AVG_PAGE_LOAD_TIME, description: '' }, + { title: 'DOM Build Time', slug: FilterKey.AVG_PAGES_DOM_BUILD_TIME, description: '' }, + { title: 'Pages Response Time', slug: FilterKey.AVG_PAGES_RESPONSE_TIME, description: '' }, + { title: 'Request Load Time', slug: FilterKey.AVG_REQUEST_LOADT_IME, description: '' }, + { title: 'Response Time ', slug: FilterKey.AVG_RESPONSE_TIME, description: '' }, + { title: 'Session Dueration', slug: FilterKey.AVG_SESSION_DURATION, description: '' }, + { title: 'Time Till First Byte', slug: FilterKey.AVG_TILL_FIRST_BYTE, description: '' }, + { title: 'Time to be Interactive', slug: FilterKey.AVG_TIME_TO_INTERACTIVE, description: '' }, + { title: 'Time to Render', slug: FilterKey.AVG_TIME_TO_RENDER, description: '' }, + { title: 'JS Heap Size', slug: FilterKey.AVG_USED_JS_HEAP_SIZE, description: '' }, + { title: 'Visited Pages', slug: FilterKey.AVG_VISITED_PAGES, description: '' }, + { + title: 'Captured Requests', + slug: FilterKey.COUNT_REQUESTS, + description: 'Trend of sessions count in over the time.', + }, + { + title: 'Captured Sessions', + slug: FilterKey.COUNT_SESSIONS, + description: 'See list of users, sessions, errors, issues, etc.,', + }, + ], + }, + { + title: 'User Path', + icon: 'signpost-split', + description: 'Discover user journeys between 2 points.', + slug: 'user-path', + }, + { + title: 'Retention', + icon: 'arrow-repeat', + description: 'Retension graph of users / features over a period of time.', + slug: 'retention', + }, + { + title: 'Feature Adoption', + icon: 'card-checklist', + description: 'Find the adoption of your all features in your app.', + slug: 'feature-adoption', + }, +]; diff --git a/frontend/app/mstore/dashboardStore.ts b/frontend/app/mstore/dashboardStore.ts index bf3a970d8..417f20f4d 100644 --- a/frontend/app/mstore/dashboardStore.ts +++ b/frontend/app/mstore/dashboardStore.ts @@ -277,9 +277,9 @@ export default class DashboardStore { ); } - getDashboard(dashboardId: string): Dashboard | null { + getDashboard(dashboardId: string|number): Dashboard | null { return ( - this.dashboards.find((d) => d.dashboardId === dashboardId) || null + this.dashboards.find((d) => d.dashboardId == dashboardId) || null ); } diff --git a/frontend/app/types/filter/filterType.ts b/frontend/app/types/filter/filterType.ts index 9d2748e2e..c82a54779 100644 --- a/frontend/app/types/filter/filterType.ts +++ b/frontend/app/types/filter/filterType.ts @@ -220,4 +220,58 @@ export enum FilterKey { SESSIONS = 'SESSIONS', ERRORS = 'js_exception', + + RESOURCES_COUNT_BY_TYPE = 'resourcesCountByType', + RESOURCES_LOADING_TIME = 'resourcesLoadingTime', + AVG_CPU = 'avgCpu', + AVG_DOM_CONTENT_LOADED = 'avgDomContentLoaded', + AVG_DOM_CONTENT_LOAD_START = 'avgDomContentLoadStart', + AVG_FIRST_CONTENTFUL_PIXEL = 'avgFirstContentfulPixel', + AVG_FIRST_PAINT = 'avgFirstPaint', + AVG_FPS = 'avgFps', + AVG_IMAGE_LOAD_TIME = 'avgImageLoadTime', + AVG_PAGE_LOAD_TIME = 'avgPageLoadTime', + AVG_PAGES_DOM_BUILD_TIME = 'avgPagesDomBuildtime', + AVG_PAGES_RESPONSE_TIME = 'avgPagesResponseTime', + AVG_REQUEST_LOADT_IME = 'avgRequestLoadTime', + AVG_RESPONSE_TIME = 'avgResponseTime', + AVG_SESSION_DURATION = 'avgSessionDuration', + AVG_TILL_FIRST_BYTE = 'avgTillFirstByte', + AVG_TIME_TO_INTERACTIVE = 'avgTimeToInteractive', + AVG_TIME_TO_RENDER = 'avgTimeToRender', + AVG_USED_JS_HEAP_SIZE = 'avgUsedJsHeapSize', + AVG_VISITED_PAGES = 'avgVisitedPages', + COUNT_REQUESTS = 'countRequests', + COUNT_SESSIONS = 'countSessions', + + // Errors + RESOURCES_BY_PARTY = 'resourcesByParty', + ERRORS_PER_DOMAINS = 'errorsPerDomains', + ERRORS_PER_TYPE = 'errorsPerType', + CALLS_ERRORS = 'callsErrors', + DOMAINS_ERRORS_4XX = 'domainsErrors4Xx', + DOMAINS_ERRORS_5XX = 'domainsErrors5Xx', + IMPACTED_SESSIONS_BY_JS_ERRORS = 'impactedSessionsByJsErrors', + + // Performance + CPU = 'cpu', + CRASHES = 'crashes', + FPS = 'fps', + PAGES_DOM_BUILD_TIME = 'pagesDomBuildtime', + MEMORY_CONSUMPTION = 'memoryConsumption', + PAGES_RESPONSE_TIME = 'pagesResponseTime', + PAGES_RESPONSE_TIME_DISTRIBUTION = 'pagesResponseTimeDistribution', + RESOURCES_VS_VISUALLY_COMPLETE = 'resourcesVsVisuallyComplete', + SESSIONS_PER_BROWSER = 'sessionsPerBrowser', + SLOWEST_DOMAINS = 'slowestDomains', + SPEED_LOCATION = 'speedLocation', + TIME_TO_RENDER = 'timeToRender', + IMPACTED_SESSIONS_BY_SLOW_PAGES = 'impactedSessionsBySlowPages', + + // Resources + BREAKDOWN_OF_LOADED_RESOURCES = 'breakdownOfLoadedResources', + MISSING_RESOURCES = 'missingResources', + RESOURCE_TYPE_VS_RESPONSE_END = 'resourceTypeVsResponseEnd', + RESOURCE_FETCH_TIME = 'resourceFetchTime', + SLOWEST_RESOURCES = 'slowestResources', }