Просмотр исходного кода

feat(ui): Show conditional release comparisons (#27497)

Matej Minar 3 лет назад
Родитель
Сommit
54e3b371a7

+ 2 - 2
static/app/utils/sessions.tsx

@@ -10,7 +10,7 @@ import {
 import {SessionApiResponse, SessionField, SessionStatus} from 'app/types';
 import {SeriesDataUnit} from 'app/types/echarts';
 import {defined, percent} from 'app/utils';
-import {getCrashFreePercent} from 'app/views/releases/utils';
+import {getCrashFreePercent, getSessionStatusPercent} from 'app/views/releases/utils';
 
 export function getCount(groups: SessionApiResponse['groups'] = [], field: SessionField) {
   return groups.reduce((acc, group) => acc + group.totals[field], 0);
@@ -103,7 +103,7 @@ export function getSessionStatusRateSeries(
 
       return {
         name: interval,
-        value: statusSessionsPercent,
+        value: getSessionStatusPercent(statusSessionsPercent),
       };
     })
   );

+ 27 - 22
static/app/views/releases/detail/overview/index.tsx

@@ -454,19 +454,22 @@ class ReleaseOverview extends AsyncView<Props> {
                               }}
                               defaultPeriod={RELEASE_PERIOD_KEY}
                             />
