From 5fcc974382d5872be9cb87cf7755dbb5bcd2b2d9 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Tue, 14 Jan 2025 11:58:51 +0100 Subject: [PATCH] ui: further changes for search/cards --- frontend/app/components/Alerts/AlertForm.js | 7 + .../CustomMetricsWidgets/BigNumChart.tsx | 28 ++-- .../NewDashModal/ExampleCards.tsx | 41 ++---- .../components/FilterSeries/FilterSeries.tsx | 26 ++-- .../components/WidgetForm/WidgetFormNew.tsx | 128 ++++++++++++++---- .../components/WidgetView/WidgetView.tsx | 2 +- .../shared/Filters/FilterItem/FilterItem.tsx | 3 + .../shared/Filters/FilterList/FilterList.tsx | 9 +- .../Filters/FilterModal/FilterModal.tsx | 22 ++- .../FilterSelection/FilterSelection.tsx | 3 + .../Filters/FilterValue/FilterValue.tsx | 3 +- frontend/app/mstore/customFieldStore.ts | 73 +++++++--- frontend/app/mstore/filterStore.ts | 1 - frontend/app/types/filter/filterType.ts | 3 +- frontend/app/types/filter/newFilter.js | 27 ++-- 15 files changed, 251 insertions(+), 125 deletions(-) diff --git a/frontend/app/components/Alerts/AlertForm.js b/frontend/app/components/Alerts/AlertForm.js index bf3a0f58d..da3b74148 100644 --- a/frontend/app/components/Alerts/AlertForm.js +++ b/frontend/app/components/Alerts/AlertForm.js @@ -60,6 +60,13 @@ function AlertForm(props) { const triggerOptions = metricStore.instance.series.length > 0 ? allTriggerSeries.filter(s => { return metricStore.instance.series.findIndex(ms => ms.seriesId === s.value) !== -1 + }).map(v => { + const labelArr = v.label.split('.') + labelArr.shift() + return { + ...v, + label: labelArr.join('.') + } }) : allTriggerSeries const instance = alertsStore.instance const deleting = loading diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/BigNumChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/BigNumChart.tsx index 01d4ca2e8..56df66377 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/BigNumChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/BigNumChart.tsx @@ -18,19 +18,21 @@ function BigNumChart(props: Props) { onSeriesFocus, } = props; return ( -
- {values.map((val, i) => ( - - ))} +
+
+ {values.map((val, i) => ( + + ))} +
) } diff --git a/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/ExampleCards.tsx b/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/ExampleCards.tsx index 49a7748df..bf9c9e812 100644 --- a/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/ExampleCards.tsx +++ b/frontend/app/components/Dashboard/components/DashboardList/NewDashModal/ExampleCards.tsx @@ -9,24 +9,13 @@ import { HEATMAP, ERRORS, FUNNEL, - INSIGHTS, TABLE, TIMESERIES, USER_PATH, - PERFORMANCE, RETENTION } from "App/constants/card"; import { FilterKey } from 'Types/filter/filterType'; import { BarChart, TrendingUp, SearchSlash } from 'lucide-react'; -import ByIssues from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/SessionsBy/ByIssues'; -import InsightsExample from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/InsightsExample'; import ByUser from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/SessionsBy/ByUser'; -import BarChartCard from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/BarChart'; -import SpeedIndexByLocationExample - from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/SpeedIndexByLocationExample'; -import CallsWithErrorsExample - from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/CallsWithErrorsExample'; -import SlowestDomains - from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/SessionsBy/SlowestDomains'; import HeatmapsExample from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/HeatmapsExample'; import ByReferrer from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/SessionsBy/ByRferrer'; import ByFetch from 'Components/Dashboard/components/DashboardList/NewDashModal/Examples/SessionsBy/ByFecth'; @@ -60,7 +49,7 @@ export interface CardType { export const CARD_LIST: CardType[] = [ { - title: 'Funnel', + title: 'Untitled Funnel', key: FUNNEL, cardType: FUNNEL, category: CARD_CATEGORIES[0].key, @@ -92,7 +81,7 @@ export const CARD_LIST: CardType[] = [ } }, { - title: 'Heatmaps', + title: 'Untitled Heatmaps', key: HEATMAP, cardType: HEATMAP, metricOf: 'heatMapUrl', @@ -100,14 +89,14 @@ export const CARD_LIST: CardType[] = [ example: HeatmapsExample }, { - title: 'Journey', + title: 'Untitled Journey', key: USER_PATH, cardType: USER_PATH, category: CARD_CATEGORIES[0].key, example: ExamplePath }, { - title: 'Trend', + title: 'Untitled Trend', key: TIMESERIES, cardType: TIMESERIES, metricOf: 'sessionCount', @@ -122,7 +111,7 @@ export const CARD_LIST: CardType[] = [ example: ExampleTrend }, { - title: 'Users Trend', + title: 'Untitled Users Trend', key: TIMESERIES + '_userCount', cardType: TIMESERIES, metricOf: 'userCount', @@ -140,7 +129,7 @@ export const CARD_LIST: CardType[] = [ // Web analytics { - title: 'Top Users', + title: 'Untitled Top Users', key: FilterKey.USERID, cardType: TABLE, metricOf: FilterKey.USERID, @@ -149,7 +138,7 @@ export const CARD_LIST: CardType[] = [ }, { - title: 'Top Browsers', + title: 'Untitled Top Browsers', key: FilterKey.USER_BROWSER, cardType: TABLE, metricOf: FilterKey.USER_BROWSER, @@ -165,7 +154,7 @@ export const CARD_LIST: CardType[] = [ // example: BySystem, // }, { - title: 'Top Countries', + title: 'Untitled Top Countries', key: FilterKey.USER_COUNTRY, cardType: TABLE, metricOf: FilterKey.USER_COUNTRY, @@ -174,7 +163,7 @@ export const CARD_LIST: CardType[] = [ }, { - title: 'Top Devices', + title: 'Untitled Top Devices', key: FilterKey.USER_DEVICE, cardType: TABLE, metricOf: FilterKey.USER_DEVICE, @@ -182,7 +171,7 @@ export const CARD_LIST: CardType[] = [ example: BySystem }, { - title: 'Top Pages', + title: 'Untitled Top Pages', key: FilterKey.LOCATION, cardType: TABLE, metricOf: FilterKey.LOCATION, @@ -191,7 +180,7 @@ export const CARD_LIST: CardType[] = [ }, { - title: 'Top Referrer', + title: 'Untitled Top Referrer', key: FilterKey.REFERRER, cardType: TABLE, metricOf: FilterKey.REFERRER, @@ -201,7 +190,7 @@ export const CARD_LIST: CardType[] = [ // Monitors { - title: 'Table of Errors', + title: 'Untitled Table of Errors', key: FilterKey.ERRORS, cardType: TABLE, metricOf: FilterKey.ERRORS, @@ -216,7 +205,7 @@ export const CARD_LIST: CardType[] = [ example: TableOfErrors }, { - title: 'Top Network Requests', + title: 'Untitled Top Network Requests', key: FilterKey.FETCH, cardType: TABLE, metricOf: FilterKey.FETCH, @@ -224,7 +213,7 @@ export const CARD_LIST: CardType[] = [ example: ByFetch }, { - title: 'Sessions with 4xx/5xx Requests', + title: 'Untitled Sessions with 4xx/5xx Requests', key: TIMESERIES + '_4xx_requests', cardType: TIMESERIES, metricOf: 'sessionCount', @@ -258,7 +247,7 @@ export const CARD_LIST: CardType[] = [ example: ExampleTrend }, { - title: 'Sessions with Slow Network Requests', + title: 'Untitled Sessions with Slow Network Requests', key: TIMESERIES + '_slow_network_requests', cardType: TIMESERIES, metricOf: 'sessionCount', diff --git a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx index ae92828b8..814d0a14c 100644 --- a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx @@ -118,11 +118,13 @@ interface Props { emptyMessage?: any; observeChanges?: () => void; excludeFilterKeys?: Array; + excludeCategory?: string[] canExclude?: boolean; expandable?: boolean; isHeatmap?: boolean; removeEvents?: boolean; - defaultClosed?: boolean; + collapseState: boolean; + onToggleCollapse: () => void; } function FilterSeries(props: Props) { @@ -137,23 +139,13 @@ function FilterSeries(props: Props) { expandable = false, isHeatmap, removeEvents, - defaultClosed, + collapseState, + onToggleCollapse, + excludeCategory } = props; - const [expanded, setExpanded] = useState(!defaultClosed || hideHeader); + const expanded = !collapseState + const setExpanded = onToggleCollapse const { series, seriesIndex } = props; - const [prevLength, setPrevLength] = useState(0); - - useEffect(() => { - if ( - series.filter.filters.length === 1 && - prevLength === 0 && - seriesIndex === 0 && - !defaultClosed - ) { - setExpanded(true); - } - setPrevLength(series.filter.filters.length); - }, [series.filter.filters.length, defaultClosed]); const onUpdateFilter = (filterIndex: any, filter: any) => { series.filter.updateFilter(filterIndex, filter); @@ -234,6 +226,7 @@ function FilterSeries(props: Props) { mergeUp={!hideHeader} mergeDown cannotAdd={isHeatmap} + excludeCategory={excludeCategory} /> } ) : null} diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx index 939b78e69..46f1ba14f 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Card, Space, Button, Alert, Form, Select } from 'antd'; +import { Card, Space, Button, Alert, Form, Select, Tooltip } from 'antd'; import { useStore } from 'App/mstore'; import { eventKeys } from 'Types/filter/newFilter'; import { @@ -13,18 +13,37 @@ import { } from 'App/constants/card'; import FilterSeries from 'Components/Dashboard/components/FilterSeries/FilterSeries'; import { issueCategories } from 'App/constants/filterOptions'; -import { PlusIcon } from 'lucide-react'; +import { PlusIcon, ChevronUp } from 'lucide-react'; import { observer } from 'mobx-react-lite'; import FilterItem from 'Shared/Filters/FilterItem'; -import { FilterKey } from 'Types/filter/filterType'; +import { FilterKey, FilterCategory } from 'Types/filter/filterType'; -function WidgetFormNew() { +const getExcludedKeys = (metricType: string) => { + switch (metricType) { + case USER_PATH: + case HEATMAP: + return eventKeys; + default: + return []; + } +} + +const getExcludedCategories = (metricType: string) => { + switch (metricType) { + case USER_PATH: + case FUNNEL: + return [FilterCategory.DEVTOOLS] + default: + return []; + } +} + +function WidgetFormNew({ layout }: { layout: string }) { const { metricStore } = useStore(); const metric: any = metricStore.instance; + const excludeFilterKeys = getExcludedKeys(metric.metricType); + const excludeCategory = getExcludedCategories(metric.metricType); - const isHeatMap = metric.metricType === HEATMAP; - const isPathAnalysis = metric.metricType === USER_PATH; - const excludeFilterKeys = isHeatMap || isPathAnalysis ? eventKeys : []; const isPredefined = metric.metricType === ERRORS; return isPredefined ? ( @@ -32,16 +51,36 @@ function WidgetFormNew() { ) : ( - + ); } export default observer(WidgetFormNew); -const FilterSection = observer(({ metric, excludeFilterKeys }: any) => { - const defaultClosed = React.useRef(metric.exists()); - const defaultSeries = React.useRef(metric.series.map((s) => s.name)); +const FilterSection = observer(({ layout, metric, excludeFilterKeys, excludeCategory }: any) => { + const allOpen = layout.startsWith('flex-row'); + const defaultClosed = React.useRef(!allOpen && metric.exists()); + const [seriesCollapseState, setSeriesCollapseState] = React.useState>({}); + + React.useEffect(() => { + const defaultSeriesCollapseState: Record = {}; + metric.series.forEach((s: any) => { + defaultSeriesCollapseState[s.seriesId] = defaultSeriesCollapseState[ + s.seriesId + ] + ? defaultSeriesCollapseState[s.seriesId] + : allOpen + ? false + : defaultClosed.current; + }); + setSeriesCollapseState(defaultSeriesCollapseState); + }, [metric.series]); const isTable = metric.metricType === TABLE; const isHeatMap = metric.metricType === HEATMAP; const isFunnel = metric.metricType === FUNNEL; @@ -57,6 +96,27 @@ const FilterSection = observer(({ metric, excludeFilterKeys }: any) => { isInsights || isRetention || isPathAnalysis; + + const collapseAll = () => { + setSeriesCollapseState((seriesCollapseState) => { + const newState = { ...seriesCollapseState }; + Object.keys(newState).forEach((key) => { + newState[key] = true; + }); + return newState; + }); + } + const expandAll = () => { + setSeriesCollapseState((seriesCollapseState) => { + const newState = { ...seriesCollapseState }; + Object.keys(newState).forEach((key) => { + newState[key] = false; + }); + return newState; + }); + } + + const allCollapsed = Object.values(seriesCollapseState).every((v) => v); return ( <> {metric.series.length > 0 && @@ -70,6 +130,7 @@ const FilterSection = observer(({ metric, excludeFilterKeys }: any) => { removeEvents={isPathAnalysis} supportsEmpty={!isHeatMap && !isPathAnalysis} excludeFilterKeys={excludeFilterKeys} + excludeCategory={excludeCategory} observeChanges={() => metric.updateKey('hasChanged', true)} hideHeader={ isTable || @@ -82,11 +143,13 @@ const FilterSection = observer(({ metric, excludeFilterKeys }: any) => { series={series} onRemoveSeries={() => metric.removeSeries(index)} canDelete={metric.series.length > 1} - defaultClosed={ - metric.hasChanged - ? defaultSeries.current.includes(series.name) - : defaultClosed.current - } + collapseState={seriesCollapseState[series.seriesId]} + onToggleCollapse={() => { + setSeriesCollapseState((seriesCollapseState) => ({ + ...seriesCollapseState, + [series.seriesId]: !seriesCollapseState[series.seriesId], + })); + }} emptyMessage={ isTable ? 'Filter data using any event or attribute. Use Add Step button below to do so.' @@ -96,21 +159,30 @@ const FilterSection = observer(({ metric, excludeFilterKeys }: any) => { />
))} - - {!isSingleSeries && canAddSeries && ( +
+ + + - )} +
); }); diff --git a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx index a6b197dae..6a6b05674 100644 --- a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx +++ b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx @@ -198,7 +198,7 @@ function WidgetView(props: Props) { />
- +
diff --git a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx index dceb4513b..28df71ae1 100644 --- a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx +++ b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx @@ -18,6 +18,7 @@ interface Props { saveRequestPayloads?: boolean; disableDelete?: boolean; excludeFilterKeys?: Array; + excludeCategory?: Array; allowedFilterKeys?: Array; readonly?: boolean; hideIndex?: boolean; @@ -35,6 +36,7 @@ function FilterItem(props: Props) { hideDelete = false, allowedFilterKeys = [], excludeFilterKeys = [], + excludeCategory = [], isConditional, hideIndex = false, } = props; @@ -84,6 +86,7 @@ function FilterItem(props: Props) { onFilterClick={replaceFilter} allowedFilterKeys={allowedFilterKeys} excludeFilterKeys={excludeFilterKeys} + excludeCategory={excludeCategory} disabled={disableDelete || props.readonly} /> diff --git a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx index 2fb928b9c..e2352fe7f 100644 --- a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx +++ b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx @@ -8,7 +8,7 @@ import EventsOrder from 'Shared/Filters/FilterList/EventsOrder'; import FilterSelection from '../FilterSelection/FilterSelection'; interface Props { - filter?: any; // event/filter + filter?: any; onUpdateFilter: (filterIndex: any, filter: any) => void; onFilterMove?: (filters: any) => void; onRemoveFilter: (filterIndex: any) => void; @@ -19,6 +19,7 @@ interface Props { supportsEmpty?: boolean; readonly?: boolean; excludeFilterKeys?: Array; + excludeCategory?: string[]; isConditional?: boolean; actions?: React.ReactNode[]; onAddFilter: (filter: any) => void; @@ -37,6 +38,7 @@ export const FilterList = observer((props: Props) => { onAddFilter, readonly, borderless, + excludeCategory, } = props; const filters = filter.filters; @@ -65,6 +67,8 @@ export const FilterList = observer((props: Props) => { filter={undefined} onFilterClick={onAddFilter} disabled={readonly} + excludeFilterKeys={excludeFilterKeys} + excludeCategory={excludeCategory} >
) : null diff --git a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx index 18f4a23a7..17667c4cc 100644 --- a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx +++ b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx @@ -36,7 +36,7 @@ import { Icon, Loader } from 'UI'; import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG'; import { Input } from 'antd'; -import { FilterKey } from 'Types/filter/filterType'; +import { FilterCategory, FilterKey } from "Types/filter/filterType"; import stl from './FilterModal.module.css'; import { observer } from 'mobx-react-lite'; import { useStore } from 'App/mstore'; @@ -80,13 +80,15 @@ export const IconMap = { function filterJson( jsonObj: Record, excludeKeys: string[] = [], + excludeCategory: string[] = [], allowedFilterKeys: string[] = [], mode: 'filters' | 'events' ): Record { return Object.fromEntries( Object.entries(jsonObj) .map(([key, value]) => { - const arr = value.filter((i: { key: string, isEvent: boolean }) => { + const arr = value.filter((i: { key: string, isEvent: boolean, category: string }) => { + if (excludeCategory.includes(i.category)) return false; if (excludeKeys.includes(i.key)) return false; if (mode === 'events' && !i.isEvent) return false; if (mode === 'filters' && i.isEvent) return false; @@ -139,6 +141,7 @@ interface Props { isMainSearch?: boolean; searchQuery?: string; excludeFilterKeys?: Array; + excludeCategory?: Array; allowedFilterKeys?: Array; isConditional?: boolean; isMobile?: boolean; @@ -162,6 +165,7 @@ function FilterModal(props: Props) { onFilterClick = () => null, isMainSearch = false, excludeFilterKeys = [], + excludeCategory = [], allowedFilterKeys = [], isConditional, mode, @@ -185,10 +189,18 @@ function FilterModal(props: Props) { ? searchStoreLive.loadingFilterSearch : searchStore.loadingFilterSearch; + const parseAndAdd = (filter) => { + if (filter.category === FilterCategory.EVENTS && filter.key.startsWith('_')) { + filter.value = [filter.key.substring(1)]; + filter.key = FilterKey.CUSTOM; + filter.label = 'Custom Events' + } + onFilterClick(filter) + } const onFilterSearchClick = (filter: any) => { const _filter = { ...filtersMap[filter.type] }; _filter.value = [filter.value]; - onFilterClick(_filter); + parseAndAdd(_filter); }; const filterJsonObj = isConditional @@ -198,7 +210,7 @@ function FilterModal(props: Props) { : filters; const { matchingCategories, matchingFilters } = getMatchingEntries( searchQuery, - filterJson(filterJsonObj, excludeFilterKeys, allowedFilterKeys, mode) + filterJson(filterJsonObj, excludeFilterKeys, excludeCategory, allowedFilterKeys, mode) ); const isResultEmpty = @@ -247,7 +259,7 @@ function FilterModal(props: Props) { className={cn( 'flex items-center p-2 cursor-pointer gap-1 rounded-lg hover:bg-active-blue' )} - onClick={() => onFilterClick({ ...filter })} + onClick={() => parseAndAdd({ ...filter })} > {filter.category ?
{filter.category} diff --git a/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx b/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx index 77bed5ccb..1fdfd970a 100644 --- a/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx +++ b/frontend/app/components/shared/Filters/FilterSelection/FilterSelection.tsx @@ -13,6 +13,7 @@ interface Props { onFilterClick: (filter: any) => void; children?: any; excludeFilterKeys?: Array; + excludeCategory?: Array; allowedFilterKeys?: Array; disabled?: boolean; isConditional?: boolean; @@ -26,6 +27,7 @@ function FilterSelection(props: Props) { onFilterClick, children, excludeFilterKeys = [], + excludeCategory = [], allowedFilterKeys = [], disabled = false, isConditional, @@ -86,6 +88,7 @@ function FilterSelection(props: Props) { onFilterClick={onAddFilter} excludeFilterKeys={excludeFilterKeys} allowedFilterKeys={allowedFilterKeys} + excludeCategory={excludeCategory} isConditional={isConditional} isMobile={isMobile} mode={mode} diff --git a/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx b/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx index 22ce8433e..f365ddeac 100644 --- a/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx +++ b/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx @@ -18,9 +18,8 @@ interface Props { } function FilterValue(props: Props) { const { filter } = props; - const isEvent = filter.isEvent; const [durationValues, setDurationValues] = useState({ - minDuration: filter.value[0], + minDuration: filter.value?.[0], maxDuration: filter.value.length > 1 ? filter.value[1] : filter.value[0], }); const showCloseButton = filter.value.length > 1; diff --git a/frontend/app/mstore/customFieldStore.ts b/frontend/app/mstore/customFieldStore.ts index f5502615d..a4d2de3fd 100644 --- a/frontend/app/mstore/customFieldStore.ts +++ b/frontend/app/mstore/customFieldStore.ts @@ -1,17 +1,16 @@ import { makeAutoObservable } from 'mobx'; -import { customFieldService } from 'App/services'; - +import { customFieldService, filterService } from 'App/services'; import { addElementToConditionalFiltersMap, addElementToMobileConditionalFiltersMap, addElementToFiltersMap, addElementToFlagConditionsMap, addElementToLiveFiltersMap, - clearMetaFilters + clearMetaFilters, } from 'Types/filter/newFilter'; -import { FilterCategory } from 'Types/filter/filterType'; +import { FilterCategory, FilterType } from "Types/filter/filterType"; import CustomField from 'App/mstore/types/customField'; -import customFields from 'Components/Client/CustomFields'; +import filterOptions from 'App/constants'; class CustomFieldStore { isLoading: boolean = false; @@ -48,14 +47,40 @@ class CustomFieldStore { const response = await customFieldService.fetchList(siteId); clearMetaFilters(); response.forEach((item: any) => { - addElementToFiltersMap(FilterCategory.METADATA, '_' + item.key); - addElementToLiveFiltersMap(FilterCategory.METADATA, '_' + item.key); - addElementToFlagConditionsMap(FilterCategory.METADATA, '_' + item.key); - addElementToConditionalFiltersMap(FilterCategory.METADATA, '_' + item.key); - addElementToMobileConditionalFiltersMap(FilterCategory.METADATA, '_' + item.key); + const calls = [ + addElementToFiltersMap, + addElementToLiveFiltersMap, + addElementToFlagConditionsMap, + addElementToConditionalFiltersMap, + addElementToMobileConditionalFiltersMap, + ]; + calls.forEach((call) => { + call(FilterCategory.METADATA, '_' + item.key); + }); }); this.list = response.map((item_1: any) => new CustomField(item_1)); this.fetchedMetadata = true; + filterService.fetchTopValues('custom', undefined).then((response: []) => { + response.forEach((item: any) => { + const calls = [ + addElementToFiltersMap, + addElementToFlagConditionsMap, + addElementToConditionalFiltersMap, + addElementToMobileConditionalFiltersMap, + ]; + calls.forEach((call) => { + call( + FilterCategory.EVENTS, + '_' + item.value, + FilterType.MULTIPLE, + 'is', + filterOptions.stringOperators, + 'filters/custom', + true + ); + }); + }); + }); } finally { this.isLoading = false; } @@ -65,11 +90,14 @@ class CustomFieldStore { this.isLoading = true; try { const response = await customFieldService.get('/integration/sources'); - this.sources = response.map(({ value, ...item }: any) => new CustomField({ - label: value, - key: value, - ...item - })); + this.sources = response.map( + ({ value, ...item }: any) => + new CustomField({ + label: value, + key: value, + ...item, + }) + ); } finally { this.isLoading = false; } @@ -79,16 +107,18 @@ class CustomFieldStore { this.isSaving = true; try { const wasCreating = !instance.exists(); - const response = wasCreating ? await customFieldService.create(siteId, instance.toData()) : - await customFieldService.update(siteId, instance.toData()); + const response = wasCreating + ? await customFieldService.create(siteId, instance.toData()) + : await customFieldService.update(siteId, instance.toData()); const updatedInstance = new CustomField(response); if (wasCreating) { this.list.push(updatedInstance); } else { - const index = this.list.findIndex(item => item.index === instance.index); - if (index >= 0) - this.list[index] = updatedInstance; + const index = this.list.findIndex( + (item) => item.index === instance.index + ); + if (index >= 0) this.list[index] = updatedInstance; } } finally { this.isSaving = false; @@ -99,7 +129,7 @@ class CustomFieldStore { this.isSaving = true; try { await customFieldService.delete(siteId, index); - this.list = this.list.filter(item => item.index !== index); + this.list = this.list.filter((item) => item.index !== index); } finally { this.isSaving = false; } @@ -115,5 +145,4 @@ class CustomFieldStore { } } - export default CustomFieldStore; diff --git a/frontend/app/mstore/filterStore.ts b/frontend/app/mstore/filterStore.ts index 3ffd9023c..b9d8d5736 100644 --- a/frontend/app/mstore/filterStore.ts +++ b/frontend/app/mstore/filterStore.ts @@ -1,5 +1,4 @@ import { makeAutoObservable } from 'mobx'; -import { filters } from 'Types/filter/newFilter'; import { filterService } from 'App/services'; interface TopValue { diff --git a/frontend/app/types/filter/filterType.ts b/frontend/app/types/filter/filterType.ts index 91ddf0aa3..1e951f774 100644 --- a/frontend/app/types/filter/filterType.ts +++ b/frontend/app/types/filter/filterType.ts @@ -1,10 +1,11 @@ export enum FilterCategory { AUTOCAPTURE = 'Autocapture', - DEVTOOLS = 'Devtools', + DEVTOOLS = 'DevTools', USER = 'User', METADATA = 'Metadata', SESSION = 'Session', ISSUE = 'Issue', + EVENTS = 'Events', } export const setQueryParamKeyFromFilterkey = (filterKey: string) => { diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index 17c2cc860..8c5761b5f 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -135,7 +135,7 @@ export const filters = [ { key: FilterKey.CUSTOM, type: FilterType.MULTIPLE, - category: FilterCategory.DEVTOOLS, + category: FilterCategory.EVENTS, label: 'Custom Events', placeholder: 'Enter event key', operator: 'is', @@ -951,6 +951,7 @@ export const clearMetaFilters = () => { * @param {*} operator * @param {*} operatorOptions * @param {*} icon + * @param {*} isEvent */ export const addElementToFiltersMap = ( category = FilterCategory.METADATA, @@ -958,7 +959,8 @@ export const addElementToFiltersMap = ( type = FilterType.MULTIPLE, operator = 'is', operatorOptions = filterOptions.stringOperators, - icon = 'filters/metadata' + icon = 'filters/metadata', + isEvent = false ) => { filtersMap[key] = { key, @@ -969,7 +971,8 @@ export const addElementToFiltersMap = ( operator: operator, operatorOptions, icon, - isLive: true + isLive: true, + isEvent, }; }; @@ -992,7 +995,8 @@ export const addElementToFlagConditionsMap = ( type = FilterType.MULTIPLE, operator = 'is', operatorOptions = filterOptions.stringOperators, - icon = 'filters/metadata' + icon = 'filters/metadata', + isEvent = false ) => { fflagsConditionsMap[key] = { key, @@ -1002,7 +1006,8 @@ export const addElementToFlagConditionsMap = ( operator: operator, operatorOptions, icon, - isLive: true + isLive: true, + isEvent, }; }; @@ -1012,7 +1017,8 @@ export const addElementToConditionalFiltersMap = ( type = FilterType.MULTIPLE, operator = 'is', operatorOptions = filterOptions.stringOperators, - icon = 'filters/metadata' + icon = 'filters/metadata', + isEvent = false ) => { conditionalFiltersMap[key] = { key, @@ -1022,7 +1028,8 @@ export const addElementToConditionalFiltersMap = ( operator: operator, operatorOptions, icon, - isLive: true + isLive: true, + isEvent, }; }; @@ -1032,7 +1039,8 @@ export const addElementToMobileConditionalFiltersMap = ( type = FilterType.MULTIPLE, operator = 'is', operatorOptions = filterOptions.stringOperators, - icon = 'filters/metadata' + icon = 'filters/metadata', + isEvent = false ) => { mobileConditionalFiltersMap[key] = { key, @@ -1042,7 +1050,8 @@ export const addElementToMobileConditionalFiltersMap = ( operator: operator, operatorOptions, icon, - isLive: true + isLive: true, + isEvent, }; };