Browse Source

feat(stats): Add switch button field for client discard legend (#74548)

Priscila Oliveira 7 months ago
parent
commit
252cb4bc9c

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

@@ -52,6 +52,8 @@ export const PAGE_QUERY_PARAMS = [
   'query',
   'cursor',
   'spikeCursor',
+  // From show data discarded on client toggle
+  'clientDiscard',
 ];
 
 export type OrganizationStatsProps = {
@@ -119,6 +121,10 @@ export class OrganizationStats extends Component<OrganizationStatsProps> {
     return {period: DEFAULT_STATS_PERIOD};
   }
 
+  get clientDiscard(): boolean {
+    return this.props.location?.query?.clientDiscard === 'true';
+  }
+
   // Validation and type-casting should be handled by chart
   get chartTransform(): string | undefined {
     return this.props.location?.query?.transform;
@@ -186,6 +192,7 @@ export class OrganizationStats extends Component<OrganizationStatsProps> {
    */
   setStateOnUrl = (
     nextState: {
+      clientDiscard?: boolean;
       cursor?: string;
       dataCategory?: DataCategoryInfo['plural'];
       query?: string;
@@ -273,6 +280,7 @@ export class OrganizationStats extends Component<OrganizationStatsProps> {
         dataCategoryApiName={this.dataCategoryInfo.apiName}
         dataDatetime={this.dataDatetime}
         chartTransform={this.chartTransform}
+        clientDiscard={this.clientDiscard}
         handleChangeState={this.setStateOnUrl}
         router={router}
         location={location}

+ 11 - 19
static/app/views/organizationStats/usageChart/index.tsx

@@ -7,7 +7,7 @@ import type {
   TooltipComponentOption,
 } from 'echarts';
 
-import BaseChart from 'sentry/components/charts/baseChart';
+import BaseChart, {type BaseChartProps} from 'sentry/components/charts/baseChart';
 import Legend from 'sentry/components/charts/components/legend';
 import xAxis from 'sentry/components/charts/components/xAxis';
 import barSeries from 'sentry/components/charts/series/barSeries';
@@ -117,21 +117,17 @@ export const enum SeriesTypes {
 
 export type UsageChartProps = {
   dataCategory: DataCategoryInfo['plural'];
-
   dataTransform: ChartDataTransform;
   usageDateEnd: string;
-
   usageDateStart: string;
   /**
    * Usage data to draw on chart
    */
   usageStats: ChartStats;
-
   /**
    * Override chart colors for each outcome
    */
   categoryColors?: string[];
-
   /**
    * Config for category dropdown options
    */
@@ -140,13 +136,11 @@ export type UsageChartProps = {
    * Additional data to draw on the chart alongside usage
    */
   chartSeries?: SeriesOption[];
-
   /**
    * Replace default tooltip
    */
   chartTooltip?: TooltipComponentOption;
   errors?: Record<string, Error>;
-
   /**
    * Modify the usageStats using the transformation method selected.
    * If the parent component will handle the data transformation, you should
@@ -156,15 +150,18 @@ export type UsageChartProps = {
     stats: Readonly<ChartStats>,
     transform: Readonly<ChartDataTransform>
   ) => ChartStats;
-
   isError?: boolean;
   isLoading?: boolean;
-
+  /**
+   * Selected map of each legend item.
+   * Default to be selected if item is not in the map
+   */
+  legendSelected?: Record<string, boolean>;
+  onLegendSelectChanged?: BaseChartProps['onLegendSelectChanged'];
   /**
    * Intervals between the x-axis values
    */
   usageDateInterval?: IntervalPeriod;
-
   /**
    * Display datetime in UTC
    */
@@ -339,6 +336,8 @@ function UsageChartBody({
   usageDateShowUtc = true,
   yAxisFormatter,
   handleDataTransformation = cumulativeTotalDataTransformation,
+  legendSelected,
+  onLegendSelectChanged,
 }: UsageChartProps) {
   const theme = useTheme();
 
@@ -514,20 +513,13 @@ function UsageChartBody({
               valueFormatter: tooltipValueFormatter,
             }
       }
-      onLegendSelectChanged={() => {}}
+      onLegendSelectChanged={onLegendSelectChanged}
       legend={Legend({
         right: 10,
         top: 5,
         data: chartLegendData(),
         theme,
-        selected: {
-          [SeriesTypes.ACCEPTED]: true,
-          [SeriesTypes.FILTERED]: true,
-          [SeriesTypes.RATE_LIMITED]: true,
-          [SeriesTypes.INVALID]: true,
-          [SeriesTypes.CLIENT_DISCARD]: false,
-          [SeriesTypes.PROJECTED]: true,
-        },
+        selected: legendSelected,
       })}
     />
   );

+ 36 - 4
static/app/views/organizationStats/usageStatsOrg.tsx

@@ -11,11 +11,13 @@ import OptionSelector from 'sentry/components/charts/optionSelector';
 import {InlineContainer, SectionHeading} from 'sentry/components/charts/styles';
 import type {DateTimeObject} from 'sentry/components/charts/utils';
 import {getSeriesApiInterval} from 'sentry/components/charts/utils';
+import {Flex} from 'sentry/components/container/flex';
 import DeprecatedAsyncComponent from 'sentry/components/deprecatedAsyncComponent';
 import ErrorBoundary from 'sentry/components/errorBoundary';
 import NotAvailable from 'sentry/components/notAvailable';
 import type {ScoreCardProps} from 'sentry/components/scoreCard';
 import ScoreCard from 'sentry/components/scoreCard';
+import SwitchButton from 'sentry/components/switchButton';
 import {DEFAULT_STATS_PERIOD} from 'sentry/constants';
 import {t, tct} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
@@ -26,7 +28,11 @@ import {FORMAT_DATETIME_DAILY, FORMAT_DATETIME_HOURLY} from './usageChart/utils'
 import {mapSeriesToChart} from './mapSeriesToChart';
 import type {UsageSeries} from './types';
 import type {ChartStats, UsageChartProps} from './usageChart';
-import UsageChart, {CHART_OPTIONS_DATA_TRANSFORM, ChartDataTransform} from './usageChart';
+import UsageChart, {
+  CHART_OPTIONS_DATA_TRANSFORM,
+  ChartDataTransform,
+  SeriesTypes,
+} from './usageChart';
 import UsageStatsPerMin from './usageStatsPerMin';
 import {isDisplayUtc} from './utils';
 
@@ -36,6 +42,7 @@ export interface UsageStatsOrganizationProps extends WithRouterProps {
   dataCategoryName: string;
   dataDatetime: DateTimeObject;
   handleChangeState: (state: {
+    clientDiscard?: boolean;
     dataCategory?: DataCategoryInfo['plural'];
     pagePeriod?: string | null;
     transform?: ChartDataTransform;
@@ -44,6 +51,7 @@ export interface UsageStatsOrganizationProps extends WithRouterProps {
   organization: Organization;
   projectIds: number[];
   chartTransform?: string;
+  clientDiscard?: boolean;
 }
 
 type UsageStatsOrganizationState = {
@@ -237,7 +245,7 @@ class UsageStatsOrganization<
   }
 
   get chartProps(): UsageChartProps {
-    const {dataCategory} = this.props;
+    const {dataCategory, clientDiscard, handleChangeState} = this.props;
     const {error, errors, loading} = this.state;
     const {
       chartStats,
@@ -269,6 +277,12 @@ class UsageStatsOrganization<
         subLabels: chartSubLabels,
         skipZeroValuedSubLabels: true,
       },
+      legendSelected: {[SeriesTypes.CLIENT_DISCARD]: !!clientDiscard},
+      onLegendSelectChanged: ({name, selected}) => {
+        if (name === SeriesTypes.CLIENT_DISCARD) {
+          handleChangeState({clientDiscard: selected[name]});
+        }
+      },
     } as UsageChartProps;
 
     return chartProps;
@@ -361,7 +375,7 @@ class UsageStatsOrganization<
   }
 
   renderChartFooter = () => {
-    const {handleChangeState} = this.props;
+    const {handleChangeState, clientDiscard} = this.props;
     const {loading, error} = this.state;
     const {
       chartDateInterval,
@@ -390,6 +404,19 @@ class UsageStatsOrganization<
             </span>
           </FooterDate>
         </InlineContainer>
+        <InlineContainer>
+          {(this.chartData.chartStats.clientDiscard ?? []).length > 0 && (
+            <Flex align="center" gap={space(1)}>
+              <strong>{t('Show client-discarded data:')}</strong>
+              <SwitchButton
+                toggle={() => {
+                  handleChangeState({clientDiscard: !clientDiscard});
+                }}
+                isActive={clientDiscard}
+              />
+            </Flex>
+          )}
+        </InlineContainer>
         <InlineContainer>
           <OptionSelector
             title={t('Type')}
@@ -456,9 +483,14 @@ const ChartWrapper = styled('div')`
 const Footer = styled('div')`
   display: flex;
   flex-direction: row;
-  justify-content: space-between;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: ${space(1.5)};
   padding: ${space(1)} ${space(3)};
   border-top: 1px solid ${p => p.theme.border};
+  > *:first-child {
+    flex-grow: 1;
+  }
 `;
 const FooterDate = styled('div')`
   display: flex;