feat(ui) - custom metrics

This commit is contained in:
Shekar Siri 2022-01-26 00:24:08 +05:30
parent 45db3fa1d4
commit 2008d3dc2f
14 changed files with 193 additions and 147 deletions

View file

@ -5,20 +5,24 @@ import { fetchList as fetchFunnelsList } from 'Duck/funnels';
import DateRangeDropdown from 'Shared/DateRangeDropdown';
@connect(state => ({
rangeValue: state.getIn([ 'filters', 'appliedFilter', 'rangeValue' ]),
startDate: state.getIn([ 'filters', 'appliedFilter', 'startDate' ]),
endDate: state.getIn([ 'filters', 'appliedFilter', 'endDate' ]),
filter: state.getIn([ 'search', 'instance' ]),
// rangeValue: state.getIn([ 'search', 'instance', 'rangeValue' ]),
// startDate: state.getIn([ 'search', 'instance', 'startDate' ]),
// endDate: state.getIn([ 'search', 'instance', 'endDate' ]),
}), {
applyFilter, fetchFunnelsList
})
export default class DateRange extends React.PureComponent {
onDateChange = (e) => {
console.log('onDateChange', e);
this.props.fetchFunnelsList(e.rangeValue)
this.props.applyFilter(e)
}
render() {
const { startDate, endDate, rangeValue, className } = this.props;
const { filter: { rangeValue, startDate, endDate }, className } = this.props;
// const { startDate, endDate, rangeValue, className } = this.props;
return (
<DateRangeDropdown
button

View file

@ -11,7 +11,7 @@ interface Props {
}
function FilterList(props: Props) {
const { filter } = props;
const filters = filter.filters.toJS()
const filters = filter.filters;
const hasEvents = filter.filters.filter(i => i.isEvent).size > 0;
const hasFilters = filter.filters.filter(i => !i.isEvent).size > 0;

View file

@ -10,9 +10,9 @@ function FilterModal(props: Props) {
const { filters, onFilterClick = () => null } = props;
return (
<div className="border p-3" style={{ width: '490px', height: '400px', overflowY: 'auto'}}>
<div className="grid grid-flow-row-dense grid-cols-2">
<div className="" style={{ columns: "100px 2" }}>
{filters && Object.keys(filters).map((key) => (
<div className="p-3">
<div className="p-3 aspect-w-1">
<div className="uppercase font-medium mb-1">{key}</div>
<div>
{filters[key].map((filter: any) => (

View file

@ -53,7 +53,6 @@ function FilterValue(props: Props) {
const renderValueFiled = (value, valueIndex) => {
switch(filter.type) {
case FilterType.ISSUE:
case FilterType.DROPDOWN:
return (
<FilterValueDropdown
@ -63,6 +62,7 @@ function FilterValue(props: Props) {
onChange={(e, { name, value }) => onSelect(e, { value }, valueIndex)}
/>
)
case FilterType.ISSUE:
case FilterType.MULTIPLE_DROPDOWN:
return (
<FilterValueDropdown
@ -111,7 +111,6 @@ function FilterValue(props: Props) {
)
}
}
console.log('durationValues', durationValues)
return (
<div className="grid grid-cols-3 gap-3">

View file

@ -1,3 +1,38 @@
.wrapper {
border: solid thin $gray-light !important;
border-radius: 3px;
background-color: $gray-lightest !important;
display: flex;
align-items: center;
height: 30px;
& .right {
height: 28px;
display: flex;
align-items: stretch;
padding: 0;
background-color: $gray-lightest;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
& div {
/* background-color: red; */
border-left: solid thin $gray-light !important;
width: 28px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
&:last-child {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
&:hover {
background-color: $gray-light;
}
}
}
}
.operatorDropdown {
font-weight: 400;
height: 30px;
@ -8,9 +43,9 @@
padding: 0 8px !important;
font-size: 13px;
/* background-color: rgba(255, 255, 255, 0.8) !important; */
background-color: $gray-lightest !important;
border: solid thin rgba(34, 36, 38, 0.15) !important;
border-radius: 4px !important;
/* background-color: $gray-lightest !important; */
/* border: solid thin rgba(34, 36, 38, 0.15) !important; */
/* border-radius: 4px !important; */
color: $gray-darkest !important;
font-size: 14px !important;
&.ui.basic.button {

View file

@ -12,22 +12,35 @@ interface Props {
options: any[];
search?: boolean;
multiple?: boolean;
showCloseButton?: boolean;
showOrButton?: boolean;
onRemoveValue?: () => void;
onAddValue?: () => void;
}
function FilterValueDropdown(props: Props) {
const { multiple = false, search = false, options, onChange, value, className = '' } = props;
const { multiple = false, search = false, options, onChange, value, className = '', showCloseButton = true, showOrButton = true } = props;
// const options = []
return (
<Dropdown
search={search}
className={ cn(stl.operatorDropdown, className) }
options={ options }
name="issue_type"
value={ value }
onChange={ onChange }
placeholder="Select"
icon={ <Icon className="ml-5" name="chevron-down" size="12" /> }
/>
<div className={stl.wrapper}>
<Dropdown
search={search}
className={ cn(stl.operatorDropdown, className) }
options={ options }
name="issue_type"
value={ value }
onChange={ onChange }
placeholder="Select"
icon={ <Icon className="ml-5" name="chevron-down" size="12" /> }
/>
<div
className={stl.right}
// onClick={showOrButton ? onRemoveValue : onAddValue}
>
{ showCloseButton && <div onClick={props.onRemoveValue}><Icon name="close" size="18" /></div> }
{ showOrButton && <div onClick={props.onAddValue} className="color-teal"><span className="px-1">or</span></div> }
</div>
</div>
);
}

View file

@ -1,6 +1,6 @@
import React from 'react';
import { connect } from 'react-redux';
import { edit, save } from 'Duck/filters';
import { edit, save } from 'Duck/search';
import { Button, Modal, Form, Icon, Checkbox } from 'UI';
import stl from './SaveSearchModal.css';
@ -72,7 +72,7 @@ function SaveSearchModal(props: Props) {
}
export default connect(state => ({
filter: state.getIn(['filters', 'instance']),
filter: state.getIn(['search', 'instance']),
loading: state.getIn([ 'filters', 'saveRequest', 'loading' ]) ||
state.getIn([ 'filters', 'updateRequest', 'loading' ]),
}), { edit, save })(SaveSearchModal);

View file

@ -15,18 +15,15 @@ function SessionSearch(props) {
const onAddFilter = (filter) => {
filter.value = [""]
const newFilters = appliedFilter.filter.filters.concat(filter);
const newFilters = appliedFilter.filters.concat(filter);
props.edit({
...appliedFilter,
filter: {
...appliedFilter.filter,
filters: newFilters,
}
});
}
const onUpdateFilter = (filterIndex, filter) => {
const newFilters = appliedFilter.filter.filters.map((_filter, i) => {
const newFilters = appliedFilter.filters.map((_filter, i) => {
if (i === filterIndex) {
return filter;
} else {
@ -35,45 +32,30 @@ function SessionSearch(props) {
});
props.edit({
...appliedFilter.toData(),
filter: {
...appliedFilter.filter,
filters: newFilters,
}
});
}
const onRemoveFilter = (filterIndex) => {
const newFilters = appliedFilter.filter.filters.filter((_filter, i) => {
const newFilters = appliedFilter.filters.filter((_filter, i) => {
return i !== filterIndex;
});
props.edit({
...appliedFilter,
filter: {
...appliedFilter.filter,
filters: newFilters,
}
filters: newFilters,
});
}
const onChangeEventsOrder = (e, { name, value }) => {
props.edit({
...appliedFilter.toData(),
filter: {
...appliedFilter.filter.toData(),
eventsOrder: value,
}
eventsOrder: value,
});
}
const clearSearch = () => {
props.edit({
...appliedFilter.toData(),
filter: {
...appliedFilter.filter.toData(),
filters: [],
}
});
}
@ -83,7 +65,7 @@ function SessionSearch(props) {
<div className="p-5">
<FilterList
// filters={appliedFilter.filter.filters.toJS()}
filter={appliedFilter.filter}
filter={appliedFilter}
onUpdateFilter={onUpdateFilter}
onRemoveFilter={onRemoveFilter}
onChangeEventsOrder={onChangeEventsOrder}

View file

@ -1,16 +1,11 @@
import { List, Map } from 'immutable';
// import { clean as cleanParams } from 'App/api_client';
import ErrorInfo, { RESOLVED, UNRESOLVED, IGNORED } from 'Types/errorInfo';
import CustomMetric, { FilterSeries } from 'Types/customMetric'
import { createFetch, fetchListType, fetchType, saveType, removeType, editType, createRemove, createEdit } from './funcTools/crud';
// import { createEdit, createInit } from './funcTools/crud';
import { createRequestReducer, ROOT_KEY } from './funcTools/request';
import { array, request, success, failure, createListUpdater, mergeReducers } from './funcTools/tools';
import Filter from 'Types/filter';
// import filter from 'core-js/fn/array/filter';
// import NewFilter from 'Types/filter/newFilter';
// import Event from 'Types/filter/event';
// import CustomFilter from 'Types/filter/customFilter';
import SavedFilter from 'Types/filter/savedFilter';
import { errors as errorsRoute, isRoute } from "App/routes";
import { fetchList as fetchSessionList } from './sessions';
import { fetchList as fetchErrorsList } from './errors';
@ -41,26 +36,25 @@ function chartWrapper(chart = []) {
const initialState = Map({
list: List(),
alertMetricId: null,
// instance: null,
instance: FilterSeries({ filter: new Filter({ filters: [] }) }),
instance: new Filter({ filters: [] }),
savedFilter: new SavedFilter({ filters: [] }),
});
// Metric - Series - [] - filters
function reducer(state = initialState, action = {}) {
switch (action.type) {
case EDIT:
return state.set('instance', FilterSeries(action.instance));
return state.mergeIn(['instance'], action.instance);
case APPLY:
return action.fromUrl
? state.set('instance',
Filter(action.filter)
// .set('events', state.getIn([ 'instance', 'events' ]))
)
: state.mergeIn([ 'instance', 'filter' ], action.filter);
: state.mergeIn(['instance'], action.filter);
case success(SAVE):
return state.set([ 'instance' ], CustomMetric(action.data));
return state.mergeIn([ 'instance' ], action.data);
case success(REMOVE):
console.log('action', action)
return state.update('list', list => list.filter(item => item.metricId !== action.id));
case success(FETCH):
return state.set("instance", ErrorInfo(action.data));
@ -79,9 +73,9 @@ export default mergeReducers(
}),
);
const filterMap = ({value, type, key, operator, source, custom, isEvent }) => ({
value: Array.isArray(value) ? value: [value],
// value: Array.isArray(value) ? value: [value],
value: value.filter(i => i !== '' && i !== null),
custom,
type: key,
key, operator,
@ -91,7 +85,7 @@ const filterMap = ({value, type, key, operator, source, custom, isEvent }) => ({
const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => {
dispatch(actionCreator(...args));
const filter = getState().getIn([ 'search', 'instance', 'filter' ]).toData();
const filter = getState().getIn([ 'search', 'instance']).toData();
filter.filters = filter.filters.map(filterMap);
filter.isNew = true // TODO remove this line
@ -130,7 +124,11 @@ export function fetch(id) {
export function save(instance) {
return {
types: SAVE.array,
call: client => client.post( `/${ name }s`, instance.toSaveData()),
call: client => client.post('/saved_search', {
name: instance.name,
filter: instance.filter.toSaveData(),
}),
instance,
};
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M228.5 511.8l-25-7.1c-3.2-.9-5-4.2-4.1-7.4L340.1 4.4c.9-3.2 4.2-5 7.4-4.1l25 7.1c3.2.9 5 4.2 4.1 7.4L235.9 507.6c-.9 3.2-4.3 5.1-7.4 4.2zm-75.6-125.3l18.5-20.9c1.9-2.1 1.6-5.3-.5-7.1L49.9 256l121-102.5c2.1-1.8 2.4-5 .5-7.1l-18.5-20.9c-1.8-2.1-5-2.3-7.1-.4L1.7 252.3c-2.3 2-2.3 5.5 0 7.5L145.8 387c2.1 1.8 5.3 1.6 7.1-.5zm277.3.4l144.1-127.2c2.3-2 2.3-5.5 0-7.5L430.2 125.1c-2.1-1.8-5.2-1.6-7.1.4l-18.5 20.9c-1.9 2.1-1.6 5.3.5 7.1l121 102.5-121 102.5c-2.1 1.8-2.4 5-.5 7.1l18.5 20.9c1.8 2.1 5 2.3 7.1.4z"/></svg>

After

Width:  |  Height:  |  Size: 582 B

View file

@ -1,11 +1,6 @@
import Record from 'Types/Record';
import { List } from 'immutable';
// import { DateTime } from 'luxon';
// import { validateEmail, validateName } from 'App/validate';
import Filter from 'Types/filter';
import NewFilter from 'Types/filter';
// import { Event } from 'Types/filter';
// import CustomFilter from 'Types/filter/customFilter';
export const FilterSeries = Record({
seriesId: undefined,

View file

@ -35,8 +35,8 @@ export default Record({
startDate,
endDate,
sort: '',
order: '',
sort: 'startTs',
order: 'desc',
viewed: undefined,
consoleLogCount: undefined,
@ -49,6 +49,24 @@ export default Record({
}, {
idKey: 'searchId',
methods: {
toSaveData() {
const js = this.toJS();
js.filters = js.filters.map(filter => {
filter.type = filter.key
delete filter.category
delete filter.icon
delete filter.operatorOptions
delete filter._key
delete filter.key
return filter;
});
delete js.createdAt;
delete js.key;
delete js._key;
return js;
},
toData() {
const js = this.toJS();
js.filters = js.filters.map(filter => {

View file

@ -1,3 +1,13 @@
export enum FilterCategory {
INTERACTIONS = "Interactions",
GEAR = "Gear",
RECORDING_ATTRIBUTES = "Recording Attributes",
JAVASCRIPT = "Javascript",
USER = "User",
METADATA = "Metadata",
PERFORMANCE = "Performance",
};
export enum FilterType {
ISSUE = "ISSUE",
BOOLEAN = "BOOLEAN",
@ -48,4 +58,5 @@ export enum FilterKey {
TTFB = "TTFB",
AVG_CPU_LOAD = "AVG_CPU_LOAD",
AVG_MEMORY_USAGE = "AVG_MEMORY_USAGE",
FETCH_FAILED = "FETCH_FAILED",
}

View file

@ -1,58 +1,27 @@
import Record from 'Types/Record';
import { FilterType, FilterKey } from './filterType'
import { FilterType, FilterKey, FilterCategory } from './filterType'
import { countries, platformOptions } from 'App/constants';
const countryOptions = Object.keys(countries).map(i => ({ text: countries[i], value: i }));
export const CLICK = 'CLICK';
export const INPUT = 'INPUT';
export const LOCATION = 'LOCATION';
export const VIEW = 'VIEW_IOS';
export const CONSOLE = 'ERROR';
export const METADATA = 'METADATA';
export const CUSTOM = 'CUSTOM';
export const URL = 'URL';
export const CLICK_RAGE = 'CLICKRAGE';
export const USER_BROWSER = 'USERBROWSER';
export const USER_OS = 'USEROS';
export const USER_COUNTRY = 'USERCOUNTRY';
export const USER_DEVICE = 'USERDEVICE';
export const PLATFORM = 'PLATFORM';
export const DURATION = 'DURATION';
export const REFERRER = 'REFERRER';
export const ERROR = 'ERROR';
export const MISSING_RESOURCE = 'MISSINGRESOURCE';
export const SLOW_SESSION = 'SLOWSESSION';
export const JOURNEY = 'JOUNRNEY';
export const FETCH = 'REQUEST';
export const GRAPHQL = 'GRAPHQL';
export const STATEACTION = 'STATEACTION';
export const REVID = 'REVID';
export const USERANONYMOUSID = 'USERANONYMOUSID';
export const USERID = 'USERID';
export const ISSUE = 'ISSUE';
export const EVENTS_COUNT = 'EVENTS_COUNT';
export const UTM_SOURCE = 'UTM_SOURCE';
export const UTM_MEDIUM = 'UTM_MEDIUM';
export const UTM_CAMPAIGN = 'UTM_CAMPAIGN';
export const DOM_COMPLETE = 'DOM_COMPLETE';
export const LARGEST_CONTENTFUL_PAINT_TIME = 'LARGEST_CONTENTFUL_PAINT_TIME';
export const TIME_BETWEEN_EVENTS = 'TIME_BETWEEN_EVENTS';
export const TTFB = 'TTFB';
export const AVG_CPU_LOAD = 'AVG_CPU_LOAD';
export const AVG_MEMORY_USAGE = 'AVG_MEMORY_USAGE';
const ISSUE_OPTIONS = [
{ text: 'Click Range', 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' },
]
const filterKeys = ['is', 'isNot'];
const stringFilterKeys = ['is', 'isNot', 'contains', 'startsWith', 'endsWith'];
const targetFilterKeys = ['on', 'notOn'];
const stringFilterKeys = ['is', 'isNot', 'contains', 'startsWith', 'endsWith', 'notContains'];
const targetFilterKeys = ['on', 'notOn', 'onAny'];
const signUpStatusFilterKeys = ['isSignedUp', 'notSignedUp'];
const rangeFilterKeys = ['before', 'after', 'on', 'inRange', 'notInRange', 'withInLast', 'notWithInLast'];
@ -78,9 +47,9 @@ const options = [
text: 'contains',
value: 'contains'
}, {
key: 'doesNotContain',
text: 'does not contain',
value: 'doesNotContain'
key: 'notContains',
text: 'not contains',
value: 'notContains'
}, {
key: 'hasAnyValue',
text: 'has any value',
@ -172,9 +141,9 @@ const options = [
{
key: 'onAnything',
text: 'on anything',
value: 'onAnything'
key: 'onAny',
text: 'on any',
value: 'onAny'
}
];
@ -186,41 +155,59 @@ export const booleanOptions = [
{ key: 'false', text: 'false', value: 'false' },
]
export const customOperators = [
{ key: '=', text: '=', value: '=' },
{ key: '<', text: '<', value: '<' },
{ key: '>', text: '>', value: '>' },
{ key: '<=', text: '<=', value: '<=' },
{ key: '>=', text: '>=', value: '>=' },
]
export const filtersMap = {
[FilterKey.CLICK]: { key: FilterKey.CLICK, type: FilterType.MULTIPLE, category: 'interactions', label: 'Click', operator: 'on', operatorOptions: targetFilterOptions, icon: 'filters/click', isEvent: true },
[FilterKey.INPUT]: { key: FilterKey.INPUT, type: FilterType.MULTIPLE, category: 'interactions', label: 'Input', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/input', isEvent: true },
[FilterKey.LOCATION]: { key: FilterKey.LOCATION, type: FilterType.MULTIPLE, category: 'interactions', label: 'Page', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/location', isEvent: true },
[FilterKey.CLICK]: { key: FilterKey.CLICK, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Click', operator: 'on', operatorOptions: targetFilterOptions, icon: 'filters/click', isEvent: true },
[FilterKey.INPUT]: { key: FilterKey.INPUT, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Input', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/input', isEvent: true },
[FilterKey.LOCATION]: { key: FilterKey.LOCATION, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Page', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/location', isEvent: true },
[FilterKey.CUSTOM]: { key: FilterKey.CUSTOM, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Custom Events', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/custom', isEvent: true },
[FilterKey.FETCH]: { key: FilterKey.FETCH, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Fetch', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/fetch', isEvent: true },
[FilterKey.GRAPHQL]: { key: FilterKey.GRAPHQL, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'GraphQL', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/graphql', isEvent: true },
[FilterKey.STATEACTION]: { key: FilterKey.STATEACTION, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'StateAction', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/state-action', isEvent: true },
[FilterKey.ERROR]: { key: FilterKey.ERROR, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Error', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/error', isEvent: true },
// [FilterKey.METADATA]: { key: FilterKey.METADATA, type: FilterType.MULTIPLE, category: FilterCategory.METADATA, label: 'Metadata', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/metadata', isEvent: true },
[FilterKey.USER_OS]: { key: FilterKey.USER_OS, type: FilterType.MULTIPLE, category: 'gear', label: 'User OS', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/os' },
[FilterKey.USER_BROWSER]: { key: FilterKey.USER_BROWSER, type: FilterType.MULTIPLE, category: 'gear', label: 'User Browser', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/browser' },
[FilterKey.USER_DEVICE]: { key: FilterKey.USER_DEVICE, type: FilterType.MULTIPLE, category: 'gear', label: 'User Device', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/device' },
[FilterKey.PLATFORM]: { key: FilterKey.PLATFORM, type: FilterType.MULTIPLE_DROPDOWN, category: 'gear', label: 'Platform', operator: 'is', operatorOptions: filterOptions, icon: 'filters/platform', options: platformOptions },
[FilterKey.REVID]: { key: FilterKey.REVID, type: FilterType.MULTIPLE, category: 'gear', label: 'RevId', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/rev-id' },
[FilterKey.USER_OS]: { key: FilterKey.USER_OS, type: FilterType.MULTIPLE, category: FilterCategory.GEAR, label: 'User OS', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/os' },
[FilterKey.USER_BROWSER]: { key: FilterKey.USER_BROWSER, type: FilterType.MULTIPLE, category: FilterCategory.GEAR, label: 'User Browser', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/browser' },
[FilterKey.USER_DEVICE]: { key: FilterKey.USER_DEVICE, type: FilterType.MULTIPLE, category: FilterCategory.GEAR, label: 'User Device', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/device' },
[FilterKey.PLATFORM]: { key: FilterKey.PLATFORM, type: FilterType.MULTIPLE_DROPDOWN, category: FilterCategory.GEAR, label: 'Platform', operator: 'is', operatorOptions: filterOptions, icon: 'filters/platform', options: platformOptions },
[FilterKey.REVID]: { key: FilterKey.REVID, type: FilterType.MULTIPLE, category: FilterCategory.GEAR, label: 'RevId', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/rev-id' },
[FilterKey.REFERRER]: { key: FilterKey.REFERRER, type: FilterType.MULTIPLE, category: 'recording_attributes', label: 'Referrer', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/referrer' },
[FilterKey.DURATION]: { key: FilterKey.DURATION, type: FilterType.DURATION, category: 'recording_attributes', label: 'Duration', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/duration' },
[FilterKey.USER_COUNTRY]: { key: FilterKey.USER_COUNTRY, type: FilterType.DROPDOWN, category: 'recording_attributes', label: 'User Country', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/country', options: countryOptions },
[FilterKey.REFERRER]: { key: FilterKey.REFERRER, type: FilterType.MULTIPLE, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'Referrer', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/referrer' },
[FilterKey.DURATION]: { key: FilterKey.DURATION, type: FilterType.DURATION, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'Duration', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/duration' },
[FilterKey.USER_COUNTRY]: { key: FilterKey.USER_COUNTRY, type: FilterType.DROPDOWN, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'User Country', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/country', options: countryOptions },
[FilterKey.CONSOLE]: { key: FilterKey.CONSOLE, type: FilterType.MULTIPLE, category: 'javascript', label: 'Console', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/console' },
[FilterKey.ERROR]: { key: FilterKey.ERROR, type: FilterType.MULTIPLE, category: 'javascript', label: 'Error', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/error' },
[FilterKey.FETCH]: { key: FilterKey.FETCH, type: FilterType.MULTIPLE, category: 'javascript', label: 'Fetch', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/fetch' },
[FilterKey.GRAPHQL]: { key: FilterKey.GRAPHQL, type: FilterType.MULTIPLE, category: 'javascript', label: 'GraphQL', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/graphql' },
[FilterKey.STATEACTION]: { key: FilterKey.STATEACTION, type: FilterType.MULTIPLE, category: 'javascript', label: 'StateAction', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/state-action' },
[FilterKey.USERID]: { key: FilterKey.USERID, type: FilterType.MULTIPLE, category: 'user', label: 'UserId', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/userid' },
[FilterKey.USERANONYMOUSID]: { key: FilterKey.USERANONYMOUSID, type: FilterType.MULTIPLE, category: 'user', label: 'UserAnonymousId', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/userid' },
[FilterKey.CONSOLE]: { key: FilterKey.CONSOLE, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Console', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/console' },
[FilterKey.USERID]: { key: FilterKey.USERID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'UserId', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/userid' },
[FilterKey.USERANONYMOUSID]: { key: FilterKey.USERANONYMOUSID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'UserAnonymousId', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/userid' },
[FilterKey.DOM_COMPLETE]: { key: FilterKey.DOM_COMPLETE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'DOM Complete', operator: 'is', operatorOptions: stringFilterOptions, sourcesourceOperatorOptions: customOperators, source: [], icon: 'filters/click', isEvent: true },
[FilterKey.LARGEST_CONTENTFUL_PAINT_TIME]: { key: FilterKey.LARGEST_CONTENTFUL_PAINT_TIME, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Largest Contentful Paint Time', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click', isEvent: true },
// [FilterKey.TIME_BETWEEN_EVENTS]: { key: FilterKey.TIME_BETWEEN_EVENTS, type: FilterType.NUMBER, category: FilterCategory.PERFORMANCE, label: 'Time Between Events', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click' },
[FilterKey.TTFB]: { key: FilterKey.TTFB, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Time to First Byte', operator: 'is', operatorOptions: stringFilterOptions, sourceOperatorOptions: customOperators, source: [], icon: 'filters/click', isEvent: true },
[FilterKey.AVG_CPU_LOAD]: { key: FilterKey.AVG_CPU_LOAD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg CPU Load', operator: 'is', operatorOptions: stringFilterOptions, sourceOperatorOptions: customOperators, source: [], icon: 'filters/click', isEvent: true },
[FilterKey.AVG_MEMORY_USAGE]: { key: FilterKey.AVG_MEMORY_USAGE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg Memory Usage', operator: 'is', operatorOptions: stringFilterOptions, sourceOperatorOptions: customOperators, source: [], icon: 'filters/click', isEvent: true },
[FilterKey.FETCH_FAILED]: { key: FilterKey.AVG_MEMORY_USAGE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Fetch Failed', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click', isEvent: true },
// [FilterKey.DOM_COMPLETE]: { key: FilterKey.DOM_COMPLETE, type: FilterType.MULTIPLE, category: 'new', label: 'DOM Complete', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click' },
// [FilterKey.LARGEST_CONTENTFUL_PAINT_TIME]: { key: FilterKey.LARGEST_CONTENTFUL_PAINT_TIME, type: FilterType.NUMBER, category: 'new', label: 'Largest Contentful Paint Time', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click' },
// [FilterKey.TIME_BETWEEN_EVENTS]: { key: FilterKey.TIME_BETWEEN_EVENTS, type: FilterType.NUMBER, category: 'new', label: 'Time Between Events', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click' },
// [FilterKey.TTFB]: { key: FilterKey.TTFB, type: 'time', category: 'new', label: 'TTFB', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click' },
// [FilterKey.AVG_CPU_LOAD]: { key: FilterKey.AVG_CPU_LOAD, type: FilterType.NUMBER, category: 'new', label: 'Avg CPU Load', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click' },
// [FilterKey.AVG_MEMORY_USAGE]: { key: FilterKey.AVG_MEMORY_USAGE, type: FilterType.NUMBER, category: 'new', label: 'Avg Memory Usage', operator: 'is', operatorOptions: stringFilterOptions, icon: 'filters/click' },
// [FilterKey.SLOW_SESSION]: { key: FilterKey.SLOW_SESSION, type: FilterType.BOOLEAN, category: 'new', label: 'Slow Session', operator: 'true', operatorOptions: [{ key: 'true', text: 'true', value: 'true' }], icon: 'filters/click' },
// [FilterKey.MISSING_RESOURCE]: { key: FilterKey.MISSING_RESOURCE, type: FilterType.BOOLEAN, category: 'new', label: 'Missing Resource', operator: 'true', operatorOptions: [{ key: 'inImages', text: 'in images', value: 'true' }], icon: 'filters/click' },
// [FilterKey.CLICK_RAGE]: { key: FilterKey.CLICK_RAGE, type: FilterType.BOOLEAN, category: 'new', label: 'Click Rage', operator: 'onAnything', operatorOptions: [{ key: 'onAnything', text: 'on anything', value: 'true' }], icon: 'filters/click' },
[FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: 'javascript', label: 'Issue', operator: 'onAnything', operatorOptions: filterOptions, icon: 'filters/click', options: ISSUE_OPTIONS },
[FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions, icon: 'filters/click', options: ISSUE_OPTIONS },
// [FilterKey.URL]: { / [TYPES,TYPES. category: 'interactions', label: 'URL', operator: 'is', operatorOptions: stringFilterOptions },
// [FilterKey.CUSTOM]: { / [TYPES,TYPES. category: 'interactions', label: 'Custom', operator: 'is', operatorOptions: stringFilterOptions },
// [FilterKey.METADATA]: { / [TYPES,TYPES. category: 'interactions', label: 'Metadata', operator: 'is', operatorOptions: stringFilterOptions },
@ -233,6 +220,7 @@ export default Record({
icon: '',
type: '',
value: [""],
source: [""],
category: '',
custom: '',
@ -243,8 +231,10 @@ export default Record({
isFilter: false,
actualValue: '',
operator: 'notOn',
operator: '',
sourceOperator: '=',
operatorOptions: [],
sourceOptions: [],
isEvent: false,
index: 0,
options: [],