123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- import type {Theme} from '@emotion/react';
- import type {Location} from 'history';
- import isEqual from 'lodash/isEqual';
- import pick from 'lodash/pick';
- import ErrorPanel from 'sentry/components/charts/errorPanel';
- import LoadingPanel from 'sentry/components/charts/loadingPanel';
- import DeprecatedAsyncComponent from 'sentry/components/deprecatedAsyncComponent';
- import {IconWarning} from 'sentry/icons';
- import type {OrganizationSummary} from 'sentry/types';
- import {defined} from 'sentry/utils';
- import EventView from 'sentry/utils/discover/eventView';
- import type {ViewProps} from '../../../types';
- import {QUERY_KEYS} from '../../../utils';
- import {filterToColor, SpanOperationBreakdownFilter} from '../../filter';
- import Chart from './chart';
- import {transformData} from './utils';
- type ApiResult = Record<string, number>;
- type Props = DeprecatedAsyncComponent['props'] &
- ViewProps & {
- currentFilter: SpanOperationBreakdownFilter;
- fields: string[];
- location: Location;
- organization: OrganizationSummary;
- queryExtras?: Record<string, string>;
- };
- type State = DeprecatedAsyncComponent['state'] & {
- chartData: {data: ApiResult[]} | null;
- };
- /**
- * Fetch and render a bar chart that shows event volume
- * for each duration bucket. We always render 15 buckets of
- * equal widths based on the endpoints min + max durations.
- *
- * This graph visualizes how many transactions were recorded
- * at each duration bucket, showing the modality of the transaction.
- */
- class Content extends DeprecatedAsyncComponent<Props, State> {
- getEndpoints(): ReturnType<DeprecatedAsyncComponent['getEndpoints']> {
- const {
- organization,
- query,
- start,
- end,
- statsPeriod,
- environment,
- project,
- fields,
- location,
- queryExtras,
- } = this.props;
- const eventView = EventView.fromSavedQuery({
- id: '',
- name: '',
- version: 2,
- fields,
- orderby: '',
- projects: project,
- range: statsPeriod,
- query,
- environment,
- start,
- end,
- });
- let apiPayload = eventView.getEventsAPIPayload(location);
- apiPayload = {
- ...apiPayload,
- ...queryExtras,
- referrer: 'api.performance.durationpercentilechart',
- };
- const endpoint = `/organizations/${organization.slug}/events/`;
- return [['chartData', endpoint, {query: apiPayload}]];
- }
- componentDidUpdate(prevProps: Props) {
- if (this.shouldRefetchData(prevProps)) {
- this.fetchData();
- }
- }
- shouldRefetchData(prevProps: Props) {
- if (this.state.loading) {
- return false;
- }
- return !isEqual(pick(prevProps, QUERY_KEYS), pick(this.props, QUERY_KEYS));
- }
- renderLoading() {
- return <LoadingPanel data-test-id="histogram-loading" />;
- }
- renderError() {
- // Don't call super as we don't really need issues for this.
- return (
- <ErrorPanel>
- <IconWarning color="gray300" size="lg" />
- </ErrorPanel>
- );
- }
- renderBody() {
- const {currentFilter} = this.props;
- const {chartData} = this.state;
- if (!defined(chartData)) {
- return null;
- }
- const colors = (theme: Theme) =>
- currentFilter === SpanOperationBreakdownFilter.NONE
- ? theme.charts.getColorPalette(1)
- : [filterToColor(currentFilter)];
- return <Chart series={transformData(chartData.data, false)} colors={colors} />;
- }
- }
- export default Content;
|