-                            <ReleaseComparisonChart
-                              release={release}
-                              releaseSessions={thisRelease}
-                              allSessions={allReleases}
-                              platform={project.platform}
-                              location={location}
-                              loading={loading}
-                              reloading={reloading}
-                              errored={errored}
-                              project={project}
-                              organization={organization}
-                              api={api}
-                            />
+                            {(hasDiscover || hasPerformance || hasHealthData) && (
+                              <ReleaseComparisonChart
+                                release={release}
+                                releaseSessions={thisRelease}
+                                allSessions={allReleases}
+                                platform={project.platform}
+                                location={location}
+                                loading={loading}
+                                reloading={reloading}
+                                errored={errored}
+                                project={project}
+                                organization={organization}
+                                api={api}
+                                hasHealthData={hasHealthData}
+                              />
+                            )}
                           </Fragment>
                         ) : (
                           (hasDiscover || hasPerformance || hasHealthData) && (
@@ -538,15 +541,17 @@ class ReleaseOverview extends AsyncView<Props> {
                       isHealthLoading={isHealthLoading}
                     />
                     <Feature features={['release-comparison']}>
-                      <ReleaseAdoption
-                        releaseSessions={thisRelease}
-                        allSessions={allReleases}
-                        loading={loading}
-                        reloading={reloading}
-                        errored={errored}
-                        release={release}
-                        project={project}
-                      />
+                      {hasHealthData && (
+                        <ReleaseAdoption
+                          releaseSessions={thisRelease}
+                          allSessions={allReleases}
+                          loading={loading}
+                          reloading={reloading}
+                          errored={errored}
+                          release={release}
+                          project={project}
+                        />
+                      )}
                     </Feature>
                     <ProjectReleaseDetails
                       release={release}

+ 20 - 8
static/app/views/releases/detail/overview/releaseAdoption.tsx

@@ -56,10 +56,16 @@ function ReleaseComparisonChart({
       return [];
     }
 
-    const sessionsMarkLines = generateReleaseMarkLines(release, project.slug, theme, {
-      hideLabel: true,
-      axisIndex: 0,
-    });
+    const sessionsMarkLines = generateReleaseMarkLines(
+      release,
+      project.slug,
+      theme,
+      location,
+      {
+        hideLabel: true,
+        axisIndex: 0,
+      }
+    );
 
     const series = [
       ...sessionsMarkLines,
@@ -78,10 +84,16 @@ function ReleaseComparisonChart({
     ];
 
     if (hasUsers) {
-      const usersMarkLines = generateReleaseMarkLines(release, project.slug, theme, {
-        hideLabel: true,
-        axisIndex: 1,
-      });
+      const usersMarkLines = generateReleaseMarkLines(
+        release,
+        project.slug,
+        theme,
+        location,
+        {
+          hideLabel: true,
+          axisIndex: 1,
+        }
+      );
 
       series.push(...usersMarkLines);
       series.push({

Разница между файлами не показана из-за своего большого размера
+ 315 - 572
static/app/views/releases/detail/overview/releaseComparisonChart/index.tsx


+ 332 - 26
static/app/views/releases/detail/overview/releaseComparisonChart/releaseSessionsChart.tsx

@@ -12,22 +12,37 @@ import TransitionChart from 'app/components/charts/transitionChart';
 import TransparentLoadingMask from 'app/components/charts/transparentLoadingMask';
 import QuestionTooltip from 'app/components/questionTooltip';
 import {PlatformKey} from 'app/data/platformCategories';
-import {ReleaseComparisonChartType} from 'app/types';
-import {Series} from 'app/types/echarts';
+import {t} from 'app/locale';
+import {
+  ReleaseComparisonChartType,
+  ReleaseProject,
+  ReleaseWithHealth,
+  SessionApiResponse,
+  SessionField,
+  SessionStatus,
+} from 'app/types';
 import {defined} from 'app/utils';
+import {getCrashFreeRateSeries, getSessionStatusRateSeries} from 'app/utils/sessions';
 import {Theme} from 'app/utils/theme';
 import {displayCrashFreePercent} from 'app/views/releases/utils';
 
 import {
+  generateReleaseMarkLines,
   releaseComparisonChartHelp,
   releaseComparisonChartTitles,
   releaseMarkLinesLabels,
 } from '../../utils';
+import {
+  fillChartDataFromSessionsResponse,
+  initSessionsBreakdownChartData,
+} from '../chart/utils';
 
 type Props = {
   theme: Theme;
-  series: Series[];
-  previousSeries: Series[];
+  release: ReleaseWithHealth;
+  project: ReleaseProject;
+  releaseSessions: SessionApiResponse | null;
+  allSessions: SessionApiResponse | null;
   chartType: ReleaseComparisonChartType;
   platform: PlatformKey;
   value: React.ReactNode;
@@ -70,7 +85,7 @@ class ReleaseSessionsChart extends React.Component<Props> {
     }
   };
 
-  configureYAxis() {
+  getYAxis() {
     const {theme, chartType} = this.props;
     switch (chartType) {
       case ReleaseComparisonChartType.CRASH_FREE_SESSIONS:
@@ -159,31 +174,322 @@ class ReleaseSessionsChart extends React.Component<Props> {
     }
   }
 
+  getSeries(chartType: ReleaseComparisonChartType) {
+    const {releaseSessions, allSessions, release, location, project, theme} = this.props;
+
+    if (!releaseSessions) {
+      return {};
+    }
+
+    const markLines = generateReleaseMarkLines(release, project.slug, theme, location);
+
+    switch (chartType) {
+      case ReleaseComparisonChartType.CRASH_FREE_SESSIONS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getCrashFreeRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.SESSIONS
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getCrashFreeRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.SESSIONS
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.HEALTHY_SESSIONS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getSessionStatusRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.SESSIONS,
+                SessionStatus.HEALTHY
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getSessionStatusRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.SESSIONS,
+                SessionStatus.HEALTHY
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.ABNORMAL_SESSIONS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getSessionStatusRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.SESSIONS,
+                SessionStatus.ABNORMAL
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getSessionStatusRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.SESSIONS,
+                SessionStatus.ABNORMAL
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.ERRORED_SESSIONS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getSessionStatusRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.SESSIONS,
+                SessionStatus.ERRORED
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getSessionStatusRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.SESSIONS,
+                SessionStatus.ERRORED
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.CRASHED_SESSIONS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getSessionStatusRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.SESSIONS,
+                SessionStatus.CRASHED
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getSessionStatusRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.SESSIONS,
+                SessionStatus.CRASHED
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.CRASH_FREE_USERS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getCrashFreeRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.USERS
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getCrashFreeRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.USERS
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.HEALTHY_USERS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getSessionStatusRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.USERS,
+                SessionStatus.HEALTHY
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getSessionStatusRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.USERS,
+                SessionStatus.HEALTHY
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.ABNORMAL_USERS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getSessionStatusRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.USERS,
+                SessionStatus.ABNORMAL
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getSessionStatusRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.USERS,
+                SessionStatus.ABNORMAL
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.ERRORED_USERS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getSessionStatusRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.USERS,
+                SessionStatus.ERRORED
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getSessionStatusRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.USERS,
+                SessionStatus.ERRORED
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.CRASHED_USERS:
+        return {
+          series: [
+            {
+              seriesName: t('This Release'),
+              connectNulls: true,
+              data: getSessionStatusRateSeries(
+                releaseSessions?.groups,
+                releaseSessions?.intervals,
+                SessionField.USERS,
+                SessionStatus.CRASHED
+              ),
+            },
+          ],
+          previousSeries: [
+            {
+              seriesName: t('All Releases'),
+              data: getSessionStatusRateSeries(
+                allSessions?.groups,
+                allSessions?.intervals,
+                SessionField.USERS,
+                SessionStatus.CRASHED
+              ),
+            },
+          ],
+          markLines,
+        };
+      case ReleaseComparisonChartType.SESSION_COUNT:
+        return {
+          series: Object.values(
+            fillChartDataFromSessionsResponse({
+              response: releaseSessions,
+              field: SessionField.SESSIONS,
+              groupBy: 'session.status',
+              chartData: initSessionsBreakdownChartData(),
+            })
+          ),
+          markLines,
+        };
+      case ReleaseComparisonChartType.USER_COUNT:
+        return {
+          series: Object.values(
+            fillChartDataFromSessionsResponse({
+              response: releaseSessions,
+              field: SessionField.USERS,
+              groupBy: 'session.status',
+              chartData: initSessionsBreakdownChartData(),
+            })
+          ),
+          markLines,
+        };
+      default:
+        return {};
+    }
+  }
+
   render() {
-    const {
-      series,
-      previousSeries,
-      chartType,
-      router,
-      period,
-      start,
-      end,
-      utc,
-      value,
-      diff,
-      loading,
-      reloading,
-    } = this.props;
+    const {chartType, router, period, start, end, utc, value, diff, loading, reloading} =
+      this.props;
 
     const Chart = this.getChart();
+    const {series, previousSeries, markLines} = this.getSeries(chartType);
 
     const legend = {
       right: 10,
       top: 0,
-      // do not show adoption markers in the legend
-      data: [...series, ...previousSeries]
-        .filter(s => !s.markLine)
-        .map(s => s.seriesName),
+      data: [...(series ?? []), ...(previousSeries ?? [])].map(s => s.seriesName),
     };
 
     return (
@@ -215,8 +521,8 @@ class ReleaseSessionsChart extends React.Component<Props> {
           {zoomRenderProps => (
             <Chart
               legend={legend}
-              series={series}
-              previousPeriod={previousSeries}
+              series={[...(series ?? []), ...(markLines ?? [])]}
+              previousPeriod={previousSeries ?? []}
               {...zoomRenderProps}
               grid={{
                 left: '10px',
@@ -224,7 +530,7 @@ class ReleaseSessionsChart extends React.Component<Props> {
                 top: '70px',
                 bottom: '0px',
               }}
-              yAxis={this.configureYAxis()}
+              yAxis={this.getYAxis()}
               tooltip={{valueFormatter: this.formatTooltipValue}}
               colors={this.getColors()}
               transformSinglePointToBar

+ 10 - 0
static/app/views/releases/detail/utils.tsx

@@ -234,10 +234,20 @@ export function generateReleaseMarkLines(
   release: ReleaseWithHealth,
   projectSlug: string,
   theme: Theme,
+  location: Location,
   options?: GenerateReleaseMarklineOptions
 ) {
   const adoptionStages = release.adoptionStages?.[projectSlug];
 
+  if (
+    location.query.pageStart ||
+    location.query.pageEnd ||
+    location.query.pageStatsPeriod
+  ) {
+    // for now want to show marklines only on default time period "Entire Release Period"
+    return [];
+  }
+
   const markLines = [
     generateReleaseMarkLine(
       releaseMarkLinesLabels.created,

Некоторые файлы не были показаны из-за большого количества измененных файлов