From af037600753789376748e9c59149c2df55811762 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 2 Feb 2022 17:20:59 +0100 Subject: [PATCH] feat(ui) - filters global search list --- .../Filters/FilterModal/FilterModal.css | 19 +++ .../Filters/FilterModal/FilterModal.tsx | 45 +++++- .../SessionSearchField/SessionSearchField.tsx | 2 +- frontend/app/duck/search.js | 14 +- frontend/app/types/filter/filterType.ts | 2 +- frontend/app/types/filter/newFilter.js | 137 +----------------- 6 files changed, 76 insertions(+), 143 deletions(-) diff --git a/frontend/app/components/shared/Filters/FilterModal/FilterModal.css b/frontend/app/components/shared/Filters/FilterModal/FilterModal.css index fd1f8fcd4..cb4611d4f 100644 --- a/frontend/app/components/shared/Filters/FilterModal/FilterModal.css +++ b/frontend/app/components/shared/Filters/FilterModal/FilterModal.css @@ -2,6 +2,8 @@ border-radius: 3px; border: solid thin $gray-light; padding: 20px; + overflow: hidden; + overflow-y: auto; } .optionItem { white-space: nowrap; @@ -14,4 +16,21 @@ fill: $teal !important; } } +} + +.filterSearchItem { + &:hover { + background-color: $active-blue; + color: $teal; + + & svg { + fill: $teal; + } + } + + & div { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } } \ No newline at end of file diff --git a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx index fc39c89ed..527fd7390 100644 --- a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx +++ b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx @@ -3,15 +3,53 @@ import { Icon } from 'UI'; import { connect } from 'react-redux'; import cn from 'classnames'; import stl from './FilterModal.css'; +import { filtersMap } from 'Types/filter/newFilter' interface Props { filters: any, - onFilterClick?: (filter) => void + onFilterClick?: (filter) => void, + filterSearchList: any, } function FilterModal(props: Props) { - const { filters, onFilterClick = () => null } = props; + const { filters, onFilterClick = () => null, filterSearchList } = props; + const hasFilerSearchList = filterSearchList && Object.keys(filterSearchList).length > 0; + + const onFilterSearchClick = (filter) => { + const _filter = filtersMap[filter.type]; + _filter.value = [filter.value]; + onFilterClick(_filter); + } return (
+ { hasFilerSearchList && ( +
+ { filterSearchList && Object.keys(filterSearchList).map((key, index) => { + const filter = filterSearchList[key]; + const option = filtersMap[key]; + return ( +
+
{option.label}
+
+ {filter.map((f, i) => ( +
onFilterSearchClick({ type: key, value: f.value })} + > + +
{f.value}
+
+ ))} +
+
+ ); + })} +
+ )} +
{filters && Object.keys(filters).map((key) => (
@@ -32,5 +70,6 @@ function FilterModal(props: Props) { } export default connect(state => ({ - filters: state.getIn([ 'filters', 'filterList' ]) + filters: state.getIn([ 'filters', 'filterList' ]), + filterSearchList: state.getIn([ 'search', 'filterSearchList' ]) }))(FilterModal); \ No newline at end of file diff --git a/frontend/app/components/shared/SessionSearchField/SessionSearchField.tsx b/frontend/app/components/shared/SessionSearchField/SessionSearchField.tsx index 2f0218ce1..39556dd72 100644 --- a/frontend/app/components/shared/SessionSearchField/SessionSearchField.tsx +++ b/frontend/app/components/shared/SessionSearchField/SessionSearchField.tsx @@ -30,7 +30,7 @@ function SessionSearchField(props: Props) { } const onAddFilter = (filter) => { - filter.value = [""] + filter.value = filter.value ? filter.value : [""] const newFilters = appliedFilter.filters.concat(filter); props.editFilter({ ...appliedFilter.filter, diff --git a/frontend/app/duck/search.js b/frontend/app/duck/search.js index 39925d774..d2924f12d 100644 --- a/frontend/app/duck/search.js +++ b/frontend/app/duck/search.js @@ -43,7 +43,7 @@ const initialState = Map({ alertMetricId: null, instance: new Filter({ filters: [] }), savedSearch: null, - filterSearchList: List(), + filterSearchList: {}, }); // Metric - Series - [] - filters @@ -69,7 +69,17 @@ function reducer(state = initialState, action = {}) { const { data } = action; return state.set("list", List(data.map(SavedFilter))); case success(FETCH_FILTER_SEARCH): - return state.set("filterSearchList", action.data.map(NewFilter)); + const groupedList = action.data.reduce((acc, item) => { + const { projectId, type, value } = item; + const key = type; + if (!acc[key]) { + acc[key] = []; + } + acc[key].push({ projectId, value }); + return acc; + }, {}); + console.log('groupedList', groupedList); + return state.set('filterSearchList', groupedList); case APPLY_SAVED_SEARCH: return state.set('savedSearch', action.filter); } diff --git a/frontend/app/types/filter/filterType.ts b/frontend/app/types/filter/filterType.ts index b5449b161..9ab054386 100644 --- a/frontend/app/types/filter/filterType.ts +++ b/frontend/app/types/filter/filterType.ts @@ -40,7 +40,7 @@ export enum FilterKey { REFERRER = "REFERRER", USER_COUNTRY = "USER_COUNTRY", JOURNEY = "JOURNEY", - FETCH = "FETCH", + REQUEST = "REQUEST", GRAPHQL = "GRAPHQL", STATEACTION = "STATEACTION", REVID = "REVID", diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index d3d7e25ee..3b24acc2d 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -19,148 +19,13 @@ const ISSUE_OPTIONS = [ { text: 'JS Exception', value: 'js_exception' }, ] -// const filterKeys = ['is', 'isNot']; -// 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']; - -// const options = [ -// { -// key: 'is', -// text: 'is', -// value: 'is' -// }, { -// key: 'isNot', -// text: 'is not', -// value: 'isNot' -// }, { -// key: 'startsWith', -// text: 'starts with', -// value: 'startsWith' -// }, { -// key: 'endsWith', -// text: 'ends with', -// value: 'endsWith' -// }, { -// key: 'contains', -// text: 'contains', -// value: 'contains' -// }, { -// key: 'notContains', -// text: 'not contains', -// value: 'notContains' -// }, { -// key: 'hasAnyValue', -// text: 'has any value', -// value: 'hasAnyValue' -// }, { -// key: 'hasNoValue', -// text: 'has no value', -// value: 'hasNoValue' -// }, -// { -// key: 'isSignedUp', -// text: 'is signed up', -// value: 'isSignedUp' -// }, { -// key: 'notSignedUp', -// text: 'not signed up', -// value: 'notSignedUp' -// }, -// { -// key: 'before', -// text: 'before', -// value: 'before' -// }, { -// key: 'after', -// text: 'after', -// value: 'after' -// }, { -// key: 'on', -// text: 'on', -// value: 'on' -// }, { -// key: 'notOn', -// text: 'not on', -// value: 'notOn' -// }, { -// key: 'inRage', -// text: 'in rage', -// value: 'inRage' -// }, { -// key: 'notInRage', -// text: 'not in rage', -// value: 'notInRage' -// }, { -// key: 'withinLast', -// text: 'within last', -// value: 'withinLast' -// }, { -// key: 'notWithinLast', -// text: 'not within last', -// value: 'notWithinLast' -// }, -// { -// key: 'greaterThan', -// text: 'greater than', -// value: 'greaterThan' -// }, { -// key: 'lessThan', -// text: 'less than', -// value: 'lessThan' -// }, { -// key: 'equal', -// text: 'equal', -// value: 'equal' -// }, { -// key: 'not equal', -// text: 'not equal', -// value: 'not equal' -// }, -// { -// key: 'onSelector', -// text: 'on selector', -// value: 'onSelector' -// }, { -// key: 'onText', -// text: 'on text', -// value: 'onText' -// }, { -// key: 'onComponent', -// text: 'on component', -// value: 'onComponent' -// }, -// { -// key: 'onAny', -// text: 'on any', -// value: 'onAny' -// } -// ]; - -// export const filterOptions = options.filter(({key}) => filterKeys.includes(key)); -// export const filterOptions.stringOperators = options.filter(({key}) => stringFilterKeys.includes(key)); -// export const filterOptions.targetOperators = options.filter(({key}) => targetFilterKeys.includes(key)); -// export const booleanOptions = [ -// { key: 'true', text: 'true', value: 'true' }, -// { key: 'false', text: 'false', value: 'false' }, -// ] - -// export const filterOptions.customOperators = [ -// { key: '=', text: '=', value: '=' }, -// { key: '<', text: '<', value: '<' }, -// { key: '>', text: '>', value: '>' }, -// { key: '<=', text: '<=', value: '<=' }, -// { key: '>=', text: '>=', value: '>=' }, -// ] - 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 }, [FilterKey.INPUT]: { key: FilterKey.INPUT, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Input', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/input', isEvent: true }, [FilterKey.LOCATION]: { key: FilterKey.LOCATION, type: FilterType.MULTIPLE, category: FilterCategory.INTERACTIONS, label: 'Page', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/location', isEvent: true }, [FilterKey.CUSTOM]: { key: FilterKey.CUSTOM, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Custom Events', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/custom', isEvent: true }, - [FilterKey.FETCH]: { key: FilterKey.FETCH, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Fetch', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch', isEvent: true }, + [FilterKey.REQUEST]: { key: FilterKey.REQUEST, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Fetch', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/fetch', isEvent: true }, [FilterKey.GRAPHQL]: { key: FilterKey.GRAPHQL, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'GraphQL', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/graphql', isEvent: true }, [FilterKey.STATEACTION]: { key: FilterKey.STATEACTION, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'StateAction', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/state-action', isEvent: true }, [FilterKey.ERROR]: { key: FilterKey.ERROR, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Error', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/error', isEvent: true },