Browse Source

feat(workflow): Sort all team stats tables by trend (#29503)

Scott Cooper 3 years ago
parent
commit
f6aad2c871

+ 4 - 5
static/app/views/organizationStats/teamInsights/teamMisery.tsx

@@ -20,6 +20,8 @@ import type {Color} from 'app/utils/theme';
 
 import {transactionSummaryRouteWithQuery} from '../../performance/transactionSummary/utils';
 
+import {groupByTrend} from './utils';
+
 type TeamMiseryProps = {
   organization: Organization;
   location: Location;
@@ -31,7 +33,7 @@ type TeamMiseryProps = {
 };
 
 /** The number of elements to display before collapsing */
-const COLLAPSE_COUNT = 8;
+const COLLAPSE_COUNT = 5;
 
 function TeamMisery({
   organization,
@@ -69,10 +71,7 @@ function TeamMisery({
     .filter(x => x.trend !== null)
     .sort((a, b) => Math.abs(b.trend) - Math.abs(a.trend));
 
-  const worseItems = sortedTableData.filter(x => Math.round(x.trend) < 0);
-  const betterItems = sortedTableData.filter(x => Math.round(x.trend) > 0);
-  const zeroItems = sortedTableData.filter(x => Math.round(x.trend) === 0);
-  const groupedData = [...worseItems, ...betterItems, ...zeroItems];
+  const groupedData = groupByTrend(sortedTableData);
 
   return (
     <Fragment>

+ 11 - 2
static/app/views/organizationStats/teamInsights/teamReleases.tsx

@@ -19,7 +19,7 @@ import space from 'app/styles/space';
 import {Organization, Project} from 'app/types';
 import {Color, Theme} from 'app/utils/theme';
 
-import {barAxisLabel, convertDaySeriesToWeeks} from './utils';
+import {barAxisLabel, convertDaySeriesToWeeks, groupByTrend} from './utils';
 
 type Props = AsyncComponent['props'] & {
   theme: Theme;
@@ -172,6 +172,12 @@ class TeamReleases extends AsyncComponent<Props, State> {
     const {projects, period, theme} = this.props;
     const {periodReleases} = this.state;
 
+    const sortedProjects = projects
+      .map(project => ({project, trend: this.getTrend(Number(project.id)) ?? 0}))
+      .sort((a, b) => Math.abs(b.trend) - Math.abs(a.trend));
+
+    const groupedProjects = groupByTrend(sortedProjects);
+
     const data = Object.entries(periodReleases?.release_counts ?? {}).map(
       ([bucket, count]) => ({
         value: Math.ceil(count),
@@ -209,6 +215,9 @@ class TeamReleases extends AsyncComponent<Props, State> {
                   lineStyle: {color: theme.gray200, type: 'dashed', width: 1},
                   // @ts-expect-error yAxis type not correct
                   data: [{yAxis: totalPeriodAverage}],
+                  label: {
+                    show: false,
+                  },
                 }),
               },
             ]}
@@ -247,7 +256,7 @@ class TeamReleases extends AsyncComponent<Props, State> {
             <RightAligned key="diff">{t('Difference')}</RightAligned>,
           ]}
         >
-          {projects.map(project => (
+          {groupedProjects.map(({project}) => (
             <Fragment key={project.id}>
               <ProjectBadgeContainer>
                 <ProjectBadge avatarSize={18} project={project} />

+ 9 - 1
static/app/views/organizationStats/teamInsights/teamStability.tsx

@@ -17,6 +17,8 @@ import {getCrashFreeRate} from 'app/utils/sessions';
 import {Color} from 'app/utils/theme';
 import {displayCrashFreePercent} from 'app/views/releases/utils';
 
+import {groupByTrend} from './utils';
+
 type Props = AsyncComponent['props'] & {
   organization: Organization;
   projects: Project[];
@@ -171,6 +173,12 @@ class TeamStability extends AsyncComponent<Props, State> {
   renderBody() {
     const {projects, period} = this.props;
 
+    const sortedProjects = projects
+      .map(project => ({project, trend: this.getTrend(Number(project.id)) ?? 0}))
+      .sort((a, b) => Math.abs(b.trend) - Math.abs(a.trend));
+
+    const groupedProjects = groupByTrend(sortedProjects);
+
     return (
       <StyledPanelTable
         isEmpty={projects.length === 0}
@@ -181,7 +189,7 @@ class TeamStability extends AsyncComponent<Props, State> {
           <RightAligned key="diff">{t('Difference')}</RightAligned>,
         ]}
       >
-        {projects.map(project => (
+        {groupedProjects.map(({project}) => (
           <Fragment key={project.id}>
             <ProjectBadgeContainer>
               <ProjectBadge avatarSize={18} project={project} />

+ 10 - 0
static/app/views/organizationStats/teamInsights/utils.tsx

@@ -31,6 +31,16 @@ export function convertDayValueObjectToSeries(
   }));
 }
 
+/**
+ * Takes a sorted array of trend items and groups them by worst/better/no chagne
+ */
+export function groupByTrend<T extends {trend: number}>(data: T[]): T[] {
+  const worseItems = data.filter(x => Math.round(x.trend) < 0);
+  const betterItems = data.filter(x => Math.round(x.trend) > 0);
+  const zeroItems = data.filter(x => Math.round(x.trend) === 0);
+  return [...worseItems, ...betterItems, ...zeroItems];
+}
+
 export const barAxisLabel = (
   dataEntries: number
 ): React.ComponentProps<typeof BaseChart>['xAxis'] => {

+ 2 - 2
tests/js/spec/views/organizationStats/teamInsights/teamMisery.spec.jsx

@@ -105,11 +105,11 @@ describe('TeamMisery', () => {
     expect(periodMisery).toHaveBeenCalledTimes(1);
 
     // Should have 8 items, the rest are collapsed.
-    expect(screen.getAllByText(project.slug)).toHaveLength(8);
+    expect(screen.getAllByText(project.slug)).toHaveLength(5);
 
     expect(screen.getByText('10% better')).toBeInTheDocument();
     expect(screen.getByText('25% worse')).toBeInTheDocument();
-    expect(screen.getAllByText('0% change')).toHaveLength(6);
+    expect(screen.getAllByText('0% change')).toHaveLength(3);
 
     expect(screen.getByText('More')).toBeInTheDocument();
     fireEvent.click(screen.getByText('More'));