From 9dd8a351d9ea417c6fe69c29305b22d1660913ca Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 6 Jan 2023 11:56:12 +0100 Subject: [PATCH 1/4] change(ui) - filter series to check for empty flag --- .../components/FilterSeries/FilterSeries.tsx | 6 ++++-- .../Dashboard/components/WidgetForm/WidgetForm.tsx | 1 + .../shared/Filters/FilterItem/FilterItem.tsx | 13 ++++++------- .../shared/Filters/FilterList/FilterList.tsx | 5 ++++- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx index 12fbab009..c0de60d2d 100644 --- a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx @@ -11,7 +11,7 @@ interface Props { series: any; onRemoveSeries: (seriesIndex: any) => void; canDelete?: boolean; - + supportsEmpty?: boolean; hideHeader?: boolean; emptyMessage?: any; observeChanges?: () => void; @@ -23,7 +23,8 @@ function FilterSeries(props: Props) { }, canDelete, hideHeader = false, - emptyMessage = 'Add user event or filter to define the series by clicking Add Step.' + emptyMessage = 'Add user event or filter to define the series by clicking Add Step.', + supportsEmpty = true, } = props; const [expanded, setExpanded] = useState(true) const { series, seriesIndex } = props; @@ -74,6 +75,7 @@ function FilterSeries(props: Props) { onUpdateFilter={onUpdateFilter} onRemoveFilter={onRemoveFilter} onChangeEventsOrder={onChangeEventsOrder} + supportsEmpty={supportsEmpty} /> ) : (
{emptyMessage}
diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx index bc8429d87..a24db7391 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx @@ -201,6 +201,7 @@ function WidgetForm(props: Props) { .map((series: any, index: number) => (
metric.updateKey('hasChanged', true)} hideHeader={isTable || isClickmap} seriesIndex={index} diff --git a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx index fae8d9f1d..c76cc7938 100644 --- a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx +++ b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx @@ -2,7 +2,7 @@ import React from 'react'; import FilterOperator from '../FilterOperator'; import FilterSelection from '../FilterSelection'; import FilterValue from '../FilterValue'; -import { Icon } from 'UI'; +import { Icon, Button } from 'UI'; import FilterSource from '../FilterSource'; import { FilterKey, FilterType } from 'App/types/filter/filterType'; import SubFilterItem from '../SubFilterItem'; @@ -14,9 +14,10 @@ interface Props { onRemoveFilter: () => void; isFilter?: boolean; saveRequestPayloads?: boolean; + disableDelete?: boolean } function FilterItem(props: Props) { - const { isFilter = false, filterIndex, filter, saveRequestPayloads } = props; + const { isFilter = false, filterIndex, filter, saveRequestPayloads, disableDelete = false } = props; const canShowValues = !(filter.operator === 'isAny' || filter.operator === 'onAny' || filter.operator === 'isUndefined'); const isSubFilter = filter.type === FilterType.SUB_FILTERS; @@ -49,7 +50,7 @@ function FilterItem(props: Props) { }; return ( -
+
{!isFilter && (
@@ -102,10 +103,8 @@ function FilterItem(props: Props) {
)}
-
-
- -
+
+
); diff --git a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx index f6cbbec94..afdd02823 100644 --- a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx +++ b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx @@ -12,13 +12,15 @@ interface Props { hideEventsOrder?: boolean; observeChanges?: () => void; saveRequestPayloads?: boolean; + supportsEmpty?: boolean } function FilterList(props: Props) { - const { observeChanges = () => {}, filter, hideEventsOrder = false, saveRequestPayloads } = props; + const { observeChanges = () => {}, filter, hideEventsOrder = false, saveRequestPayloads, supportsEmpty = true } = props; const filters = List(filter.filters); const hasEvents = filters.filter((i: any) => i.isEvent).size > 0; const hasFilters = filters.filter((i: any) => !i.isEvent).size > 0; let rowIndex = 0; + const cannotDeleteFilter = filters.size === 1 && !supportsEmpty; useEffect(observeChanges, [filters]); @@ -69,6 +71,7 @@ function FilterList(props: Props) { onUpdate={(filter) => props.onUpdateFilter(filterIndex, filter)} onRemoveFilter={() => onRemoveFilter(filterIndex)} saveRequestPayloads={saveRequestPayloads} + disableDelete={cannotDeleteFilter} /> ) : null )} From 221e605cc476af8768d6a000211182c5c3c80b4a Mon Sep 17 00:00:00 2001 From: sylenien Date: Fri, 6 Jan 2023 13:15:53 +0100 Subject: [PATCH 2/4] fix(ui): fix default player data --- frontend/app/player/web/WebPlayer.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/app/player/web/WebPlayer.ts b/frontend/app/player/web/WebPlayer.ts index 089ad94c5..e27432daf 100644 --- a/frontend/app/player/web/WebPlayer.ts +++ b/frontend/app/player/web/WebPlayer.ts @@ -26,19 +26,18 @@ export default class WebPlayer extends Player { private targetMarker: TargetMarker constructor(protected wpState: Store, session: any, live: boolean) { - console.log(session.events, session.stackEvents, session.resources, session.errors) let initialLists = live ? {} : { - event: session.events, + event: session.events || [], stack: session.stackEvents || [], resource: session.resources || [], // MBTODO: put ResourceTiming in file - exceptions: session.errors.map(({ time, errorId, name }: any) => + exceptions: session.errors?.map(({ time, errorId, name }: any) => Log({ level: LogLevel.ERROR, value: name, time, errorId, }) - ), + ) || [], } const screen = new Screen(session.isMobile) From a30da5ef77f96a77ad149c9c6b57fdbb220983a7 Mon Sep 17 00:00:00 2001 From: sylenien Date: Fri, 6 Jan 2023 14:55:57 +0100 Subject: [PATCH 3/4] fix(ui): fix alert modal --- .../components/shared/AlertTriggersModal/AlertTriggersModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/components/shared/AlertTriggersModal/AlertTriggersModal.tsx b/frontend/app/components/shared/AlertTriggersModal/AlertTriggersModal.tsx index b76666962..594fa0f8b 100644 --- a/frontend/app/components/shared/AlertTriggersModal/AlertTriggersModal.tsx +++ b/frontend/app/components/shared/AlertTriggersModal/AlertTriggersModal.tsx @@ -31,7 +31,7 @@ function AlertTriggersModal(props: Props) { }, []) return useObserver(() => ( -
+
Alerts
{ count > 0 && ( From 9e7486c6b7309b7bc689253601cc39cb8f4ae846 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 6 Jan 2023 18:04:26 +0100 Subject: [PATCH 4/4] change(ui) - clickmaps disable first event selection and delete btn, also restrict the filters --- .../components/FilterSeries/FilterSeries.tsx | 4 ++ .../components/WidgetForm/WidgetForm.tsx | 6 +- .../shared/Filters/FilterItem/FilterItem.tsx | 7 ++- .../shared/Filters/FilterList/FilterList.tsx | 7 ++- .../Filters/FilterModal/FilterModal.tsx | 25 ++++++++- .../FilterSelection/FilterSelection.tsx | 56 ++++++++++++------- frontend/app/types/filter/newFilter.js | 2 + 7 files changed, 78 insertions(+), 29 deletions(-) diff --git a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx index c0de60d2d..49f3659da 100644 --- a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx @@ -15,6 +15,7 @@ interface Props { hideHeader?: boolean; emptyMessage?: any; observeChanges?: () => void; + excludeFilterKeys?: Array } function FilterSeries(props: Props) { @@ -25,6 +26,7 @@ function FilterSeries(props: Props) { hideHeader = false, emptyMessage = 'Add user event or filter to define the series by clicking Add Step.', supportsEmpty = true, + excludeFilterKeys = [] } = props; const [expanded, setExpanded] = useState(true) const { series, seriesIndex } = props; @@ -76,6 +78,7 @@ function FilterSeries(props: Props) { onRemoveFilter={onRemoveFilter} onChangeEventsOrder={onChangeEventsOrder} supportsEmpty={supportsEmpty} + excludeFilterKeys={excludeFilterKeys} /> ) : (
{emptyMessage}
@@ -86,6 +89,7 @@ function FilterSeries(props: Props) { diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx index a24db7391..d9eaf0e65 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx @@ -19,9 +19,8 @@ import { PERFORMANCE, WEB_VITALS, } from 'App/constants/card'; -import { clickmapFilter } from 'App/types/filter/newFilter'; +import { clickmapFilter, eventKeys } from 'App/types/filter/newFilter'; import { renderClickmapThumbnail } from './renderMap'; - interface Props { history: any; match: any; @@ -51,6 +50,8 @@ function WidgetForm(props: Props) { metric.metricType ); + const excludeFilterKeys = isClickmap ? eventKeys : [] + const writeOption = ({ value, name }: { value: any; name: any }) => { value = Array.isArray(value) ? value : value.value; const obj: any = { [name]: value }; @@ -202,6 +203,7 @@ function WidgetForm(props: Props) {
metric.updateKey('hasChanged', true)} hideHeader={isTable || isClickmap} seriesIndex={index} diff --git a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx index c76cc7938..854a15b75 100644 --- a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx +++ b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx @@ -14,10 +14,11 @@ interface Props { onRemoveFilter: () => void; isFilter?: boolean; saveRequestPayloads?: boolean; - disableDelete?: boolean + disableDelete?: boolean; + excludeFilterKeys?: Array; } function FilterItem(props: Props) { - const { isFilter = false, filterIndex, filter, saveRequestPayloads, disableDelete = false } = props; + const { isFilter = false, filterIndex, filter, saveRequestPayloads, disableDelete = false, excludeFilterKeys = [] } = props; const canShowValues = !(filter.operator === 'isAny' || filter.operator === 'onAny' || filter.operator === 'isUndefined'); const isSubFilter = filter.type === FilterType.SUB_FILTERS; @@ -57,7 +58,7 @@ function FilterItem(props: Props) { {filterIndex + 1}
)} - + {/* Filter with Source */} {filter.hasSource && ( diff --git a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx index afdd02823..521a70eeb 100644 --- a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx +++ b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx @@ -13,14 +13,15 @@ interface Props { observeChanges?: () => void; saveRequestPayloads?: boolean; supportsEmpty?: boolean + excludeFilterKeys?: Array } function FilterList(props: Props) { - const { observeChanges = () => {}, filter, hideEventsOrder = false, saveRequestPayloads, supportsEmpty = true } = props; + const { observeChanges = () => {}, filter, hideEventsOrder = false, saveRequestPayloads, supportsEmpty = true, excludeFilterKeys = [] } = props; const filters = List(filter.filters); const hasEvents = filters.filter((i: any) => i.isEvent).size > 0; const hasFilters = filters.filter((i: any) => !i.isEvent).size > 0; let rowIndex = 0; - const cannotDeleteFilter = filters.size === 1 && !supportsEmpty; + const cannotDeleteFilter = hasEvents && !supportsEmpty; useEffect(observeChanges, [filters]); @@ -72,6 +73,7 @@ function FilterList(props: Props) { onRemoveFilter={() => onRemoveFilter(filterIndex)} saveRequestPayloads={saveRequestPayloads} disableDelete={cannotDeleteFilter} + excludeFilterKeys={excludeFilterKeys} /> ) : null )} @@ -92,6 +94,7 @@ function FilterList(props: Props) { filter={filter} onUpdate={(filter) => props.onUpdateFilter(filterIndex, filter)} onRemoveFilter={() => onRemoveFilter(filterIndex)} + excludeFilterKeys={excludeFilterKeys} /> ) : null )} diff --git a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx index 5106dd8c6..fa259b9f6 100644 --- a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx +++ b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { Icon, Loader } from 'UI'; import { connect } from 'react-redux'; import cn from 'classnames'; @@ -6,10 +6,27 @@ import stl from './FilterModal.module.css'; import { filtersMap } from 'Types/filter/newFilter'; import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG'; +function filterJson( + jsonObj: Record, + excludeKeys: string[] = [] +): Record { + let filtered: Record = {}; + + for (const key in jsonObj) { + const arr = jsonObj[key].filter((i: any) => !excludeKeys.includes(i.key)); + if (arr.length) { + filtered[key] = arr; + } + } + + return filtered; +} + export const getMatchingEntries = (searchQuery: string, filters: Record) => { const matchingCategories: string[] = []; const matchingFilters: Record = {}; const lowerCaseQuery = searchQuery.toLowerCase(); + if (lowerCaseQuery.length === 0) return { matchingCategories: Object.keys(filters), matchingFilters: filters, @@ -33,12 +50,13 @@ export const getMatchingEntries = (searchQuery: string, filters: Record void, + onFilterClick?: (filter: any) => void, filterSearchList: any, // metaOptions: any, isMainSearch?: boolean, fetchingFilterSearchList: boolean, searchQuery?: string, + excludeFilterKeys?: Array } function FilterModal(props: Props) { const { @@ -48,6 +66,7 @@ function FilterModal(props: Props) { isMainSearch = false, fetchingFilterSearchList, searchQuery = '', + excludeFilterKeys = [] } = props; const showSearchList = isMainSearch && searchQuery.length > 0; @@ -57,7 +76,7 @@ function FilterModal(props: Props) { onFilterClick(_filter); } - const { matchingCategories, matchingFilters } = getMatchingEntries(searchQuery, filters); + const { matchingCategories, matchingFilters } = getMatchingEntries(searchQuery, filterJson(filters, excludeFilterKeys)); const isResultEmpty = (!filterSearchList || Object.keys(filterSearchList).length === 0) && matchingCategories.length === 0 && Object.keys(matchingFilters).length === 0 diff --git a/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx b/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx index d4e20d322..e78904936 100644 --- a/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx +++ b/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx @@ -3,7 +3,8 @@ import FilterModal from '../FilterModal'; import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; import { Icon } from 'UI'; import { connect } from 'react-redux'; -import { assist as assistRoute, isRoute } from "App/routes"; +import { assist as assistRoute, isRoute } from 'App/routes'; +import cn from 'classnames'; const ASSIST_ROUTE = assistRoute(); @@ -14,40 +15,54 @@ interface Props { onFilterClick: (filter: any) => void; children?: any; isLive?: boolean; + excludeFilterKeys?: Array + disabled?: boolean } function FilterSelection(props: Props) { - const { filter, onFilterClick, children } = props; + const { filter, onFilterClick, children, excludeFilterKeys = [], disabled = false } = props; const [showModal, setShowModal] = useState(false); return (
setTimeout(function() { - setShowModal(false) - }, 200)} + onClickOutside={() => + setTimeout(function () { + setShowModal(false); + }, 200) + } > - { children ? React.cloneElement(children, { onClick: (e) => { - e.stopPropagation(); - e.preventDefault(); - setShowModal(true); - }}) : ( + {children ? ( + React.cloneElement(children, { + onClick: (e) => { + e.stopPropagation(); + e.preventDefault(); + setShowModal(true); + }, + disabled: disabled + }) + ) : (
setShowModal(true)} > -
{filter.label}
+
+ {filter.label} +
- ) } + )}
{showModal && (
)} @@ -55,8 +70,11 @@ function FilterSelection(props: Props) { ); } -export default connect((state: any) => ({ - filterList: state.getIn([ 'search', 'filterList' ]), - filterListLive: state.getIn([ 'search', 'filterListLive' ]), - isLive: state.getIn([ 'sessions', 'activeTab' ]).type === 'live', -}), { })(FilterSelection); \ No newline at end of file +export default connect( + (state: any) => ({ + filterList: state.getIn(['search', 'filterList']), + filterListLive: state.getIn(['search', 'filterListLive']), + isLive: state.getIn(['sessions', 'activeTab']).type === 'live', + }), + {} +)(FilterSelection); diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index 488eb0331..2f4ffe127 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -53,6 +53,8 @@ export const filters = [ { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', placeholder: 'Select an issue', operator: 'is', operatorOptions: filterOptions.getOperatorsByKeys(['is', 'isAny', 'isNot']), icon: 'filters/click', options: filterOptions.issueOptions }, ]; +export const eventKeys = filters.filter((i) => i.isEvent).map(i => i.key); + export const clickmapFilter = { key: FilterKey.LOCATION, type: FilterType.MULTIPLE,