123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- import {Component} from 'react';
- import type {Client} from 'sentry/api';
- import * as Layout from 'sentry/components/layouts/thirds';
- import NoProjectMessage from 'sentry/components/noProjectMessage';
- import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
- import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
- import {ALL_ACCESS_PROJECTS} from 'sentry/constants/pageFilters';
- import {t} from 'sentry/locale';
- import type {RouteComponentProps} from 'sentry/types/legacyReactRouter';
- import type {Organization} from 'sentry/types/organization';
- import EventView from 'sentry/utils/discover/eventView';
- import {QueryError} from 'sentry/utils/discover/genericDiscoverQuery';
- import {TraceFullDetailedQuery} from 'sentry/utils/performance/quickTrace/traceFullQuery';
- import TraceMetaQuery from 'sentry/utils/performance/quickTrace/traceMetaQuery';
- import type {
- TraceMeta,
- TraceSplitResults,
- } from 'sentry/utils/performance/quickTrace/types';
- import {decodeScalar} from 'sentry/utils/queryString';
- import withApi from 'sentry/utils/withApi';
- import withOrganization from 'sentry/utils/withOrganization';
- import type {TraceTree} from 'sentry/views/performance/newTraceDetails/traceModels/traceTree';
- import {TraceView as TraceViewV1} from './../newTraceDetails';
- import TraceDetailsContent from './content';
- import {DEFAULT_TRACE_ROWS_LIMIT} from './limitExceededMessage';
- import NewTraceDetailsContent from './newTraceDetailsContent';
- import {getTraceSplitResults} from './utils';
- type Props = RouteComponentProps<{traceSlug: string}, {}> & {
- api: Client;
- organization: Organization;
- };
- type State = {
- limit: number;
- };
- class TraceSummary extends Component<Props> {
- state: State = {
- limit: DEFAULT_TRACE_ROWS_LIMIT,
- };
- componentDidMount(): void {
- const {query} = this.props.location;
- if (query.limit) {
- this.setState({limit: query.limit});
- }
- }
- handleLimitChange = (newLimit: number) => {
- this.setState({limit: newLimit});
- };
- getDocumentTitle(): string {
- return [t('Trace Details'), t('Performance')].join(' — ');
- }
- getTraceSlug(): string {
- const {traceSlug} = this.props.params;
- return typeof traceSlug === 'string' ? traceSlug.trim() : '';
- }
- getDateSelection() {
- const {location} = this.props;
- const queryParams = normalizeDateTimeParams(location.query, {
- allowAbsolutePageDatetime: true,
- });
- const start = decodeScalar(queryParams.start);
- const end = decodeScalar(queryParams.end);
- const statsPeriod = decodeScalar(queryParams.statsPeriod);
- return {start, end, statsPeriod};
- }
- getTraceEventView() {
- const traceSlug = this.getTraceSlug();
- const {start, end, statsPeriod} = this.getDateSelection();
- return EventView.fromSavedQuery({
- id: undefined,
- name: `Events with Trace ID ${traceSlug}`,
- fields: ['title', 'event.type', 'project', 'timestamp'],
- orderby: '-timestamp',
- query: `trace:${traceSlug}`,
- projects: [ALL_ACCESS_PROJECTS],
- version: 2,
- start,
- end,
- range: statsPeriod,
- });
- }
- renderContent() {
- const {location, organization, params} = this.props;
- const traceSlug = this.getTraceSlug();
- const {start, end, statsPeriod} = this.getDateSelection();
- const dateSelected = Boolean(statsPeriod || (start && end));
- const backend = decodeScalar(location.query.backend);
- const content = ({
- isLoading,
- error,
- traces,
- meta,
- }: {
- error: QueryError | null;
- isLoading: boolean;
- meta: TraceMeta | null;
- traces: (TraceTree.Transaction[] | TraceSplitResults<TraceTree.Transaction>) | null;
- }) => {
- const {transactions, orphanErrors} = getTraceSplitResults<TraceTree.Transaction>(
- traces ?? [],
- organization
- );
- const commonProps = {
- location,
- organization,
- params,
- traceSlug,
- traceEventView: this.getTraceEventView(),
- dateSelected,
- isLoading,
- error,
- orphanErrors,
- traces: transactions ?? (traces as TraceTree.Transaction[]),
- meta,
- handleLimitChange: this.handleLimitChange,
- };
- return organization.features.includes('performance-trace-details') ? (
- <NewTraceDetailsContent {...commonProps} />
- ) : (
- <TraceDetailsContent {...commonProps} />
- );
- };
- if (!dateSelected) {
- return content({
- isLoading: false,
- error: new QueryError('date selection not specified'),
- traces: null,
- meta: null,
- });
- }
- return (
- <TraceFullDetailedQuery
- type={backend === 'indexedSpans' ? 'spans' : 'detailed'}
- location={location}
- orgSlug={organization.slug}
- traceId={traceSlug}
- start={start}
- end={end}
- statsPeriod={statsPeriod}
- limit={this.state.limit}
- >
- {traceResults => (
- <TraceMetaQuery
- location={location}
- orgSlug={organization.slug}
- traceId={traceSlug}
- start={start}
- end={end}
- statsPeriod={statsPeriod}
- >
- {metaResults =>
- content({
- isLoading: traceResults.isLoading || metaResults.isLoading,
- error: traceResults.error || metaResults.error,
- traces: traceResults.traces as unknown as TraceTree.Transaction[],
- meta: metaResults.meta,
- })
- }
- </TraceMetaQuery>
- )}
- </TraceFullDetailedQuery>
- );
- }
- render() {
- const {organization} = this.props;
- if (organization.features.includes('trace-view-v1')) {
- return <TraceViewV1 />;
- }
- return (
- <SentryDocumentTitle title={this.getDocumentTitle()} orgSlug={organization.slug}>
- <Layout.Page>
- <NoProjectMessage organization={organization}>
- {this.renderContent()}
- </NoProjectMessage>
- </Layout.Page>
- </SentryDocumentTitle>
- );
- }
- }
- export default withOrganization(withApi(TraceSummary));
|