import {Fragment, useCallback, useMemo, useState} from 'react'; import {browserHistory} from 'react-router'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/button'; import Count from 'sentry/components/count'; import EmptyStateWarning from 'sentry/components/emptyStateWarning'; import * as Layout from 'sentry/components/layouts/thirds'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; import Panel from 'sentry/components/panels/panel'; import PanelHeader from 'sentry/components/panels/panelHeader'; import PanelItem from 'sentry/components/panels/panelItem'; import PerformanceDuration from 'sentry/components/performanceDuration'; import type {SmartSearchBarProps} from 'sentry/components/smartSearchBar'; import {IconChevron} from 'sentry/icons/iconChevron'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {PageFilters} from 'sentry/types'; import {useApiQuery} from 'sentry/utils/queryClient'; import {decodeInteger, decodeScalar} from 'sentry/utils/queryString'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import {ProjectRenderer, SpanIdRenderer, TraceIdRenderer} from './fieldRenderers'; import {TracesSearchBar} from './tracesSearchBar'; const DEFAULT_PER_PAGE = 20; const FIELDS = [ 'project', 'transaction.id', 'id', 'timestamp', 'span.op', 'span.description', 'span.duration', ]; type Field = (typeof FIELDS)[number]; export function Content() { const location = useLocation(); const query = useMemo(() => { return decodeScalar(location.query.query, ''); }, [location.query.query]); const limit = useMemo(() => { return decodeInteger(location.query.perPage, DEFAULT_PER_PAGE); }, [location.query.perPage]); const handleSearch: SmartSearchBarProps['onSearch'] = useCallback( (searchQuery: string) => { browserHistory.push({ ...location, query: { ...location.query, cursor: undefined, query: searchQuery || undefined, }, }); }, [location] ); const traces = useTraces({ fields: FIELDS, limit, query, }); const isLoading = traces.isFetching; const isError = !isLoading && traces.isError; const isEmpty = !isLoading && !isError && (traces?.data?.data?.length ?? 0) === 0; const data = !isLoading && !isError ? traces?.data?.data : undefined; return ( {t('Trace ID')} {t('Trace Root Name')} {t('Spans')} {t('Breakdown')} {t('Trace Duration')} {t('Issues')} {isLoading && ( )} {isError && ( // TODO: need an error state )} {isEmpty && ( )} {data?.map(trace => )} ); } function TraceRow({trace}: {trace: TraceResult}) { const [expanded, setExpanded] = useState(false); return (