From 79f3cb7d98b20eae5af8c67ccad14ab40a9cb4b4 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 15 Jan 2025 15:18:18 +0100 Subject: [PATCH] ui: fix alert pre-init function, fix metric list options, fix legend placement --- .../CustomMetricsWidgets/BigNumChart.tsx | 32 +++++--- .../DashboardList/DashboardList.tsx | 82 ++++++++++--------- .../components/WidgetChart/WidgetChart.tsx | 1 + .../components/WidgetForm/WidgetFormNew.tsx | 49 ++++++----- .../components/WidgetWrapper/AlertButton.tsx | 11 ++- .../WidgetWrapper/WidgetWrapperNew.tsx | 7 +- .../Filters/FilterModal/FilterModal.tsx | 14 ++-- frontend/app/mstore/customFieldStore.ts | 43 +++++----- frontend/app/types/filter/newFilter.js | 76 ++++++++++------- 9 files changed, 180 insertions(+), 135 deletions(-) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/BigNumChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/BigNumChart.tsx index 56df66377..3f22c9103 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/BigNumChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/BigNumChart.tsx @@ -16,6 +16,7 @@ function BigNumChart(props: Props) { label = 'Number of Sessions', values, onSeriesFocus, + hideLegend, } = props; return (
@@ -23,6 +24,7 @@ function BigNumChart(props: Props) { {values.map((val, i) => ( void + hideLegend?: boolean }) { const formattedNumber = (num: number) => { return Intl.NumberFormat().format(num); @@ -66,21 +69,28 @@ function BigNum({ color, series, value, label, compData, valueLabel, onSeriesFoc 'hover:transition-all ease-in-out hover:ease-in-out hover:bg-teal/5 hover:cursor-pointer' )} > -
-
-
{series}
-
+ {hideLegend ? null : +
+
+
{series}
+
+ }
- {formattedNumber(value)}{valueLabel ? `${valueLabel}` : null} -
-
- {label} + {formattedNumber(value)} + {valueLabel ? `${valueLabel}` : null}
+
{label}
{compData ? ( - compData} absDelta={change} delta={changePercent} /> + compData} + absDelta={change} + delta={changePercent} + /> ) : null}
- ) + ); } export default BigNumChart; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx b/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx index cf4f9a1e6..360e70109 100644 --- a/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx +++ b/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx @@ -1,4 +1,3 @@ - import { observer } from 'mobx-react-lite'; import React from 'react'; import { useHistory } from 'react-router'; @@ -105,7 +104,7 @@ function DashboardList() { } checkedChildren={'Team'} unCheckedChildren={'Private'} - className='toggle-team-private' + className="toggle-team-private" />
@@ -128,41 +127,48 @@ function DashboardList() { dataIndex: 'dashboardId', width: '5%', render: (id) => ( - , - key: 'rename', - label: 'Rename', +
e.stopPropagation()}> + , + key: 'rename', + label: 'Rename', + }, + { + icon: , + key: 'access', + label: 'Visibility & Access', + }, + { + icon: , + key: 'delete', + label: 'Delete', + }, + ], + onClick: async ({ key }) => { + if (key === 'rename') { + onEdit(id, true); + } else if (key === 'access') { + onEdit(id, false); + } else if (key === 'delete') { + await onDelete(id); + } }, - { - icon: , - key: 'access', - label: 'Visibility & Access', - }, - { - icon: , - key: 'delete', - label: 'Delete', - }, - ], - onClick: async ({ key }) => { - if (key === 'rename') { - onEdit(id, true); - } else if (key === 'access') { - onEdit(id, false); - } else if (key === 'delete') { - await onDelete(id); - } - }, - }} - > -
), }, ]; @@ -230,10 +236,12 @@ function DashboardList() { onClick: (e) => { const possibleDropdown = document.querySelector('.ant-dropdown-menu'); + const btn = document.querySelector('#ignore-prop'); if ( e.target.classList.contains('lucide') || e.target.id === 'ignore-prop' || - possibleDropdown?.contains(e.target) + possibleDropdown?.contains(e.target) || + btn?.contains(e.target) ) { return; } diff --git a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx index 0c0947071..8c93c147e 100644 --- a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx +++ b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx @@ -253,6 +253,7 @@ function WidgetChart(props: Props) { values={values} inGrid={!props.isPreview} colors={colors} + hideLegend onClick={onChartClick} label={ 'Conversion' diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx index 46f1ba14f..cce9d5457 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx @@ -159,30 +159,37 @@ const FilterSection = observer(({ layout, metric, excludeFilterKeys, excludeCate />
))} -
- + {isSingleSeries ? null : +
+ + + - - -
+
+ } ); }); diff --git a/frontend/app/components/Dashboard/components/WidgetWrapper/AlertButton.tsx b/frontend/app/components/Dashboard/components/WidgetWrapper/AlertButton.tsx index c9cbac62f..3cacb3d25 100644 --- a/frontend/app/components/Dashboard/components/WidgetWrapper/AlertButton.tsx +++ b/frontend/app/components/Dashboard/components/WidgetWrapper/AlertButton.tsx @@ -12,16 +12,15 @@ interface Props { } function AlertButton(props: Props) { - const {seriesId} = props; - const {dashboardStore, alertsStore} = useStore(); - const {openModal, closeModal} = useModal(); + const { seriesId, initAlert } = props; + const { alertsStore } = useStore(); + const { openModal, closeModal } = useModal(); const onClick = () => { - // dashboardStore.toggleAlertModal(true); - alertsStore.init({query: {left: seriesId}}) + initAlert?.(); + alertsStore.init({ query: { left: seriesId } }) openModal(, { - // title: 'Set Alerts', placement: 'right', width: 620, }); diff --git a/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapperNew.tsx b/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapperNew.tsx index 14163e86b..93fe435bd 100644 --- a/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapperNew.tsx +++ b/frontend/app/components/Dashboard/components/WidgetWrapper/WidgetWrapperNew.tsx @@ -36,7 +36,7 @@ interface Props { } function WidgetWrapperNew(props: Props & RouteComponentProps) { - const { dashboardStore } = useStore(); + const { dashboardStore, metricStore } = useStore(); const { isWidget = false, active = false, @@ -94,6 +94,9 @@ function WidgetWrapperNew(props: Props & RouteComponentProps) { widget.metricOf !== FilterKey.ERRORS && widget.metricOf !== FilterKey.SESSIONS); + const beforeAlertInit = () => { + metricStore.init(widget) + } return ( {!isPredefined && isTimeSeries && !isGridView && ( - + )} {showMenu && ( diff --git a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx index 83962f3bd..f5274a4bd 100644 --- a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx +++ b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx @@ -112,7 +112,7 @@ export const getMatchingEntries = ( if (lowerCaseQuery.length === 0) return { - matchingCategories: ['ALL', ...Object.keys(filters)], + matchingCategories: ['All', ...Object.keys(filters)], matchingFilters: filters, }; @@ -130,7 +130,7 @@ export const getMatchingEntries = ( } }); - return { matchingCategories: ['ALL', ...matchingCategories], matchingFilters }; + return { matchingCategories: ['All', ...matchingCategories], matchingFilters }; }; interface Props { @@ -171,7 +171,7 @@ function FilterModal(props: Props) { mode, } = props; const [searchQuery, setSearchQuery] = React.useState(''); - const [category, setCategory] = React.useState('ALL'); + const [category, setCategory] = React.useState('All'); const { searchStore, searchStoreLive, projectsStore } = useStore(); const isMobile = projectsStore.active?.platform === 'ios'; // TODO - should be using mobile once the app is changed const filters = isLive @@ -222,12 +222,14 @@ function FilterModal(props: Props) { Object.keys(matchingFilters).length === 0; const displayedFilters = - category === 'ALL' + category === 'All' ? Object.entries(matchingFilters).flatMap(([category, filters]) => filters.map((f: any) => ({ ...f, category })) ) : matchingFilters[category]; + + console.log(displayedFilters) return (
setCategory(key)} className={cn('rounded-xl px-4 py-2 hover:bg-active-blue capitalize cursor-pointer font-medium', key === category ? 'bg-active-blue text-teal' : '')} > - {key.toLowerCase()} + {key}
))} @@ -265,7 +267,7 @@ function FilterModal(props: Props) { onClick={() => parseAndAdd({ ...filter })} > {filter.category ?
- {filter.category} + {filter.subCategory ? filter.subCategory : filter.category}
: null}
diff --git a/frontend/app/mstore/customFieldStore.ts b/frontend/app/mstore/customFieldStore.ts index a4d2de3fd..26221f1b5 100644 --- a/frontend/app/mstore/customFieldStore.ts +++ b/frontend/app/mstore/customFieldStore.ts @@ -60,27 +60,28 @@ class CustomFieldStore { }); 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 - ); - }); - }); - }); + // custom_event values fetcher; turned off for now; useful for later + // 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; } diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index 8c5761b5f..77aa9649e 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -11,19 +11,21 @@ const countryOptions = Object.keys(countries).map(i => ({ label: countries[i], v const containsFilters = [{ key: 'contains', label: 'contains', text: 'contains', value: 'contains' }]; const filterOrder = { - [FilterCategory.AUTOCAPTURE]: 0, - [FilterCategory.DEVTOOLS]: 1, - [FilterCategory.USER]: 2, - [FilterCategory.SESSION]: 3, - [FilterCategory.ISSUE]: 4, - [FilterCategory.METADATA]: 5 + [FilterCategory.EVENTS]: 0, + [FilterCategory.AUTOCAPTURE]: 1, + [FilterCategory.DEVTOOLS]: 2, + [FilterCategory.USER]: 3, + [FilterCategory.SESSION]: 4, + [FilterCategory.ISSUE]: 5, + [FilterCategory.METADATA]: 6 }; export const mobileFilters = [ { key: FilterKey.CLICK_MOBILE, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Tap', operator: 'on', operatorOptions: filterOptions.targetOperators, @@ -33,7 +35,8 @@ export const mobileFilters = [ { key: FilterKey.INPUT_MOBILE, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Text Input', placeholder: 'Enter input label name', operator: 'is', @@ -44,7 +47,8 @@ export const mobileFilters = [ { key: FilterKey.VIEW_MOBILE, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Screen', placeholder: 'Enter screen name', operator: 'is', @@ -55,7 +59,7 @@ export const mobileFilters = [ { key: FilterKey.CUSTOM_MOBILE, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, label: 'Custom Events', placeholder: 'Enter event key', operator: 'is', @@ -77,7 +81,8 @@ export const mobileFilters = [ { key: FilterKey.SWIPE_MOBILE, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Swipe', operator: 'on', operatorOptions: filterOptions.targetOperators, @@ -103,7 +108,8 @@ export const filters = [ { key: FilterKey.CLICK, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Click', operator: 'on', operatorOptions: filterOptions.targetOperators.concat(clickSelectorOperators), @@ -113,7 +119,8 @@ export const filters = [ { key: FilterKey.INPUT, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Text Input', placeholder: 'Enter input label name', operator: 'is', @@ -124,7 +131,8 @@ export const filters = [ { key: FilterKey.LOCATION, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Visited URL', placeholder: 'Enter path', operator: 'is', @@ -132,6 +140,18 @@ export const filters = [ icon: 'filters/location', isEvent: true }, + { + key: FilterKey.TAGGED_ELEMENT, + type: FilterType.MULTIPLE_DROPDOWN, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, + label: 'Tagged Element', + operator: 'is', + isEvent: true, + icon: 'filters/tag-element', + operatorOptions: filterOptions.tagElementOperators, + options: [] + }, { key: FilterKey.CUSTOM, type: FilterType.MULTIPLE, @@ -306,17 +326,6 @@ export const filters = [ operatorOptions: filterOptions.getOperatorsByKeys(['is']), icon: 'filters/duration' }, - { - key: FilterKey.TAGGED_ELEMENT, - type: FilterType.MULTIPLE_DROPDOWN, - category: FilterCategory.AUTOCAPTURE, - label: 'Tagged Element', - operator: 'is', - isEvent: true, - icon: 'filters/tag-element', - operatorOptions: filterOptions.tagElementOperators, - options: [] - }, { key: FilterKey.UTM_SOURCE, type: FilterType.MULTIPLE, @@ -587,7 +596,8 @@ export const conditionalFilters = [ { key: FilterKey.CLICK, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Click', operator: 'on', operatorOptions: filterOptions.targetConditional, @@ -597,7 +607,8 @@ export const conditionalFilters = [ { key: FilterKey.LOCATION, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Visited URL', placeholder: 'Enter path', operator: 'is', @@ -817,7 +828,8 @@ export const mobileConditionalFilters = [ { key: 'viewComponent', type: FilterType.STRING, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'View on screen', placeholder: 'View Name', operator: 'is', @@ -857,7 +869,8 @@ export const mobileConditionalFilters = [ { key: 'clickEvent', type: FilterType.STRING, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Tap on view', placeholder: 'View Name', operator: 'is', @@ -887,7 +900,8 @@ export const nonConditionalFlagFilters = filters.filter(i => { export const clickmapFilter = { key: FilterKey.LOCATION, type: FilterType.MULTIPLE, - category: FilterCategory.AUTOCAPTURE, + category: FilterCategory.EVENTS, + subCategory: FilterCategory.AUTOCAPTURE, label: 'Visited URL', placeholder: 'Enter URL or path', operator: filterOptions.pageUrlOperators[0].value, operatorOptions: filterOptions.pageUrlOperators, @@ -910,7 +924,7 @@ const mapLiveFilters = (list) => { const obj = {}; list.forEach(filter => { if ( - filter.category !== FilterCategory.AUTOCAPTURE && + filter.category !== FilterCategory.EVENTS && filter.category !== FilterCategory.DEVTOOLS && filter.key !== FilterKey.DURATION && filter.key !== FilterKey.REFERRER &&