From 3a08033f16ac225f178067f04affaae5e43411be Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Feb 2022 14:41:35 +0100 Subject: [PATCH] feat(ui) - customm metrics ui review and changes --- frontend/app/components/Alerts/AlertForm.js | 5 +- .../Alerts/AlertFormModal/AlertFormModal.tsx | 2 +- .../app/components/Dashboard/Dashboard.js | 30 +++++++++-- .../CustomMetricWidget/CustomMetricWidget.tsx | 36 +++++++------ .../CustomMetricWidgetPreview.tsx | 2 +- .../CustomMetricsWidgets.tsx | 9 +++- frontend/app/components/shared/AddWidgets.js | 24 ++++++--- .../CustomMetricForm/CustomMetricForm.tsx | 53 ++++++++++++++----- .../shared/CustomMetrics/CustomMetrics.tsx | 4 +- .../FilterSeries/FilterSeries.tsx | 2 +- .../FilterSeries/SeriesName/SeriesName.tsx | 26 +++++---- .../SessionListModal/SessionListModal.tsx | 7 +-- .../SaveSearchModal/SaveSearchModal.tsx | 2 +- .../components/ui/IconButton/iconButton.css | 5 +- frontend/app/duck/customMetrics.js | 2 +- frontend/app/svg/icons/close.svg | 5 +- frontend/app/svg/icons/sliders.svg | 3 ++ frontend/app/types/filter/newFilter.js | 4 +- 18 files changed, 150 insertions(+), 71 deletions(-) create mode 100644 frontend/app/svg/icons/sliders.svg diff --git a/frontend/app/components/Alerts/AlertForm.js b/frontend/app/components/Alerts/AlertForm.js index 692191c96..f3286542b 100644 --- a/frontend/app/components/Alerts/AlertForm.js +++ b/frontend/app/components/Alerts/AlertForm.js @@ -47,7 +47,7 @@ const Section = ({ index, title, description, content }) => ( const integrationsRoute = client(CLIENT_TABS.INTEGRATIONS); const AlertForm = props => { - const { instance, slackChannels, webhooks, loading, onDelete, deleting, triggerOptions } = props; + const { instance, slackChannels, webhooks, loading, onDelete, deleting, triggerOptions, metricId } = props; const write = ({ target: { value, name } }) => props.edit({ [ name ]: value }) const writeOption = (e, { name, value }) => props.edit({ [ name ]: value }); const onChangeOption = (e, { checked, name }) => props.edit({ [ name ]: checked }) @@ -70,8 +70,7 @@ const AlertForm = props => { const unit = metric ? metric.unit : ''; const isThreshold = instance.detectionMethod === 'threshold'; - console.log('triggerOptions', triggerOptions) - + console.log('AlertForm', instance.query); return (
props.onSubmit(instance)} id="alert-form"> diff --git a/frontend/app/components/Alerts/AlertFormModal/AlertFormModal.tsx b/frontend/app/components/Alerts/AlertFormModal/AlertFormModal.tsx index f6fd62ad5..cfa4a7ca5 100644 --- a/frontend/app/components/Alerts/AlertFormModal/AlertFormModal.tsx +++ b/frontend/app/components/Alerts/AlertFormModal/AlertFormModal.tsx @@ -72,7 +72,7 @@ function AlertFormModal(props) { size="medium" content={ showModal &&
- + { activeWidget && }
@@ -206,8 +215,21 @@ export default class Dashboard extends React.PureComponent {
- -
+ +
+ + Custom Metrics are not supported for comparison. +
+ +
+ } + > +
null}/>
diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx index 2e2e8c05b..5af7e8257 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; -import { Loader, NoContent, Icon } from 'UI'; +import { Loader, NoContent, Icon, Popup } from 'UI'; import { Styles } from '../../common'; import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts'; import { LineChart, Line, Legend } from 'recharts'; @@ -89,25 +89,14 @@ function CustomMetricWidget(props: Props) { props.setActiveWidget({ widget: metric, startTimestamp, endTimestamp, timestamp: event.activePayload[0].payload.timestamp, index }) } - // const onAlertClick = () => { - // props.setShowAlerts(true) - // props.setAlertMetricId(metric.metricId) - // } - return (
{metric.name + ' ' + metric.metricId}
-
- -
-
props.edit(metric)}> - -
-
- -
+ + props.edit(metric)} /> +
@@ -170,4 +159,19 @@ function CustomMetricWidget(props: Props) { export default connect(state => ({ period: state.getIn(['dashboard', 'period']), -}), { remove, setShowAlerts, setAlertMetricId, edit, setActiveWidget })(CustomMetricWidget); \ No newline at end of file +}), { remove, setShowAlerts, setAlertMetricId, edit, setActiveWidget })(CustomMetricWidget); + + +const WidgetIcon = ({ className = '', tooltip = '', icon, onClick }) => ( + + +
+ } + content={tooltip} + position="top center" + inverted + /> +) \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx index 5ee1534f9..74633b1cd 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx @@ -125,7 +125,7 @@ function CustomMetricWidget(props: Props) { allowDecimals={false} label={{ ...Styles.axisLabelLeft, - value: "Number of Errors" + value: "Number of Sessions" }} /> diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx index 6d60e313d..26c019eaf 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx @@ -3,11 +3,13 @@ import { connect } from 'react-redux'; import { fetchList } from 'Duck/customMetrics'; import CustomMetricWidget from './CustomMetricWidget'; import AlertFormModal from 'App/components/Alerts/AlertFormModal'; +import { init as initAlert } from 'Duck/alerts'; interface Props { fetchList: Function; list: any; onClickEdit: (e) => void; + initAlert: Function; } function CustomMetricsWidgets(props: Props) { const { list } = props; @@ -25,7 +27,10 @@ function CustomMetricsWidgets(props: Props) { setActiveMetricId(item.metricId)} + onAlertClick={(e) => { + setActiveMetricId(item.metricId) + props.initAlert({ left: item.series.first().seriesId }) + }} /> ))} @@ -40,4 +45,4 @@ function CustomMetricsWidgets(props: Props) { export default connect(state => ({ list: state.getIn(['customMetrics', 'list']), -}), { fetchList })(CustomMetricsWidgets); \ No newline at end of file +}), { fetchList, initAlert })(CustomMetricsWidgets); \ No newline at end of file diff --git a/frontend/app/components/shared/AddWidgets.js b/frontend/app/components/shared/AddWidgets.js index 64aaef8ca..cbe4509eb 100644 --- a/frontend/app/components/shared/AddWidgets.js +++ b/frontend/app/components/shared/AddWidgets.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import cn from 'classnames'; import withToggle from 'HOCs/withToggle'; -import { IconButton, SlideModal, NoContent } from 'UI'; +import { IconButton, SlideModal, NoContent, Popup } from 'UI'; import { updateAppearance } from 'Duck/user'; import { WIDGET_LIST } from 'Types/dashboard'; import stl from './addWidgets.css'; @@ -76,13 +76,21 @@ export default class AddWidgets extends React.PureComponent { } onClose={ this.props.switchOpen } /> - + } + content={ `Add a metric to this section.` } + size="tiny" + inverted + position="top center" />
); diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index b8d96a590..b7a552593 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -2,8 +2,11 @@ import React from 'react'; import { Form, SegmentSelection, Button, IconButton } from 'UI'; import FilterSeries from '../FilterSeries'; import { connect } from 'react-redux'; -import { edit as editMetric, save, addSeries } from 'Duck/customMetrics'; +import { edit as editMetric, save, addSeries, remove } from 'Duck/customMetrics'; import CustomMetricWidgetPreview from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview'; +import { confirm } from 'UI/Confirmation'; +import { toast } from 'react-toastify'; +import cn from 'classnames'; interface Props { metric: any; @@ -12,6 +15,7 @@ interface Props { loading: boolean; addSeries: (series?) => void; onClose: () => void; + remove: (id) => Promise; } function CustomMetricForm(props: Props) { @@ -52,7 +56,23 @@ function CustomMetricForm(props: Props) { }; const save = () => { - props.save(metric).then(props.onClose); + props.save(metric).then(() => { + toast.success(metric.exists() ? 'Updated succesfully.' : 'Created succesfully.'); + props.onClose() + }); + } + + const deleteHandler = async () => { + if (await confirm({ + header: 'Custom Metric', + confirmButton: 'Delete', + confirmation: `Are you sure you want to delete ${metric.name}` + })) { + props.remove(metric.metricId).then(() => { + toast.success('Deleted succesfully.'); + props.onClose(); + }); + } } return ( @@ -78,7 +98,7 @@ function CustomMetricForm(props: Props) {
- Timeseries + Timeseries of
@@ -98,7 +118,7 @@ function CustomMetricForm(props: Props) {
- + {metric.series && metric.series.size > 0 && metric.series.map((series: any, index: number) => (
-
- +
2})}> +
-
+
-
- +
+
+ + + +
+
+ +
); @@ -132,4 +159,4 @@ function CustomMetricForm(props: Props) { export default connect(state => ({ metric: state.getIn(['customMetrics', 'instance']), loading: state.getIn(['customMetrics', 'saveRequest', 'loading']), -}), { editMetric, save, addSeries })(CustomMetricForm); \ No newline at end of file +}), { editMetric, save, addSeries, remove })(CustomMetricForm); \ No newline at end of file diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx index 55495fecc..ccf3a1133 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx @@ -15,12 +15,12 @@ function CustomMetrics(props: Props) { return (
- props.init()} /> + props.init()} /> - { 'Custom Metric' } + { metric && metric.exists() ? 'Update Custom Metric' : 'Create Custom Metric' }
} isDisplayed={ !!metric } diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx index 74e1696b0..5ef8d6006 100644 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx @@ -104,7 +104,7 @@ function FilterSeries(props: Props) { onChangeEventsOrder={onChangeEventsOrder} /> ): ( -
Add user event or filter to build the series.
+
Add user event or filter to define the series by clicking Add Step.
)}
diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx index 74b4bd47d..7d7d131ae 100644 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx +++ b/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx @@ -28,16 +28,22 @@ function SeriesName(props: Props) { // const { name } = props; return ( -
- setEditing(true)} - /> +
+ { editing ? ( + setEditing(true)} + /> + ) : ( +
{name}
+ )} +
setEditing(true)}>
); diff --git a/frontend/app/components/shared/CustomMetrics/SessionListModal/SessionListModal.tsx b/frontend/app/components/shared/CustomMetrics/SessionListModal/SessionListModal.tsx index 372c36118..60e8a59b2 100644 --- a/frontend/app/components/shared/CustomMetrics/SessionListModal/SessionListModal.tsx +++ b/frontend/app/components/shared/CustomMetrics/SessionListModal/SessionListModal.tsx @@ -49,7 +49,7 @@ function SessionListModal(props: Props) { -
{ 'Custom Metric: ' + activeWidget.widget.name }
+
{ activeWidget.widget.name }
)} isDisplayed={ !!activeWidget } @@ -64,7 +64,7 @@ function SessionListModal(props: Props) {
- Sort By + Series { filteredSessions.map(session => ) } diff --git a/frontend/app/components/shared/SaveSearchModal/SaveSearchModal.tsx b/frontend/app/components/shared/SaveSearchModal/SaveSearchModal.tsx index a091c99b1..9545426c1 100644 --- a/frontend/app/components/shared/SaveSearchModal/SaveSearchModal.tsx +++ b/frontend/app/components/shared/SaveSearchModal/SaveSearchModal.tsx @@ -87,7 +87,7 @@ function SaveSearchModal(props: Props) {
- { savedSearch && } diff --git a/frontend/app/components/ui/IconButton/iconButton.css b/frontend/app/components/ui/IconButton/iconButton.css index 3aaff8347..1685ca4d6 100644 --- a/frontend/app/components/ui/IconButton/iconButton.css +++ b/frontend/app/components/ui/IconButton/iconButton.css @@ -89,7 +89,10 @@ } &.plain { - background-color: transparent; + background-color: transparent !important; + color: $teal !important; + box-shadow: none !important; + padding: 0 10px !important; &:hover { background-color: $active-blue; } diff --git a/frontend/app/duck/customMetrics.js b/frontend/app/duck/customMetrics.js index 26aed2f07..cbfd0dff6 100644 --- a/frontend/app/duck/customMetrics.js +++ b/frontend/app/duck/customMetrics.js @@ -33,7 +33,7 @@ const defaultInstance = CustomMetric({ name: 'New', series: List([ { - name: 'Session Count', + name: 'Series 1', filter: new Filter({ filters: [], eventsOrder: 'and' }), }, ]) diff --git a/frontend/app/svg/icons/close.svg b/frontend/app/svg/icons/close.svg index e1a7e4bc2..ddb768e16 100644 --- a/frontend/app/svg/icons/close.svg +++ b/frontend/app/svg/icons/close.svg @@ -1,3 +1,4 @@ - - + + + \ No newline at end of file diff --git a/frontend/app/svg/icons/sliders.svg b/frontend/app/svg/icons/sliders.svg new file mode 100644 index 000000000..6a354ebcf --- /dev/null +++ b/frontend/app/svg/icons/sliders.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index bf3b4de1c..5c9b5a942 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -6,7 +6,7 @@ import { capitalize } from 'App/utils'; const countryOptions = Object.keys(countries).map(i => ({ text: countries[i], value: i })); const ISSUE_OPTIONS = [ - { text: 'Click Range', value: 'click_rage' }, + { text: 'Click Rage', value: 'click_rage' }, { text: 'Dead Click', value: 'dead_click' }, { text: 'Excessive Scrolling', value: 'excessive_scrolling' }, { text: 'Bad Request', value: 'bad_request' }, @@ -40,7 +40,7 @@ export const filtersMap = { [FilterKey.PLATFORM]: { key: FilterKey.PLATFORM, type: FilterType.MULTIPLE_DROPDOWN, category: FilterCategory.GEAR, label: 'Platform', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/platform', options: platformOptions }, [FilterKey.REVID]: { key: FilterKey.REVID, type: FilterType.MULTIPLE, category: FilterCategory.GEAR, label: 'RevId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/rev-id' }, [FilterKey.REFERRER]: { key: FilterKey.REFERRER, type: FilterType.MULTIPLE, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'Referrer', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/referrer' }, - [FilterKey.DURATION]: { key: FilterKey.DURATION, type: FilterType.DURATION, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'Duration', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/duration' }, + [FilterKey.DURATION]: { key: FilterKey.DURATION, type: FilterType.DURATION, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'Duration', operator: 'is', operatorOptions: filterOptions.baseOperators, icon: 'filters/duration' }, [FilterKey.USER_COUNTRY]: { key: FilterKey.USER_COUNTRY, type: FilterType.MULTIPLE_DROPDOWN, category: FilterCategory.RECORDING_ATTRIBUTES, label: 'User Country', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/country', options: countryOptions }, // [FilterKey.CONSOLE]: { key: FilterKey.CONSOLE, type: FilterType.MULTIPLE, category: FilterCategory.JAVASCRIPT, label: 'Console', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/console' }, [FilterKey.USERID]: { key: FilterKey.USERID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'User Id', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' },