Browse Source

feat(crons): Split duration graph from checks graph (#48644)

https://www.figma.com/file/cfcxnhwGet0cHZKEZXY5kV/Crons?node-id=289-8491&t=RrpBmUGmB9sUE7P9-0

Before:
<img width="910" alt="image"
src="https://user-images.githubusercontent.com/9372512/236539766-130c43a8-2641-403f-970f-fc1704fc651e.png">


After:
<img width="900" alt="image"
src="https://user-images.githubusercontent.com/9372512/236539639-7d32cf9f-d28c-49eb-ac3e-ee05fecff984.png">

Closes: https://github.com/getsentry/sentry/issues/48592
David Wang 1 year ago
parent
commit
2a49f2f074
1 changed files with 57 additions and 37 deletions
  1. 57 37
      static/app/views/monitors/components/monitorStats.tsx

+ 57 - 37
static/app/views/monitors/components/monitorStats.tsx

@@ -1,11 +1,14 @@
-import type {LineSeriesOption} from 'echarts';
+import React from 'react';
+import styled from '@emotion/styled';
 
+import {AreaChart, AreaChartSeries} from 'sentry/components/charts/areaChart';
 import {BarChart, BarChartSeries} from 'sentry/components/charts/barChart';
 import {getYAxisMaxFn} from 'sentry/components/charts/miniBarChart';
-import LineSeries from 'sentry/components/charts/series/lineSeries';
+import {HeaderTitle} from 'sentry/components/charts/styles';
 import EmptyMessage from 'sentry/components/emptyMessage';
 import {Panel, PanelBody} from 'sentry/components/panels';
 import {t} from 'sentry/locale';
+import {space} from 'sentry/styles/space';
 import {intervalToMilliseconds} from 'sentry/utils/dates';
 import {axisLabelFormatter, tooltipFormatter} from 'sentry/utils/discover/charts';
 import {AggregationOutputType} from 'sentry/utils/discover/fields';
@@ -59,25 +62,24 @@ const MonitorStats = ({monitor, monitorEnv, orgId}: Props) => {
   let emptyStats = true;
   const success: BarChartSeries = {
     seriesName: t('Successful'),
-    yAxisIndex: 0,
     data: [],
   };
   const failed: BarChartSeries = {
     seriesName: t('Failed'),
-    yAxisIndex: 0,
     data: [],
   };
   const missed: BarChartSeries = {
     seriesName: t('Missed'),
-    yAxisIndex: 0,
     data: [],
   };
   const timeout: BarChartSeries = {
     seriesName: t('Timeout'),
-    yAxisIndex: 0,
     data: [],
   };
-  const durationData = [] as [number, number][];
+  const duration: AreaChartSeries = {
+    seriesName: t('Average Duration'),
+    data: [],
+  };
 
   data.stats?.forEach(p => {
     if (p.ok || p.error || p.missed || p.timeout) {
@@ -88,22 +90,10 @@ const MonitorStats = ({monitor, monitorEnv, orgId}: Props) => {
     failed.data.push({name: timestamp, value: p.error});
     timeout.data.push({name: timestamp, value: p.timeout});
     missed.data.push({name: timestamp, value: p.missed});
-    durationData.push([timestamp, Math.trunc(p.duration)]);
+    duration.data.push({name: timestamp, value: Math.trunc(p.duration)});
   });
   const colors = [theme.green200, theme.red200, theme.red200, theme.yellow200];
 
-  const durationTitle = t('Average Duration');
-  const additionalSeries: LineSeriesOption[] = [
-    LineSeries({
-      name: durationTitle,
-      data: durationData,
-      lineStyle: {color: theme.purple300, width: 2},
-      itemStyle: {color: theme.purple300},
-      yAxisIndex: 1,
-      animation: false,
-    }),
-  ];
-
   const height = 150;
   const getYAxisOptions = (aggregateType: AggregationOutputType) => ({
     max: getYAxisMaxFn(height),
@@ -116,44 +106,74 @@ const MonitorStats = ({monitor, monitorEnv, orgId}: Props) => {
     },
   });
 
+  if (emptyStats) {
+    return renderComponent(
+      <Panel>
+        <PanelBody withPadding>
+          <EmptyMessage
+            title={t('No check-ins have been recorded for this time period.')}
+          />
+        </PanelBody>
+      </Panel>
+    );
+  }
+
   return renderComponent(
-    <Panel>
-      <PanelBody withPadding>
-        {!emptyStats ? (
+    <React.Fragment>
+      <Panel>
+        <PanelBody withPadding>
+          <StyledHeaderTitle>{t('Recent Check-Ins')}</StyledHeaderTitle>
           <BarChart
             isGroupedByDate
             showTimeInTooltip
             useShortDate
             series={[success, failed, timeout, missed]}
             stacked
-            additionalSeries={additionalSeries}
             height={height}
             colors={colors}
             tooltip={{
               trigger: 'axis',
-              valueFormatter: (value: number, label?: string) => {
-                return label === durationTitle
-                  ? tooltipFormatter(value, 'duration')
-                  : tooltipFormatter(value, 'number');
-              },
             }}
-            yAxes={[{...getYAxisOptions('number')}, {...getYAxisOptions('duration')}]}
+            yAxis={getYAxisOptions('number')}
             grid={{
               top: 6,
               bottom: 0,
-              left: 4,
+              left: 0,
               right: 0,
             }}
             animation={false}
           />
-        ) : (
-          <EmptyMessage
-            title={t('No check-ins have been recorded for this time period.')}
+        </PanelBody>
+      </Panel>
+      <Panel>
+        <PanelBody withPadding>
+          <StyledHeaderTitle>{t('Average Duration')}</StyledHeaderTitle>
+          <AreaChart
+            isGroupedByDate
+            showTimeInTooltip
+            useShortDate
+            series={[duration]}
+            height={height}
+            colors={[theme.charts.colors[0]]}
+            yAxis={getYAxisOptions('duration')}
+            grid={{
+              top: 6,
+              bottom: 0,
+              left: 0,
+              right: 0,
+            }}
+            tooltip={{
+              valueFormatter: value => tooltipFormatter(value, 'duration'),
+            }}
           />
-        )}
-      </PanelBody>
-    </Panel>
+        </PanelBody>
+      </Panel>
+    </React.Fragment>
   );
 };
 
+const StyledHeaderTitle = styled(HeaderTitle)`
+  margin-bottom: ${space(1)};
+`;
+
 export default MonitorStats;