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

Revert "feat(stats): Display subseries in tooltip (#73869)"

This reverts commit d58fc8b11fc39e4697300c7f537083ccc11376ab.

Co-authored-by: priscilawebdev <29228205+priscilawebdev@users.noreply.github.com>
getsentry-bot 7 месяцев назад
Родитель
Сommit
97648a32ac

+ 0 - 4
static/app/components/charts/baseChart.tsx

@@ -111,10 +111,6 @@ interface TooltipOption
     name: string,
     seriesParams?: TooltipComponentFormatterCallback<any>
   ) => string;
-  /**
-   * If true does not display sublabels with a value of 0.
-   */
-  skipZeroValuedSubLabels?: boolean;
   /**
    * Array containing data that is used to display indented sublabels.
    */

+ 2 - 13
static/app/components/charts/components/tooltip.tsx

@@ -118,10 +118,6 @@ export type FormatterOptions = Pick<
      * Limit the number of series rendered in the tooltip and display "+X more".
      */
     limit?: number;
-    /**
-     * If true does not display sublabels with a value of 0.
-     */
-    skipZeroValuedSubLabels?: boolean;
     /**
      * Array containing data that is used to display indented sublabels.
      */
@@ -142,7 +138,6 @@ export function getFormatter({
   subLabels = [],
   addSecondsToTimeFormat = false,
   limit,
-  skipZeroValuedSubLabels,
 }: FormatterOptions): TooltipComponentFormatterCallback<any> {
   const getFilter = (seriesParam: any) => {
     // Series do not necessarily have `data` defined, e.g. releases don't have `data`, but rather
@@ -258,11 +253,7 @@ export function getFormatter({
           ];
 
           for (const subLabel of filteredSubLabels) {
-            const serieValue = subLabel.data[serie.dataIndex]?.value ?? 0;
-
-            if (skipZeroValuedSubLabels && serieValue === 0) {
-              continue;
-            }
+            const serieValue = subLabel.data[serie.dataIndex].value;
 
             labelWithSubLabels.push(
               `<div><span class="tooltip-label tooltip-label-indent"><strong>${
@@ -270,7 +261,7 @@ export function getFormatter({
               }</strong></span> ${valueFormatter(serieValue)}</div>`
             );
 
-            acc.total = acc.total + serieValue;
+            acc.total = acc.total + subLabel.data[serie.dataIndex].value;
           }
 
           acc.series.push(labelWithSubLabels.join(''));
@@ -345,7 +336,6 @@ export function computeChartTooltip(
     hideDelay,
     subLabels,
     chartId,
-    skipZeroValuedSubLabels,
     ...props
   }: Props,
   theme: Theme
@@ -365,7 +355,6 @@ export function computeChartTooltip(
       nameFormatter,
       markerFormatter,
       subLabels,
-      skipZeroValuedSubLabels,
     });
 
   return {

+ 1 - 2
static/app/types/core.tsx

@@ -118,11 +118,10 @@ export enum Outcome {
   ACCEPTED = 'accepted',
   FILTERED = 'filtered',
   INVALID = 'invalid',
-  ABUSE = 'abuse',
+  DROPPED = 'dropped', // this is not a real outcome coming from the server
   RATE_LIMITED = 'rate_limited',
   CLIENT_DISCARD = 'client_discard',
   CARDINALITY_LIMITED = 'cardinality_limited',
-  DROPPED = 'dropped', // this is not a real outcome coming from the server
 }
 
 export type IntervalPeriod = ReturnType<typeof getInterval>;

+ 3 - 6
static/app/utils/theme.tsx

@@ -424,12 +424,9 @@ const dataCategory = {
  * Default colors for data usage outcomes
  */
 const outcome = {
-  [Outcome.ACCEPTED]: CHART_PALETTE[5][0], // #444674 - chart 100
-  [Outcome.FILTERED]: CHART_PALETTE[5][2], // #B85586 - chart 300
-  [Outcome.RATE_LIMITED]: CHART_PALETTE[5][3], // #E9626E - chart 400
-  [Outcome.INVALID]: CHART_PALETTE[5][4], // #F58C46 - chart 500
-  [Outcome.CLIENT_DISCARD]: CHART_PALETTE[5][5], // #F2B712 - chart 600
-  [Outcome.DROPPED]: CHART_PALETTE[5][3], // #F58C46 - chart 500
+  [Outcome.ACCEPTED]: CHART_PALETTE[0][0],
+  [Outcome.FILTERED]: CHART_PALETTE[1][1],
+  [Outcome.DROPPED]: CHART_PALETTE[5][3],
 };
 
 const generateAlertTheme = (colors: BaseColors, alias: Aliases) => ({

+ 0 - 194
static/app/views/organizationStats/getReasonGroupName.ts

@@ -1,194 +0,0 @@
-import {Outcome} from 'sentry/types';
-
-// List of Relay's current invalid reasons - https://github.com/getsentry/relay/blob/89a8dd7caaad1f126e1cacced0d73bb50fcd4f5a/relay-server/src/services/outcome.rs#L333
-enum DiscardReason {
-  DUPLICATE = 'duplicate',
-  PROJECT_ID = 'project_id',
-  AUTH_VERSION = 'auth_version',
-  AUTH_CLIENT = 'auth_client',
-  NO_DATA = 'no_data',
-  DISALLOWED_METHOD = 'disallowed_method',
-  CONTENT_TYPE = 'content_type',
-  INVALID_MULTIPART = 'invalid_multipart',
-  INVALID_MSGPACK = 'invalid_msgpack',
-  INVALID_JSON = 'invalid_json',
-  INVALID_ENVELOPE = 'invalid_envelope',
-  TIMESTAMP = 'timestamp',
-  DUPLICATE_ITEM = 'duplicate_item',
-  INVALID_TRANSACTION = 'invalid_transaction',
-  INVALID_SPAN = 'invalid_span',
-  INVALID_REPLAY = 'invalid_replay',
-  INVALID_REPLAY_RECORDING = 'invalid_replay_recording',
-  INVALID_REPLAY_VIDEO = 'invalid_replay_video',
-  PAYLOAD = 'payload',
-  INVALID_COMPRESSION = 'invalid_compression',
-  TOO_LARGE = 'too_large',
-  MISSING_MINIDUMP_UPLOAD = 'missing_minidump_upload',
-  INVALID_MINIDUMP = 'invalid_minidump',
-  SECURITY_REPORT = 'security_report',
-  SECURITY_REPORT_TYPE = 'security_report_type',
-  PROCESS_UNREAL = 'process_unreal',
-  CORS = 'cors',
-  NO_EVENT_PAYLOAD = 'no_event_payload',
-  EMPTY_ENVELOPE = 'empty_envelope',
-  INVALID_REPLAY_NO_PAYLOAD = 'invalid_replay_no_payload',
-  TRANSACTION_SAMPLED = 'transaction_sampled',
-  INTERNAL = 'internal',
-  MULTI_PROJECT_ID = 'multi_project_id',
-  PROJECT_STATE = 'project_state',
-  PROJECT_STATE_PII = 'project_state_pii',
-  INVALID_REPLAY_PII_SCRUBBER_FAILED = 'invalid_replay_pii_scrubber_failed',
-  FEATURE_DISABLED = 'feature_disabled',
-}
-
-// List of Relay's current filtered reasons - https://github.com/getsentry/relay/blob/ce5520b4a3bea022808982a52a66bfddacc70ac0/relay-filter/src/common.rs#L11
-enum FilteredReason {
-  BROWSER_EXTENSION = 'browser-extensions',
-  DENIED_NAME = 'denied-name',
-  DISABLED_NAMESPACE = 'disabled-namespace',
-  ERROR_MESSAGE = 'error-message',
-  FILTERED_TRANSACTION = 'filtered-transaction',
-  INVALID_CSP = 'invalid-csp',
-  IP_ADDRESS = 'ip-address',
-  LEGACY_BROWSER = 'legacy-browsers',
-  LOCALHOST = 'localhost',
-  RELEASE_VERSION = 'release-version',
-  WEB_CRAWLER = 'web-crawlers',
-}
-
-// List of Client Discard Reason according to the Client Report's doc - https://develop.sentry.dev/sdk/client-reports/#envelope-item-payload
-enum ClientDiscardReason {
-  QUEUE_OVERFLOW = 'queue_overflow',
-  CACHE_OVERFLOW = 'cache_overflow',
-  RATELIMIT_BACKOFF = 'ratelimit_backoff',
-  NETWORK_ERROR = 'network_error',
-  SAMPLE_RATE = 'sample_rate',
-  BEFORE_SEND = 'before_send',
-  EVENT_PROCESSSOR = 'event_processor',
-  SEND_ERROR = 'send_error',
-  INTERNAL_SDK_ERROR = 'internal_sdk_error',
-  INSUFFICIENT_DATA = 'insufficient_data',
-  BACKPRESSURE = 'backpressure',
-}
-
-enum RateLimitedReason {
-  KEY_QUOTA = 'key_quota',
-  SPIKE_PROTECTION = 'spike_protection',
-  SMART_RATE_LIMIT = 'smart_rate_limit',
-}
-
-// Invalid reasons should not be exposed directly, but instead in the following groups:
-const invalidReasonsGroup: Record<string, DiscardReason[]> = {
-  duplicate: [DiscardReason.DUPLICATE],
-  project_missing: [DiscardReason.PROJECT_ID],
-  invalid_request: [
-    DiscardReason.AUTH_VERSION,
-    DiscardReason.AUTH_CLIENT,
-    DiscardReason.NO_DATA,
-    DiscardReason.DISALLOWED_METHOD,
-    DiscardReason.CONTENT_TYPE,
-    DiscardReason.INVALID_MULTIPART,
-    DiscardReason.INVALID_MSGPACK,
-    DiscardReason.INVALID_JSON,
-    DiscardReason.INVALID_ENVELOPE,
-    DiscardReason.TIMESTAMP,
-    DiscardReason.DUPLICATE_ITEM,
-  ],
-  invalid_data: [
-    DiscardReason.INVALID_TRANSACTION,
-    DiscardReason.INVALID_SPAN,
-    DiscardReason.INVALID_REPLAY,
-    DiscardReason.INVALID_REPLAY_RECORDING,
-    DiscardReason.INVALID_REPLAY_VIDEO,
-  ],
-  payload: [DiscardReason.PAYLOAD, DiscardReason.INVALID_COMPRESSION],
-  too_large: [DiscardReason.TOO_LARGE],
-  minidump: [DiscardReason.MISSING_MINIDUMP_UPLOAD, DiscardReason.INVALID_MINIDUMP],
-  security_report: [DiscardReason.SECURITY_REPORT, DiscardReason.SECURITY_REPORT_TYPE],
-  unreal: [DiscardReason.PROCESS_UNREAL],
-  cors: [DiscardReason.CORS],
-  empty: [
-    DiscardReason.NO_EVENT_PAYLOAD,
-    DiscardReason.EMPTY_ENVELOPE,
-    DiscardReason.INVALID_REPLAY_NO_PAYLOAD,
-  ],
-  sampling: [DiscardReason.TRANSACTION_SAMPLED],
-};
-
-function getInvalidReasonGroupName(reason: DiscardReason): string {
-  for (const [group, reasons] of Object.entries(invalidReasonsGroup)) {
-    if (reasons.includes(reason)) {
-      return group;
-    }
-  }
-  return 'internal';
-}
-
-function getRateLimitedReasonGroupName(reason: RateLimitedReason | string): string {
-  if (reason.endsWith('_usage_exceeded')) {
-    return 'quota';
-  }
-
-  switch (reason) {
-    case RateLimitedReason.KEY_QUOTA:
-      return 'key limit';
-    case RateLimitedReason.SPIKE_PROTECTION:
-    case RateLimitedReason.SMART_RATE_LIMIT:
-      return 'spike protection';
-    default:
-      return 'internal';
-  }
-}
-
-function getFilteredReasonGroupName(reason: FilteredReason): string {
-  switch (reason) {
-    case FilteredReason.BROWSER_EXTENSION:
-    case FilteredReason.ERROR_MESSAGE:
-    case FilteredReason.FILTERED_TRANSACTION:
-    case FilteredReason.INVALID_CSP:
-    case FilteredReason.IP_ADDRESS:
-    case FilteredReason.LEGACY_BROWSER:
-    case FilteredReason.LOCALHOST:
-    case FilteredReason.RELEASE_VERSION:
-    case FilteredReason.WEB_CRAWLER:
-      return reason;
-    default:
-      return 'other';
-  }
-}
-
-function getClientDiscardReasonGroupName(reason: ClientDiscardReason): string {
-  switch (reason) {
-    case ClientDiscardReason.QUEUE_OVERFLOW:
-    case ClientDiscardReason.CACHE_OVERFLOW:
-    case ClientDiscardReason.RATELIMIT_BACKOFF:
-    case ClientDiscardReason.NETWORK_ERROR:
-    case ClientDiscardReason.SAMPLE_RATE:
-    case ClientDiscardReason.BEFORE_SEND:
-    case ClientDiscardReason.EVENT_PROCESSSOR:
-    case ClientDiscardReason.SEND_ERROR:
-    case ClientDiscardReason.INTERNAL_SDK_ERROR:
-    case ClientDiscardReason.INSUFFICIENT_DATA:
-    case ClientDiscardReason.BACKPRESSURE:
-      return reason;
-    default:
-      return 'other';
-  }
-}
-
-export function getReasonGroupName(outcome: string | number, reason: string): string {
-  switch (outcome) {
-    case Outcome.INVALID:
-      return getInvalidReasonGroupName(reason as DiscardReason);
-    case Outcome.CARDINALITY_LIMITED:
-    case Outcome.RATE_LIMITED:
-    case Outcome.ABUSE:
-      return getRateLimitedReasonGroupName(reason as RateLimitedReason);
-    case Outcome.FILTERED:
-      return getFilteredReasonGroupName(reason as FilteredReason);
-    case Outcome.CLIENT_DISCARD:
-      return getClientDiscardReasonGroupName(reason as ClientDiscardReason);
-    default:
-      return String(reason);
-  }
-}

+ 23 - 33
static/app/views/organizationStats/index.spec.tsx

@@ -89,8 +89,6 @@ describe('OrganizationStats', function () {
   it('renders the base view', async () => {
     render(<OrganizationStats {...defaultProps} />, {router});
 
-    expect(await screen.findByTestId('usage-stats-chart')).toBeInTheDocument();
-
     // Default to Errors category
     expect(screen.getAllByText('Errors')[0]).toBeInTheDocument();
 
@@ -100,32 +98,26 @@ describe('OrganizationStats', function () {
 
     // Render the cards
     expect(screen.getAllByText('Total')[0]).toBeInTheDocument();
-    // Total from cards and project table should match
-    expect(screen.getAllByText('67')).toHaveLength(2);
+    expect(screen.getByText('64')).toBeInTheDocument();
 
     expect(screen.getAllByText('Accepted')[0]).toBeInTheDocument();
-    // Total from cards and project table should match
-    expect(screen.getAllByText('28')).toHaveLength(2);
+    expect(screen.getByText('28')).toBeInTheDocument();
     expect(await screen.findByText('6 in last min')).toBeInTheDocument();
 
     expect(screen.getAllByText('Filtered')[0]).toBeInTheDocument();
     expect(screen.getAllByText('7')[0]).toBeInTheDocument();
 
-    expect(screen.getAllByText('Rate Limited')[0]).toBeInTheDocument();
-    expect(screen.getAllByText('17')[0]).toBeInTheDocument();
-
-    expect(screen.getAllByText('Invalid')[0]).toBeInTheDocument();
-    expect(screen.getAllByText('15')[0]).toBeInTheDocument();
+    expect(screen.getAllByText('Dropped')[0]).toBeInTheDocument();
+    expect(screen.getAllByText('29')[0]).toBeInTheDocument();
 
     // Correct API Calls
     const mockExpectations = {
       UsageStatsOrg: {
         statsPeriod: DEFAULT_STATS_PERIOD,
         interval: '1h',
-        groupBy: ['outcome', 'reason'],
+        groupBy: ['category', 'outcome'],
         project: [-1],
         field: ['sum(quantity)'],
-        category: 'error',
       },
       UsageStatsPerMin: {
         statsPeriod: '5m',
@@ -322,10 +314,9 @@ describe('OrganizationStats', function () {
         query: {
           statsPeriod: DEFAULT_STATS_PERIOD,
           interval: '1h',
-          groupBy: ['outcome', 'reason'],
+          groupBy: ['category', 'outcome'],
           project: selectedProjects,
           field: ['sum(quantity)'],
-          category: 'error',
         },
       })
     );
@@ -364,10 +355,9 @@ describe('OrganizationStats', function () {
         query: {
           statsPeriod: DEFAULT_STATS_PERIOD,
           interval: '1h',
-          groupBy: ['outcome', 'reason'],
+          groupBy: ['category', 'outcome'],
           project: selectedProject,
           field: ['sum(quantity)'],
-          category: 'error',
         },
       })
     );
@@ -432,66 +422,66 @@ const mockStatsResponse = {
     {
       by: {
         project: 1,
-        category: 'error',
+        category: 'attachment',
         outcome: 'accepted',
       },
       totals: {
-        'sum(quantity)': 28,
+        'sum(quantity)': 28000,
       },
       series: {
-        'sum(quantity)': [1, 2, 3, 4, 5, 6, 7],
+        'sum(quantity)': [1000, 2000, 3000, 4000, 5000, 6000, 7000],
       },
     },
     {
       by: {
         project: 1,
-        category: 'error',
-        outcome: 'filtered',
+        outcome: 'accepted',
+        category: 'transaction',
       },
       totals: {
-        'sum(quantity)': 7,
+        'sum(quantity)': 28,
       },
       series: {
-        'sum(quantity)': [1, 1, 1, 1, 1, 1, 1],
+        'sum(quantity)': [1, 2, 3, 4, 5, 6, 7],
       },
     },
     {
       by: {
         project: 1,
         category: 'error',
-        outcome: 'rate_limited',
+        outcome: 'accepted',
       },
       totals: {
-        'sum(quantity)': 14,
+        'sum(quantity)': 28,
       },
       series: {
-        'sum(quantity)': [2, 2, 2, 2, 2, 2, 2],
+        'sum(quantity)': [1, 2, 3, 4, 5, 6, 7],
       },
     },
     {
       by: {
         project: 1,
         category: 'error',
-        outcome: 'abuse',
+        outcome: 'filtered',
       },
       totals: {
-        'sum(quantity)': 2,
+        'sum(quantity)': 7,
       },
       series: {
-        'sum(quantity)': [2, 0, 0, 0, 0, 0, 0],
+        'sum(quantity)': [1, 1, 1, 1, 1, 1, 1],
       },
     },
     {
       by: {
         project: 1,
         category: 'error',
-        outcome: 'cardinality_limited',
+        outcome: 'rate_limited',
       },
       totals: {
-        'sum(quantity)': 1,
+        'sum(quantity)': 14,
       },
       series: {
-        'sum(quantity)': [1, 0, 0, 0, 0, 0, 0],
+        'sum(quantity)': [2, 2, 2, 2, 2, 2, 2],
       },
     },
     {

+ 0 - 1
static/app/views/organizationStats/index.tsx

@@ -270,7 +270,6 @@ export class OrganizationStats extends Component<OrganizationStatsProps> {
         organization={organization}
         dataCategory={this.dataCategory}
         dataCategoryName={this.dataCategoryInfo.titleName}
-        dataCategoryApiName={this.dataCategoryInfo.apiName}
         dataDatetime={this.dataDatetime}
         chartTransform={this.chartTransform}
         handleChangeState={this.setStateOnUrl}

+ 0 - 111
static/app/views/organizationStats/mapSeriesToChart.spec.ts

@@ -1,111 +0,0 @@
-import {mapSeriesToChart} from './mapSeriesToChart';
-import type {UsageSeries} from './types';
-
-const mockSeries: UsageSeries = {
-  start: '2021-01-01T00:00:00Z',
-  end: '2021-01-07T00:00:00Z',
-  intervals: ['2021-01-01T00:00:00Z', '2021-01-02T00:00:00Z', '2021-01-03T00:00:00Z'],
-  groups: [
-    {
-      by: {
-        outcome: 'accepted',
-      },
-      totals: {
-        'sum(quantity)': 6,
-      },
-      series: {
-        'sum(quantity)': [1, 2, 3],
-      },
-    },
-    {
-      by: {
-        outcome: 'filtered',
-        reason: 'other',
-      },
-      totals: {
-        'sum(quantity)': 4,
-      },
-      series: {
-        'sum(quantity)': [0, 1, 3],
-      },
-    },
-    {
-      by: {
-        outcome: 'invalid',
-        reason: 'invalid_transaction',
-      },
-      totals: {
-        'sum(quantity)': 6,
-      },
-      series: {
-        'sum(quantity)': [2, 2, 2],
-      },
-    },
-    {
-      by: {
-        outcome: 'invalid',
-        reason: 'other_reason_a',
-      },
-      totals: {
-        'sum(quantity)': 6,
-      },
-      series: {
-        'sum(quantity)': [1, 2, 3],
-      },
-    },
-    {
-      by: {
-        outcome: 'invalid',
-        reason: 'other_reason_b',
-      },
-      totals: {
-        'sum(quantity)': 3,
-      },
-      series: {
-        'sum(quantity)': [1, 1, 1],
-      },
-    },
-  ],
-};
-
-describe('mapSeriesToChart func', function () {
-  it("should return correct chart tooltip's reasons", function () {
-    const mappedSeries = mapSeriesToChart({
-      orgStats: mockSeries,
-      chartDateInterval: '1h',
-      chartDateUtc: true,
-      dataCategory: 'transactions',
-      endpointQuery: {},
-    });
-
-    expect(mappedSeries.chartSubLabels).toEqual([
-      {
-        parentLabel: 'Filtered',
-        label: 'Other',
-        data: [
-          {name: '2021-01-01T00:00:00Z', value: 0},
-          {name: '2021-01-02T00:00:00Z', value: 1},
-          {name: '2021-01-03T00:00:00Z', value: 3},
-        ],
-      },
-      {
-        parentLabel: 'Invalid',
-        label: 'Invalid Data',
-        data: [
-          {name: '2021-01-01T00:00:00Z', value: 2},
-          {name: '2021-01-02T00:00:00Z', value: 2},
-          {name: '2021-01-03T00:00:00Z', value: 2},
-        ],
-      },
-      {
-        parentLabel: 'Invalid',
-        label: 'Internal',
-        data: [
-          {name: '2021-01-01T00:00:00Z', value: 2},
-          {name: '2021-01-02T00:00:00Z', value: 3},
-          {name: '2021-01-03T00:00:00Z', value: 4},
-        ],
-      },
-    ]);
-  });
-});

+ 0 - 229
static/app/views/organizationStats/mapSeriesToChart.ts

@@ -1,229 +0,0 @@
-import * as Sentry from '@sentry/react';
-import startCase from 'lodash/startCase';
-import moment from 'moment';
-
-import type {TooltipSubLabel} from 'sentry/components/charts/components/tooltip';
-import type {DataCategoryInfo, IntervalPeriod} from 'sentry/types';
-import {Outcome} from 'sentry/types';
-
-import {getDateFromMoment} from './usageChart/utils';
-import {getReasonGroupName} from './getReasonGroupName';
-import type {UsageSeries, UsageStat} from './types';
-import type {ChartStats} from './usageChart';
-import {SeriesTypes} from './usageChart';
-import {formatUsageWithUnits, getFormatUsageOptions} from './utils';
-
-export function mapSeriesToChart({
-  orgStats,
-  dataCategory,
-  chartDateUtc,
-  endpointQuery,
-  chartDateInterval,
-}: {
-  chartDateInterval: IntervalPeriod;
-  chartDateUtc: boolean;
-  dataCategory: DataCategoryInfo['plural'];
-  endpointQuery: Record<string, unknown>;
-  orgStats?: UsageSeries;
-}): {
-  cardStats: {
-    accepted?: string;
-    filtered?: string;
-    invalid?: string;
-    rateLimited?: string;
-    total?: string;
-  };
-  chartStats: ChartStats;
-  chartSubLabels: TooltipSubLabel[];
-  dataError?: Error;
-} {
-  const cardStats = {
-    total: undefined,
-    accepted: undefined,
-    filtered: undefined,
-    invalid: undefined,
-    rateLimited: undefined,
-  };
-  const chartStats: ChartStats = {
-    accepted: [],
-    filtered: [],
-    rateLimited: [],
-    invalid: [],
-    clientDiscard: [],
-    projected: [],
-  };
-  const chartSubLabels: TooltipSubLabel[] = [];
-
-  if (!orgStats) {
-    return {cardStats, chartStats, chartSubLabels};
-  }
-
-  try {
-    const usageStats: UsageStat[] = orgStats.intervals.map(interval => {
-      const dateTime = moment(interval);
-
-      return {
-        date: getDateFromMoment(dateTime, chartDateInterval, chartDateUtc),
-        total: 0,
-        accepted: 0,
-        filtered: 0,
-        rateLimited: 0,
-        invalid: 0,
-        clientDiscard: 0,
-      };
-    });
-
-    // Tally totals for card data
-    const count = {
-      total: 0,
-      [Outcome.ACCEPTED]: 0,
-      [Outcome.FILTERED]: 0,
-      [Outcome.INVALID]: 0,
-      [Outcome.RATE_LIMITED]: 0, // Combined with dropped later
-      [Outcome.CLIENT_DISCARD]: 0,
-      [Outcome.CARDINALITY_LIMITED]: 0, // Combined with dropped later
-      [Outcome.ABUSE]: 0, // Combined with dropped later
-    };
-
-    orgStats.groups.forEach(group => {
-      const {outcome} = group.by;
-
-      if (outcome !== Outcome.CLIENT_DISCARD) {
-        count.total += group.totals['sum(quantity)'];
-      }
-
-      count[outcome] += group.totals['sum(quantity)'];
-
-      group.series['sum(quantity)'].forEach((stat, i) => {
-        const dataObject = {name: orgStats.intervals[i], value: stat};
-
-        const strigfiedReason = String(group.by.reason ?? '');
-        const reason = getReasonGroupName(outcome, strigfiedReason);
-
-        const label = startCase(reason.replace(/-|_/g, ' '));
-
-        // Combine rate limited counts
-        count[Outcome.RATE_LIMITED] +=
-          count[Outcome.ABUSE] + count[Outcome.CARDINALITY_LIMITED];
-
-        // Function to handle chart sub-label updates
-        const updateChartSubLabels = (parentLabel: SeriesTypes) => {
-          const existingSubLabel = chartSubLabels.find(
-            subLabel => subLabel.label === label && subLabel.parentLabel === parentLabel
-          );
-
-          if (existingSubLabel) {
-            // Check if the existing sub-label's data length matches the intervals length
-            if (existingSubLabel.data.length === group.series['sum(quantity)'].length) {
-              // Update the value of the current interval
-              existingSubLabel.data[i].value += stat;
-            } else {
-              // Add a new data object if the length does not match
-              existingSubLabel.data.push(dataObject);
-            }
-          } else {
-            chartSubLabels.push({
-              parentLabel,
-              label,
-              data: [dataObject],
-            });
-          }
-        };
-
-        switch (outcome) {
-          case Outcome.FILTERED:
-            usageStats[i].filtered += stat;
-            updateChartSubLabels(SeriesTypes.FILTERED);
-            break;
-          case Outcome.ACCEPTED:
-            usageStats[i].accepted += stat;
-            break;
-          case Outcome.CARDINALITY_LIMITED:
-          case Outcome.RATE_LIMITED:
-          case Outcome.ABUSE:
-            usageStats[i].rateLimited += stat;
-            updateChartSubLabels(SeriesTypes.RATE_LIMITED);
-            break;
-          case Outcome.CLIENT_DISCARD:
-            usageStats[i].clientDiscard += stat;
-            updateChartSubLabels(SeriesTypes.CLIENT_DISCARD);
-            break;
-          case Outcome.INVALID:
-            usageStats[i].invalid += stat;
-            updateChartSubLabels(SeriesTypes.INVALID);
-            break;
-          default:
-            break;
-        }
-      });
-    });
-
-    usageStats.forEach(stat => {
-      stat.total = [
-        stat.accepted,
-        stat.filtered,
-        stat.rateLimited,
-        stat.invalid,
-        stat.clientDiscard,
-      ].reduce((acc, val) => acc + val, 0);
-
-      // Chart Data
-      const chartData = [
-        {key: 'accepted', value: stat.accepted},
-        {key: 'filtered', value: stat.filtered},
-        {key: 'rateLimited', value: stat.rateLimited},
-        {key: 'invalid', value: stat.invalid},
-        {key: 'clientDiscard', value: stat.clientDiscard},
-      ];
-
-      chartData.forEach(data => {
-        (chartStats[data.key] as any[]).push({value: [stat.date, data.value]});
-      });
-    });
-
-    return {
-      cardStats: {
-        total: formatUsageWithUnits(
-          count.total,
-          dataCategory,
-          getFormatUsageOptions(dataCategory)
-        ),
-        accepted: formatUsageWithUnits(
-          count[Outcome.ACCEPTED],
-          dataCategory,
-          getFormatUsageOptions(dataCategory)
-        ),
-        filtered: formatUsageWithUnits(
-          count[Outcome.FILTERED],
-          dataCategory,
-          getFormatUsageOptions(dataCategory)
-        ),
-        invalid: formatUsageWithUnits(
-          count[Outcome.INVALID],
-          dataCategory,
-          getFormatUsageOptions(dataCategory)
-        ),
-        rateLimited: formatUsageWithUnits(
-          count[Outcome.RATE_LIMITED],
-          dataCategory,
-          getFormatUsageOptions(dataCategory)
-        ),
-      },
-      chartStats,
-      chartSubLabels,
-    };
-  } catch (err) {
-    Sentry.withScope(scope => {
-      scope.setContext('query', endpointQuery);
-      scope.setContext('body', {...orgStats});
-      Sentry.captureException(err);
-    });
-
-    return {
-      cardStats,
-      chartStats,
-      chartSubLabels,
-      dataError: new Error('Failed to parse stats data'),
-    };
-  }
-}

+ 4 - 3
static/app/views/organizationStats/types.tsx

@@ -12,10 +12,11 @@ export interface UsageSeries extends SeriesApi {
 
 export type UsageStat = {
   accepted: number;
-  clientDiscard: number;
   date: string;
+  dropped: {
+    total: number;
+    other?: number;
+  };
   filtered: number;
-  invalid: number;
-  rateLimited: number;
   total: number;
 };

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