import {Fragment, useEffect, useState} from 'react'; import type {Location} from 'history'; import pick from 'lodash/pick'; import round from 'lodash/round'; import {doSessionsRequest} from 'sentry/actionCreators/sessions'; import {Button} from 'sentry/components/button'; import {shouldFetchPreviousPeriod} from 'sentry/components/charts/utils'; import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse'; import ScoreCard from 'sentry/components/scoreCard'; import {parseStatsPeriod} from 'sentry/components/timeRangeSelector/utils'; import {URL_PARAM} from 'sentry/constants/pageFilters'; import {IconArrow} from 'sentry/icons/iconArrow'; import {t} from 'sentry/locale'; import type {PageFilters} from 'sentry/types/core'; import type {Organization, SessionApiResponse} from 'sentry/types/organization'; import {trackAnalytics} from 'sentry/utils/analytics'; import {getPeriod} from 'sentry/utils/duration/getPeriod'; import {formatAbbreviatedNumber} from 'sentry/utils/formatters'; import {formatPercentage} from 'sentry/utils/number/formatPercentage'; import useApi from 'sentry/utils/useApi'; import { getSessionTermDescription, SessionTerm, } from 'sentry/views/releases/utils/sessionTerm'; type Props = { isProjectStabilized: boolean; location: Location; organization: Organization; selection: PageFilters; query?: string; }; export function ProjectAnrScoreCard({ isProjectStabilized, organization, selection, location, query, }: Props) { const {environments, projects, datetime} = selection; const {start, end, period} = datetime; const api = useApi(); const [sessionsData, setSessionsData] = useState(null); const [previousSessionData, setPreviousSessionsData] = useState(null); useEffect(() => { let unmounted = false; const requestData = { orgSlug: organization.slug, field: ['anr_rate()'], environment: environments, project: projects, query, includeSeries: false, }; doSessionsRequest(api, {...requestData, ...normalizeDateTimeParams(datetime)}).then( response => { if (unmounted) { return; } setSessionsData(response); } ); return () => { unmounted = true; }; }, [api, datetime, environments, organization.slug, projects, query]); useEffect(() => { let unmounted = false; if ( !shouldFetchPreviousPeriod({ start, end, period, }) ) { setPreviousSessionsData(null); } else { const requestData = { orgSlug: organization.slug, field: ['anr_rate()'], environment: environments, project: projects, query, includeSeries: false, }; const {start: previousStart} = parseStatsPeriod( getPeriod({period, start: undefined, end: undefined}, {shouldDoublePeriod: true}) .statsPeriod! ); const {start: previousEnd} = parseStatsPeriod( getPeriod({period, start: undefined, end: undefined}, {shouldDoublePeriod: false}) .statsPeriod! ); doSessionsRequest(api, { ...requestData, start: previousStart, end: previousEnd, }).then(response => { if (unmounted) { return; } setPreviousSessionsData(response); }); } return () => { unmounted = true; }; }, [start, end, period, api, organization.slug, environments, projects, query]); const value = sessionsData?.groups?.[0]?.totals['anr_rate()'] ?? null; const previousValue = previousSessionData?.groups?.[0]?.totals['anr_rate()'] ?? null; const hasCurrentAndPrevious = previousValue && value; const trend = hasCurrentAndPrevious ? round(value - previousValue, 4) : null; const trendStatus = !trend ? undefined : trend < 0 ? 'good' : 'bad'; if (!isProjectStabilized) { return null; } function renderTrend() { return trend ? ( {trend >= 0 ? ( ) : ( )} {`${formatAbbreviatedNumber(Math.abs(trend))}\u0025`} ) : null; } const endpointPath = `/organizations/${organization.slug}/issues/`; const issueQuery = ['mechanism:[ANR,AppExitInfo]', query].join(' ').trim(); const queryParams = { ...normalizeDateTimeParams(pick(location.query, [...Object.values(URL_PARAM)])), query: issueQuery, sort: 'freq', }; const issueSearch = { pathname: endpointPath, query: queryParams, }; function renderButton() { return ( ); } return ( ); }