feat(ui) - filters fixes

This commit is contained in:
Shekar Siri 2022-02-07 21:29:54 +01:00
parent 49adef4971
commit fe265eb247
10 changed files with 57 additions and 32 deletions

View file

@ -28,9 +28,9 @@ export default class FunnelSaveModal extends React.PureComponent {
onChangeOption = (e, { checked, name }) => this.props.edit({ [ name ]: checked })
onSave = () => {
const { funnel, closeHandler } = this.props;
const { funnel, filter } = this.props;
if (funnel.name.trim() === '') return;
this.props.save({ ...funnel, filter: filter }).then(function() {
this.props.save(funnel).then(function() {
this.props.fetchFunnelsList();
this.props.closeHandler();
}.bind(this));

View file

@ -45,8 +45,7 @@ function FilterAutoComplete(props: Props) {
const [query, setQuery] = useState(value);
const requestValues = (q) => {
// const { params, method } = props;
const requestValues = (q) => {
setLoading(true);
return new APIClient()[method?.toLowerCase()](endpoint, { ...params, q })
@ -55,13 +54,7 @@ function FilterAutoComplete(props: Props) {
if (errors) {
// this.setError();
} else {
setOptions(data);
// this.setState({
// ddOpen: true,
// values: data,
// loading: false,
// noResultsMessage: NO_RESULTS_MSG,
// });
setOptions(data);
}
}).finally(() => setLoading(false));
// .catch(this.setError);
@ -81,6 +74,17 @@ function FilterAutoComplete(props: Props) {
debouncedRequestValues(query)
}, [query])
useEffect(() => {
if(value === '') {
setQuery(value);
}
}, [value])
const onBlur = (e) => {
setTimeout(() => { setShowModal(false) }, 200)
props.onSelect(e, { value: query })
}
const onItemClick = (e, item) => {
e.stopPropagation();
e.preventDefault();
@ -103,7 +107,7 @@ function FilterAutoComplete(props: Props) {
<input
name="query"
onChange={ onInputChange }
onBlur={ () => setTimeout(() => { setShowModal(false) }, 200) }
onBlur={ onBlur }
onFocus={ () => setShowModal(true)}
value={ query }
autoFocus={ true }

View file

@ -14,6 +14,7 @@ interface Props {
}
function FilterItem(props: Props) {
const { isFilter = false, filterIndex, filter } = props;
const canShowValues = !(filter.operator === "isAny" || filter.operator === "onAny");
const replaceFilter = (filter) => {
props.onUpdate({ ...filter, value: [""]});
@ -53,9 +54,7 @@ function FilterItem(props: Props) {
className="mx-2 flex-shrink-0"
value={filter.operator}
/>
{ !(filter.operator === "isAny" || filter.operator === "onAny") && (
<FilterValue filter={filter} onUpdate={props.onUpdate} />
)}
{ canShowValues && (<FilterValue filter={filter} onUpdate={props.onUpdate} />) }
</div>
<div className="flex flex-shrink-0 self-start mt-1 ml-auto px-2">

View file

@ -1,5 +1,5 @@
import { FilterType } from 'App/types/filter/filterType';
import React from 'react';
import React, { useState, useEffect } from 'react';
import stl from './FilterSource.css';
interface Props {
@ -8,11 +8,22 @@ interface Props {
}
function FilterSource(props: Props) {
const { filter } = props;
const [value, setValue] = useState(filter.source[0] || '');
const onChange = ({ target: { value, name } }) => {
props.onUpdate({ ...filter, [name]: [value] })
}
useEffect(() => {
setValue(filter.source[0] || '');
}, [filter])
useEffect(() => {
props.onUpdate({ ...filter, source: [value] })
}, [value])
const write = ({ target: { value, name } }) => setValue(value)
const renderFiled = () => {
switch(filter.sourceType) {
case FilterType.NUMBER:
@ -20,9 +31,9 @@ function FilterSource(props: Props) {
<input
name="source"
className={stl.inputField}
value={filter.source[0]}
onBlur={onChange}
onChange={onChange}
value={value}
onBlur={write}
onChange={write}
type="number"
/>
)

View file

@ -11,6 +11,8 @@ interface Props {
function FilterValue(props: Props) {
const { filter } = props;
const [durationValues, setDurationValues] = useState({ minDuration: filter.value[0], maxDuration: filter.value[1] });
const showCloseButton = filter.value.length > 1;
const lastIndex = filter.value.length - 1;
const onAddValue = () => {
const newValues = filter.value.concat("")
@ -65,8 +67,7 @@ function FilterValue(props: Props) {
}
const renderValueFiled = (value, valueIndex) => {
const showCloseButton = filter.value.length > 1;
const showOrButton = valueIndex === filter.value.length - 1;
const showOrButton = valueIndex === lastIndex;
switch(filter.type) {
case FilterType.DROPDOWN:
return (

View file

@ -122,6 +122,10 @@ const targetFilterKeys = ['on', 'notOn', 'onAny'];
const signUpStatusFilterKeys = ['isSignedUp', 'notSignedUp'];
const rangeFilterKeys = ['before', 'after', 'on', 'inRange', 'notInRange', 'withInLast', 'notWithInLast'];
const getOperatorsByKeys = (keys) => {
return options.filter(option => keys.includes(option.key));
};
export const baseOperators = options.filter(({key}) => filterKeys.includes(key));
export const stringOperators = options.filter(({key}) => stringFilterKeys.includes(key));
export const targetOperators = options.filter(({key}) => targetFilterKeys.includes(key));
@ -145,4 +149,5 @@ export default {
targetOperators,
booleanOperators,
customOperators,
getOperatorsByKeys,
}

View file

@ -7,6 +7,7 @@ import { createItemInListUpdater, mergeReducers, success, array } from './funcTo
import { createRequestReducer } from './funcTools/request';
import { getDateRangeFromValue } from 'App/dateRange';
import { LAST_7_DAYS } from 'Types/app/period';
import { filterMap as searchFilterMap } from './search';
const name = 'funnel';
const idKey = 'funnelId';
@ -265,16 +266,20 @@ export const fetchIssueTypes = () => {
}
}
export const save = (instance) => {
export const save = (instance) => (dispatch, getState) => {
// export const save = (instance) => {
const filter = getState().getIn([ 'search', 'instance']).toData();
filter.filters = filter.filters.map(searchFilterMap);
const _instance = instance instanceof Funnel ? instance : Funnel(instance);
const url = _instance.exists()
? `/funnels/${ _instance[idKey] }`
: `/funnels`;
return {
return dispatch({
types: array(_instance.exists() ? SAVE : UPDATE),
call: client => client.post(url, _instance.toData()),
}
call: client => client.post(url, { ..._instance.toData(), filter }),
});
}
export const updateFunnelFilters = (funnelId, filter) => {

View file

@ -7,6 +7,7 @@ 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';
import { FilterCategory, FilterKey } from '../types/filter/filterType';
const ERRORS_ROUTE = errorsRoute();
@ -88,13 +89,12 @@ export default mergeReducers(
}),
);
const filterMap = ({value, key, operator, sourceOperator, source, custom, isEvent }) => ({
export const filterMap = ({category, value, key, operator, sourceOperator, source, custom, isEvent }) => ({
value: value.filter(i => i !== '' && i !== null),
custom,
type: key,
// key,
type: category === FilterCategory.METADATA ? FilterKey.METADATA : key,
operator,
source,
source: category === FilterCategory.METADATA ? key : source,
sourceOperator,
isEvent
});

View file

@ -45,7 +45,7 @@ export default Record({
suspicious: undefined,
consoleLevel: undefined,
strict: false,
eventsOrder: 'and',
eventsOrder: 'then',
}, {
idKey: 'searchId',
methods: {

View file

@ -40,8 +40,8 @@ export const filtersMap = {
[FilterKey.PLATFORM]: { key: FilterKey.PLATFORM, type: FilterType.MULTIPLE_DROPDOWN, category: FilterCategory.GEAR, label: 'Platform', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/platform', options: platformOptions },
[FilterKey.REVID]: { key: FilterKey.REVID, type: FilterType.MULTIPLE, category: FilterCategory.GEAR, label: 'RevId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/rev-id' },
[FilterKey.REFERRER]: { key: FilterKey.REFERRER, type: FilterType.MULTIPLE, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'Referrer', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/referrer' },
[FilterKey.DURATION]: { key: FilterKey.DURATION, type: FilterType.DURATION, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'Duration', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/duration' },
[FilterKey.USER_COUNTRY]: { key: FilterKey.USER_COUNTRY, type: FilterType.MULTIPLE_DROPDOWN, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'User Country', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/country', options: countryOptions },
[FilterKey.DURATION]: { key: FilterKey.DURATION, type: FilterType.DURATION, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'Duration', operator: 'is', operatorOptions: filterOptions.getOperatorsByKeys(['is']), icon: 'filters/duration' },
[FilterKey.USER_COUNTRY]: { key: FilterKey.USER_COUNTRY, type: FilterType.MULTIPLE_DROPDOWN, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'User Country', operator: 'is', operatorOptions: filterOptions.getOperatorsByKeys(['is', 'isAny', 'isNot']), icon: 'filters/country', options: countryOptions },
// [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: 'User Id', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' },
[FilterKey.USERANONYMOUSID]: { key: FilterKey.USERANONYMOUSID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'User AnonymousId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' },