feat(ui) - custom metrics - wip

This commit is contained in:
Shekar Siri 2022-03-03 13:24:39 +01:00
parent fd9f4bc0d3
commit ed56d206be
22 changed files with 254 additions and 151 deletions

View file

@ -240,7 +240,6 @@ export default class Dashboard extends React.PureComponent {
Custom Metrics are not supported for comparison.
</div>
)}
{/* <CustomMetrics /> */}
</div>
}
>

View file

@ -8,15 +8,17 @@ interface Props {
params: any;
seriesMap: any;
colors: any;
onClick?: (event, index) => void;
}
function CustomMetriLineChart(props: Props) {
const { data, params, seriesMap, colors } = props;
const { data, params, seriesMap, colors, onClick = () => null } = props;
return (
<ResponsiveContainer height={ 240 } width="100%">
<LineChart
data={ data }
margin={Styles.chartMargins}
// syncId={ showSync ? "domainsErrors_4xx" : undefined }
onClick={onClick}
>
<CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" />
<XAxis

View file

@ -1 +0,0 @@
export { default } from './CustomMetriPercentage';

View file

@ -2,13 +2,16 @@ import React from 'react'
interface Props {
data: any;
params: any;
colors: any;
onClick?: (event, index) => void;
}
function CustomMetriPercentage(props: Props) {
const { data } = props;
return (
<div className="flex flex-col items-center justify-center" style={{ height: '240px'}}>
<div className="text-6xl">0%</div>
<div className="text-lg mt-6">0 ( 0.0% ) from previous hour</div>
<div className="text-6xl">{data.count}</div>
<div className="text-lg mt-6">{`${data.previousCount} ( ${data.countProgress}% ) from previous hour`}</div>
</div>
)
}

View file

@ -0,0 +1 @@
export { default } from './CustomMetricPercentage';

View file

@ -1,15 +1,46 @@
import React from 'react'
import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts';
import { LineChart, Line, Legend, PieChart, Pie } from 'recharts';
import { Styles } from '../../common';
interface Props {
data: any;
params: any;
// seriesMap: any;
colors: any;
onClick?: (event, index) => void;
}
function CustomMetricPieChart(props: Props) {
const { data } = props;
const { data, params, colors, onClick = () => null } = props;
const data01 = [
{ "name": "Group A", "value": 400 },
{ "name": "Group B", "value": 300 },
{ "name": "Group C", "value": 300 },
{ "name": "Group D", "value": 200 },
{ "name": "Group E", "value": 278 },
{ "name": "Group F", "value": 189 }
];
return (
<div className="flex flex-col items-center justify-center" style={{ height: '240px'}}>
<div className="text-6xl">0%</div>
<div className="text-lg mt-6">0 ( 0.0% ) from previous hour</div>
</div>
// <div className="flex flex-col items-center justify-center" style={{ height: '240px'}}>
// <div className="text-6xl">0%</div>
// <div className="text-lg mt-6">0 ( 0.0% ) from previous hour</div>
// </div>
<ResponsiveContainer height={ 240 } width="100%">
<PieChart width={730} height={250} onClick={onClick}>
<Pie
data={data01}
dataKey="value"
nameKey="name"
cx="50%"
cy="50%"
innerRadius={40}
outerRadius={70}
fill={colors[0]}
activeIndex={1}
label
/>
<Tooltip {...Styles.tooltip} />
</PieChart>
</ResponsiveContainer>
)
}

View file

@ -2,22 +2,24 @@ import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Loader, NoContent, Icon, Popup } from 'UI';
import { Styles } from '../../common';
import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts';
import { LineChart, Line, Legend } from 'recharts';
import { ResponsiveContainer } from 'recharts';
import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period';
import stl from './CustomMetricWidget.css';
import { getChartFormatter, getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper';
import { init, edit, remove, setAlertMetricId, setActiveWidget, updateActiveState } from 'Duck/customMetrics';
import APIClient from 'App/api_client';
import { setShowAlerts } from 'Duck/dashboard';
import CustomMetriLineChart from '../CustomMetriLineChart';
import CustomMetricPieChart from '../CustomMetricPieChart';
import CustomMetricPercentage from '../CustomMetricPercentage';
const customParams = rangeName => {
const params = { density: 70 }
if (rangeName === LAST_24_HOURS) params.density = 70
if (rangeName === LAST_30_MINUTES) params.density = 70
if (rangeName === YESTERDAY) params.density = 70
if (rangeName === LAST_7_DAYS) params.density = 70
// if (rangeName === LAST_24_HOURS) params.density = 70
// if (rangeName === LAST_30_MINUTES) params.density = 70
// if (rangeName === YESTERDAY) params.density = 70
// if (rangeName === LAST_7_DAYS) params.density = 70
return params
}
@ -47,11 +49,10 @@ function CustomMetricWidget(props: Props) {
const colors = Styles.customMetricColors;
const params = customParams(period.rangeName)
const gradientDef = Styles.gradientDef();
const metricParams = { ...params, metricId: metric.metricId, viewType: 'lineChart', startDate: period.start, endDate: period.end }
useEffect(() => {
new APIClient()['post']('/custom_metrics/chart', { ...metricParams, q: metric.name })
new APIClient()['post'](`/custom_metrics/${metricParams.metricId}/chart`, { ...metricParams, q: metric.name })
.then(response => response.json())
.then(({ errors, data }) => {
if (errors) {
@ -78,8 +79,19 @@ function CustomMetricWidget(props: Props) {
if (event) {
const payload = event.activePayload[0].payload;
const timestamp = payload.timestamp;
const { startTimestamp, endTimestamp } = getStartAndEndTimestampsByDensity(timestamp, period.start, period.end, params.density);
props.setActiveWidget({ widget: metric, startTimestamp, endTimestamp, timestamp: payload.timestamp, index })
const periodTimestamps = metric.metricType === 'timeseries' ?
getStartAndEndTimestampsByDensity(timestamp, period.start, period.end, params.density) :
period.toTimestamps();
const activeWidget = {
widget: metric,
period: period,
...periodTimestamps,
timestamp: payload.timestamp,
index,
}
props.setActiveWidget(activeWidget);
}
}
@ -104,49 +116,35 @@ function CustomMetricWidget(props: Props) {
show={ data.length === 0 }
>
<ResponsiveContainer height={ 240 } width="100%">
<LineChart
data={ data }
margin={Styles.chartMargins}
syncId={ showSync ? "domainsErrors_4xx" : undefined }
onClick={clickHandler}
>
<defs>
<linearGradient id="colorCount" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={colors[4]} stopOpacity={ 0.9 } />
<stop offset="95%" stopColor={colors[4]} stopOpacity={ 0.2 } />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" vertical={ false } stroke="#EEEEEE" />
<XAxis
{...Styles.xaxis}
dataKey="time"
interval={params.density/7}
/>
<YAxis
{...Styles.yaxis}
allowDecimals={false}
label={{
...Styles.axisLabelLeft,
value: "Number of Sessions"
}}
/>
<Legend />
<Tooltip {...Styles.tooltip} />
{ seriesMap.map((key, index) => (
<Line
key={key}
name={key}
type="monotone"
dataKey={key}
stroke={colors[index]}
fillOpacity={ 1 }
strokeWidth={ 2 }
strokeOpacity={ 0.8 }
fill="url(#colorCount)"
dot={false}
<>
{metric.viewType === 'lineChart' && (
<CustomMetriLineChart
data={ data }
params={ params }
seriesMap={ seriesMap }
colors={ colors }
onClick={ clickHandler }
/>
))}
</LineChart>
)}
{metric.viewType === 'pieChart' && (
<CustomMetricPieChart
data={ data }
params={ params }
colors={ colors }
onClick={ clickHandler }
/>
)}
{metric.viewType === 'progress' && (
<CustomMetricPercentage
data={ data }
params={ params }
colors={ colors }
onClick={ clickHandler }
/>
)}
</>
</ResponsiveContainer>
</NoContent>
</Loader>

View file

@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import { Loader, NoContent, SegmentSelection, Icon } from 'UI';
import { Styles } from '../../common';
import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Tooltip, LineChart, Line, Legend } from 'recharts';
// import { ResponsiveContainer, XAxis, YAxis, CartesianGrid, Tooltip, LineChart, Line, Legend } from 'recharts';
import Period, { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period';
import stl from './CustomMetricWidgetPreview.css';
import { getChartFormatter } from 'Types/dashboard/helper';
@ -10,10 +10,11 @@ import { remove } from 'Duck/customMetrics';
import DateRange from 'Shared/DateRange';
import { edit } from 'Duck/customMetrics';
import CustomMetriLineChart from '../CustomMetriLineChart';
import CustomMetriPercentage from '../CustomMetriPercentage';
import CustomMetricPercentage from '../CustomMetricPercentage';
import CustomMetricTable from '../CustomMetricTable';
import APIClient from 'App/api_client';
import CustomMetricPieChart from '../CustomMetricPieChart';
const customParams = rangeName => {
const params = { density: 70 }
@ -46,8 +47,9 @@ function CustomMetricWidget(props: Props) {
const params = customParams(period.rangeName)
const gradientDef = Styles.gradientDef();
const metricParams = { ...params, metricId: metric.metricId, viewType: 'lineChart' }
const prevMetricRef = useRef<any>();
const isTimeSeries = metric.metricType === 'timeseries';
const isTable = metric.metricType === 'table';
useEffect(() => {
// Check for title change
@ -95,17 +97,35 @@ function CustomMetricWidget(props: Props) {
<div className="flex items-center mb-4">
<div className="mr-auto font-medium">Preview</div>
<div className="flex items-center">
<SegmentSelection
name="viewType"
className="my-3"
size="extraSmall"
onSelect={ chagneViewType }
value={{ value: metric.viewType }}
list={ [
{ value: 'chart', icon: 'graph-up-arrow' },
{ value: 'percent', icon: 'hash' },
]}
/>
{isTimeSeries && (
<SegmentSelection
name="viewType"
className="my-3"
primary
icons={true}
onSelect={ chagneViewType }
value={{ value: metric.viewType }}
list={ [
{ value: 'lineChart', icon: 'graph-up-arrow' },
{ value: 'progress', icon: 'hash' },
]}
/>
)}
{isTable && (
<SegmentSelection
name="viewType"
className="my-3"
primary={true}
icons={true}
onSelect={ chagneViewType }
value={{ value: metric.viewType }}
list={[
{ value: 'table', icon: 'table' },
{ value: 'pieChart', icon: 'graph-up-arrow' },
]}
/>
)}
<div className="mx-2" />
<span className="mr-1 color-gray-medium">Time Range</span>
<DateRange
@ -125,12 +145,16 @@ function CustomMetricWidget(props: Props) {
size="small"
show={ data.length === 0 }
>
{ metric.metricType === 'timeseries' && (
{ isTimeSeries && (
<>
{ metric.viewType === 'percent' && (
<CustomMetriPercentage data={data} />
{ metric.viewType === 'progress' && (
<CustomMetricPercentage
data={data[0]}
colors={colors}
params={params}
/>
)}
{ metric.viewType === 'chart' && (
{ metric.viewType === 'lineChart' && (
<CustomMetriLineChart
data={data}
seriesMap={seriesMap}
@ -141,9 +165,17 @@ function CustomMetricWidget(props: Props) {
</>
)}
{ metric.metricType === 'table' && (
{ isTable && (
<div className="p-3">
<CustomMetricTable data={data} />
{ metric.viewType === 'table' ? (
<CustomMetricTable data={data} />
) : (
<CustomMetricPieChart
data={data}
colors={colors}
params={params}
/>
)}
</div>
)}
</NoContent>

View file

@ -5,6 +5,7 @@ import CustomMetricWidget from './CustomMetricWidget';
import AlertFormModal from 'App/components/Alerts/AlertFormModal';
import { init as initAlert } from 'Duck/alerts';
import LazyLoad from 'react-lazyload';
import CustomMetrics from 'App/components/shared/CustomMetrics';
interface Props {
fetchList: Function;
@ -22,7 +23,7 @@ function CustomMetricsWidgets(props: Props) {
return (
<>
{list.filter(item => item.active).map((item: any) => (
{list.map((item: any) => (
<LazyLoad>
<CustomMetricWidget
key={item.metricId}
@ -36,6 +37,13 @@ function CustomMetricsWidgets(props: Props) {
</LazyLoad>
))}
{list.size === 0 && (
<div className="flex items-center py-2">
<div className="mr-2">Be proactive by monitoring the metrics you care about the most.</div>
<CustomMetrics />
</div>
)}
<AlertFormModal
showModal={!!activeMetricId}
metricId={activeMetricId}
@ -46,5 +54,5 @@ function CustomMetricsWidgets(props: Props) {
}
export default connect(state => ({
list: state.getIn(['customMetrics', 'list']),
list: state.getIn(['customMetrics', 'list']).filter(item => item.active),
}), { fetchList, initAlert })(CustomMetricsWidgets);

View file

@ -1,5 +1,5 @@
import React from 'react';
import { Form, SegmentSelection, Button, IconButton } from 'UI';
import { Form, Button, IconButton } from 'UI';
import FilterSeries from '../FilterSeries';
import { connect } from 'react-redux';
import { edit as editMetric, save, addSeries, removeSeries, remove } from 'Duck/customMetrics';
@ -8,8 +8,7 @@ import { confirm } from 'UI/Confirmation';
import { toast } from 'react-toastify';
import cn from 'classnames';
import DropdownPlain from '../../DropdownPlain';
import { metricTypes, metricOf } from 'App/constants/filterOptions';
import { metricTypes, metricOf, issueOptions } from 'App/constants/filterOptions';
interface Props {
metric: any;
editMetric: (metric, shouldFetch?) => void;
@ -23,7 +22,7 @@ interface Props {
function CustomMetricForm(props: Props) {
const { metric, loading } = props;
const metricOfOptions = metricOf.filter(i => i.key === metric.metricType);
// const metricOfOptions = metricOf.filter(i => i.key === metric.metricType);
const timeseriesOptions = metricOf.filter(i => i.key === 'timeseries');
const tableOptions = metricOf.filter(i => i.key === 'table');
@ -39,18 +38,28 @@ function CustomMetricForm(props: Props) {
const writeOption = (e, { value, name }) => {
props.editMetric({ [ name ]: value }, false);
if (name === 'metricValue') {
props.editMetric({ metricValue: [value] }, false);
}
if (name === 'metricOf') {
if (value === 'ISSUES') {
props.editMetric({ metricValue: [issueOptions[0].value] }, false);
}
}
if (name === 'metricType') {
if (value === 'timeseries') {
props.editMetric({ metricOf: timeseriesOptions[0].value }, false);
props.editMetric({ metricOf: timeseriesOptions[0].value, viewType: 'lineChart' }, false);
} else if (value === 'table') {
props.editMetric({ metricOf: tableOptions[0].value }, false);
props.editMetric({ metricOf: tableOptions[0].value, viewType: 'table' }, false);
}
}
};
const changeConditionTab = (e, { name, value }) => {
props.editMetric({[ 'viewType' ]: value });
};
// const changeConditionTab = (e, { name, value }) => {
// props.editMetric({[ 'viewType' ]: value });
// };
const save = () => {
props.save(metric).then(() => {
@ -126,38 +135,32 @@ function CustomMetricForm(props: Props) {
</>
)}
{metric.metricOf === 'ISSUES' && (
<>
<span className="mx-3">issue type</span>
<DropdownPlain
name="metricValue"
options={issueOptions}
value={ metric.metricValue[0] }
onChange={ writeOption }
/>
</>
)}
{metric.metricType === 'table' && (
<>
<span className="mx-3">showing</span>
<DropdownPlain
name="viewType"
name="metricFormat"
options={[
{ value: 'sessionCount', text: 'Session Count' },
]}
value={ metric.viewType }
value={ metric.metricFormat }
onChange={ writeOption }
/>
</>
)}
</div>
{/* <div className="flex items-center">
<span className="bg-white p-1 px-2 border rounded" style={{ height: '30px'}}>Timeseries</span>
<span className="mx-2 color-gray-medium">of</span>
<div>
<SegmentSelection
primary
name="viewType"
small={true}
// className="my-3"
onSelect={ changeConditionTab }
value={{ value: metric.viewType }}
list={ [
{ name: 'Session Count', value: 'lineChart' },
{ name: 'Session Percentage', value: 'progress', disabled: true },
]}
/>
</div>
</div> */}
</div>
<div className="form-group">

View file

@ -81,7 +81,7 @@ function FilterSeries(props: Props) {
<div className="color-gray-medium">Add user event or filter to define the series by clicking Add Step.</div>
)}
</div>
<div className="px-5 border-t h-12 flex items-center">
<div className="px-6 border-t h-12 flex items-center -mx-4">
<FilterSelection
filter={undefined}
onFilterClick={onAddFilter}

View file

@ -5,7 +5,6 @@ import stl from './SessionListModal.css';
import { connect } from 'react-redux';
import { fetchSessionList, setActiveWidget } from 'Duck/customMetrics';
import { DateTime } from 'luxon';
interface Props {
loading: boolean;
list: any;
@ -57,9 +56,9 @@ function SessionListModal(props: Props) {
const writeOption = (e, { name, value }) => setActiveSeries(value);
const filteredSessions = getListSessionsBySeries(activeSeries);
const startTime = DateTime.fromMillis(activeWidget.startTimestamp).toFormat('LLL dd, yyyy HH:mm a');
const endTime = DateTime.fromMillis(activeWidget.endTimestamp).toFormat('LLL dd, yyyy HH:mm a');
return (
<SlideModal
title={ activeWidget && (

View file

@ -9,10 +9,11 @@ interface Props {
icon?: string;
direction?: string;
value: any;
multiple?: boolean;
}
export default function DropdownPlain(props: Props) {
const { name = "sort", value, options, icon = "chevron-down", direction = "right" } = props;
const { name = "sort", value, options, icon = "chevron-down", direction = "right", multiple = false } = props;
return (
<div>
<Dropdown
@ -24,6 +25,7 @@ export default function DropdownPlain(props: Props) {
onChange={ props.onChange }
// floating
scrolling
multiple={ multiple }
selectOnBlur={ false }
// defaultValue={ value }
icon={ icon ? <Icon name="chevron-down" color="gray-dark" size="14" className={stl.dropdownIcon} /> : null }

View file

@ -100,18 +100,20 @@ const FilterDropdown = props => {
</div>
)}
{showDropdown && (
<div className="absolute mt-2 bg-white rounded border p-3 z-20" id="filter-dropdown" style={{ width: '200px'}}>
<div className="font-medium mb-2 tracking-widest color-gray-dark">SELECT FILTER</div>
{filterKeys.filter(f => !filterKeyMaps.includes(f.key)).map(f => (
<div
key={f.key}
onClick={() => onFilterKeySelect(f.key)}
className={cn(stl.filterItem, 'py-3 -mx-3 px-3 flex items-center cursor-pointer')}
>
<Icon name={f.icon} size="16" />
<span className="ml-3 capitalize">{f.name}</span>
</div>
))}
<div className="absolute mt-2 bg-white rounded border z-20" id="filter-dropdown" style={{ width: '200px'}}>
<div className="font-medium mb-2 tracking-widest color-gray-dark p-3">SELECT FILTER</div>
<div className="px-3" style={{ maxHeight: '200px', overflowY: 'auto'}} >
{filterKeys.filter(f => !filterKeyMaps.includes(f.key)).map(f => (
<div
key={f.key}
onClick={() => onFilterKeySelect(f.key)}
className={cn(stl.filterItem, 'py-3 -mx-3 px-3 flex items-center cursor-pointer')}
>
<Icon name={f.icon} size="16" />
<span className="ml-3 capitalize">{f.name}</span>
</div>
))}
</div>
</div>
)}
{filterKey && (

View file

@ -32,7 +32,7 @@ function FilterList(props: Props) {
<div className="mr-2 color-gray-medium text-sm" style={{ textDecoration: 'underline dotted'}}>
<Popup
trigger={<div>Events Order</div>}
content={ `Events Order` }
content={ `Select the operator to be applied between events in your search.` }
size="tiny"
inverted
position="top center"

View file

@ -9,13 +9,14 @@ class SegmentSelection extends React.Component {
}
render() {
const { className, list, small = false, extraSmall = false, primary = false, size = "normal" } = this.props;
const { className, list, small = false, extraSmall = false, primary = false, size = "normal", icons = false } = this.props;
return (
<div className={ cn(styles.wrapper, {
[styles.primary] : primary,
[styles.small] : size === 'small' || small,
[styles.extraSmall] : size === 'extraSmall' || extraSmall,
[styles.icons] : icons === true,
}, className) }
>
{ list.map(item => (
@ -27,7 +28,7 @@ class SegmentSelection extends React.Component {
data-active={ this.props.value && this.props.value.value === item.value }
onClick={ () => !item.disabled && this.setActiveItem(item) }
>
{ item.icon && <Icon name={ item.icon } size={size === "extraSmall" ? 12 : 20} marginRight={ item.name ? "10" : "" } /> }
{ item.icon && <Icon name={ item.icon } size={(size === "extraSmall" || icons) ? 14 : 20} marginRight={ item.name ? "10" : "" } /> }
<div>{ item.name }</div>
</div>
}

View file

@ -54,9 +54,15 @@
color: $teal;
background-color: white;
border-right: solid thin $teal;
& svg {
fill: $teal !important;
}
&[data-active=true] {
background-color: $teal;
color: white;
& svg {
fill: white !important;
}
}
}
}
@ -66,6 +72,11 @@
}
.extraSmall .item {
padding: 6px !important;
padding: 0 4px !important;
font-size: 12px;
}
.icons .item {
padding: 4px !important;
font-size: 12px;
}

View file

@ -69,6 +69,21 @@ export const metricOf = [
{ text: 'URL', value: 'VISITED_URL', key: 'table' },
]
export const issueOptions = [
{ text: 'Click Rage', value: 'click_rage' },
{ text: 'Dead Click', value: 'dead_click' },
{ text: 'Excessive Scrolling', value: 'excessive_scrolling' },
{ text: 'Bad Request', value: 'bad_request' },
{ text: 'Missing Resource', value: 'missing_resource' },
{ text: 'Memory', value: 'memory' },
{ text: 'CPU', value: 'cpu' },
{ text: 'Slow Resource', value: 'slow_resource' },
{ text: 'Slow Page Load', value: 'slow_page_load' },
{ text: 'Crash', value: 'crash' },
{ text: 'Custom', value: 'custom' },
{ text: 'JS Exception', value: 'js_exception' },
]
export default {
options,
baseOperators,
@ -79,4 +94,5 @@ export default {
getOperatorsByKeys,
metricTypes,
metricOf,
issueOptions,
}

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-table" viewBox="0 0 16 16">
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm15 2h-4v3h4V4zm0 4h-4v3h4V8zm0 4h-4v3h3a1 1 0 0 0 1-1v-2zm-5 3v-3H6v3h4zm-5 0v-3H1v2a1 1 0 0 0 1 1h3zm-4-4h4V8H1v3zm0-4h4V4H1v3zm5-3v3h4V4H6zm4 4H6v3h4V8z"/>
</svg>

After

Width:  |  Height:  |  Size: 371 B

View file

@ -103,5 +103,11 @@ export default Record({
endTimestamp: this.end,
};
},
toTimestampstwo() {
return {
startTimestamp: this.start / 1000,
endTimestamp: this.end / 1000,
};
},
}
});

View file

@ -29,7 +29,9 @@ export default Record({
name: 'Series',
metricType: 'table',
metricOf: 'USERID',
viewType: 'lineChart',
metricValue: ['sessionCount'],
metricFormat: 'sessionCount',
viewType: 'table',
series: List(),
isPublic: true,
startDate: '',

View file

@ -6,21 +6,6 @@ import { capitalize } from 'App/utils';
const countryOptions = Object.keys(countries).map(i => ({ text: countries[i], value: i }));
const containsFilters = [{ key: 'contains', text: 'contains', value: 'contains' }]
const ISSUE_OPTIONS = [
{ text: 'Click Rage', value: 'click_rage' },
{ text: 'Dead Click', value: 'dead_click' },
{ text: 'Excessive Scrolling', value: 'excessive_scrolling' },
{ text: 'Bad Request', value: 'bad_request' },
{ text: 'Missing Resource', value: 'missing_resource' },
{ text: 'Memory', value: 'memory' },
{ text: 'CPU', value: 'cpu' },
{ text: 'Slow Resource', value: 'slow_resource' },
{ text: 'Slow Page Load', value: 'slow_page_load' },
{ text: 'Crash', value: 'crash' },
{ text: 'Custom', value: 'custom' },
{ text: 'JS Exception', value: 'js_exception' },
]
export const filtersMap = {
// EVENTS
[FilterKey.CLICK]: { key: FilterKey.CLICK, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Click', operator: 'on', operatorOptions: filterOptions.targetOperators, icon: 'filters/click', isEvent: true },
@ -59,7 +44,7 @@ export const filtersMap = {
[FilterKey.AVG_CPU_LOAD]: { key: FilterKey.AVG_CPU_LOAD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg CPU Load', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/cpu-load', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators },
[FilterKey.AVG_MEMORY_USAGE]: { key: FilterKey.AVG_MEMORY_USAGE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg Memory Usage', operator: 'isAny', operatorOptions: filterOptions.stringOperators, source: [], icon: 'filters/memory-load', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators },
[FilterKey.FETCH_FAILED]: { key: FilterKey.FETCH_FAILED, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Failed Request', operator: 'isAny', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch-failed', isEvent: true },
[FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/click', options: ISSUE_OPTIONS },
[FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/click', options: filterOptions.issueOptions },
}
export const liveFiltersMap = {