From 3e7634c043377ac11f924f7459b6bb468998a1c1 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 7 Feb 2022 18:34:28 +0100 Subject: [PATCH] feat(ui) - custom metric widgets active inactive --- .../app/components/Dashboard/AddWidgets.js | 44 +-------- .../app/components/Dashboard/Dashboard.js | 24 +++-- .../Dashboard/WidgetSection/WidgetSection.js | 4 +- .../CustomMetricWidget/CustomMetricWidget.tsx | 11 ++- .../CustomMetricsWidgets.tsx | 2 +- frontend/app/components/shared/AddWidgets.js | 96 ++++++++----------- .../shared/WidgetSection/WidgetSection.js | 4 +- frontend/app/duck/customMetrics.js | 13 +++ 8 files changed, 87 insertions(+), 111 deletions(-) diff --git a/frontend/app/components/Dashboard/AddWidgets.js b/frontend/app/components/Dashboard/AddWidgets.js index 72c3731e4..23751e90a 100644 --- a/frontend/app/components/Dashboard/AddWidgets.js +++ b/frontend/app/components/Dashboard/AddWidgets.js @@ -18,11 +18,11 @@ export default class AddWidgets extends React.PureComponent { const { appearance } = this.props; const newAppearance = appearance.setIn([ 'dashboard', widgetKey ], true); this.props.switchOpen(false); - this.props.updateAppearance(newAppearance) + this.props.updateAppearance(newAppearance) } render() { - const { appearance, disabled } = this.props; + const { appearance } = this.props; const avaliableWidgets = WIDGET_LIST.filter(({ key, type }) => !appearance.dashboard[ key ] && type === this.props.type ); return ( @@ -44,46 +44,6 @@ export default class AddWidgets extends React.PureComponent { } - - - { avaliableWidgets.map(({ key, name, description, thumb }) => ( -
-
-
-

{ name }

-
- -
-
- ))} - - } - onClose={ this.props.switchOpen } - /> - ); } diff --git a/frontend/app/components/Dashboard/Dashboard.js b/frontend/app/components/Dashboard/Dashboard.js index 6bd682db4..c5ecbc530 100644 --- a/frontend/app/components/Dashboard/Dashboard.js +++ b/frontend/app/components/Dashboard/Dashboard.js @@ -4,7 +4,7 @@ import withPageTitle from 'HOCs/withPageTitle'; import withPermissions from 'HOCs/withPermissions' import { setPeriod, setPlatform, fetchMetadataOptions } from 'Duck/dashboard'; import { NoContent, Icon } from 'UI'; -import { WIDGET_KEYS } from 'Types/dashboard'; +import { WIDGET_KEYS, WIDGET_LIST } from 'Types/dashboard'; import CustomMetrics from 'Shared/CustomMetrics'; import SessionListModal from 'Shared/CustomMetrics/SessionListModal'; @@ -124,6 +124,7 @@ function isInViewport(el) { platform: state.getIn([ 'dashboard', 'platform' ]), dashboardAppearance: state.getIn([ 'user', 'account', 'appearance', 'dashboard' ]), activeWidget: state.getIn(['customMetrics', 'activeWidget']), + appearance: state.getIn([ 'user', 'account', 'appearance' ]), }), { setPeriod, setPlatform, fetchMetadataOptions }) @withPageTitle('Metrics - OpenReplay') @withRouter @@ -144,6 +145,10 @@ export default class Dashboard extends React.PureComponent { pageSection: 'metrics', }; + getWidgetsByKey = (widgetType) => { + return WIDGET_LIST.filter(({ key, type }) => !this.props.appearance.dashboard[ key ] && type === widgetType); + } + componentDidMount() { const { history, location } = this.props; // TODO check the hash navigato it @@ -209,7 +214,13 @@ export default class Dashboard extends React.PureComponent { icon empty > - +
@@ -217,8 +228,9 @@ export default class Dashboard extends React.PureComponent { {comparing && ( @@ -236,7 +248,7 @@ export default class Dashboard extends React.PureComponent { - +
{ dashboardAppearance.impactedSessionsByJsErrors && } { dashboardAppearance.errorsPerDomains && } @@ -250,7 +262,7 @@ export default class Dashboard extends React.PureComponent {
- +
{ dashboardAppearance.speedLocation && } { dashboardAppearance.crashes && } @@ -270,7 +282,7 @@ export default class Dashboard extends React.PureComponent {
- +
{ dashboardAppearance.resourcesCountByType && } { dashboardAppearance.resourcesLoadingTime && } diff --git a/frontend/app/components/Dashboard/WidgetSection/WidgetSection.js b/frontend/app/components/Dashboard/WidgetSection/WidgetSection.js index a7129c7fb..43959ff57 100644 --- a/frontend/app/components/Dashboard/WidgetSection/WidgetSection.js +++ b/frontend/app/components/Dashboard/WidgetSection/WidgetSection.js @@ -7,8 +7,8 @@ function WidgetSection({ className, title, children, description, type }) {
-
{title}
- +
{title}
+ {/* */}
{description &&
{description}
}
diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx index 5af7e8257..3a6414424 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx @@ -7,7 +7,7 @@ import { LineChart, Line, Legend } from 'recharts'; import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period'; import stl from './CustomMetricWidget.css'; import { getChartFormatter, getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper'; -import { edit, remove, setAlertMetricId, setActiveWidget } from 'Duck/customMetrics'; +import { edit, remove, setAlertMetricId, setActiveWidget, updateActiveState } from 'Duck/customMetrics'; import { confirm } from 'UI/Confirmation'; import APIClient from 'App/api_client'; import { setShowAlerts } from 'Duck/dashboard'; @@ -37,6 +37,7 @@ interface Props { onAlertClick: (e) => void; edit: (setDefault?) => void; setActiveWidget: (widget) => void; + updateActiveState: (metricId, state) => void; } function CustomMetricWidget(props: Props) { const { metric, showSync, compare, period } = props; @@ -89,6 +90,10 @@ function CustomMetricWidget(props: Props) { props.setActiveWidget({ widget: metric, startTimestamp, endTimestamp, timestamp: event.activePayload[0].payload.timestamp, index }) } + const updateActiveState = (metricId, state) => { + props.updateActiveState(metricId, state); + } + return (
@@ -96,7 +101,7 @@ function CustomMetricWidget(props: Props) {
props.edit(metric)} /> - + updateActiveState(metric.metricId, false)} />
@@ -159,7 +164,7 @@ function CustomMetricWidget(props: Props) { export default connect(state => ({ period: state.getIn(['dashboard', 'period']), -}), { remove, setShowAlerts, setAlertMetricId, edit, setActiveWidget })(CustomMetricWidget); +}), { remove, setShowAlerts, setAlertMetricId, edit, setActiveWidget, updateActiveState })(CustomMetricWidget); const WidgetIcon = ({ className = '', tooltip = '', icon, onClick }) => ( diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx index fb927bc0a..91de93afd 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricsWidgets.tsx @@ -21,7 +21,7 @@ function CustomMetricsWidgets(props: Props) { return ( <> - {list.map((item: any) => ( + {list.filter(item => item.active).map((item: any) => ( ({ appearance: state.getIn([ 'user', 'account', 'appearance' ]), + customMetrics: state.getIn(['customMetrics', 'list']), }), { - updateAppearance, + updateAppearance, updateActiveState, }) @withToggle() export default class AddWidgets extends React.PureComponent { makeAddHandler = widgetKey => () => { - const { appearance } = this.props; - const newAppearance = appearance.setIn([ 'dashboard', widgetKey ], true); + if (this.props.type === CUSTOM_METRICS) { + this.props.updateActiveState(widgetKey, true); + } else { + const { appearance } = this.props; + const newAppearance = appearance.setIn([ 'dashboard', widgetKey ], true); + this.props.updateAppearance(newAppearance) + } + this.props.switchOpen(false); - this.props.updateAppearance(newAppearance) + } + + getCustomMetricWidgets = () => { + return this.props.customMetrics.filter(i => !i.active).map(item => ({ + type: CUSTOM_METRICS, + key: item.metricId, + name: item.name, + })) } render() { - const { appearance, disabled } = this.props; - const avaliableWidgets = WIDGET_LIST.filter(({ key, type }) => !appearance.dashboard[ key ] && type === this.props.type ); + const { disabled, widgets, type } = this.props; + // const widgets = WIDGET_LIST.filter(({ key, type }) => !appearance.dashboard[ key ] && type === this.props.type ); + const filteredWidgets = type === CUSTOM_METRICS ? this.getCustomMetricWidgets() : widgets; return (
+ + } + content={ `Add a metric to this section.` } + size="tiny" + inverted + position="top center" + /> this.props.switchOpen(false)}> {this.props.open &&
- {avaliableWidgets.map(w => ( + {filteredWidgets.map(w => (
} - - - { avaliableWidgets.map(({ key, name, description, thumb }) => ( -
-
-
-

{ name }

-
- -
-
- ))} - - } - onClose={ this.props.switchOpen } - /> - - } - content={ `Add a metric to this section.` } - size="tiny" - inverted - position="top center" - />
); } diff --git a/frontend/app/components/shared/WidgetSection/WidgetSection.js b/frontend/app/components/shared/WidgetSection/WidgetSection.js index 3893ff392..45b339236 100644 --- a/frontend/app/components/shared/WidgetSection/WidgetSection.js +++ b/frontend/app/components/shared/WidgetSection/WidgetSection.js @@ -2,13 +2,13 @@ import React from 'react' import cn from 'classnames' import AddWidgets from '../AddWidgets'; -function WidgetSection({ className, title, children, description, type }) { +function WidgetSection({ className, title, children, description, type, widgets = [] }) { return (
{title}
- +
{description &&
{description}
}
diff --git a/frontend/app/duck/customMetrics.js b/frontend/app/duck/customMetrics.js index cbfd0dff6..e486e75b0 100644 --- a/frontend/app/duck/customMetrics.js +++ b/frontend/app/duck/customMetrics.js @@ -13,6 +13,7 @@ const FETCH_LIST = fetchListType(name); const FETCH_SESSION_LIST = fetchListType(`${name}/FETCH_SESSION_LIST`); const FETCH = fetchType(name); const SAVE = saveType(name); +const UPDATE_ACTIVE_STATE = saveType(`${name}/UPDATE_ACTIVE_STATE`); const EDIT = editType(name); const INIT = `${name}/INIT`; const SET_ACTIVE_WIDGET = `${name}/SET_ACTIVE_WIDGET`; @@ -72,6 +73,8 @@ function reducer(state = initialState, action = {}) { case success(FETCH_LIST): const { data } = action; return state.set("list", List(data.map(CustomMetric))); + // case success(UPDATE_ACTIVE_STATE): + // return updateItemInList(updateInstance(state, action.data), action.data); case success(FETCH_SESSION_LIST): return state.set("sessionList", List(action.data.map(item => ({ ...item, sessions: item.sessions.map(Session) })))); case SET_ACTIVE_WIDGET: @@ -161,4 +164,14 @@ export const setActiveWidget = (widget) => (dispatch, getState) => { type: SET_ACTIVE_WIDGET, widget, }); +} + +export const updateActiveState = (metricId, state) => (dispatch, getState) => { + return dispatch({ + types: UPDATE_ACTIVE_STATE.array, + call: client => client.post(`/custom_metrics/${metricId}/status`, { active: state }), + metricId + }).then(() => { + dispatch(fetchList()); + }); } \ No newline at end of file