feat(ui) - dashboard improvements - api - integration and other fixes

This commit is contained in:
Shekar Siri 2023-01-02 09:31:45 +01:00
parent 9ff3b2f017
commit 7fb72a7f20
11 changed files with 141 additions and 122 deletions

View file

@ -46,13 +46,13 @@ function MetricListItem(props: Props) {
onClick={onItemClick}
>
<div className="col-span-4 flex items-center">
{/* <Checkbox
<Checkbox
name="slack"
className="mr-4"
type="checkbox"
checked={selected}
onClick={toggleSelection}
/> */}
/>
<div className="flex items-center">
<MetricTypeIcon type={metric.metricType} />
<div className="link capitalize-first">{metric.name}</div>

View file

@ -1,20 +1,23 @@
import Modal from 'App/components/Modal/Modal';
import React, { useMemo, useState } from 'react';
import React, { useEffect, 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';
import { observer, useObserver } from 'mobx-react-lite';
interface Props {
dashboardId: number;
siteId: string;
}
function MetricsLibraryModal(props: Props) {
const { metricStore } = useStore();
const { siteId, dashboardId } = props;
const [selectedList, setSelectedList] = useState([]);
console.log('dashboardId', dashboardId);
useEffect(() => {
metricStore.updateKey('listView', true)
}, [])
const onSelectionChange = (list: any) => {
setSelectedList(list);
@ -34,7 +37,7 @@ function MetricsLibraryModal(props: Props) {
);
}
export default MetricsLibraryModal;
export default observer(MetricsLibraryModal);
function SelectedContent({ dashboardId, selected }: any) {
const { hideModal } = useModal();

View file

@ -13,7 +13,7 @@ function ListView(props: Props) {
return (
<div>
<div className="grid grid-cols-12 py-2 font-medium px-6">
{/* <div className="col-span-4 flex items-center">
<div className="col-span-4 flex items-center">
<Checkbox
name="slack"
className="mr-4"
@ -22,7 +22,7 @@ function ListView(props: Props) {
onClick={() => selectedList(list.map((i: any) => i.metricId))}
/>
<span>Title</span>
</div> */}
</div>
<div className="col-span-4">Owner</div>
<div className="col-span-2">Visibility</div>
<div className="col-span-2 text-right">Last Modified</div>

View file

@ -13,7 +13,7 @@ import { getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper';
import { debounce } from 'App/utils';
import useIsMounted from 'App/hooks/useIsMounted'
import { FilterKey } from 'Types/filter/filterType';
import { CLICKMAP } from 'App/constants/card';
import { TIMESERIES, TABLE, CLICKMAP, FUNNEL, ERRORS, PERFORMANCE, RESOURCE_MONITORING, WEB_VITALS } from 'App/constants/card';
import FunnelWidget from 'App/components/Funnels/FunnelWidget';
import ErrorsWidget from '../Errors/ErrorsWidget';
import SessionWidget from '../Sessions/SessionWidget';
@ -101,23 +101,25 @@ function WidgetChart(props: Props) {
return <SessionWidget metric={metric} data={data} />
}
if (metricType === 'errors') {
return <ErrorsWidget metric={metric} data={data} />
}
// if (metricType === ERRORS) {
// return <ErrorsWidget metric={metric} data={data} />
// }
if (metricType === 'funnel') {
if (metricType === FUNNEL) {
return <FunnelWidget metric={metric} data={data} isWidget={isWidget || isTemplate} />
}
if (metricType === 'predefined') {
if (metricType === 'predefined' || metricType === ERRORS || metricType === PERFORMANCE || metricType === RESOURCE_MONITORING || metricType === WEB_VITALS) {
const defaultMetric = metric.data.chart.length === 0 ? metricWithData : metric
if (isOverviewWidget) {
return <CustomMetricOverviewChart data={data} />
}
return <WidgetPredefinedChart isTemplate={isTemplate} metric={defaultMetric} data={data} predefinedKey={metric.predefinedKey} />
return <WidgetPredefinedChart isTemplate={isTemplate} metric={defaultMetric} data={data} predefinedKey={metric.metricOf} />
}
if (metricType === 'timeseries') {
// TODO add USER_PATH, RETENTION, FEATUER_ADOPTION
if (metricType === TIMESERIES) {
if (viewType === 'lineChart') {
return (
<CustomMetriLineChart
@ -138,7 +140,7 @@ function WidgetChart(props: Props) {
}
}
if (metricType === 'table') {
if (metricType === TABLE) {
if (metricOf === FilterKey.SESSIONS) {
return (
<CustomMetricTableSessions
@ -159,7 +161,7 @@ function WidgetChart(props: Props) {
/>
)
}
if (viewType === 'table') {
if (viewType === TABLE) {
return (
<CustomMetricTable
metric={metric} data={data[0]}

View file

@ -10,7 +10,7 @@ import Select from 'Shared/Select';
import { withSiteId, dashboardMetricDetails, metricDetails } from 'App/routes';
import MetricTypeDropdown from './components/MetricTypeDropdown';
import MetricSubtypeDropdown from './components/MetricSubtypeDropdown';
import { TIMESERIES, TABLE, CLICKMAP } from 'App/constants/card';
import { TIMESERIES, TABLE, CLICKMAP, FUNNEL, ERRORS } from 'App/constants/card';
import { clickmapFilter } from 'App/types/filter/newFilter';
import { renderClickmapThumbnail } from './renderMap'
@ -67,6 +67,10 @@ function WidgetForm(props: Props) {
} else if (value === TABLE) {
obj['metricOf'] = tableOptions[0].value;
obj['viewType'] = 'table';
} else if (value === FUNNEL) {
obj['metricOf'] = 'sessionCount';
} else if (value === ERRORS) {
obj['viewType'] = 'chart';
}
if (metric.metricType === CLICKMAP && value !== CLICKMAP) {
metric.series[0].filter.removeFilter(0)

View file

@ -27,6 +27,7 @@ import CallWithErrors from '../../Widgets/PredefinedWidgets/CallWithErrors';
import SpeedIndexByLocation from '../../Widgets/PredefinedWidgets/SpeedIndexByLocation';
import SlowestResources from '../../Widgets/PredefinedWidgets/SlowestResources';
import ResponseTimeDistribution from '../../Widgets/PredefinedWidgets/ResponseTimeDistribution';
import { FilterKey } from 'Types/filter/filterType';
interface Props {
data: any;
@ -40,59 +41,59 @@ function WidgetPredefinedChart(props: Props) {
const renderWidget = () => {
switch (predefinedKey) {
// ERRORS
case 'errors_per_type':
case FilterKey.ERRORS_PER_TYPE:
return <ErrorsByType data={data} metric={metric} />
case 'errors_per_domains':
case FilterKey.ERRORS_PER_DOMAINS:
return <ErrorsPerDomain data={data} metric={metric} />
case 'resources_by_party':
case FilterKey.RESOURCES_BY_PARTY:
return <ErrorsByOrigin data={data} metric={metric} />
case 'impacted_sessions_by_js_errors':
case FilterKey.IMPACTED_SESSIONS_BY_JS_ERRORS:
return <SessionsAffectedByJSErrors data={data} metric={metric} />
case 'domains_errors_4xx':
case FilterKey.DOMAINS_ERRORS_4XX:
return <CallsErrors4xx data={data} metric={metric} />
case 'domains_errors_5xx':
case FilterKey.DOMAINS_ERRORS_5XX:
return <CallsErrors5xx data={data} metric={metric} />
case 'calls_errors':
case FilterKey.CALLS_ERRORS:
return <CallWithErrors isTemplate={isTemplate} data={data} metric={metric} />
// PERFORMANCE
case 'impacted_sessions_by_slow_pages':
case FilterKey.IMPACTED_SESSIONS_BY_SLOW_PAGES:
return <SessionsImpactedBySlowRequests data={data} metric={metric} />
case 'pages_response_time_distribution':
case FilterKey.PAGES_RESPONSE_TIME_DISTRIBUTION:
return <ResponseTimeDistribution data={data} metric={metric} />
case 'speed_location':
case FilterKey.SPEED_LOCATION:
return <SpeedIndexByLocation metric={metric} />
case 'cpu':
case FilterKey.CPU:
return <CPULoad data={data} metric={metric} />
case 'crashes':
case FilterKey.CRASHES:
return <Crashes data={data} metric={metric} />
case 'pages_dom_buildtime':
case FilterKey.PAGES_DOM_BUILD_TIME:
return <DomBuildingTime data={data} metric={metric} />
case 'fps':
case FilterKey.FPS:
return <FPS data={data} metric={metric} />
case 'memory_consumption':
case FilterKey.MEMORY_CONSUMPTION:
return <MemoryConsumption data={data} metric={metric} />
case 'pages_response_time':
case FilterKey.PAGES_RESPONSE_TIME:
return <ResponseTime data={data} metric={metric} />
case 'resources_vs_visually_complete':
case FilterKey.RESOURCES_VS_VISUALLY_COMPLETE:
return <ResourceLoadedVsVisuallyComplete data={data} metric={metric} />
case 'sessions_per_browser':
case FilterKey.SESSIONS_PER_BROWSER:
return <SessionsPerBrowser data={data} metric={metric} />
case 'slowest_domains':
case FilterKey.SLOWEST_DOMAINS:
return <SlowestDomains data={data} metric={metric} />
case 'time_to_render':
case FilterKey.TIME_TO_RENDER:
return <TimeToRender data={data} metric={metric} />
// Resources
case 'resources_count_by_type':
case FilterKey.BREAKDOWN_OF_LOADED_RESOURCES:
return <BreakdownOfLoadedResources data={data} metric={metric} />
case 'missing_resources':
case FilterKey.MISSING_RESOURCES:
return <MissingResources isTemplate={isTemplate} data={data} metric={metric} />
case 'resource_type_vs_response_end':
case FilterKey.RESOURCE_TYPE_VS_RESPONSE_END:
return <ResourceLoadedVsResponseEnd data={data} metric={metric} />
case 'resources_loading_time':
case FilterKey.RESOURCES_LOADING_TIME:
return <ResourceLoadingTime data={data} metric={metric} />
case 'slowest_resources':
case FilterKey.SLOWEST_RESOURCES:
return <SlowestResources isTemplate={isTemplate} data={data} metric={metric} />
default:

View file

@ -38,9 +38,9 @@ class SegmentSelection extends React.Component {
className
)}
>
{list.map((item) => (
{list.map((item, i) => (
<div
key={item.name}
key={`${item.name}-${i}`}
className={cn(styles.item, 'w-full', { 'opacity-25 cursor-default': item.disabled })}
data-active={this.props.value && this.props.value.value === item.value}
onClick={() => !item.disabled && this.setActiveItem(item)}

View file

@ -12,7 +12,15 @@ export interface CardType {
export const LIBRARY = 'library';
export const TIMESERIES = 'timeseries';
export const TABLE = 'table';
export const CLICKMAP = 'clickMap'
export const CLICKMAP = 'clickMap';
export const FUNNEL = 'funnel';
export const ERRORS = 'errors';
export const PERFORMANCE = 'performance';
export const RESOURCE_MONITORING = 'resources';
export const WEB_VITALS = 'webVitals';
export const USER_PATH = 'userPath';
export const RETENTION = 'retention';
export const FEATURE_ADOPTION = 'featureAdoption';
export const TYPES: CardType[] = [
{
@ -57,22 +65,22 @@ export const TYPES: CardType[] = [
title: 'Funnel',
icon: 'funnel',
description: 'Uncover the issues impacting user journeys.',
slug: 'funnel',
slug: FUNNEL,
},
{
title: 'Errors Tracking',
icon: 'exclamation-circle',
description: 'Discover user journeys between 2 points.',
slug: 'errors',
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: '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',
title: 'Impacted Sessions by JS Errors',
slug: FilterKey.IMPACTED_SESSIONS_BY_JS_ERRORS,
description: '',
},
@ -82,30 +90,30 @@ export const TYPES: CardType[] = [
title: 'Performance Monitoring',
icon: 'speedometer2',
description: 'Retention graph of users / features over a period of time.',
slug: 'performance',
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 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',
title: 'Pages Response Time Distribution',
slug: FilterKey.PAGES_RESPONSE_TIME_DISTRIBUTION,
description: '',
},
{
title: 'Resources_Vs_Visually_Complete',
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: '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',
title: 'Impacted Sessions By Slow Pages',
slug: FilterKey.IMPACTED_SESSIONS_BY_SLOW_PAGES,
description: '',
},
@ -115,35 +123,35 @@ export const TYPES: CardType[] = [
title: 'Resource Monitoring',
icon: 'files',
description: 'Find the adoption of your all features in your app.',
slug: 'resource-monitoring',
slug: RESOURCE_MONITORING,
subTypes: [
{
title: 'Breakdown_Of_Loaded_Resources',
title: 'Breakdown of Loaded Resources',
slug: FilterKey.BREAKDOWN_OF_LOADED_RESOURCES,
description: '',
},
{ title: 'Missing_Resources', slug: FilterKey.MISSING_RESOURCES, description: '' },
{ title: 'Missing Resources', slug: FilterKey.MISSING_RESOURCES, description: '' },
{
title: 'Resource_Type_Vs_Response_End',
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: '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',
slug: WEB_VITALS,
subTypes: [
{
title: 'Resources_Count_By_Type',
title: 'Resources Count By Type',
slug: FilterKey.RESOURCES_COUNT_BY_TYPE,
description: '',
},
{ title: 'Resources_Loading_Time', slug: FilterKey.RESOURCES_LOADING_TIME, description: '' },
{ title: 'Resources Loading Time', slug: FilterKey.RESOURCES_LOADING_TIME, description: '' },
{
title: 'CPU Load',
slug: FilterKey.AVG_CPU,
@ -206,18 +214,18 @@ export const TYPES: CardType[] = [
title: 'User Path',
icon: 'signpost-split',
description: 'Discover user journeys between 2 points.',
slug: 'user-path',
slug: USER_PATH,
},
{
title: 'Retention',
icon: 'arrow-repeat',
description: 'Retension graph of users / features over a period of time.',
slug: 'retention',
slug: RETENTION,
},
{
title: 'Feature Adoption',
icon: 'card-checklist',
description: 'Find the adoption of your all features in your app.',
slug: 'feature-adoption',
slug: FEATURE_ADOPTION,
},
];

View file

@ -18,7 +18,7 @@ export default class MetricStore {
sessionsPage: number = 1;
sessionsPageSize: number = 10;
listView?: boolean = false
listView?: boolean = true
clickMapFilter: boolean = false
clickMapSearch = ''
@ -38,6 +38,7 @@ export default class MetricStore {
}
updateKey(key: string, value: any) {
console.log('up');
// @ts-ignore
this[key] = value;
}

View file

@ -18,7 +18,7 @@ export default class MetricService {
* @returns {Promise<any>}
*/
getMetrics(): Promise<any> {
return this.client.post('/cards/search', { limit: 100 })
return this.client.get('/cards')
.then((response: { json: () => any; }) => response.json())
.then((response: { data: any; }) => response.data || []);
}

View file

@ -135,18 +135,18 @@ export const getFilterKeyTypeByKey = (key: string) => {
};
export enum IssueType {
CLICK_RAGE = 'clickRage',
DEAD_CLICK = 'deadClick',
EXCESSIVE_SCROLLING = 'excessiveScrolling',
BAD_REQUEST = 'badRequest',
MISSING_RESOURCE = 'missingResource',
CLICK_RAGE = 'click_rage',
DEAD_CLICK = 'dead_click',
EXCESSIVE_SCROLLING = 'excessive_scrolling',
BAD_REQUEST = 'bad_request',
MISSING_RESOURCE = 'missing_resource',
MEMORY = 'memory',
CPU = 'cpu',
SLOW_RESOURCE = 'slowResource',
SLOW_PAGE_LOAD = 'slowPageLoad',
SLOW_RESOURCE = 'slow_resource',
SLOW_PAGE_LOAD = 'slow_pageLoad',
CRASH = 'crash',
CUSTOM = 'custom',
JS_EXCEPTION = 'jsException',
JS_EXCEPTION = 'js_exception',
}
export enum FilterType {
@ -165,39 +165,39 @@ export enum FilterType {
}
export enum FilterKey {
ERROR = 'ERROR',
MISSING_RESOURCE = 'MISSING_RESOURCE',
SLOW_SESSION = 'SLOW_SESSION',
CLICK_RAGE = 'CLICK_RAGE',
CLICK = 'CLICK',
INPUT = 'INPUT',
LOCATION = 'LOCATION',
VIEW = 'VIEW',
CONSOLE = 'CONSOLE',
METADATA = 'METADATA',
CUSTOM = 'CUSTOM',
URL = 'URL',
USER_BROWSER = 'USERBROWSER',
USER_OS = 'USEROS',
USER_DEVICE = 'USERDEVICE',
PLATFORM = 'PLATFORM',
DURATION = 'DURATION',
REFERRER = 'REFERRER',
USER_COUNTRY = 'USERCOUNTRY',
JOURNEY = 'JOURNEY',
REQUEST = 'REQUEST',
GRAPHQL = 'GRAPHQL',
STATEACTION = 'STATEACTION',
REVID = 'REVID',
USERANONYMOUSID = 'USERANONYMOUSID',
USERID = 'USERID',
ISSUE = 'ISSUE',
EVENTS_COUNT = 'EVENTS_COUNT',
UTM_SOURCE = 'UTM_SOURCE',
UTM_MEDIUM = 'UTM_MEDIUM',
UTM_CAMPAIGN = 'UTM_CAMPAIGN',
ERROR = 'error',
MISSING_RESOURCE = 'missingResource',
SLOW_SESSION = 'slowSession',
CLICK_RAGE = 'clickRage',
CLICK = 'click',
INPUT = 'input',
LOCATION = 'location',
VIEW = 'view',
CONSOLE = 'console',
METADATA = 'metadata',
CUSTOM = 'custom',
URL = 'url',
USER_BROWSER = 'userBrowser',
USER_OS = 'userOs',
USER_DEVICE = 'userDevice',
PLATFORM = 'platform',
DURATION = 'duration',
REFERRER = 'preferrer',
USER_COUNTRY = 'userCountry',
JOURNEY = 'journey',
REQUEST = 'request',
GRAPHQL = 'graphql',
STATEACTION = 'stateAction',
REVID = 'revId',
USERANONYMOUSID = 'userAnonymousId',
USERID = 'userId',
ISSUE = 'issue',
EVENTS_COUNT = 'eventsCount',
UTM_SOURCE = 'utmSource',
UTM_MEDIUM = 'utmMedium',
UTM_CAMPAIGN = 'utmCampaign',
DOM_COMPLETE = 'DOM_COMPLETE',
DOM_COMPLETE = 'domComplete',
LARGEST_CONTENTFUL_PAINT_TIME = 'LARGEST_CONTENTFUL_PAINT_TIME',
TIME_BETWEEN_EVENTS = 'TIME_BETWEEN_EVENTS',
TTFB = 'TTFB',
@ -218,8 +218,8 @@ export enum FilterKey {
GRAPHQL_REQUEST_BODY = 'GRAPHQL_REQUEST_BODY',
GRAPHQL_RESPONSE_BODY = 'GRAPHQL_RESPONSE_BODY',
SESSIONS = 'SESSIONS',
ERRORS = 'js_exception',
SESSIONS = 'sessions',
ERRORS = 'jsException',
RESOURCES_COUNT_BY_TYPE = 'resourcesCountByType',
RESOURCES_LOADING_TIME = 'resourcesLoadingTime',
@ -249,8 +249,8 @@ export enum FilterKey {
ERRORS_PER_DOMAINS = 'errorsPerDomains',
ERRORS_PER_TYPE = 'errorsPerType',
CALLS_ERRORS = 'callsErrors',
DOMAINS_ERRORS_4XX = 'domainsErrors4Xx',
DOMAINS_ERRORS_5XX = 'domainsErrors5Xx',
DOMAINS_ERRORS_4XX = 'domainsErrors4xx',
DOMAINS_ERRORS_5XX = 'domainsErrors5xx',
IMPACTED_SESSIONS_BY_JS_ERRORS = 'impactedSessionsByJsErrors',
// Performance