chartFooter.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import Feature from 'sentry/components/acl/feature';
  4. import IntervalSelector from 'sentry/components/charts/intervalSelector';
  5. import OptionSelector from 'sentry/components/charts/optionSelector';
  6. import {
  7. ChartControls,
  8. InlineContainer,
  9. SectionHeading,
  10. SectionValue,
  11. } from 'sentry/components/charts/styles';
  12. import FeatureBadge from 'sentry/components/featureBadge';
  13. import ExternalLink from 'sentry/components/links/externalLink';
  14. import QuestionTooltip from 'sentry/components/questionTooltip';
  15. import Switch from 'sentry/components/switchButton';
  16. import {t, tct} from 'sentry/locale';
  17. import {Organization, SelectValue} from 'sentry/types';
  18. import {defined} from 'sentry/utils';
  19. import EventView from 'sentry/utils/discover/eventView';
  20. import {TOP_EVENT_MODES} from 'sentry/utils/discover/types';
  21. import {formatAbbreviatedNumber} from 'sentry/utils/formatters';
  22. import localStorage from 'sentry/utils/localStorage';
  23. export const PROCESSED_BASELINE_TOGGLE_KEY = 'show-processed-baseline';
  24. type Props = {
  25. displayMode: string;
  26. displayOptions: SelectValue<string>[];
  27. eventView: EventView;
  28. onAxisChange: (value: string[]) => void;
  29. onDisplayChange: (value: string) => void;
  30. onIntervalChange: (value: string | undefined) => void;
  31. onTopEventsChange: (value: string) => void;
  32. organization: Organization;
  33. setShowBaseline: (value: boolean) => void;
  34. showBaseline: boolean;
  35. topEvents: string;
  36. total: number | null;
  37. yAxisOptions: SelectValue<string>[];
  38. yAxisValue: string[];
  39. disableProcessedBaselineToggle?: boolean;
  40. loadingProcessedTotals?: boolean;
  41. processedTotal?: number;
  42. };
  43. export default function ChartFooter({
  44. total,
  45. yAxisValue,
  46. yAxisOptions,
  47. onAxisChange,
  48. displayMode,
  49. displayOptions,
  50. onDisplayChange,
  51. onTopEventsChange,
  52. onIntervalChange,
  53. topEvents,
  54. setShowBaseline,
  55. showBaseline,
  56. organization,
  57. disableProcessedBaselineToggle,
  58. eventView,
  59. processedTotal,
  60. loadingProcessedTotals,
  61. }: Props) {
  62. const elements: React.ReactNode[] = [];
  63. elements.push(<SectionHeading key="total-label">{t('Total Events')}</SectionHeading>);
  64. elements.push(
  65. total === null || loadingProcessedTotals === true ? (
  66. <SectionValue data-test-id="loading-placeholder" key="total-value">
  67. &mdash;
  68. </SectionValue>
  69. ) : defined(processedTotal) ? (
  70. <SectionValue key="total-value">
  71. {tct('[indexedTotal] of [processedTotal]', {
  72. indexedTotal: formatAbbreviatedNumber(total),
  73. processedTotal: formatAbbreviatedNumber(processedTotal),
  74. })}
  75. </SectionValue>
  76. ) : (
  77. <SectionValue key="total-value">{total.toLocaleString()}</SectionValue>
  78. )
  79. );
  80. const topEventOptions: SelectValue<string>[] = [];
  81. for (let i = 1; i <= 10; i++) {
  82. topEventOptions.push({value: i.toString(), label: i.toString()});
  83. }
  84. return (
  85. <ChartControls>
  86. <InlineContainer>{elements}</InlineContainer>
  87. <InlineContainer>
  88. <Feature organization={organization} features={['discover-metrics-baseline']}>
  89. <Fragment>
  90. <SwitchLabel>{t('Processed events')}</SwitchLabel>
  91. <Switch
  92. data-test-id="processed-events-toggle"
  93. isActive={showBaseline}
  94. isDisabled={disableProcessedBaselineToggle ?? true}
  95. size="lg"
  96. toggle={() => {
  97. const value = !showBaseline;
  98. localStorage.setItem(
  99. PROCESSED_BASELINE_TOGGLE_KEY,
  100. value === true ? '1' : '0'
  101. );
  102. setShowBaseline(value);
  103. }}
  104. />
  105. <QuestionTooltip
  106. isHoverable
  107. position="top"
  108. size="sm"
  109. title={tct(
  110. 'Show a baseline of client-side [processedEventsLink: processed events].[break]Available on the Total Period display for y-axes scoped to [transactionEventsLink: transaction events].',
  111. {
  112. transactionEventsLink: (
  113. <ExternalLink href="https://docs.sentry.io/product/sentry-basics/tracing/event-detail/" />
  114. ),
  115. processedEventsLink: (
  116. <ExternalLink href="https://docs.sentry.io/product/data-management-settings/server-side-sampling/" />
  117. ),
  118. break: (
  119. <div>
  120. <br />
  121. </div>
  122. ),
  123. }
  124. )}
  125. />
  126. <FeatureBadge type="alpha" />
  127. </Fragment>
  128. </Feature>
  129. <Feature organization={organization} features={['discover-interval-selector']}>
  130. <IntervalSelector eventView={eventView} onIntervalChange={onIntervalChange} />
  131. </Feature>
  132. <OptionSelector
  133. title={t('Display')}
  134. selected={displayMode}
  135. options={displayOptions}
  136. onChange={onDisplayChange}
  137. />
  138. {TOP_EVENT_MODES.includes(displayMode) && (
  139. <OptionSelector
  140. title={t('Limit')}
  141. selected={topEvents}
  142. options={topEventOptions}
  143. onChange={onTopEventsChange}
  144. />
  145. )}
  146. {TOP_EVENT_MODES.includes(displayMode) ? (
  147. <OptionSelector
  148. title={t('Y-Axis')}
  149. selected={yAxisValue[0]}
  150. options={yAxisOptions}
  151. onChange={yAxis => onAxisChange([yAxis])}
  152. />
  153. ) : (
  154. <OptionSelector
  155. multiple
  156. isClearable
  157. menuTitle={
  158. yAxisOptions.length > 3 ? t('Select up to 3 options') : t('Y-axis')
  159. }
  160. title={t('Y-Axis')}
  161. selected={yAxisValue}
  162. options={yAxisOptions}
  163. onChange={onAxisChange}
  164. />
  165. )}
  166. </InlineContainer>
  167. </ChartControls>
  168. );
  169. }
  170. const SwitchLabel = styled('div')`
  171. padding-right: 4px;
  172. font-weight: bold;
  173. `;