feat(fitlers) - fitlers and custommetrics
This commit is contained in:
parent
562f4d976d
commit
985301e1c0
12 changed files with 114 additions and 28 deletions
|
|
@ -3,6 +3,7 @@ import FilterOperator from '../FilterOperator';
|
|||
import FilterSelection from '../FilterSelection';
|
||||
import FilterValue from '../FilterValue';
|
||||
import { Icon } from 'UI';
|
||||
import FilterSource from '../FilterSource';
|
||||
|
||||
interface Props {
|
||||
filterIndex: number;
|
||||
|
|
@ -21,16 +22,40 @@ function FitlerItem(props: Props) {
|
|||
const onOperatorChange = (e, { name, value }) => {
|
||||
props.onUpdate({ ...filter, operator: value })
|
||||
}
|
||||
|
||||
const onSourceOperatorChange = (e, { name, value }) => {
|
||||
props.onUpdate({ ...filter, sourceOperator: value })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center hover:bg-active-blue -mx-5 px-5 py-2">
|
||||
<div className="flex items-start w-full">
|
||||
{ !isFilter && <div className="mt-1 flex-shrink-0 border w-6 h-6 text-xs flex justify-center rounded-full bg-gray-light-shade mr-2">{filterIndex+1}</div> }
|
||||
<FilterSelection filter={filter} onFilterClick={replaceFilter} />
|
||||
<FilterOperator filter={filter} onChange={onOperatorChange} className="mx-2 flex-shrink-0"/>
|
||||
|
||||
{/* Filter with Source */}
|
||||
{ filter.hasSource && (
|
||||
<>
|
||||
<FilterOperator
|
||||
options={filter.sourceOperatorOptions}
|
||||
onChange={onSourceOperatorChange}
|
||||
className="mx-2 flex-shrink-0"
|
||||
value={filter.sourceOperator}
|
||||
/>
|
||||
<FilterSource filter={filter} onUpdate={props.onUpdate} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Filter values */}
|
||||
<FilterOperator
|
||||
options={filter.operatorOptions}
|
||||
onChange={onOperatorChange}
|
||||
className="mx-2 flex-shrink-0"
|
||||
value={filter.operator}
|
||||
/>
|
||||
<FilterValue filter={filter} onUpdate={props.onUpdate} />
|
||||
</div>
|
||||
<div className="flex self-start mt-1 ml-auto px-2">
|
||||
<div className="flex flex-shrink-0 self-start mt-1 ml-auto px-2">
|
||||
<div
|
||||
className="cursor-pointer p-1"
|
||||
onClick={props.onRemoveFilter}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,17 @@
|
|||
.wrapper {
|
||||
border-radius: 3px;
|
||||
border: solid thin $gray-light;
|
||||
padding: 20px;
|
||||
}
|
||||
.optionItem {
|
||||
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
&:hover {
|
||||
background-color: $active-blue;
|
||||
color: $teal !important;
|
||||
& svg {
|
||||
fill: $teal !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,14 +11,14 @@ interface Props {
|
|||
function FilterModal(props: Props) {
|
||||
const { filters, onFilterClick = () => null } = props;
|
||||
return (
|
||||
<div className="border p-3" style={{ width: '490px', height: '400px', overflowY: 'auto'}}>
|
||||
<div className={stl.wrapper} style={{ width: '490px', height: '400px', overflowY: 'auto'}}>
|
||||
<div className="" style={{ columns: "100px 2" }}>
|
||||
{filters && Object.keys(filters).map((key) => (
|
||||
<div className="p-3 aspect-w-1">
|
||||
<div className="uppercase font-medium mb-1">{key}</div>
|
||||
<div className="mb-4">
|
||||
<div className="uppercase font-medium mb-1 color-gray-medium">{key}</div>
|
||||
<div>
|
||||
{filters[key].map((filter: any) => (
|
||||
<div className={cn(stl.optionItem, "flex items-center py-2 cursor-pointer hover:bg-gray-lightest -mx-2 px-2")} onClick={() => onFilterClick(filter)}>
|
||||
<div className={cn(stl.optionItem, "flex items-center py-2 cursor-pointer -mx-2 px-2")} onClick={() => onFilterClick(filter)}>
|
||||
<Icon name={filter.icon} size="16"/>
|
||||
<span className="ml-2">{filter.label}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@ import { Dropdown, Icon } from 'UI';
|
|||
import stl from './FilterOperator.css';
|
||||
|
||||
interface Props {
|
||||
filter: any; // event/filter
|
||||
// filter: any; // event/filter
|
||||
onChange: (e, { name, value }) => void;
|
||||
className?: string;
|
||||
options?: any;
|
||||
value?: string;
|
||||
}
|
||||
function FilterOperator(props: Props) {
|
||||
const { filter, onChange, className = '' } = props;
|
||||
|
||||
console.log('FilterOperator', filter.operator);
|
||||
const { options, value, onChange, className = '' } = props;
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
className={ cn(stl.operatorDropdown, className, 'hover:bg-gray-light-shade') }
|
||||
options={ filter.operatorOptions }
|
||||
options={ options }
|
||||
name="operator"
|
||||
value={ filter.operator }
|
||||
value={ value }
|
||||
onChange={ onChange }
|
||||
placeholder="Select operator"
|
||||
icon={ <Icon className="ml-5" name="chevron-down" size="12" /> }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
.inputField {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
border: solid thin $gray-light;
|
||||
border-radius: 3px;
|
||||
height: 26px;
|
||||
background-color: $white;
|
||||
padding: 0 5px;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { FilterType } from 'App/types/filter/filterType';
|
||||
import React from 'react';
|
||||
import stl from './FilterSource.css';
|
||||
|
||||
interface Props {
|
||||
filter: any,
|
||||
onUpdate: (filter) => void;
|
||||
}
|
||||
function FilterSource(props: Props) {
|
||||
const { filter } = props;
|
||||
|
||||
const onChange = ({ target: { value, name } }) => {
|
||||
props.onUpdate({ ...filter, source: [value] })
|
||||
}
|
||||
|
||||
const renderFiled = () => {
|
||||
switch(filter.sourceType) {
|
||||
case FilterType.NUMBER:
|
||||
return <input className={stl.inputField} value={filter.source[0]} onBlur={onChange} type="number" />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ renderFiled()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FilterSource;
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './FilterSource';
|
||||
|
|
@ -22,7 +22,7 @@ function FilterValue(props: Props) {
|
|||
props.onUpdate({ ...filter, value: newValues })
|
||||
}
|
||||
|
||||
const onSelect = (e, item, valueIndex) => {
|
||||
const onChange = (e, item, valueIndex) => {
|
||||
const newValues = filter.value.map((_, _index) => {
|
||||
if (_index === valueIndex) {
|
||||
return item.value;
|
||||
|
|
@ -61,7 +61,7 @@ function FilterValue(props: Props) {
|
|||
value={value}
|
||||
filter={filter}
|
||||
options={filter.options}
|
||||
onChange={(e, { name, value }) => onSelect(e, { value }, valueIndex)}
|
||||
onChange={(e, { name, value }) => onChange(e, { value }, valueIndex)}
|
||||
/>
|
||||
)
|
||||
case FilterType.ISSUE:
|
||||
|
|
@ -72,7 +72,7 @@ function FilterValue(props: Props) {
|
|||
value={value}
|
||||
filter={filter}
|
||||
options={filter.options}
|
||||
onChange={(e, { name, value }) => onSelect(e, { value }, valueIndex)}
|
||||
onChange={(e, { name, value }) => onChange(e, { value }, valueIndex)}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
showCloseButton={showCloseButton}
|
||||
|
|
@ -96,7 +96,7 @@ function FilterValue(props: Props) {
|
|||
type="number"
|
||||
name={`${filter.key}-${valueIndex}`}
|
||||
value={value}
|
||||
onChange={(e) => onSelect(e, { value: e.target.value }, valueIndex)}
|
||||
onChange={(e) => onChange(e, { value: e.target.value }, valueIndex)}
|
||||
/>
|
||||
)
|
||||
case FilterType.MULTIPLE:
|
||||
|
|
@ -112,7 +112,7 @@ function FilterValue(props: Props) {
|
|||
params={{ type: filter.key }}
|
||||
headerText={''}
|
||||
// placeholder={''}
|
||||
onSelect={(e, item) => onSelect(e, item, valueIndex)}
|
||||
onSelect={(e, item) => onChange(e, item, valueIndex)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ Object.keys(filtersMap).forEach(key => {
|
|||
filterOptions[filter.category] = [filter];
|
||||
}
|
||||
})
|
||||
|
||||
console.log('filterOptions', filterOptions)
|
||||
|
||||
|
||||
// for (var i = 0; i < newFiltersList.length; i++) {
|
||||
|
|
|
|||
|
|
@ -74,13 +74,14 @@ export default mergeReducers(
|
|||
}),
|
||||
);
|
||||
|
||||
const filterMap = ({value, type, key, operator, source, custom, isEvent }) => ({
|
||||
// value: Array.isArray(value) ? value: [value],
|
||||
const filterMap = ({value, key, operator, sourceOperator, source, custom, isEvent }) => ({
|
||||
value: value.filter(i => i !== '' && i !== null),
|
||||
custom,
|
||||
type: key,
|
||||
key, operator,
|
||||
// key,
|
||||
operator,
|
||||
source,
|
||||
sourceOperator,
|
||||
isEvent
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ export default Record({
|
|||
consoleLevel: undefined,
|
||||
strict: false,
|
||||
eventsOrder: 'and',
|
||||
sourceOperator: '',
|
||||
}, {
|
||||
idKey: 'searchId',
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -179,7 +179,9 @@ export const filtersMap = {
|
|||
[FilterKey.CONSOLE]: { key: FilterKey.CONSOLE, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Console', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/console' },
|
||||
[FilterKey.USERID]: { key: FilterKey.USERID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'UserId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' },
|
||||
[FilterKey.USERANONYMOUSID]: { key: FilterKey.USERANONYMOUSID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'UserAnonymousId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' },
|
||||
[FilterKey.DOM_COMPLETE]: { key: FilterKey.DOM_COMPLETE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'DOM Complete', operator: 'is', operatorOptions: filterOptions.stringOperators, sourcesourceOperatorOptions: filterOptions.customOperators, source: [], icon: 'filters/click', isEvent: true },
|
||||
|
||||
// PERFORMANCE
|
||||
[FilterKey.DOM_COMPLETE]: { key: FilterKey.DOM_COMPLETE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'DOM Complete', operator: 'is', operatorOptions: filterOptions.stringOperators, sourceOperatorOptions: filterOptions.customOperators, source: [], icon: 'filters/click', isEvent: true, hasSource: true, sourceOperator: '=', sourceType: FilterType.NUMBER },
|
||||
[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: filterOptions.stringOperators, 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: filterOptions.stringOperators, icon: 'filters/click' },
|
||||
[FilterKey.TTFB]: { key: FilterKey.TTFB, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Time to First Byte', operator: 'is', operatorOptions: filterOptions.stringOperators, sourceOperatorOptions: filterOptions.customOperators, source: [], icon: 'filters/click', isEvent: true },
|
||||
|
|
@ -202,15 +204,19 @@ export default Record({
|
|||
custom: '',
|
||||
// target: Target(),
|
||||
level: '',
|
||||
source: null,
|
||||
|
||||
hasNoValue: false,
|
||||
isFilter: false,
|
||||
actualValue: '',
|
||||
|
||||
operator: '',
|
||||
hasSource: false,
|
||||
source: [""],
|
||||
sourceType: '',
|
||||
sourceOperator: '=',
|
||||
operatorOptions: [],
|
||||
sourceOptions: [],
|
||||
sourceOperatorOptions: [],
|
||||
|
||||
operator: '',
|
||||
operatorOptions: [],
|
||||
isEvent: false,
|
||||
index: 0,
|
||||
options: [],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue