import {Fragment, useCallback, useEffect, useMemo, useState} from 'react'; import {browserHistory} from 'react-router'; import {Theme, useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/button'; import ChartZoom from 'sentry/components/charts/chartZoom'; import {LineChart} from 'sentry/components/charts/lineChart'; import Count from 'sentry/components/count'; import EmptyStateWarning from 'sentry/components/emptyStateWarning'; import IdBadge from 'sentry/components/idBadge'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import Pagination, {CursorHandler} from 'sentry/components/pagination'; import PerformanceDuration from 'sentry/components/performanceDuration'; import TextOverflow from 'sentry/components/textOverflow'; import {Tooltip} from 'sentry/components/tooltip'; import {IconArrow, IconChevron, IconWarning} from 'sentry/icons'; import {t, tct} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {Series} from 'sentry/types/echarts'; import {axisLabelFormatter, tooltipFormatter} from 'sentry/utils/discover/charts'; import type {TrendType} from 'sentry/utils/profiling/hooks/types'; import {FunctionTrend} from 'sentry/utils/profiling/hooks/types'; import {useProfileFunctionTrends} from 'sentry/utils/profiling/hooks/useProfileFunctionTrends'; import {decodeScalar} from 'sentry/utils/queryString'; import {useLocation} from 'sentry/utils/useLocation'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjects from 'sentry/utils/useProjects'; import useRouter from 'sentry/utils/useRouter'; import { Accordion, AccordionItem, ContentContainer, HeaderContainer, HeaderTitleLegend, StatusContainer, Subtitle, WidgetContainer, } from './styles'; const MAX_FUNCTIONS = 3; const CURSOR_NAME = 'fnTrendCursor'; interface FunctionTrendsWidgetProps { trendFunction: 'p50()' | 'p75()' | 'p95()' | 'p99()'; trendType: TrendType; userQuery?: string; } export function FunctionTrendsWidget({ userQuery, trendFunction, trendType, }: FunctionTrendsWidgetProps) { const location = useLocation(); const [expandedIndex, setExpandedIndex] = useState(0); const fnTrendCursor = useMemo( () => decodeScalar(location.query[CURSOR_NAME]), [location.query] ); const handleCursor = useCallback((cursor, pathname, query) => { browserHistory.push({ pathname, query: {...query, [CURSOR_NAME]: cursor}, }); }, []); const trendsQuery = useProfileFunctionTrends({ trendFunction, trendType, query: userQuery, limit: MAX_FUNCTIONS, cursor: fnTrendCursor, }); useEffect(() => { setExpandedIndex(0); }, [trendsQuery.data]); const hasTrends = (trendsQuery.data?.length || 0) > 0; const isLoading = trendsQuery.isLoading; const isError = trendsQuery.isError; return ( {isLoading && ( )} {isError && ( )} {!isError && !isLoading && !hasTrends && (

{t('No functions found')}

)} {hasTrends && ( {(trendsQuery.data ?? []).map((f, i) => { return ( setExpandedIndex(i)} func={f} /> ); })} )}
); } interface FunctionTrendsWidgetHeaderProps { handleCursor: CursorHandler; pageLinks: string | null; trendType: TrendType; } function FunctionTrendsWidgetHeader({ handleCursor, pageLinks, trendType, }: FunctionTrendsWidgetHeaderProps) { switch (trendType) { case 'regression': return ( {t('Most Regressed Functions')} {t('Functions by most regressed.')} ); case 'improvement': return ( {t('Most Improved Functions')} {t('Functions by most improved.')} ); default: throw new Error(t('Unknown trend type')); } } interface FunctionTrendsEntryProps { func: FunctionTrend; isExpanded: boolean; setExpanded: () => void; trendFunction: string; } function FunctionTrendsEntry({ func, isExpanded, setExpanded, trendFunction, }: FunctionTrendsEntryProps) { const {projects} = useProjects(); const project = projects.find(p => p.id === func.project); return ( {project && ( )} {func.function} , })} >