From 1b9df5e6bd4a0cd01e25d6e450eba4106a7713b2 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 8 Apr 2022 18:11:55 +0200 Subject: [PATCH] feat(ui) - dashboard - wip --- .../CustomMetricOverviewChart.tsx | 15 +-- .../CustomMetricPieChart.tsx | 2 +- .../BreakdownOfLoadedResources.tsx | 48 +++++++ .../BreakdownOfLoadedResources/index.ts | 1 + .../MissingResources/Chart.js | 16 +++ .../MissingResources/CopyPath.js | 23 ++++ .../MissingResources/MissingResources.tsx | 62 +++++++++ .../MissingResources/ResourceInfo.js | 18 +++ .../MissingResources/index.ts | 1 + .../MissingResources/resourceInfo.css | 10 ++ .../ResourceLoadedVsResponseEnd.tsx | 70 ++++++++++ .../ResourceLoadedVsResponseEnd/index.ts | 1 + .../ResourceLoadedVsVisuallyComplete.tsx | 73 +++++++++++ .../ResourceLoadedVsVisuallyComplete/index.ts | 1 + .../ResourceLoadingTime.tsx | 122 ++++++++++++++++++ .../ResourceLoadingTime/index.ts | 1 + .../SessionsImpactedBySlowRequests.tsx | 55 ++++++++ .../SessionsImpactedBySlowRequests/index.ts | 1 + .../TimeToRender/TimeToRender.tsx | 2 +- .../DashboardMetricSelection.tsx | 2 +- .../components/WidgetChart/WidgetChart.tsx | 4 + .../WidgetPredefinedChart.tsx | 54 +++++--- .../app/components/ui/NoContent/NoContent.js | 5 +- frontend/app/mstore/dashboardStore.ts | 80 ++++++++---- frontend/app/mstore/types/widget.ts | 1 + 25 files changed, 610 insertions(+), 58 deletions(-) create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/BreakdownOfLoadedResources/BreakdownOfLoadedResources.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/BreakdownOfLoadedResources/index.ts create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/Chart.js create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/CopyPath.js create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/MissingResources.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/ResourceInfo.js create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/index.ts create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/resourceInfo.css create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd/ResourceLoadedVsResponseEnd.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd/index.ts create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete/ResourceLoadedVsVisuallyComplete.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete/index.ts create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime/ResourceLoadingTime.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime/index.ts create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests/SessionsImpactedBySlowRequests.tsx create mode 100644 frontend/app/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests/index.ts diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricOverviewChart/CustomMetricOverviewChart.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricOverviewChart/CustomMetricOverviewChart.tsx index 3dad11dc5..93e0fbf6d 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricOverviewChart/CustomMetricOverviewChart.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricOverviewChart/CustomMetricOverviewChart.tsx @@ -8,26 +8,18 @@ import { numberWithCommas } from 'App/utils'; interface Props { data: any; - params: any; - seriesMap: any; - colors: any; - onClick?: (event, index) => void; + // onClick?: (event, index) => void; } function CustomMetricOverviewChart(props: Props) { - const { data, params, seriesMap, colors, onClick = () => null } = props; + const { data } = props; console.log('data', data) const gradientDef = Styles.gradientDef(); return ( -
+
- {/*
{ 'test' }
*/}
- {/* {prefix} */} - {/*
-
-
*/} + + + + {gradientDef} + + + + + + + + + + + + ); +} + +export default BreakdownOfLoadedResources; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/BreakdownOfLoadedResources/index.ts b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/BreakdownOfLoadedResources/index.ts new file mode 100644 index 000000000..5770a63d8 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/BreakdownOfLoadedResources/index.ts @@ -0,0 +1 @@ +export { default } from './BreakdownOfLoadedResources' \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/Chart.js b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/Chart.js new file mode 100644 index 000000000..2f406622d --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/Chart.js @@ -0,0 +1,16 @@ +import { AreaChart, Area } from 'recharts'; +import { Styles } from '../../common'; + +const Chart = ({ data, compare }) => { + const colors = compare ? Styles.compareColors : Styles.colors; + + return ( + + + + ); +} + +Chart.displayName = 'Chart'; + +export default Chart; diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/CopyPath.js b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/CopyPath.js new file mode 100644 index 000000000..6b7e709e7 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/CopyPath.js @@ -0,0 +1,23 @@ +import React from 'react' +import copy from 'copy-to-clipboard' +import { useState } from 'react' + +const CopyPath = ({ data }) => { + const [copied, setCopied] = useState(false) + + const copyHandler = () => { + copy(data.url); + setCopied(true); + setTimeout(function() { + setCopied(false) + }, 500); + } + + return ( +
+ { copied ? 'Copied' : 'Copy Path'} +
+ ) +} + +export default CopyPath diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/MissingResources.tsx b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/MissingResources.tsx new file mode 100644 index 000000000..ce3544f3e --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/MissingResources.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { NoContent } from 'UI'; +import { Styles, Table } from '../../common'; +import { List } from 'immutable'; + +import Chart from './Chart'; +import ResourceInfo from './ResourceInfo'; +import CopyPath from './CopyPath'; + +const cols = [ + { + key: 'resource', + title: 'Resource', + Component: ResourceInfo, + width: '40%', + }, + { + key: 'sessions', + title: 'Sessions', + toText: count => `${ count > 1000 ? Math.trunc(count / 1000) : count }${ count > 1000 ? 'k' : '' }`, + width: '20%', + }, + { + key: 'trend', + title: 'Trend', + Component: Chart, + width: '20%', + }, + { + key: 'copy-path', + title: '', + Component: CopyPath, + cellClass: 'invisible group-hover:visible text-right', + width: '20%', + } +]; + +interface Props { + data: any +} +function MissingResources(props: Props) { + const { data } = props; + + return ( + +
+ + + + ); +} + +export default MissingResources; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/ResourceInfo.js b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/ResourceInfo.js new file mode 100644 index 000000000..d4b1ed9b8 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/ResourceInfo.js @@ -0,0 +1,18 @@ +import { diffFromNowString } from 'App/date'; +import { TextEllipsis } from 'UI'; + +import styles from './resourceInfo.css'; + +export default class ResourceInfo extends React.PureComponent { + render() { + const { data } = this.props; + return ( +
+ +
+ { data.endedAt && data.startedAt && `${ diffFromNowString(data.endedAt) } ago - ${ diffFromNowString(data.startedAt) } old` } +
+
+ ); + } +} diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/index.ts b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/index.ts new file mode 100644 index 000000000..db419a09a --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/index.ts @@ -0,0 +1 @@ +export { default } from './MissingResources' \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/resourceInfo.css b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/resourceInfo.css new file mode 100644 index 000000000..d73d23530 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/MissingResources/resourceInfo.css @@ -0,0 +1,10 @@ +.name { + letter-spacing: -.04em; + font-size: .9rem; + cursor: pointer; +} + +.timings { + color: $gray-medium; + font-size: 12px; +} \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd/ResourceLoadedVsResponseEnd.tsx b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd/ResourceLoadedVsResponseEnd.tsx new file mode 100644 index 000000000..378a3abdc --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd/ResourceLoadedVsResponseEnd.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { NoContent } from 'UI'; +import { Styles } from '../../common'; +import { + ComposedChart, Bar, CartesianGrid, Line, Legend, ResponsiveContainer, + XAxis, YAxis, Tooltip +} from 'recharts'; + +interface Props { + data: any +} +function ResourceLoadedVsResponseEnd(props: Props) { + const { data } = props; + const params = { density: 70 } + + return ( + + + + + + Styles.tickFormatter(val, 'ms')} + /> + Styles.tickFormatter(val, 'ms')} + /> + + + + + + + + + ); +} + +export default ResourceLoadedVsResponseEnd; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd/index.ts b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd/index.ts new file mode 100644 index 000000000..072096a6f --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd/index.ts @@ -0,0 +1 @@ +export { default } from './ResourceLoadedVsResponseEnd' \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete/ResourceLoadedVsVisuallyComplete.tsx b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete/ResourceLoadedVsVisuallyComplete.tsx new file mode 100644 index 000000000..cab6b10ee --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete/ResourceLoadedVsVisuallyComplete.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { NoContent } from 'UI'; +import { Styles } from '../../common'; +import { + ComposedChart, Bar, CartesianGrid, Line, Legend, ResponsiveContainer, + XAxis, YAxis, Tooltip +} from 'recharts'; + +interface Props { + data: any +} +function ResourceLoadedVsVisuallyComplete(props: Props) { + const { data } = props; + const gradientDef = Styles.gradientDef(); + const params = { density: 70 } + + return ( + + + + + + Styles.tickFormatter(val, 'ms')} + /> + Styles.tickFormatter(val)} + /> + + + + + + + + + + ); +} + +export default ResourceLoadedVsVisuallyComplete; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete/index.ts b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete/index.ts new file mode 100644 index 000000000..af77c13fa --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete/index.ts @@ -0,0 +1 @@ +export { default } from './ResourceLoadedVsVisuallyComplete' \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime/ResourceLoadingTime.tsx b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime/ResourceLoadingTime.tsx new file mode 100644 index 000000000..f83b7c01f --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime/ResourceLoadingTime.tsx @@ -0,0 +1,122 @@ +import React from 'react'; +import { NoContent, DropdownPlain } from 'UI'; +import { Styles, AvgLabel } from '../../common'; +import { withRequest } from 'HOCs' +import { + AreaChart, Area, + BarChart, Bar, CartesianGrid, Tooltip, + LineChart, Line, Legend, ResponsiveContainer, + XAxis, YAxis + } from 'recharts'; +import WidgetAutoComplete from 'Shared/WidgetAutoComplete'; +import { toUnderscore } from 'App/utils'; + +const WIDGET_KEY = 'resourcesLoadingTime'; +export const RESOURCE_OPTIONS = [ + { text: 'All', value: 'all', }, + { text: 'JS', value: "SCRIPT", }, + { text: 'CSS', value: "STYLESHEET", }, + { text: 'Fetch', value: "REQUEST", }, + { text: 'Image', value: "IMG", }, + { text: 'Media', value: "MEDIA", }, + { text: 'Other', value: "OTHER", }, +]; + +interface Props { + data: any + optionsLoading: any + fetchOptions: any + options: any +} +function ResourceLoadingTime(props: Props) { + const { data, optionsLoading } = props; + const gradientDef = Styles.gradientDef(); + const params = { density: 70 } + const [autoCompleteSelected, setSutoCompleteSelected] = React.useState(''); + const [type, setType] = React.useState(''); + + const onSelect = (params) => { + const _params = { density: 70 } + setSutoCompleteSelected(params.value); + console.log('params', params) // TODO reload the data with new params; + // this.props.fetchWidget(WIDGET_KEY, dashbaordStore.period, props.platform, { ..._params, url: params.value }) + } + + const writeOption = (e, { name, value }) => { + // this.setState({ [name]: value }) + setType(value); + const _params = { density: 70 } // TODO reload the data with new params; + // this.props.fetchWidget(WIDGET_KEY, this.props.period, this.props.platform, { ..._params, [ name ]: value === 'all' ? null : value }) + } + + return ( + + <> +
+ + + +
+ + + {gradientDef} + + + Styles.tickFormatter(val)} + label={{ ...Styles.axisLabelLeft, value: "CPU Load (%)" }} + /> + + + + + +
+ ); +} + +export default withRequest({ + dataName: "options", + initialData: [], + dataWrapper: data => data, + loadingName: 'optionsLoading', + requestName: "fetchOptions", + endpoint: '/dashboard/' + toUnderscore(WIDGET_KEY) + '/search', + method: 'GET' +})(ResourceLoadingTime) \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime/index.ts b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime/index.ts new file mode 100644 index 000000000..1c9fa51c8 --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime/index.ts @@ -0,0 +1 @@ +export { default } from './ResourceLoadingTime' \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests/SessionsImpactedBySlowRequests.tsx b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests/SessionsImpactedBySlowRequests.tsx new file mode 100644 index 000000000..5314a054b --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests/SessionsImpactedBySlowRequests.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { NoContent } from 'UI'; +import { Styles } from '../../common'; +import { + AreaChart, Area, + BarChart, Bar, CartesianGrid, Tooltip, + LineChart, Line, Legend, ResponsiveContainer, + XAxis, YAxis + } from 'recharts'; + +interface Props { + data: any +} +function SessionsImpactedBySlowRequests(props: Props) { + const { data } = props; + const gradientDef = Styles.gradientDef(); + const params = { density: 70 } + + return ( + + + + {gradientDef} + + + Styles.tickFormatter(val)} + label={{ ...Styles.axisLabelLeft, value: "CPU Load (%)" }} + /> + + + + + + ); +} + +export default SessionsImpactedBySlowRequests; \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests/index.ts b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests/index.ts new file mode 100644 index 000000000..d950b82ae --- /dev/null +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests/index.ts @@ -0,0 +1 @@ +export { default } from './SessionsImpactedBySlowRequests' \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/TimeToRender/TimeToRender.tsx b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/TimeToRender/TimeToRender.tsx index 5332f71c5..1a3ab28ab 100644 --- a/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/TimeToRender/TimeToRender.tsx +++ b/frontend/app/components/Dashboard/Widgets/PredefinedWidgets/TimeToRender/TimeToRender.tsx @@ -47,7 +47,7 @@ function TimeToRender(props: Props) { /> - +
{activeCategory && activeCategory.widgets.map((widget: any) => ( diff --git a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx index 86bffb9e9..a0d4dd75e 100644 --- a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx +++ b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx @@ -8,6 +8,7 @@ import { observer, useObserver, useLocalObservable } from 'mobx-react-lite'; import { Loader } from 'UI'; import { useStore } from 'App/mstore'; import WidgetPredefinedChart from '../WidgetPredefinedChart'; +import CustomMetricOverviewChart from '../../Widgets/CustomMetricsWidgets/CustomMetricOverviewChart'; interface Props { metric: any; isWidget?: boolean @@ -45,6 +46,9 @@ function WidgetChart(props: Props) { const { metricType, viewType, predefinedKey } = metric; if (metricType === 'predefined') { + if (viewType === 'overview') { + return + } return } diff --git a/frontend/app/components/Dashboard/components/WidgetPredefinedChart/WidgetPredefinedChart.tsx b/frontend/app/components/Dashboard/components/WidgetPredefinedChart/WidgetPredefinedChart.tsx index da6c49280..7ae8a581f 100644 --- a/frontend/app/components/Dashboard/components/WidgetPredefinedChart/WidgetPredefinedChart.tsx +++ b/frontend/app/components/Dashboard/components/WidgetPredefinedChart/WidgetPredefinedChart.tsx @@ -5,17 +5,23 @@ import ErrorsByType from 'App/components/Dashboard/Widgets/PredefinedWidgets/Err import ErrorsByOrigin from 'App/components/Dashboard/Widgets/PredefinedWidgets/ErrorsByOrigin'; import ErrorsPerDomain from 'App/components/Dashboard/Widgets/PredefinedWidgets/ErrorsPerDomain'; import { useObserver } from 'mobx-react-lite'; -import SessionsAffectedByJSErrors from '../../Widgets/PredefinedWidgets/SessionsAffectedByJSErrors'; -import CallsErrors4xx from '../../Widgets/PredefinedWidgets/CallsErrors4xx'; -import CallsErrors5xx from '../../Widgets/PredefinedWidgets/CallsErrors5xx'; -import CPULoad from '../../Widgets/PredefinedWidgets/CPULoad'; -import Crashes from '../../Widgets/PredefinedWidgets/Crashes'; -import DomBuildingTime from '../../Widgets/PredefinedWidgets/DomBuildingTime'; -import FPS from '../../Widgets/PredefinedWidgets/FPS'; -import MemoryConsumption from '../../Widgets/PredefinedWidgets/MemoryConsumption'; -import ResponseTime from '../../Widgets/PredefinedWidgets/ResponseTime'; -import TimeToRender from '../../Widgets/PredefinedWidgets/TimeToRender'; -import SlowestDomains from '../../Widgets/PredefinedWidgets/SlowestDomains'; +import SessionsAffectedByJSErrors from 'App/components/Dashboard/Widgets/PredefinedWidgets/SessionsAffectedByJSErrors'; +import CallsErrors4xx from 'App/components/Dashboard/Widgets/PredefinedWidgets/CallsErrors4xx'; +import CallsErrors5xx from 'App/components/Dashboard/Widgets/PredefinedWidgets/CallsErrors5xx'; +import CPULoad from 'App/components/Dashboard/Widgets/PredefinedWidgets/CPULoad'; +import Crashes from 'App/components/Dashboard/Widgets/PredefinedWidgets/Crashes'; +import DomBuildingTime from 'App/components/Dashboard/Widgets/PredefinedWidgets/DomBuildingTime'; +import FPS from 'App/components/Dashboard/Widgets/PredefinedWidgets/FPS'; +import MemoryConsumption from 'App/components/Dashboard/Widgets/PredefinedWidgets/MemoryConsumption'; +import ResponseTime from 'App/components/Dashboard/Widgets/PredefinedWidgets/ResponseTime'; +import TimeToRender from 'App/components/Dashboard/Widgets/PredefinedWidgets/TimeToRender'; +import SlowestDomains from 'App/components/Dashboard/Widgets/PredefinedWidgets/SlowestDomains'; +import ResourceLoadedVsVisuallyComplete from 'App/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsVisuallyComplete'; +import SessionsImpactedBySlowRequests from 'App/components/Dashboard/Widgets/PredefinedWidgets/SessionsImpactedBySlowRequests'; +import ResourceLoadingTime from 'App/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadingTime'; +import BreakdownOfLoadedResources from 'App/components/Dashboard/Widgets/PredefinedWidgets/BreakdownOfLoadedResources'; +import MissingResources from 'App/components/Dashboard/Widgets/PredefinedWidgets/MissingResources'; +import ResourceLoadedVsResponseEnd from 'App/components/Dashboard/Widgets/PredefinedWidgets/ResourceLoadedVsResponseEnd'; interface Props { data: any; @@ -23,8 +29,6 @@ interface Props { } function WidgetPredefinedChart(props: Props) { const { data, predefinedKey } = props; - // const { viewType } = data; - const params = { density: 70 } const renderWidget = () => { switch (predefinedKey) { @@ -43,6 +47,9 @@ function WidgetPredefinedChart(props: Props) { return // PERFORMANCE + // case 'impacted_sessions_by_slow_pages': + // case 'pages_response_time_distribution': + // case 'speed_location': case 'cpu': return case 'crashes': @@ -55,19 +62,28 @@ function WidgetPredefinedChart(props: Props) { return case 'pages_response_time': return - // case 'pages_response_time_distribution': - // case 'resources_vs_visually_complete': - // case 'impacted_sessions_by_slow_pages': - // case 'sessions_per_browser': + case 'resources_vs_visually_complete': + return + case 'sessions_per_browser': + return case 'slowest_domains': return - // case 'speed_location': case 'time_to_render': return + // Resources + case 'resources_count_by_type': + return + case 'missing_resources': + return + case 'resource_type_vs_response_end': + return + case 'resources_loading_time': + return + // case 'slowest_resources': default: - return
No widget found
+ return
Widget not supported
} } diff --git a/frontend/app/components/ui/NoContent/NoContent.js b/frontend/app/components/ui/NoContent/NoContent.js index 8c14a0917..83b4f53f3 100644 --- a/frontend/app/components/ui/NoContent/NoContent.js +++ b/frontend/app/components/ui/NoContent/NoContent.js @@ -9,9 +9,10 @@ export default ({ show = true, children = null, empty = false, - image = null + image = null, + style = {}, }) => (!show ? children : -
+
{ icon &&
} diff --git a/frontend/app/mstore/dashboardStore.ts b/frontend/app/mstore/dashboardStore.ts index 6f2e35da2..0231bbf7c 100644 --- a/frontend/app/mstore/dashboardStore.ts +++ b/frontend/app/mstore/dashboardStore.ts @@ -193,19 +193,25 @@ export default class DashboardStore implements IDashboardSotre { dashboard.metrics = this.selectedWidgets.map(w => w.metricId) - return dashboardService.saveDashboard(dashboard).then(_dashboard => { - runInAction(() => { - if (isCreating) { - toast.success('Dashboard created successfully') - this.addDashboard(_dashboard) - } else { - toast.success('Dashboard updated successfully') - this.updateDashboard(_dashboard) - } - }) - }).finally(() => { - runInAction(() => { - this.isSaving = false + return new Promise((resolve, reject) => { + dashboardService.saveDashboard(dashboard).then(_dashboard => { + runInAction(() => { + if (isCreating) { + toast.success('Dashboard created successfully') + this.addDashboard(_dashboard) + } else { + toast.success('Dashboard updated successfully') + this.updateDashboard(_dashboard) + } + resolve(_dashboard) + }) + }).catch(error => { + toast.error('Error saving dashboard') + reject() + }).finally(() => { + runInAction(() => { + this.isSaving = false + }) }) }) } @@ -406,12 +412,12 @@ export default class DashboardStore implements IDashboardSotre { metric.setData(_data) resolve(_data); } else { - if (metric.predefinedKey === 'errors_per_domains') { - console.log('errors_per_domains', data) - data.chart = data - } else { - data.chart = getChartFormatter(this.period)(Array.isArray(data) ? data : data.chart) - } + // if (metric.predefinedKey === 'errors_per_domains') { + // console.log('errors_per_domains', data) + // data.chart = data + // } else { + // data.chart = getChartFormatter(this.period)(Array.isArray(data) ? data : data.chart) + // } data.namesMap = Array.isArray(data) ? data .map(i => Object.keys(i)) .flat() @@ -422,10 +428,40 @@ export default class DashboardStore implements IDashboardSotre { } return unique; }, []) : data.chart; - console.log('map', data.namesMap) - const _data = { namesMap: data.namesMap, chart: data.chart } + // console.log('map', data.namesMap) + // const _data = { ...data, namesMap: data.namesMap, chart: data.chart } + // metric.setData(_data) + // resolve(_data); + + const _data = {} + if (data.hasOwnProperty('chart')) { + _data['chart'] = getChartFormatter(this.period)(data.chart) + _data['namesMap'] = data.chart + .map(i => Object.keys(i)) + .flat() + .filter(i => i !== 'time' && i !== 'timestamp') + .reduce((unique: any, item: any) => { + if (!unique.includes(item)) { + unique.push(item); + } + return unique; + }, []) + } else { + _data['chart'] = data + _data['namesMap'] = data + .map(i => Object.keys(i)) + .flat() + .filter(i => i !== 'time' && i !== 'timestamp') + .reduce((unique: any, item: any) => { + if (!unique.includes(item)) { + unique.push(item); + } + return unique; + }, []) + } + metric.setData(_data) - resolve(_data); + resolve({ ...data, ..._data }); } }).catch((err) => { console.log('err', err) diff --git a/frontend/app/mstore/types/widget.ts b/frontend/app/mstore/types/widget.ts index 09d96d699..ee9c559b4 100644 --- a/frontend/app/mstore/types/widget.ts +++ b/frontend/app/mstore/types/widget.ts @@ -111,6 +111,7 @@ export default class Widget implements IWidget { } fromJson(json: any) { + json.config = json.config || {} runInAction(() => { this.metricId = json.metricId this.widgetId = json.widgetId