From a55b2084340d661f06b77b56dbba42880d5f24c5 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 4 Feb 2022 19:41:52 +0100 Subject: [PATCH] feat(ui) - filters - metadata and other ui changes --- .../CustomMetricWidgetPreview.tsx | 2 +- .../CustomMetricForm/CustomMetricForm.tsx | 10 +- .../Filters/FilterModal/FilterModal.tsx | 117 ++++++++++-------- .../FilterSelection/FilterSelection.tsx | 6 +- .../Filters/FilterValue/FilterValue.tsx | 4 +- .../shared/MainSearchBar/MainSearchBar.tsx | 2 +- .../SaveFunnelButton/SaveFunnelButton.tsx | 2 +- .../SaveSearchModal/SaveSearchModal.tsx | 7 +- .../SavedSearchDropdown.tsx | 4 +- .../SessionSearchField/SessionSearchField.tsx | 24 ++-- frontend/app/duck/search.js | 2 +- frontend/app/svg/icons/funnel.svg | 3 + frontend/app/types/customMetric.js | 1 + frontend/app/types/filter/newFilter.js | 7 ++ 14 files changed, 111 insertions(+), 80 deletions(-) create mode 100644 frontend/app/svg/icons/funnel.svg diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx index 8c09ed389..246d54a02 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx @@ -54,7 +54,7 @@ function CustomMetricWidget(props: Props) { console.log('err', errors) } else { const _data = getChartFormatter(period)(data[0]); - console.log('__data', _data) + // console.log('__data', _data) setData({ chart: _data }); } }).finally(() => setLoading(false)); diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index 60bcce7a9..10f1b3296 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -11,6 +11,7 @@ interface Props { save: (metric) => void; loading: boolean; } + function CustomMetricForm(props: Props) { const { metric, loading } = props; @@ -18,15 +19,16 @@ function CustomMetricForm(props: Props) { const newSeries = { name: `Series ${metric.series.size + 1}`, type: '', - series: [], + // series: [], filter: { type: '', value: '', + filters: [], }, }; props.editMetric({ ...metric, - series: [...metric.series, newSeries], + series: metric.series.concat(newSeries), }); } @@ -40,10 +42,10 @@ function CustomMetricForm(props: Props) { }); } - const write = ({ target: { value, name } }) => props.editMetric({ ...metric.toData(), [ name ]: value }) + const write = ({ target: { value, name } }) => props.editMetric({ ...metric, [ name ]: value }) const changeConditionTab = (e, { name, value }) => { - props.editMetric({ ...metric.toData(), [ 'type' ]: value }) + props.editMetric({ ...metric, [ 'type' ]: value }) }; return ( diff --git a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx index 2d4730a72..edb75a5cf 100644 --- a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx +++ b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import { Icon } from 'UI'; +import { Icon, Loader } from 'UI'; import { connect } from 'react-redux'; import cn from 'classnames'; import stl from './FilterModal.css'; -import { filtersMap } from 'Types/filter/newFilter'; +import { filtersMap, getMetaDataFilter } from 'Types/filter/newFilter'; import { FilterKey, FilterType } from 'Types/filter/filterType'; interface Props { @@ -11,21 +11,31 @@ interface Props { onFilterClick?: (filter) => void, filterSearchList: any, metaOptions: any, + isMainSearch?: boolean, + fetchingFilterSearchList: boolean, + searchQuery?: string, } function FilterModal(props: Props) { - const { filters, metaOptions, onFilterClick = () => null, filterSearchList } = props; + const { + filters, + metaOptions, + onFilterClick = () => null, + filterSearchList, + isMainSearch = false, + fetchingFilterSearchList, + searchQuery = '', + } = props; const hasFilerSearchList = filterSearchList && Object.keys(filterSearchList).length > 0; + const hasSearchQuery = searchQuery && searchQuery.length > 0; + const showSearchList = isMainSearch && searchQuery.length > 0; - const allFilters = Object.assign({}, filtersMap); + const allFilters = Object.assign({}, filters); if (metaOptions.size > 0) { + allFilters['Metadata'] = []; metaOptions.forEach((option) => { if (option.key) { - allFilters[option.key] = { - category: FilterKey.METADATA, - key: option.key, - name: option.key, - label: option.key, - }; + const _metaFilter = getMetaDataFilter(option.key, option.value); + allFilters['Metadata'].push(_metaFilter); } }); } @@ -36,51 +46,55 @@ function FilterModal(props: Props) { 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}
-
- ))} +
+ { showSearchList && ( + +
+ { 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) => ( -
-
{key}
-
- {filters[key].map((filter: any) => ( -
onFilterClick(filter)}> - - {filter.label} -
- ))} + { !hasSearchQuery && ( +
+ {allFilters && Object.keys(allFilters).map((key) => ( +
+
{key}
+
+ {allFilters[key].map((filter: any) => ( +
onFilterClick(filter)}> + + {filter.label} +
+ ))} +
-
- ))} -
+ ))} +
+ )}
); } @@ -89,4 +103,5 @@ export default connect(state => ({ filters: state.getIn([ 'filters', 'filterList' ]), filterSearchList: state.getIn([ 'search', 'filterSearchList' ]), metaOptions: state.getIn([ 'customFields', 'list' ]), + fetchingFilterSearchList: state.getIn([ 'search', 'fetchFilterSearch', 'loading' ]), }))(FilterModal); \ No newline at end of file diff --git a/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx b/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx index 674d81a78..d3233d48a 100644 --- a/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx +++ b/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx @@ -20,7 +20,11 @@ function FilterSelection(props: Props) { setShowModal(false) }, 200)} > - { children ? React.cloneElement(children, { onClick: () => setShowModal(true)}) : ( + { children ? React.cloneElement(children, { onClick: (e) => { + e.stopPropagation(); + e.preventDefault(); + setShowModal(true); + }}) : (
( - renderValueFiled(value, valueIndex) +
+ {renderValueFiled(value, valueIndex)} +
)) )}
diff --git a/frontend/app/components/shared/MainSearchBar/MainSearchBar.tsx b/frontend/app/components/shared/MainSearchBar/MainSearchBar.tsx index fb8567b54..082afc90d 100644 --- a/frontend/app/components/shared/MainSearchBar/MainSearchBar.tsx +++ b/frontend/app/components/shared/MainSearchBar/MainSearchBar.tsx @@ -24,7 +24,7 @@ const MainSearchBar = (props: Props) => { Clear } - content={'Clear all filters and search'} + content={'Clear Steps'} size="tiny" inverted position="top right" diff --git a/frontend/app/components/shared/SaveFunnelButton/SaveFunnelButton.tsx b/frontend/app/components/shared/SaveFunnelButton/SaveFunnelButton.tsx index 195fe95b7..c68c451d0 100644 --- a/frontend/app/components/shared/SaveFunnelButton/SaveFunnelButton.tsx +++ b/frontend/app/components/shared/SaveFunnelButton/SaveFunnelButton.tsx @@ -8,7 +8,7 @@ export default function SaveFunnelButton() {
setshowModal(true)} primaryText label="SAVE FUNNEL" icon="zoom-in" + onClick={() => setshowModal(true)} primaryText label="SAVE FUNNEL" icon="funnel" /> + { savedSearch &&
Changes in filters will be updated.
} - +
- { savedSearch && } + { savedSearch && }
); diff --git a/frontend/app/components/shared/SavedSearch/components/SavedSearchDropdown/SavedSearchDropdown.tsx b/frontend/app/components/shared/SavedSearch/components/SavedSearchDropdown/SavedSearchDropdown.tsx index 58869a115..faff1e34b 100644 --- a/frontend/app/components/shared/SavedSearch/components/SavedSearchDropdown/SavedSearchDropdown.tsx +++ b/frontend/app/components/shared/SavedSearch/components/SavedSearchDropdown/SavedSearchDropdown.tsx @@ -22,7 +22,7 @@ function Row ({ name, onClick, onClickEdit, onDelete }) { >
{name}
-
+ {/*
*/} {/*
*/}
@@ -53,7 +53,7 @@ function SavedSearchDropdown(props: Props) { } return ( -
+
{props.list.map(item => ( void; + // setSearchQuery: (query: string) => void; fetchFilterSearch: (query: any) => void; - searchQuery: string; + // searchQuery: string; appliedFilter: any; editFilter: typeof editFilter; } @@ -23,9 +23,10 @@ function SessionSearchField(props: Props) { const { appliedFilter } = props; const debounceFetchFilterSearch = debounce(props.fetchFilterSearch, 1000) const [showModal, setShowModal] = useState(false) + const [searchQuery, setSearchQuery] = useState('') const onSearchChange = (e, { value }) => { - // props.setSearchQuery(value) + setSearchQuery(value) debounceFetchFilterSearch({ q: value }); } @@ -58,17 +59,11 @@ function SessionSearchField(props: Props) { autocomplete="off" /> - {/* setShowModal(false) } - displayed={ showModal } - // displayed={ true } - // loading={ loading } - // searchedEvents={ searchedEvents } - searchQuery={ props.searchQuery } - /> */} { showModal && (
@@ -79,8 +74,7 @@ function SessionSearchField(props: Props) { export default connect(state => ({ events: state.getIn([ 'filters', 'appliedFilter', 'events' ]), - // appliedFilter: state.getIn([ 'filters', 'appliedFilter' ]), - searchQuery: state.getIn([ 'filters', 'searchQuery' ]), + // searchQuery: state.getIn([ 'filters', 'searchQuery' ]), appliedFilterKeys: state.getIn([ 'filters', 'appliedFilter', 'filters' ]) .map(({type}) => type).toJS(), searchedEvents: state.getIn([ 'events', 'list' ]), @@ -88,4 +82,4 @@ export default connect(state => ({ strict: state.getIn([ 'filters', 'appliedFilter', 'strict' ]), blink: state.getIn([ 'funnels', 'blink' ]), appliedFilter: state.getIn(['search', 'instance']), -}), { setSearchQuery, fetchFilterSearch, editFilter })(SessionSearchField); \ No newline at end of file +}), { fetchFilterSearch, editFilter })(SessionSearchField); \ No newline at end of file diff --git a/frontend/app/duck/search.js b/frontend/app/duck/search.js index 05ec59db2..86cc19e6a 100644 --- a/frontend/app/duck/search.js +++ b/frontend/app/duck/search.js @@ -72,7 +72,6 @@ function reducer(state = initialState, action = {}) { 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); @@ -85,6 +84,7 @@ export default mergeReducers( createRequestReducer({ [ ROOT_KEY ]: FETCH_LIST, fetch: FETCH, + fetchFilterSearch: FETCH_FILTER_SEARCH }), ); diff --git a/frontend/app/svg/icons/funnel.svg b/frontend/app/svg/icons/funnel.svg new file mode 100644 index 000000000..5f29fe302 --- /dev/null +++ b/frontend/app/svg/icons/funnel.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/types/customMetric.js b/frontend/app/types/customMetric.js index 0334ae2e6..fb3044b51 100644 --- a/frontend/app/types/customMetric.js +++ b/frontend/app/types/customMetric.js @@ -47,6 +47,7 @@ export default Record({ return filter; }); delete series._key + delete series.key return series; }); diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index e5193a393..690c04390 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -1,6 +1,7 @@ import Record from 'Types/Record'; import { FilterType, FilterKey, FilterCategory } from './filterType' import filterOptions, { countries, platformOptions } from 'App/constants'; +import { capitalize } from 'App/utils'; const countryOptions = Object.keys(countries).map(i => ({ text: countries[i], value: i })); @@ -55,6 +56,12 @@ export const filtersMap = { [FilterKey.ISSUE]: { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/click', options: ISSUE_OPTIONS }, } + +export const getMetaDataFilter = (key) => { + const METADATA_FILTER = { key: key, type: FilterType.MULTIPLE, category: FilterCategory.METADATA, label: capitalize(key), operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/metadata' } + return METADATA_FILTER; +} + export default Record({ timestamp: 0, key: '',