From 3c0d8f81fc2e6757160cd4912f8856823887c58c Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Thu, 21 Apr 2022 13:28:54 +0200 Subject: [PATCH] fix(ui) - data reload on change --- .../components/FilterSeries/FilterSeries.tsx | 7 ++-- .../components/WidgetChart/WidgetChart.tsx | 36 ++++++++++++------- .../components/WidgetForm/WidgetForm.tsx | 20 ++++++----- .../WidgetSessions/WidgetSessions.tsx | 21 ++++++++--- .../components/WidgetView/WidgetView.tsx | 3 +- .../WidgetWrapper/WidgetWrapper.tsx | 3 +- frontend/app/mstore/metricStore.ts | 16 ++++----- frontend/app/mstore/types/filter.ts | 4 +-- frontend/app/mstore/types/widget.ts | 10 +++--- 9 files changed, 68 insertions(+), 52 deletions(-) diff --git a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx index 337aa1a8a..181a3c8ee 100644 --- a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx @@ -13,8 +13,7 @@ import { IconButton, Icon } from 'UI'; import FilterSelection from 'Shared/Filters/FilterSelection'; import SeriesName from './SeriesName'; import cn from 'classnames'; -import { useDashboardStore } from '../../store/store'; -import { observer, useObserver } from 'mobx-react-lite'; +import { observer } from 'mobx-react-lite'; interface Props { seriesIndex: number; @@ -37,7 +36,7 @@ function FilterSeries(props: Props) { const [expanded, setExpanded] = useState(true) const { series, seriesIndex } = props; - useEffect(observeChanges, [series]) + useEffect(observeChanges, [series.filter]); const onAddFilter = (filter) => { series.filter.addFilter(filter) @@ -49,12 +48,10 @@ function FilterSeries(props: Props) { const onChangeEventsOrder = (e, { name, value }) => { series.filter.updateKey(name, value) - // props.editSeriesFilter(seriesIndex, { eventsOrder: value }); } const onRemoveFilter = (filterIndex) => { series.filter.removeFilter(filterIndex) - // props.removeSeriesFilterFilter(seriesIndex, filterIndex); } return ( diff --git a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx index 55552a78f..eb63d8f08 100644 --- a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx +++ b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx @@ -4,29 +4,32 @@ import CustomMetricPercentage from 'App/components/Dashboard/Widgets/CustomMetri import CustomMetricTable from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTable'; import CustomMetricPieChart from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricPieChart'; import { Styles } from 'App/components/Dashboard/Widgets/common'; -import { useObserver } from 'mobx-react-lite'; +import { observer, useObserver } from 'mobx-react-lite'; import { Loader } from 'UI'; import { useStore } from 'App/mstore'; import WidgetPredefinedChart from '../WidgetPredefinedChart'; import CustomMetricOverviewChart from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricOverviewChart'; import { getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper'; +import { debounce } from 'App/utils'; interface Props { metric: any; isWidget?: boolean } function WidgetChart(props: Props) { const { isWidget = false, metric } = props; - const { dashboardStore } = useStore(); + const { dashboardStore, metricStore } = useStore(); + const _metric: any = useObserver(() => metricStore.instance); const period = useObserver(() => dashboardStore.period); const drillDownFilter = useObserver(() => dashboardStore.drillDownFilter); const colors = Styles.customMetricColors; - const [loading, setLoading] = useState(false) + const [loading, setLoading] = useState(true) const isOverviewWidget = metric.metricType === 'predefined' && metric.viewType === 'overview'; const params = { density: isOverviewWidget ? 7 : 70 } const metricParams = { ...params } const prevMetricRef = useRef(); const [data, setData] = useState(metric.data); + const isTableWidget = metric.metricType === 'table' && metric.viewType === 'table'; const isPieChart = metric.metricType === 'table' && metric.viewType === 'pieChart'; @@ -52,21 +55,28 @@ function WidgetChart(props: Props) { } } + const depsString = JSON.stringify(_metric.series); + + + const fetchMetricChartData = (metric, payload, isWidget) => { + setLoading(true) + dashboardStore.fetchMetricChartData(metric, payload, isWidget).then((res: any) => { + setData(res); + }).finally(() => { + setLoading(false); + }); + } + + const debounceRequest: any = React.useCallback(debounce(fetchMetricChartData, 500), []); useEffect(() => { if (prevMetricRef.current && prevMetricRef.current.name !== metric.name) { prevMetricRef.current = metric; return }; prevMetricRef.current = metric; - - setLoading(true); const payload = isWidget ? { ...params } : { ...metricParams, ...metric.toJson() }; - dashboardStore.fetchMetricChartData(metric, payload, isWidget).then((res: any) => { - setData(res); - }).finally(() => { - setLoading(false); - }); - }, [period]); + debounceRequest(metric, payload, isWidget); + }, [period, depsString]); const renderChart = () => { const { metricType, viewType } = metric; @@ -121,10 +131,10 @@ function WidgetChart(props: Props) { return
Unknown
; } return useObserver(() => ( - + {renderChart()} )); } -export default WidgetChart; \ No newline at end of file +export default observer(WidgetChart); \ No newline at end of file diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx index 13507960d..72c9c33c7 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx @@ -4,9 +4,8 @@ import { metricTypes, metricOf, issueOptions } from 'App/constants/filterOptions import { FilterKey } from 'Types/filter/filterType'; import { useStore } from 'App/mstore'; import { useObserver } from 'mobx-react-lite'; -import { HelpText, Button, Icon } from 'UI' +import { Button, Icon } from 'UI' import FilterSeries from '../FilterSeries'; -import { withRouter } from 'react-router-dom'; import { confirm } from 'UI/Confirmation'; import { withSiteId, dashboardMetricDetails, metricDetails } from 'App/routes' import DashboardSelectionModal from '../DashboardSelectionModal/DashboardSelectionModal'; @@ -28,31 +27,34 @@ function WidgetForm(props: Props) { const timeseriesOptions = metricOf.filter(i => i.type === 'timeseries'); const tableOptions = metricOf.filter(i => i.type === 'table'); const isTable = metric.metricType === 'table'; - const isTimeSeries = metric.metricType === 'timeseries'; const _issueOptions = [{ text: 'All', value: 'all' }].concat(issueOptions); const canAddToDashboard = metric.exists() && dashboards.length > 0; const write = ({ target: { value, name } }) => metricStore.merge({ [ name ]: value }); const writeOption = (e, { value, name }) => { - metricStore.merge({ [ name ]: value }); + const obj = { [ name ]: value }; if (name === 'metricValue') { - metricStore.merge({ metricValue: [value] }); + obj['metricValue'] = [value]; } if (name === 'metricOf') { if (value === FilterKey.ISSUE) { - metricStore.merge({ metricValue: ['all'] }); + obj['metricValue'] = ['all']; } } if (name === 'metricType') { if (value === 'timeseries') { - metricStore.merge({ metricOf: timeseriesOptions[0].value, viewType: 'lineChart' }); + obj['metricOf'] = timeseriesOptions[0].value; + obj['viewType'] = 'lineChart'; } else if (value === 'table') { - metricStore.merge({ metricOf: tableOptions[0].value, viewType: 'table' }); + obj['metricOf'] = tableOptions[0].value; + obj['viewType'] = 'table'; } } + + metricStore.merge(obj); }; const onSave = () => { @@ -172,7 +174,7 @@ function WidgetForm(props: Props) { 'Filter data using any event or attribute. Use Add Step button below to do so.' : 'Add user event or filter to define the series by clicking Add Step.' } - observeChanges={onObserveChanges} + // observeChanges={onObserveChanges} /> ))} diff --git a/frontend/app/components/Dashboard/components/WidgetSessions/WidgetSessions.tsx b/frontend/app/components/Dashboard/components/WidgetSessions/WidgetSessions.tsx index d82cde20b..52a670229 100644 --- a/frontend/app/components/Dashboard/components/WidgetSessions/WidgetSessions.tsx +++ b/frontend/app/components/Dashboard/components/WidgetSessions/WidgetSessions.tsx @@ -5,12 +5,14 @@ import { useStore } from 'App/mstore'; import SessionItem from 'Shared/SessionItem'; import { observer, useObserver } from 'mobx-react-lite'; import { DateTime } from 'luxon'; +import { debounce } from 'App/utils'; interface Props { className?: string; } function WidgetSessions(props: Props) { const { className = '' } = props; const [data, setData] = useState([]); + const [loading, setLoading] = useState(false); const [seriesOptions, setSeriesOptions] = useState([ { text: 'All', value: 'all' }, ]); @@ -30,18 +32,27 @@ function WidgetSessions(props: Props) { ]); }, [data]); + const fetchSessions = (metricId, filter) => { + setLoading(true) + widget.fetchSessions(metricId, filter).then(res => { + setData(res) + }).finally(() => { + setLoading(false) + }); + } + const filteredSessions = getListSessionsBySeries(data, activeSeries); const { dashboardStore, metricStore } = useStore(); const filter = useObserver(() => dashboardStore.drillDownFilter); const widget: any = useObserver(() => metricStore.instance); const startTime = DateTime.fromMillis(filter.startTimestamp).toFormat('LLL dd, yyyy HH:mm a'); const endTime = DateTime.fromMillis(filter.endTimestamp).toFormat('LLL dd, yyyy HH:mm a'); + const debounceRequest: any = React.useCallback(debounce(fetchSessions, 1000), []); + const depsString = JSON.stringify(widget.series); useEffect(() => { - widget.fetchSessions({ ...filter, series: widget.toJsonDrilldown() }).then(res => { - setData(res); - }); - }, [filter.startTimestamp, filter.endTimestamp, filter.filters]); + debounceRequest(widget.metricId, { ...filter, series: widget.toJsonDrilldown() }); + }, [filter.startTimestamp, filter.endTimestamp, filter.filters, depsString]); return useObserver(() => (
@@ -71,7 +82,7 @@ function WidgetSessions(props: Props) {
- + props.widget); const isPredefined = widget.metricType === 'predefined'; const dashboard = useObserver(() => dashboardStore.selectedDashboard); + const isOverviewWidget = widget.widgetType === 'predefined' && widget.viewType === 'overview'; const [{ opacity, isDragging }, dragRef] = useDrag({ type: 'item', @@ -117,7 +118,7 @@ function WidgetWrapper(props: Props) { )}
- +
diff --git a/frontend/app/mstore/metricStore.ts b/frontend/app/mstore/metricStore.ts index 89cf153a0..4d4d340a3 100644 --- a/frontend/app/mstore/metricStore.ts +++ b/frontend/app/mstore/metricStore.ts @@ -73,13 +73,13 @@ export default class MetricStore implements IMetricStore { paginatedList: computed, }) - reaction( - () => this.metricsSearch, - (metricsSearch) => { // TODO filter the list for View - this.page = 1 - this.paginatedList - } - ) + // reaction( + // () => this.metricsSearch, + // (metricsSearch) => { // TODO filter the list for View + // this.page = 1 + // this.paginatedList + // } + // ) } // State Actions @@ -92,7 +92,7 @@ export default class MetricStore implements IMetricStore { } merge(object: any) { - this.instance = Object.assign(this.instance, object) + Object.assign(this.instance, object) } reset(id: string) { diff --git a/frontend/app/mstore/types/filter.ts b/frontend/app/mstore/types/filter.ts index 900008fa4..c557c5a1f 100644 --- a/frontend/app/mstore/types/filter.ts +++ b/frontend/app/mstore/types/filter.ts @@ -1,6 +1,4 @@ -import { makeAutoObservable, runInAction, observable, action, reaction } from "mobx" -import { FilterKey, FilterType } from 'Types/filter/filterType' -import { filtersMap } from 'Types/filter/newFilter' +import { makeAutoObservable, runInAction, observable, action } from "mobx" import FilterItem from "./filterItem" export interface IFilter { diff --git a/frontend/app/mstore/types/widget.ts b/frontend/app/mstore/types/widget.ts index 9a6f90fb7..a2fac1d80 100644 --- a/frontend/app/mstore/types/widget.ts +++ b/frontend/app/mstore/types/widget.ts @@ -4,6 +4,7 @@ import { DateTime } from 'luxon'; import { IFilter } from "./filter"; import { metricService } from "App/services"; import Session, { ISession } from "App/mstore/types/session"; + export interface IWidget { metricId: any widgetId: any @@ -45,7 +46,7 @@ export interface IWidget { exists(): boolean toWidget(): any setData(data: any): void - fetchSessions(filter: any): Promise + fetchSessions(metricId: any, filter: any): Promise } export default class Widget implements IWidget { public static get ID_KEY():string { return "metricId" } @@ -195,18 +196,15 @@ export default class Widget implements IWidget { }) } - fetchSessions(filter: any): Promise { - this.sessionsLoading = true + fetchSessions(metricId: any, filter: any): Promise { return new Promise((resolve, reject) => { - metricService.fetchSessions(this.metricId, filter).then(response => { + metricService.fetchSessions(metricId, filter).then(response => { resolve(response.map(cat => { return { ...cat, sessions: cat.sessions.map(s => new Session().fromJson(s)) } })) - }).finally(() => { - this.sessionsLoading = false }) }) }