Browse Source

feat(discover): Add percentage data for `getChartData` (#11329)

Adds an option to calculate percentage data for each series
Billy Vong 6 years ago
parent
commit
28a640b8b0

+ 45 - 6
src/sentry/static/sentry/app/views/organizationDiscover/result/utils.jsx

@@ -14,11 +14,9 @@ const CHART_KEY = '__CHART_KEY__';
  *
  * @param {Array} data Data returned from Snuba
  * @param {Object} query Query state corresponding to data
- * @param {Object} [options] Options object
- * @param {Boolean} [options.hideFieldName] (default: false) Hide field name in results set
  * @returns {Array}
  */
-export function getChartData(data, query, options = {}) {
+export function getChartData(data, query) {
   const {fields} = query;
 
   return query.aggregations.map(aggregation => {
@@ -27,10 +25,51 @@ export function getChartData(data, query, options = {}) {
       data: data.map(res => {
         return {
           value: res[aggregation[2]],
-          name: fields
-            .map(field => `${options.hideFieldName ? '' : `${field} `}${res[field]}`)
-            .join(options.separator || ' '),
+          name: fields.map(field => `${field} ${res[field]}`).join(' '),
+        };
+      }),
+    };
+  });
+}
+
+/**
+ * Returns data formatted for charts, with each aggregation representing a series.
+ * Includes each aggregation's series relative percentage to total within that aggregation.
+ *
+ * @param {Array} data Data returned from Snuba
+ * @param {Object} query Query state corresponding to data
+ * @returns {Array}
+ */
+export function getChartDataWithPercentages(data, query) {
+  const {fields} = query;
+
+  const totalsBySeries = new Map();
+
+  query.aggregations.forEach(aggregation => {
+    totalsBySeries.set(
+      aggregation[2],
+      data.reduce((acc, res) => {
+        acc += res[aggregation[2]];
+        return acc;
+      }, 0)
+    );
+  });
+
+  return query.aggregations.map(aggregation => {
+    const total = totalsBySeries.get(aggregation[2]);
+    return {
+      seriesName: aggregation[2],
+      data: data.map(res => {
+        const obj = {
+          value: res[aggregation[2]],
+          name: fields.map(field => `${res[field]}`).join(' '),
         };
+
+        if (total) {
+          obj.percentage = Math.round(res[aggregation[2]] / total * 10000) / 100;
+        }
+
+        return obj;
       }),
     };
   });

+ 23 - 34
tests/js/spec/views/organizationDiscover/result/utils.spec.jsx

@@ -2,6 +2,7 @@ import {mount} from 'enzyme';
 
 import {
   getChartData,
+  getChartDataWithPercentages,
   getChartDataByDay,
   getDisplayValue,
   getDisplayText,
@@ -45,55 +46,43 @@ describe('Utils', function() {
 
       expect(getChartData(raw, query)).toEqual(expected);
     });
+  });
 
-    it('customizes separator', function() {
-      const expected = [
-        {
-          seriesName: 'count',
-          data: [
-            {value: 2, name: 'project.id 5, environment null'},
-            {value: 2, name: 'project.id 5, environment staging'},
-            {value: 2, name: 'project.id 5, environment alpha'},
-            {value: 6, name: 'project.id 5, environment production'},
-          ],
-        },
-        {
-          seriesName: 'uniq_id',
-          data: [
-            {value: 1, name: 'project.id 5, environment null'},
-            {value: 3, name: 'project.id 5, environment staging'},
-            {value: 4, name: 'project.id 5, environment alpha'},
-            {value: 10, name: 'project.id 5, environment production'},
-          ],
-        },
-      ];
-
-      expect(getChartData(raw, query, {separator: ', '})).toEqual(expected);
-    });
+  describe('getChartDataWithPercentages()', function() {
+    const raw = [
+      {count: 2, uniq_id: 1, 'project.id': 5, environment: null},
+      {count: 2, uniq_id: 3, 'project.id': 5, environment: 'staging'},
+      {count: 2, uniq_id: 4, 'project.id': 5, environment: 'alpha'},
+      {count: 6, uniq_id: 10, 'project.id': 5, environment: 'production'},
+    ];
+    const query = {
+      aggregations: [['count()', null, 'count'], ['uniq', 'id', 'uniq_id']],
+      fields: ['project.id', 'environment'],
+    };
 
-    it('hides field name for series label', function() {
+    it('returns chart data with percentages', function() {
       const expected = [
         {
           seriesName: 'count',
           data: [
-            {value: 2, name: '5 null'},
-            {value: 2, name: '5 staging'},
-            {value: 2, name: '5 alpha'},
-            {value: 6, name: '5 production'},
+            {value: 2, percentage: 16.67, name: '5 null'},
+            {value: 2, percentage: 16.67, name: '5 staging'},
+            {value: 2, percentage: 16.67, name: '5 alpha'},
+            {value: 6, percentage: 50, name: '5 production'},
           ],
         },
         {
           seriesName: 'uniq_id',
           data: [
-            {value: 1, name: '5 null'},
-            {value: 3, name: '5 staging'},
-            {value: 4, name: '5 alpha'},
-            {value: 10, name: '5 production'},
+            {value: 1, percentage: 5.56, name: '5 null'},
+            {value: 3, percentage: 16.67, name: '5 staging'},
+            {value: 4, percentage: 22.22, name: '5 alpha'},
+            {value: 10, percentage: 55.56, name: '5 production'},
           ],
         },
       ];
 
-      expect(getChartData(raw, query, {hideFieldName: true})).toEqual(expected);
+      expect(getChartDataWithPercentages(raw, query)).toEqual(expected);
     });
   });