feat(ui) - custom metrics
This commit is contained in:
parent
45db3fa1d4
commit
2008d3dc2f
14 changed files with 193 additions and 147 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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) => (
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
1
frontend/app/svg/icons/filters/custom.svg
Normal file
1
frontend/app/svg/icons/filters/custom.svg
Normal 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 |
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
}
|
||||
|
|
@ -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: [],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue